").addClass(this.editRowClass);
this._eachField(function(field) {
var fieldValue = this._getItemFieldValue(item, field);
this._prepareCell("", field, "editcss")
.append(this.renderTemplate(field.editTemplate || "", field, { value: fieldValue, item: 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),
updatedItem = $.extend(true, {}, updatingItem, editedItem);
var args = this._callEventHandler(this.onItemUpdating, {
row: $updatingRow,
item: updatedItem,
itemIndex: updatingItemIndex,
previousItem: updatingItem
});
return this._controllerCall("updateItem", updatedItem, args.cancel, function(loadedUpdatedItem) {
var previousItem = $.extend(true, {}, updatingItem);
updatedItem = loadedUpdatedItem || $.extend(true, updatingItem, editedItem);
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 && 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,
version: '1.5.3'
};
}(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 = $("").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 = $(" ").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();
},
reset: function() {
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")
};
},
reset: function() {
return this._grid.loadData();
},
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 isDefined = function(val) {
return typeof(val) !== "undefined" && val !== null;
};
var sortStrategies = {
string: function(str1, str2) {
if(!isDefined(str1) && !isDefined(str2))
return 0;
if(!isDefined(str1))
return -1;
if(!isDefined(str2))
return 1;
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 Validation(config) {
this._init(config);
}
Validation.prototype = {
_init: function(config) {
$.extend(true, this, config);
},
validate: function(args) {
var errors = [];
$.each(this._normalizeRules(args.rules), function(_, rule) {
if(rule.validator(args.value, args.item, rule.param))
return;
var errorMessage = $.isFunction(rule.message) ? rule.message(args.value, args.item) : rule.message;
errors.push(errorMessage);
});
return errors;
},
_normalizeRules: function(rules) {
if(!$.isArray(rules))
rules = [rules];
return $.map(rules, $.proxy(function(rule) {
return this._normalizeRule(rule);
}, this));
},
_normalizeRule: function(rule) {
if(typeof rule === "string")
rule = { validator: rule };
if($.isFunction(rule))
rule = { validator: rule };
if($.isPlainObject(rule))
rule = $.extend({}, rule);
else
throw Error("wrong validation config specified");
if($.isFunction(rule.validator))
return rule;
return this._applyNamedValidator(rule, rule.validator);
},
_applyNamedValidator: function(rule, validatorName) {
delete rule.validator;
var validator = validators[validatorName];
if(!validator)
throw Error("unknown validator \"" + validatorName + "\"");
if($.isFunction(validator)) {
validator = { validator: validator };
}
return $.extend({}, validator, rule);
}
};
jsGrid.Validation = Validation;
var validators = {
required: {
message: "Field is required",
validator: function(value) {
return value !== undefined && value !== null && value !== "";
}
},
rangeLength: {
message: "Field value length is out of the defined range",
validator: function(value, _, param) {
return value.length >= param[0] && value.length <= param[1];
}
},
minLength: {
message: "Field value is too short",
validator: function(value, _, param) {
return value.length >= param;
}
},
maxLength: {
message: "Field value is too long",
validator: function(value, _, param) {
return value.length <= param;
}
},
pattern: {
message: "Field value is not matching the defined pattern",
validator: function(value, _, param) {
if(typeof param === "string") {
param = new RegExp("^(?:" + param + ")$");
}
return param.test(value);
}
},
range: {
message: "Field value is out of the defined range",
validator: function(value, _, param) {
return value >= param[0] && value <= param[1];
}
},
min: {
message: "Field value is too small",
validator: function(value, _, param) {
return value >= param;
}
},
max: {
message: "Field value is too large",
validator: function(value, _, param) {
return value <= param;
}
}
};
jsGrid.validators = validators;
}(jsGrid, jQuery));
(function(jsGrid, $, undefined) {
function Field(config) {
$.extend(true, this, config);
this.sortingFunc = this._getSortingFunc();
}
Field.prototype = {
name: "",
title: null,
css: "",
align: "",
width: 100,
visible: true,
filtering: true,
inserting: true,
editing: true,
sorting: true,
sorter: "string", // name of SortStrategy or function to compare elements
headerTemplate: function() {
return (this.title === undefined || this.title === null) ? this.name : this.title;
},
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,
readOnly: false,
filterTemplate: function() {
if(!this.filtering)
return "";
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() {
if(!this.inserting)
return "";
return this.insertControl = this._createTextBox();
},
editTemplate: function(value) {
if(!this.editing)
return this.itemTemplate.apply(this, arguments);
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 $("").attr("type", "text")
.prop("readonly", !!this.readOnly);
}
});
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",
readOnly: false,
filterValue: function() {
return this.filterControl.val()
? parseInt(this.filterControl.val() || 0, 10)
: undefined;
},
insertValue: function() {
return this.insertControl.val()
? parseInt(this.insertControl.val() || 0, 10)
: undefined;
},
editValue: function() {
return this.editControl.val()
? parseInt(this.editControl.val() || 0, 10)
: undefined;
},
_createTextBox: function() {
return $("").attr("type", "number")
.prop("readonly", !!this.readOnly);
}
});
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() {
if(!this.inserting)
return "";
return this.insertControl = this._createTextArea();
},
editTemplate: function(value) {
if(!this.editing)
return this.itemTemplate.apply(this, arguments);
var $result = this.editControl = this._createTextArea();
$result.val(value);
return $result;
},
_createTextArea: function() {
return $("
|