/************************************************************************
* DELETION extension for jTable *
*************************************************************************/
(function ($) {
//Reference to base object members
var base = {
_create: $.hik.jtable.prototype._create,
_addColumnsToHeaderRow: $.hik.jtable.prototype._addColumnsToHeaderRow,
_addCellsToRowUsingRecord: $.hik.jtable.prototype._addCellsToRowUsingRecord
};
//extension members
$.extend(true, $.hik.jtable.prototype, {
/************************************************************************
* DEFAULT OPTIONS / EVENTS *
*************************************************************************/
options: {
//Options
deleteConfirmation: true,
//Events
recordDeleted: function (event, data) { },
//Localization
messages: {
deleteConfirmation: 'This record will be deleted. Are you sure?',
deleteText: 'Delete',
deleting: 'Deleting',
canNotDeletedRecords: 'Can not delete {0} of {1} records!',
deleteProggress: 'Deleting {0} of {1} records, processing...'
}
},
/************************************************************************
* PRIVATE FIELDS *
*************************************************************************/
_$deleteRecordDiv: null, //Reference to the adding new record dialog div (jQuery object)
_$deletingRow: null, //Reference to currently deleting row (jQuery object)
/************************************************************************
* CONSTRUCTOR *
*************************************************************************/
/* Overrides base method to do deletion-specific constructions.
*************************************************************************/
_create: function () {
base._create.apply(this, arguments);
this._createDeleteDialogDiv();
},
/* Creates and prepares delete record confirmation dialog div.
*************************************************************************/
_createDeleteDialogDiv: function () {
var self = this;
//Check if deleteAction is supplied
if (!self.options.actions.deleteAction) {
return;
}
//Create div element for delete confirmation dialog
self._$deleteRecordDiv = $('
').appendTo(self._$mainContainer);
//Prepare dialog
self._$deleteRecordDiv.dialog({
autoOpen: false,
show: self.options.dialogShowEffect,
hide: self.options.dialogHideEffect,
modal: true,
title: self.options.messages.areYouSure,
buttons:
[{ //cancel button
text: self.options.messages.cancel,
click: function () {
self._$deleteRecordDiv.dialog("close");
}
}, {//delete button
id: 'DeleteDialogButton',
text: self.options.messages.deleteText,
click: function () {
//row maybe removed by another source, if so, do nothing
if (self._$deletingRow.hasClass('jtable-row-removed')) {
self._$deleteRecordDiv.dialog('close');
return;
}
var $deleteButton = self._$deleteRecordDiv.parent().find('#DeleteDialogButton');
self._setEnabledOfDialogButton($deleteButton, false, self.options.messages.deleting);
self._deleteRecordFromServer(
self._$deletingRow,
function () {
self._removeRowsFromTableWithAnimation(self._$deletingRow);
self._$deleteRecordDiv.dialog('close');
},
function (message) { //error
self._showError(message);
self._setEnabledOfDialogButton($deleteButton, true, self.options.messages.deleteText);
}
);
}
}],
close: function () {
var $deleteButton = self._$deleteRecordDiv.parent().find('#DeleteDialogButton');
self._setEnabledOfDialogButton($deleteButton, true, self.options.messages.deleteText);
}
});
},
/************************************************************************
* PUBLIC METHODS *
*************************************************************************/
/* This method is used to delete one or more rows from server and the table.
*************************************************************************/
deleteRows: function ($rows) {
var self = this;
if ($rows.length <= 0) {
self._logWarn('No rows specified to jTable deleteRows method.');
return;
}
if (self._isBusy()) {
self._logWarn('Can not delete rows since jTable is busy!');
return;
}
//Deleting just one row
if ($rows.length == 1) {
self._deleteRecordFromServer(
$rows,
function () { //success
self._removeRowsFromTableWithAnimation($rows);
},
function (message) { //error
self._showError(message);
}
);
return;
}
//Deleting multiple rows
self._showBusy(self._formatString(self.options.messages.deleteProggress, 0, $rows.length));
//This method checks if deleting of all records is completed
var completedCount = 0;
var isCompleted = function () {
return (completedCount >= $rows.length);
};
//This method is called when deleting of all records completed
var completed = function () {
var $deletedRows = $rows.filter('.jtable-row-ready-to-remove');
if ($deletedRows.length < $rows.length) {
self._showError(self._formatString(self.options.messages.canNotDeletedRecords, $rows.length - $deletedRows.length, $rows.length));
}
if ($deletedRows.length > 0) {
self._removeRowsFromTableWithAnimation($deletedRows);
}
self._hideBusy();
};
//Delete all rows
var deletedCount = 0;
$rows.each(function () {
var $row = $(this);
self._deleteRecordFromServer(
$row,
function () { //success
++deletedCount; ++completedCount;
$row.addClass('jtable-row-ready-to-remove');
self._showBusy(self._formatString(self.options.messages.deleteProggress, deletedCount, $rows.length));
if (isCompleted()) {
completed();
}
},
function () { //error
++completedCount;
if (isCompleted()) {
completed();
}
}
);
});
},
/* Deletes a record from the table (optionally from the server also).
*************************************************************************/
deleteRecord: function (options) {
var self = this;
options = $.extend({
clientOnly: false,
animationsEnabled: self.options.animationsEnabled,
url: self.options.actions.deleteAction,
success: function () { },
error: function () { }
}, options);
if (options.key == undefined) {
self._logWarn('options parameter in deleteRecord method must contain a key property.');
return;
}
var $deletingRow = self.getRowByKey(options.key);
if ($deletingRow == null) {
self._logWarn('Can not found any row by key: ' + options.key);
return;
}
if (options.clientOnly) {
self._removeRowsFromTableWithAnimation($deletingRow, options.animationsEnabled);
options.success();
return;
}
self._deleteRecordFromServer(
$deletingRow,
function (data) { //success
self._removeRowsFromTableWithAnimation($deletingRow, options.animationsEnabled);
options.success(data);
},
function (message) { //error
self._showError(message);
options.error(message);
},
options.url
);
},
/************************************************************************
* OVERRIDED METHODS *
*************************************************************************/
/* Overrides base method to add a 'deletion column cell' to header row.
*************************************************************************/
_addColumnsToHeaderRow: function ($tr) {
base._addColumnsToHeaderRow.apply(this, arguments);
if (this.options.actions.deleteAction != undefined) {
$tr.append(this._createEmptyCommandHeader());
}
},
/* Overrides base method to add a 'delete command cell' to a row.
*************************************************************************/
_addCellsToRowUsingRecord: function ($row) {
base._addCellsToRowUsingRecord.apply(this, arguments);
var self = this;
if (self.options.actions.deleteAction != undefined) {
var $span = $('').html(self.options.messages.deleteText);
var $button = $('')
.addClass('jtable-command-button jtable-delete-command-button')
.append($span)
.click(function (e) {
e.preventDefault();
e.stopPropagation();
self._deleteButtonClickedForRow($row);
});
$('
')
.addClass('jtable-command-column')
.append($button)
.appendTo($row);
}
},
/************************************************************************
* PRIVATE METHODS *
*************************************************************************/
/* This method is called when user clicks delete button on a row.
*************************************************************************/
_deleteButtonClickedForRow: function ($row) {
var self = this;
var deleteConfirm;
var deleteConfirmMessage = self.options.messages.deleteConfirmation;
//If options.deleteConfirmation is function then call it
if ($.isFunction(self.options.deleteConfirmation)) {
var data = { row: $row, record: $row.data('record'), deleteConfirm: true, deleteConfirmMessage: deleteConfirmMessage, cancel: false, cancelMessage: null };
self.options.deleteConfirmation(data);
//If delete progress is cancelled
if (data.cancel) {
//If a canlellation reason is specified
if (data.cancelMessage) {
self._showError(data.cancelMessage); //TODO: show warning/stop message instead of error (also show warning/error ui icon)!
}
return;
}
deleteConfirmMessage = data.deleteConfirmMessage;
deleteConfirm = data.deleteConfirm;
} else {
deleteConfirm = self.options.deleteConfirmation;
}
if (deleteConfirm != false) {
//Confirmation
self._$deleteRecordDiv.find('.jtable-delete-confirm-message').html(deleteConfirmMessage);
self._showDeleteDialog($row);
} else {
//No confirmation
self._deleteRecordFromServer(
$row,
function () { //success
self._removeRowsFromTableWithAnimation($row);
},
function (message) { //error
self._showError(message);
}
);
}
},
/* Shows delete comfirmation dialog.
*************************************************************************/
_showDeleteDialog: function ($row) {
this._$deletingRow = $row;
this._$deleteRecordDiv.dialog('open');
},
/* Performs an ajax call to server to delete record
* and removes row of the record from table if ajax call success.
*************************************************************************/
_deleteRecordFromServer: function ($row, success, error, url) {
var self = this;
var completeDelete = function(data) {
if (data.Result != 'OK') {
$row.data('deleting', false);
if (error) {
error(data.Message);
}
return;
}
self._trigger("recordDeleted", null, { record: $row.data('record'), row: $row, serverResponse: data });
if (success) {
success(data);
}
};
//Check if it is already being deleted right now
if ($row.data('deleting') == true) {
return;
}
$row.data('deleting', true);
var postData = {};
postData[self._keyField] = self._getKeyValueOfRecord($row.data('record'));
//deleteAction may be a function, check if it is
if (!url && $.isFunction(self.options.actions.deleteAction)) {
//Execute the function
var funcResult = self.options.actions.deleteAction(postData);
//Check if result is a jQuery Deferred object
if (self._isDeferredObject(funcResult)) {
//Wait promise
funcResult.done(function (data) {
completeDelete(data);
}).fail(function () {
$row.data('deleting', false);
if (error) {
error(self.options.messages.serverCommunicationError);
}
});
} else { //assume it returned the deletion result
completeDelete(funcResult);
}
} else { //Assume it's a URL string
//Make ajax call to delete the record from server
this._ajax({
url: (url || self.options.actions.deleteAction),
data: postData,
success: function (data) {
completeDelete(data);
},
error: function () {
$row.data('deleting', false);
if (error) {
error(self.options.messages.serverCommunicationError);
}
}
});
}
},
/* Removes a row from table after a 'deleting' animation.
*************************************************************************/
_removeRowsFromTableWithAnimation: function ($rows, animationsEnabled) {
var self = this;
if (animationsEnabled == undefined) {
animationsEnabled = self.options.animationsEnabled;
}
if (animationsEnabled) {
var className = 'jtable-row-deleting';
if (this.options.jqueryuiTheme) {
className = className + ' ui-state-disabled';
}
//Stop current animation (if does exists) and begin 'deleting' animation.
$rows.stop(true, true).addClass(className, 'slow', '').promise().done(function () {
self._removeRowsFromTable($rows, 'deleted');
});
} else {
self._removeRowsFromTable($rows, 'deleted');
}
}
});
})(jQuery);