| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424 |
- (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 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",
- 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",
- 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"));
- },
- onRefreshing: $.noop,
- onRefreshed: $.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();
- },
- 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));
- },
- 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 "noDataText":
- 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 = $("<table>").addClass(this.tableClass)
- .append($headerRow)
- .append($filterRow)
- .append($insertRow);
- var $header = this._header = $("<div>").addClass(this.gridHeaderClass)
- .addClass(this._scrollBarWidth() ? "jsgrid-header-scrollbar" : "")
- .append($headerGrid);
- return $header;
- },
- _createBody: function() {
- var $content = this._content = $("<tbody>");
- var $bodyGrid = this._bodyGrid = $("<table>").addClass(this.tableClass)
- .append($content);
- var $body = this._body = $("<div>").addClass(this.gridBodyClass)
- .append($bodyGrid)
- .on("scroll", $.proxy(function(e) {
- this._header.scrollLeft(e.target.scrollLeft);
- }, this));
- return $body;
- },
- _createPagerContainer: function() {
- var pagerContainer = this.pagerContainer || $("<div>").appendTo(this._container);
- return $(pagerContainer).addClass(this.pagerContainerClass);
- },
- _eachField: function(callBack) {
- var self = this;
- $.each(this.fields, function(index, field) {
- if(field.visible) {
- callBack.call(self, field, index);
- }
- });
- },
- _createHeaderRow: function() {
- if($.isFunction(this.headerRowRenderer))
- return $(this.headerRowRenderer());
- var $result = $("<tr>").addClass(this.headerRowClass);
- this._eachField(function(field, index) {
- var $th = this._prepareCell("<th>", field, "headercss")
- .append(field.headerTemplate ? field.headerTemplate() : "")
- .appendTo($result);
- if(this.sorting && field.sorting) {
- $th.addClass(this.sortableClass)
- .on("click", $.proxy(function() {
- this.sort(index);
- }, this));
- }
- });
- return $result;
- },
- _prepareCell: function(cell, field, cssprop) {
- return $(cell).css("width", field.width)
- .addClass((cssprop && field[cssprop]) || field.css)
- .addClass(field.align ? ("jsgrid-align-" + field.align) : "");
- },
- _createFilterRow: function() {
- if($.isFunction(this.filterRowRenderer))
- return $(this.filterRowRenderer());
- var $result = $("<tr>").addClass(this.filterRowClass);
- this._eachField(function(field) {
- this._prepareCell("<td>", field, "filtercss")
- .append(field.filterTemplate ? field.filterTemplate() : "")
- .appendTo($result);
- });
- return $result;
- },
- _createInsertRow: function() {
- if($.isFunction(this.insertRowRenderer))
- return $(this.insertRowRenderer());
- var $result = $("<tr>").addClass(this.insertRowClass);
- this._eachField(function(field) {
- this._prepareCell("<td>", field, "insertcss")
- .append(field.insertTemplate ? field.insertTemplate() : "")
- .appendTo($result);
- });
- return $result;
- },
- _callEventHandler: function(handler, eventParams) {
- handler.call(this, $.extend(eventParams, {
- grid: this
- }));
- return eventParams;
- },
- reset: function() {
- this._resetSorting();
- this._resetPager();
- this.refresh();
- },
- _resetPager: function() {
- this._firstDisplayingPage = 1;
- this._setPage(1);
- },
- _resetSorting: function() {
- this._sortField = null;
- this._sortOrder = SORT_ORDER_ASC;
- this._clearSortingCss();
- },
- refresh: function() {
- this._callEventHandler(this.onRefreshing);
- this.cancelEdit();
- this._refreshHeading();
- this._refreshFiltering();
- this._refreshInserting();
- this._refreshContent();
- this._refreshPager();
- this._refreshSize();
- this._callEventHandler(this.onRefreshed);
- },
- _refreshHeading: function() {
- this._headerRow.toggle(this.heading);
- },
- _refreshFiltering: function() {
- this._filterRow.toggle(this.filtering);
- },
- _refreshInserting: function() {
- this._insertRow.toggle(this.inserting);
- },
- _refreshContent: function() {
- var $content = this._content;
- $content.empty();
- if(!this.data.length) {
- $content.append(this._createNoDataRow());
- return this;
- }
- var indexFrom = this._loadStrategy.firstDisplayIndex();
- var indexTo = this._loadStrategy.lastDisplayIndex();
- for(var itemIndex = indexFrom; itemIndex < indexTo; itemIndex++) {
- var item = this.data[itemIndex];
- $content.append(this._createRow(item, itemIndex));
- }
- },
- _createNoDataRow: function() {
- var noDataContent = getOrApply(this.noDataContent, this);
- var amountOfFields = 0;
- this._eachField(function() {
- amountOfFields++;
- });
- return $("<tr>").addClass(this.noDataRowClass)
- .append($("<td>").attr("colspan", amountOfFields).append(noDataContent));
- },
- _createNoDataContent: function() {
- return $.isFunction(this.noDataRenderer)
- ? this.noDataRenderer()
- : this.noDataText;
- },
- _createRow: function(item, itemIndex) {
- var $result;
- if($.isFunction(this.rowRenderer)) {
- $result = $(this.rowRenderer(item, itemIndex));
- } else {
- $result = $("<tr>");
- this._renderCells($result, item);
- }
- $result.addClass(this._getRowClasses(item, itemIndex))
- .data(JSGRID_ROW_DATA_KEY, item)
- .on("click", $.proxy(function(e) {
- this.rowClick({
- item: item,
- itemIndex: itemIndex,
- event: e
- });
- }, this))
- .on("dblclick", $.proxy(function(e) {
- this.rowDoubleClick({
- item: item,
- itemIndex: itemIndex,
- event: e
- });
- }, this));
- if(this.selecting) {
- this._attachRowHover($result);
- }
- return $result;
- },
- _getRowClasses: function(item, itemIndex) {
- var classes = [];
- classes.push(((itemIndex + 1) % 2) ? this.oddRowClass : this.evenRowClass);
- classes.push(getOrApply(this.rowClass, this, item, itemIndex));
- return classes.join(" ");
- },
- _attachRowHover: function($row) {
- var selectedRowClass = this.selectedRowClass;
- $row.hover(function() {
- $(this).addClass(selectedRowClass);
- },
- function() {
- $(this).removeClass(selectedRowClass);
- }
- );
- },
- _renderCells: function($row, item) {
- this._eachField(function(field) {
- $row.append(this._createCell(item, field));
- });
- return this;
- },
- _createCell: function(item, field) {
- var $result;
- var fieldValue = this._getItemFieldValue(item, field);
- if($.isFunction(field.cellRenderer)) {
- $result = $(field.cellRenderer(fieldValue, item));
- } else {
- $result = $("<td>").append(field.itemTemplate ? field.itemTemplate(fieldValue, item) : fieldValue);
- }
- return this._prepareCell($result, field);
- },
- _getItemFieldValue: function(item, field) {
- var props = field.name.split('.');
- var result = item[props.shift()];
- while(result && props.length) {
- result = result[props.shift()];
- }
- return result;
- },
- _setItemFieldValue: function(item, field, value) {
- var props = field.name.split('.');
- var current = item;
- var prop = props[0];
- while(current && props.length) {
- item = current;
- prop = props.shift();
- current = item[prop];
- }
- if(!current) {
- while(props.length) {
- item = item[prop] = {};
- prop = props.shift();
- }
- }
- item[prop] = value;
- },
- sort: function(field, order) {
- if($.isPlainObject(field)) {
- order = field.order;
- field = field.field;
- }
- this._clearSortingCss();
- this._setSortingParams(field, order);
- this._setSortingCss();
- return this._loadStrategy.sort();
- },
- _clearSortingCss: function() {
- this._headerRow.find("th")
- .removeClass(this.sortAscClass)
- .removeClass(this.sortDescClass);
- },
- _setSortingParams: function(field, order) {
- field = this._normalizeField(field);
- order = order || ((this._sortField === field) ? this._reversedSortOrder(this._sortOrder) : SORT_ORDER_ASC);
- this._sortField = field;
- this._sortOrder = order;
- },
- _normalizeField: function(field) {
- if($.isNumeric(field)) {
- return this.fields[field];
- }
- if(typeof field === "string") {
- return $.grep(this.fields, function(f) {
- return f.name === field;
- })[0];
- }
- return field;
- },
- _reversedSortOrder: function(order) {
- return (order === SORT_ORDER_ASC ? SORT_ORDER_DESC : SORT_ORDER_ASC);
- },
- _setSortingCss: function() {
- var fieldIndex = $.inArray(this._sortField, $.grep(this.fields, function(f) { return f.visible; }));
- this._headerRow.find("th").eq(fieldIndex)
- .addClass(this._sortOrder === SORT_ORDER_ASC ? this.sortAscClass : this.sortDescClass);
- },
- _sortData: function() {
- var sortFactor = this._sortFactor(),
- sortField = this._sortField;
- if(sortField) {
- this.data.sort(function(item1, item2) {
- return sortFactor * sortField.sortingFunc(item1[sortField.name], item2[sortField.name]);
- });
- }
- },
- _sortFactor: function() {
- return this._sortOrder === SORT_ORDER_ASC ? 1 : -1;
- },
- _itemsCount: function() {
- return this._loadStrategy.itemsCount();
- },
- _pagesCount: function() {
- var itemsCount = this._itemsCount(),
- pageSize = this.pageSize;
- return Math.floor(itemsCount / pageSize) + (itemsCount % pageSize ? 1 : 0);
- },
- _refreshPager: function() {
- var $pagerContainer = this._pagerContainer;
- $pagerContainer.empty();
- if(this.paging) {
- $pagerContainer.append(this._createPager());
- }
- var showPager = this.paging && this._pagesCount() > 1;
- $pagerContainer.toggle(showPager);
- },
- _createPager: function() {
- var $result;
- if($.isFunction(this.pagerRenderer)) {
- $result = $(this.pagerRenderer({
- pageIndex: this.pageIndex,
- pageCount: this._pagesCount()
- }));
- } else {
- $result = $("<div>").append(this._createPagerByFormat());
- }
- $result.addClass(this.pagerClass);
- return $result;
- },
- _createPagerByFormat: function() {
- var pageIndex = this.pageIndex,
- pageCount = this._pagesCount(),
- itemCount = this._itemsCount(),
- pagerParts = this.pagerFormat.split(" ");
- return $.map(pagerParts, $.proxy(function(pagerPart) {
- var result = pagerPart;
- if(pagerPart === PAGES_PLACEHOLDER) {
- result = this._createPages();
- } else if(pagerPart === FIRST_PAGE_PLACEHOLDER) {
- result = this._createPagerNavButton(this.pageFirstText, 1, pageIndex > 1);
- } else if(pagerPart === PREV_PAGE_PLACEHOLDER) {
- result = this._createPagerNavButton(this.pagePrevText, pageIndex - 1, pageIndex > 1);
- } else if(pagerPart === NEXT_PAGE_PLACEHOLDER) {
- result = this._createPagerNavButton(this.pageNextText, pageIndex + 1, pageIndex < pageCount);
- } else if(pagerPart === LAST_PAGE_PLACEHOLDER) {
- result = this._createPagerNavButton(this.pageLastText, pageCount, pageIndex < pageCount);
- } else if(pagerPart === PAGE_INDEX_PLACEHOLDER) {
- result = pageIndex;
- } else if(pagerPart === PAGE_COUNT_PLACEHOLDER) {
- result = pageCount;
- } else if(pagerPart === ITEM_COUNT_PLACEHOLDER) {
- result = itemCount;
- }
- return $.isArray(result) ? result.concat([" "]) : [result, " "];
- }, this));
- },
- _createPages: function() {
- var pageCount = this._pagesCount(),
- pageButtonCount = this.pageButtonCount,
- firstDisplayingPage = this._firstDisplayingPage,
- pages = [];
- if(firstDisplayingPage > 1) {
- pages.push(this._createPagerPageNavButton(this.pageNavigatorPrevText, this.showPrevPages));
- }
- for(var i = 0, pageNumber = firstDisplayingPage; i < pageButtonCount && pageNumber <= pageCount; i++, pageNumber++) {
- pages.push(pageNumber === this.pageIndex
- ? this._createPagerCurrentPage()
- : this._createPagerPage(pageNumber));
- }
- if((firstDisplayingPage + pageButtonCount - 1) < pageCount) {
- pages.push(this._createPagerPageNavButton(this.pageNavigatorNextText, this.showNextPages));
- }
- return pages;
- },
- _createPagerNavButton: function(text, pageIndex, isActive) {
- return this._createPagerButton(text, this.pagerNavButtonClass + (isActive ? "" : " " + this.pagerNavButtonInactiveClass),
- isActive ? function() { this.openPage(pageIndex); } : $.noop);
- },
- _createPagerPageNavButton: function(text, handler) {
- return this._createPagerButton(text, this.pagerNavButtonClass, handler);
- },
- _createPagerPage: function(pageIndex) {
- return this._createPagerButton(pageIndex, this.pageClass, function() {
- this.openPage(pageIndex);
- });
- },
- _createPagerButton: function(text, css, handler) {
- var $link = $("<a>").attr("href", EMPTY_HREF)
- .html(text)
- .on("click", $.proxy(handler, this));
- return $("<span>").addClass(css).append($link);
- },
- _createPagerCurrentPage: function() {
- return $("<span>")
- .addClass(this.pageClass)
- .addClass(this.currentPageClass)
- .text(this.pageIndex);
- },
- _refreshSize: function() {
- this._refreshHeight();
- this._refreshWidth();
- },
- _refreshWidth: function() {
- var $headerGrid = this._headerGrid,
- $bodyGrid = this._bodyGrid,
- width = this.width;
- if(width === "auto") {
- $headerGrid.width("auto");
- width = $headerGrid.outerWidth();
- }
- $headerGrid.width("");
- $bodyGrid.width("");
- this._container.width(width);
- width = $headerGrid.outerWidth();
- $bodyGrid.width(width);
- },
- _scrollBarWidth: (function() {
- var result;
- return function() {
- if(result === undefined) {
- var $ghostContainer = $("<div style='width:50px;height:50px;overflow:hidden;position:absolute;top:-10000px;left:-10000px;'></div>");
- var $ghostContent = $("<div style='height:100px;'></div>");
- $ghostContainer.append($ghostContent).appendTo("body");
- var width = $ghostContent.innerWidth();
- $ghostContainer.css("overflow-y", "auto");
- var widthExcludingScrollBar = $ghostContent.innerWidth();
- $ghostContainer.remove();
- result = width - widthExcludingScrollBar;
- }
- return result;
- };
- })(),
- _refreshHeight: function() {
- var container = this._container,
- pagerContainer = this._pagerContainer,
- height = this.height,
- nonBodyHeight;
- container.height(height);
- if(height !== "auto") {
- height = container.height();
- nonBodyHeight = this._header.outerHeight(true);
- if(pagerContainer.parents(container).length) {
- nonBodyHeight += pagerContainer.outerHeight(true);
- }
- this._body.outerHeight(height - nonBodyHeight);
- }
- },
- showPrevPages: function() {
- var firstDisplayingPage = this._firstDisplayingPage,
- pageButtonCount = this.pageButtonCount;
- this._firstDisplayingPage = (firstDisplayingPage > pageButtonCount) ? firstDisplayingPage - pageButtonCount : 1;
- this._refreshPager();
- },
- showNextPages: function() {
- var firstDisplayingPage = this._firstDisplayingPage,
- pageButtonCount = this.pageButtonCount,
- pageCount = this._pagesCount();
- this._firstDisplayingPage = (firstDisplayingPage + 2 * pageButtonCount > pageCount)
- ? pageCount - pageButtonCount + 1
- : firstDisplayingPage + pageButtonCount;
- this._refreshPager();
- },
- openPage: function(pageIndex) {
- if(pageIndex < 1 || pageIndex > this._pagesCount())
- return;
- this._setPage(pageIndex);
- this._loadStrategy.openPage(pageIndex);
- },
- _setPage: function(pageIndex) {
- var firstDisplayingPage = this._firstDisplayingPage,
- pageButtonCount = this.pageButtonCount;
- this.pageIndex = pageIndex;
- if(pageIndex < firstDisplayingPage) {
- this._firstDisplayingPage = pageIndex;
- }
- if(pageIndex > firstDisplayingPage + pageButtonCount - 1) {
- this._firstDisplayingPage = pageIndex - pageButtonCount + 1;
- }
- },
- _controllerCall: function(method, param, isCanceled, doneCallback) {
- if(isCanceled)
- return $.Deferred().reject().promise();
- this._showLoading();
- var controller = this._controller;
- if(!controller || !controller[method]) {
- throw Error("controller has no method '" + method + "'");
- }
- return $.when(controller[method](param))
- .done($.proxy(doneCallback, this))
- .fail($.proxy(this._errorHandler, this))
- .always($.proxy(this._hideLoading, this));
- },
- _errorHandler: function() {
- this._callEventHandler(this.onError, {
- args: $.makeArray(arguments)
- });
- },
- _showLoading: function() {
- if(!this.loadIndication)
- return;
- clearTimeout(this._loadingTimer);
- this._loadingTimer = setTimeout($.proxy(function() {
- this._loadIndicator.show();
- }, this), this.loadIndicationDelay);
- },
- _hideLoading: function() {
- if(!this.loadIndication)
- return;
- clearTimeout(this._loadingTimer);
- this._loadIndicator.hide();
- },
- search: function(filter) {
- this._resetSorting();
- this._resetPager();
- return this.loadData(filter);
- },
- loadData: function(filter) {
- filter = filter || (this.filtering ? this.getFilter() : {});
- $.extend(filter, this._loadStrategy.loadParams(), this._sortingParams());
- var args = this._callEventHandler(this.onDataLoading, {
- filter: filter
- });
- return this._controllerCall("loadData", filter, args.cancel, function(loadedData) {
- if(!loadedData)
- return;
- this._loadStrategy.finishLoad(loadedData);
- this._callEventHandler(this.onDataLoaded, {
- data: loadedData
- });
- });
- },
- getFilter: function() {
- var result = {};
- this._eachField(function(field) {
- if(field.filtering) {
- this._setItemFieldValue(result, field, field.filterValue());
- }
- });
- return result;
- },
- _sortingParams: function() {
- if(this.sorting && this._sortField) {
- return {
- sortField: this._sortField.name,
- sortOrder: this._sortOrder
- };
- }
- return {};
- },
- getSorting: function() {
- var sortingParams = this._sortingParams();
- return {
- field: sortingParams.sortField,
- order: sortingParams.sortOrder
- };
- },
- clearFilter: function() {
- var $filterRow = this._createFilterRow();
- this._filterRow.replaceWith($filterRow);
- this._filterRow = $filterRow;
- return this.search();
- },
- insertItem: function(item) {
- var insertingItem = item || this._getValidatedInsertItem();
- if(!insertingItem)
- return $.Deferred().reject().promise();
- var args = this._callEventHandler(this.onItemInserting, {
- item: insertingItem
- });
- return this._controllerCall("insertItem", insertingItem, args.cancel, function(insertedItem) {
- insertedItem = insertedItem || insertingItem;
- this._loadStrategy.finishInsert(insertedItem);
- this._callEventHandler(this.onItemInserted, {
- item: insertedItem
- });
- });
- },
- _getValidatedInsertItem: function() {
- var item = this._getInsertItem();
- return this._validateItem(item, this._insertRow) ? item : null;
- },
- _getInsertItem: function() {
- var result = {};
- this._eachField(function(field) {
- if(field.inserting) {
- this._setItemFieldValue(result, field, field.insertValue());
- }
- });
- return result;
- },
- _validateItem: function(item, $row) {
- var validationErrors = [];
- var args = {
- item: item,
- itemIndex: this._rowIndex($row),
- row: $row
- };
- this._eachField(function(field, index) {
- if(!field.validate)
- return;
- var errors = this._validation.validate($.extend({
- value: this._getItemFieldValue(item, field),
- rules: field.validate
- }, args));
- this._setCellValidity($row.children().eq(index), errors);
- if(!errors.length)
- return;
- validationErrors.push.apply(validationErrors,
- $.map(errors, function(message) {
- return { field: field, message: message };
- }));
- });
- if(!validationErrors.length)
- return true;
- var invalidArgs = $.extend({
- errors: validationErrors
- }, args);
- this._callEventHandler(this.onItemInvalid, invalidArgs);
- this.invalidNotify(invalidArgs);
- return false;
- },
- _setCellValidity: function($cell, errors) {
- $cell
- .toggleClass(this.invalidClass, !!errors.length)
- .attr("title", errors.join("\n"));
- },
- clearInsert: function() {
- var insertRow = this._createInsertRow();
- this._insertRow.replaceWith(insertRow);
- this._insertRow = insertRow;
- this.refresh();
- },
- editItem: function(item) {
- var $row = this.rowByItem(item);
- if($row.length) {
- this._editRow($row);
- }
- },
- rowByItem: function(item) {
- if(item.jquery || item.nodeType)
- return $(item);
- return this._content.find("tr").filter(function() {
- return $.data(this, JSGRID_ROW_DATA_KEY) === item;
- });
- },
- _editRow: function($row) {
- if(!this.editing)
- return;
- var item = $row.data(JSGRID_ROW_DATA_KEY);
- var args = this._callEventHandler(this.onItemEditing, {
- row: $row,
- item: item,
- itemIndex: this._itemIndex(item)
- });
- if(args.cancel)
- return;
- if(this._editingRow) {
- this.cancelEdit();
- }
- var $editRow = this._createEditRow(item);
- this._editingRow = $row;
- $row.hide();
- $editRow.insertBefore($row);
- $row.data(JSGRID_EDIT_ROW_DATA_KEY, $editRow);
- },
- _createEditRow: function(item) {
- if($.isFunction(this.editRowRenderer)) {
- return $(this.editRowRenderer(item, this._itemIndex(item)));
- }
- var $result = $("<tr>").addClass(this.editRowClass);
- this._eachField(function(field) {
- var fieldValue = this._getItemFieldValue(item, field);
- this._prepareCell("<td>", field, "editcss")
- .append(field.editTemplate ? field.editTemplate(fieldValue, item) : "")
- .appendTo($result);
- });
- return $result;
- },
- updateItem: function(item, editedItem) {
- if(arguments.length === 1) {
- editedItem = item;
- }
- var $row = item ? this.rowByItem(item) : this._editingRow;
- editedItem = editedItem || this._getValidatedEditedItem();
- if(!editedItem)
- return;
- return this._updateRow($row, editedItem);
- },
- _getValidatedEditedItem: function() {
- var item = this._getEditedItem();
- return this._validateItem(item, this._getEditRow()) ? item : null;
- },
- _updateRow: function($updatingRow, editedItem) {
- var updatingItem = $updatingRow.data(JSGRID_ROW_DATA_KEY),
- updatingItemIndex = this._itemIndex(updatingItem),
- previousItem = $.extend(true, {}, updatingItem);
- $.extend(true, updatingItem, editedItem);
- var args = this._callEventHandler(this.onItemUpdating, {
- row: $updatingRow,
- item: updatingItem,
- itemIndex: updatingItemIndex,
- previousItem: previousItem
- });
- return this._controllerCall("updateItem", updatingItem, args.cancel, function(updatedItem) {
- updatedItem = updatedItem || updatingItem;
- var $updatedRow = this._finishUpdate($updatingRow, updatedItem, updatingItemIndex);
- this._callEventHandler(this.onItemUpdated, {
- row: $updatedRow,
- item: updatedItem,
- itemIndex: updatingItemIndex,
- previousItem: previousItem
- });
- });
- },
- _rowIndex: function(row) {
- return this._content.children().index($(row));
- },
- _itemIndex: function(item) {
- return $.inArray(item, this.data);
- },
- _finishUpdate: function($updatingRow, updatedItem, updatedItemIndex) {
- this.cancelEdit();
- this.data[updatedItemIndex] = updatedItem;
- var $updatedRow = this._createRow(updatedItem, updatedItemIndex);
- $updatingRow.replaceWith($updatedRow);
- return $updatedRow;
- },
- _getEditedItem: function() {
- var result = {};
- this._eachField(function(field) {
- if(field.editing) {
- this._setItemFieldValue(result, field, field.editValue());
- }
- });
- return result;
- },
- cancelEdit: function() {
- if(!this._editingRow)
- return;
- this._getEditRow().remove();
- this._editingRow.show();
- this._editingRow = null;
- },
- _getEditRow: function() {
- return this._editingRow.data(JSGRID_EDIT_ROW_DATA_KEY);
- },
- deleteItem: function(item) {
- var $row = this.rowByItem(item);
- if(!$row.length)
- return;
- if(this.confirmDeleting && !window.confirm(getOrApply(this.deleteConfirm, this, $row.data(JSGRID_ROW_DATA_KEY))))
- return;
- return this._deleteRow($row);
- },
- _deleteRow: function($row) {
- var deletingItem = $row.data(JSGRID_ROW_DATA_KEY),
- deletingItemIndex = this._itemIndex(deletingItem);
- var args = this._callEventHandler(this.onItemDeleting, {
- row: $row,
- item: deletingItem,
- itemIndex: deletingItemIndex
- });
- return this._controllerCall("deleteItem", deletingItem, args.cancel, function() {
- this._loadStrategy.finishDelete(deletingItem, deletingItemIndex);
- this._callEventHandler(this.onItemDeleted, {
- row: $row,
- item: deletingItem,
- itemIndex: deletingItemIndex
- });
- });
- }
- };
- $.fn.jsGrid = function(config) {
- var args = $.makeArray(arguments),
- methodArgs = args.slice(1),
- result = this;
- this.each(function() {
- var $element = $(this),
- instance = $element.data(JSGRID_DATA_KEY),
- methodResult;
- if(instance) {
- if(typeof config === "string") {
- methodResult = instance[config].apply(instance, methodArgs);
- if(methodResult !== undefined && methodResult !== instance) {
- result = methodResult;
- return false;
- }
- } else {
- instance._detachWindowResizeCallback();
- instance._init(config);
- instance.render();
- }
- } else {
- new Grid($element, config);
- }
- });
- return result;
- };
- var fields = {};
- var setDefaults = function(config) {
- var componentPrototype;
- if($.isPlainObject(config)) {
- componentPrototype = Grid.prototype;
- } else {
- componentPrototype = fields[config].prototype;
- config = arguments[1] || {};
- }
- $.extend(componentPrototype, config);
- };
- var locales = {};
- var locale = function(lang) {
- var localeConfig = $.isPlainObject(lang) ? lang : locales[lang];
- if(!localeConfig)
- throw Error("unknown locale " + lang);
- setLocale(jsGrid, localeConfig);
- };
- var setLocale = function(obj, localeConfig) {
- $.each(localeConfig, function(field, value) {
- if($.isPlainObject(value)) {
- setLocale(obj[field] || obj[field[0].toUpperCase() + field.slice(1)], value);
- return;
- }
- if(obj.hasOwnProperty(field)) {
- obj[field] = value;
- } else {
- obj.prototype[field] = value;
- }
- });
- };
- window.jsGrid = {
- Grid: Grid,
- fields: fields,
- setDefaults: setDefaults,
- locales: locales,
- locale: locale
- };
- }(window, jQuery));
|