Merge commit '8997d5b1ff' as 'jtable'

This commit is contained in:
Mark Schouten 2016-08-05 13:20:31 +02:00
commit d90fb0d2a6
155 changed files with 22323 additions and 0 deletions

Binary file not shown.

View file

@ -0,0 +1,6 @@
jtable builder
======
Although you can manually merge all javascript files in order in jquery.jtable.build.txt file, you can use this tool to merge all javascript files and build jquery.jtable.js. Just run jTableBuilder-build.bat.
NOTE: It's a C# (.NET 4.0) application.

View file

@ -0,0 +1 @@
jTableBuilder.exe ..\jquery.jtable.build.txt

Binary file not shown.

View file

@ -0,0 +1,13 @@
create ..\jquery.jtable.js
add jquery.jtable.header.txt
add jquery.jtable.core.js
add jquery.jtable.utils.js
add jquery.jtable.forms.js
add jquery.jtable.creation.js
add jquery.jtable.editing.js
add jquery.jtable.deletion.js
add jquery.jtable.selecting.js
add jquery.jtable.paging.js
add jquery.jtable.sorting.js
add jquery.jtable.dynamiccolumns.js
add jquery.jtable.masterchild.js

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,348 @@
/************************************************************************
* CREATE RECORD extension for jTable *
*************************************************************************/
(function ($) {
//Reference to base object members
var base = {
_create: $.hik.jtable.prototype._create
};
//extension members
$.extend(true, $.hik.jtable.prototype, {
/************************************************************************
* DEFAULT OPTIONS / EVENTS *
*************************************************************************/
options: {
//Events
recordAdded: function (event, data) { },
//Localization
messages: {
addNewRecord: 'Add new record'
}
},
/************************************************************************
* PRIVATE FIELDS *
*************************************************************************/
_$addRecordDiv: null, //Reference to the adding new record dialog div (jQuery object)
/************************************************************************
* CONSTRUCTOR *
*************************************************************************/
/* Overrides base method to do create-specific constructions.
*************************************************************************/
_create: function () {
base._create.apply(this, arguments);
if (!this.options.actions.createAction) {
return;
}
this._createAddRecordDialogDiv();
},
/* Creates and prepares add new record dialog div
*************************************************************************/
_createAddRecordDialogDiv: function () {
var self = this;
//Create a div for dialog and add to container element
self._$addRecordDiv = $('<div />')
.appendTo(self._$mainContainer);
//Prepare dialog
self._$addRecordDiv.dialog({
autoOpen: false,
show: self.options.dialogShowEffect,
hide: self.options.dialogHideEffect,
width: 'auto',
minWidth: '300',
modal: true,
title: self.options.messages.addNewRecord,
buttons:
[{ //Cancel button
text: self.options.messages.cancel,
click: function () {
self._$addRecordDiv.dialog('close');
}
}, { //Save button
id: 'AddRecordDialogSaveButton',
text: self.options.messages.save,
click: function () {
self._onSaveClickedOnCreateForm();
}
}],
close: function () {
var $addRecordForm = self._$addRecordDiv.find('form').first();
var $saveButton = self._$addRecordDiv.parent().find('#AddRecordDialogSaveButton');
self._trigger("formClosed", null, { form: $addRecordForm, formType: 'create' });
self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
$addRecordForm.remove();
}
});
if (self.options.addRecordButton) {
//If user supplied a button, bind the click event to show dialog form
self.options.addRecordButton.click(function (e) {
e.preventDefault();
self._showAddRecordForm();
});
} else {
//If user did not supplied a button, create a 'add record button' toolbar item.
self._addToolBarItem({
icon: true,
cssClass: 'jtable-toolbar-item-add-record',
text: self.options.messages.addNewRecord,
click: function () {
self._showAddRecordForm();
}
});
}
},
_onSaveClickedOnCreateForm: function () {
var self = this;
var $saveButton = self._$addRecordDiv.parent().find('#AddRecordDialogSaveButton');
var $addRecordForm = self._$addRecordDiv.find('form');
if (self._trigger("formSubmitting", null, { form: $addRecordForm, formType: 'create' }) != false) {
self._setEnabledOfDialogButton($saveButton, false, self.options.messages.saving);
self._saveAddRecordForm($addRecordForm, $saveButton);
}
},
/************************************************************************
* PUBLIC METHODS *
*************************************************************************/
/* Shows add new record dialog form.
*************************************************************************/
showCreateForm: function () {
this._showAddRecordForm();
},
/* Adds a new record to the table (optionally to the server also)
*************************************************************************/
addRecord: function (options) {
var self = this;
options = $.extend({
clientOnly: false,
animationsEnabled: self.options.animationsEnabled,
success: function () { },
error: function () { }
}, options);
if (!options.record) {
self._logWarn('options parameter in addRecord method must contain a record property.');
return;
}
if (options.clientOnly) {
self._addRow(
self._createRowFromRecord(options.record), {
isNewRow: true,
animationsEnabled: options.animationsEnabled
});
options.success();
return;
}
var completeAddRecord = function (data) {
if (data.Result != 'OK') {
self._showError(data.Message);
options.error(data);
return;
}
if (!data.Record) {
self._logError('Server must return the created Record object.');
options.error(data);
return;
}
self._onRecordAdded(data);
self._addRow(
self._createRowFromRecord(data.Record), {
isNewRow: true,
animationsEnabled: options.animationsEnabled
});
options.success(data);
};
//createAction may be a function, check if it is
if (!options.url && $.isFunction(self.options.actions.createAction)) {
//Execute the function
var funcResult = self.options.actions.createAction($.param(options.record));
//Check if result is a jQuery Deferred object
if (self._isDeferredObject(funcResult)) {
//Wait promise
funcResult.done(function (data) {
completeAddRecord(data);
}).fail(function () {
self._showError(self.options.messages.serverCommunicationError);
options.error();
});
} else { //assume it returned the creation result
completeAddRecord(funcResult);
}
} else { //Assume it's a URL string
//Make an Ajax call to create record
self._submitFormUsingAjax(
options.url || self.options.actions.createAction,
$.param(options.record),
function (data) {
completeAddRecord(data);
},
function () {
self._showError(self.options.messages.serverCommunicationError);
options.error();
});
}
},
/************************************************************************
* PRIVATE METHODS *
*************************************************************************/
/* Shows add new record dialog form.
*************************************************************************/
_showAddRecordForm: function () {
var self = this;
//Create add new record form
var $addRecordForm = $('<form id="jtable-create-form" class="jtable-dialog-form jtable-create-form"></form>');
//Create input elements
for (var i = 0; i < self._fieldList.length; i++) {
var fieldName = self._fieldList[i];
var field = self.options.fields[fieldName];
//Do not create input for fields that is key and not specially marked as creatable
if (field.key == true && field.create != true) {
continue;
}
//Do not create input for fields that are not creatable
if (field.create == false) {
continue;
}
if (field.type == 'hidden') {
$addRecordForm.append(self._createInputForHidden(fieldName, field.defaultValue));
continue;
}
//Create a container div for this input field and add to form
var $fieldContainer = $('<div />')
.addClass('jtable-input-field-container')
.appendTo($addRecordForm);
//Create a label for input
$fieldContainer.append(self._createInputLabelForRecordField(fieldName));
//Create input element
$fieldContainer.append(
self._createInputForRecordField({
fieldName: fieldName,
formType: 'create',
form: $addRecordForm
}));
}
self._makeCascadeDropDowns($addRecordForm, undefined, 'create');
$addRecordForm.submit(function () {
self._onSaveClickedOnCreateForm();
return false;
});
//Open the form
self._$addRecordDiv.append($addRecordForm).dialog('open');
self._trigger("formCreated", null, { form: $addRecordForm, formType: 'create' });
},
/* Saves new added record to the server and updates table.
*************************************************************************/
_saveAddRecordForm: function ($addRecordForm, $saveButton) {
var self = this;
var completeAddRecord = function (data) {
if (data.Result != 'OK') {
self._showError(data.Message);
self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
return;
}
if (!data.Record) {
self._logError('Server must return the created Record object.');
self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
return;
}
self._onRecordAdded(data);
self._addRow(
self._createRowFromRecord(data.Record), {
isNewRow: true
});
self._$addRecordDiv.dialog("close");
};
$addRecordForm.data('submitting', true); //TODO: Why it's used, can remove? Check it.
//createAction may be a function, check if it is
if ($.isFunction(self.options.actions.createAction)) {
//Execute the function
var funcResult = self.options.actions.createAction($addRecordForm.serialize());
//Check if result is a jQuery Deferred object
if (self._isDeferredObject(funcResult)) {
//Wait promise
funcResult.done(function (data) {
completeAddRecord(data);
}).fail(function () {
self._showError(self.options.messages.serverCommunicationError);
self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
});
} else { //assume it returned the creation result
completeAddRecord(funcResult);
}
} else { //Assume it's a URL string
//Make an Ajax call to create record
self._submitFormUsingAjax(
self.options.actions.createAction,
$addRecordForm.serialize(),
function (data) {
completeAddRecord(data);
},
function () {
self._showError(self.options.messages.serverCommunicationError);
self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
});
}
},
_onRecordAdded: function (data) {
this._trigger("recordAdded", null, { record: data.Record, serverResponse: data });
}
});
})(jQuery);

View file

