I've been developing a simple CMS both for practical use and learning about Laravel, and I decided to implement a simple service that makes it possible for the administrators to send messages to one another. However, the finished JavaScript code, while completely functional, ended up being a bit sketchy so I'm looking for ways to improve its performance and security. Any feedback is greatly appreciated.
This is the JavaScript code that sends Ajax calls to server (based on search term, whether we want the sent messages or the incoming messages) and formats and reloads the table shown in my CMS:
var page = 1;
var perPage = 10;
var lastPage = 1;
var searchTerm = '';
var category = 'inbox';
function nextPage () {
// Incrementing the global 'page' variable
page++;
reloadList();
}
function prevPage () {
// Decrementing the global 'page' variable
page--;
reloadList();
}
function search () {
// Resetting the global 'page' variable
page = 1;
/* reloadList() automatically detects the search terms and sends the appropriate AJAX request
based on the value of the 'searchTerm' variable */
searchTerm = $("#searchBox").val();
reloadList();
}
function changeCat (cat) {
// Resetting the global 'page' variable
page = 1;
// Resetting the global 'searchTerm' variable
$("#searchBox").val('');
searchTerm = '';
// Setting the global 'category' variable
category = cat;
// Hackish way of setting the correct header for the page
$("#tab-header").html($("#"+cat+"-pill-header").html());
// Deactivating the old pill menu item
$("#category-pills>li.active").removeClass("active");
// Activating the selected pill menu item
$("#"+cat+"-pill").addClass('active');
reloadList();
}
function toggleStar (id) {
// Calling the server to toggle the 'starred' field for 'id'
var data = 'id=' + id + '&_token=' + pageToken;
$.ajax({
type: "POST",
url: '/admin/messages/toggle-star',
data: data,
success: function(data) {
reloadList();
},
error: function(data) {
showAlert('danger', 'Error', 'Something went wrong. <a href="{{ Request::url() }}">Try again</a>', 'alerts');
}
});
}
function deleteChecked () {
// Getting all the checked checkboxes
var checkedBoxes = $("#messages>tr>td>input:checkbox:checked");
// Determining the 'url' based on if this is a soft delete or a permanent delete
var url = '/admin/messages/trash-checked';
if (category == 'trash') url = '/admin/messages/delete-checked';
// Filling the 'deleteIds' array with the soon to be deleted message ids
var deleteIds = [];
checkedBoxes.each(function () {
deleteIds.push($(this).attr('id'));
});
// Calling the server to delete the messages with ids inside our 'deleteIds' array
var data = 'deleteIds=' + JSON.stringify(deleteIds) + '&_token=' + pageToken;
$.ajax({
type: "POST",
url: url,
data: data,
success: function(data) {
// Checking to see if the messages were deleted
if (data == 'true') {
// Hackish way of getting the count of unread messages
var navCount = +($(".navbar-messages-count").html());
checkedBoxes.each(function () {
// Getting the id of the deleted message
var id = $(this).attr('id');
// Determining if it was on display in the messages section in navbar
if ($("#navbar-message-" + id).length) {
// Hiding the message
/* We are hiding, and not removing, the element to ease the task of redisplaying in case of message restore */
$("#navbar-message-" + id).hide();
// Decrementing the count of unread messages
navCount--;
}
});
// Updating the count of unread messages shown on numerous places in the panel
$(".navbar-messages-count").html(navCount);
}
reloadList();
},
error: function(data) {
showAlert('danger', 'Error', 'Something went wrong. <a href="{{ Request::url() }}">Try again</a>', 'alerts');
}
});
}
function restoreChecked () {
// Getting all the checked checkboxes
var checkedBoxes = $("#messages>tr>td>input:checkbox:checked");
// Filling the 'restoreIds' array with the soon to be restored message ids
var restoreIds = [];
checkedBoxes.each(function () {
restoreIds.push($(this).attr('id'));
});
// Calling the server to restore the messages with ids inside our 'restoreIds' array
var data = 'restoreIds=' + JSON.stringify(restoreIds) + '&_token=' + pageToken;
$.ajax({
type: "POST",
url: '/admin/messages/restore-checked',
data: data,
success: function(data) {
// Checking to see if the messages were restored
if (data == 'true') {
// Hackish way of getting the count of unread messages
var navCount = +($(".navbar-messages-count").html());
checkedBoxes.each(function () {
// Getting the id of the restored message
var id = $(this).attr('id');
// Determining if it was on display in the messages section in navbar before getting deleted
if ($("#navbar-message-" + id).length) {
// Redisplaying the message
$("#navbar-message-" + id).show();
// Incrementing the count of unread messages
navCount++;
}
});
// Updating the count of unread messages shown on numerous places in the panel
$(".navbar-messages-count").html(navCount);
}
reloadList();
},
error: function(data) {
showAlert('danger', 'Error', 'Something went wrong. <a href="{{ Request::url() }}">Try again</a>', 'alerts');
}
});
}
function reloadList () {
// Emptying out all the table rows
$("#messages").html('');
// Checking to see if we're on the trash pill item in order to add or remove the restore button accordingly
if (category == 'trash') {
if (!$("#restore-checked").length) {
var restoreButtonHtml = '<button type="button" class="btn btn-default btn-sm" id="restore-checked" onclick="restoreChecked()"><i class="fa fa-rotate-left"></i></button>';
$("#mailbox-controls").append(restoreButtonHtml);
}
} else {
if ($("#restore-checked").length) $("#restore-checked").remove();
}
var i = 0;
// Getting information to build rows for our table
getPageRows(page, perPage, '/admin/messages/show-'+category, searchTerm, pageToken, function (data) {
lastPage = data['last_page'];
rowData = data['data'];
// If messages were available
if (rowData.length == 0) {
var tableRow = '<tr><td style="text-align:center;">No data to show</td></tr>';
$("#messages").append(tableRow);
}
// Looping through available messages
for (i = 0; i < rowData.length; i++) {
// Making a table row for each message
var tableRow = makeMessageRow(rowData[i]['id'], rowData[i]['starred'], rowData[i]['toOrFrom'], rowData[i]['read'], rowData[i]['subject'], rowData[i]['sent']);
$("#messages").append(tableRow);
}
// Disabling the previous page button if we're at page one
if (page == 1) {
$("#prev_page_button").prop('disabled', true);
} else {
$("#prev_page_button").prop('disabled', false);
}
// Disabling the next page button if we're at the last page
if (page == lastPage) {
$("#next_page_button").prop('disabled', true);
} else {
$("#next_page_button").prop('disabled', false);
}
});
}
// Gets paginated, searched and categorized messages from server in order to show in the inbox section in the panel
function getPageRows (page, perPage, url, search, token, handleData) {
// Calling the server to get 'perPage' of messages
var data = 'page=' + page + '&perPage=' + perPage + '&search=' + search + '&_token=' + token;
$.ajax({
type: "POST",
url: url,
data: data,
success: function(data) {
handleData(data);
},
error: function(data) {
showAlert('danger', 'Error', 'Something went wrong. <a href="{{ Request::url() }}">Try again</a>', 'alerts');
}
});
}
// Makes a table row based on given information for the inbox section in the panel
function makeMessageRow (id, starred, sender_name, read, subject, sent) {
var tableRow = '<tr><td><input type="checkbox" id="'+id+'"></td><td class="mailbox-star">';
if (starred) {
tableRow += '<a href="javascript:void(0)" onclick="toggleStar('+id+')"><i class="fa fa-star text-yellow"></i></a>';
} else {
tableRow += '<a href="javascript:void(0)" onclick="toggleStar('+id+')"><i class="fa fa-star-o text-yellow"></i></a>';
}
tableRow += '</td><td class="mailbox-name"><a href="#">'+sender_name+'</a>';
if (!read) {
tableRow += '<span class="label label-primary message-label">unread</span>';
}
tableRow += '</td><td class="mailbox-subject">'+subject+'</td><td class="mailbox-date">'+sent+'</td>';
return tableRow;
}