You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2018/04/08 16:49:46 UTC
[34/46] logging-log4j-audit git commit: Fixed the catalog editor.
Support using a branch
http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/7ccfa3aa/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/jtable.2.4.0/jquery.jtable.js
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/jtable.2.4.0/jquery.jtable.js b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/jtable.2.4.0/jquery.jtable.js
new file mode 100644
index 0000000..869af24
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/jtable.2.4.0/jquery.jtable.js
@@ -0,0 +1,5021 @@
+/*
+
+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 rec
<TRUNCATED>