@ -0,0 +1,432 @@
/************************************************************************
* 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 = $('<div><p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span><span class="jtable-delete-confirm-message"></span></p></div>').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 = $('<span></span>').html(self.options.messages.deleteText);
var $button = $('<button title="' + self.options.messages.deleteText + '"></button>')
.addClass('jtable-command-button jtable-delete-command-button')
.append($span)
.click(function (e) {
e.preventDefault();
e.stopPropagation();
self._deleteButtonClickedForRow($row);
});
$('<td></td>')
.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);

View file

@ -0,0 +1,461 @@
/************************************************************************
* DYNAMIC COLUMNS extension for jTable *
* (Show/hide/resize columns) *
*************************************************************************/
(function ($) {
//Reference to base object members
var base = {
_create: $.hik.jtable.prototype._create,
_normalizeFieldOptions: $.hik.jtable.prototype._normalizeFieldOptions,
_createHeaderCellForField: $.hik.jtable.prototype._createHeaderCellForField,
_createCellForRecordField: $.hik.jtable.prototype._createCellForRecordField
};
//extension members
$.extend(true, $.hik.jtable.prototype, {
/************************************************************************
* DEFAULT OPTIONS / EVENTS *
*************************************************************************/
options: {
tableId: undefined,
columnResizable: true,
columnSelectable: true
},
/************************************************************************
* PRIVATE FIELDS *
*************************************************************************/
_$columnSelectionDiv: null,
_$columnResizeBar: null,
_cookieKeyPrefix: null,
_currentResizeArgs: null,
/************************************************************************
* OVERRIDED METHODS *
*************************************************************************/
/* Overrides _addRowToTableHead method.
*************************************************************************/
_create: function () {
base._create.apply(this, arguments);
this._createColumnResizeBar();
this._createColumnSelection();
if (this.options.saveUserPreferences) {
this._loadColumnSettings();
}
this._normalizeColumnWidths();
},
/* Normalizes some options for a field (sets default values).
*************************************************************************/
_normalizeFieldOptions: function (fieldName, props) {
base._normalizeFieldOptions.apply(this, arguments);
//columnResizable
if (this.options.columnResizable) {
props.columnResizable = (props.columnResizable != false);
}
//visibility
if (!props.visibility) {
props.visibility = 'visible';
}
},
/* Overrides _createHeaderCellForField to make columns dynamic.
*************************************************************************/
_createHeaderCellForField: function (fieldName, field) {
var $headerCell = base._createHeaderCellForField.apply(this, arguments);
//Make data columns resizable except the last one
if (this.options.columnResizable && field.columnResizable && (fieldName != this._columnList[this._columnList.length - 1])) {
this._makeColumnResizable($headerCell);
}
//Hide column if needed
if (field.visibility == 'hidden') {
$headerCell.hide();
}
return $headerCell;
},
/* Overrides _createHeaderCellForField to decide show or hide a column.
*************************************************************************/
_createCellForRecordField: function (record, fieldName) {
var $column = base._createCellForRecordField.apply(this, arguments);
var field = this.options.fields[fieldName];
if (field.visibility == 'hidden') {
$column.hide();
}
return $column;
},
/************************************************************************
* PUBLIC METHODS *
*************************************************************************/
/* Changes visibility of a column.
*************************************************************************/
changeColumnVisibility: function (columnName, visibility) {
this._changeColumnVisibilityInternal(columnName, visibility);
this._normalizeColumnWidths();
if (this.options.saveUserPreferences) {
this._saveColumnSettings();
}
},
/************************************************************************
* PRIVATE METHODS *
*************************************************************************/
/* Changes visibility of a column.
*************************************************************************/
_changeColumnVisibilityInternal: function (columnName, visibility) {
//Check if there is a column with given name
var columnIndex = this._columnList.indexOf(columnName);
if (columnIndex < 0) {
this._logWarn('Column "' + columnName + '" does not exist in fields!');
return;
}
//Check if visibility value is valid
if (['visible', 'hidden', 'fixed'].indexOf(visibility) < 0) {
this._logWarn('Visibility value is not valid: "' + visibility + '"! Options are: visible, hidden, fixed.');
return;
}
//Get the field
var field = this.options.fields[columnName];
if (field.visibility == visibility) {
return; //No action if new value is same as old one.
}
//Hide or show the column if needed
var columnIndexInTable = this._firstDataColumnOffset + columnIndex + 1;
if (field.visibility != 'hidden' && visibility == 'hidden') {
this._$table
.find('>thead >tr >th:nth-child(' + columnIndexInTable + '),>tbody >tr >td:nth-child(' + columnIndexInTable + ')')
.hide();
} else if (field.visibility == 'hidden' && visibility != 'hidden') {
this._$table
.find('>thead >tr >th:nth-child(' + columnIndexInTable + '),>tbody >tr >td:nth-child(' + columnIndexInTable + ')')
.show()
.css('display', 'table-cell');
}
field.visibility = visibility;
},
/* Prepares dialog to change settings.
*************************************************************************/
_createColumnSelection: function () {
var self = this;
//Create a div for dialog and add to container element
this._$columnSelectionDiv = $('<div />')
.addClass('jtable-column-selection-container')
.appendTo(self._$mainContainer);
this._$table.children('thead').bind('contextmenu', function (e) {
if (!self.options.columnSelectable) {
return;
}
e.preventDefault();
//Make an overlay div to disable page clicks
$('<div />')
.addClass('jtable-contextmenu-overlay')
.click(function () {
$(this).remove();
self._$columnSelectionDiv.hide();
})
.bind('contextmenu', function () { return false; })
.appendTo(document.body);
self._fillColumnSelection();
//Calculate position of column selection list and show it
var containerOffset = self._$mainContainer.offset();
var selectionDivTop = e.pageY - containerOffset.top;
var selectionDivLeft = e.pageX - containerOffset.left;
var selectionDivMinWidth = 100; //in pixels
var containerWidth = self._$mainContainer.width();
//If user clicks right area of header of the table, show list at a little left
if ((containerWidth > selectionDivMinWidth) && (selectionDivLeft > (containerWidth - selectionDivMinWidth))) {
selectionDivLeft = containerWidth - selectionDivMinWidth;
}
self._$columnSelectionDiv.css({
left: selectionDivLeft,
top: selectionDivTop,
'min-width': selectionDivMinWidth + 'px'
}).show();
});
},
/* Prepares content of settings dialog.
*************************************************************************/
_fillColumnSelection: function () {
var self = this;
var $columnsUl = $('<ul></ul>')
.addClass('jtable-column-select-list');
for (var i = 0; i < this._columnList.length; i++) {
var columnName = this._columnList[i];
var field = this.options.fields[columnName];
//Crete li element
var $columnLi = $('<li></li>').appendTo($columnsUl);
//Create label for the checkbox
var $label = $('<label for="' + columnName + '"></label>')
.append($('<span>' + (field.title || columnName) + '</span>'))
.appendTo($columnLi);
//Create checkbox
var $checkbox = $('<input type="checkbox" name="' + columnName + '">')
.prependTo($label)
.click(function () {
var $clickedCheckbox = $(this);
var clickedColumnName = $clickedCheckbox.attr('name');
var clickedField = self.options.fields[clickedColumnName];
if (clickedField.visibility == 'fixed') {
return;
}
self.changeColumnVisibility(clickedColumnName, $clickedCheckbox.is(':checked') ? 'visible' : 'hidden');
});
//Check, if column if shown
if (field.visibility != 'hidden') {
$checkbox.attr('checked', 'checked');
}
//Disable, if column is fixed
if (field.visibility == 'fixed') {
$checkbox.attr('disabled', 'disabled');
}
}
this._$columnSelectionDiv.html($columnsUl);
},
/* creates a vertical bar that is shown while resizing columns.
*************************************************************************/
_createColumnResizeBar: function () {
this._$columnResizeBar = $('<div />')
.addClass('jtable-column-resize-bar')
.appendTo(this._$mainContainer)
.hide();
},
/* Makes a column sortable.
*************************************************************************/
_makeColumnResizable: function ($columnHeader) {
var self = this;
//Create a handler to handle mouse click event
$('<div />')
.addClass('jtable-column-resize-handler')
.appendTo($columnHeader.find('.jtable-column-header-container')) //Append the handler to the column
.mousedown(function (downevent) { //handle mousedown event for the handler
downevent.preventDefault();
downevent.stopPropagation();
var mainContainerOffset = self._$mainContainer.offset();
//Get a reference to the next column
var $nextColumnHeader = $columnHeader.nextAll('th.jtable-column-header:visible:first');
if (!$nextColumnHeader.length) {
return;
}
//Store some information to be used on resizing
var minimumColumnWidth = 10; //A column's width can not be smaller than 10 pixel.
self._currentResizeArgs = {
currentColumnStartWidth: $columnHeader.outerWidth(),
minWidth: minimumColumnWidth,
maxWidth: $columnHeader.outerWidth() + $nextColumnHeader.outerWidth() - minimumColumnWidth,
mouseStartX: downevent.pageX,
minResizeX: function () { return this.mouseStartX - (this.currentColumnStartWidth - this.minWidth); },
maxResizeX: function () { return this.mouseStartX + (this.maxWidth - this.currentColumnStartWidth); }
};
//Handle mouse move event to move resizing bar
var resizeonmousemove = function (moveevent) {
if (!self._currentResizeArgs) {
return;
}
var resizeBarX = self._normalizeNumber(moveevent.pageX, self._currentResizeArgs.minResizeX(), self._currentResizeArgs.maxResizeX());
self._$columnResizeBar.css('left', (resizeBarX - mainContainerOffset.left) + 'px');
};
//Handle mouse up event to finish resizing of the column
var resizeonmouseup = function (upevent) {
if (!self._currentResizeArgs) {
return;
}
$(document).unbind('mousemove', resizeonmousemove);
$(document).unbind('mouseup', resizeonmouseup);
self._$columnResizeBar.hide();
//Calculate new widths in pixels
var mouseChangeX = upevent.pageX - self._currentResizeArgs.mouseStartX;
var currentColumnFinalWidth = self._normalizeNumber(self._currentResizeArgs.currentColumnStartWidth + mouseChangeX, self._currentResizeArgs.minWidth, self._currentResizeArgs.maxWidth);
var nextColumnFinalWidth = $nextColumnHeader.outerWidth() + (self._currentResizeArgs.currentColumnStartWidth - currentColumnFinalWidth);
//Calculate widths as percent
var pixelToPercentRatio = $columnHeader.data('width-in-percent') / self._currentResizeArgs.currentColumnStartWidth;
$columnHeader.data('width-in-percent', currentColumnFinalWidth * pixelToPercentRatio);
$nextColumnHeader.data('width-in-percent', nextColumnFinalWidth * pixelToPercentRatio);
//Set new widths to columns (resize!)
$columnHeader.css('width', $columnHeader.data('width-in-percent') + '%');
$nextColumnHeader.css('width', $nextColumnHeader.data('width-in-percent') + '%');
//Normalize all column widths
self._normalizeColumnWidths();
//Finish resizing
self._currentResizeArgs = null;
//Save current preferences
if (self.options.saveUserPreferences) {
self._saveColumnSettings();
}
};
//Show vertical resize bar
self._$columnResizeBar
.show()
.css({
top: ($columnHeader.offset().top - mainContainerOffset.top) + 'px',
left: (downevent.pageX - mainContainerOffset.left) + 'px',
height: (self._$table.outerHeight()) + 'px'
});
//Bind events
$(document).bind('mousemove', resizeonmousemove);
$(document).bind('mouseup', resizeonmouseup);
});
},
/* Normalizes column widths as percent for current view.
*************************************************************************/
_normalizeColumnWidths: function () {
//Set command column width
var commandColumnHeaders = this._$table
.find('>thead th.jtable-command-column-header')
.data('width-in-percent', 1)
.css('width', '1%');
//Find data columns
var headerCells = this._$table.find('>thead th.jtable-column-header');
//Calculate total width of data columns
var totalWidthInPixel = 0;
headerCells.each(function () {
var $cell = $(this);
if ($cell.is(':visible')) {
totalWidthInPixel += $cell.outerWidth();
}
});
//Calculate width of each column
var columnWidhts = {};
var availableWidthInPercent = 100.0 - commandColumnHeaders.length;
headerCells.each(function () {
var $cell = $(this);
if ($cell.is(':visible')) {
var fieldName = $cell.data('fieldName');
var widthInPercent = $cell.outerWidth() * availableWidthInPercent / totalWidthInPixel;
columnWidhts[fieldName] = widthInPercent;
}
});
//Set width of each column
headerCells.each(function () {
var $cell = $(this);
if ($cell.is(':visible')) {
var fieldName = $cell.data('fieldName');
$cell.data('width-in-percent', columnWidhts[fieldName]).css('width', columnWidhts[fieldName] + '%');
}
});
},
/* Saves field setting to cookie.
* Saved setting will be a string like that:
* fieldName1=visible;23|fieldName2=hidden;17|...
*************************************************************************/
_saveColumnSettings: function () {
var self = this;
var fieldSettings = '';
this._$table.find('>thead >tr >th.jtable-column-header').each(function () {
var $cell = $(this);
var fieldName = $cell.data('fieldName');
var columnWidth = $cell.data('width-in-percent');
var fieldVisibility = self.options.fields[fieldName].visibility;
var fieldSetting = fieldName + "=" + fieldVisibility + ';' + columnWidth;
fieldSettings = fieldSettings + fieldSetting + '|';
});
this._setCookie('column-settings', fieldSettings.substr(0, fieldSettings.length - 1));
},
/* Loads field settings from cookie that is saved by _saveFieldSettings method.
*************************************************************************/
_loadColumnSettings: function () {
var self = this;
var columnSettingsCookie = this._getCookie('column-settings');
if (!columnSettingsCookie) {
return;
}
var columnSettings = {};
$.each(columnSettingsCookie.split('|'), function (inx, fieldSetting) {
var splitted = fieldSetting.split('=');
var fieldName = splitted[0];
var settings = splitted[1].split(';');
columnSettings[fieldName] = {
columnVisibility: settings[0],
columnWidth: settings[1]
};
});
var headerCells = this._$table.find('>thead >tr >th.jtable-column-header');
headerCells.each(function () {
var $cell = $(this);
var fieldName = $cell.data('fieldName');
var field = self.options.fields[fieldName];
if (columnSettings[fieldName]) {
if (field.visibility != 'fixed') {
self._changeColumnVisibilityInternal(fieldName, columnSettings[fieldName].columnVisibility);
}
$cell.data('width-in-percent', columnSettings[fieldName].columnWidth).css('width', columnSettings[fieldName].columnWidth + '%');
}
});
}
});
})(jQuery);

