UNPKG

@progress/kendo-ui

Version:

This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.

1,654 lines (1,351 loc) 220 kB
import './kendo.core.js'; import './kendo.data.odata.js'; import './kendo.data.xml.js'; /* This code is copied/inspired by the internal @progress/kendo-data-query repo: https://github.com/telerik/kendo-data-query/tree/develop/src/filtering !!! 1. If updates are to be synced consider the accentFoldingFiltering, which at the moment is not present as a feature in the data-query-package. 2. Double-check available operators as well. 3. Make sure objs are strings -> i.e., replace (a || "") to (a + '') !!! In future, if we consider reusing the code directly we should revise the above omissions. */ 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); }; 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$1) { 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: 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) { if (!this.omitChangeEvent) { this.trigger(CHANGE, { action: "remove", index: 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: 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) { 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) { // This way we cover both if the serializeFunctions parameter is an object OR a boolean. 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: 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 = 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$1) { 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: 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$1) { 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$1 ? 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) { //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 || []; } // Continue to support legacy unsafe-eval for the spreadsheet Query.filterExpr = function(expression, options = { noEval: false }) { if (options.noEval) { // using no-eval for most cases 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); //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$1 ? 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$1 ? [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: dir } : sorts, descriptors = isArray(descriptor) ? descriptor : (descriptor !== undefined$1 ? [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: field, dir: dir, compare: compare, sk