/* * jsGrid v1.5.1 (http://js-grid.com) * (c) 2016 Artem Tabalin * Licensed under MIT (https://github.com/tabalinas/jsgrid/blob/master/LICENSE) */ (function(window, $, undefined) { var JSGRID = "JSGrid", JSGRID_DATA_KEY = JSGRID, JSGRID_ROW_DATA_KEY = "JSGridItem", JSGRID_EDIT_ROW_DATA_KEY = "JSGridEditRow", SORT_ORDER_ASC = "asc", SORT_ORDER_DESC = "desc", FIRST_PAGE_PLACEHOLDER = "{first}", PAGES_PLACEHOLDER = "{pages}", PREV_PAGE_PLACEHOLDER = "{prev}", NEXT_PAGE_PLACEHOLDER = "{next}", LAST_PAGE_PLACEHOLDER = "{last}", PAGE_INDEX_PLACEHOLDER = "{pageIndex}", PAGE_COUNT_PLACEHOLDER = "{pageCount}", ITEM_COUNT_PLACEHOLDER = "{itemCount}", EMPTY_HREF = "javascript:void(0);"; var getOrApply = function(value, context) { if($.isFunction(value)) { return value.apply(context, $.makeArray(arguments).slice(2)); } return value; }; var normalizePromise = function(promise) { var d = $.Deferred(); if(promise && promise.then) { promise.then(function() { d.resolve.apply(d, arguments); }, function() { d.reject.apply(d, arguments); }); } else { d.resolve(promise); } return d.promise(); }; var defaultController = { loadData: $.noop, insertItem: $.noop, updateItem: $.noop, deleteItem: $.noop }; function Grid(element, config) { var $element = $(element); $element.data(JSGRID_DATA_KEY, this); this._container = $element; this.data = []; this.fields = []; this._editingRow = null; this._sortField = null; this._sortOrder = SORT_ORDER_ASC; this._firstDisplayingPage = 1; this._init(config); this.render(); } Grid.prototype = { width: "auto", height: "auto", updateOnResize: true, rowClass: $.noop, rowRenderer: null, rowClick: function(args) { if(this.editing) { this.editItem($(args.event.target).closest("tr")); } }, rowDoubleClick: $.noop, noDataContent: "Not found", noDataRowClass: "jsgrid-nodata-row", heading: true, headerRowRenderer: null, headerRowClass: "jsgrid-header-row", headerCellClass: "jsgrid-header-cell", filtering: false, filterRowRenderer: null, filterRowClass: "jsgrid-filter-row", inserting: false, insertRowRenderer: null, insertRowClass: "jsgrid-insert-row", editing: false, editRowRenderer: null, editRowClass: "jsgrid-edit-row", confirmDeleting: true, deleteConfirm: "Are you sure?", selecting: true, selectedRowClass: "jsgrid-selected-row", oddRowClass: "jsgrid-row", evenRowClass: "jsgrid-alt-row", cellClass: "jsgrid-cell", sorting: false, sortableClass: "jsgrid-header-sortable", sortAscClass: "jsgrid-header-sort jsgrid-header-sort-asc", sortDescClass: "jsgrid-header-sort jsgrid-header-sort-desc", paging: false, pagerContainer: null, pageIndex: 1, pageSize: 20, pageButtonCount: 15, pagerFormat: "Pages: {first} {prev} {pages} {next} {last} {pageIndex} of {pageCount}", pagePrevText: "Prev", pageNextText: "Next", pageFirstText: "First", pageLastText: "Last", pageNavigatorNextText: "...", pageNavigatorPrevText: "...", pagerContainerClass: "jsgrid-pager-container", pagerClass: "jsgrid-pager", pagerNavButtonClass: "jsgrid-pager-nav-button", pagerNavButtonInactiveClass: "jsgrid-pager-nav-inactive-button", pageClass: "jsgrid-pager-page", currentPageClass: "jsgrid-pager-current-page", customLoading: false, pageLoading: false, autoload: false, controller: defaultController, loadIndication: true, loadIndicationDelay: 500, loadMessage: "Please, wait...", loadShading: true, invalidMessage: "Invalid data entered!", invalidNotify: function(args) { var messages = $.map(args.errors, function(error) { return error.message || null; }); window.alert([this.invalidMessage].concat(messages).join("\n")); }, onInit: $.noop, onRefreshing: $.noop, onRefreshed: $.noop, onPageChanged: $.noop, onItemDeleting: $.noop, onItemDeleted: $.noop, onItemInserting: $.noop, onItemInserted: $.noop, onItemEditing: $.noop, onItemUpdating: $.noop, onItemUpdated: $.noop, onItemInvalid: $.noop, onDataLoading: $.noop, onDataLoaded: $.noop, onOptionChanging: $.noop, onOptionChanged: $.noop, onError: $.noop, invalidClass: "jsgrid-invalid", containerClass: "jsgrid", tableClass: "jsgrid-table", gridHeaderClass: "jsgrid-grid-header", gridBodyClass: "jsgrid-grid-body", _init: function(config) { $.extend(this, config); this._initLoadStrategy(); this._initController(); this._initFields(); this._attachWindowLoadResize(); this._attachWindowResizeCallback(); this._callEventHandler(this.onInit) }, loadStrategy: function() { return this.pageLoading ? new jsGrid.loadStrategies.PageLoadingStrategy(this) : new jsGrid.loadStrategies.DirectLoadingStrategy(this); }, _initLoadStrategy: function() { this._loadStrategy = getOrApply(this.loadStrategy, this); }, _initController: function() { this._controller = $.extend({}, defaultController, getOrApply(this.controller, this)); }, renderTemplate: function(source, context, config) { args = []; for(var key in config) { args.push(config[key]); } args.unshift(source, context); source = getOrApply.apply(null, args); return (source === undefined || source === null) ? "" : source; }, loadIndicator: function(config) { return new jsGrid.LoadIndicator(config); }, validation: function(config) { return jsGrid.Validation && new jsGrid.Validation(config); }, _initFields: function() { var self = this; self.fields = $.map(self.fields, function(field) { if($.isPlainObject(field)) { var fieldConstructor = (field.type && jsGrid.fields[field.type]) || jsGrid.Field; field = new fieldConstructor(field); } field._grid = self; return field; }); }, _attachWindowLoadResize: function() { $(window).on("load", $.proxy(this._refreshSize, this)); }, _attachWindowResizeCallback: function() { if(this.updateOnResize) { $(window).on("resize", $.proxy(this._refreshSize, this)); } }, _detachWindowResizeCallback: function() { $(window).off("resize", this._refreshSize); }, option: function(key, value) { var optionChangingEventArgs, optionChangedEventArgs; if(arguments.length === 1) return this[key]; optionChangingEventArgs = { option: key, oldValue: this[key], newValue: value }; this._callEventHandler(this.onOptionChanging, optionChangingEventArgs); this._handleOptionChange(optionChangingEventArgs.option, optionChangingEventArgs.newValue); optionChangedEventArgs = { option: optionChangingEventArgs.option, value: optionChangingEventArgs.newValue }; this._callEventHandler(this.onOptionChanged, optionChangedEventArgs); }, fieldOption: function(field, key, value) { field = this._normalizeField(field); if(arguments.length === 2) return field[key]; field[key] = value; this._renderGrid(); }, _handleOptionChange: function(name, value) { this[name] = value; switch(name) { case "width": case "height": this._refreshSize(); break; case "rowClass": case "rowRenderer": case "rowClick": case "rowDoubleClick": case "noDataRowClass": case "noDataContent": case "selecting": case "selectedRowClass": case "oddRowClass": case "evenRowClass": this._refreshContent(); break; case "pageButtonCount": case "pagerFormat": case "pagePrevText": case "pageNextText": case "pageFirstText": case "pageLastText": case "pageNavigatorNextText": case "pageNavigatorPrevText": case "pagerClass": case "pagerNavButtonClass": case "pageClass": case "currentPageClass": case "pagerRenderer": this._refreshPager(); break; case "fields": this._initFields(); this.render(); break; case "data": case "editing": case "heading": case "filtering": case "inserting": case "paging": this.refresh(); break; case "loadStrategy": case "pageLoading": this._initLoadStrategy(); this.search(); break; case "pageIndex": this.openPage(value); break; case "pageSize": this.refresh(); this.search(); break; case "editRowRenderer": case "editRowClass": this.cancelEdit(); break; case "updateOnResize": this._detachWindowResizeCallback(); this._attachWindowResizeCallback(); break; case "invalidNotify": case "invalidMessage": break; default: this.render(); break; } }, destroy: function() { this._detachWindowResizeCallback(); this._clear(); this._container.removeData(JSGRID_DATA_KEY); }, render: function() { this._renderGrid(); return this.autoload ? this.loadData() : $.Deferred().resolve().promise(); }, _renderGrid: function() { this._clear(); this._container.addClass(this.containerClass) .css("position", "relative") .append(this._createHeader()) .append(this._createBody()); this._pagerContainer = this._createPagerContainer(); this._loadIndicator = this._createLoadIndicator(); this._validation = this._createValidation(); this.refresh(); }, _createLoadIndicator: function() { return getOrApply(this.loadIndicator, this, { message: this.loadMessage, shading: this.loadShading, container: this._container }); }, _createValidation: function() { return getOrApply(this.validation, this); }, _clear: function() { this.cancelEdit(); clearTimeout(this._loadingTimer); this._pagerContainer && this._pagerContainer.empty(); this._container.empty() .css({ position: "", width: "", height: "" }); }, _createHeader: function() { var $headerRow = this._headerRow = this._createHeaderRow(), $filterRow = this._filterRow = this._createFilterRow(), $insertRow = this._insertRow = this._createInsertRow(); var $headerGrid = this._headerGrid = $("