View file

@ -0,0 +1,452 @@
/************************************************************************
* EDIT RECORD 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: {
//Events
recordUpdated: function (event, data) { },
rowUpdated: function (event, data) { },
//Localization
messages: {
editRecord: 'Edit Record'
}
},
/************************************************************************
* PRIVATE FIELDS *
*************************************************************************/
_$editDiv: null, //Reference to the editing dialog div (jQuery object)
_$editingRow: null, //Reference to currently editing row (jQuery object)
/************************************************************************
* CONSTRUCTOR AND INITIALIZATION METHODS *
*************************************************************************/
/* Overrides base method to do editing-specific constructions.
*************************************************************************/
_create: function () {
base._create.apply(this, arguments);
if (!this.options.actions.updateAction) {
return;
}
this._createEditDialogDiv();
},
/* Creates and prepares edit dialog div
*************************************************************************/
_createEditDialogDiv: function () {
var self = this;
//Create a div for dialog and add to container element
self._$editDiv = $('<div></div>')
.appendTo(self._$mainContainer);
//Prepare dialog
self._$editDiv.dialog({
autoOpen: false,
show: self.options.dialogShowEffect,
hide: self.options.dialogHideEffect,
width: 'auto',
minWidth: '300',
modal: true,
title: self.options.messages.editRecord,
buttons:
[{ //cancel button
text: self.options.messages.cancel,
click: function () {
self._$editDiv.dialog('close');
}
}, { //save button
id: 'EditDialogSaveButton',
text: self.options.messages.save,
click: function () {
self._onSaveClickedOnEditForm();
}
}],
close: function () {
var $editForm = self._$editDiv.find('form:first');
var $saveButton = self._$editDiv.parent().find('#EditDialogSaveButton');
self._trigger("formClosed", null, { form: $editForm, formType: 'edit', row: self._$editingRow });
self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
$editForm.remove();
}
});
},
/* Saves editing form to server.
*************************************************************************/
_onSaveClickedOnEditForm: function () {
var self = this;
//row maybe removed by another source, if so, do nothing
if (self._$editingRow.hasClass('jtable-row-removed')) {
self._$editDiv.dialog('close');
return;
}
var $saveButton = self._$editDiv.parent().find('#EditDialogSaveButton');
var $editForm = self._$editDiv.find('form');
if (self._trigger("formSubmitting", null, { form: $editForm, formType: 'edit', row: self._$editingRow }) != false) {
self._setEnabledOfDialogButton($saveButton, false, self.options.messages.saving);
self._saveEditForm($editForm, $saveButton);
}
},
/************************************************************************
* PUBLIC METHODS *
*************************************************************************/
/* Updates a record on the table (optionally on the server also)
*************************************************************************/
updateRecord: function (options) {
var self = this;
options = $.extend({
clientOnly: false,
animationsEnabled: self.options.animationsEnabled,
success: function () { },
error: function () { }
}, options);
if (!options.record) {
self._logWarn('options parameter in updateRecord method must contain a record property.');
return;
}
var key = self._getKeyValueOfRecord(options.record);
if (key == undefined || key == null) {
self._logWarn('options parameter in updateRecord method must contain a record that contains the key field property.');
return;
}
var $updatingRow = self.getRowByKey(key);
if ($updatingRow == null) {
self._logWarn('Can not found any row by key "' + key + '" on the table. Updating row must be visible on the table.');
return;
}
if (options.clientOnly) {
$.extend($updatingRow.data('record'), options.record);
self._updateRowTexts($updatingRow);
self._onRecordUpdated($updatingRow, null);
if (options.animationsEnabled) {
self._showUpdateAnimationForRow($updatingRow);
}
options.success();
return;
}
var completeEdit = function (data) {
if (data.Result != 'OK') {
self._showError(data.Message);
options.error(data);
return;
}
$.extend($updatingRow.data('record'), options.record);
self._updateRecordValuesFromServerResponse($updatingRow.data('record'), data);
self._updateRowTexts($updatingRow);
self._onRecordUpdated($updatingRow, data);
if (options.animationsEnabled) {
self._showUpdateAnimationForRow($updatingRow);
}
options.success(data);
};
//updateAction may be a function, check if it is
if (!options.url && $.isFunction(self.options.actions.updateAction)) {
//Execute the function
var funcResult = self.options.actions.updateAction($.param(options.record));
//Check if result is a jQuery Deferred object
if (self._isDeferredObject(funcResult)) {
//Wait promise
funcResult.done(function (data) {
completeEdit(data);
}).fail(function () {
self._showError(self.options.messages.serverCommunicationError);
options.error();
});
} else { //assume it returned the creation result
completeEdit(funcResult);
}
} else { //Assume it's a URL string
//Make an Ajax call to create record
self._submitFormUsingAjax(
options.url || self.options.actions.updateAction,
$.param(options.record),
function (data) {
completeEdit(data);
},
function () {
self._showError(self.options.messages.serverCommunicationError);
options.error();
});
}
},
/************************************************************************
* OVERRIDED METHODS *
*************************************************************************/
/* Overrides base method to add a 'editing column cell' to header row.
*************************************************************************/
_addColumnsToHeaderRow: function ($tr) {
base._addColumnsToHeaderRow.apply(this, arguments);
if (this.options.actions.updateAction != undefined) {
$tr.append(this._createEmptyCommandHeader());
}
},
/* Overrides base method to add a 'edit command cell' to a row.
*************************************************************************/
_addCellsToRowUsingRecord: function ($row) {
var self = this;
base._addCellsToRowUsingRecord.apply(this, arguments);
if (self.options.actions.updateAction != undefined) {
var $span = $('<span></span>').html(self.options.messages.editRecord);
var $button = $('<button title="' + self.options.messages.editRecord + '"></button>')
.addClass('jtable-command-button jtable-edit-command-button')
.append($span)
.click(function (e) {
e.preventDefault();
e.stopPropagation();
self._showEditForm($row);
});
$('<td></td>')
.addClass('jtable-command-column')
.append($button)
.appendTo($row);
}
},
/************************************************************************
* PRIVATE METHODS *
*************************************************************************/
/* Shows edit form for a row.
*************************************************************************/
_showEditForm: function ($tableRow) {
var self = this;
var record = $tableRow.data('record');
//Create edit form
var $editForm = $('<form id="jtable-edit-form" class="jtable-dialog-form jtable-edit-form"></form>');
//Create input fields
for (var i = 0; i < self._fieldList.length; i++) {
var fieldName = self._fieldList[i];
var field = self.options.fields[fieldName];
var fieldValue = record[fieldName];
if (field.key == true) {
if (field.edit != true) {
//Create hidden field for key
$editForm.append(self._createInputForHidden(fieldName, fieldValue));
continue;
} else {
//Create a special hidden field for key (since key is be editable)
$editForm.append(self._createInputForHidden('jtRecordKey', fieldValue));
}
}
//Do not create element for non-editable fields
if (field.edit == false) {
continue;
}
//Hidden field
if (field.type == 'hidden') {
$editForm.append(self._createInputForHidden(fieldName, fieldValue));
continue;
}
//Create a container div for this input field and add to form
var $fieldContainer = $('<div class="jtable-input-field-container"></div>').appendTo($editForm);
//Create a label for input
$fieldContainer.append(self._createInputLabelForRecordField(fieldName));
//Create input element with it's current value
var currentValue = self._getValueForRecordField(record, fieldName);
$fieldContainer.append(
self._createInputForRecordField({
fieldName: fieldName,
value: currentValue,
record: record,
formType: 'edit',
form: $editForm
}));
}
self._makeCascadeDropDowns($editForm, record, 'edit');
$editForm.submit(function () {
self._onSaveClickedOnEditForm();
return false;
});
//Open dialog
self._$editingRow = $tableRow;
self._$editDiv.append($editForm).dialog('open');
self._trigger("formCreated", null, { form: $editForm, formType: 'edit', record: record, row: $tableRow });
},
/* Saves editing form to the server and updates the record on the table.
*************************************************************************/
_saveEditForm: function ($editForm, $saveButton) {
var self = this;
var completeEdit = function (data) {
if (data.Result != 'OK') {
self._showError(data.Message);
self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
return;
}
var record = self._$editingRow.data('record');
self._updateRecordValuesFromForm(record, $editForm);
self._updateRecordValuesFromServerResponse(record, data);
self._updateRowTexts(self._$editingRow);
self._$editingRow.attr('data-record-key', self._getKeyValueOfRecord(record));
self._onRecordUpdated(self._$editingRow, data);
if (self.options.animationsEnabled) {
self._showUpdateAnimationForRow(self._$editingRow);
}
self._$editDiv.dialog("close");
};
//updateAction may be a function, check if it is
if ($.isFunction(self.options.actions.updateAction)) {
//Execute the function
var funcResult = self.options.actions.updateAction($editForm.serialize());
//Check if result is a jQuery Deferred object
if (self._isDeferredObject(funcResult)) {
//Wait promise
funcResult.done(function (data) {
completeEdit(data);
}).fail(function () {
self._showError(self.options.messages.serverCommunicationError);
self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
});
} else { //assume it returned the creation result
completeEdit(funcResult);
}
} else { //Assume it's a URL string
//Make an Ajax call to update record
self._submitFormUsingAjax(
self.options.actions.updateAction,
$editForm.serialize(),
function(data) {
completeEdit(data);
},
function() {
self._showError(self.options.messages.serverCommunicationError);
self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
});
}
},
/* This method ensures updating of current record with server response,
* if server sends a Record object as response to updateAction.
*************************************************************************/
_updateRecordValuesFromServerResponse: function (record, serverResponse) {
if (!serverResponse || !serverResponse.Record) {
return;
}
$.extend(true, record, serverResponse.Record);
},
/* Gets text for a field of a record according to it's type.
*************************************************************************/
_getValueForRecordField: function (record, fieldName) {
var field = this.options.fields[fieldName];
var fieldValue = record[fieldName];
if (field.type == 'date') {
return this._getDisplayTextForDateRecordField(field, fieldValue);
} else {
return fieldValue;
}
},
/* Updates cells of a table row's text values from row's record values.
*************************************************************************/
_updateRowTexts: function ($tableRow) {
var record = $tableRow.data('record');
var $columns = $tableRow.find('td');
for (var i = 0; i < this._columnList.length; i++) {
var displayItem = this._getDisplayTextForRecordField(record, this._columnList[i]);
if ((displayItem === 0)) displayItem = "0";
$columns.eq(this._firstDataColumnOffset + i).html(displayItem || '');
}
this._onRowUpdated($tableRow);
},
/* Shows 'updated' animation for a table row.
*************************************************************************/
_showUpdateAnimationForRow: function ($tableRow) {
var className = 'jtable-row-updated';
if (this.options.jqueryuiTheme) {
className = className + ' ui-state-highlight';
}
$tableRow.stop(true, true).addClass(className, 'slow', '', function () {
$tableRow.removeClass(className, 5000);
});
},
/************************************************************************
* EVENT RAISING METHODS *
*************************************************************************/
_onRowUpdated: function ($row) {
this._trigger("rowUpdated", null, { row: $row, record: $row.data('record') });
},
_onRecordUpdated: function ($row, data) {
this._trigger("recordUpdated", null, { record: $row.data('record'), row: $row, serverResponse: data });
}
});
})(jQuery);

