1954 lines
58 KiB
JavaScript
1954 lines
58 KiB
JavaScript
/*
|
|
* jsGrid v1.0.1 (http://js-grid.com)
|
|
* (c) 2015 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}",
|
|
|
|
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"));
|
|
}
|
|
},
|
|
|
|
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",
|
|
pageClass: "jsgrid-pager-page",
|
|
currentPageClass: "jsgrid-pager-current-page",
|
|
|
|
pageLoading: false,
|
|
|
|
autoload: false,
|
|
controller: defaultController,
|
|
|
|
loadIndication: true,
|
|
loadIndicationDelay: 500,
|
|
loadMessage: "Please, wait...",
|
|
loadShading: true,
|
|
|
|
onRefreshing: $.noop,
|
|
onRefreshed: $.noop,
|
|
onItemDeleting: $.noop,
|
|
onItemDeleted: $.noop,
|
|
onItemInserting: $.noop,
|
|
onItemInserted: $.noop,
|
|
onItemUpdating: $.noop,
|
|
onItemUpdated: $.noop,
|
|
onDataLoading: $.noop,
|
|
onDataLoaded: $.noop,
|
|
onOptionChanging: $.noop,
|
|
onOptionChanged: $.noop,
|
|
onError: $.noop,
|
|
|
|
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);
|
|
},
|
|
|
|
_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);
|
|
},
|
|
|
|
_handleOptionChange: function(name, value) {
|
|
this[name] = value;
|
|
|
|
switch(name) {
|
|
case "width":
|
|
case "height":
|
|
this._refreshSize();
|
|
break;
|
|
case "rowClass":
|
|
case "rowRenderer":
|
|
case "rowClick":
|
|
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":
|
|
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 "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;
|
|
default:
|
|
this.render();
|
|
break;
|
|
}
|
|
},
|
|
|
|
destroy: function() {
|
|
this._detachWindowResizeCallback();
|
|
this._clear();
|
|
this._container.removeData(JSGRID_DATA_KEY);
|
|
},
|
|
|
|
render: 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.refresh();
|
|
|
|
return this.autoload ? this.loadData() : $.Deferred().resolve().promise();
|
|
},
|
|
|
|
_createLoadIndicator: function() {
|
|
return getOrApply(this.loadIndicator, this, {
|
|
message: this.loadMessage,
|
|
shading: this.loadShading,
|
|
container: this._container
|
|
});
|
|
},
|
|
|
|
_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)
|
|
.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);
|
|
|
|
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) {
|
|
return 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 = $("<th>").addClass(field.css)
|
|
.appendTo($result)
|
|
.append(field.headerTemplate ? field.headerTemplate() : "")
|
|
.css("width", field.width);
|
|
|
|
if(this.sorting && field.sorting) {
|
|
$th.addClass(this.sortableClass)
|
|
.on("click", $.proxy(function() {
|
|
this.sort(index);
|
|
}, this));
|
|
}
|
|
});
|
|
|
|
return $result;
|
|
},
|
|
|
|
_createFilterRow: function() {
|
|
if($.isFunction(this.filterRowRenderer)) {
|
|
return $(this.filterRowRenderer());
|
|
}
|
|
|
|
var $result = $("<tr>").addClass(this.filterRowClass);
|
|
|
|
this._eachField(function(field) {
|
|
$("<td>").addClass(field.css)
|
|
.appendTo($result)
|
|
.append(field.filterTemplate ? field.filterTemplate() : "")
|
|
.width(field.width);
|
|
});
|
|
|
|
return $result;
|
|
},
|
|
|
|
_createInsertRow: function() {
|
|
if($.isFunction(this.insertRowRenderer)) {
|
|
return $(this.insertRowRenderer());
|
|
}
|
|
|
|
var $result = $("<tr>").addClass(this.insertRowClass);
|
|
|
|
this._eachField(function(field) {
|
|
$("<td>").addClass(field.css)
|
|
.appendTo($result)
|
|
.append(field.insertTemplate ? field.insertTemplate() : "")
|
|
.width(field.width);
|
|
});
|
|
|
|
return $result;
|
|
},
|
|
|
|
_callEventHandler: function(handler, eventParams) {
|
|
return handler.call(this, $.extend(eventParams, {
|
|
grid: this
|
|
}));
|
|
},
|
|
|
|
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);
|
|
return $("<tr>").addClass(this.noDataRowClass)
|
|
.append($("<td>").attr("colspan", this.fields.length).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));
|
|
|
|
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 = item[field.name];
|
|
|
|
if($.isFunction(field.cellRenderer)) {
|
|
$result = $(field.cellRenderer(fieldValue, item));
|
|
} else {
|
|
$result = $("<td>").append(field.itemTemplate ? field.itemTemplate(fieldValue, item) : fieldValue);
|
|
}
|
|
|
|
$result.addClass(field.css)
|
|
.width(field.width);
|
|
|
|
field.align && $result.addClass("jsgrid-align-" + field.align);
|
|
|
|
return $result;
|
|
},
|
|
|
|
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._normalizeSortingField(field);
|
|
order = order || ((this._sortField === field) ? this._reversedSortOrder(this._sortOrder) : SORT_ORDER_ASC);
|
|
|
|
this._sortField = field;
|
|
this._sortOrder = order;
|
|
},
|
|
|
|
_normalizeSortingField: 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, this.fields);
|
|
|
|
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 && this._pagesCount() > 1) {
|
|
$pagerContainer.show()
|
|
.append(this._createPager());
|
|
} else {
|
|
$pagerContainer.hide();
|
|
}
|
|
},
|
|
|
|
_createPager: function() {
|
|
var pageIndex = this.pageIndex,
|
|
pageCount = this._pagesCount(),
|
|
pagerParts = this.pagerFormat.split(" ");
|
|
|
|
pagerParts = $.map(pagerParts, $.proxy(function(pagerPart) {
|
|
var result = pagerPart;
|
|
|
|
if(pagerPart === PAGES_PLACEHOLDER) {
|
|
result = this._createPages();
|
|
} else if(pagerPart === FIRST_PAGE_PLACEHOLDER) {
|
|
result = pageIndex > 1 ? this._createPagerNavButton(this.pageFirstText, 1) : "";
|
|
} else if(pagerPart === PREV_PAGE_PLACEHOLDER) {
|
|
result = pageIndex > 1 ? this._createPagerNavButton(this.pagePrevText, pageIndex - 1) : "";
|
|
} else if(pagerPart === NEXT_PAGE_PLACEHOLDER) {
|
|
result = pageIndex < pageCount ? this._createPagerNavButton(this.pageNextText, pageIndex + 1) : "";
|
|
} else if(pagerPart === LAST_PAGE_PLACEHOLDER) {
|
|
result = pageIndex < pageCount ? this._createPagerNavButton(this.pageLastText, pageCount) : "";
|
|
} else if(pagerPart === PAGE_INDEX_PLACEHOLDER) {
|
|
result = pageIndex;
|
|
} else if(pagerPart === PAGE_COUNT_PLACEHOLDER) {
|
|
result = pageCount;
|
|
}
|
|
|
|
return $.isArray(result) ? result.concat([" "]) : [result, " "];
|
|
}, this));
|
|
|
|
var $pager = $("<div>").addClass(this.pagerClass)
|
|
.append(pagerParts);
|
|
|
|
return $pager;
|
|
},
|
|
|
|
_createPages: function() {
|
|
var pageCount = this._pagesCount(),
|
|
pageButtonCount = this.pageButtonCount,
|
|
firstDisplayingPage = this._firstDisplayingPage,
|
|
pages = [],
|
|
pageNumber;
|
|
|
|
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) {
|
|
return this._createPagerButton(text, this.pagerNavButtonClass, function() {
|
|
this.openPage(pageIndex);
|
|
});
|
|
},
|
|
|
|
_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,
|
|
scrollBarWidth = this._scrollBarWidth(),
|
|
gridWidth;
|
|
|
|
if(width === "auto") {
|
|
$headerGrid.width("auto");
|
|
gridWidth = $headerGrid.outerWidth();
|
|
width = gridWidth + scrollBarWidth;
|
|
}
|
|
|
|
$headerGrid.width("");
|
|
$bodyGrid.width("");
|
|
this._header.css("padding-right", scrollBarWidth);
|
|
this._container.width(width);
|
|
gridWidth = $headerGrid.outerWidth();
|
|
$bodyGrid.width(gridWidth);
|
|
},
|
|
|
|
_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, doneCallback) {
|
|
this._showLoading();
|
|
|
|
var controller = this._controller;
|
|
if(!controller || !controller[method]) {
|
|
throw new 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() {
|
|
clearTimeout(this._loadingTimer);
|
|
|
|
this._loadingTimer = setTimeout($.proxy(function() {
|
|
this._loadIndicator.show();
|
|
}, this), this.loadIndicationDelay);
|
|
},
|
|
|
|
_hideLoading: function() {
|
|
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());
|
|
|
|
this._callEventHandler(this.onDataLoading, {
|
|
filter: filter
|
|
});
|
|
|
|
return this._controllerCall("loadData", filter, function(loadedData) {
|
|
this._loadStrategy.finishLoad(loadedData);
|
|
|
|
this._callEventHandler(this.onDataLoaded, {
|
|
data: loadedData
|
|
});
|
|
});
|
|
},
|
|
|
|
_getFilter: function() {
|
|
var result = {};
|
|
this._eachField(function(field) {
|
|
if(field.filtering) {
|
|
result[field.name] = field.filterValue();
|
|
}
|
|
});
|
|
return result;
|
|
},
|
|
|
|
_sortingParams: function() {
|
|
if(this.sorting && this._sortField) {
|
|
return {
|
|
sortField: this._sortField.name,
|
|
sortOrder: this._sortOrder
|
|
};
|
|
}
|
|
return {};
|
|
},
|
|
|
|
clearFilter: function() {
|
|
var $filterRow = this._createFilterRow();
|
|
this._filterRow.replaceWith($filterRow);
|
|
this._filterRow = $filterRow;
|
|
return this.search();
|
|
},
|
|
|
|
insertItem: function(item) {
|
|
var insertingItem = item || this._getInsertItem();
|
|
|
|
this._callEventHandler(this.onItemInserting, {
|
|
item: insertingItem
|
|
});
|
|
|
|
return this._controllerCall("insertItem", insertingItem, function(insertedItem) {
|
|
insertedItem = insertedItem || insertingItem;
|
|
this._loadStrategy.finishInsert(insertedItem);
|
|
|
|
this._callEventHandler(this.onItemInserted, {
|
|
item: insertedItem
|
|
});
|
|
});
|
|
},
|
|
|
|
_getInsertItem: function() {
|
|
var result = {};
|
|
this._eachField(function(field) {
|
|
if(field.inserting) {
|
|
result[field.name] = field.insertValue();
|
|
}
|
|
});
|
|
return result;
|
|
},
|
|
|
|
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;
|
|
|
|
if(this._editingRow) {
|
|
this.cancelEdit();
|
|
}
|
|
|
|
var item = $row.data(JSGRID_ROW_DATA_KEY),
|
|
$editRow = this._createEditRow(item);
|
|
|
|
this._editingRow = $row;
|
|
$row.hide();
|
|
$editRow.insertAfter($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) {
|
|
$("<td>").addClass(field.css)
|
|
.appendTo($result)
|
|
.append(field.editTemplate ? field.editTemplate(item[field.name], item) : "")
|
|
.width(field.width || "auto");
|
|
});
|
|
|
|
return $result;
|
|
},
|
|
|
|
updateItem: function(item, editedItem) {
|
|
if(arguments.length === 1) {
|
|
editedItem = item;
|
|
}
|
|
|
|
var $row = item ? this._rowByItem(item) : this._editingRow;
|
|
editedItem = editedItem || this._getEditedItem();
|
|
|
|
return this._updateRow($row, editedItem);
|
|
},
|
|
|
|
_updateRow: function($updatingRow, editedItem) {
|
|
var updatingItem = $updatingRow.data(JSGRID_ROW_DATA_KEY),
|
|
updatingItemIndex = this._itemIndex(updatingItem);
|
|
|
|
$.extend(updatingItem, editedItem);
|
|
|
|
this._callEventHandler(this.onItemUpdating, {
|
|
row: $updatingRow,
|
|
item: updatingItem,
|
|
itemIndex: updatingItemIndex
|
|
});
|
|
|
|
return this._controllerCall("updateItem", updatingItem, function(updatedItem) {
|
|
updatedItem = updatedItem || updatingItem;
|
|
this._finishUpdate($updatingRow, updatedItem, updatingItemIndex);
|
|
|
|
this._callEventHandler(this.onItemUpdated, {
|
|
row: $updatingRow,
|
|
item: updatedItem,
|
|
itemIndex: updatingItemIndex
|
|
});
|
|
});
|
|
},
|
|
|
|
_itemIndex: function(item) {
|
|
return $.inArray(item, this.data);
|
|
},
|
|
|
|
_finishUpdate: function($updatedRow, updatedItem, updatedItemIndex) {
|
|
this.cancelEdit();
|
|
this.data[updatedItemIndex] = updatedItem;
|
|
$updatedRow.replaceWith(this._createRow(updatedItem, updatedItemIndex));
|
|
},
|
|
|
|
_getEditedItem: function() {
|
|
var result = {};
|
|
this._eachField(function(field) {
|
|
if(field.editing) {
|
|
result[field.name] = field.editValue();
|
|
}
|
|
});
|
|
return result;
|
|
},
|
|
|
|
cancelEdit: function() {
|
|
if(!this._editingRow) {
|
|
return;
|
|
}
|
|
|
|
var $row = this._editingRow,
|
|
$editRow = $row.data(JSGRID_EDIT_ROW_DATA_KEY);
|
|
|
|
$editRow.remove();
|
|
$row.show();
|
|
this._editingRow = null;
|
|
},
|
|
|
|
deleteItem: function(item) {
|
|
var $row = this._rowByItem(item);
|
|
|
|
if(!$row.length)
|
|
return;
|
|
|
|
var that = this;
|
|
if (typeof this.deleteConfirm === 'function') {
|
|
this.deleteConfirm(this, $row.data(JSGRID_ROW_DATA_KEY), function (result) {
|
|
if (result) {
|
|
that._deleteRow($row);
|
|
}
|
|
});
|
|
} else {
|
|
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);
|
|
|
|
this._callEventHandler(this.onItemDeleting, {
|
|
row: $row,
|
|
item: deletingItem,
|
|
itemIndex: deletingItemIndex
|
|
});
|
|
|
|
return this._controllerCall("deleteItem", deletingItem, 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;
|
|
};
|
|
|
|
window.jsGrid = {
|
|
Grid: Grid,
|
|
fields: []
|
|
};
|
|
|
|
}(window, jQuery));
|
|
(function(jsGrid, $, undefined) {
|
|
|
|
function LoadIndicator(config) {
|
|
this._init(config);
|
|
}
|
|
|
|
LoadIndicator.prototype = {
|
|
|
|
container: "body",
|
|
message: "Loading...",
|
|
shading: true,
|
|
|
|
zIndex: 1000,
|
|
shaderClass: "jsgrid-load-shader",
|
|
loadPanelClass: "jsgrid-load-panel",
|
|
|
|
_init: function(config) {
|
|
$.extend(true, this, config);
|
|
|
|
this._initContainer();
|
|
this._initShader();
|
|
this._initLoadPanel();
|
|
},
|
|
|
|
_initContainer: function() {
|
|
this._container = $(this.container);
|
|
},
|
|
|
|
_initShader: function() {
|
|
if(!this.shading)
|
|
return;
|
|
|
|
this._shader = $("<div>").addClass(this.shaderClass)
|
|
.hide()
|
|
.css({
|
|
position: "absolute",
|
|
top: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
left: 0,
|
|
zIndex: this.zIndex
|
|
})
|
|
.appendTo(this._container);
|
|
},
|
|
|
|
_initLoadPanel: function() {
|
|
this._loadPanel = $("<div>").addClass(this.loadPanelClass)
|
|
.text(this.message)
|
|
.hide()
|
|
.css({
|
|
position: "absolute",
|
|
top: "50%",
|
|
left: "50%",
|
|
zIndex: this.zIndex
|
|
})
|
|
.appendTo(this._container);
|
|
},
|
|
|
|
show: function() {
|
|
var $loadPanel = this._loadPanel.show();
|
|
|
|
var actualWidth = $loadPanel.outerWidth();
|
|
var actualHeight = $loadPanel.outerHeight();
|
|
|
|
$loadPanel.css({
|
|
marginTop: -actualHeight / 2,
|
|
marginLeft: -actualWidth / 2
|
|
});
|
|
|
|
this._shader.show();
|
|
},
|
|
|
|
hide: function() {
|
|
this._loadPanel.hide();
|
|
this._shader.hide();
|
|
}
|
|
|
|
};
|
|
|
|
jsGrid.LoadIndicator = LoadIndicator;
|
|
|
|
}(jsGrid, jQuery));
|
|
(function(jsGrid, $, undefined) {
|
|
|
|
function DirectLoadingStrategy(grid) {
|
|
this._grid = grid;
|
|
}
|
|
|
|
DirectLoadingStrategy.prototype = {
|
|
|
|
firstDisplayIndex: function() {
|
|
var grid = this._grid;
|
|
return grid.option("paging") ? (grid.option("pageIndex") - 1) * grid.option("pageSize") : 0;
|
|
},
|
|
|
|
lastDisplayIndex: function() {
|
|
var grid = this._grid;
|
|
var itemsCount = grid.option("data").length;
|
|
|
|
return grid.option("paging")
|
|
? Math.min(grid.option("pageIndex") * grid.option("pageSize"), itemsCount)
|
|
: itemsCount;
|
|
},
|
|
|
|
itemsCount: function() {
|
|
return this._grid.option("data").length;
|
|
},
|
|
|
|
openPage: function(index) {
|
|
this._grid.refresh();
|
|
},
|
|
|
|
loadParams: function() {
|
|
return {};
|
|
},
|
|
|
|
sort: function() {
|
|
this._grid._sortData();
|
|
this._grid.refresh();
|
|
return $.Deferred().resolve().promise();
|
|
},
|
|
|
|
finishLoad: function(loadedData) {
|
|
this._grid.option("data", loadedData);
|
|
},
|
|
|
|
finishInsert: function(insertedItem) {
|
|
var grid = this._grid;
|
|
grid.option("data").push(insertedItem);
|
|
grid.refresh();
|
|
},
|
|
|
|
finishDelete: function(deletedItem, deletedItemIndex) {
|
|
var grid = this._grid;
|
|
grid.option("data").splice(deletedItemIndex, 1);
|
|
grid.reset();
|
|
}
|
|
};
|
|
|
|
|
|
function PageLoadingStrategy(grid) {
|
|
this._grid = grid;
|
|
this._itemsCount = 0;
|
|
}
|
|
|
|
PageLoadingStrategy.prototype = {
|
|
firstDisplayIndex: function() {
|
|
return 0;
|
|
},
|
|
|
|
lastDisplayIndex: function() {
|
|
return this._grid.option("data").length;
|
|
},
|
|
|
|
itemsCount: function() {
|
|
return this._itemsCount;
|
|
},
|
|
|
|
openPage: function(index) {
|
|
this._grid.loadData();
|
|
},
|
|
|
|
loadParams: function() {
|
|
var grid = this._grid;
|
|
return {
|
|
pageIndex: grid.option("pageIndex"),
|
|
pageSize: grid.option("pageSize")
|
|
};
|
|
},
|
|
|
|
sort: function() {
|
|
return this._grid.loadData();
|
|
},
|
|
|
|
finishLoad: function(loadedData) {
|
|
this._itemsCount = loadedData.itemsCount;
|
|
this._grid.option("data", loadedData.data);
|
|
},
|
|
|
|
finishInsert: function(insertedItem) {
|
|
this._grid.search();
|
|
},
|
|
|
|
finishDelete: function(deletedItem, deletedItemIndex) {
|
|
this._grid.search();
|
|
}
|
|
};
|
|
|
|
jsGrid.loadStrategies = {
|
|
DirectLoadingStrategy: DirectLoadingStrategy,
|
|
PageLoadingStrategy: PageLoadingStrategy
|
|
};
|
|
|
|
}(jsGrid, jQuery));
|
|
(function(jsGrid, $, undefined) {
|
|
|
|
var sortStrategies = {
|
|
string: function(str1, str2) {
|
|
return str1.localeCompare(str2);
|
|
},
|
|
|
|
number: function(n1, n2) {
|
|
return n1 - n2;
|
|
},
|
|
|
|
date: function(dt1, dt2) {
|
|
return dt1 - dt2;
|
|
},
|
|
|
|
numberAsString: function(n1, n2) {
|
|
return parseFloat(n1) - parseFloat(n2);
|
|
}
|
|
};
|
|
|
|
jsGrid.sortStrategies = sortStrategies;
|
|
|
|
}(jsGrid, jQuery));
|
|
(function(jsGrid, $, undefined) {
|
|
|
|
function Field(config) {
|
|
$.extend(true, this, config);
|
|
this.sortingFunc = this._getSortingFunc();
|
|
}
|
|
|
|
Field.prototype = {
|
|
name: "",
|
|
title: "",
|
|
css: "",
|
|
align: "",
|
|
width: 100,
|
|
|
|
filtering: true,
|
|
inserting: true,
|
|
editing: true,
|
|
sorting: true,
|
|
sorter: "string", // name of SortStrategy or function to compare elements
|
|
|
|
headerTemplate: function() {
|
|
return this.title || this.name;
|
|
},
|
|
|
|
itemTemplate: function(value, item) {
|
|
return value;
|
|
},
|
|
|
|
filterTemplate: function() {
|
|
return "";
|
|
},
|
|
|
|
insertTemplate: function() {
|
|
return "";
|
|
},
|
|
|
|
editTemplate: function(value, item) {
|
|
this._value = value;
|
|
return this.itemTemplate(value, item);
|
|
},
|
|
|
|
filterValue: function() {
|
|
return "";
|
|
},
|
|
|
|
insertValue: function() {
|
|
return "";
|
|
},
|
|
|
|
editValue: function() {
|
|
return this._value;
|
|
},
|
|
|
|
_getSortingFunc: function() {
|
|
var sorter = this.sorter;
|
|
|
|
if($.isFunction(sorter)) {
|
|
return sorter;
|
|
}
|
|
|
|
if(typeof sorter === "string") {
|
|
return jsGrid.sortStrategies[sorter];
|
|
}
|
|
|
|
throw Error("Wrong sorter for the field \"" + this.name + "\"!");
|
|
}
|
|
};
|
|
|
|
jsGrid.Field = Field;
|
|
|
|
}(jsGrid, jQuery));
|
|
(function(jsGrid, $, undefined) {
|
|
|
|
var Field = jsGrid.Field;
|
|
|
|
function TextField(config) {
|
|
Field.call(this, config);
|
|
}
|
|
|
|
TextField.prototype = new Field({
|
|
|
|
autosearch: true,
|
|
|
|
filterTemplate: function() {
|
|
var grid = this._grid,
|
|
$result = this.filterControl = this._createTextBox();
|
|
|
|
if(this.autosearch) {
|
|
$result.on("keypress", function(e) {
|
|
if(e.which === 13) {
|
|
grid.search();
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
}
|
|
|
|
return $result;
|
|
},
|
|
|
|
insertTemplate: function() {
|
|
var $result = this.insertControl = this._createTextBox();
|
|
return $result;
|
|
},
|
|
|
|
editTemplate: function(value) {
|
|
var $result = this.editControl = this._createTextBox();
|
|
$result.val(value);
|
|
return $result;
|
|
},
|
|
|
|
filterValue: function() {
|
|
return this.filterControl.val();
|
|
},
|
|
|
|
insertValue: function() {
|
|
return this.insertControl.val();
|
|
},
|
|
|
|
editValue: function() {
|
|
return this.editControl.val();
|
|
},
|
|
|
|
_createTextBox: function() {
|
|
return $("<input>").attr("type", "text");
|
|
}
|
|
});
|
|
|
|
jsGrid.fields.text = jsGrid.TextField = TextField;
|
|
|
|
}(jsGrid, jQuery));
|
|
(function(jsGrid, $, undefined) {
|
|
|
|
var TextField = jsGrid.TextField;
|
|
|
|
function NumberField(config) {
|
|
TextField.call(this, config);
|
|
}
|
|
|
|
NumberField.prototype = new TextField({
|
|
|
|
sorter: "number",
|
|
align: "right",
|
|
|
|
filterValue: function() {
|
|
return parseInt(this.filterControl.val() || 0, 10);
|
|
},
|
|
|
|
insertValue: function() {
|
|
return parseInt(this.insertControl.val() || 0, 10);
|
|
},
|
|
|
|
editValue: function() {
|
|
return parseInt(this.editControl.val() || 0, 10);
|
|
},
|
|
|
|
_createTextBox: function() {
|
|
return $("<input>").attr("type", "number");
|
|
}
|
|
});
|
|
|
|
jsGrid.fields.number = jsGrid.NumberField = NumberField;
|
|
|
|
}(jsGrid, jQuery));
|
|
(function(jsGrid, $, undefined) {
|
|
|
|
var TextField = jsGrid.TextField;
|
|
|
|
function TextAreaField(config) {
|
|
TextField.call(this, config);
|
|
}
|
|
|
|
TextAreaField.prototype = new TextField({
|
|
|
|
insertTemplate: function() {
|
|
var $result = this.insertControl = this._createTextArea();
|
|
return $result;
|
|
},
|
|
|
|
editTemplate: function(value) {
|
|
var $result = this.editControl = this._createTextArea();
|
|
$result.val(value);
|
|
return $result;
|
|
},
|
|
|
|
_createTextArea: function() {
|
|
return $("<textarea>");
|
|
}
|
|
});
|
|
|
|
jsGrid.fields.textarea = jsGrid.TextAreaField = TextAreaField;
|
|
|
|
}(jsGrid, jQuery));
|
|
(function(jsGrid, $, undefined) {
|
|
|
|
var NumberField = jsGrid.NumberField;
|
|
|
|
function SelectField(config) {
|
|
this.items = [];
|
|
this.selectedIndex = -1;
|
|
this.valueField = "";
|
|
this.textField = "";
|
|
|
|
NumberField.call(this, config);
|
|
|
|
if(!config.valueType && this.valueField && this.items.length) {
|
|
this.valueType = typeof this.items[0][this.valueField];
|
|
}
|
|
}
|
|
|
|
SelectField.prototype = new NumberField({
|
|
|
|
align: "center",
|
|
valueType: "number",
|
|
|
|
itemTemplate: function(value) {
|
|
var items = this.items,
|
|
valueField = this.valueField,
|
|
textField = this.textField,
|
|
resultItem;
|
|
|
|
if(valueField) {
|
|
resultItem = $.grep(items, function(item, index) {
|
|
return item[valueField] === value;
|
|
})[0] || {};
|
|
}
|
|
else {
|
|
resultItem = items[value];
|
|
}
|
|
|
|
return (textField ? resultItem[textField] : resultItem) || "";
|
|
},
|
|
|
|
filterTemplate: function() {
|
|
var grid = this._grid,
|
|
$result = this.filterControl = this._createSelect();
|
|
|
|
if(this.autosearch) {
|
|
$result.on("change", function(e) {
|
|
grid.search();
|
|
});
|
|
}
|
|
|
|
return $result;
|
|
},
|
|
|
|
insertTemplate: function() {
|
|
var $result = this.insertControl = this._createSelect();
|
|
return $result;
|
|
},
|
|
|
|
editTemplate: function(value) {
|
|
var $result = this.editControl = this._createSelect();
|
|
(value !== undefined) && $result.val(value);
|
|
return $result;
|
|
},
|
|
|
|
filterValue: function() {
|
|
var val = this.filterControl.val();
|
|
return this.valueType === "number" ? parseInt(val || 0, 10) : val;
|
|
},
|
|
|
|
insertValue: function() {
|
|
var val = this.insertControl.val();
|
|
return this.valueType === "number" ? parseInt(val || 0, 10) : val;
|
|
},
|
|
|
|
editValue: function() {
|
|
var val = this.editControl.val();
|
|
return this.valueType === "number" ? parseInt(val || 0, 10) : val;
|
|
},
|
|
|
|
_createSelect: function() {
|
|
var $result = $("<select>"),
|
|
valueField = this.valueField,
|
|
textField = this.textField,
|
|
selectedIndex = this.selectedIndex;
|
|
|
|
$.each(this.items, function(index, item) {
|
|
var value = valueField ? item[valueField] : index,
|
|
text = textField ? item[textField] : item;
|
|
|
|
var $option = $("<option>")
|
|
.attr("value", value)
|
|
.text(text)
|
|
.appendTo($result);
|
|
|
|
$option.prop("selected", (selectedIndex === index));
|
|
});
|
|
|
|
return $result;
|
|
}
|
|
});
|
|
|
|
jsGrid.fields.select = jsGrid.SelectField = SelectField;
|
|
|
|
}(jsGrid, jQuery));
|
|
(function(jsGrid, $, undefined) {
|
|
|
|
var Field = jsGrid.Field;
|
|
|
|
function CheckboxField(config) {
|
|
Field.call(this, config);
|
|
}
|
|
|
|
CheckboxField.prototype = new Field({
|
|
|
|
sorter: "number",
|
|
align: "center",
|
|
autosearch: true,
|
|
|
|
itemTemplate: function(value) {
|
|
return this._createCheckbox().prop({
|
|
checked: value,
|
|
disabled: true
|
|
});
|
|
},
|
|
|
|
filterTemplate: function() {
|
|
var grid = this._grid,
|
|
$result = this.filterControl = this._createCheckbox();
|
|
|
|
$result.prop({
|
|
readOnly: true,
|
|
indeterminate: true
|
|
});
|
|
|
|
$result.on("click", function() {
|
|
var $cb = $(this);
|
|
|
|
if($cb.prop("readOnly")) {
|
|
$cb.prop({
|
|
checked: false,
|
|
readOnly: false
|
|
});
|
|
}
|
|
else if (!$cb.prop("checked")) {
|
|
$cb.prop({
|
|
readOnly: true,
|
|
indeterminate: true
|
|
});
|
|
}
|
|
});
|
|
|
|
if(this.autosearch) {
|
|
$result.on("click", function() {
|
|
grid.search();
|
|
});
|
|
}
|
|
|
|
return $result;
|
|
},
|
|
|
|
insertTemplate: function() {
|
|
var $result = this.insertControl = this._createCheckbox();
|
|
return $result;
|
|
},
|
|
|
|
editTemplate: function(value) {
|
|
var $result = this.editControl = this._createCheckbox();
|
|
$result.prop("checked", value);
|
|
return $result;
|
|
},
|
|
|
|
filterValue: function() {
|
|
return this.filterControl.get(0).indeterminate
|
|
? undefined
|
|
: this.filterControl.is(":checked");
|
|
},
|
|
|
|
insertValue: function() {
|
|
return this.insertControl.is(":checked");
|
|
},
|
|
|
|
editValue: function() {
|
|
return this.editControl.is(":checked");
|
|
},
|
|
|
|
_createCheckbox: function() {
|
|
return $("<input>").attr("type", "checkbox");
|
|
}
|
|
});
|
|
|
|
jsGrid.fields.checkbox = jsGrid.CheckboxField = CheckboxField;
|
|
|
|
}(jsGrid, jQuery));
|
|
(function(jsGrid, $, undefined) {
|
|
|
|
var Field = jsGrid.Field;
|
|
|
|
function ControlField(config) {
|
|
Field.call(this, config);
|
|
}
|
|
|
|
ControlField.prototype = new Field({
|
|
css: "jsgrid-control-field",
|
|
align: "center",
|
|
width: 50,
|
|
filtering: false,
|
|
inserting: false,
|
|
editing: false,
|
|
sorting: false,
|
|
|
|
buttonClass: "jsgrid-button",
|
|
modeButtonClass: "jsgrid-mode-button",
|
|
|
|
searchModeButtonClass: "jsgrid-search-mode-button",
|
|
insertModeButtonClass: "jsgrid-insert-mode-button",
|
|
editButtonClass: "jsgrid-edit-button",
|
|
deleteButtonClass: "jsgrid-delete-button",
|
|
searchButtonClass: "jsgrid-search-button",
|
|
clearFilterButtonClass: "jsgrid-clear-filter-button",
|
|
insertButtonClass: "jsgrid-insert-button",
|
|
updateButtonClass: "jsgrid-update-button",
|
|
cancelEditButtonClass: "jsgrid-cancel-edit-button",
|
|
|
|
searchModeButtonTooltip: "Switch to searching",
|
|
insertModeButtonTooltip: "Switch to inserting",
|
|
editButtonTooltip: "Edit",
|
|
deleteButtonTooltip: "Delete",
|
|
searchButtonTooltip: "Search",
|
|
clearFilterButtonTooltip: "Clear filter",
|
|
insertButtonTooltip: "Insert",
|
|
updateButtonTooltip: "Update",
|
|
cancelEditButtonTooltip: "Cancel edit",
|
|
|
|
editButton: true,
|
|
deleteButton: true,
|
|
clearFilterButton: true,
|
|
modeSwitchButton: true,
|
|
|
|
headerTemplate: function() {
|
|
return this.modeSwitchButton ? this._createModeSwitchButton() : "";
|
|
},
|
|
|
|
itemTemplate: function(value, item) {
|
|
var $result = $([]);
|
|
|
|
if(this.editButton) {
|
|
$result = $result.add(this._createEditButton(item));
|
|
}
|
|
|
|
if(this.deleteButton) {
|
|
$result = $result.add(this._createDeleteButton(item));
|
|
}
|
|
|
|
return $result;
|
|
},
|
|
|
|
filterTemplate: function() {
|
|
var $result = this._createSearchButton();
|
|
return this.clearFilterButton ? $result.add(this._createClearFilterButton()) : $result;
|
|
},
|
|
|
|
insertTemplate: function() {
|
|
return this._createInsertButton();
|
|
},
|
|
|
|
editTemplate: function() {
|
|
return this._createUpdateButton().add(this._createCancelEditButton());
|
|
},
|
|
|
|
_createModeSwitchButton: function() {
|
|
var isInserting = false;
|
|
|
|
var updateButtonState = $.proxy(function() {
|
|
$button.attr("title", isInserting ? this.searchModeButtonTooltip : this.insertModeButtonTooltip)
|
|
.toggleClass(this.insertModeButtonClass, !isInserting)
|
|
.toggleClass(this.searchModeButtonClass, isInserting);
|
|
}, this);
|
|
|
|
var $button = this._createGridButton(this.modeButtonClass, "", function(grid) {
|
|
isInserting = !isInserting;
|
|
grid.option("inserting", isInserting);
|
|
grid.option("filtering", !isInserting);
|
|
updateButtonState();
|
|
});
|
|
|
|
updateButtonState();
|
|
|
|
return $button;
|
|
},
|
|
|
|
_createEditButton: function(item) {
|
|
return this._createGridButton(this.editButtonClass, this.editButtonTooltip, function(grid, e) {
|
|
grid.editItem(item);
|
|
e.stopPropagation();
|
|
});
|
|
},
|
|
|
|
_createDeleteButton: function(item) {
|
|
return this._createGridButton(this.deleteButtonClass, this.deleteButtonTooltip, function(grid, e) {
|
|
grid.deleteItem(item);
|
|
e.stopPropagation();
|
|
});
|
|
},
|
|
|
|
_createSearchButton: function() {
|
|
return this._createGridButton(this.searchButtonClass, this.searchButtonTooltip, function(grid) {
|
|
grid.search();
|
|
});
|
|
},
|
|
|
|
_createClearFilterButton: function() {
|
|
return this._createGridButton(this.clearFilterButtonClass, this.clearFilterButtonTooltip, function(grid) {
|
|
grid.clearFilter();
|
|
});
|
|
},
|
|
|
|
_createInsertButton: function() {
|
|
return this._createGridButton(this.insertButtonClass, this.insertButtonTooltip, function(grid) {
|
|
grid.insertItem();
|
|
grid.clearInsert();
|
|
});
|
|
},
|
|
|
|
_createUpdateButton: function() {
|
|
return this._createGridButton(this.updateButtonClass, this.updateButtonTooltip, function(grid, e) {
|
|
grid.updateItem();
|
|
e.stopPropagation();
|
|
});
|
|
},
|
|
|
|
_createCancelEditButton: function() {
|
|
return this._createGridButton(this.cancelEditButtonClass, this.cancelEditButtonTooltip, function(grid, e) {
|
|
grid.cancelEdit();
|
|
e.stopPropagation();
|
|
});
|
|
},
|
|
|
|
_createGridButton: function(cls, tooltip, clickHandler) {
|
|
var grid = this._grid;
|
|
|
|
return $("<input>").addClass(this.buttonClass)
|
|
.addClass(cls)
|
|
.attr({
|
|
type: "button",
|
|
title: tooltip
|
|
})
|
|
.on("click", function(e) {
|
|
clickHandler(grid, e);
|
|
});
|
|
},
|
|
|
|
editValue: function() {
|
|
return "";
|
|
}
|
|
|
|
});
|
|
|
|
jsGrid.fields.control = jsGrid.ControlField = ControlField;
|
|
|
|
}(jsGrid, jQuery)); |