| /* |
| |
| 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. |
| |
| */ |
| |
| /************************************************************************ |
| * CORE jTable module * |
| *************************************************************************/ |
| (function ($) { |
| |
| var unloadingPage; |
| |
| $(window).on('beforeunload', function () { |
| unloadingPage = true; |
| }); |
| $(window).on('unload', function () { |
| unloadingPage = false; |
| }); |
| |
| $.widget("hik.jtable", { |
| |
| /************************************************************************ |
| * DEFAULT OPTIONS / EVENTS * |
| *************************************************************************/ |
| options: { |
| |
| //Options |
| actions: {}, |
| fields: {}, |
| animationsEnabled: true, |
| defaultDateFormat: 'yy-mm-dd', |
| dialogShowEffect: 'fade', |
| dialogHideEffect: 'fade', |
| showCloseButton: false, |
| loadingAnimationDelay: 500, |
| saveUserPreferences: true, |
| jqueryuiTheme: false, |
| unAuthorizedRequestRedirectUrl: null, |
| |
| ajaxSettings: { |
| type: 'POST', |
| dataType: 'json' |
| }, |
| |
| toolbar: { |
| hoverAnimation: true, |
| hoverAnimationDuration: 60, |
| hoverAnimationEasing: undefined, |
| items: [] |
| }, |
| |
| //Events |
| closeRequested: function (event, data) { }, |
| formCreated: function (event, data) { }, |
| formSubmitting: function (event, data) { }, |
| formClosed: function (event, data) { }, |
| loadingRecords: function (event, data) { }, |
| recordsLoaded: function (event, data) { }, |
| rowInserted: function (event, data) { }, |
| rowsRemoved: function (event, data) { }, |
| |
| //Localization |
| messages: { |
| serverCommunicationError: 'An error occured while communicating to the server.', |
| loadingMessage: 'Loading records...', |
| noDataAvailable: 'No data available!', |
| areYouSure: 'Are you sure?', |
| save: 'Save', |
| saving: 'Saving', |
| cancel: 'Cancel', |
| error: 'Error', |
| close: 'Close', |
| cannotLoadOptionsFor: 'Can not load options for field {0}' |
| } |
| }, |
| |
| /************************************************************************ |
| * PRIVATE FIELDS * |
| *************************************************************************/ |
| |
| _$mainContainer: null, //Reference to the main container of all elements that are created by this plug-in (jQuery object) |
| |
| _$titleDiv: null, //Reference to the title div (jQuery object) |
| _$toolbarDiv: null, //Reference to the toolbar div (jQuery object) |
| |
| _$table: null, //Reference to the main <table> (jQuery object) |
| _$tableBody: null, //Reference to <body> in the table (jQuery object) |
| _$tableRows: null, //Array of all <tr> in the table (except "no data" row) (jQuery object array) |
| |
| _$busyDiv: null, //Reference to the div that is used to block UI while busy (jQuery object) |
| _$busyMessageDiv: null, //Reference to the div that is used to show some message when UI is blocked (jQuery object) |
| _$errorDialogDiv: null, //Reference to the error dialog div (jQuery object) |
| |
| _columnList: null, //Name of all data columns in the table (select column and command columns are not included) (string array) |
| _fieldList: null, //Name of all fields of a record (defined in fields option) (string array) |
| _keyField: null, //Name of the key field of a record (that is defined as 'key: true' in the fields option) (string) |
| |
| _firstDataColumnOffset: 0, //Start index of first record field in table columns (some columns can be placed before first data column, such as select checkbox column) (integer) |
| _lastPostData: null, //Last posted data on load method (object) |
| |
| _cache: null, //General purpose cache dictionary (object) |
| |
| /************************************************************************ |
| * CONSTRUCTOR AND INITIALIZATION METHODS * |
| *************************************************************************/ |
| |
| /* Contructor. |
| *************************************************************************/ |
| _create: function () { |
| |
| //Initialization |
| this._normalizeFieldsOptions(); |
| this._initializeFields(); |
| this._createFieldAndColumnList(); |
| |
| //Creating DOM elements |
| this._createMainContainer(); |
| this._createTableTitle(); |
| this._createToolBar(); |
| this._createTable(); |
| this._createBusyPanel(); |
| this._createErrorDialogDiv(); |
| this._addNoDataRow(); |
| |
| this._cookieKeyPrefix = this._generateCookieKeyPrefix(); |
| }, |
| |
| /* Normalizes some options for all fields (sets default values). |
| *************************************************************************/ |
| _normalizeFieldsOptions: function () { |
| var self = this; |
| $.each(self.options.fields, function (fieldName, props) { |
| self._normalizeFieldOptions(fieldName, props); |
| }); |
| }, |
| |
| /* Normalizes some options for a field (sets default values). |
| *************************************************************************/ |
| _normalizeFieldOptions: function (fieldName, props) { |
| if (props.listClass == undefined) { |
| props.listClass = ''; |
| } |
| if (props.inputClass == undefined) { |
| props.inputClass = ''; |
| } |
| |
| //Convert dependsOn to array if it's a comma seperated lists |
| if (props.dependsOn && $.type(props.dependsOn) === 'string') { |
| var dependsOnArray = props.dependsOn.split(','); |
| props.dependsOn = []; |
| for (var i = 0; i < dependsOnArray.length; i++) { |
| props.dependsOn.push($.trim(dependsOnArray[i])); |
| } |
| } |
| }, |
| |
| /* Intializes some private variables. |
| *************************************************************************/ |
| _initializeFields: function () { |
| this._lastPostData = {}; |
| this._$tableRows = []; |
| this._columnList = []; |
| this._fieldList = []; |
| this._cache = []; |
| }, |
| |
| /* Fills _fieldList, _columnList arrays and sets _keyField variable. |
| *************************************************************************/ |
| _createFieldAndColumnList: function () { |
| var self = this; |
| |
| $.each(self.options.fields, function (name, props) { |
| |
| //Add field to the field list |
| self._fieldList.push(name); |
| |
| //Check if this field is the key field |
| if (props.key == true) { |
| self._keyField = name; |
| } |
| |
| //Add field to column list if it is shown in the table |
| if (props.list != false && props.type != 'hidden') { |
| self._columnList.push(name); |
| } |
| }); |
| }, |
| |
| /* Creates the main container div. |
| *************************************************************************/ |
| _createMainContainer: function () { |
| this._$mainContainer = $('<div />') |
| .addClass('jtable-main-container') |
| .appendTo(this.element); |
| |
| this._jqueryuiThemeAddClass(this._$mainContainer, 'ui-widget'); |
| }, |
| |
| /* Creates title of the table if a title supplied in options. |
| *************************************************************************/ |
| _createTableTitle: function () { |
| var self = this; |
| |
| if (!self.options.title) { |
| return; |
| } |
| |
| var $titleDiv = $('<div />') |
| .addClass('jtable-title') |
| .appendTo(self._$mainContainer); |
| |
| self._jqueryuiThemeAddClass($titleDiv, 'ui-widget-header'); |
| |
| $('<div />') |
| .addClass('jtable-title-text') |
| .appendTo($titleDiv) |
| .append(self.options.title); |
| |
| if (self.options.showCloseButton) { |
| |
| var $textSpan = $('<span />') |
| .html(self.options.messages.close); |
| |
| $('<button></button>') |
| .addClass('jtable-command-button jtable-close-button') |
| .attr('title', self.options.messages.close) |
| .append($textSpan) |
| .appendTo($titleDiv) |
| .click(function (e) { |
| e.preventDefault(); |
| e.stopPropagation(); |
| self._onCloseRequested(); |
| }); |
| } |
| |
| self._$titleDiv = $titleDiv; |
| }, |
| |
| /* Creates the table. |
| *************************************************************************/ |
| _createTable: function () { |
| this._$table = $('<table></table>') |
| .addClass('jtable') |
| .appendTo(this._$mainContainer); |
| |
| if (this.options.tableId) { |
| this._$table.attr('id', this.options.tableId); |
| } |
| |
| this._jqueryuiThemeAddClass(this._$table, 'ui-widget-content'); |
| |
| this._createTableHead(); |
| this._createTableBody(); |
| }, |
| |
| /* Creates header (all column headers) of the table. |
| *************************************************************************/ |
| _createTableHead: function () { |
| var $thead = $('<thead></thead>') |
| .appendTo(this._$table); |
| |
| this._addRowToTableHead($thead); |
| }, |
| |
| /* Adds tr element to given thead element |
| *************************************************************************/ |
| _addRowToTableHead: function ($thead) { |
| var $tr = $('<tr></tr>') |
| .appendTo($thead); |
| |
| this._addColumnsToHeaderRow($tr); |
| }, |
| |
| /* Adds column header cells to given tr element. |
| *************************************************************************/ |
| _addColumnsToHeaderRow: function ($tr) { |
| for (var i = 0; i < this._columnList.length; i++) { |
| var fieldName = this._columnList[i]; |
| var $headerCell = this._createHeaderCellForField(fieldName, this.options.fields[fieldName]); |
| $headerCell.appendTo($tr); |
| } |
| }, |
| |
| /* Creates a header cell for given field. |
| * Returns th jQuery object. |
| *************************************************************************/ |
| _createHeaderCellForField: function (fieldName, field) { |
| field.width = field.width || '10%'; //default column width: 10%. |
| |
| var $headerTextSpan = $('<span />') |
| .addClass('jtable-column-header-text') |
| .html(field.title); |
| |
| var $headerContainerDiv = $('<div />') |
| .addClass('jtable-column-header-container') |
| .append($headerTextSpan); |
| |
| var $th = $('<th></th>') |
| .addClass('jtable-column-header') |
| .addClass(field.listClass) |
| .css('width', field.width) |
| .data('fieldName', fieldName) |
| .append($headerContainerDiv); |
| |
| this._jqueryuiThemeAddClass($th, 'ui-state-default'); |
| |
| return $th; |
| }, |
| |
| /* Creates an empty header cell that can be used as command column headers. |
| *************************************************************************/ |
| _createEmptyCommandHeader: function () { |
| var $th = $('<th></th>') |
| .addClass('jtable-command-column-header') |
| .css('width', '1%'); |
| |
| this._jqueryuiThemeAddClass($th, 'ui-state-default'); |
| |
| return $th; |
| }, |
| |
| /* Creates tbody tag and adds to the table. |
| *************************************************************************/ |
| _createTableBody: function () { |
| this._$tableBody = $('<tbody></tbody>').appendTo(this._$table); |
| }, |
| |
| /* Creates a div to block UI while jTable is busy. |
| *************************************************************************/ |
| _createBusyPanel: function () { |
| this._$busyMessageDiv = $('<div />').addClass('jtable-busy-message').prependTo(this._$mainContainer); |
| this._$busyDiv = $('<div />').addClass('jtable-busy-panel-background').prependTo(this._$mainContainer); |
| this._jqueryuiThemeAddClass(this._$busyMessageDiv, 'ui-widget-header'); |
| this._hideBusy(); |
| }, |
| |
| /* Creates and prepares error dialog div. |
| *************************************************************************/ |
| _createErrorDialogDiv: function () { |
| var self = this; |
| |
| self._$errorDialogDiv = $('<div></div>').appendTo(self._$mainContainer); |
| self._$errorDialogDiv.dialog({ |
| autoOpen: false, |
| show: self.options.dialogShowEffect, |
| hide: self.options.dialogHideEffect, |
| modal: true, |
| title: self.options.messages.error, |
| buttons: [{ |
| text: self.options.messages.close, |
| click: function () { |
| self._$errorDialogDiv.dialog('close'); |
| } |
| }] |
| }); |
| }, |
| |
| /************************************************************************ |
| * PUBLIC METHODS * |
| *************************************************************************/ |
| |
| /* Loads data using AJAX call, clears table and fills with new data. |
| *************************************************************************/ |
| load: function (postData, completeCallback) { |
| this._lastPostData = postData; |
| this._reloadTable(completeCallback); |
| }, |
| |
| /* Refreshes (re-loads) table data with last postData. |
| *************************************************************************/ |
| reload: function (completeCallback) { |
| this._reloadTable(completeCallback); |
| }, |
| |
| /* Gets a jQuery row object according to given record key |
| *************************************************************************/ |
| getRowByKey: function (key) { |
| for (var i = 0; i < this._$tableRows.length; i++) { |
| if (key == this._getKeyValueOfRecord(this._$tableRows[i].data('record'))) { |
| return this._$tableRows[i]; |
| } |
| } |
| |
| return null; |
| }, |
| |
| /* Completely removes the table from it's container. |
| *************************************************************************/ |
| destroy: function () { |
| this.element.empty(); |
| $.Widget.prototype.destroy.call(this); |
| }, |
| |
| /************************************************************************ |
| * PRIVATE METHODS * |
| *************************************************************************/ |
| |
| /* Used to change options dynamically after initialization. |
| *************************************************************************/ |
| _setOption: function (key, value) { |
| |
| }, |
| |
| /* LOADING RECORDS *****************************************************/ |
| |
| /* Performs an AJAX call to reload data of the table. |
| *************************************************************************/ |
| _reloadTable: function (completeCallback) { |
| var self = this; |
| |
| var completeReload = function(data) { |
| self._hideBusy(); |
| |
| //Show the error message if server returns error |
| if (data.Result != 'OK') { |
| self._showError(data.Message); |
| return; |
| } |
| |
| //Re-generate table rows |
| self._removeAllRows('reloading'); |
| self._addRecordsToTable(data.Records); |
| |
| self._onRecordsLoaded(data); |
| |
| //Call complete callback |
| if (completeCallback) { |
| completeCallback(); |
| } |
| }; |
| |
| self._showBusy(self.options.messages.loadingMessage, self.options.loadingAnimationDelay); //Disable table since it's busy |
| self._onLoadingRecords(); |
| |
| //listAction may be a function, check if it is |
| if ($.isFunction(self.options.actions.listAction)) { |
| |
| //Execute the function |
| var funcResult = self.options.actions.listAction(self._lastPostData, self._createJtParamsForLoading()); |
| |
| //Check if result is a jQuery Deferred object |
| if (self._isDeferredObject(funcResult)) { |
| funcResult.done(function(data) { |
| completeReload(data); |
| }).fail(function() { |
| self._showError(self.options.messages.serverCommunicationError); |
| }).always(function() { |
| self._hideBusy(); |
| }); |
| } else { //assume it's the data we're loading |
| completeReload(funcResult); |
| } |
| |
| } else { //assume listAction as URL string. |
| |
| //Generate URL (with query string parameters) to load records |
| var loadUrl = self._createRecordLoadUrl(); |
| |
| //Load data from server using AJAX |
| self._ajax({ |
| url: loadUrl, |
| data: self._lastPostData, |
| success: function (data) { |
| completeReload(data); |
| }, |
| error: function () { |
| self._hideBusy(); |
| self._showError(self.options.messages.serverCommunicationError); |
| } |
| }); |
| |
| } |
| }, |
| |
| /* Creates URL to load records. |
| *************************************************************************/ |
| _createRecordLoadUrl: function () { |
| return this.options.actions.listAction; |
| }, |
| |
| _createJtParamsForLoading: function() { |
| return { |
| //Empty as default, paging, sorting or other extensions can override this method to add additional params to load request |
| }; |
| }, |
| |
| /* TABLE MANIPULATION METHODS *******************************************/ |
| |
| /* Creates a row from given record |
| *************************************************************************/ |
| _createRowFromRecord: function (record) { |
| var $tr = $('<tr></tr>') |
| .addClass('jtable-data-row') |
| .attr('data-record-key', this._getKeyValueOfRecord(record)) |
| .data('record', record); |
| |
| this._addCellsToRowUsingRecord($tr); |
| return $tr; |
| }, |
| |
| /* Adds all cells to given row. |
| *************************************************************************/ |
| _addCellsToRowUsingRecord: function ($row) { |
| var record = $row.data('record'); |
| for (var i = 0; i < this._columnList.length; i++) { |
| this._createCellForRecordField(record, this._columnList[i]) |
| .appendTo($row); |
| } |
| }, |
| |
| /* Create a cell for given field. |
| *************************************************************************/ |
| _createCellForRecordField: function (record, fieldName) { |
| return $('<td></td>') |
| .addClass(this.options.fields[fieldName].listClass) |
| .append((this._getDisplayTextForRecordField(record, fieldName))); |
| }, |
| |
| /* Adds a list of records to the table. |
| *************************************************************************/ |
| _addRecordsToTable: function (records) { |
| var self = this; |
| |
| $.each(records, function (index, record) { |
| self._addRow(self._createRowFromRecord(record)); |
| }); |
| |
| self._refreshRowStyles(); |
| }, |
| |
| /* Adds a single row to the table. |
| * NOTE: THIS METHOD IS DEPRECATED AND WILL BE REMOVED FROM FEATURE RELEASES. |
| * USE _addRow METHOD. |
| *************************************************************************/ |
| _addRowToTable: function ($tableRow, index, isNewRow, animationsEnabled) { |
| var options = { |
| index: this._normalizeNumber(index, 0, this._$tableRows.length, this._$tableRows.length) |
| }; |
| |
| if (isNewRow == true) { |
| options.isNewRow = true; |
| } |
| |
| if (animationsEnabled == false) { |
| options.animationsEnabled = false; |
| } |
| |
| this._addRow($tableRow, options); |
| }, |
| |
| /* Adds a single row to the table. |
| *************************************************************************/ |
| _addRow: function ($row, options) { |
| //Set defaults |
| options = $.extend({ |
| index: this._$tableRows.length, |
| isNewRow: false, |
| animationsEnabled: true |
| }, options); |
| |
| //Remove 'no data' row if this is first row |
| if (this._$tableRows.length <= 0) { |
| this._removeNoDataRow(); |
| } |
| |
| //Add new row to the table according to it's index |
| options.index = this._normalizeNumber(options.index, 0, this._$tableRows.length, this._$tableRows.length); |
| if (options.index == this._$tableRows.length) { |
| //add as last row |
| this._$tableBody.append($row); |
| this._$tableRows.push($row); |
| } else if (options.index == 0) { |
| //add as first row |
| this._$tableBody.prepend($row); |
| this._$tableRows.unshift($row); |
| } else { |
| //insert to specified index |
| this._$tableRows[options.index - 1].after($row); |
| this._$tableRows.splice(options.index, 0, $row); |
| } |
| |
| this._onRowInserted($row, options.isNewRow); |
| |
| //Show animation if needed |
| if (options.isNewRow) { |
| this._refreshRowStyles(); |
| if (this.options.animationsEnabled && options.animationsEnabled) { |
| this._showNewRowAnimation($row); |
| } |
| } |
| }, |
| |
| /* Shows created animation for a table row |
| * TODO: Make this animation cofigurable and changable |
| *************************************************************************/ |
| _showNewRowAnimation: function ($tableRow) { |
| var className = 'jtable-row-created'; |
| if (this.options.jqueryuiTheme) { |
| className = className + ' ui-state-highlight'; |
| } |
| |
| $tableRow.addClass(className, 'slow', '', function () { |
| $tableRow.removeClass(className, 5000); |
| }); |
| }, |
| |
| /* Removes a row or rows (jQuery selection) from table. |
| *************************************************************************/ |
| _removeRowsFromTable: function ($rows, reason) { |
| var self = this; |
| |
| //Check if any row specified |
| if ($rows.length <= 0) { |
| return; |
| } |
| |
| //remove from DOM |
| $rows.addClass('jtable-row-removed').remove(); |
| |
| //remove from _$tableRows array |
| $rows.each(function () { |
| var index = self._findRowIndex($(this)); |
| if (index >= 0) { |
| self._$tableRows.splice(index, 1); |
| } |
| }); |
| |
| self._onRowsRemoved($rows, reason); |
| |
| //Add 'no data' row if all rows removed from table |
| if (self._$tableRows.length == 0) { |
| self._addNoDataRow(); |
| } |
| |
| self._refreshRowStyles(); |
| }, |
| |
| /* Finds index of a row in table. |
| *************************************************************************/ |
| _findRowIndex: function ($row) { |
| return this._findIndexInArray($row, this._$tableRows, function ($row1, $row2) { |
| return $row1.data('record') == $row2.data('record'); |
| }); |
| }, |
| |
| /* Removes all rows in the table and adds 'no data' row. |
| *************************************************************************/ |
| _removeAllRows: function (reason) { |
| //If no rows does exists, do nothing |
| if (this._$tableRows.length <= 0) { |
| return; |
| } |
| |
| //Select all rows (to pass it on raising _onRowsRemoved event) |
| var $rows = this._$tableBody.find('tr.jtable-data-row'); |
| |
| //Remove all rows from DOM and the _$tableRows array |
| this._$tableBody.empty(); |
| this._$tableRows = []; |
| |
| this._onRowsRemoved($rows, reason); |
| |
| //Add 'no data' row since we removed all rows |
| this._addNoDataRow(); |
| }, |
| |
| /* Adds "no data available" row to the table. |
| *************************************************************************/ |
| _addNoDataRow: function () { |
| if (this._$tableBody.find('>tr.jtable-no-data-row').length > 0) { |
| return; |
| } |
| |
| var $tr = $('<tr></tr>') |
| .addClass('jtable-no-data-row') |
| .appendTo(this._$tableBody); |
| |
| var totalColumnCount = this._$table.find('thead th').length; |
| $('<td></td>') |
| .attr('colspan', totalColumnCount) |
| .html(this.options.messages.noDataAvailable) |
| .appendTo($tr); |
| }, |
| |
| /* Removes "no data available" row from the table. |
| *************************************************************************/ |
| _removeNoDataRow: function () { |
| this._$tableBody.find('.jtable-no-data-row').remove(); |
| }, |
| |
| /* Refreshes styles of all rows in the table |
| *************************************************************************/ |
| _refreshRowStyles: function () { |
| for (var i = 0; i < this._$tableRows.length; i++) { |
| if (i % 2 == 0) { |
| this._$tableRows[i].addClass('jtable-row-even'); |
| } else { |
| this._$tableRows[i].removeClass('jtable-row-even'); |
| } |
| } |
| }, |
| |
| /* RENDERING FIELD VALUES ***********************************************/ |
| |
| /* Gets text for a field of a record according to it's type. |
| *************************************************************************/ |
| _getDisplayTextForRecordField: function (record, fieldName) { |
| var field = this.options.fields[fieldName]; |
| var fieldValue = record[fieldName]; |
| |
| //if this is a custom field, call display function |
| if (field.display) { |
| return field.display({ record: record }); |
| } |
| |
| if (field.type == 'date') { |
| return this._getDisplayTextForDateRecordField(field, fieldValue); |
| } else if (field.type == 'checkbox') { |
| return this._getCheckBoxTextForFieldByValue(fieldName, fieldValue); |
| } else if (field.options) { //combobox or radio button list since there are options. |
| var options = this._getOptionsForField(fieldName, { |
| record: record, |
| value: fieldValue, |
| source: 'list', |
| dependedValues: this._createDependedValuesUsingRecord(record, field.dependsOn) |
| }); |
| return this._findOptionByValue(options, fieldValue).DisplayText; |
| } else { //other types |
| return fieldValue; |
| } |
| }, |
| |
| /* Creates and returns an object that's properties are depended values of a record. |
| *************************************************************************/ |
| _createDependedValuesUsingRecord: function (record, dependsOn) { |
| if (!dependsOn) { |
| return {}; |
| } |
| |
| var dependedValues = {}; |
| for (var i = 0; i < dependsOn.length; i++) { |
| dependedValues[dependsOn[i]] = record[dependsOn[i]]; |
| } |
| |
| return dependedValues; |
| }, |
| |
| /* Finds an option object by given value. |
| *************************************************************************/ |
| _findOptionByValue: function (options, value) { |
| for (var i = 0; i < options.length; i++) { |
| if (options[i].Value == value) { |
| return options[i]; |
| } |
| } |
| |
| return {}; //no option found |
| }, |
| |
| /* Gets text for a date field. |
| *************************************************************************/ |
| _getDisplayTextForDateRecordField: function (field, fieldValue) { |
| if (!fieldValue) { |
| return ''; |
| } |
| |
| var displayFormat = field.displayFormat || this.options.defaultDateFormat; |
| var date = this._parseDate(fieldValue); |
| return $.datepicker.formatDate(displayFormat, date); |
| }, |
| |
| /* Gets options for a field according to user preferences. |
| *************************************************************************/ |
| _getOptionsForField: function (fieldName, funcParams) { |
| var field = this.options.fields[fieldName]; |
| var optionsSource = field.options; |
| |
| if ($.isFunction(optionsSource)) { |
| //prepare parameter to the function |
| funcParams = $.extend(true, { |
| _cacheCleared: false, |
| dependedValues: {}, |
| clearCache: function () { |
| this._cacheCleared = true; |
| } |
| }, funcParams); |
| |
| //call function and get actual options source |
| optionsSource = optionsSource(funcParams); |
| } |
| |
| var options; |
| |
| //Build options according to it's source type |
| if (typeof optionsSource == 'string') { //It is an Url to download options |
| var cacheKey = 'options_' + fieldName + '_' + optionsSource; //create a unique cache key |
| if (funcParams._cacheCleared || (!this._cache[cacheKey])) { |
| //if user calls clearCache() or options are not found in the cache, download options |
| this._cache[cacheKey] = this._buildOptionsFromArray(this._downloadOptions(fieldName, optionsSource)); |
| this._sortFieldOptions(this._cache[cacheKey], field.optionsSorting); |
| } else { |
| //found on cache.. |
| //if this method (_getOptionsForField) is called to get option for a specific value (on funcParams.source == 'list') |
| //and this value is not in cached options, we need to re-download options to get the unfound (probably new) option. |
| if (funcParams.value != undefined) { |
| var optionForValue = this._findOptionByValue(this._cache[cacheKey], funcParams.value); |
| if (optionForValue.DisplayText == undefined) { //this value is not in cached options... |
| this._cache[cacheKey] = this._buildOptionsFromArray(this._downloadOptions(fieldName, optionsSource)); |
| this._sortFieldOptions(this._cache[cacheKey], field.optionsSorting); |
| } |
| } |
| } |
| |
| options = this._cache[cacheKey]; |
| } else if (jQuery.isArray(optionsSource)) { //It is an array of options |
| options = this._buildOptionsFromArray(optionsSource); |
| this._sortFieldOptions(options, field.optionsSorting); |
| } else { //It is an object that it's properties are options |
| options = this._buildOptionsArrayFromObject(optionsSource); |
| this._sortFieldOptions(options, field.optionsSorting); |
| } |
| |
| return options; |
| }, |
| |
| /* Download options for a field from server. |
| *************************************************************************/ |
| _downloadOptions: function (fieldName, url) { |
| var self = this; |
| var options = []; |
| |
| self._ajax({ |
| url: url, |
| async: false, |
| success: function (data) { |
| if (data.Result != 'OK') { |
| self._showError(data.Message); |
| return; |
| } |
| |
| options = data.Options; |
| }, |
| error: function () { |
| var errMessage = self._formatString(self.options.messages.cannotLoadOptionsFor, fieldName); |
| self._showError(errMessage); |
| } |
| }); |
| |
| return options; |
| }, |
| |
| /* Sorts given options according to sorting parameter. |
| * sorting can be: 'value', 'value-desc', 'text' or 'text-desc'. |
| *************************************************************************/ |
| _sortFieldOptions: function (options, sorting) { |
| |
| if ((!options) || (!options.length) || (!sorting)) { |
| return; |
| } |
| |
| //Determine using value of text |
| var dataSelector; |
| if (sorting.indexOf('value') == 0) { |
| dataSelector = function (option) { |
| return option.Value; |
| }; |
| } else { //assume as text |
| dataSelector = function (option) { |
| return option.DisplayText; |
| }; |
| } |
| |
| var compareFunc; |
| if ($.type(dataSelector(options[0])) == 'string') { |
| compareFunc = function (option1, option2) { |
| return dataSelector(option1).localeCompare(dataSelector(option2)); |
| }; |
| } else { //asuume as numeric |
| compareFunc = function (option1, option2) { |
| return dataSelector(option1) - dataSelector(option2); |
| }; |
| } |
| |
| if (sorting.indexOf('desc') > 0) { |
| options.sort(function (a, b) { |
| return compareFunc(b, a); |
| }); |
| } else { //assume as asc |
| options.sort(function (a, b) { |
| return compareFunc(a, b); |
| }); |
| } |
| }, |
| |
| /* Creates an array of options from given object. |
| *************************************************************************/ |
| _buildOptionsArrayFromObject: function (options) { |
| var list = []; |
| |
| $.each(options, function (propName, propValue) { |
| list.push({ |
| Value: propName, |
| DisplayText: propValue |
| }); |
| }); |
| |
| return list; |
| }, |
| |
| /* Creates array of options from giving options array. |
| *************************************************************************/ |
| _buildOptionsFromArray: function (optionsArray) { |
| var list = []; |
| |
| for (var i = 0; i < optionsArray.length; i++) { |
| if ($.isPlainObject(optionsArray[i])) { |
| list.push(optionsArray[i]); |
| } else { //assumed as primitive type (int, string...) |
| list.push({ |
| Value: optionsArray[i], |
| DisplayText: optionsArray[i] |
| }); |
| } |
| } |
| |
| return list; |
| }, |
| |
| /* Parses given date string to a javascript Date object. |
| * Given string must be formatted one of the samples shown below: |
| * /Date(1320259705710)/ |
| * 2011-01-01 20:32:42 (YYYY-MM-DD HH:MM:SS) |
| * 2011-01-01 (YYYY-MM-DD) |
| *************************************************************************/ |
| _parseDate: function (dateString) { |
| if (dateString.indexOf('Date') >= 0) { //Format: /Date(1320259705710)/ |
| return new Date( |
| parseInt(dateString.substr(6), 10) |
| ); |
| } else if (dateString.length == 10) { //Format: 2011-01-01 |
| return new Date( |
| parseInt(dateString.substr(0, 4), 10), |
| parseInt(dateString.substr(5, 2), 10) - 1, |
| parseInt(dateString.substr(8, 2), 10) |
| ); |
| } else if (dateString.length == 19) { //Format: 2011-01-01 20:32:42 |
| return new Date( |
| parseInt(dateString.substr(0, 4), 10), |
| parseInt(dateString.substr(5, 2), 10) - 1, |
| parseInt(dateString.substr(8, 2, 10)), |
| parseInt(dateString.substr(11, 2), 10), |
| parseInt(dateString.substr(14, 2), 10), |
| parseInt(dateString.substr(17, 2), 10) |
| ); |
| } else { |
| this._logWarn('Given date is not properly formatted: ' + dateString); |
| return 'format error!'; |
| } |
| }, |
| |
| /* TOOL BAR *************************************************************/ |
| |
| /* Creates the toolbar. |
| *************************************************************************/ |
| _createToolBar: function () { |
| this._$toolbarDiv = $('<div />') |
| .addClass('jtable-toolbar') |
| .appendTo(this._$titleDiv); |
| |
| for (var i = 0; i < this.options.toolbar.items.length; i++) { |
| this._addToolBarItem(this.options.toolbar.items[i]); |
| } |
| }, |
| |
| /* Adds a new item to the toolbar. |
| *************************************************************************/ |
| _addToolBarItem: function (item) { |
| |
| //Check if item is valid |
| if ((item == undefined) || (item.text == undefined && item.icon == undefined)) { |
| this._logWarn('Can not add tool bar item since it is not valid!'); |
| this._logWarn(item); |
| return null; |
| } |
| |
| var $toolBarItem = $('<span></span>') |
| .addClass('jtable-toolbar-item') |
| .appendTo(this._$toolbarDiv); |
| |
| this._jqueryuiThemeAddClass($toolBarItem, 'ui-widget ui-state-default ui-corner-all', 'ui-state-hover'); |
| |
| //cssClass property |
| if (item.cssClass) { |
| $toolBarItem |
| .addClass(item.cssClass); |
| } |
| |
| //tooltip property |
| if (item.tooltip) { |
| $toolBarItem |
| .attr('title', item.tooltip); |
| } |
| |
| //icon property |
| if (item.icon) { |
| var $icon = $('<span class="jtable-toolbar-item-icon"></span>').appendTo($toolBarItem); |
| if (item.icon === true) { |
| //do nothing |
| } else if ($.type(item.icon === 'string')) { |
| $icon.css('background', 'url("' + item.icon + '")'); |
| } |
| } |
| |
| //text property |
| if (item.text) { |
| $('<span class=""></span>') |
| .html(item.text) |
| .addClass('jtable-toolbar-item-text').appendTo($toolBarItem); |
| } |
| |
| //click event |
| if (item.click) { |
| $toolBarItem.click(function () { |
| item.click(); |
| }); |
| } |
| |
| //set hover animation parameters |
| var hoverAnimationDuration = undefined; |
| var hoverAnimationEasing = undefined; |
| if (this.options.toolbar.hoverAnimation) { |
| hoverAnimationDuration = this.options.toolbar.hoverAnimationDuration; |
| hoverAnimationEasing = this.options.toolbar.hoverAnimationEasing; |
| } |
| |
| //change class on hover |
| $toolBarItem.hover(function () { |
| $toolBarItem.addClass('jtable-toolbar-item-hover', hoverAnimationDuration, hoverAnimationEasing); |
| }, function () { |
| $toolBarItem.removeClass('jtable-toolbar-item-hover', hoverAnimationDuration, hoverAnimationEasing); |
| }); |
| |
| return $toolBarItem; |
| }, |
| |
| /* ERROR DIALOG *********************************************************/ |
| |
| /* Shows error message dialog with given message. |
| *************************************************************************/ |
| _showError: function (message) { |
| this._$errorDialogDiv.html(message).dialog('open'); |
| }, |
| |
| /* BUSY PANEL ***********************************************************/ |
| |
| /* Shows busy indicator and blocks table UI. |
| * TODO: Make this cofigurable and changable |
| *************************************************************************/ |
| _setBusyTimer: null, |
| _showBusy: function (message, delay) { |
| var self = this; // |
| |
| //Show a transparent overlay to prevent clicking to the table |
| self._$busyDiv |
| .width(self._$mainContainer.width()) |
| .height(self._$mainContainer.height()) |
| .addClass('jtable-busy-panel-background-invisible') |
| .show(); |
| |
| var makeVisible = function () { |
| self._$busyDiv.removeClass('jtable-busy-panel-background-invisible'); |
| self._$busyMessageDiv.html(message).show(); |
| }; |
| |
| if (delay) { |
| if (self._setBusyTimer) { |
| return; |
| } |
| |
| self._setBusyTimer = setTimeout(makeVisible, delay); |
| } else { |
| makeVisible(); |
| } |
| }, |
| |
| /* Hides busy indicator and unblocks table UI. |
| *************************************************************************/ |
| _hideBusy: function () { |
| clearTimeout(this._setBusyTimer); |
| this._setBusyTimer = null; |
| this._$busyDiv.hide(); |
| this._$busyMessageDiv.html('').hide(); |
| }, |
| |
| /* Returns true if jTable is busy. |
| *************************************************************************/ |
| _isBusy: function () { |
| return this._$busyMessageDiv.is(':visible'); |
| }, |
| |
| /* Adds jQueryUI class to an item. |
| *************************************************************************/ |
| _jqueryuiThemeAddClass: function ($elm, className, hoverClassName) { |
| if (!this.options.jqueryuiTheme) { |
| return; |
| } |
| |
| $elm.addClass(className); |
| |
| if (hoverClassName) { |
| $elm.hover(function () { |
| $elm.addClass(hoverClassName); |
| }, function () { |
| $elm.removeClass(hoverClassName); |
| }); |
| } |
| }, |
| |
| /* COMMON METHODS *******************************************************/ |
| |
| /* Performs an AJAX call to specified URL. |
| * THIS METHOD IS DEPRECATED AND WILL BE REMOVED FROM FEATURE RELEASES. |
| * USE _ajax METHOD. |
| *************************************************************************/ |
| _performAjaxCall: function (url, postData, async, success, error) { |
| this._ajax({ |
| url: url, |
| data: postData, |
| async: async, |
| success: success, |
| error: error |
| }); |
| }, |
| |
| _unAuthorizedRequestHandler: function() { |
| if (this.options.unAuthorizedRequestRedirectUrl) { |
| location.href = this.options.unAuthorizedRequestRedirectUrl; |
| } else { |
| location.reload(true); |
| } |
| }, |
| |
| /* This method is used to perform AJAX calls in jTable instead of direct |
| * usage of jQuery.ajax method. |
| *************************************************************************/ |
| _ajax: function (options) { |
| var self = this; |
| |
| //Handlers for HTTP status codes |
| var opts = { |
| statusCode: { |
| 401: function () { //Unauthorized |
| self._unAuthorizedRequestHandler(); |
| } |
| } |
| }; |
| |
| opts = $.extend(opts, this.options.ajaxSettings, options); |
| |
| //Override success |
| opts.success = function (data) { |
| //Checking for Authorization error |
| if (data && data.UnAuthorizedRequest == true) { |
| self._unAuthorizedRequestHandler(); |
| } |
| |
| if (options.success) { |
| options.success(data); |
| } |
| }; |
| |
| //Override error |
| opts.error = function (jqXHR, textStatus, errorThrown) { |
| if (unloadingPage) { |
| jqXHR.abort(); |
| return; |
| } |
| |
| if (options.error) { |
| options.error(arguments); |
| } |
| }; |
| |
| //Override complete |
| opts.complete = function () { |
| if (options.complete) { |
| options.complete(); |
| } |
| }; |
| |
| $.ajax(opts); |
| }, |
| |
| /* Gets value of key field of a record. |
| *************************************************************************/ |
| _getKeyValueOfRecord: function (record) { |
| return record[this._keyField]; |
| }, |
| |
| /************************************************************************ |
| * COOKIE * |
| *************************************************************************/ |
| |
| /* Sets a cookie with given key. |
| *************************************************************************/ |
| _setCookie: function (key, value) { |
| key = this._cookieKeyPrefix + key; |
| |
| var expireDate = new Date(); |
| expireDate.setDate(expireDate.getDate() + 30); |
| document.cookie = encodeURIComponent(key) + '=' + encodeURIComponent(value) + "; expires=" + expireDate.toUTCString(); |
| }, |
| |
| /* Gets a cookie with given key. |
| *************************************************************************/ |
| _getCookie: function (key) { |
| key = this._cookieKeyPrefix + key; |
| |
| var equalities = document.cookie.split('; '); |
| for (var i = 0; i < equalities.length; i++) { |
| if (!equalities[i]) { |
| continue; |
| } |
| |
| var splitted = equalities[i].split('='); |
| if (splitted.length != 2) { |
| continue; |
| } |
| |
| if (decodeURIComponent(splitted[0]) === key) { |
| return decodeURIComponent(splitted[1] || ''); |
| } |
| } |
| |
| return null; |
| }, |
| |
| /* Generates a hash key to be prefix for all cookies for this jtable instance. |
| *************************************************************************/ |
| _generateCookieKeyPrefix: function () { |
| |
| var simpleHash = function (value) { |
| var hash = 0; |
| if (value.length == 0) { |
| return hash; |
| } |
| |
| for (var i = 0; i < value.length; i++) { |
| var ch = value.charCodeAt(i); |
| hash = ((hash << 5) - hash) + ch; |
| hash = hash & hash; |
| } |
| |
| return hash; |
| }; |
| |
| var strToHash = ''; |
| if (this.options.tableId) { |
| strToHash = strToHash + this.options.tableId + '#'; |
| } |
| |
| strToHash = strToHash + this._columnList.join('$') + '#c' + this._$table.find('thead th').length; |
| return 'jtable#' + simpleHash(strToHash); |
| }, |
| |
| /************************************************************************ |
| * EVENT RAISING METHODS * |
| *************************************************************************/ |
| |
| _onLoadingRecords: function () { |
| this._trigger("loadingRecords", null, {}); |
| }, |
| |
| _onRecordsLoaded: function (data) { |
| this._trigger("recordsLoaded", null, { records: data.Records, serverResponse: data }); |
| }, |
| |
| _onRowInserted: function ($row, isNewRow) { |
| this._trigger("rowInserted", null, { row: $row, record: $row.data('record'), isNewRow: isNewRow }); |
| }, |
| |
| _onRowsRemoved: function ($rows, reason) { |
| this._trigger("rowsRemoved", null, { rows: $rows, reason: reason }); |
| }, |
| |
| _onCloseRequested: function () { |
| this._trigger("closeRequested", null, {}); |
| } |
| |
| }); |
| |
| }(jQuery)); |
| |
| |
| /************************************************************************ |
| * 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); |
| |
| |
| /************************************************************************ |
| * 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 + '" 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 + '" 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); |
| |
| |
| /************************************************************************ |
| * 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); |
| |
| |
| /************************************************************************ |
| * 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 != "") && (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); |
| |
| |
| /************************************************************************ |
| * 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); |
| |
| |
| /************************************************************************ |
| * 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); |
| |
| |
| /************************************************************************ |
| * 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('<<') |
| .data('pageNumber', 1) |
| .appendTo(this._$pagingListArea); |
| |
| var $previous = $('<span></span>') |
| .addClass('jtable-page-number-previous') |
| .html('<') |
| .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('>') |
| .data('pageNumber', this._currentPageNo + 1) |
| .appendTo(this._$pagingListArea); |
| var $last = $('<span></span>') |
| .addClass('jtable-page-number-last') |
| .html('>>') |
| .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); |
| |
| |
| /************************************************************************ |
| * 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); |
| |
| /************************************************************************ |
| * 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); |
| |
| |
| /************************************************************************ |
| * 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); |
| |