View file

@ -0,0 +1,483 @@
/************************************************************************
* FORMS extension for jTable (base for edit/create forms) *
*************************************************************************/
(function ($) {
$.extend(true, $.hik.jtable.prototype, {
/************************************************************************
* PRIVATE METHODS *
*************************************************************************/
/* Submits a form asynchronously using AJAX.
* This method is needed, since form submitting logic can be overrided
* by extensions.
*************************************************************************/
_submitFormUsingAjax: function (url, formData, success, error) {
this._ajax({
url: url,
data: formData,
success: success,
error: error
});
},
/* Creates label for an input element.
*************************************************************************/
_createInputLabelForRecordField: function (fieldName) {
//TODO: May create label tag instead of a div.
return $('<div />')
.addClass('jtable-input-label')
.html(this.options.fields[fieldName].inputTitle || this.options.fields[fieldName].title);
},
/* Creates an input element according to field type.
*************************************************************************/
_createInputForRecordField: function (funcParams) {
var fieldName = funcParams.fieldName,
value = funcParams.value,
record = funcParams.record,
formType = funcParams.formType,
form = funcParams.form;
//Get the field
var field = this.options.fields[fieldName];
//If value if not supplied, use defaultValue of the field
if (value == undefined || value == null) {
value = field.defaultValue;
}
//Use custom function if supplied
if (field.input) {
var $input = $(field.input({
value: value,
record: record,
formType: formType,
form: form
}));
//Add id attribute if does not exists
if (!$input.attr('id')) {
$input.attr('id', 'Edit-' + fieldName);
}
//Wrap input element with div
return $('<div />')
.addClass('jtable-input jtable-custom-input')
.append($input);
}
//Create input according to field type
if (field.type == 'date') {
return this._createDateInputForField(field, fieldName, value);
} else if (field.type == 'textarea') {
return this._createTextAreaForField(field, fieldName, value);
} else if (field.type == 'password') {
return this._createPasswordInputForField(field, fieldName, value);
} else if (field.type == 'checkbox') {
return this._createCheckboxForField(field, fieldName, value);
} else if (field.options) {
if (field.type == 'radiobutton') {
return this._createRadioButtonListForField(field, fieldName, value, record, formType);
} else {
return this._createDropDownListForField(field, fieldName, value, record, formType, form);
}
} else {
return this._createTextInputForField(field, fieldName, value);
}
},
//Creates a hidden input element with given name and value.
_createInputForHidden: function (fieldName, value) {
if (value == undefined) {
value = "";
}
return $('<input type="hidden" name="' + fieldName + '" id="Edit-' + fieldName + '"></input>')
.val(value);
},
/* Creates a date input for a field.
*************************************************************************/
_createDateInputForField: function (field, fieldName, value) {
var $input = $('<input class="' + field.inputClass + '" id="Edit-' + fieldName + '" type="text" name="' + fieldName + '"></input>');
if(value != undefined) {
$input.val(value);
}
var displayFormat = field.displayFormat || this.options.defaultDateFormat;
$input.datepicker({ dateFormat: displayFormat });
return $('<div />')
.addClass('jtable-input jtable-date-input')
.append($input);
},
/* Creates a textarea element for a field.
*************************************************************************/
_createTextAreaForField: function (field, fieldName, value) {
var $textArea = $('<textarea class="' + field.inputClass + '" id="Edit-' + fieldName + '" name="' + fieldName + '"></textarea>');
if (value != undefined) {
$textArea.val(value);
}
return $('<div />')
.addClass('jtable-input jtable-textarea-input')
.append($textArea);
},
/* Creates a standart textbox for a field.
*************************************************************************/
_createTextInputForField: function (field, fieldName, value) {
var $input = $('<input class="' + field.inputClass + '" placeholder="' + field.placeholder + '" id="Edit-' + fieldName + '" type="text" name="' + fieldName + '"></input>');
if (value != undefined) {
$input.val(value);
}
return $('<div />')
.addClass('jtable-input jtable-text-input')
.append($input);
},
/* Creates a password input for a field.
*************************************************************************/
_createPasswordInputForField: function (field, fieldName, value) {
var $input = $('<input class="' + field.inputClass + '" placeholder="' + field.placeholder + '" id="Edit-' + fieldName + '" type="password" name="' + fieldName + '"></input>');
if (value != undefined) {
$input.val(value);
}
return $('<div />')
.addClass('jtable-input jtable-password-input')
.append($input);
},
/* Creates a checkboxfor a field.
*************************************************************************/
_createCheckboxForField: function (field, fieldName, value) {
var self = this;
//If value is undefined, get unchecked state's value
if (value == undefined) {
value = self._getCheckBoxPropertiesForFieldByState(fieldName, false).Value;
}
//Create a container div
var $containerDiv = $('<div />')
.addClass('jtable-input jtable-checkbox-input');
//Create checkbox and check if needed
var $checkBox = $('<input class="' + field.inputClass + '" id="Edit-' + fieldName + '" type="checkbox" name="' + fieldName + '" />')
.appendTo($containerDiv);
if (value != undefined) {
$checkBox.val(value);
}
//Create display text of checkbox for current state
var $textSpan = $('<span>' + (field.formText || self._getCheckBoxTextForFieldByValue(fieldName, value)) + '</span>')
.appendTo($containerDiv);
//Check the checkbox if it's value is checked-value
if (self._getIsCheckBoxSelectedForFieldByValue(fieldName, value)) {
$checkBox.attr('checked', 'checked');
}
//This method sets checkbox's value and text according to state of the checkbox
var refreshCheckBoxValueAndText = function () {
var checkboxProps = self._getCheckBoxPropertiesForFieldByState(fieldName, $checkBox.is(':checked'));
$checkBox.attr('value', checkboxProps.Value);
$textSpan.html(field.formText || checkboxProps.DisplayText);
};
//Register to click event to change display text when state of checkbox is changed.
$checkBox.click(function () {
refreshCheckBoxValueAndText();
});
//Change checkbox state when clicked to text
if (field.setOnTextClick != false) {
$textSpan
.addClass('jtable-option-text-clickable')
.click(function () {
if ($checkBox.is(':checked')) {
$checkBox.attr('checked', false);
} else {
$checkBox.attr('checked', true);
}
refreshCheckBoxValueAndText();
});
}
return $containerDiv;
},
/* Creates a drop down list (combobox) input element for a field.
*************************************************************************/
_createDropDownListForField: function (field, fieldName, value, record, source, form) {
//Create a container div
var $containerDiv = $('<div />')
.addClass('jtable-input jtable-dropdown-input');
//Create select element
var $select = $('<select class="' + field.inputClass + '" id="Edit-' + fieldName + '" name="' + fieldName + '"></select>')
.appendTo($containerDiv);
//add options
var options = this._getOptionsForField(fieldName, {
record: record,
source: source,
form: form,
dependedValues: this._createDependedValuesUsingForm(form, field.dependsOn)
});
this._fillDropDownListWithOptions($select, options, value);
return $containerDiv;
},
/* Fills a dropdown list with given options.
*************************************************************************/
_fillDropDownListWithOptions: function ($select, options, value) {
$select.empty();
for (var i = 0; i < options.length; i++) {
$('<option' + (options[i].Value == value ? ' selected="selected"' : '') + '>' + options[i].DisplayText + '</option>')
.val(options[i].Value)
.appendTo($select);
}
},
/* Creates depended values object from given form.
*************************************************************************/
_createDependedValuesUsingForm: function ($form, dependsOn) {
if (!dependsOn) {
return {};
}
var dependedValues = {};
for (var i = 0; i < dependsOn.length; i++) {
var dependedField = dependsOn[i];
var $dependsOn = $form.find('select[name=' + dependedField + ']');
if ($dependsOn.length <= 0) {
continue;
}
dependedValues[dependedField] = $dependsOn.val();
}
return dependedValues;
},
/* Creates a radio button list for a field.
*************************************************************************/
_createRadioButtonListForField: function (field, fieldName, value, record, source) {
var $containerDiv = $('<div />')
.addClass('jtable-input jtable-radiobuttonlist-input');
var options = this._getOptionsForField(fieldName, {
record: record,
source: source
});
$.each(options, function(i, option) {
var $radioButtonDiv = $('<div class=""></div>')
.addClass('jtable-radio-input')
.appendTo($containerDiv);
var $radioButton = $('<input type="radio" id="Edit-' + fieldName + '-' + i + '" class="' + field.inputClass + '" name="' + fieldName + '"' + ((option.Value == (value + '')) ? ' checked="true"' : '') + ' />')
.val(option.Value)
.appendTo($radioButtonDiv);
var $textSpan = $('<span></span>')
.html(option.DisplayText)
.appendTo($radioButtonDiv);
if (field.setOnTextClick != false) {
$textSpan
.addClass('jtable-option-text-clickable')
.click(function () {
if (!$radioButton.is(':checked')) {
$radioButton.attr('checked', true);
}
});
}
});
return $containerDiv;
},
/* Gets display text for a checkbox field.
*************************************************************************/
_getCheckBoxTextForFieldByValue: function (fieldName, value) {
return this.options.fields[fieldName].values[value];
},
/* Returns true if given field's value must be checked state.
*************************************************************************/
_getIsCheckBoxSelectedForFieldByValue: function (fieldName, value) {
return (this._createCheckBoxStateArrayForFieldWithCaching(fieldName)[1].Value.toString() == value.toString());
},
/* Gets an object for a checkbox field that has Value and DisplayText
* properties.
*************************************************************************/
_getCheckBoxPropertiesForFieldByState: function (fieldName, checked) {
return this._createCheckBoxStateArrayForFieldWithCaching(fieldName)[(checked ? 1 : 0)];
},
/* Calls _createCheckBoxStateArrayForField with caching.
*************************************************************************/
_createCheckBoxStateArrayForFieldWithCaching: function (fieldName) {
var cacheKey = 'checkbox_' + fieldName;
if (!this._cache[cacheKey]) {
this._cache[cacheKey] = this._createCheckBoxStateArrayForField(fieldName);
}
return this._cache[cacheKey];
},
/* Creates a two element array of objects for states of a checkbox field.
* First element for unchecked state, second for checked state.
* Each object has two properties: Value and DisplayText
*************************************************************************/
_createCheckBoxStateArrayForField: function (fieldName) {
var stateArray = [];
var currentIndex = 0;
$.each(this.options.fields[fieldName].values, function (propName, propValue) {
if (currentIndex++ < 2) {
stateArray.push({ 'Value': propName, 'DisplayText': propValue });
}
});
return stateArray;
},
/* Searches a form for dependend dropdowns and makes them cascaded.
*/
_makeCascadeDropDowns: function ($form, record, source) {
var self = this;
$form.find('select') //for each combobox
.each(function () {
var $thisDropdown = $(this);
//get field name
var fieldName = $thisDropdown.attr('name');
if (!fieldName) {
return;
}
var field = self.options.fields[fieldName];
//check if this combobox depends on others
if (!field.dependsOn) {
return;
}
//for each dependency
$.each(field.dependsOn, function (index, dependsOnField) {
//find the depended combobox
var $dependsOnDropdown = $form.find('select[name=' + dependsOnField + ']');
//when depended combobox changes
$dependsOnDropdown.change(function () {
//Refresh options
var funcParams = {
record: record,
source: source,
form: $form,
dependedValues: {}
};
funcParams.dependedValues = self._createDependedValuesUsingForm($form, field.dependsOn);
var options = self._getOptionsForField(fieldName, funcParams);
//Fill combobox with new options
self._fillDropDownListWithOptions($thisDropdown, options, undefined);
//Thigger change event to refresh multi cascade dropdowns.
$thisDropdown.change();
});
});
});
},
/* Updates values of a record from given form
*************************************************************************/
_updateRecordValuesFromForm: function (record, $form) {
for (var i = 0; i < this._fieldList.length; i++) {
var fieldName = this._fieldList[i];
var field = this.options.fields[fieldName];
//Do not update non-editable fields
if (field.edit == false) {
continue;
}
//Get field name and the input element of this field in the form
var $inputElement = $form.find('[name="' + fieldName + '"]');
if ($inputElement.length <= 0) {
continue;
}
//Update field in record according to it's type
if (field.type == 'date') {
var dateVal = $inputElement.val();
if (dateVal) {
var displayFormat = field.displayFormat || this.options.defaultDateFormat;
try {
var date = $.datepicker.parseDate(displayFormat, dateVal);
record[fieldName] = '/Date(' + date.getTime() + ')/';
} catch (e) {
//TODO: Handle incorrect/different date formats
this._logWarn('Date format is incorrect for field ' + fieldName + ': ' + dateVal);
record[fieldName] = undefined;
}
} else {
this._logDebug('Date is empty for ' + fieldName);
record[fieldName] = undefined; //TODO: undefined, null or empty string?
}
} else if (field.options && field.type == 'radiobutton') {
var $checkedElement = $inputElement.filter(':checked');
if ($checkedElement.length) {
record[fieldName] = $checkedElement.val();
} else {
record[fieldName] = undefined;
}
} else {
record[fieldName] = $inputElement.val();
}
}
},
/* Sets enabled/disabled state of a dialog button.
*************************************************************************/
_setEnabledOfDialogButton: function ($button, enabled, buttonText) {
if (!$button) {
return;
}
if (enabled != false) {
$button
.removeAttr('disabled')
.removeClass('ui-state-disabled');
} else {
$button
.attr('disabled', 'disabled')
.addClass('ui-state-disabled');
}
if (buttonText) {
$button
.find('span')
.text(buttonText);
}
}
});
})(jQuery);

