@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
5,613 lines • 178 kB
JavaScript
module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ({
/***/ 0:
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1048);
/***/ }),
/***/ 3:
/***/ (function(module, exports) {
module.exports = function() { throw new Error("define cannot be used indirect"); };
/***/ }),
/***/ 1006:
/***/ (function(module, exports) {
module.exports = require("./kendo.core");
/***/ }),
/***/ 1048:
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function(f, define){
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(1006), __webpack_require__(1049), __webpack_require__(1050) ], __WEBPACK_AMD_DEFINE_FACTORY__ = (f), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
})(function(){
var __meta__ = { // jshint ignore:line
id: "data",
name: "Data source",
category: "framework",
description: "Powerful component for using local and remote data.Fully supports CRUD, Sorting, Paging, Filtering, Grouping, and Aggregates.",
depends: [ "core" ],
features: [ {
id: "data-odata",
name: "OData",
description: "Support for accessing Open Data Protocol (OData) services.",
depends: [ "data.odata" ]
}, {
id: "data-signalr",
name: "SignalR",
description: "Support for binding to SignalR hubs.",
depends: [ "data.signalr" ]
}, {
id: "data-XML",
name: "XML",
description: "Support for binding to XML.",
depends: [ "data.xml" ]
}]
};
/*jshint eqnull: true, loopfunc: true, evil: true */
(function($, undefined) {
var extend = $.extend,
proxy = $.proxy,
isPlainObject = $.isPlainObject,
isEmptyObject = $.isEmptyObject,
isArray = $.isArray,
grep = $.grep,
ajax = $.ajax,
map,
each = $.each,
noop = $.noop,
kendo = window.kendo,
isFunction = kendo.isFunction,
Observable = kendo.Observable,
Class = kendo.Class,
STRING = "string",
FUNCTION = "function",
ASCENDING = "asc",
CREATE = "create",
READ = "read",
UPDATE = "update",
DESTROY = "destroy",
CHANGE = "change",
SYNC = "sync",
GET = "get",
ERROR = "error",
REQUESTSTART = "requestStart",
PROGRESS = "progress",
REQUESTEND = "requestEnd",
crud = [CREATE, READ, UPDATE, DESTROY],
identity = function(o) { return o; },
getter = kendo.getter,
stringify = kendo.stringify,
math = Math,
push = [].push,
join = [].join,
pop = [].pop,
splice = [].splice,
shift = [].shift,
slice = [].slice,
unshift = [].unshift,
toString = {}.toString,
stableSort = kendo.support.stableSort,
dateRegExp = /^\/Date\((.*?)\)\/$/;
var ObservableArray = Observable.extend({
init: function(array, type) {
var that = this;
that.type = type || ObservableObject;
Observable.fn.init.call(that);
that.length = array.length;
that.wrapAll(array, that);
},
at: function(index) {
return this[index];
},
toJSON: function() {
var idx, length = this.length, value, json = new Array(length);
for (idx = 0; idx < length; idx++){
value = this[idx];
if (value instanceof ObservableObject) {
value = value.toJSON();
}
json[idx] = value;
}
return json;
},
parent: noop,
wrapAll: function(source, target) {
var that = this,
idx,
length,
parent = function() {
return that;
};
target = target || [];
for (idx = 0, length = source.length; idx < length; idx++) {
target[idx] = that.wrap(source[idx], parent);
}
return target;
},
wrap: function(object, parent) {
var that = this,
observable;
if (object !== null && toString.call(object) === "[object Object]") {
observable = object instanceof that.type || object instanceof Model;
if (!observable) {
object = object instanceof ObservableObject ? object.toJSON() : object;
object = new that.type(object);
}
object.parent = parent;
object.bind(CHANGE, function(e) {
that.trigger(CHANGE, {
field: e.field,
node: e.node,
index: e.index,
items: e.items || [this],
action: e.node ? (e.action || "itemloaded") : "itemchange"
});
});
}
return object;
},
push: function() {
var index = this.length,
items = this.wrapAll(arguments),
result;
result = push.apply(this, items);
this.trigger(CHANGE, {
action: "add",
index: index,
items: items
});
return result;
},
slice: slice,
sort: [].sort,
join: join,
pop: function() {
var length = this.length, result = pop.apply(this);
if (length) {
this.trigger(CHANGE, {
action: "remove",
index: length - 1,
items:[result]
});
}
return result;
},
splice: function(index, howMany, item) {
var items = this.wrapAll(slice.call(arguments, 2)),
result, i, len;
result = splice.apply(this, [index, howMany].concat(items));
if (result.length) {
this.trigger(CHANGE, {
action: "remove",
index: index,
items: result
});
for (i = 0, len = result.length; i < len; i++) {
if (result[i] && result[i].children) {
result[i].unbind(CHANGE);
}
}
}
if (item) {
this.trigger(CHANGE, {
action: "add",
index: index,
items: items
});
}
return result;
},
shift: function() {
var length = this.length, result = shift.apply(this);
if (length) {
this.trigger(CHANGE, {
action: "remove",
index: 0,
items:[result]
});
}
return result;
},
unshift: function() {
var items = this.wrapAll(arguments),
result;
result = unshift.apply(this, items);
this.trigger(CHANGE, {
action: "add",
index: 0,
items: items
});
return result;
},
indexOf: function(item) {
var that = this,
idx,
length;
for (idx = 0, length = that.length; idx < length; idx++) {
if (that[idx] === item) {
return idx;
}
}
return -1;
},
forEach: function(callback, thisArg) {
var idx = 0;
var length = this.length;
var context = thisArg || window;
for (; idx < length; idx++) {
callback.call(context, this[idx], idx, this);
}
},
map: function(callback, thisArg) {
var idx = 0;
var result = [];
var length = this.length;
var context = thisArg || window;
for (; idx < length; idx++) {
result[idx] = callback.call(context, this[idx], idx, this);
}
return result;
},
reduce: function(callback) {
var idx = 0,
result,
length = this.length;
if (arguments.length == 2) {
result = arguments[1];
} else if (idx < length) {
result = this[idx++];
}
for (; idx < length; idx++) {
result = callback(result, this[idx], idx, this);
}
return result;
},
reduceRight: function(callback) {
var idx = this.length - 1,
result;
if (arguments.length == 2) {
result = arguments[1];
} else if (idx > 0) {
result = this[idx--];
}
for (; idx >= 0; idx--) {
result = callback(result, this[idx], idx, this);
}
return result;
},
filter: function(callback, thisArg) {
var idx = 0;
var result = [];
var item;
var length = this.length;
var context = thisArg || window;
for (; idx < length; idx++) {
item = this[idx];
if (callback.call(context, item, idx, this)) {
result[result.length] = item;
}
}
return result;
},
find: function(callback, thisArg) {
var idx = 0;
var item;
var length = this.length;
var context = thisArg || window;
for (; idx < length; idx++) {
item = this[idx];
if (callback.call(context, item, idx, this)) {
return item;
}
}
},
every: function(callback, thisArg) {
var idx = 0;
var item;
var length = this.length;
var context = thisArg || window;
for (; idx < length; idx++) {
item = this[idx];
if (!callback.call(context, item, idx, this)) {
return false;
}
}
return true;
},
some: function(callback, thisArg) {
var idx = 0;
var item;
var length = this.length;
var context = thisArg || window;
for (; idx < length; idx++) {
item = this[idx];
if (callback.call(context, item, idx, this)) {
return true;
}
}
return false;
},
// non-standard collection methods
remove: function(item) {
var idx = this.indexOf(item);
if (idx !== -1) {
this.splice(idx, 1);
}
},
empty: function() {
this.splice(0, this.length);
}
});
// Polyfill for Symbol.iterator
if (typeof Symbol !== "undefined" && Symbol.iterator && !ObservableArray.prototype[Symbol.iterator]) {
ObservableArray.prototype[Symbol.iterator] = [][Symbol.iterator];
}
var LazyObservableArray = ObservableArray.extend({
init: function (data, type, events) {
Observable.fn.init.call(this);
this.type = type || ObservableObject;
if (events) {
this._events = events;
}
for (var idx = 0; idx < data.length; idx++) {
this[idx] = data[idx];
}
this.length = idx;
this._parent = proxy(function() { return this; }, this);
},
at: function(index) {
var item = this[index];
if (!(item instanceof this.type)) {
item = this[index] = this.wrap(item, this._parent);
} else {
item.parent = this._parent;
}
return item;
}
});
function eventHandler(context, type, field, prefix) {
return function(e) {
var event = {}, key;
for (key in e) {
event[key] = e[key];
}
if (prefix) {
event.field = field + "." + e.field;
} else {
event.field = field;
}
if (type == CHANGE && context._notifyChange) {
context._notifyChange(event);
}
context.trigger(type, event);
};
}
var ObservableObject = Observable.extend({
init: function(value) {
var that = this,
member,
field,
parent = function() {
return that;
};
Observable.fn.init.call(this);
this._handlers = {};
for (field in value) {
member = value[field];
if (typeof member === "object" && member && !member.getTime && field.charAt(0) != "_") {
member = that.wrap(member, field, parent);
}
that[field] = member;
}
that.uid = kendo.guid();
},
shouldSerialize: function(field) {
return this.hasOwnProperty(field) && field !== "_handlers" && field !== "_events" && typeof this[field] !== FUNCTION && field !== "uid";
},
forEach: function(f) {
for (var i in this) {
if (this.shouldSerialize(i)) {
f(this[i], i);
}
}
},
toJSON: function() {
var result = {}, value, field;
for (field in this) {
if (this.shouldSerialize(field)) {
value = this[field];
if (value instanceof ObservableObject || value instanceof ObservableArray) {
value = value.toJSON();
}
result[field] = value;
}
}
return result;
},
get: function(field) {
var that = this, result;
that.trigger(GET, { field: field });
if (field === "this") {
result = that;
} else {
result = kendo.getter(field, true)(that);
}
return result;
},
_set: function(field, value) {
var that = this;
var composite = field.indexOf(".") >= 0;
if (composite) {
var paths = field.split("."),
path = "";
while (paths.length > 1) {
path += paths.shift();
var obj = kendo.getter(path, true)(that);
if (obj instanceof ObservableObject) {
obj.set(paths.join("."), value);
return composite;
}
path += ".";
}
}
kendo.setter(field)(that, value);
return composite;
},
set: function(field, value) {
var that = this,
isSetPrevented = false,
composite = field.indexOf(".") >= 0,
current = kendo.getter(field, true)(that);
if (current !== value) {
if (current instanceof Observable && this._handlers[field]) {
if (this._handlers[field].get) {
current.unbind(GET, this._handlers[field].get);
}
current.unbind(CHANGE, this._handlers[field].change);
}
isSetPrevented = that.trigger("set", { field: field, value: value });
if (!isSetPrevented) {
if (!composite) {
value = that.wrap(value, field, function() { return that; });
}
if (!that._set(field, value) || field.indexOf("(") >= 0 || field.indexOf("[") >= 0) {
that.trigger(CHANGE, { field: field });
}
}
}
return isSetPrevented;
},
parent: noop,
wrap: function(object, field, parent) {
var that = this;
var get;
var change;
var type = toString.call(object);
if (object != null && (type === "[object Object]" || type === "[object Array]")) {
var isObservableArray = object instanceof ObservableArray;
var isDataSource = object instanceof DataSource;
if (type === "[object Object]" && !isDataSource && !isObservableArray) {
if (!(object instanceof ObservableObject)) {
object = new ObservableObject(object);
}
get = eventHandler(that, GET, field, true);
object.bind(GET, get);
change = eventHandler(that, CHANGE, field, true);
object.bind(CHANGE, change);
that._handlers[field] = { get: get, change: change };
} else if (type === "[object Array]" || isObservableArray || isDataSource) {
if (!isObservableArray && !isDataSource) {
object = new ObservableArray(object);
}
change = eventHandler(that, CHANGE, field, false);
object.bind(CHANGE, change);
that._handlers[field] = { change: change };
}
object.parent = parent;
}
return object;
}
});
function equal(x, y) {
if (x === y) {
return true;
}
var xtype = $.type(x), ytype = $.type(y), field;
if (xtype !== ytype) {
return false;
}
if (xtype === "date") {
return x.getTime() === y.getTime();
}
if (xtype !== "object" && xtype !== "array") {
return false;
}
for (field in x) {
if (!equal(x[field], y[field])) {
return false;
}
}
return true;
}
var parsers = {
"number": function(value) {
if (typeof value === STRING && value.toLowerCase() === "null") {
return null;
}
return kendo.parseFloat(value);
},
"date": function(value) {
if (typeof value === STRING && value.toLowerCase() === "null") {
return null;
}
return kendo.parseDate(value);
},
"boolean": function(value) {
if (typeof value === STRING) {
if (value.toLowerCase() === "null") {
return null;
} else {
return value.toLowerCase() === "true";
}
}
return value != null ? !!value : value;
},
"string": function(value) {
if (typeof value === STRING && value.toLowerCase() === "null") {
return null;
}
return value != null ? (value + "") : value;
},
"default": function(value) {
return value;
}
};
var defaultValues = {
"string": "",
"number": 0,
"date": new Date(),
"boolean": false,
"default": ""
};
function getFieldByName(obj, name) {
var field,
fieldName;
for (fieldName in obj) {
field = obj[fieldName];
if (isPlainObject(field) && field.field && field.field === name) {
return field;
} else if (field === name) {
return field;
}
}
return null;
}
var Model = ObservableObject.extend({
init: function(data) {
var that = this;
if (!data || $.isEmptyObject(data)) {
data = $.extend({}, that.defaults, data);
if (that._initializers) {
for (var idx = 0; idx < that._initializers.length; idx++) {
var name = that._initializers[idx];
data[name] = that.defaults[name]();
}
}
}
ObservableObject.fn.init.call(that, data);
that.dirty = false;
that.dirtyFields = {};
if (that.idField) {
that.id = that.get(that.idField);
if (that.id === undefined) {
that.id = that._defaultId;
}
}
},
shouldSerialize: function(field) {
return ObservableObject.fn.shouldSerialize.call(this, field) &&
field !== "uid" && !(this.idField !== "id" && field === "id") &&
field !== "dirty" && field !== "dirtyFields" && field !== "_accessors";
},
_parse: function(field, value) {
var that = this,
fieldName = field,
fields = (that.fields || {}),
parse;
field = fields[field];
if (!field) {
field = getFieldByName(fields, fieldName);
}
if (field) {
parse = field.parse;
if (!parse && field.type) {
parse = parsers[field.type.toLowerCase()];
}
}
return parse ? parse(value) : value;
},
_notifyChange: function(e) {
var action = e.action;
if (action == "add" || action == "remove") {
this.dirty = true;
this.dirtyFields[e.field] = true;
}
},
editable: function(field) {
field = (this.fields || {})[field];
return field ? field.editable !== false : true;
},
set: function(field, value, initiator) {
var that = this;
var dirty = that.dirty;
if (that.editable(field)) {
value = that._parse(field, value);
if (!equal(value, that.get(field))) {
that.dirty = true;
that.dirtyFields[field] = true;
if (ObservableObject.fn.set.call(that, field, value, initiator) && !dirty) {
that.dirty = dirty;
if (!that.dirty) {
that.dirtyFields[field] = false;
}
}
} else {
that.trigger("equalSet", { field: field, value: value });
}
}
},
accept: function(data) {
var that = this,
parent = function() { return that; },
field;
for (field in data) {
var value = data[field];
if (field.charAt(0) != "_") {
value = that.wrap(data[field], field, parent);
}
that._set(field, value);
}
if (that.idField) {
that.id = that.get(that.idField);
}
that.dirty = false;
that.dirtyFields = {};
},
isNew: function() {
return this.id === this._defaultId;
}
});
Model.define = function(base, options) {
if (options === undefined) {
options = base;
base = Model;
}
var model,
proto = extend({ defaults: {} }, options),
name,
field,
type,
value,
idx,
length,
fields = {},
originalName,
id = proto.id,
functionFields = [];
if (id) {
proto.idField = id;
}
if (proto.id) {
delete proto.id;
}
if (id) {
proto.defaults[id] = proto._defaultId = "";
}
if (toString.call(proto.fields) === "[object Array]") {
for (idx = 0, length = proto.fields.length; idx < length; idx++) {
field = proto.fields[idx];
if (typeof field === STRING) {
fields[field] = {};
} else if (field.field) {
fields[field.field] = field;
}
}
proto.fields = fields;
}
for (name in proto.fields) {
field = proto.fields[name];
type = field.type || "default";
value = null;
originalName = name;
name = typeof (field.field) === STRING ? field.field : name;
if (!field.nullable) {
value = proto.defaults[originalName !== name ? originalName : name] = field.defaultValue !== undefined ? field.defaultValue : defaultValues[type.toLowerCase()];
if (typeof value === "function") {
functionFields.push(name);
}
}
if (options.id === name) {
proto._defaultId = value;
}
proto.defaults[originalName !== name ? originalName : name] = value;
field.parse = field.parse || parsers[type];
}
if (functionFields.length > 0) {
proto._initializers = functionFields;
}
model = base.extend(proto);
model.define = function(options) {
return Model.define(model, options);
};
if (proto.fields) {
model.fields = proto.fields;
model.idField = proto.idField;
}
return model;
};
var Comparer = {
selector: function(field) {
return isFunction(field) ? field : getter(field);
},
compare: function(field) {
var selector = this.selector(field);
return function (a, b) {
a = selector(a);
b = selector(b);
if (a == null && b == null) {
return 0;
}
if (a == null) {
return -1;
}
if (b == null) {
return 1;
}
if (a.localeCompare) {
return a.localeCompare(b);
}
return a > b ? 1 : (a < b ? -1 : 0);
};
},
create: function(sort) {
var compare = sort.compare || this.compare(sort.field);
if (sort.dir == "desc") {
return function(a, b) {
return compare(b, a, true);
};
}
return compare;
},
combine: function(comparers) {
return function(a, b) {
var result = comparers[0](a, b),
idx,
length;
for (idx = 1, length = comparers.length; idx < length; idx ++) {
result = result || comparers[idx](a, b);
}
return result;
};
}
};
var StableComparer = extend({}, Comparer, {
asc: function(field) {
var selector = this.selector(field);
return function (a, b) {
var valueA = selector(a);
var valueB = selector(b);
if (valueA && valueA.getTime && valueB && valueB.getTime) {
valueA = valueA.getTime();
valueB = valueB.getTime();
}
if (valueA === valueB) {
return a.__position - b.__position;
}
if (valueA == null) {
return -1;
}
if (valueB == null) {
return 1;
}
if (valueA.localeCompare) {
return valueA.localeCompare(valueB);
}
return valueA > valueB ? 1 : -1;
};
},
desc: function(field) {
var selector = this.selector(field);
return function (a, b) {
var valueA = selector(a);
var valueB = selector(b);
if (valueA && valueA.getTime && valueB && valueB.getTime) {
valueA = valueA.getTime();
valueB = valueB.getTime();
}
if (valueA === valueB) {
return a.__position - b.__position;
}
if (valueA == null) {
return 1;
}
if (valueB == null) {
return -1;
}
if (valueB.localeCompare) {
return valueB.localeCompare(valueA);
}
return valueA < valueB ? 1 : -1;
};
},
create: function(sort) {
return this[sort.dir](sort.field);
}
});
map = function (array, callback) {
var idx, length = array.length, result = new Array(length);
for (idx = 0; idx < length; idx++) {
result[idx] = callback(array[idx], idx, array);
}
return result;
};
var operators = (function(){
function quote(str) {
if (typeof str == "string") {
str = str.replace(/[\r\n]+/g, "");
}
return JSON.stringify(str);
}
function textOp(impl) {
return function(a, b, ignore, accentFoldingFiltering) {
b += "";
if (ignore) {
a = "(" + a + " || '').toString()" + ((accentFoldingFiltering) ? ".toLocaleLowerCase('" + accentFoldingFiltering +"')" : ".toLowerCase()");
b = ((accentFoldingFiltering) ? b.toLocaleLowerCase(accentFoldingFiltering) : b.toLowerCase());
}
return impl(a, quote(b), ignore);
};
}
function operator(op, a, b, ignore, accentFoldingFiltering) {
if (b != null) {
if (typeof b === STRING) {
var date = dateRegExp.exec(b);
if (date) {
b = new Date(+date[1]);
} else if (ignore) {
b = quote(((accentFoldingFiltering) ? b.toLocaleLowerCase(accentFoldingFiltering) : b.toLowerCase()));
a = "((" + a + " || '')+'')" + ((accentFoldingFiltering) ? ".toLocaleLowerCase('" + accentFoldingFiltering +"')" : ".toLowerCase()");
} else {
b = quote(b);
}
}
if (b.getTime) {
//b looks like a Date
a = "(" + a + "&&" + a + ".getTime?" + a + ".getTime():" + a + ")";
b = b.getTime();
}
}
return a + " " + op + " " + b;
}
function getMatchRegexp(pattern) {
// take a pattern, as supported by Excel match filter, and
// convert it to the equivalent JS regular expression.
// Excel patterns support:
//
// * - match any sequence of characters
// ? - match a single character
//
// to match a literal * or ?, they must be prefixed by a tilde (~)
for (var rx = "/^", esc = false, i = 0; i < pattern.length; ++i) {
var ch = pattern.charAt(i);
if (esc) {
rx += "\\" + ch;
} else if (ch == "~") {
esc = true;
continue;
} else if (ch == "*") {
rx += ".*";
} else if (ch == "?") {
rx += ".";
} else if (".+^$()[]{}|\\/\n\r\u2028\u2029\xA0".indexOf(ch) >= 0) {
rx += "\\" + ch;
} else {
rx += ch;
}
esc = false;
}
return rx + "$/";
}
return {
quote: function(value) {
if (value && value.getTime) {
return "new Date(" + value.getTime() + ")";
}
return quote(value);
},
eq: function(a, b, ignore, accentFoldingFiltering) {
return operator("==", a, b, ignore, accentFoldingFiltering);
},
neq: function(a, b, ignore, accentFoldingFiltering) {
return operator("!=", a, b, ignore, accentFoldingFiltering);
},
gt: function(a, b, ignore) {
return operator(">", a, b, ignore);
},
gte: function(a, b, ignore) {
return operator(">=", a, b, ignore);
},
lt: function(a, b, ignore) {
return operator("<", a, b, ignore);
},
lte: function(a, b, ignore) {
return operator("<=", a, b, ignore);
},
startswith: textOp(function(a, b) {
return a + ".lastIndexOf(" + b + ", 0) == 0";
}),
doesnotstartwith: textOp(function(a, b) {
return a + ".lastIndexOf(" + b + ", 0) == -1";
}),
endswith: textOp(function(a, b) {
var n = b ? b.length - 2 : 0;
return a + ".indexOf(" + b + ", " + a + ".length - " + n + ") >= 0";
}),
doesnotendwith: textOp(function(a, b) {
var n = b ? b.length - 2 : 0;
return a + ".indexOf(" + b + ", " + a + ".length - " + n + ") < 0";
}),
contains: textOp(function(a, b) {
return a + ".indexOf(" + b + ") >= 0";
}),
doesnotcontain: textOp(function(a, b) {
return a + ".indexOf(" + b + ") == -1";
}),
matches: textOp(function(a, b){
b = b.substring(1, b.length - 1);
return getMatchRegexp(b) + ".test(" + a + ")";
}),
doesnotmatch: textOp(function(a, b){
b = b.substring(1, b.length - 1);
return "!" + getMatchRegexp(b) + ".test(" + a + ")";
}),
isempty: function(a) {
return a + " === ''";
},
isnotempty: function(a) {
return a + " !== ''";
},
isnull: function(a) {
return "(" + a + " == null)";
},
isnotnull: function(a) {
return "(" + a + " != null)";
},
isnullorempty: function(a) {
return "(" + a + " === null) || (" + a + " === '')";
},
isnotnullorempty: function(a) {
return "(" + a + " !== null) && (" + a + " !== '')";
}
};
})();
function Query(data) {
this.data = data || [];
}
Query.filterExpr = function(expression) {
var expressions = [],
logic = { and: " && ", or: " || " },
idx,
length,
filter,
expr,
fieldFunctions = [],
operatorFunctions = [],
field,
operator,
filters = expression.filters;
for (idx = 0, length = filters.length; idx < length; idx++) {
filter = filters[idx];
field = filter.field;
operator = filter.operator;
if (filter.filters) {
expr = Query.filterExpr(filter);
//Nested function fields or operators - update their index e.g. __o[0] -> __o[1]
filter = expr.expression
.replace(/__o\[(\d+)\]/g, function(match, index) {
index = +index;
return "__o[" + (operatorFunctions.length + index) + "]";
})
.replace(/__f\[(\d+)\]/g, function(match, index) {
index = +index;
return "__f[" + (fieldFunctions.length + index) + "]";
});
operatorFunctions.push.apply(operatorFunctions, expr.operators);
fieldFunctions.push.apply(fieldFunctions, expr.fields);
} else {
if (typeof field === FUNCTION) {
expr = "__f[" + fieldFunctions.length +"](d)";
fieldFunctions.push(field);
} else {
expr = kendo.expr(field);
}
if (typeof operator === FUNCTION) {
filter = "__o[" + operatorFunctions.length + "](" + expr + ", " + operators.quote(filter.value) + ")";
operatorFunctions.push(operator);
} else {
filter = operators[(operator || "eq").toLowerCase()](expr, filter.value, filter.ignoreCase !== undefined? filter.ignoreCase : true, expression.accentFoldingFiltering);
}
}
expressions.push(filter);
}
return { expression: "(" + expressions.join(logic[expression.logic]) + ")", fields: fieldFunctions, operators: operatorFunctions };
};
function normalizeSort(field, dir) {
if (field) {
var descriptor = typeof field === STRING ? { field: field, dir: dir } : field,
descriptors = isArray(descriptor) ? descriptor : (descriptor !== undefined ? [descriptor] : []);
return grep(descriptors, function(d) { return !!d.dir; });
}
}
var operatorMap = {
"==": "eq",
equals: "eq",
isequalto: "eq",
equalto: "eq",
equal: "eq",
"!=": "neq",
ne: "neq",
notequals: "neq",
isnotequalto: "neq",
notequalto: "neq",
notequal: "neq",
"<": "lt",
islessthan: "lt",
lessthan: "lt",
less: "lt",
"<=": "lte",
le: "lte",
islessthanorequalto: "lte",
lessthanequal: "lte",
">": "gt",
isgreaterthan: "gt",
greaterthan: "gt",
greater: "gt",
">=": "gte",
isgreaterthanorequalto: "gte",
greaterthanequal: "gte",
ge: "gte",
notsubstringof: "doesnotcontain",
isnull: "isnull",
isempty: "isempty",
isnotempty: "isnotempty"
};
function normalizeOperator(expression) {
var idx,
length,
filter,
operator,
filters = expression.filters;
if (filters) {
for (idx = 0, length = filters.length; idx < length; idx++) {
filter = filters[idx];
operator = filter.operator;
if (operator && typeof operator === STRING) {
filter.operator = operatorMap[operator.toLowerCase()] || operator;
}
normalizeOperator(filter);
}
}
}
function normalizeFilter(expression) {
if (expression && !isEmptyObject(expression)) {
if (isArray(expression) || !expression.filters) {
expression = {
logic: "and",
filters: isArray(expression) ? expression : [expression]
};
}
normalizeOperator(expression);
return expression;
}
}
Query.normalizeFilter = normalizeFilter;
function compareDescriptor(f1, f2) {
if (f1.logic || f2.logic) {
return false;
}
return f1.field === f2.field && f1.value === f2.value && f1.operator === f2.operator;
}
function normalizeDescriptor(filter) {
filter = filter || {};
if (isEmptyObject(filter)) {
return { logic: "and", filters: [] };
}
return normalizeFilter(filter);
}
function fieldComparer(a, b) {
if (b.logic || (a.field > b.field)) {
return 1;
} else if (a.field < b.field) {
return -1;
} else {
return 0;
}
}
function compareFilters(expr1, expr2) {
expr1 = normalizeDescriptor(expr1);
expr2 = normalizeDescriptor(expr2);
if (expr1.logic !== expr2.logic) {
return false;
}
var f1, f2;
var filters1 = (expr1.filters || []).slice();
var filters2 = (expr2.filters || []).slice();
if (filters1.length !== filters2.length) {
return false;
}
filters1 = filters1.sort(fieldComparer);
filters2 = filters2.sort(fieldComparer);
for (var idx = 0; idx < filters1.length; idx++) {
f1 = filters1[idx];
f2 = filters2[idx];
if (f1.logic && f2.logic) {
if (!compareFilters(f1, f2)) {
return false;
}
} else if (!compareDescriptor(f1, f2)) {
return false;
}
}
return true;
}
Query.compareFilters = compareFilters;
function normalizeAggregate(expressions) {
return isArray(expressions) ? expressions : [expressions];
}
function normalizeGroup(field, dir, compare, skipItemSorting) {
var descriptor = typeof field === STRING ? { field: field, dir: dir, compare: compare, skipItemSorting : skipItemSorting } : field,
descriptors = isArray(descriptor) ? descriptor : (descriptor !== undefined ? [descriptor] : []);
return map(descriptors, function(d) {
return {
field: d.field,
dir: d.dir || "asc",
aggregates: d.aggregates,
compare: d.compare,
skipItemSorting: d.skipItemSorting
};
});
}
function normalizeGroupWithoutCompare(field, dir, compare) {
var descriptors = normalizeGroup(field, dir, compare);
for (var i = 0; i < descriptors.length; i++) {
delete descriptors[i].compare;
}
return descriptors;
}
function anyGroupDescriptorHasCompare(groupDescriptors) {
var descriptors = isArray(groupDescriptors) ? groupDescriptors : [groupDescriptors];
for (var i = 0; i < descriptors.length; i++) {
if (descriptors[i] && isFunction(descriptors[i].compare)) {
return true;
}
}
return false;
}
Query.prototype = {
toArray: function () {
return this.data;
},
range: function(index, count) {
return new Query(this.data.slice(index, index + count));
},
skip: function (count) {
return new Query(this.data.slice(count));
},
take: function (count) {
return new Query(this.data.slice(0, count));
},
select: function (selector) {
return new Query(map(this.data, selector));
},
order: function(selector, dir, inPlace) {
var sort = { dir: dir };
if (selector) {
if (selector.compare) {
sort.compare = selector.compare;
} else {
sort.field = selector;
}
}
if (inPlace) {
return new Query(this.data.sort(Comparer.create(sort)));
}
return new Query(this.data.slice(0).sort(Comparer.create(sort)));
},
orderBy: function(selector, inPlace) {
return this.order(selector, "asc", inPlace);
},
orderByDescending: function(selector, inPlace) {
return this.order(selector, "desc", inPlace);
},
sort: function(field, dir, comparer, inPlace) {
var idx,
length,
descriptors = normalizeSort(field, dir),
comparers = [];
comparer = comparer || Comparer;
if (descriptors.length) {
for (idx = 0, length = descriptors.length; idx < length; idx++) {
comparers.push(comparer.create(descriptors[idx]));
}
return this.orderBy({ compare: comparer.combine(comparers) }, inPlace);
}
return this;
},
filter: function(expressions) {
var idx,
current,
length,
compiled,
predicate,
data = this.data,
fields,
operators,
result = [],
filter;
expressions = normalizeFilter(expressions);
if (!expressions || expressions.filters.length === 0) {
return this;
}
compiled = Query.filterExpr(expressions);
fields = compiled.fields;
operators = compiled.operators;
predicate = filter = new Function("d, __f, __o", "return " + compiled.expression);
if (fields.length || operators.length) {
filter = function(d) {
return predicate(d, fields, operators);
};
}
for (idx = 0, length = data.length; idx < length; idx++) {
current = data[idx];
if (filter(current)) {
result.push(current);
}
}
return new Query(result);
},
group: function(descriptors, allData) {
descriptors = normalizeGroup(descriptors || []);
allData = allData || this.data;
var that = this,
result = new Query(that.data),
descriptor;
if (descriptors.length > 0) {
descriptor = descriptors[0];
result = result.groupBy(descriptor).select(function(group) {
var data = new Query(allData).filter([ { field: group.field, operator: "eq", value: group.value, ignoreCase: false } ]);
return {
field: group.field,
value: group.value,
items: descriptors.length > 1 ? new Query(group.items).group(descriptors.slice(1), data.toArray()).toArray() : group.items,
hasSubgroups: descriptors.length > 1,
aggregates: data.aggregate(descriptor.aggregates)
};
});
}
return result;
},
groupBy: function(descriptor) {
var that = this;
if (isEmptyObject(descriptor) || !this.data.length) {
return new Query([]);
}
var field = descriptor.field,
sorted = descriptor.skipItemSorting ? this.data : this._sortForGrouping(field, descriptor.dir || "asc"),
accessor = kendo.accessor(field),
item,
groupValue = accessor.get(sorted[0], field),
group = {
field: field,
value: groupValue,
items: []
},
currentValue,
idx,
len,
result = [group];
for(idx = 0, len = sorted.length; idx < len; idx++) {
item = sorted[idx];
currentValue = accessor.get(item, field);
if(!groupValueComparer(groupValue, currentValue)) {
groupValue = currentValue;
group = {
field: field,
value: groupValue,
items: []
};
result.push(group);
}
group.items.push(item);
}
result = that._sortGroups(result, descriptor);
return new Query(result);
},
_sortForGrouping: function(field, dir) {
var idx, length,
data = this.data;
if (!stableSort) {
for (idx = 0, length = data.length; idx < length; idx++) {
data[idx].__position = idx;
}
data = new Query(data).sort(field, dir, StableComparer).toArray();
for (idx = 0, length = data.length; idx < length; idx++) {
delete data[idx].__position;
}
return data;
}
return this.sort(field, dir).toArray();
},
_sortGroups: function(groups, descriptor) {
var result = groups;
if (descriptor && isFunction(descriptor.compare)) {
result = new Query(result).order({ compare: descriptor.compare }, descriptor.dir || ASCENDING).toArray();
}
return result;
},
aggregate: function (aggregates) {
var idx,
len,
result = {},
state = {};
if (aggregates && aggregates.length) {
for(idx = 0, len = this.data.length; idx < len; idx++) {
calculateAggregate(result, aggregates, this.data[idx], idx, len, state);
}
}
return result;
}
};
function groupValueComparer(a, b) {
if (a && a.getTime && b && b.getTime) {
return a.getTime() === b.getTime();
}
return a === b;
}
function calculateAggregate(accumulator, aggregates, item, index, length, state) {
aggregates = aggregates || [];
var idx,
aggr,
functionName,
len = aggregates.length;
for (idx = 0; idx < len; idx++) {
aggr = aggregates[idx];
functionName = aggr.aggregate;
var field = aggr.field;
accumulator[field] = accumulator[field] || {};
state[field] = state[field] || {};
state[field][functionName] = state[field][functionName] || {};
accumulator[field][functionName] = functions[functionName.toLowerCase()](accumulator[field][functionName], item, kendo.accessor(field), index, length, state[field][functionName]);
}
}
var functions = {
sum: function(accumulator, item, accessor) {
var value = accessor.get(item);
if (!isNumber(accumulator)) {
accumulator = value;
} else if (isNumber(value)) {
accumulator += value;
}
return accumulator;
},
count: function(accumulator) {
return (accumulator || 0) + 1;
},
average: function(accumulator, item, accessor, index, length, state) {
var value = accessor.get(item);
if (state.count === undefined) {
state.count = 0;
}
if (!isNumber(accumulator)) {
accumulator = value;
} else if (isNumber(value)) {
accumulator += value;
}
if (isNumber(value)) {
state.count++;
}
if(index == length - 1 && isNumber(accumulator)) {
accumulator = accumulator / state.count;
}
return accumulator;
},
max: function(accumulator, item, accessor) {
var value = accessor.get(item);
if (!isNumber(accumulator) && !isDate(accumulator)) {
accumulator = value;
}
if(accumulator < value && (isNumber(value) || isDate(value))) {
accumulator = value;
}
return accumulator;
},
min: function(accumulator, item, accessor) {
var value = accessor.get(item);
if (!isNumber(accumulator) && !isDate(accumulator)) {
accumulator = value;
}
if(accumulator > value && (isNumber(value) || isDate(value))) {
accumulator = value;
}
return accumulator;
}
};
function isNumber(val) {
return typeof val === "number" && !isNaN(val);
}
function isDate(val) {
return val && val.getTime;
}
function toJSON(array) {
var idx, length = array.length, result = new Array(length);
for (idx = 0; idx < length; idx++) {
result[idx] = array[idx].toJSON();
}
return result;
}
Query.normalizeGroup = normalizeGroup;
Query.normalizeSort = normalizeSort;
Query.process = function(data, options, inPlace) {
options = options || {};
var group = options.group;
var customGroupSort = anyGroupDescriptorHasCompare(normalizeGroup(group || []));
var query = new Query(data),
groupDescriptorsWithoutCompare = normalizeGroupWithoutCompare(group || []),
normalizedSort = normalizeSort(options.sort || []),
sort = customGroupSort ? normalizedSort : groupDescriptorsWithoutCompare.concat(normalizedSort),
groupDescriptorsWithoutSort,
total,
filterCallback = options.filterCallback,
filter = options.filter,
skip = options.skip,
take = options.take;
if (sort && inPlace) {
query = query.sort(sort, undefined, undefined, inPlace);
}
if (filter) {
query = query.filter(filter);
if (filterCallback) {
query = filterCallback(query);
}
total = query.toArray().length;
}
if (sort && !inPlace) {
query = query.sort(sort);
if (group) {
data = query.toArray();
}
}
if (customGroupSort) {
query = query.group(group, data);
if (skip !== undefined && take !== undefined) {
query = new Query(flatGroups(query.toArray())).range(skip, take);
groupDescriptorsWithoutSort = map(groupDescriptorsWithoutCompare, function(groupDescriptor) {
return extend({}, groupDescriptor, {
skipItemSorting: true
});
});
query = query.group(groupDescriptorsWithoutSort, data);
}
} else {
if (skip !== undefined && take !== undefined) {
query = query.range(skip, take);
}
if (group) {
query = query.group(group, data);
}
}
return {
total: total,
data: query.toArray()
};
};
var LocalTransport = Class.extend({
init: function(options) {
this.data = options.data;
},
read: function(options) {
options.success(this.data);
},
update: function(options) {
options.success(options.data);
},
create: function(options) {
options.success(options.data);
},
destroy: function(options) {
options.success(options.data);
}
});
var RemoteTransport = Class.extend( {
init: function(options) {
var that = this, parameterMap;
options = that.options = extend({}, that.options, options);
each(crud, function(index, type) {
if (typeof options[type] === STRING) {
options[type] = {
url: options[type]
};
}
});
that.cache = options.cache? Cache.create(options.cache) : {
find: noop,
add: noop
};
parameterMap = options.parameterMap;
if (options.submit) {
that.submit = options.submit;
}
if (isFunction(options.push)) {
that.push = options.push;
}
if (!that.push) {
that.push = identity;
}
that.parameterMap = isFunction(parameterMap) ? parameterMap : function(options) {
var result = {};
each(options, function(option, value) {
if (option in parameterMap) {
option = parameterMap[option];
if (isPlainObject(option)) {
value = option.value(value);
option = option.key;
}
}
result[option] = value;
});
return result;
};
},
options: {
parameterMap: identity
},
create: function(options) {
return ajax(this.setup(options, CREATE));
},
read: function(options) {
var that = this,
success,
error,
result,
cache = that.cache;
options = that.setup(options, READ);
success = options.success || noop;
error = options.error || noop;
result = cache.find(options.data);
if(result !== undefined) {
success(result);
} else {
options.success = function(result) {
cache.add(options.data, result);
success(result);
};
$.ajax(options);
}
},
update: function(options) {
return ajax(this.setup(options, UPDATE));
},
destroy: function(options) {
return ajax(this.setup(options, DESTROY));
},
setup: function(options, type) {
options = options || {};
var that = this,
parameters,
operation = that.options[type],
data = isFunction(operation.data) ? operation.data(options.data) : operation.data;
options = extend(true, {}, operation, options);
parameters = extend(true, {}, data, options.data);
options.data = that.parameterMap(parameters, type);
if (isFunction(options.url)) {
options.url = options.url(parameters);
}
return options;
}
});
var Cache = Class.extend({
init: function() {
this._store = {};
},
add: function(key, data) {
if(key !== undefined) {
this._store[stringify(key)] = data;
}
},
find: function(key) {
return this._store[stringify(key)];
},
clear: function() {
this._store = {};
},
remove: function(key) {
delete this._store[stringify(key)];
}
});
Cache.create = function(options) {
var store = {
"inmemory": function() { return new Cache(); }
};
if (isPlainObject(options) && isFunction(options.find)) {
return options;
}
if (options === true) {
return new Cache();
}
return store[options]();
};
function serializeRecords(data, getters, modelInstance, originalFieldNames, fieldNames) {
var record,
getter,
originalName,
idx,
setters = {},
length;
for (idx = 0, length = data.length; idx < length; idx++) {
record = data[idx];
for (getter in getters) {
originalName = fieldNames[getter];
if (originalName && originalName !== getter) {
if (!setters[originalName]) {
setters[originalName] = kendo.setter(originalName);
}
setters[originalName](record, getters[getter](record));
delete record[getter];
}
}
}
}
function convertRecords(data, getters, modelInstance, originalFieldNames, fieldNames) {
var record,
getter,
originalName,
idx,
length;
for (idx = 0, length = data.length; idx < length; idx++) {
record = data[idx];
for (getter in getters) {
record[getter] = modelInstance._parse(getter, getters[getter](record));
originalName = fieldNames[getter];
if (originalName && originalName !== getter) {
delete record[originalName];
}
}
}
}
function convertGroup(data, getters, modelInstance, originalFieldNames, fieldNames) {
var record,
idx,
fieldName,
length;
for (idx = 0, length = data.length; idx < length; idx++) {
record = data[idx];
fieldName = originalFieldNames[record.field];
if (fieldName && fieldName != record.field) {
record.field = fieldName;
}
record.value = modelInstance._parse(record.field, record.value);
if (record.hasSubgroups) {
convertGroup(record.items, getters, modelInstance, originalFieldNames, fieldNames);
} else {
convertRecords(record.items, getters, modelInstance, originalFieldNames, fieldNames);
}
}
}
function wrapDataAccess(originalFunction, model, converter, getters, originalFieldNames, fieldNames) {
return function(data) {
data = originalFunction(data);
return wrapDataAccessBase(model, converter, getters, originalFieldNames, fieldNames)(data);
};
}
function wrapDataAccessBase(model, converter, getters, originalFieldNames, fieldNames) {
return function(data) {
if (data && !isEmptyObject(getters)) {
if (toString.call(data) !== "[object Array]" && !(data instanceof ObservableArray)) {
data = [data];
}
converter(data, getters, new model(), originalFieldNames, fieldNames);
}
return data || [];
};
}
var DataReader = Class.extend({
init: function(schema) {
var that = this, member, get, model, base;
schema = schema || {};
for (member in schema) {
get = schema[member];
that[member] = typeof get === STRING ? getter(get) : get;
}
base = schema.modelBase || Model;
if (isPlainObject(that.model)) {
that.model = model = base.define(that.model);
}
var dataFunction = proxy(that.data, that);
that._dataAccessFunction = dataFunction;
if (that.model) {
var groupsFunction = proxy(that.groups, that),
serializeFunction = proxy(that.serialize, that),
originalFieldNames = {},
getters = {},
serializeGetters = {},
fieldNames = {},
shouldSerialize = false,
fieldName,
name;
model = that.model;
if (model.fields) {
each(model.fields, function(field, value) {
var fromName;
fieldName = field;
if (isPlainObject(value) && value.field) {
fieldName = value.field;
} else if (typeof value === STRING) {
fieldName = value;
}
if (isPlainObject(value) && value.from) {
fromName = value.from;
}
shouldSerialize = shouldSerialize || (fromName && fromName !== field) || fieldName !== field;
name = fromName || fieldName;
getters[field] = name.indexOf(".") !== -1 ? getter(name, true) : getter(name);
serializeGetters[field] = getter(field);
originalFieldNames[fromName || fieldName] = field;
fieldNames[field] = fromName || fieldName;
});
if (!schema.serialize && shouldSerialize) {
that.serialize = wrapDataAccess(serializeFunction, model, serializeRecords, serializeGetters, originalFieldNames, fieldNames);
}
}
that._dataAccessFunction = dataFunction;
that._wrapDataAccessBase = wrapDataAccessBase(model, convertRecords, getters, originalFieldNames, fieldNames);
that.data = wrapDataAccess(dataFunction, model, convertRecords, getters, originalFieldNames, fieldNames);
that.groups = wrapDataAccess(groupsFunction, model, convertGroup, getters, originalFieldNames, fieldNames);
}
},
errors: function(data) {
return data ? data.errors : null;
},
parse: identity,
data: identity,
total: function(data) {
return data.length;
},
groups: identity,
aggregates: function() {
return {};
},
serialize: function(data) {
return data;
}
});
function fillLastGroup(originalGroup, newGroup) {
var currOriginal;
var currentNew;
if (newGroup.items && newGroup.items.length) {
for (var i = 0; i < newGroup.items.length; i++) {
currOriginal = originalGroup.items[i];
currentNew = newGroup.items[i];
if (currOriginal && currentNew) {
if (currOriginal.hasSubgroups) {
fillLastGroup(currOriginal, currentNew);
} else if (currOriginal.field && currOriginal.value == currentNew.value) {
currOriginal.items.push.apply(currOriginal.items, currentNew.items);
} else {
originalGroup.items.push.apply(originalGroup.items, [currentNew]);
}
} else if (currentNew) {
originalGroup.items.push.apply(originalGroup.items, [currentNew]);
}
}
}
}
function mergeGroups(target, dest, skip, take) {
var group,
idx = 0,
items;
while (dest.length && take) {
group = dest[idx];
items = group.items;
var length = items.length;
if (target && target.field === group.field && target.value === group.value) {
if (target.hasSubgroups && target.items.length) {
mergeGroups(target.items[target.items.length - 1], group.items, skip, take);
} else {
items = items.slice(skip, skip + take);
target.items = target.items.concat(items);
}
dest.splice(idx--, 1);
} else if (group.hasSubgroups && items.length) {
mergeGroups(group, items, skip, take);
if (!group.items.length) {
dest.splice(idx--, 1);
}
} else {
items = items.slice(skip, skip + take);
group.items = items;
if (!group.items.length) {
dest.splice(idx--, 1);
}
}
if (items.length === 0) {
skip -= length;
} else {
skip = 0;
take -= items.length;
}
if (++idx >= dest.length) {
break;
}
}
if (idx < dest.length) {
dest.splice(idx, dest.length - idx);
}
}
function flatGroups(groups, indexFunction) {
var result = [];
var groupsLength = (groups || []).length;
var group;
var items;
var indexFn = isFunction(indexFunction) ? indexFunction : function(array, index) {
return array[index];
};
for (var groupIndex = 0; groupIndex < groupsLength; groupIndex++) {
group = indexFn(groups, groupIndex);
if (group.hasSubgroups) {
result = result.concat(flatGroups(group.items));
} else {
items = group.items;
for (var itemIndex = 0; itemIndex < items.length; itemIndex++) {
result.push(indexFn(items, itemIndex));
}
}
}
return result;
}
function flattenGroups(data) {
var idx,
result = [],
length,
items,
itemIndex;
for (idx = 0, length = data.length; idx < length; idx++) {
var group = data.at(idx);
if (group.hasSubgroups) {
result = result.concat(flattenGroups(group.items));
} else {
items = group.items;
for (itemIndex = 0; itemIndex < items.length; itemIndex++) {
result.push(items.at(itemIndex));
}
}
}
return result;
}
function wrapGroupItems(data, model) {
var idx, length, group;
if (model) {
for (idx = 0, length = data.length; idx < length; idx++) {
group = data.at(idx);
if (group.hasSubgroups) {
wrapGroupItems(group.items, model);
} else {
group.items = new LazyObservableArray(group.items, model, group.items._events);
}
}
}
}
function eachGroupItems(data, func) {
for (var idx = 0; idx < data.length; idx++) {
if (data[idx].hasSubgroups) {
if (eachGroupItems(data[idx].items, func)) {
return true;
}
} else if (func(data[idx].items, data[idx])) {
return true;
}
}
}
function replaceInRanges(ranges, data, item, observable) {
for (var idx = 0; idx < ranges.length; idx++) {
if (ranges[idx].data === data) {
break;
}
if (replaceInRange(ranges[idx].data, item, observable)) {
break;
}
}
}
function replaceInRange(items, item, observable) {
for (var idx = 0, length = items.length; idx < length; idx++) {
if (items[idx] && items[idx].hasSubgroups) {
return replaceInRange(items[idx].items, item, observable);
} else if (items[idx] === item || items[idx] === observable) {
items[idx] = observable;
return true;
}
}
}
function replaceWithObservable(view, data, ranges, type, serverGrouping) {
for (var viewIndex = 0, length = view.length; viewIndex < length; viewIndex++) {
var item = view[viewIndex];
if (!item || item instanceof type) {
continue;
}
if (item.hasSubgroups !== undefined && !serverGrouping) {
replaceWithObservable(item.items, data, ranges, type, serverGrouping);
} else {
for (var idx = 0; idx < data.length; idx++) {
if (data[idx] === item) {
view[viewIndex] = data.at(idx);
replaceInRanges(ranges, data, item, view[viewIndex]);
break;
}
}
}
}
}
function removeModel(data, model) {
var length = data.length;
var dataItem;
var idx;
for (idx = 0; idx < length; idx++) {
dataItem = data[idx];
if (dataItem.uid && dataItem.uid == model.uid) {
data.splice(idx, 1);
return dataItem;
}
}
}
function indexOfPristineModel(data, model) {
if (model) {
return indexOf(data, function(item) {
return (item.uid && item.uid == model.uid) || (item[model.idField] === model.id && model.id !== model._defaultId);
});
}
return -1;
}
function indexOfModel(data, model) {
if (model) {
return indexOf(data, function(item) {
return item.uid == model.uid;
});
}
return -1;
}
function indexOf(data, comparer) {
var idx, length;
for (idx = 0, length = data.length; idx < length; idx++) {
if (comparer(data[idx])) {
return idx;
}
}
return -1;
}
function fieldNameFromModel(fields, name) {
if (fields && !isEmptyObject(fields)) {
var descriptor = fields[name];
var fieldName;
if (isPlainObject(descriptor)) {
fieldName = descriptor.from || descriptor.field || name;
} else {
fieldName = fields[name] || name;
}
if (isFunction(fieldName)) {
return name;
}
return fieldName;
}
return name;
}
function convertFilterDescriptorsField(descriptor, model) {
var idx,
length,
target = {};
for (var field in descriptor) {
if (field !== "filters") {
target[field] = descriptor[field];
}
}
if (descriptor.filters) {
target.filters = [];
for (idx = 0, length = descriptor.filters.length; idx < length; idx++) {
target.filters[idx] = convertFilterDescriptorsField(descriptor.filters[idx], model);
}
} else {
target.field = fieldNameFromModel(model.fields, target.field);
}
return target;
}
function convertDescriptorsField(descriptors, model) {
var idx,
length,
result = [],
target,
descriptor;
for (idx = 0, length = descriptors.length; idx < length; idx ++) {
target = {};
descriptor = descriptors[idx];
for (var field in descriptor) {
target[field] = descriptor[field];
}
target.field = fieldNameFromModel(model.fields, target.field);
if (target.aggregates && isArray(target.aggregates)) {
target.aggregates = convertDescriptorsField(target.aggregates, model);
}
result.push(target);
}
return result;
}
var DataSource = Observable.extend({
init: function(options) {
var that = this, model, data;
if (options) {
data = options.data;
}
options = that.options = extend({}, that.options, options);
that._map = {};
that._prefetch = {};
that._data = [];
that._pristineData = [];
that._ranges = [];
that._view = [];
that._pristineTotal = 0;
that._destroyed = [];
that._pageSize = options.pageSize;
that._page = options.page || (options.pageSize ? 1 : undefined);
that._sort = normalizeSort(options.sort);
that._filter = normalizeFilter(options.filter);
that._group = normalizeGroup(options.group);
that._aggregate = options.aggregate;
that._total = options.total;
that._shouldDetachObservableParents = true;
Observable.fn.init.call(that);
that.transport = Transport.create(options, data, that);
if (isFunction(that.transport.push)) {
that.transport.push({
pushCreate: proxy(that._pushCreate, that),
pushUpdate: proxy(that._pushUpdate, that),
pushDestroy: proxy(that._pushDestroy, that)
});
}
if (options.offlineStorage != null) {
if (typeof options.offlineStorage == "string") {
var key = options.offlineStorage;
that._storage = {
getItem: function() {
return JSON.parse(localStorage.getItem(key));
},
setItem: function(item) {
localStorage.setItem(key, stringify(that.reader.serialize(item)));
}
};
} else {
that._storage = options.offlineStorage;
}
}
that.reader = new kendo.data.readers[options.schema.type || "json" ](options.schema);
model = that.reader.model || {};
that._detachObservableParents();
that._data = that._observe(that._data);
that._online = true;
that.bind(["push", ERROR, CHANGE, REQUESTSTART, SYNC, REQUESTEND, PROGRESS], options);
},
options: {
data: null,
schema: {
modelBase: Model
},
offlineStorage: null,
serverSorting: false,
serverPaging: false,
serverFiltering: false,
serverGrouping: false,
serverAggregates: false,
batch: false,
inPlaceSort: false
},
clone: function() {
return this;
},
online: function(value) {
if (value !== undefined) {
if (this._online != value) {
this._online = value;
if (value) {
return this.sync();
}
}
return $.Deferred().resolve().promise();
} else {
return this._online;
}
},
offlineData: function(state) {
if (this.options.offlineStorage == null) {
return null;
}
if (state !== undefined) {
return this._storage.setItem(state);
}
return this._storage.getItem() || [];
},
_isServerGrouped: function() {
var group = this.group() || [];
return this.options.serverGrouping && group.length;
},
_pushCreate: function(result) {
this._push(result, "pushCreate");
},
_pushUpdate: function(result) {
this._push(result, "pushUpdate");
},
_pushDestroy: function(result) {
this._push(result, "pushDestroy");
},
_push: function(result, operation) {
var data = this._readData(result);
if (!data) {
data = result;
}
this[operation](data);
},
_flatData: function(data, skip) {
if (data) {
if (this._isServerGrouped()) {
return flattenGroups(data);
}
if (!skip) {
for (var idx = 0; idx < data.length; idx++) {
data.at(idx);
}
}
}
return data;
},
parent: noop,
get: function(id) {
var idx, length, data = this._flatData(this._data, this.options.useRanges);
for (idx = 0, length = data.length; idx < length; idx++) {
if (data[idx].id == id) {
return data[idx];
}
}
},
getByUid: function(id) {
return this._getByUid(id, this._data);
},
_getByUid: function(id, dataItems) {
var idx, length, data = this._flatData(dataItems, this.options.useRanges);
if (!data) {
return;
}
for (idx = 0, length = data.length; idx < length; idx++) {
if (data[idx].uid == id) {
return data[idx];
}
}
},
indexOf: function(model) {
return indexOfModel(this._data, model);
},
at: function(index) {
return this._data.at(index);
},
data: function(value) {
var that = this;
if (value !== undefined) {
that._detachObservableParents();
that._data = this._observe(value);
that._pristineData = value.slice(0);
that._storeData();
that._ranges = [];
that.trigger("reset");
that._addRange(that._data);
that._total = that._data.length;
that._pristineTotal = that._total;
that._process(that._data);
} else {
if (that._data) {
for (var idx = 0; idx < that._data.length; idx++) {
that._data.at(idx);
}
}
return that._data;
}
},
view: function(value) {
if (value === undefined) {
return this._view;
} else {
this._view = this._observeView(value);
}
},
_observeView: function(data) {
var that = this;
replaceWithObservable(data, that._data, that._ranges, that.reader.model || ObservableObject, that._isServerGrouped());
var view = new LazyObservableArray(data, that.reader.model);
view.parent = function() { return that.parent(); };
return view;
},
flatView: function() {
var groups = this.group() || [];
if (groups.length) {
return flattenGroups(this._view);
} else {
return this._view;
}
},
add: function(model) {
return this.insert(this._data.length, model);
},
_createNewModel: function(model) {
if (this.reader.model) {
return new this.reader.model(model);
}
if (model instanceof ObservableObject) {
return model;
}
return new ObservableObject(model);
},
insert: function(index, model) {
if (!model) {
model = index;
index = 0;
}
if (!(model instanceof Model)) {
model = this._createNewModel(model);
}
if (this._isServerGrouped()) {
this._data.splice(index, 0, this._wrapInEmptyGroup(model));
} else {
this._data.splice(index, 0, model);
}
this._insertModelInRange(index, model);
return model;
},
pushInsert: function(index, items) {
var that = this;
var rangeSpan = that._getCurrentRangeSpan();
if (!items) {
items = index;
index = 0;
}
if (!isArray(items)) {
items = [items];
}
var pushed = [];
var autoSync = this.options.autoSync;
this.options.autoSync = false;
try {
for (var idx = 0; idx < items.length; idx ++) {
var item = items[idx];
var result = this.insert(index, item);
pushed.push(result);
var pristine = result.toJSON();
if (this._isServerGrouped()) {
pristine = this._wrapInEmptyGroup(pristine);
}
this._pristineData.push(pristine);
if (rangeSpan && rangeSpan.length) {
$(rangeSpan).last()[0].pristineData.push(pristine);
}
index++;
}
} finally {
this.options.autoSync = autoSync;
}
if (pushed.length) {
this.trigger("push", {
type: "create",
items: pushed
});
}
},
pushCreate: function(items) {
this.pushInsert(this._data.length, items);
},
pushUpdate: function(items) {
if (!isArray(items)) {
items = [items];
}
var pushed = [];
for (var idx = 0; idx < items.length; idx ++) {
var item = items[idx];
var model = this._createNewModel(item);
var target = this.get(model.id);
if (target) {
pushed.push(target);
target.accept(item);
target.trigger(CHANGE);
this._updatePristineForModel(target, item);
} else {
this.pushCreate(item);
}
}
if (pushed.length) {
this.trigger("push", {
type: "update",
items: pushed
});
}
},
pushDestroy: function(items) {
var pushed = this._removeItems(items);
if (pushed.length) {
this.trigger("push", {
type: "destroy",
items: pushed
});
}
},
_removeItems: function(items, removePristine) {
if (!isArray(items)) {
items = [items];
}
var shouldRemovePristine = typeof removePristine !== "undefined" ? removePristine : true;
var destroyed = [];
var autoSync = this.options.autoSync;
this.options.autoSync = false;
try {
for (var idx = 0; idx < items.length; idx ++) {
var item = items[idx];
var model = this._createNewModel(item);
var found = false;
this._eachItem(this._data, function(items){
for (var idx = 0; idx < items.length; idx++) {
var item = items.at(idx);
if (item.id === model.id) {
destroyed.push(item);
items.splice(idx, 1);
found = true;
break;
}
}
});
if (found && shouldRemovePristine) {
this._removePristineForModel(model);
this._destroyed.pop();
}
}
} finally {
this.options.autoSync = autoSync;
}
return destroyed;
},
remove: function(model) {
var result,
that = this,
hasGroups = that._isServerGrouped();
this._eachItem(that._data, function(items) {
result = removeModel(items, model);
if (result && hasGroups) {
if (!result.isNew || !result.isNew()) {
that._destroyed.push(result);
}
return true;
}
});
this._removeModelFromRanges(model);
return model;
},
destroyed: function() {
return this._destroyed;
},
created: function() {
var idx,
length,
result = [],
data = this._flatData(this._data, this.options.useRanges);
for (idx = 0, length = data.length; idx < length; idx++) {
if (data[idx].isNew && data[idx].isNew()) {
result.push(data[idx]);
}
}
return result;
},
updated: function() {
var idx,
length,
result = [],
data = this._flatData(this._data, this.options.useRanges);
for (idx = 0, length = data.length; idx < length; idx++) {
if ((data[idx].isNew && !data[idx].isNew()) && data[idx].dirty) {
result.push(data[idx]);
}
}
return result;
},
sync: function() {
var that = this,
created = [],
updated = [],
destroyed = that._destroyed;
var promise = $.Deferred().resolve().promise();
if (that.online()) {
if (!that.reader.model) {
return promise;
}
created = that.created();
updated = that.updated();
var promises = [];
if (that.options.batch && that.transport.submit) {
promises = that._sendSubmit(created, updated, destroyed);
} else {
promises.push.apply(promises, that._send("create", created));
promises.push.apply(promises, that._send("update", updated));
promises.push.apply(promises, that._send("destroy", destroyed));
}
promise = $.when
.apply(null, promises)
.then(function() {
var idx, length;
for (idx = 0, length = arguments.length; idx < length; idx++){
if (arguments[idx]) {
that._accept(arguments[idx]);
}
}
that._storeData(true);
that._syncEnd();
that._change({ action: "sync" });
that.trigger(SYNC);
});
} else {
that._storeData(true);
that._syncEnd();
that._change({ action: "sync" });
}
return promise;
},
_syncEnd: noop,
cancelChanges: function(model) {
var that = this;
if (model instanceof kendo.data.Model) {
that._cancelModel(model);
} else {
that._destroyed = [];
that._detachObservableParents();
that._data = that._observe(that._pristineData);
if (that.options.serverPaging) {
that._total = that._pristineTotal;
}
that._ranges = [];
that._addRange(that._data, 0);
that._changesCanceled();
that._change();
that._markOfflineUpdatesAsDirty();
}
},
_changesCanceled: noop,
_markOfflineUpdatesAsDirty: function() {
var that = this;
if (that.options.offlineStorage != null) {
that._eachItem(that._data, function(items) {
for (var idx = 0; idx < items.length; idx++) {
var item = items.at(idx);
if (item.__state__ == "update" || item.__state__ == "create") {
item.dirty = true;
}
}
});
}
},
hasChanges: function() {
var idx,
length,
data = this._flatData(this._data, this.options.useRanges);
if (this._destroyed.length) {
return true;
}
for (idx = 0, length = data.length; idx < length; idx++) {
if ((data[idx].isNew && data[idx].isNew()) || data[idx].dirty) {
return true;
}
}
return false;
},
_accept: function(result) {
var that = this,
models = result.models,
response = result.response,
idx = 0,
serverGroup = that._isServerGrouped(),
pristine = that._pristineData,
type = result.type,
length;
that.trigger(REQUESTEND, { response: response, type: type });
if (response && !isEmptyObject(response)) {
response = that.reader.parse(response);
if (that._handleCustomErrors(response)) {
return;
}
response = that.reader.data(response);
if (!isArray(response)) {
response = [response];
}
} else {
response = $.map(models, function(model) { return model.toJSON(); } );
}
if (type === "destroy") {
that._destroyed = [];
}
for (idx = 0, length = models.length; idx < length; idx++) {
if (type !== "destroy") {
models[idx].accept(response[idx]);
if (type === "create") {
pristine.push(serverGroup ? that._wrapInEmptyGroup(models[idx].toJSON()) : response[idx]);
} else if (type === "update") {
that._updatePristineForModel(models[idx], response[idx]);
}
} else {
that._removePristineForModel(models[idx]);
}
}
},
_updatePristineForModel: function(model, values) {
this._executeOnPristineForModel(model, function(index, items) {
kendo.deepExtend(items[index], values);
});
},
_executeOnPristineForModel: function(model, callback) {
this._eachPristineItem(
function(items) {
var index = indexOfPristineModel(items, model);
if (index > -1) {
callback(index, items);
return true;
}
});
},
_removePristineForModel: function(model) {
this._executeOnPristineForModel(model, function(index, items) {
items.splice(index, 1);
});
},
_readData: function(data) {
var read = !this._isServerGrouped() ? this.reader.data : this.reader.groups;
return read.call(this.reader, data);
},
_eachPristineItem: function(callback) {
var that = this;
var options = that.options;
var rangeSpan = that._getCurrentRangeSpan();
that._eachItem(that._pristineData, callback);
if (options.serverPaging && options.useRanges) {
each(rangeSpan, function(i, range) {
that._eachItem(range.pristineData, callback);
});
}
},
_eachItem: function(data, callback) {
if (data && data.length) {
if (this._isServerGrouped()) {
eachGroupItems(data, callback);
} else {
callback(data);
}
}
},
_pristineForModel: function(model) {
var pristine,
idx,
callback = function(items) {
idx = indexOfPristineModel(items, model);
if (idx > -1) {
pristine = items[idx];
return true;
}
};
this._eachPristineItem(callback);
return pristine;
},
_cancelModel: function(model) {
var that = this;
var pristine = this._pristineForModel(model);
this._eachItem(this._data, function(items) {
var idx = indexOfModel(items, model);
if (idx >= 0) {
if (pristine && (!model.isNew() || pristine.__state__)) {
items[idx].accept(pristine);
if (pristine.__state__ == "update") {
items[idx].dirty = true;
}
} else {
that._modelCanceled(model);
items.splice(idx, 1);
that._removeModelFromRanges(model);
}
}
});
},
_modelCanceled: noop,
_submit: function(promises, data) {
var that = this;
that.trigger(REQUESTSTART, { type: "submit" });
that.trigger(PROGRESS);
that.transport.submit(extend({
success: function(response, type) {
var promise = $.grep(promises, function(x) {
return x.type == type;
})[0];
if (promise) {
promise.resolve({
response: response,
models: promise.models,
type: type
});
}
},
error: function(response, status, error) {
for (var idx = 0; idx < promises.length; idx++) {
promises[idx].reject(response);
}
that.error(response, status, error);
}
}, data));
},
_sendSubmit: function(created, updated, destroyed) {
var that = this,
promises = [];
if (that.options.batch) {
if (created.length) {
promises.push($.Deferred(function(deferred) {
deferred.type = "create";
deferred.models = created;
}));
}
if (updated.length) {
promises.push($.Deferred(function(deferred) {
deferred.type = "update";
deferred.models = updated;
}));
}
if (destroyed.length) {
promises.push($.Deferred(function(deferred) {
deferred.type = "destroy";
deferred.models = destroyed;
}));
}
that._submit(promises, {
data: {
created: that.reader.serialize(toJSON(created)),
updated: that.reader.serialize(toJSON(updated)),
destroyed: that.reader.serialize(toJSON(destroyed))
}
});
}
return promises;
},
_promise: function(data, models, type) {
var that = this;
return $.Deferred(function(deferred) {
that.trigger(REQUESTSTART, { type: type });
that.trigger(PROGRESS);
that.transport[type].call(that.transport, extend({
success: function(response) {
deferred.resolve({
response: response,
models: models,
type: type
});
},
error: function(response, status, error) {
deferred.reject(response);
that.error(response, status, error);
}
}, data));
}).promise();
},
_send: function(method, data) {
var that = this,
idx,
length,
promises = [],
converted = that.reader.serialize(toJSON(data));
if (that.options.batch) {
if (data.length) {
promises.push(that._promise( { data: { models: converted } }, data , method));
}
} else {
for (idx = 0, length = data.length; idx < length; idx++) {
promises.push(that._promise( { data: converted[idx] }, [ data[idx] ], method));
}
}
return promises;
},
read: function(data) {
var that = this, params = that._params(data);
var deferred = $.Deferred();
that._queueRequest(params, function() {
var isPrevented = that.trigger(REQUESTSTART, { type: "read" });
if (!isPrevented) {
that.trigger(PROGRESS);
that._ranges = [];
that.trigger("reset");
if (that.online()) {
that.transport.read({
data: params,
success: function(data) {
that._ranges = [];
that.success(data, params);
deferred.resolve();
},
error: function() {
var args = slice.call(arguments);
that.error.apply(that, args);
deferred.reject.apply(deferred, args);
}
});
} else if (that.options.offlineStorage != null){
that.success(that.offlineData(), params);
deferred.resolve();
}
} else {
that._dequeueRequest();
deferred.resolve(isPrevented);
}
});
return deferred.promise();
},
_readAggregates: function(data) {
return this.reader.aggregates(data);
},
success: function(data) {
var that = this,
options = that.options,
items,
replaceSubset;
that.trigger(REQUESTEND, { response: data, type: "read" });
if (that.online()) {
data = that.reader.parse(data);
if (that._handleCustomErrors(data)) {
that._dequeueRequest();
return;
}
that._total = that.reader.total(data);
if (that._pageSize > that._total) {
that._pageSize = that._total;
if (that.options.pageSize && that.options.pageSize > that._pageSize) {
that._pageSize = that.options.pageSize;
}
}
if (that._aggregate && options.serverAggregates) {
that._aggregateResult = that._readAggregates(data);
}
data = that._readData(data);
that._destroyed = [];
} else {
data = that._readData(data);
items = [];
var itemIds = {};
var model = that.reader.model;
var idField = model ? model.idField : "id";
var idx;
for (idx = 0; idx < this._destroyed.length; idx++) {
var id = this._destroyed[idx][idField];
itemIds[id] = id;
}
for (idx = 0; idx < data.length; idx++) {
var item = data[idx];
var state = item.__state__;
if (state == "destroy") {
if (!itemIds[item[idField]]) {
this._destroyed.push(this._createNewModel(item));
}
} else {
items.push(item);
}
}
data = items;
that._total = data.length;
}
that._pristineTotal = that._total;
replaceSubset = that._skip && that._data.length && that._skip < that._data.length;
if (that.options.endless) {
if (replaceSubset) {
that._pristineData.splice(that._skip, that._pristineData.length);
}
items = data.slice(0);
for (var j = 0; j < items.length; j++) {
that._pristineData.push(items[j]);
}
} else {
that._pristineData = data.slice(0);
}
that._detachObservableParents();
if (that.options.endless) {
that._data.unbind(CHANGE, that._changeHandler);
if (that._isServerGrouped() && that._data[that._data.length - 1].value === data[0].value) {
fillLastGroup(that._data[that._data.length - 1], data[0]);
data.shift();
}
data = that._observe(data);
if (replaceSubset) {
that._data.splice(that._skip, that._data.length);
}
for (var i = 0; i < data.length; i++) {
that._data.push(data[i]);
}
that._data.bind(CHANGE, that._changeHandler);
} else {
that._data = that._observe(data);
}
that._markOfflineUpdatesAsDirty();
that._storeData();
that._addRange(that._data);
that._process(that._data);
that._dequeueRequest();
},
_detachObservableParents: function() {
if (this._data && this._shouldDetachObservableParents) {
for (var idx = 0; idx < this._data.length; idx++) {
if (this._data[idx].parent) {
this._data[idx].parent = noop;
}
}
}
},
_storeData: function(updatePristine) {
var serverGrouping = this._isServerGrouped();
var model = this.reader.model;
function items(data) {
var state = [];
for (var idx = 0; idx < data.length; idx++) {
var dataItem = data.at(idx);
var item = dataItem.toJSON();
if (serverGrouping && dataItem.items) {
item.items = items(dataItem.items);
} else {
item.uid = dataItem.uid;
if (model) {
if (dataItem.isNew()) {
item.__state__ = "create";
} else if (dataItem.dirty) {
item.__state__ = "update";
}
}
}
state.push(item);
}
return state;
}
if (this.options.offlineStorage != null) {
var state = items(this._data);
var destroyed = [];
for (var idx = 0; idx < this._destroyed.length; idx++) {
var item = this._destroyed[idx].toJSON();
item.__state__ = "destroy";
destroyed.push(item);
}
this.offlineData(state.concat(destroyed));
if (updatePristine) {
this._pristineData = this.reader.reader ? this.reader.reader._wrapDataAccessBase(state) : this.reader._wrapDataAccessBase(state);
}
}
},
_addRange: function(data, skip) {
var that = this,
start = typeof(skip) !== "undefined" ? skip : (that._skip || 0),
end = start + that._flatData(data, true).length;
that._ranges.push({
start: start,
end: end,
data: data,
pristineData: data.toJSON(),
timestamp: that._timeStamp()
});
that._sortRanges();
},
_sortRanges: function() {
this._ranges.sort(function(x, y) {
return x.start - y.start;
});
},
error: function(xhr, status, errorThrown) {
this._dequeueRequest();
this.trigger(REQUESTEND, { });
this.trigger(ERROR, { xhr: xhr, status: status, errorThrown: errorThrown });
},
_params: function(data) {
var that = this,
options = extend({
take: that.take(),
skip: that.skip(),
page: that.page(),
pageSize: that.pageSize(),
sort: that._sort,
filter: that._filter,
group: that._group,
aggregate: that._aggregate
}, data);
if (!that.options.serverPaging) {
delete options.take;
delete options.skip;
delete options.page;
delete options.pageSize;
}
if (!that.options.serverGrouping) {
delete options.group;
} else if (that.reader.model && options.group) {
options.group = convertDescriptorsField(options.group, that.reader.model);
}
if (!that.options.serverFiltering) {
delete options.filter;
} else if (that.reader.model && options.filter) {
options.filter = convertFilterDescriptorsField(options.filter, that.reader.model);
}
if (!that.options.serverSorting) {
delete options.sort;
} else if (that.reader.model && options.sort) {
options.sort = convertDescriptorsField(options.sort, that.reader.model);
}
if (!that.options.serverAggregates) {
delete options.aggregate;
} else if (that.reader.model && options.aggregate) {
options.aggregate = convertDescriptorsField(options.aggregate, that.reader.model);
}
return options;
},
_queueRequest: function(options, callback) {
var that = this;
if (!that._requestInProgress) {
that._requestInProgress = true;
that._pending = undefined;
callback();
} else {
that._pending = { callback: proxy(callback, that), options: options };
}
},
_dequeueRequest: function() {
var that = this;
that._requestInProgress = false;
if (that._pending) {
that._queueRequest(that._pending.options, that._pending.callback);
}
},
_handleCustomErrors: function(response) {
if (this.reader.errors) {
var errors = this.reader.errors(response);
if (errors) {
this.trigger(ERROR, { xhr: null, status: "customerror", errorThrown: "custom error", errors: errors });
return true;
}
}
return false;
},
_shouldWrap: function(data) {
var model = this.reader.model;
if (model && data.length) {
return !(data[0] instanceof model);
}
return false;
},
_observe: function(data) {
var that = this,
model = that.reader.model;
that._shouldDetachObservableParents = true;
if (data instanceof ObservableArray) {
that._shouldDetachObservableParents = false;
if (that._shouldWrap(data)) {
data.type = that.reader.model;
data.wrapAll(data, data);
}
} else {
var arrayType = that.pageSize() && !that.options.serverPaging ? LazyObservableArray : ObservableArray;
data = new arrayType(data, that.reader.model);
data.parent = function() { return that.parent(); };
}
if (that._isServerGrouped()) {
wrapGroupItems(data, model);
}
if (that._changeHandler && that._data && that._data instanceof ObservableArray &&
!(that.options.useRanges && that.options.serverPaging)) {
that._data.unbind(CHANGE, that._changeHandler);
} else {
that._changeHandler = proxy(that._change, that);
}
return data.bind(CHANGE, that._changeHandler);
},
_updateTotalForAction: function(action, items) {
var that = this;
var total = parseInt(that._total, 10);
if (!isNumber(that._total)) {
total = parseInt(that._pristineTotal, 10);
}
if (action === "add") {
total += items.length;
} else if (action === "remove") {
total -= items.length;
} else if (action !== "itemchange" && action !== "sync" && !that.options.serverPaging) {
total = that._pristineTotal;
} else if (action === "sync") {
total = that._pristineTotal = parseInt(that._total, 10);
}
that._total = total;
},
_change: function(e) {
var that = this, idx, length, action = e ? e.action : "";
if (action === "remove") {
for (idx = 0, length = e.items.length; idx < length; idx++) {
if (!e.items[idx].isNew || !e.items[idx].isNew()) {
that._destroyed.push(e.items[idx]);
}
}
}
if (that.options.autoSync && (action === "add" || action === "remove" || action === "itemchange")) {
var handler = function(args) {
if (args.action === "sync") {
that.unbind("change", handler);
that._updateTotalForAction(action, e.items);
}
};
that.first("change", handler);
that.sync();
} else {
that._updateTotalForAction(action, e ? e.items : []);
that._process(that._data, e);
}
},
_calculateAggregates: function (data, options) {
options = options || {};
var query = new Query(data),
aggregates = options.aggregate,
filter = options.filter;
if (filter) {
query = query.filter(filter);
}
return query.aggregate(aggregates);
},
_process: function (data, e) {
var that = this,
options = {},
result;
if (that.options.serverPaging !== true) {
options.skip = that._skip;
options.take = that._take || that._pageSize;
if(options.skip === undefined && that._page !== undefined && that._pageSize !== undefined) {
options.skip = (that._page - 1) * that._pageSize;
}
if (that.options.useRanges) {
options.skip = that.currentRangeStart();
}
}
if (that.options.serverSorting !== true) {
options.sort = that._sort;
}
if (that.options.serverFiltering !== true) {
options.filter = that._filter;
}
if (that.options.serverGrouping !== true) {
options.group = that._group;
}
if (that.options.serverAggregates !== true) {
options.aggregate = that._aggregate;
}
if (that.options.serverGrouping) {
that._clearEmptyGroups(data);
}
result = that._queryProcess(data, options);
if (that.options.serverAggregates !== true) {
// for performance reasons, calculate aggregates for part of the data only after query process
// this is necessary in the TreeList when paging
that._aggregateResult = that._calculateAggregates(result.dataToAggregate || data, options);
}
that.view(result.data);
that._setFilterTotal(result.total, false);
e = e || {};
e.items = e.items || that._view;
that.trigger(CHANGE, e);
},
_clearEmptyGroups: function(data) {
for (var idx = data.length - 1; idx >=0; idx--) {
var group = data[idx];
if (group.hasSubgroups) {
this._clearEmptyGroups(group.items);
} else {
if (group.items && !group.items.length) {
splice.apply(group.parent(), [idx, 1]);
}
}
}
},
_queryProcess: function(data, options) {
if (this.options.inPlaceSort) {
return Query.process(data, options, this.options.inPlaceSort);
}
else {
return Query.process(data, options);
}
},
_mergeState: function(options) {
var that = this;
if (options !== undefined) {
that._pageSize = options.pageSize;
that._page = options.page;
that._sort = options.sort;
that._filter = options.filter;
that._group = options.group;
that._aggregate = options.aggregate;
that._skip = that._currentRangeStart = options.skip;
that._take = options.take;
if(that._skip === undefined) {
that._skip = that._currentRangeStart = that.skip();
options.skip = that.skip();
}
if(that._take === undefined && that._pageSize !== undefined) {
that._take = that._pageSize;
options.take = that._take;
}
if (options.sort) {
that._sort = options.sort = normalizeSort(options.sort);
}
if (options.filter) {
that._filter = options.filter = (that.options.accentFoldingFiltering && !$.isEmptyObject(options.filter)) ? $.extend({}, normalizeFilter(options.filter), { accentFoldingFiltering: that.options.accentFoldingFiltering}) : normalizeFilter(options.filter);
}
if (options.group) {
that._group = options.group = normalizeGroup(options.group);
}
if (options.aggregate) {
that._aggregate = options.aggregate = normalizeAggregate(options.aggregate);
}
}
return options;
},
query: function(options) {
var result;
var remote = this.options.serverSorting || this.options.serverPaging || this.options.serverFiltering || this.options.serverGrouping || this.options.serverAggregates;
if (remote || ((this._data === undefined || this._data.length === 0) && !this._destroyed.length)) {
if (this.options.endless) {
var moreItemsCount = options.pageSize - this.pageSize();
if (moreItemsCount > 0) {
moreItemsCount = this.pageSize();
options.page = options.pageSize / moreItemsCount;
options.pageSize = moreItemsCount;
} else {
options.page = 1;
this.options.endless = false;
}
}
return this.read(this._mergeState(options));
}
var isPrevented = this.trigger(REQUESTSTART, { type: "read" });
if (!isPrevented) {
this.trigger(PROGRESS);
result = this._queryProcess(this._data, this._mergeState(options));
this._setFilterTotal(result.total, true);
this._aggregateResult = this._calculateAggregates(result.dataToAggregate || this._data, options);
this.view(result.data);
this.trigger(REQUESTEND, { type: "read" });
this.trigger(CHANGE, { items: result.data });
}
return $.Deferred().resolve(isPrevented).promise();
},
_setFilterTotal: function(filterTotal, setDefaultValue) {
var that = this;
if (!that.options.serverFiltering) {
if (filterTotal !== undefined) {
that._total = filterTotal;
} else if (setDefaultValue) {
that._total = that._data.length;
}
}
},
fetch: function(callback) {
var that = this;
var fn = function(isPrevented) {
if (isPrevented !== true && isFunction(callback)) {
callback.call(that);
}
};
return this._query().done(fn);
},
_query: function(options) {
var that = this;
return that.query(extend({}, {
page: that.page(),
pageSize: that.pageSize(),
sort: that.sort(),
filter: that.filter(),
group: that.group(),
aggregate: that.aggregate()
}, options));
},
next: function(options) {
var that = this,
page = that.page(),
total = that.total();
options = options || {};
if (!page || (total && page + 1 > that.totalPages())) {
return;
}
that._skip = that._currentRangeStart = page * that.take();
page += 1;
options.page = page;
that._query(options);
return page;
},
prev: function(options) {
var that = this,
page = that.page();
options = options || {};
if (!page || page === 1) {
return;
}
that._skip = that._currentRangeStart = that._skip - that.take();
page -= 1;
options.page = page;
that._query(options);
return page;
},
page: function(val) {
var that = this,
skip;
if(val !== undefined) {
val = math.max(math.min(math.max(val, 1), that.totalPages()), 1);
that._query(that._pageableQueryOptions({ page: val }));
return;
}
skip = that.skip();
return skip !== undefined ? math.round((skip || 0) / (that.take() || 1)) + 1 : undefined;
},
pageSize: function(val) {
var that = this;
if (val !== undefined) {
that._query(that._pageableQueryOptions({ pageSize: val, page: 1 }));
return;
}
return that.take();
},
sort: function(val) {
var that = this;
if(val !== undefined) {
that._query({ sort: val });
return;
}
return that._sort;
},
filter: function(val) {
var that = this;
if (val === undefined) {
return that._filter;
}
that.trigger("reset");
that._query({ filter: val, page: 1 });
},
group: function(val) {
var that = this;
if(val !== undefined) {
that._query({ group: val });
return;
}
return that._group;
},
total: function() {
return parseInt(this._total || 0, 10);
},
aggregate: function(val) {
var that = this;
if(val !== undefined) {
that._query({ aggregate: val });
return;
}
return that._aggregate;
},
aggregates: function() {
var result = this._aggregateResult;
if (isEmptyObject(result)) {
result = this._emptyAggregates(this.aggregate());
}
return result;
},
_emptyAggregates: function(aggregates) {
var result = {};
if (!isEmptyObject(aggregates)) {
var aggregate = {};
if (!isArray(aggregates)){
aggregates = [aggregates];
}
for (var idx = 0; idx <aggregates.length; idx++) {
aggregate[aggregates[idx].aggregate] = 0;
result[aggregates[idx].field] = aggregate;
}
}
return result;
},
_pageableQueryOptions: function(options) {
return options;
},
_wrapInEmptyGroup: function(model) {
var groups = this.group(),
parent,
group,
idx,
length;
for (idx = groups.length-1, length = 0; idx >= length; idx--) {
group = groups[idx];
parent = {
value: model.get ? model.get(group.field) : model[group.field],
field: group.field,
items: parent ? [parent] : [model],
hasSubgroups: !!parent,
aggregates: this._emptyAggregates(group.aggregates)
};
}
return parent;
},
totalPages: function() {
var that = this,
pageSize = that.pageSize() || that.total();
return math.ceil((that.total() || 0) / pageSize);
},
inRange: function(skip, take) {
var that = this,
end = math.min(skip + take, that.total());
if (!that.options.serverPaging && that._data.length > 0) {
return true;
}
return that._findRange(skip, end).length > 0;
},
lastRange: function() {
var ranges = this._ranges;
return ranges[ranges.length - 1] || { start: 0, end: 0, data: [] };
},
firstItemUid: function() {
var ranges = this._ranges;
return ranges.length && ranges[0].data.length && ranges[0].data[0].uid;
},
enableRequestsInProgress: function() {
this._skipRequestsInProgress = false;
},
_timeStamp: function() {
return new Date().getTime();
},
range: function(skip, take, callback) {
this._currentRequestTimeStamp = this._timeStamp();
this._skipRequestsInProgress = true;
skip = math.min(skip || 0, this.total());
callback = isFunction(callback) ? callback : noop;
var that = this,
pageSkip = math.max(math.floor(skip / take), 0) * take,
size = math.min(pageSkip + take, that.total()),
data;
data = that._findRange(skip, math.min(skip + take, that.total()));
if (data.length || that.total() === 0) {
that._processRangeData(data, skip, take, pageSkip, size);
callback();
return;
}
if (take !== undefined) {
if (!that._rangeExists(pageSkip, size)) {
that.prefetch(pageSkip, take, function() {
if (skip > pageSkip && size < that.total() && !that._rangeExists(size, math.min(size + take, that.total()))) {
that.prefetch(size, take, function() {
that.range(skip, take, callback );
});
} else {
that.range(skip, take, callback);
}
});
} else if (pageSkip < skip) {
that.prefetch(size, take, function() {
that.range(skip, take, callback );
});
}
}
},
_findRange: function(start, end) {
var that = this,
ranges = that._ranges,
range,
data = [],
skipIdx,
takeIdx,
startIndex,
endIndex,
rangeData,
rangeEnd,
processed,
options = that.options,
remote = options.serverSorting || options.serverPaging || options.serverFiltering || options.serverGrouping || options.serverAggregates,
flatData,
count,
length;
for (skipIdx = 0, length = ranges.length; skipIdx < length; skipIdx++) {
range = ranges[skipIdx];
if (start >= range.start && start <= range.end) {
count = 0;
for (takeIdx = skipIdx; takeIdx < length; takeIdx++) {
range = ranges[takeIdx];
flatData = that._flatData(range.data, true);
if (flatData.length && start + count >= range.start) {
rangeData = range.data;
rangeEnd = range.end;
if (!remote) {
if (options.inPlaceSort) {
processed = that._queryProcess(range.data, { filter: that.filter() });
} else {
var sort = normalizeGroupWithoutCompare(that.group() || []).concat(normalizeSort(that.sort() || []));
processed = that._queryProcess(range.data, { sort: sort, filter: that.filter() });
}
flatData = rangeData = processed.data;
if (processed.total !== undefined) {
rangeEnd = processed.total;
}
}
startIndex = 0;
if (start + count > range.start) {
startIndex = (start + count) - range.start;
}
endIndex = flatData.length;
if (rangeEnd > end) {
endIndex = endIndex - (rangeEnd - end);
}
count += endIndex - startIndex;
data = that._mergeGroups(data, rangeData, startIndex, endIndex);
if (end <= range.end && count == end - start) {
return data;
}
}
}
break;
}
}
return [];
},
_mergeGroups: function(data, range, skip, take) {
if (this._isServerGrouped()) {
var temp = range.toJSON(),
prevGroup;
if (data.length) {
prevGroup = data[data.length - 1];
}
mergeGroups(prevGroup, temp, skip, take);
return data.concat(temp);
}
return data.concat(range.slice(skip, take));
},
_processRangeData: function(data, skip, take, pageSkip, size) {
var that = this;
that._pending = undefined;
that._skip = skip > that.skip() ? math.min(size, (that.totalPages() - 1) * that.take()) : pageSkip;
that._currentRangeStart = skip;
that._take = take;
var paging = that.options.serverPaging;
var sorting = that.options.serverSorting;
var filtering = that.options.serverFiltering;
var aggregates = that.options.serverAggregates;
try {
that.options.serverPaging = true;
if (!that._isServerGrouped() && !(that.group() && that.group().length)) {
that.options.serverSorting = true;
}
that.options.serverFiltering = true;
that.options.serverPaging = true;
that.options.serverAggregates = true;
if (paging) {
that._detachObservableParents();
that._data = data = that._observe(data);
}
that._process(data);
} finally {
that.options.serverPaging = paging;
that.options.serverSorting = sorting;
that.options.serverFiltering = filtering;
that.options.serverAggregates = aggregates;
}
},
skip: function() {
var that = this;
if (that._skip === undefined) {
return (that._page !== undefined ? (that._page - 1) * (that.take() || 1) : undefined);
}
return that._skip;
},
currentRangeStart: function() {
return this._currentRangeStart || 0;
},
take: function() {
return this._take || this._pageSize;
},
_prefetchSuccessHandler: function (skip, size, callback, force) {
var that = this;
var timestamp = that._timeStamp();
return function(data) {
var found = false,
range = { start: skip, end: size, data: [], timestamp: that._timeStamp() },
idx,
length,
temp;
that._dequeueRequest();
that.trigger(REQUESTEND, { response: data, type: "read" });
data = that.reader.parse(data);
temp = that._readData(data);
if (temp.length) {
for (idx = 0, length = that._ranges.length; idx < length; idx++) {
if (that._ranges[idx].start === skip) {
found = true;
range = that._ranges[idx];
range.pristineData = temp;
range.data = that._observe(temp);
range.end = range.start + that._flatData(range.data, true).length;
that._sortRanges();
break;
}
}
if (!found) {
that._addRange(that._observe(temp), skip);
}
}
that._total = that.reader.total(data);
if (force || (timestamp >= that._currentRequestTimeStamp || !that._skipRequestsInProgress)) {
if (callback && temp.length) {
callback();
} else {
that.trigger(CHANGE, {});
}
}
};
},
prefetch: function(skip, take, callback) {
var that = this,
size = math.min(skip + take, that.total()),
options = {
take: take,
skip: skip,
page: skip / take + 1,
pageSize: take,
sort: that._sort,
filter: that._filter,
group: that._group,
aggregate: that._aggregate
};
if (!that._rangeExists(skip, size)) {
clearTimeout(that._timeout);
that._timeout = setTimeout(function() {
that._queueRequest(options, function() {
if (!that.trigger(REQUESTSTART, { type: "read" })) {
that.transport.read({
data: that._params(options),
success: that._prefetchSuccessHandler(skip, size, callback),
error: function() {
var args = slice.call(arguments);
that.error.apply(that, args);
}
});
} else {
that._dequeueRequest();
}
});
}, 100);
} else if (callback) {
callback();
}
},
_multiplePrefetch: function(skip, take, callback) {
var that = this,
size = math.min(skip + take, that.total()),
options = {
take: take,
skip: skip,
page: skip / take + 1,
pageSize: take,
sort: that._sort,
filter: that._filter,
group: that._group,
aggregate: that._aggregate
};
if (!that._rangeExists(skip, size)) {
if (!that.trigger(REQUESTSTART, { type: "read" })) {
that.transport.read({
data: that._params(options),
success: that._prefetchSuccessHandler(skip, size, callback, true)
});
}
} else if (callback) {
callback();
}
},
_rangeExists: function(start, end) {
var that = this,
ranges = that._ranges,
idx,
length;
for (idx = 0, length = ranges.length; idx < length; idx++) {
if (ranges[idx].start <= start && ranges[idx].end >= end) {
return true;
}
}
return false;
},
_getCurrentRangeSpan: function() {
var that = this;
var ranges = that._ranges;
var start = that.currentRangeStart();
var end = start + (that.take() || 0);
var rangeSpan = [];
var range;
var idx;
var length = ranges.length;
for (idx = 0; idx < length; idx++) {
range = ranges[idx];
if ((range.start <= start && range.end >= start) || (range.start >= start && range.start <= end)) {
rangeSpan.push(range);
}
}
return rangeSpan;
},
_removeModelFromRanges: function(model) {
var that = this;
var range;
for (var idx = 0, length = this._ranges.length; idx < length; idx++) {
range = this._ranges[idx];
that._removeModelFromRange(range, model);
}
that._updateRangesLength();
},
_removeModelFromRange: function(range, model) {
this._eachItem(range.data, function(data) {
for (var idx = 0; idx < data.length; idx++) {
var dataItem = data[idx];
if (dataItem.uid && dataItem.uid == model.uid) {
[].splice.call(data, idx, 1);
break;
}
}
});
},
_insertModelInRange: function(index, model) {
var that = this;
var ranges = that._ranges || [];
var rangesLength = ranges.length;
var range;
var i;
for (i = 0; i < rangesLength; i++) {
range = ranges[i];
if (range.start <= index && range.end >= index) {
if (!that._getByUid(model.uid, range.data)) {
if (that._isServerGrouped()) {
range.data.splice(index, 0, that._wrapInEmptyGroup(model));
} else {
range.data.splice(index, 0, model);
}
}
break;
}
}
that._updateRangesLength();
},
_updateRangesLength: function() {
var that = this;
var ranges = that._ranges || [];
var rangesLength = ranges.length;
var mismatchFound = false;
var mismatchLength = 0;
var lengthDifference = 0;
var range;
var i;
for (i = 0; i < rangesLength; i++) {
range = ranges[i];
lengthDifference = that._flatData(range.data, true).length - math.abs(range.end - range.start);
if (!mismatchFound && lengthDifference !== 0) {
mismatchFound = true;
mismatchLength = lengthDifference;
range.end += mismatchLength;
continue;
}
if (mismatchFound) {
range.start += mismatchLength;
range.end += mismatchLength;
}
}
}
});
var Transport = {};
Transport.create = function(options, data, dataSource) {
var transport,
transportOptions = options.transport ? $.extend({}, options.transport) : null;
if (transportOptions) {
transportOptions.read = typeof transportOptions.read === STRING ? { url: transportOptions.read } : transportOptions.read;
if (options.type === "jsdo") {
transportOptions.dataSource = dataSource;
}
if (options.type) {
kendo.data.transports = kendo.data.transports || {};
kendo.data.schemas = kendo.data.schemas || {};
if (!kendo.data.transports[options.type]) {
kendo.logToConsole("Unknown DataSource transport type '" + options.type + "'.\nVerify that registration scripts for this type are included after Kendo UI on the page.", "warn");
} else if (!isPlainObject(kendo.data.transports[options.type])) {
transport = new kendo.data.transports[options.type](extend(transportOptions, { data: data }));
} else {
transportOptions = extend(true, {}, kendo.data.transports[options.type], transportOptions);
}
options.schema = extend(true, {}, kendo.data.schemas[options.type], options.schema);
}
if (!transport) {
transport = isFunction(transportOptions.read) ? transportOptions : new RemoteTransport(transportOptions);
}
} else {
transport = new LocalTransport({ data: options.data || [] });
}
return transport;
};
DataSource.create = function(options) {
if (isArray(options) || options instanceof ObservableArray) {
options = { data: options };
}
var dataSource = options || {},
data = dataSource.data,
fields = dataSource.fields,
table = dataSource.table,
select = dataSource.select,
idx,
length,
model = {},
field;
if (!data && fields && !dataSource.transport) {
if (table) {
data = inferTable(table, fields);
} else if (select) {
data = inferSelect(select, fields);
if (dataSource.group === undefined && data[0] && data[0].optgroup !== undefined) {
dataSource.group = "optgroup";
}
}
}
if (kendo.data.Model && fields && (!dataSource.schema || !dataSource.schema.model)) {
for (idx = 0, length = fields.length; idx < length; idx++) {
field = fields[idx];
if (field.type) {
model[field.field] = field;
}
}
if (!isEmptyObject(model)) {
dataSource.schema = extend(true, dataSource.schema, { model: { fields: model } });
}
}
dataSource.data = data;
select = null;
dataSource.select = null;
table = null;
dataSource.table = null;
return dataSource instanceof DataSource ? dataSource : new DataSource(dataSource);
};
function inferSelect(select, fields) {
select = $(select)[0];
var options = select.options;
var firstField = fields[0];
var secondField = fields[1];
var data = [];
var idx, length;
var optgroup;
var option;
var record;
var value;
for (idx = 0, length = options.length; idx < length; idx++) {
record = {};
option = options[idx];
optgroup = option.parentNode;
if (optgroup === select) {
optgroup = null;
}
if (option.disabled || (optgroup && optgroup.disabled)) {
continue;
}
if (optgroup) {
record.optgroup = optgroup.label;
}
record[firstField.field] = option.text;
value = option.attributes.value;
if (value && value.specified) {
value = option.value;
} else {
value = option.text;
}
record[secondField.field] = value;
data.push(record);
}
return data;
}
function inferTable(table, fields) {
var tbody = $(table)[0].tBodies[0],
rows = tbody ? tbody.rows : [],
idx,
length,
fieldIndex,
fieldCount = fields.length,
data = [],
cells,
record,
cell,
empty;
for (idx = 0, length = rows.length; idx < length; idx++) {
record = {};
empty = true;
cells = rows[idx].cells;
for (fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
cell = cells[fieldIndex];
if(cell.nodeName.toLowerCase() !== "th") {
empty = false;
record[fields[fieldIndex].field] = cell.innerHTML;
}
}
if(!empty) {
data.push(record);
}
}
return data;
}
var Node = Model.define({
idField: "id",
init: function(value) {
var that = this,
hasChildren = that.hasChildren || value && value.hasChildren,
childrenField = "items",
childrenOptions = {};
kendo.data.Model.fn.init.call(that, value);
if (typeof that.children === STRING) {
childrenField = that.children;
}
childrenOptions = {
schema: {
data: childrenField,
model: {
hasChildren: hasChildren,
id: that.idField,
fields: that.fields
}
}
};
if (typeof that.children !== STRING) {
extend(childrenOptions, that.children);
}
childrenOptions.data = value;
if (!hasChildren) {
hasChildren = childrenOptions.schema.data;
}
if (typeof hasChildren === STRING) {
hasChildren = kendo.getter(hasChildren);
}
if (isFunction(hasChildren)) {
var hasChildrenObject = hasChildren.call(that, that);
if(hasChildrenObject && hasChildrenObject.length === 0){
that.hasChildren = false;
} else{
that.hasChildren = !!hasChildrenObject;
}
}
that._childrenOptions = childrenOptions;
if (that.hasChildren) {
that._initChildren();
}
that._loaded = !!(value && value._loaded);
},
_initChildren: function() {
var that = this;
var children, transport, parameterMap;
if (!(that.children instanceof HierarchicalDataSource)) {
children = that.children = new HierarchicalDataSource(that._childrenOptions);
transport = children.transport;
parameterMap = transport.parameterMap;
transport.parameterMap = function(data, type) {
data[that.idField || "id"] = that.id;
if (parameterMap) {
data = parameterMap(data, type);
}
return data;
};
children.parent = function(){
return that;
};
children.bind(CHANGE, function(e){
e.node = e.node || that;
that.trigger(CHANGE, e);
});
children.bind(ERROR, function(e){
var collection = that.parent();
if (collection) {
e.node = e.node || that;
collection.trigger(ERROR, e);
}
});
that._updateChildrenField();
}
},
append: function(model) {
this._initChildren();
this.loaded(true);
this.children.add(model);
},
hasChildren: false,
level: function() {
var parentNode = this.parentNode(),
level = 0;
while (parentNode && parentNode.parentNode) {
level++;
parentNode = parentNode.parentNode ? parentNode.parentNode() : null;
}
return level;
},
_updateChildrenField: function() {
var fieldName = this._childrenOptions.schema.data;
this[fieldName || "items"] = this.children.data();
},
_childrenLoaded: function() {
this._loaded = true;
this._updateChildrenField();
},
load: function() {
var options = {};
var method = "_query";
var children, promise;
if (this.hasChildren) {
this._initChildren();
children = this.children;
options[this.idField || "id"] = this.id;
if (!this._loaded) {
children._data = undefined;
method = "read";
}
children.one(CHANGE, proxy(this._childrenLoaded, this));
if(this._matchFilter){
options.filter = { field: '_matchFilter', operator: 'eq', value: true };
}
promise = children[method](options);
} else {
this.loaded(true);
}
return promise || $.Deferred().resolve().promise();
},
parentNode: function() {
var array = this.parent();
return array.parent();
},
loaded: function(value) {
if (value !== undefined) {
this._loaded = value;
} else {
return this._loaded;
}
},
shouldSerialize: function(field) {
return Model.fn.shouldSerialize.call(this, field) &&
field !== "children" &&
field !== "_loaded" &&
field !== "hasChildren" &&
field !== "_childrenOptions";
}
});
function dataMethod(name) {
return function() {
var data = this._data,
result = DataSource.fn[name].apply(this, slice.call(arguments));
if (this._data != data) {
this._attachBubbleHandlers();
}
return result;
};
}
var HierarchicalDataSource = DataSource.extend({
init: function(options) {
var node = Node.define({
children: options
});
if(options.filter && !options.serverFiltering){
this._hierarchicalFilter = options.filter;
options.filter = null;
}
DataSource.fn.init.call(this, extend(true, {}, { schema: { modelBase: node, model: node } }, options));
this._attachBubbleHandlers();
},
_attachBubbleHandlers: function() {
var that = this;
that._data.bind(ERROR, function(e) {
that.trigger(ERROR, e);
});
},
read: function(data) {
var result = DataSource.fn.read.call(this, data);
if(this._hierarchicalFilter){
if(this._data && this._data.length > 0){
this.filter(this._hierarchicalFilter);
}else{
this.options.filter = this._hierarchicalFilter;
this._filter = normalizeFilter(this.options.filter);
this._hierarchicalFilter = null;
}
}
return result;
},
remove: function(node){
var parentNode = node.parentNode(),
dataSource = this,
result;
if (parentNode && parentNode._initChildren) {
dataSource = parentNode.children;
}
result = DataSource.fn.remove.call(dataSource, node);
if (parentNode && !dataSource.data().length) {
parentNode.hasChildren = false;
}
return result;
},
success: dataMethod("success"),
data: dataMethod("data"),
insert: function(index, model) {
var parentNode = this.parent();
if (parentNode && parentNode._initChildren) {
parentNode.hasChildren = true;
parentNode._initChildren();
}
return DataSource.fn.insert.call(this, index, model);
},
filter: function(val) {
if (val === undefined) {
return this._filter;
}
if(!this.options.serverFiltering && this._markHierarchicalQuery(val)){
val = { logic: "or", filters: [val, {field:'_matchFilter', operator: 'equals', value: true }]};
}
this.trigger("reset");
this._query({ filter: val, page: 1 });
},
_markHierarchicalQuery: function(expressions){
var compiled;
var predicate;
var fields;
var operators;
var filter;
var accentFoldingFiltering = this.options.accentFoldingFiltering;
expressions = accentFoldingFiltering ? $.extend({}, normalizeFilter(expressions), { accentFoldingFiltering: accentFoldingFiltering}) : normalizeFilter(expressions);
if (!expressions || expressions.filters.length === 0) {
this._updateHierarchicalFilter(function(){return true;});
return false;
}
compiled = Query.filterExpr(expressions);
fields = compiled.fields;
operators = compiled.operators;
predicate = filter = new Function("d, __f, __o", "return " + compiled.expression);
if (fields.length || operators.length) {
filter = function(d) {
return predicate(d, fields, operators);
};
}
this._updateHierarchicalFilter(filter);
return true;
},
_updateHierarchicalFilter: function(filter){
var current;
var data = this._data;
var result = false;
for (var idx = 0; idx < data.length; idx++) {
current = data[idx];
if(current.hasChildren){
current._matchFilter = current.children._updateHierarchicalFilter(filter);
if(!current._matchFilter){
current._matchFilter = filter(current);
}
}else{
current._matchFilter = filter(current);
}
if(current._matchFilter){
result = true;
}
}
return result;
},
_find: function(method, value) {
var idx, length, node, children;
var data = this._data;
if (!data) {
return;
}
node = DataSource.fn[method].call(this, value);
if (node) {
return node;
}
data = this._flatData(this._data);
for (idx = 0, length = data.length; idx < length; idx++) {
children = data[idx].children;
if (!(children instanceof HierarchicalDataSource)) {
continue;
}
node = children[method](value);
if (node) {
return node;
}
}
},
get: function(id) {
return this._find("get", id);
},
getByUid: function(uid) {
return this._find("getByUid", uid);
}
});
function inferList(list, fields) {
var items = $(list).children(),
idx,
length,
data = [],
record,
textField = fields[0].field,
urlField = fields[1] && fields[1].field,
spriteCssClassField = fields[2] && fields[2].field,
imageUrlField = fields[3] && fields[3].field,
item,
id,
textChild,
className,
children;
function elements(collection, tagName) {
return collection.filter(tagName).add(collection.find(tagName));
}
for (idx = 0, length = items.length; idx < length; idx++) {
record = { _loaded: true };
item = items.eq(idx);
textChild = item[0].firstChild;
children = item.children();
list = children.filter("ul");
children = children.filter(":not(ul)");
id = item.attr("data-id");
if (id) {
record.id = id;
}
if (textChild) {
record[textField] = textChild.nodeType == 3 ? textChild.nodeValue : children.text();
}
if (urlField) {
record[urlField] = elements(children, "a").attr("href");
}
if (imageUrlField) {
record[imageUrlField] = elements(children, "img").attr("src");
}
if (spriteCssClassField) {
className = elements(children, ".k-sprite").prop("className");
record[spriteCssClassField] = className && $.trim(className.replace("k-sprite", ""));
}
if (list.length) {
record.items = inferList(list.eq(0), fields);
}
if (item.attr("data-hasChildren") == "true") {
record.hasChildren = true;
}
data.push(record);
}
return data;
}
HierarchicalDataSource.create = function(options) {
options = options && options.push ? { data: options } : options;
var dataSource = options || {},
data = dataSource.data,
fields = dataSource.fields,
list = dataSource.list;
if (data && data._dataSource) {
return data._dataSource;
}
if (!data && fields && !dataSource.transport) {
if (list) {
data = inferList(list, fields);
}
}
dataSource.data = data;
return dataSource instanceof HierarchicalDataSource ? dataSource : new HierarchicalDataSource(dataSource);
};
var Buffer = kendo.Observable.extend({
init: function(dataSource, viewSize, disablePrefetch) {
kendo.Observable.fn.init.call(this);
this._prefetching = false;
this.dataSource = dataSource;
this.prefetch = !disablePrefetch;
var buffer = this;
dataSource.bind("change", function() {
buffer._change();
});
dataSource.bind("reset", function() {
buffer._reset();
});
this._syncWithDataSource();
this.setViewSize(viewSize);
},
setViewSize: function(viewSize) {
this.viewSize = viewSize;
this._recalculate();
},
at: function(index) {
var pageSize = this.pageSize,
itemPresent = true;
if (index >= this.total()) {
this.trigger("endreached", {index: index });
return null;
}
if (!this.useRanges) {
return this.dataSource.view()[index];
}
if (this.useRanges) {
// out of range request
if (index < this.dataOffset || index >= this.skip + pageSize) {
itemPresent = this.range(Math.floor(index / pageSize) * pageSize);
}
// prefetch
if (index === this.prefetchThreshold) {
this._prefetch();
}
// mid-range jump - prefetchThreshold and nextPageThreshold may be equal, do not change to else if
if (index === this.midPageThreshold) {
this.range(this.nextMidRange, true);
}
// next range jump
else if (index === this.nextPageThreshold) {
this.range(this.nextFullRange);
}
// pull-back
else if (index === this.pullBackThreshold) {
if (this.offset === this.skip) { // from full range to mid range
this.range(this.previousMidRange);
} else { // from mid range to full range
this.range(this.previousFullRange);
}
}
if (itemPresent) {
return this.dataSource.at(index - this.dataOffset);
} else {
this.trigger("endreached", { index: index });
return null;
}
}
},
indexOf: function(item) {
return this.dataSource.data().indexOf(item) + this.dataOffset;
},
total: function() {
return parseInt(this.dataSource.total(), 10);
},
next: function() {
var buffer = this,
pageSize = buffer.pageSize,
offset = buffer.skip - buffer.viewSize + pageSize,
pageSkip = math.max(math.floor(offset / pageSize), 0) * pageSize;
this.offset = offset;
this.dataSource.prefetch(pageSkip, pageSize, function() {
buffer._goToRange(offset, true);
});
},
range: function(offset, nextRange) {
if (this.offset === offset) {
return true;
}
var buffer = this,
pageSize = this.pageSize,
pageSkip = math.max(math.floor(offset / pageSize), 0) * pageSize,
dataSource = this.dataSource;
if (nextRange) {
pageSkip += pageSize;
}
if (dataSource.inRange(offset, pageSize)) {
this.offset = offset;
this._recalculate();
this._goToRange(offset);
return true;
} else if (this.prefetch) {
dataSource.prefetch(pageSkip, pageSize, function() {
buffer.offset = offset;
buffer._recalculate();
buffer._goToRange(offset, true);
});
return false;
}
return true;
},
syncDataSource: function() {
var offset = this.offset;
this.offset = null;
this.range(offset);
},
destroy: function() {
this.unbind();
},
_prefetch: function() {
var buffer = this,
pageSize = this.pageSize,
prefetchOffset = this.skip + pageSize,
dataSource = this.dataSource;
if (!dataSource.inRange(prefetchOffset, pageSize) && !this._prefetching && this.prefetch) {
this._prefetching = true;
this.trigger("prefetching", { skip: prefetchOffset, take: pageSize });
dataSource.prefetch(prefetchOffset, pageSize, function() {
buffer._prefetching = false;
buffer.trigger("prefetched", { skip: prefetchOffset, take: pageSize });
});
}
},
_goToRange: function(offset, expanding) {
if (this.offset !== offset) {
return;
}
this.dataOffset = offset;
this._expanding = expanding;
this.dataSource.range(offset, this.pageSize);
this.dataSource.enableRequestsInProgress();
},
_reset: function() {
this._syncPending = true;
},
_change: function() {
var dataSource = this.dataSource;
this.length = this.useRanges ? dataSource.lastRange().end : dataSource.view().length;
if (this._syncPending) {
this._syncWithDataSource();
this._recalculate();
this._syncPending = false;
this.trigger("reset", { offset: this.offset });
}
this.trigger("resize");
if (this._expanding) {
this.trigger("expand");
}
delete this._expanding;
},
_syncWithDataSource: function() {
var dataSource = this.dataSource;
this._firstItemUid = dataSource.firstItemUid();
this.dataOffset = this.offset = dataSource.skip() || 0;
this.pageSize = dataSource.pageSize();
this.useRanges = dataSource.options.serverPaging;
},
_recalculate: function() {
var pageSize = this.pageSize,
offset = this.offset,
viewSize = this.viewSize,
skip = Math.ceil(offset / pageSize) * pageSize;
this.skip = skip;
this.midPageThreshold = skip + pageSize - 1;
this.nextPageThreshold = skip + viewSize - 1;
this.prefetchThreshold = skip + Math.floor(pageSize / 3 * 2);
this.pullBackThreshold = this.offset - 1;
this.nextMidRange = skip + pageSize - viewSize;
this.nextFullRange = skip;
this.previousMidRange = offset - viewSize;
this.previousFullRange = skip - pageSize;
}
});
var BatchBuffer = kendo.Observable.extend({
init: function(dataSource, batchSize) {
var batchBuffer = this;
kendo.Observable.fn.init.call(batchBuffer);
this.dataSource = dataSource;
this.batchSize = batchSize;
this._total = 0;
this.buffer = new Buffer(dataSource, batchSize * 3);
this.buffer.bind({
"endreached": function (e) {
batchBuffer.trigger("endreached", { index: e.index });
},
"prefetching": function (e) {
batchBuffer.trigger("prefetching", { skip: e.skip, take: e.take });
},
"prefetched": function (e) {
batchBuffer.trigger("prefetched", { skip: e.skip, take: e.take });
},
"reset": function () {
batchBuffer._total = 0;
batchBuffer.trigger("reset");
},
"resize": function () {
batchBuffer._total = Math.ceil(this.length / batchBuffer.batchSize);
batchBuffer.trigger("resize", { total: batchBuffer.total(), offset: this.offset });
}
});
},
syncDataSource: function() {
this.buffer.syncDataSource();
},
at: function(index) {
var buffer = this.buffer,
skip = index * this.batchSize,
take = this.batchSize,
view = [],
item;
if (buffer.offset > skip) {
buffer.at(buffer.offset - 1);
}
for (var i = 0; i < take; i++) {
item = buffer.at(skip + i);
if (item === null) {
break;
}
view.push(item);
}
return view;
},
total: function() {
return this._total;
},
destroy: function() {
this.buffer.destroy();
this.unbind();
}
});
extend(true, kendo.data, {
readers: {
json: DataReader
},
Query: Query,
DataSource: DataSource,
HierarchicalDataSource: HierarchicalDataSource,
Node: Node,
ObservableObject: ObservableObject,
ObservableArray: ObservableArray,
LazyObservableArray: LazyObservableArray,
LocalTransport: LocalTransport,
RemoteTransport: RemoteTransport,
Cache: Cache,
DataReader: DataReader,
Model: Model,
Buffer: Buffer,
BatchBuffer: BatchBuffer
});
})(window.kendo.jQuery);
return window.kendo;
}, __webpack_require__(3));
/***/ }),
/***/ 1049:
/***/ (function(module, exports) {
module.exports = require("./kendo.data.odata");
/***/ }),
/***/ 1050:
/***/ (function(module, exports) {
module.exports = require("./kendo.data.xml");
/***/ })
/******/ });