@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
1,698 lines (1,696 loc) • 165 kB
JavaScript
//#region ../src/data/filter-expression-no-eval.js
const logic = {
"or": {
concat: (acc, fn) => (a) => acc(a) || fn(a),
identity: () => false
},
"and": {
concat: (acc, fn) => (a) => acc(a) && fn(a),
identity: () => true
}
};
const operatorsMap = {
isnullorempty: (a) => kendo.isBlank(a) || a === "",
isnotnullorempty: (a) => kendo.isPresent(a) && a !== "",
contains: (a, b) => (a + "").indexOf(b) >= 0,
doesnotcontain: (a, b) => (a + "").indexOf(b) === -1,
doesnotendwith: (a, b) => (a + "").indexOf(b, (a || "").length - (b || "").length) < 0,
doesnotstartwith: (a, b) => (a + "").lastIndexOf(b, 0) === -1,
endswith: (a, b) => (a + "").indexOf(b, (a || "").length - (b || "").length) >= 0,
eq: (a, b) => a === b,
gt: (a, b) => a > b,
gte: (a, b) => a >= b,
isempty: (a) => a === "",
isnotempty: (a) => a !== "",
isnotnull: (a) => kendo.isPresent(a),
isnull: (a) => kendo.isBlank(a),
lt: (a, b) => a < b,
lte: (a, b) => a <= b,
neq: (a, b) => a != b,
startswith: (a, b) => (a + "").lastIndexOf(b, 0) === 0
};
const dateRegExp = /^\/Date\((.*?)\)\/$/;
const convertValue = (value, ignoreCase, accentFoldingFiltering) => {
if (value != null && kendo.isString(value)) {
const date = dateRegExp.exec(value);
if (date) {
return new Date(+date[1]).getTime();
} else if (ignoreCase) {
return accentFoldingFiltering ? value.toLocaleLowerCase(accentFoldingFiltering) : value.toLowerCase();
}
} else if (value != null && kendo.isDate(value)) {
return value.getTime();
}
return value;
};
const typedGetter = (prop, value, ignoreCase, accentFoldingFiltering) => {
if (!kendo.isPresent(value)) {
return prop;
}
let acc = prop;
if (kendo.isString(value)) {
const date = dateRegExp.exec(value);
if (date) {
value = new Date(+date[1]);
} else {
acc = (a) => {
const x = prop(a);
if (typeof x === "string" && ignoreCase) {
return accentFoldingFiltering ? x.toLocaleLowerCase(accentFoldingFiltering) : x.toLowerCase();
} else {
return kendo.isNumeric(x) ? x + "" : x;
}
};
}
}
if (kendo.isDate(value)) {
return (a) => {
const x = acc(a);
return kendo.isDate(x) ? x.getTime() : x;
};
}
return acc;
};
const transformFilter = ({ field, ignoreCase, value, operator = "eq", accentFoldingFiltering }) => {
field = !kendo.isPresent(field) ? (a) => a : field;
ignoreCase = kendo.isPresent(ignoreCase) ? ignoreCase : true;
const itemProp = typedGetter(kendo.isFunction(field) ? field : kendo.getter(field, true), value, ignoreCase, accentFoldingFiltering);
value = convertValue(value, ignoreCase, accentFoldingFiltering);
const op = kendo.isFunction(operator) ? operator : operatorsMap[operator];
return (a) => op(itemProp(a), value, ignoreCase);
};
const isCompositeFilterDescriptor = (source) => kendo.isPresent(source.filters);
const transformCompositeFilter = (filter) => {
const accentFoldingFiltering = filter.accentFoldingFiltering;
const combiner = logic[filter.logic || "and"];
return filter.filters.filter(kendo.isPresent).map((x) => isCompositeFilterDescriptor(x) ? transformCompositeFilter(extendAccentFolding(x, accentFoldingFiltering)) : transformFilter(extendAccentFolding(x, accentFoldingFiltering))).reduce(combiner.concat, combiner.identity);
};
const extendAccentFolding = (filter, accentFoldingFiltering) => kendo.isPresent(accentFoldingFiltering) ? Object.assign(filter, { accentFoldingFiltering }) : filter;
const filterExprNoEval = function(expr) {
return transformCompositeFilter(expr);
};
//#endregion
//#region ../src/kendo.data.js
const __meta__ = {
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"]
}
]
};
(function($, undefined) {
var extend = $.extend, isPlainObject = $.isPlainObject, isEmptyObject = $.isEmptyObject, isArray = Array.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", ITEMSLOADED = "itemsLoaded", ITEMLOAD = "itemLoad", 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\((.*?)\)\/$/, objectKeys = [];
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);
that._loadPromises = [];
that._loadedNodes = [];
},
at: function(index) {
return this[index];
},
toJSON: function(serializeFunctions) {
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(serializeFunctions);
}
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) {
var isGroup = object.hasOwnProperty("hasSubgroups");
that.trigger(CHANGE, {
field: e.field,
node: e.node,
index: e.index,
items: e.items || [this],
action: e.node || isGroup ? e.action || "itemloaded" : "itemchange"
});
});
object.bind(ITEMLOAD, function(e) {
that._loadPromises.push(e.promise);
that._loading = true;
e.promise.done(function() {
that._loadedNodes.push(e.node);
var index = that._loadPromises.indexOf(e.promise);
that._loadPromises.splice(index, 1);
if (!that._loadPromises.length) {
that._loading = false;
that.trigger(ITEMSLOADED, {
collection: that,
nodes: that._loadedNodes
});
that._loadedNodes = [];
}
});
});
}
return object;
},
loading: function() {
return this._loading;
},
push: function() {
var index = this.length, items = this.wrapAll(arguments), result;
result = push.apply(this, items);
if (!this.omitChangeEvent) {
this.trigger(CHANGE, {
action: "add",
index,
items
});
}
return result;
},
slice,
sort: [].sort,
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) {
if (!this.omitChangeEvent) {
this.trigger(CHANGE, {
action: "remove",
index,
items: this.omitCache && this.omitCache.length ? result.concat(this.omitCache) : result
});
this.omitCache = [];
}
for (i = 0, len = result.length; i < len; i++) {
if (result[i] && result[i].children) {
result[i].unbind(CHANGE);
}
}
}
if (item) {
if (!this.omitChangeEvent) {
this.trigger(CHANGE, {
action: "add",
index,
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
});
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;
},
remove: function(item) {
var idx = this.indexOf(item);
if (idx !== -1) {
this.splice(idx, 1);
}
},
empty: function() {
this.splice(0, this.length);
}
});
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) {
var parentFn = function() {
return this;
};
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 = parentFn.bind(this);
this._loadPromises = [];
this._loadedNodes = [];
},
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);
};
}
function isPrimitiveType(value) {
return typeof value === "object" && Object.getPrototypeOf(value) === Object.getPrototypeOf({}) || Object.getPrototypeOf(value) === Object.getPrototypeOf(new Date()) || typeof value !== "object";
}
function ownKeys(value, ignoreObjectKeys) {
var props = [];
var protoKeys = [];
var keys, filteredObjectKeys;
value = value || {};
if (!isPrimitiveType(value)) {
protoKeys = Object.getOwnPropertyNames(Object.getPrototypeOf(value)).filter((f) => f.indexOf("__") !== 0);
}
keys = Object.getOwnPropertyNames(value).concat(protoKeys);
filteredObjectKeys = objectKeys.filter(function(key) {
return keys.indexOf(key) < 0;
});
while (value) {
Object.getOwnPropertyNames(value).forEach(function(prop) {
if (props.indexOf(prop) === -1 && (!ignoreObjectKeys || filteredObjectKeys.indexOf(prop) < 0)) {
props.push(prop);
}
});
value = Object.getPrototypeOf(value);
}
return props;
}
objectKeys = ownKeys({}, false);
var ObservableObject = Observable.extend({
init: function(value) {
var that = this, member, keys = ownKeys(value, true), parent = function() {
return that;
};
Observable.fn.init.call(this);
this._handlers = {};
keys.forEach(function(field) {
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, serializeFunctions) {
if (typeof serializeFunctions === "object") {
serializeFunctions = serializeFunctions && serializeFunctions[field];
}
return this.hasOwnProperty(field) && field !== "_handlers" && field !== "_events" && (serializeFunctions || typeof this[field] !== FUNCTION) && field !== "uid";
},
forEach: function(f) {
for (var i in this) {
if (this.shouldSerialize(i)) {
f(this[i], i);
}
}
},
toJSON: function(serializeFunctions) {
var result = {}, value, field;
for (field in this) {
if (this.shouldSerialize(field, serializeFunctions)) {
value = this[field];
if (value instanceof ObservableObject || value instanceof ObservableArray) {
value = value.toJSON(serializeFunctions);
}
result[field] = value;
}
}
return result;
},
get: function(field) {
var that = this, result;
that.trigger(GET, { 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,
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 });
}
}
}
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,
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 };
}
object.parent = parent;
}
return object;
}
});
function equal(x, y) {
if (x === y) {
return true;
}
var xtype = kendo.type(x), ytype = kendo.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) {
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) && !dirty) {
that.dirty = dirty;
if (!that.dirty) {
that.dirtyFields[field] = false;
}
}
} else {
that.trigger("equalSet", {
field,
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;
let nameToUse = typeof field.field === STRING ? field.field : name;
if (!field.nullable || field.defaultValue) {
value = proto.defaults[originalName !== nameToUse ? originalName : nameToUse] = field.defaultValue !== undefined ? field.defaultValue : defaultValues[type.toLowerCase()];
if (typeof value === "function") {
functionFields.push(nameToUse);
}
}
if (options.id === nameToUse) {
proto._defaultId = value;
}
proto.defaults[originalName !== nameToUse ? originalName : nameToUse] = value;
if ($.isPlainObject(field)) {
field.parse = field.parse || parsers[type];
} else {
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) {
a = "(" + a + "&&" + a + ".getTime?" + a + ".getTime():" + a + ")";
b = b.getTime();
}
}
return a + " " + op + " " + b;
}
function getMatchRegexp(pattern) {
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, options = { noEval: false }) {
if (options.noEval) {
return filterExprNoEval(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);
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,
dir
} : field, descriptors = isArray(descriptor) ? descriptor : descriptor !== undefined ? [descriptor] : [];
return grep(descriptors, function(d) {
return !!d.dir;
});
}
}
function sortFields(sorts, dir) {
var sortObject = {};
if (sorts) {
var descriptor = typeof sorts === STRING ? {
field: sorts,
dir
} : sorts, descriptors = isArray(descriptor) ? descriptor : descriptor !== undefined ? [descriptor] : [];
for (var i = 0; i < descriptors.length; i++) {
sortObject[descriptors[i].field] = {
dir: descriptors[i].dir,
index: i + 1
};
}
}
return sortObject;
}
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 hasNotFetchedItems(items, start, end) {
for (let idx = start; idx < end; idx++) {
if (items[idx].notFetched) {
return true;
}
}
return false;
}
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,
dir,
compare,
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 };
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 compiled, data = this.data, result = [];
expressions = normalizeFilter(expressions);
if (!expressions || expressions.filters.length === 0) {
return this;
}
compiled = Query.filterExpr(expressions, { noEval: true });
result = data.filter(compiled);
return new Query(result);
},
group: function(descriptors, allData, options) {
descriptors = normalizeGroup(descriptors || []);
allData = allData || this.data;
var that = this, result = new Query(that.data), descriptor;
var getFilteredData = (g, data) => {
data = data || new Query(allData).filter([{
field: g.field,
operator: "eq",
value: g.value,
ignoreCase: false
}]);
return data;
};
if (descriptors.length > 0) {
descriptor = descriptors[0];
if (options && options.groupPaging) {
result = new Query(allData).groupAllData(descriptor, allData).select(function(group) {
var cachedFilteredData;
var items = descriptors.length > 1 ? new Query(group.items).group(descriptors.slice(1), getFilteredData(group, cachedFilteredData).toArray(), options).toArray() : group.items;
return {
field: group.field,
value: group.value,
hasSubgroups: descriptors.length > 1,
items,
aggregates: descriptor.aggregates && descriptor.aggregates.length ? getFilteredData(group, cachedFilteredData).aggregate(descriptor.aggregates) : {},
uid: kendo.guid(),
itemCount: items.length,
subgroupCount: items.length
};
});
} else {
result = result.groupBy(descriptor).select(function(group) {
var cachedFilteredData;
return {
field: group.field,
value: group.value,
items: descriptors.length > 1 ? new Query(group.items).group(descriptors.slice(1), getFilteredData(group, cachedFilteredData).toArray()).toArray() : group.items,
hasSubgroups: descriptors.length > 1,
aggregates: descriptor.aggregates && descriptor.aggregates.length ? getFilteredData(group, cachedFilteredData).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,
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,
value: groupValue,
items: []
};
result.push(group);
}
group.items.push(item);
}
result = that._sortGroups(result, descriptor);
return new Query(result);
},
groupAllData: function(descriptor, allData) {
if (isEmptyObject(descriptor) || this.data && !this.data.length) {
return new Query([]);
}
var field = descriptor.field, sorted = descriptor.skipItemSorting ? allData : new Query(allData).sort(field, descriptor.dir || "asc", StableComparer).toArray(), accessor = kendo.accessor(field), item, groupValue = accessor.get(sorted[0], field), group = {
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,
value: groupValue,
items: []
};
result.push(group);
}
group.items.push(item);
}
result = this._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) {
if (!inPlace) {
query = query.sort(sort);
}
if (group) {
data = query.toArray();
}
}
if (customGroupSort) {
query = query.group(group, data, options);
if (skip !== undefined && take !== undefined && !options.groupPaging) {
query = new Query(flatGroups(query.toArray())).range(skip, take);
groupDescriptorsWithoutSort = map(groupDescriptorsWithoutCompare, function(groupDescriptor) {
return extend({}, groupDescriptor, { skipItemSorting: true });
});
query = query.group(groupDescriptorsWithoutSort, data, options);
}
} else {
if (skip !== undefined && take !== undefined) {
total = query.data.length;
if (skip + take > total && options.virtual) {
skip -= skip + take - total;
skip = skip < 0 ? 0 : skip;
}
query = query.range(skip, take);
}
if (group && (!isEmptyObject(group) || group.length !== 0)) {
query = query.group(group, data, options);
}
}
return {
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 || {