View file

@ -0,0 +1,28 @@
/*
jTable 2.4.0
http://www.jtable.org
---------------------------------------------------------------------------
Copyright (C) 2011-2014 by Halil İbrahim Kalkan (http://www.halilibrahimkalkan.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

View file

@ -0,0 +1,171 @@
/************************************************************************
* MASTER/CHILD tables extension for jTable *
*************************************************************************/
(function ($) {
//Reference to base object members
var base = {
_removeRowsFromTable: $.hik.jtable.prototype._removeRowsFromTable
};
//extension members
$.extend(true, $.hik.jtable.prototype, {
/************************************************************************
* DEFAULT OPTIONS / EVENTS *
*************************************************************************/
options: {
openChildAsAccordion: false
},
/************************************************************************
* PUBLIC METHODS *
*************************************************************************/
/* Creates and opens a new child table for given row.
*************************************************************************/
openChildTable: function ($row, tableOptions, opened) {
var self = this;
//Apply theming as same as parent table unless explicitily set
if (tableOptions.jqueryuiTheme == undefined) {
tableOptions.jqueryuiTheme = self.options.jqueryuiTheme;
}
//Show close button as default
tableOptions.showCloseButton = (tableOptions.showCloseButton != false);
//Close child table when close button is clicked (default behavior)
if (tableOptions.showCloseButton && !tableOptions.closeRequested) {
tableOptions.closeRequested = function () {
self.closeChildTable($row);
};
}
//If accordion style, close open child table (if it does exists)
if (self.options.openChildAsAccordion) {
$row.siblings('.jtable-data-row').each(function () {
self.closeChildTable($(this));
});
}
//Close child table for this row and open new one for child table
self.closeChildTable($row, function () {
var $childRowColumn = self.getChildRow($row).children('td').empty();
var $childTableContainer = $('<div />')
.addClass('jtable-child-table-container')
.appendTo($childRowColumn);
$childRowColumn.data('childTable', $childTableContainer);
$childTableContainer.jtable(tableOptions);
self.openChildRow($row);
$childTableContainer.hide().slideDown('fast', function () {
if (opened) {
opened({
childTable: $childTableContainer
});
}
});
});
},
/* Closes child table for given row.
*************************************************************************/
closeChildTable: function ($row, closed) {
var self = this;
var $childRowColumn = this.getChildRow($row).children('td');
var $childTable = $childRowColumn.data('childTable');
if (!$childTable) {
if (closed) {
closed();
}
return;
}
$childRowColumn.data('childTable', null);
$childTable.slideUp('fast', function () {
$childTable.jtable('destroy');
$childTable.remove();
self.closeChildRow($row);
if (closed) {
closed();
}
});
},
/* Returns a boolean value indicates that if a child row is open for given row.
*************************************************************************/
isChildRowOpen: function ($row) {
return (this.getChildRow($row).is(':visible'));
},
/* Gets child row for given row, opens it if it's closed (Creates if needed).
*************************************************************************/
getChildRow: function ($row) {
return $row.data('childRow') || this._createChildRow($row);
},
/* Creates and opens child row for given row.
*************************************************************************/
openChildRow: function ($row) {
var $childRow = this.getChildRow($row);
if (!$childRow.is(':visible')) {
$childRow.show();
}
return $childRow;
},
/* Closes child row if it's open.
*************************************************************************/
closeChildRow: function ($row) {
var $childRow = this.getChildRow($row);
if ($childRow.is(':visible')) {
$childRow.hide();
}
},
/************************************************************************
* OVERRIDED METHODS *
*************************************************************************/
/* Overrides _removeRowsFromTable method to remove child rows of deleted rows.
*************************************************************************/
_removeRowsFromTable: function ($rows, reason) {
//var self = this;
if (reason == 'deleted') {
$rows.each(function () {
var $row = $(this);
var $childRow = $row.data('childRow');
if ($childRow) {
//self.closeChildTable($row); //Removed since it causes "Uncaught Error: cannot call methods on jtable prior to initialization; attempted to call method 'destroy'"
$childRow.remove();
}
});
}
base._removeRowsFromTable.apply(this, arguments);
},
/************************************************************************
* PRIVATE METHODS *
*************************************************************************/
/* Creates a child row for a row, hides and returns it.
*************************************************************************/
_createChildRow: function ($row) {
var totalColumnCount = this._$table.find('thead th').length;
var $childRow = $('<tr></tr>')
.addClass('jtable-child-row')
.append('<td colspan="' + totalColumnCount + '"></td>');
$row.after($childRow);
$row.data('childRow', $childRow);
$childRow.hide();
return $childRow;
}
});
})(jQuery);

View file

@ -0,0 +1,595 @@
/************************************************************************
* PAGING extension for jTable *
*************************************************************************/
(function ($) {
//Reference to base object members
var base = {
load: $.hik.jtable.prototype.load,
_create: $.hik.jtable.prototype._create,
_setOption: $.hik.jtable.prototype._setOption,
_createRecordLoadUrl: $.hik.jtable.prototype._createRecordLoadUrl,
_createJtParamsForLoading: $.hik.jtable.prototype._createJtParamsForLoading,
_addRowToTable: $.hik.jtable.prototype._addRowToTable,
_addRow: $.hik.jtable.prototype._addRow,
_removeRowsFromTable: $.hik.jtable.prototype._removeRowsFromTable,
_onRecordsLoaded: $.hik.jtable.prototype._onRecordsLoaded
};
//extension members
$.extend(true, $.hik.jtable.prototype, {
/************************************************************************
* DEFAULT OPTIONS / EVENTS *
*************************************************************************/
options: {
paging: false,
pageList: 'normal', //possible values: 'minimal', 'normal'
pageSize: 10,
pageSizes: [10, 25, 50, 100, 250, 500],
pageSizeChangeArea: true,
gotoPageArea: 'combobox', //possible values: 'textbox', 'combobox', 'none'
messages: {
pagingInfo: 'Showing {0}-{1} of {2}',
pageSizeChangeLabel: 'Row count',
gotoPageLabel: 'Go to page'
}
},
/************************************************************************
* PRIVATE FIELDS *
*************************************************************************/
_$bottomPanel: null, //Reference to the panel at the bottom of the table (jQuery object)
_$pagingListArea: null, //Reference to the page list area in to bottom panel (jQuery object)
_$pageSizeChangeArea: null, //Reference to the page size change area in to bottom panel (jQuery object)
_$pageInfoSpan: null, //Reference to the paging info area in to bottom panel (jQuery object)
_$gotoPageArea: null, //Reference to 'Go to page' input area in to bottom panel (jQuery object)
_$gotoPageInput: null, //Reference to 'Go to page' input in to bottom panel (jQuery object)
_totalRecordCount: 0, //Total count of records on all pages
_currentPageNo: 1, //Current page number
/************************************************************************
* CONSTRUCTOR AND INITIALIZING METHODS *
*************************************************************************/
/* Overrides base method to do paging-specific constructions.
*************************************************************************/
_create: function() {
base._create.apply(this, arguments);
if (this.options.paging) {
this._loadPagingSettings();
this._createBottomPanel();
this._createPageListArea();
this._createGotoPageInput();
this._createPageSizeSelection();
}
},
/* Loads user preferences for paging.
*************************************************************************/
_loadPagingSettings: function() {
if (!this.options.saveUserPreferences) {
return;
}
var pageSize = this._getCookie('page-size');
if (pageSize) {
this.options.pageSize = this._normalizeNumber(pageSize, 1, 1000000, this.options.pageSize);
}
},
/* Creates bottom panel and adds to the page.
*************************************************************************/
_createBottomPanel: function() {
this._$bottomPanel = $('<div />')
.addClass('jtable-bottom-panel')
.insertAfter(this._$table);
this._jqueryuiThemeAddClass(this._$bottomPanel, 'ui-state-default');
$('<div />').addClass('jtable-left-area').appendTo(this._$bottomPanel);
$('<div />').addClass('jtable-right-area').appendTo(this._$bottomPanel);
},
/* Creates page list area.
*************************************************************************/
_createPageListArea: function() {
this._$pagingListArea = $('<span></span>')
.addClass('jtable-page-list')
.appendTo(this._$bottomPanel.find('.jtable-left-area'));
this._$pageInfoSpan = $('<span></span>')
.addClass('jtable-page-info')
.appendTo(this._$bottomPanel.find('.jtable-right-area'));
},
/* Creates page list change area.
*************************************************************************/
_createPageSizeSelection: function() {
var self = this;
if (!self.options.pageSizeChangeArea) {
return;
}
//Add current page size to page sizes list if not contains it
if (self._findIndexInArray(self.options.pageSize, self.options.pageSizes) < 0) {
self.options.pageSizes.push(parseInt(self.options.pageSize));
self.options.pageSizes.sort(function(a, b) { return a - b; });
}
//Add a span to contain page size change items
self._$pageSizeChangeArea = $('<span></span>')
.addClass('jtable-page-size-change')
.appendTo(self._$bottomPanel.find('.jtable-left-area'));
//Page size label
self._$pageSizeChangeArea.append('<span>' + self.options.messages.pageSizeChangeLabel + ': </span>');
//Page size change combobox
var $pageSizeChangeCombobox = $('<select></select>').appendTo(self._$pageSizeChangeArea);
//Add page sizes to the combobox
for (var i = 0; i < self.options.pageSizes.length; i++) {
$pageSizeChangeCombobox.append('<option value="' + self.options.pageSizes[i] + '">' + self.options.pageSizes[i] + '</option>');
}
//Select current page size
$pageSizeChangeCombobox.val(self.options.pageSize);
//Change page size on combobox change
$pageSizeChangeCombobox.change(function() {
self._changePageSize(parseInt($(this).val()));
});
},
/* Creates go to page area.
*************************************************************************/
_createGotoPageInput: function() {
var self = this;
if (!self.options.gotoPageArea || self.options.gotoPageArea == 'none') {
return;
}
//Add a span to contain goto page items
this._$gotoPageArea = $('<span></span>')
.addClass('jtable-goto-page')
.appendTo(self._$bottomPanel.find('.jtable-left-area'));
//Goto page label
this._$gotoPageArea.append('<span>' + self.options.messages.gotoPageLabel + ': </span>');
//Goto page input
if (self.options.gotoPageArea == 'combobox') {
self._$gotoPageInput = $('<select></select>')
.appendTo(this._$gotoPageArea)
.data('pageCount', 1)
.change(function() {
self._changePage(parseInt($(this).val()));
});
self._$gotoPageInput.append('<option value="1">1</option>');
} else { //textbox
self._$gotoPageInput = $('<input type="text" maxlength="10" value="' + self._currentPageNo + '" />')
.appendTo(this._$gotoPageArea)
.keypress(function(event) {
if (event.which == 13) { //enter
event.preventDefault();
self._changePage(parseInt(self._$gotoPageInput.val()));
} else if (event.which == 43) { // +
event.preventDefault();
self._changePage(parseInt(self._$gotoPageInput.val()) + 1);
} else if (event.which == 45) { // -
event.preventDefault();
self._changePage(parseInt(self._$gotoPageInput.val()) - 1);
} else {
//Allow only digits
var isValid = (
(47 < event.keyCode && event.keyCode < 58 && event.shiftKey == false && event.altKey == false)
|| (event.keyCode == 8)
|| (event.keyCode == 9)
);
if (!isValid) {
event.preventDefault();
}
}
});
}
},
/* Refreshes the 'go to page' input.
*************************************************************************/
_refreshGotoPageInput: function() {
if (!this.options.gotoPageArea || this.options.gotoPageArea == 'none') {
return;
}
if (this._totalRecordCount <= 0) {
this._$gotoPageArea.hide();
} else {
this._$gotoPageArea.show();
}
if (this.options.gotoPageArea == 'combobox') {
var oldPageCount = this._$gotoPageInput.data('pageCount');
var currentPageCount = this._calculatePageCount();
if (oldPageCount != currentPageCount) {
this._$gotoPageInput.empty();
//Skip some pages is there are too many pages
var pageStep = 1;
if (currentPageCount > 10000) {
pageStep = 100;
} else if (currentPageCount > 5000) {
pageStep = 10;
} else if (currentPageCount > 2000) {
pageStep = 5;
} else if (currentPageCount > 1000) {
pageStep = 2;
}
for (var i = pageStep; i <= currentPageCount; i += pageStep) {
this._$gotoPageInput.append('<option value="' + i + '">' + i + '</option>');
}
this._$gotoPageInput.data('pageCount', currentPageCount);
}
}
//same for 'textbox' and 'combobox'
this._$gotoPageInput.val(this._currentPageNo);
},
/************************************************************************
* OVERRIDED METHODS *
*************************************************************************/
/* Overrides load method to set current page to 1.
*************************************************************************/
load: function() {
this._currentPageNo = 1;
base.load.apply(this, arguments);
},
/* Used to change options dynamically after initialization.
*************************************************************************/
_setOption: function(key, value) {
base._setOption.apply(this, arguments);
if (key == 'pageSize') {
this._changePageSize(parseInt(value));
}
},
/* Changes current page size with given value.
*************************************************************************/
_changePageSize: function(pageSize) {
if (pageSize == this.options.pageSize) {
return;
}
this.options.pageSize = pageSize;
//Normalize current page
var pageCount = this._calculatePageCount();
if (this._currentPageNo > pageCount) {
this._currentPageNo = pageCount;
}
if (this._currentPageNo <= 0) {
this._currentPageNo = 1;
}
//if user sets one of the options on the combobox, then select it.
var $pageSizeChangeCombobox = this._$bottomPanel.find('.jtable-page-size-change select');
if ($pageSizeChangeCombobox.length > 0) {
if (parseInt($pageSizeChangeCombobox.val()) != pageSize) {
var selectedOption = $pageSizeChangeCombobox.find('option[value=' + pageSize + ']');
if (selectedOption.length > 0) {
$pageSizeChangeCombobox.val(pageSize);
}
}
}
this._savePagingSettings();
this._reloadTable();
},
/* Saves user preferences for paging
*************************************************************************/
_savePagingSettings: function() {
if (!this.options.saveUserPreferences) {
return;
}
this._setCookie('page-size', this.options.pageSize);
},
/* Overrides _createRecordLoadUrl method to add paging info to URL.
*************************************************************************/
_createRecordLoadUrl: function() {
var loadUrl = base._createRecordLoadUrl.apply(this, arguments);
loadUrl = this._addPagingInfoToUrl(loadUrl, this._currentPageNo);
return loadUrl;
},
/* Overrides _createJtParamsForLoading method to add paging parameters to jtParams object.
*************************************************************************/
_createJtParamsForLoading: function () {
var jtParams = base._createJtParamsForLoading.apply(this, arguments);
if (this.options.paging) {
jtParams.jtStartIndex = (this._currentPageNo - 1) * this.options.pageSize;
jtParams.jtPageSize = this.options.pageSize;
}
return jtParams;
},
/* Overrides _addRowToTable method to re-load table when a new row is created.
* NOTE: THIS METHOD IS DEPRECATED AND WILL BE REMOVED FROM FEATURE RELEASES.
* USE _addRow METHOD.
*************************************************************************/
_addRowToTable: function ($tableRow, index, isNewRow) {
if (isNewRow && this.options.paging) {
this._reloadTable();
return;
}
base._addRowToTable.apply(this, arguments);
},
/* Overrides _addRow method to re-load table when a new row is created.
*************************************************************************/
_addRow: function ($row, options) {
if (options && options.isNewRow && this.options.paging) {
this._reloadTable();
return;
}
base._addRow.apply(this, arguments);
},
/* Overrides _removeRowsFromTable method to re-load table when a row is removed from table.
*************************************************************************/
_removeRowsFromTable: function ($rows, reason) {
base._removeRowsFromTable.apply(this, arguments);
if (this.options.paging) {
if (this._$tableRows.length <= 0 && this._currentPageNo > 1) {
--this._currentPageNo;
}
this._reloadTable();
}
},
/* Overrides _onRecordsLoaded method to to do paging specific tasks.
*************************************************************************/
_onRecordsLoaded: function (data) {
if (this.options.paging) {
this._totalRecordCount = data.TotalRecordCount;
this._createPagingList();
this._createPagingInfo();
this._refreshGotoPageInput();
}
base._onRecordsLoaded.apply(this, arguments);
},
/************************************************************************
* PRIVATE METHODS *
*************************************************************************/
/* Adds jtStartIndex and jtPageSize parameters to a URL as query string.
*************************************************************************/
_addPagingInfoToUrl: function (url, pageNumber) {
if (!this.options.paging) {
return url;
}
var jtStartIndex = (pageNumber - 1) * this.options.pageSize;
var jtPageSize = this.options.pageSize;
return (url + (url.indexOf('?') < 0 ? '?' : '&') + 'jtStartIndex=' + jtStartIndex + '&jtPageSize=' + jtPageSize);
},
/* Creates and shows the page list.
*************************************************************************/
_createPagingList: function () {
if (this.options.pageSize <= 0) {
return;
}
this._$pagingListArea.empty();
if (this._totalRecordCount <= 0) {
return;
}
var pageCount = this._calculatePageCount();
this._createFirstAndPreviousPageButtons();
if (this.options.pageList == 'normal') {
this._createPageNumberButtons(this._calculatePageNumbers(pageCount));
}
this._createLastAndNextPageButtons(pageCount);
this._bindClickEventsToPageNumberButtons();
},
/* Creates and shows previous and first page links.
*************************************************************************/
_createFirstAndPreviousPageButtons: function () {
var $first = $('<span></span>')
.addClass('jtable-page-number-first')
.html('&lt&lt')
.data('pageNumber', 1)
.appendTo(this._$pagingListArea);
var $previous = $('<span></span>')
.addClass('jtable-page-number-previous')
.html('&lt')
.data('pageNumber', this._currentPageNo - 1)
.appendTo(this._$pagingListArea);
this._jqueryuiThemeAddClass($first, 'ui-button ui-state-default', 'ui-state-hover');
this._jqueryuiThemeAddClass($previous, 'ui-button ui-state-default', 'ui-state-hover');
if (this._currentPageNo <= 1) {
$first.addClass('jtable-page-number-disabled');
$previous.addClass('jtable-page-number-disabled');
this._jqueryuiThemeAddClass($first, 'ui-state-disabled');
this._jqueryuiThemeAddClass($previous, 'ui-state-disabled');
}
},
/* Creates and shows next and last page links.
*************************************************************************/
_createLastAndNextPageButtons: function (pageCount) {
var $next = $('<span></span>')
.addClass('jtable-page-number-next')
.html('&gt')
.data('pageNumber', this._currentPageNo + 1)
.appendTo(this._$pagingListArea);
var $last = $('<span></span>')
.addClass('jtable-page-number-last')
.html('&gt&gt')
.data('pageNumber', pageCount)
.appendTo(this._$pagingListArea);
this._jqueryuiThemeAddClass($next, 'ui-button ui-state-default', 'ui-state-hover');
this._jqueryuiThemeAddClass($last, 'ui-button ui-state-default', 'ui-state-hover');
if (this._currentPageNo >= pageCount) {
$next.addClass('jtable-page-number-disabled');
$last.addClass('jtable-page-number-disabled');
this._jqueryuiThemeAddClass($next, 'ui-state-disabled');
this._jqueryuiThemeAddClass($last, 'ui-state-disabled');
}
},
/* Creates and shows page number links for given number array.
*************************************************************************/
_createPageNumberButtons: function (pageNumbers) {
var previousNumber = 0;
for (var i = 0; i < pageNumbers.length; i++) {
//Create "..." between page numbers if needed
if ((pageNumbers[i] - previousNumber) > 1) {
$('<span></span>')
.addClass('jtable-page-number-space')
.html('...')
.appendTo(this._$pagingListArea);
}
this._createPageNumberButton(pageNumbers[i]);
previousNumber = pageNumbers[i];
}
},
/* Creates a page number link and adds to paging area.
*************************************************************************/
_createPageNumberButton: function (pageNumber) {
var $pageNumber = $('<span></span>')
.addClass('jtable-page-number')
.html(pageNumber)
.data('pageNumber', pageNumber)
.appendTo(this._$pagingListArea);
this._jqueryuiThemeAddClass($pageNumber, 'ui-button ui-state-default', 'ui-state-hover');
if (this._currentPageNo == pageNumber) {
$pageNumber.addClass('jtable-page-number-active jtable-page-number-disabled');
this._jqueryuiThemeAddClass($pageNumber, 'ui-state-active');
}
},
/* Calculates total page count according to page size and total record count.
*************************************************************************/
_calculatePageCount: function () {
var pageCount = Math.floor(this._totalRecordCount / this.options.pageSize);
if (this._totalRecordCount % this.options.pageSize != 0) {
++pageCount;
}
return pageCount;
},
/* Calculates page numbers and returns an array of these numbers.
*************************************************************************/
_calculatePageNumbers: function (pageCount) {
if (pageCount <= 4) {
//Show all pages
var pageNumbers = [];
for (var i = 1; i <= pageCount; ++i) {
pageNumbers.push(i);
}
return pageNumbers;
} else {
//show first three, last three, current, previous and next page numbers
var shownPageNumbers = [1, 2, pageCount - 1, pageCount];
var previousPageNo = this._normalizeNumber(this._currentPageNo - 1, 1, pageCount, 1);
var nextPageNo = this._normalizeNumber(this._currentPageNo + 1, 1, pageCount, 1);
this._insertToArrayIfDoesNotExists(shownPageNumbers, previousPageNo);
this._insertToArrayIfDoesNotExists(shownPageNumbers, this._currentPageNo);
this._insertToArrayIfDoesNotExists(shownPageNumbers, nextPageNo);
shownPageNumbers.sort(function (a, b) { return a - b; });
return shownPageNumbers;
}
},
/* Creates and shows paging informations.
*************************************************************************/
_createPagingInfo: function () {
if (this._totalRecordCount <= 0) {
this._$pageInfoSpan.empty();
return;
}
var startNo = (this._currentPageNo - 1) * this.options.pageSize + 1;
var endNo = this._currentPageNo * this.options.pageSize;
endNo = this._normalizeNumber(endNo, startNo, this._totalRecordCount, 0);
if (endNo >= startNo) {
var pagingInfoMessage = this._formatString(this.options.messages.pagingInfo, startNo, endNo, this._totalRecordCount);
this._$pageInfoSpan.html(pagingInfoMessage);
}
},
/* Binds click events of all page links to change the page.
*************************************************************************/
_bindClickEventsToPageNumberButtons: function () {
var self = this;
self._$pagingListArea
.find('.jtable-page-number,.jtable-page-number-previous,.jtable-page-number-next,.jtable-page-number-first,.jtable-page-number-last')
.not('.jtable-page-number-disabled')
.click(function (e) {
e.preventDefault();
self._changePage($(this).data('pageNumber'));
});
},
/* Changes current page to given value.
*************************************************************************/
_changePage: function (pageNo) {
pageNo = this._normalizeNumber(pageNo, 1, this._calculatePageCount(), 1);
if (pageNo == this._currentPageNo) {
this._refreshGotoPageInput();
return;
}
this._currentPageNo = pageNo;
this._reloadTable();
}
});
})(jQuery);

View file

@ -0,0 +1,382 @@
/************************************************************************
* SELECTING 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,
_onLoadingRecords: $.hik.jtable.prototype._onLoadingRecords,
_onRecordsLoaded: $.hik.jtable.prototype._onRecordsLoaded,
_onRowsRemoved: $.hik.jtable.prototype._onRowsRemoved
};
//extension members
$.extend(true, $.hik.jtable.prototype, {
/************************************************************************
* DEFAULT OPTIONS / EVENTS *
*************************************************************************/
options: {
//Options
selecting: false,
multiselect: false,
selectingCheckboxes: false,
selectOnRowClick: true,
//Events
selectionChanged: function (event, data) { }
},
/************************************************************************
* PRIVATE FIELDS *
*************************************************************************/
_selectedRecordIdsBeforeLoad: null, //This array is used to store selected row Id's to restore them after a page refresh (string array).
_$selectAllCheckbox: null, //Reference to the 'select/deselect all' checkbox (jQuery object)
_shiftKeyDown: false, //True, if shift key is currently down.
/************************************************************************
* CONSTRUCTOR *
*************************************************************************/
/* Overrides base method to do selecting-specific constructions.
*************************************************************************/
_create: function () {
if (this.options.selecting && this.options.selectingCheckboxes) {
++this._firstDataColumnOffset;
this._bindKeyboardEvents();
}
//Call base method
base._create.apply(this, arguments);
},
/* Registers to keyboard events those are needed for selection
*************************************************************************/
_bindKeyboardEvents: function () {
var self = this;
//Register to events to set _shiftKeyDown value
$(document)
.keydown(function (event) {
switch (event.which) {
case 16:
self._shiftKeyDown = true;
break;
}
})
.keyup(function (event) {
switch (event.which) {
case 16:
self._shiftKeyDown = false;
break;
}
});
},
/************************************************************************
* PUBLIC METHODS *
*************************************************************************/
/* Gets jQuery selection for currently selected rows.
*************************************************************************/
selectedRows: function () {
return this._getSelectedRows();
},
/* Makes row/rows 'selected'.
*************************************************************************/
selectRows: function ($rows) {
this._selectRows($rows);
this._onSelectionChanged(); //TODO: trigger only if selected rows changes?
},
/************************************************************************
* OVERRIDED METHODS *
*************************************************************************/
/* Overrides base method to add a 'select column' to header row.
*************************************************************************/
_addColumnsToHeaderRow: function ($tr) {
if (this.options.selecting && this.options.selectingCheckboxes) {
if (this.options.multiselect) {
$tr.append(this._createSelectAllHeader());
} else {
$tr.append(this._createEmptyCommandHeader());
}
}
base._addColumnsToHeaderRow.apply(this, arguments);
},
/* Overrides base method to add a 'delete command cell' to a row.
*************************************************************************/
_addCellsToRowUsingRecord: function ($row) {
if (this.options.selecting) {
this._makeRowSelectable($row);
}
base._addCellsToRowUsingRecord.apply(this, arguments);
},
/* Overrides base event to store selection list
*************************************************************************/
_onLoadingRecords: function () {
if (this.options.selecting) {
this._storeSelectionList();
}
base._onLoadingRecords.apply(this, arguments);
},
/* Overrides base event to restore selection list
*************************************************************************/
_onRecordsLoaded: function () {
if (this.options.selecting) {
this._restoreSelectionList();
}
base._onRecordsLoaded.apply(this, arguments);
},
/* Overrides base event to check is any selected row is being removed.
*************************************************************************/
_onRowsRemoved: function ($rows, reason) {
if (this.options.selecting && (reason != 'reloading') && ($rows.filter('.jtable-row-selected').length > 0)) {
this._onSelectionChanged();
}
base._onRowsRemoved.apply(this, arguments);
},
/************************************************************************
* PRIVATE METHODS *
*************************************************************************/
/* Creates a header column to select/deselect all rows.
*************************************************************************/
_createSelectAllHeader: function () {
var self = this;
var $columnHeader = $('<th class=""></th>')
.addClass('jtable-command-column-header jtable-column-header-selecting');
this._jqueryuiThemeAddClass($columnHeader, 'ui-state-default');
var $headerContainer = $('<div />')
.addClass('jtable-column-header-container')
.appendTo($columnHeader);
self._$selectAllCheckbox = $('<input type="checkbox" />')
.appendTo($headerContainer)
.click(function () {
if (self._$tableRows.length <= 0) {
self._$selectAllCheckbox.attr('checked', false);
return;
}
var allRows = self._$tableBody.find('>tr.jtable-data-row');
if (self._$selectAllCheckbox.is(':checked')) {
self._selectRows(allRows);
} else {
self._deselectRows(allRows);
}
self._onSelectionChanged();
});
return $columnHeader;
},
/* Stores Id's of currently selected records to _selectedRecordIdsBeforeLoad.
*************************************************************************/
_storeSelectionList: function () {
var self = this;
if (!self.options.selecting) {
return;
}
self._selectedRecordIdsBeforeLoad = [];
self._getSelectedRows().each(function () {
self._selectedRecordIdsBeforeLoad.push(self._getKeyValueOfRecord($(this).data('record')));
});
},
/* Selects rows whose Id is in _selectedRecordIdsBeforeLoad;
*************************************************************************/
_restoreSelectionList: function () {
var self = this;
if (!self.options.selecting) {
return;
}
var selectedRowCount = 0;
for (var i = 0; i < self._$tableRows.length; ++i) {
var recordId = self._getKeyValueOfRecord(self._$tableRows[i].data('record'));
if ($.inArray(recordId, self._selectedRecordIdsBeforeLoad) > -1) {
self._selectRows(self._$tableRows[i]);
++selectedRowCount;
}
}
if (self._selectedRecordIdsBeforeLoad.length > 0 && self._selectedRecordIdsBeforeLoad.length != selectedRowCount) {
self._onSelectionChanged();
}
self._selectedRecordIdsBeforeLoad = [];
self._refreshSelectAllCheckboxState();
},
/* Gets all selected rows.
*************************************************************************/
_getSelectedRows: function () {
return this._$tableBody
.find('>tr.jtable-row-selected');
},
/* Adds selectable feature to a row.
*************************************************************************/
_makeRowSelectable: function ($row) {
var self = this;
//Select/deselect on row click
if (self.options.selectOnRowClick) {
$row.click(function () {
self._invertRowSelection($row);
});
}
//'select/deselect' checkbox column
if (self.options.selectingCheckboxes) {
var $cell = $('<td></td>').addClass('jtable-selecting-column');
var $selectCheckbox = $('<input type="checkbox" />').appendTo($cell);
if (!self.options.selectOnRowClick) {
$selectCheckbox.click(function () {
self._invertRowSelection($row);
});
}
$row.append($cell);
}
},
/* Inverts selection state of a single row.
*************************************************************************/
_invertRowSelection: function ($row) {
if ($row.hasClass('jtable-row-selected')) {
this._deselectRows($row);
} else {
//Shift key?
if (this._shiftKeyDown) {
var rowIndex = this._findRowIndex($row);
//try to select row and above rows until first selected row
var beforeIndex = this._findFirstSelectedRowIndexBeforeIndex(rowIndex) + 1;
if (beforeIndex > 0 && beforeIndex < rowIndex) {
this._selectRows(this._$tableBody.find('tr').slice(beforeIndex, rowIndex + 1));
} else {
//try to select row and below rows until first selected row
var afterIndex = this._findFirstSelectedRowIndexAfterIndex(rowIndex) - 1;
if (afterIndex > rowIndex) {
this._selectRows(this._$tableBody.find('tr').slice(rowIndex, afterIndex + 1));
} else {
//just select this row
this._selectRows($row);
}
}
} else {
this._selectRows($row);
}
}
this._onSelectionChanged();
},
/* Search for a selected row (that is before given row index) to up and returns it's index
*************************************************************************/
_findFirstSelectedRowIndexBeforeIndex: function (rowIndex) {
for (var i = rowIndex - 1; i >= 0; --i) {
if (this._$tableRows[i].hasClass('jtable-row-selected')) {
return i;
}
}
return -1;
},
/* Search for a selected row (that is after given row index) to down and returns it's index
*************************************************************************/
_findFirstSelectedRowIndexAfterIndex: function (rowIndex) {
for (var i = rowIndex + 1; i < this._$tableRows.length; ++i) {
if (this._$tableRows[i].hasClass('jtable-row-selected')) {
return i;
}
}
return -1;
},
/* Makes row/rows 'selected'.
*************************************************************************/
_selectRows: function ($rows) {
if (!this.options.multiselect) {
this._deselectRows(this._getSelectedRows());
}
$rows.addClass('jtable-row-selected');
this._jqueryuiThemeAddClass($rows, 'ui-state-highlight');
if (this.options.selectingCheckboxes) {
$rows.find('>td.jtable-selecting-column >input').prop('checked', true);
}
this._refreshSelectAllCheckboxState();
},
/* Makes row/rows 'non selected'.
*************************************************************************/
_deselectRows: function ($rows) {
$rows.removeClass('jtable-row-selected ui-state-highlight');
if (this.options.selectingCheckboxes) {
$rows.find('>td.jtable-selecting-column >input').prop('checked', false);
}
this._refreshSelectAllCheckboxState();
},
/* Updates state of the 'select/deselect' all checkbox according to count of selected rows.
*************************************************************************/
_refreshSelectAllCheckboxState: function () {
if (!this.options.selectingCheckboxes || !this.options.multiselect) {
return;
}
var totalRowCount = this._$tableRows.length;
var selectedRowCount = this._getSelectedRows().length;
if (selectedRowCount == 0) {
this._$selectAllCheckbox.prop('indeterminate', false);
this._$selectAllCheckbox.attr('checked', false);
} else if (selectedRowCount == totalRowCount) {
this._$selectAllCheckbox.prop('indeterminate', false);
this._$selectAllCheckbox.attr('checked', true);
} else {
this._$selectAllCheckbox.attr('checked', false);
this._$selectAllCheckbox.prop('indeterminate', true);
}
},
/************************************************************************
* EVENT RAISING METHODS *
*************************************************************************/
_onSelectionChanged: function () {
this._trigger("selectionChanged", null, {});
}
});
})(jQuery);

View file

@ -0,0 +1,202 @@
/************************************************************************
* SORTING extension for jTable *
*************************************************************************/
(function ($) {
//Reference to base object members
var base = {
_initializeFields: $.hik.jtable.prototype._initializeFields,
_normalizeFieldOptions: $.hik.jtable.prototype._normalizeFieldOptions,
_createHeaderCellForField: $.hik.jtable.prototype._createHeaderCellForField,
_createRecordLoadUrl: $.hik.jtable.prototype._createRecordLoadUrl,
_createJtParamsForLoading: $.hik.jtable.prototype._createJtParamsForLoading
};
//extension members
$.extend(true, $.hik.jtable.prototype, {
/************************************************************************
* DEFAULT OPTIONS / EVENTS *
*************************************************************************/
options: {
sorting: false,
multiSorting: false,
defaultSorting: ''
},
/************************************************************************
* PRIVATE FIELDS *
*************************************************************************/
_lastSorting: null, //Last sorting of the table
/************************************************************************
* OVERRIDED METHODS *
*************************************************************************/
/* Overrides base method to create sorting array.
*************************************************************************/
_initializeFields: function () {
base._initializeFields.apply(this, arguments);
this._lastSorting = [];
if (this.options.sorting) {
this._buildDefaultSortingArray();
}
},
/* Overrides _normalizeFieldOptions method to normalize sorting option for fields.
*************************************************************************/
_normalizeFieldOptions: function (fieldName, props) {
base._normalizeFieldOptions.apply(this, arguments);
props.sorting = (props.sorting != false);
},
/* Overrides _createHeaderCellForField to make columns sortable.
*************************************************************************/
_createHeaderCellForField: function (fieldName, field) {
var $headerCell = base._createHeaderCellForField.apply(this, arguments);
if (this.options.sorting && field.sorting) {
this._makeColumnSortable($headerCell, fieldName);
}
return $headerCell;
},
/* Overrides _createRecordLoadUrl to add sorting specific info to URL.
*************************************************************************/
_createRecordLoadUrl: function () {
var loadUrl = base._createRecordLoadUrl.apply(this, arguments);
loadUrl = this._addSortingInfoToUrl(loadUrl);
return loadUrl;
},
/************************************************************************
* PRIVATE METHODS *
*************************************************************************/
/* Builds the sorting array according to defaultSorting string
*************************************************************************/
_buildDefaultSortingArray: function () {
var self = this;
$.each(self.options.defaultSorting.split(","), function (orderIndex, orderValue) {
$.each(self.options.fields, function (fieldName, fieldProps) {
if (fieldProps.sorting) {
var colOffset = orderValue.indexOf(fieldName);
if (colOffset > -1) {
if (orderValue.toUpperCase().indexOf(' DESC', colOffset) > -1) {
self._lastSorting.push({
fieldName: fieldName,
sortOrder: 'DESC'
});
} else {
self._lastSorting.push({
fieldName: fieldName,
sortOrder: 'ASC'
});
}
}
}
});
});
},
/* Makes a column sortable.
*************************************************************************/
_makeColumnSortable: function ($columnHeader, fieldName) {
var self = this;
$columnHeader
.addClass('jtable-column-header-sortable')
.click(function (e) {
e.preventDefault();
if (!self.options.multiSorting || !e.ctrlKey) {
self._lastSorting = []; //clear previous sorting
}
self._sortTableByColumn($columnHeader);
});
//Set default sorting
$.each(this._lastSorting, function (sortIndex, sortField) {
if (sortField.fieldName == fieldName) {
if (sortField.sortOrder == 'DESC') {
$columnHeader.addClass('jtable-column-header-sorted-desc');
} else {
$columnHeader.addClass('jtable-column-header-sorted-asc');
}
}
});
},
/* Sorts table according to a column header.
*************************************************************************/
_sortTableByColumn: function ($columnHeader) {
//Remove sorting styles from all columns except this one
if (this._lastSorting.length == 0) {
$columnHeader.siblings().removeClass('jtable-column-header-sorted-asc jtable-column-header-sorted-desc');
}
//If current sorting list includes this column, remove it from the list
for (var i = 0; i < this._lastSorting.length; i++) {
if (this._lastSorting[i].fieldName == $columnHeader.data('fieldName')) {
this._lastSorting.splice(i--, 1);
}
}
//Sort ASC or DESC according to current sorting state
if ($columnHeader.hasClass('jtable-column-header-sorted-asc')) {
$columnHeader.removeClass('jtable-column-header-sorted-asc').addClass('jtable-column-header-sorted-desc');
this._lastSorting.push({
'fieldName': $columnHeader.data('fieldName'),
sortOrder: 'DESC'
});
} else {
$columnHeader.removeClass('jtable-column-header-sorted-desc').addClass('jtable-column-header-sorted-asc');
this._lastSorting.push({
'fieldName': $columnHeader.data('fieldName'),
sortOrder: 'ASC'
});
}
//Load current page again
this._reloadTable();
},
/* Adds jtSorting parameter to a URL as query string.
*************************************************************************/
_addSortingInfoToUrl: function (url) {
if (!this.options.sorting || this._lastSorting.length == 0) {
return url;
}
var sorting = [];
$.each(this._lastSorting, function (idx, value) {
sorting.push(value.fieldName + ' ' + value.sortOrder);
});
return (url + (url.indexOf('?') < 0 ? '?' : '&') + 'jtSorting=' + sorting.join(","));
},
/* Overrides _createJtParamsForLoading method to add sorging parameters to jtParams object.
*************************************************************************/
_createJtParamsForLoading: function () {
var jtParams = base._createJtParamsForLoading.apply(this, arguments);
if (this.options.sorting && this._lastSorting.length) {
var sorting = [];
$.each(this._lastSorting, function (idx, value) {
sorting.push(value.fieldName + ' ' + value.sortOrder);
});
jtParams.jtSorting = sorting.join(",");
}
return jtParams;
}
});
})(jQuery);

View file

@ -0,0 +1,159 @@
/************************************************************************
* Some UTULITY methods used by jTable *
*************************************************************************/
(function ($) {
$.extend(true, $.hik.jtable.prototype, {
/* Gets property value of an object recursively.
*************************************************************************/
_getPropertyOfObject: function (obj, propName) {
if (propName.indexOf('.') < 0) {
return obj[propName];
} else {
var preDot = propName.substring(0, propName.indexOf('.'));
var postDot = propName.substring(propName.indexOf('.') + 1);
return this._getPropertyOfObject(obj[preDot], postDot);
}
},
/* Sets property value of an object recursively.
*************************************************************************/
_setPropertyOfObject: function (obj, propName, value) {
if (propName.indexOf('.') < 0) {
obj[propName] = value;
} else {
var preDot = propName.substring(0, propName.indexOf('.'));
var postDot = propName.substring(propName.indexOf('.') + 1);
this._setPropertyOfObject(obj[preDot], postDot, value);
}
},
/* Inserts a value to an array if it does not exists in the array.
*************************************************************************/
_insertToArrayIfDoesNotExists: function (array, value) {
if ($.inArray(value, array) < 0) {
array.push(value);
}
},
/* Finds index of an element in an array according to given comparision function
*************************************************************************/
_findIndexInArray: function (value, array, compareFunc) {
//If not defined, use default comparision
if (!compareFunc) {
compareFunc = function (a, b) {
return a == b;
};
}
for (var i = 0; i < array.length; i++) {
if (compareFunc(value, array[i])) {
return i;
}
}
return -1;
},
/* Normalizes a number between given bounds or sets to a defaultValue
* if it is undefined
*************************************************************************/
_normalizeNumber: function (number, min, max, defaultValue) {
if (number == undefined || number == null || isNaN(number)) {
return defaultValue;
}
if (number < min) {
return min;
}
if (number > max) {
return max;
}
return number;
},
/* Formats a string just like string.format in c#.
* Example:
* _formatString('Hello {0}','Halil') = 'Hello Halil'
*************************************************************************/
_formatString: function () {
if (arguments.length == 0) {
return null;
}
var str = arguments[0];
for (var i = 1; i < arguments.length; i++) {
var placeHolder = '{' + (i - 1) + '}';
str = str.replace(placeHolder, arguments[i]);
}
return str;
},
/* Checks if given object is a jQuery Deferred object.
*/
_isDeferredObject: function (obj) {
return obj.then && obj.done && obj.fail;
},
//Logging methods ////////////////////////////////////////////////////////
_logDebug: function (text) {
if (!window.console) {
return;
}
console.log('jTable DEBUG: ' + text);
},
_logInfo: function (text) {
if (!window.console) {
return;
}
console.log('jTable INFO: ' + text);
},
_logWarn: function (text) {
if (!window.console) {
return;
}
console.log('jTable WARNING: ' + text);
},
_logError: function (text) {
if (!window.console) {
return;
}
console.log('jTable ERROR: ' + text);
}
});
/* Fix for array.indexOf method in IE7.
* This code is taken from http://www.tutorialspoint.com/javascript/array_indexof.htm */
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (elt) {
var len = this.length;
var from = Number(arguments[1]) || 0;
from = (from < 0)
? Math.ceil(from)
: Math.floor(from);
if (from < 0)
from += len;
for (; from < len; from++) {
if (from in this &&
this[from] === elt)
return from;
}
return -1;
};
}
})(jQuery);