/** * Kendo UI v2016.1.112 (http://www.telerik.com/kendo-ui) * Copyright 2016 Telerik AD. All rights reserved. * * Kendo UI commercial licenses may be obtained at * http://www.telerik.com/purchase/license-agreement/kendo-ui-complete * If you do not own a commercial license, this file shall be governed by the trial license terms. */ (function (f, define) { define('kendo.binder', [ 'kendo.core', 'kendo.data' ], f); }(function () { var __meta__ = { id: 'binder', name: 'MVVM', category: 'framework', description: 'Model View ViewModel (MVVM) is a design pattern which helps developers separate the Model (the data) from the View (the UI).', depends: [ 'core', 'data' ] }; (function ($, undefined) { var kendo = window.kendo, Observable = kendo.Observable, ObservableObject = kendo.data.ObservableObject, ObservableArray = kendo.data.ObservableArray, toString = {}.toString, binders = {}, Class = kendo.Class, proxy = $.proxy, VALUE = 'value', SOURCE = 'source', EVENTS = 'events', CHECKED = 'checked', CSS = 'css', deleteExpando = true, FUNCTION = 'function', CHANGE = 'change'; (function () { var a = document.createElement('a'); try { delete a.test; } catch (e) { deleteExpando = false; } }()); var Binding = Observable.extend({ init: function (parents, path) { var that = this; Observable.fn.init.call(that); that.source = parents[0]; that.parents = parents; that.path = path; that.dependencies = {}; that.dependencies[path] = true; that.observable = that.source instanceof Observable; that._access = function (e) { that.dependencies[e.field] = true; }; if (that.observable) { that._change = function (e) { that.change(e); }; that.source.bind(CHANGE, that._change); } }, _parents: function () { var parents = this.parents; var value = this.get(); if (value && typeof value.parent == 'function') { var parent = value.parent(); if ($.inArray(parent, parents) < 0) { parents = [parent].concat(parents); } } return parents; }, change: function (e) { var dependency, ch, field = e.field, that = this; if (that.path === 'this') { that.trigger(CHANGE, e); } else { for (dependency in that.dependencies) { if (dependency.indexOf(field) === 0) { ch = dependency.charAt(field.length); if (!ch || ch === '.' || ch === '[') { that.trigger(CHANGE, e); break; } } } } }, start: function (source) { source.bind('get', this._access); }, stop: function (source) { source.unbind('get', this._access); }, get: function () { var that = this, source = that.source, index = 0, path = that.path, result = source; if (!that.observable) { return result; } that.start(that.source); result = source.get(path); while (result === undefined && source) { source = that.parents[++index]; if (source instanceof ObservableObject) { result = source.get(path); } } if (result === undefined) { source = that.source; while (result === undefined && source) { source = source.parent(); if (source instanceof ObservableObject) { result = source.get(path); } } } if (typeof result === 'function') { index = path.lastIndexOf('.'); if (index > 0) { source = source.get(path.substring(0, index)); } that.start(source); if (source !== that.source) { result = result.call(source, that.source); } else { result = result.call(source); } that.stop(source); } if (source && source !== that.source) { that.currentSource = source; source.unbind(CHANGE, that._change).bind(CHANGE, that._change); } that.stop(that.source); return result; }, set: function (value) { var source = this.currentSource || this.source; var field = kendo.getter(this.path)(source); if (typeof field === 'function') { if (source !== this.source) { field.call(source, this.source, value); } else { field.call(source, value); } } else { source.set(this.path, value); } }, destroy: function () { if (this.observable) { this.source.unbind(CHANGE, this._change); if (this.currentSource) { this.currentSource.unbind(CHANGE, this._change); } } this.unbind(); } }); var EventBinding = Binding.extend({ get: function () { var source = this.source, path = this.path, index = 0, handler; handler = source.get(path); while (!handler && source) { source = this.parents[++index]; if (source instanceof ObservableObject) { handler = source.get(path); } } return proxy(handler, source); } }); var TemplateBinding = Binding.extend({ init: function (source, path, template) { var that = this; Binding.fn.init.call(that, source, path); that.template = template; }, render: function (value) { var html; this.start(this.source); html = kendo.render(this.template, value); this.stop(this.source); return html; } }); var Binder = Class.extend({ init: function (element, bindings, options) { this.element = element; this.bindings = bindings; this.options = options; }, bind: function (binding, attribute) { var that = this; binding = attribute ? binding[attribute] : binding; binding.bind(CHANGE, function (e) { that.refresh(attribute || e); }); that.refresh(attribute); }, destroy: function () { } }); var TypedBinder = Binder.extend({ dataType: function () { var dataType = this.element.getAttribute('data-type') || this.element.type || 'text'; return dataType.toLowerCase(); }, parsedValue: function () { return this._parseValue(this.element.value, this.dataType()); }, _parseValue: function (value, dataType) { if (dataType == 'date') { value = kendo.parseDate(value, 'yyyy-MM-dd'); } else if (dataType == 'datetime-local') { value = kendo.parseDate(value, [ 'yyyy-MM-ddTHH:mm:ss', 'yyyy-MM-ddTHH:mm' ]); } else if (dataType == 'number') { value = kendo.parseFloat(value); } else if (dataType == 'boolean') { value = value.toLowerCase(); if (kendo.parseFloat(value) !== null) { value = Boolean(kendo.parseFloat(value)); } else { value = value.toLowerCase() === 'true'; } } return value; } }); binders.attr = Binder.extend({ refresh: function (key) { this.element.setAttribute(key, this.bindings.attr[key].get()); } }); binders.css = Binder.extend({ init: function (element, bindings, options) { Binder.fn.init.call(this, element, bindings, options); this.classes = {}; }, refresh: function (className) { var element = $(this.element), binding = this.bindings.css[className], hasClass = this.classes[className] = binding.get(); if (hasClass) { element.addClass(className); } else { element.removeClass(className); } } }); binders.style = Binder.extend({ refresh: function (key) { this.element.style[key] = this.bindings.style[key].get() || ''; } }); binders.enabled = Binder.extend({ refresh: function () { if (this.bindings.enabled.get()) { this.element.removeAttribute('disabled'); } else { this.element.setAttribute('disabled', 'disabled'); } } }); binders.readonly = Binder.extend({ refresh: function () { if (this.bindings.readonly.get()) { this.element.setAttribute('readonly', 'readonly'); } else { this.element.removeAttribute('readonly'); } } }); binders.disabled = Binder.extend({ refresh: function () { if (this.bindings.disabled.get()) { this.element.setAttribute('disabled', 'disabled'); } else { this.element.removeAttribute('disabled'); } } }); binders.events = Binder.extend({ init: function (element, bindings, options) { Binder.fn.init.call(this, element, bindings, options); this.handlers = {}; }, refresh: function (key) { var element = $(this.element), binding = this.bindings.events[key], handler = this.handlers[key]; if (handler) { element.off(key, handler); } handler = this.handlers[key] = binding.get(); element.on(key, binding.source, handler); }, destroy: function () { var element = $(this.element), handler; for (handler in this.handlers) { element.off(handler, this.handlers[handler]); } } }); binders.text = Binder.extend({ refresh: function () { var text = this.bindings.text.get(); var dataFormat = this.element.getAttribute('data-format') || ''; if (text == null) { text = ''; } $(this.element).text(kendo.toString(text, dataFormat)); } }); binders.visible = Binder.extend({ refresh: function () { if (this.bindings.visible.get()) { this.element.style.display = ''; } else { this.element.style.display = 'none'; } } }); binders.invisible = Binder.extend({ refresh: function () { if (!this.bindings.invisible.get()) { this.element.style.display = ''; } else { this.element.style.display = 'none'; } } }); binders.html = Binder.extend({ refresh: function () { this.element.innerHTML = this.bindings.html.get(); } }); binders.value = TypedBinder.extend({ init: function (element, bindings, options) { TypedBinder.fn.init.call(this, element, bindings, options); this._change = proxy(this.change, this); this.eventName = options.valueUpdate || CHANGE; $(this.element).on(this.eventName, this._change); this._initChange = false; }, change: function () { this._initChange = this.eventName != CHANGE; this.bindings[VALUE].set(this.parsedValue()); this._initChange = false; }, refresh: function () { if (!this._initChange) { var value = this.bindings[VALUE].get(); if (value == null) { value = ''; } var type = this.dataType(); if (type == 'date') { value = kendo.toString(value, 'yyyy-MM-dd'); } else if (type == 'datetime-local') { value = kendo.toString(value, 'yyyy-MM-ddTHH:mm:ss'); } this.element.value = value; } this._initChange = false; }, destroy: function () { $(this.element).off(this.eventName, this._change); } }); binders.source = Binder.extend({ init: function (element, bindings, options) { Binder.fn.init.call(this, element, bindings, options); var source = this.bindings.source.get(); if (source instanceof kendo.data.DataSource && options.autoBind !== false) { source.fetch(); } }, refresh: function (e) { var that = this, source = that.bindings.source.get(); if (source instanceof ObservableArray || source instanceof kendo.data.DataSource) { e = e || {}; if (e.action == 'add') { that.add(e.index, e.items); } else if (e.action == 'remove') { that.remove(e.index, e.items); } else if (e.action != 'itemchange') { that.render(); } } else { that.render(); } }, container: function () { var element = this.element; if (element.nodeName.toLowerCase() == 'table') { if (!element.tBodies[0]) { element.appendChild(document.createElement('tbody')); } element = element.tBodies[0]; } return element; }, template: function () { var options = this.options, template = options.template, nodeName = this.container().nodeName.toLowerCase(); if (!template) { if (nodeName == 'select') { if (options.valueField || options.textField) { template = kendo.format('', options.valueField || options.textField, options.textField || options.valueField); } else { template = ''; } } else if (nodeName == 'tbody') { template = '#:data#'; } else if (nodeName == 'ul' || nodeName == 'ol') { template = '
  • #:data#
  • '; } else { template = '#:data#'; } template = kendo.template(template); } return template; }, add: function (index, items) { var element = this.container(), parents, idx, length, child, clone = element.cloneNode(false), reference = element.children[index]; $(clone).html(kendo.render(this.template(), items)); if (clone.children.length) { parents = this.bindings.source._parents(); for (idx = 0, length = items.length; idx < length; idx++) { child = clone.children[0]; element.insertBefore(child, reference || null); bindElement(child, items[idx], this.options.roles, [items[idx]].concat(parents)); } } }, remove: function (index, items) { var idx, element = this.container(); for (idx = 0; idx < items.length; idx++) { var child = element.children[index]; unbindElementTree(child, true); element.removeChild(child); } }, render: function () { var source = this.bindings.source.get(), parents, idx, length, element = this.container(), template = this.template(); if (source == null) { return; } if (source instanceof kendo.data.DataSource) { source = source.view(); } if (!(source instanceof ObservableArray) && toString.call(source) !== '[object Array]') { source = [source]; } if (this.bindings.template) { unbindElementChildren(element, true); $(element).html(this.bindings.template.render(source)); if (element.children.length) { parents = this.bindings.source._parents(); for (idx = 0, length = source.length; idx < length; idx++) { bindElement(element.children[idx], source[idx], this.options.roles, [source[idx]].concat(parents)); } } } else { $(element).html(kendo.render(template, source)); } } }); binders.input = { checked: TypedBinder.extend({ init: function (element, bindings, options) { TypedBinder.fn.init.call(this, element, bindings, options); this._change = proxy(this.change, this); $(this.element).change(this._change); }, change: function () { var element = this.element; var value = this.value(); if (element.type == 'radio') { value = this.parsedValue(); this.bindings[CHECKED].set(value); } else if (element.type == 'checkbox') { var source = this.bindings[CHECKED].get(); var index; if (source instanceof ObservableArray) { value = this.parsedValue(); if (value instanceof Date) { for (var i = 0; i < source.length; i++) { if (source[i] instanceof Date && +source[i] === +value) { index = i; break; } } } else { index = source.indexOf(value); } if (index > -1) { source.splice(index, 1); } else { source.push(value); } } else { this.bindings[CHECKED].set(value); } } }, refresh: function () { var value = this.bindings[CHECKED].get(), source = value, type = this.dataType(), element = this.element; if (element.type == 'checkbox') { if (source instanceof ObservableArray) { var index = -1; value = this.parsedValue(); if (value instanceof Date) { for (var i = 0; i < source.length; i++) { if (source[i] instanceof Date && +source[i] === +value) { index = i; break; } } } else { index = source.indexOf(value); } element.checked = index >= 0; } else { element.checked = source; } } else if (element.type == 'radio' && value != null) { if (type == 'date') { value = kendo.toString(value, 'yyyy-MM-dd'); } else if (type == 'datetime-local') { value = kendo.toString(value, 'yyyy-MM-ddTHH:mm:ss'); } if (element.value === value.toString()) { element.checked = true; } else { element.checked = false; } } }, value: function () { var element = this.element, value = element.value; if (element.type == 'checkbox') { value = element.checked; } return value; }, destroy: function () { $(this.element).off(CHANGE, this._change); } }) }; binders.select = { source: binders.source.extend({ refresh: function (e) { var that = this, source = that.bindings.source.get(); if (source instanceof ObservableArray || source instanceof kendo.data.DataSource) { e = e || {}; if (e.action == 'add') { that.add(e.index, e.items); } else if (e.action == 'remove') { that.remove(e.index, e.items); } else if (e.action == 'itemchange' || e.action === undefined) { that.render(); if (that.bindings.value) { if (that.bindings.value) { var val = retrievePrimitiveValues(that.bindings.value.get(), $(that.element).data('valueField')); if (val === null) { that.element.selectedIndex = -1; } else { that.element.value = val; } } } } } else { that.render(); } } }), value: TypedBinder.extend({ init: function (target, bindings, options) { TypedBinder.fn.init.call(this, target, bindings, options); this._change = proxy(this.change, this); $(this.element).change(this._change); }, parsedValue: function () { var dataType = this.dataType(); var values = []; var value, option, idx, length; for (idx = 0, length = this.element.options.length; idx < length; idx++) { option = this.element.options[idx]; if (option.selected) { value = option.attributes.value; if (value && value.specified) { value = option.value; } else { value = option.text; } values.push(this._parseValue(value, dataType)); } } return values; }, change: function () { var values = [], element = this.element, source, field = this.options.valueField || this.options.textField, valuePrimitive = this.options.valuePrimitive, option, valueIndex, value, idx, length; for (idx = 0, length = element.options.length; idx < length; idx++) { option = element.options[idx]; if (option.selected) { value = option.attributes.value; if (value && value.specified) { value = option.value; } else { value = option.text; } values.push(this._parseValue(value, this.dataType())); } } if (field) { source = this.bindings.source.get(); if (source instanceof kendo.data.DataSource) { source = source.view(); } for (valueIndex = 0; valueIndex < values.length; valueIndex++) { for (idx = 0, length = source.length; idx < length; idx++) { var sourceValue = this._parseValue(source[idx].get(field), this.dataType()); var match = String(sourceValue) === values[valueIndex]; if (match) { values[valueIndex] = source[idx]; break; } } } } value = this.bindings[VALUE].get(); if (value instanceof ObservableArray) { value.splice.apply(value, [ 0, value.length ].concat(values)); } else if (!valuePrimitive && (value instanceof ObservableObject || value === null || value === undefined || !field)) { this.bindings[VALUE].set(values[0]); } else { this.bindings[VALUE].set(values[0].get(field)); } }, refresh: function () { var optionIndex, element = this.element, options = element.options, value = this.bindings[VALUE].get(), values = value, field = this.options.valueField || this.options.textField, found = false, type = this.dataType(), optionValue; if (!(values instanceof ObservableArray)) { values = new ObservableArray([value]); } element.selectedIndex = -1; for (var valueIndex = 0; valueIndex < values.length; valueIndex++) { value = values[valueIndex]; if (field && value instanceof ObservableObject) { value = value.get(field); } if (type == 'date') { value = kendo.toString(values[valueIndex], 'yyyy-MM-dd'); } else if (type == 'datetime-local') { value = kendo.toString(values[valueIndex], 'yyyy-MM-ddTHH:mm:ss'); } for (optionIndex = 0; optionIndex < options.length; optionIndex++) { optionValue = options[optionIndex].value; if (optionValue === '' && value !== '') { optionValue = options[optionIndex].text; } if (value != null && optionValue == value.toString()) { options[optionIndex].selected = true; found = true; } } } }, destroy: function () { $(this.element).off(CHANGE, this._change); } }) }; function dataSourceBinding(bindingName, fieldName, setter) { return Binder.extend({ init: function (widget, bindings, options) { var that = this; Binder.fn.init.call(that, widget.element[0], bindings, options); that.widget = widget; that._dataBinding = proxy(that.dataBinding, that); that._dataBound = proxy(that.dataBound, that); that._itemChange = proxy(that.itemChange, that); }, itemChange: function (e) { bindElement(e.item[0], e.data, this._ns(e.ns), [e.data].concat(this.bindings[bindingName]._parents())); }, dataBinding: function (e) { var idx, length, widget = this.widget, items = e.removedItems || widget.items(); for (idx = 0, length = items.length; idx < length; idx++) { unbindElementTree(items[idx], false); } }, _ns: function (ns) { ns = ns || kendo.ui; var all = [ kendo.ui, kendo.dataviz.ui, kendo.mobile.ui ]; all.splice($.inArray(ns, all), 1); all.unshift(ns); return kendo.rolesFromNamespaces(all); }, dataBound: function (e) { var idx, length, widget = this.widget, items = e.addedItems || widget.items(), dataSource = widget[fieldName], view, parents, hds = kendo.data.HierarchicalDataSource; if (hds && dataSource instanceof hds) { return; } if (items.length) { view = e.addedDataItems || dataSource.flatView(); parents = this.bindings[bindingName]._parents(); for (idx = 0, length = view.length; idx < length; idx++) { bindElement(items[idx], view[idx], this._ns(e.ns), [view[idx]].concat(parents)); } } }, refresh: function (e) { var that = this, source, widget = that.widget, select, multiselect; e = e || {}; if (!e.action) { that.destroy(); widget.bind('dataBinding', that._dataBinding); widget.bind('dataBound', that._dataBound); widget.bind('itemChange', that._itemChange); source = that.bindings[bindingName].get(); if (widget[fieldName] instanceof kendo.data.DataSource && widget[fieldName] != source) { if (source instanceof kendo.data.DataSource) { widget[setter](source); } else if (source && source._dataSource) { widget[setter](source._dataSource); } else { widget[fieldName].data(source); select = kendo.ui.Select && widget instanceof kendo.ui.Select; multiselect = kendo.ui.MultiSelect && widget instanceof kendo.ui.MultiSelect; if (that.bindings.value && (select || multiselect)) { widget.value(retrievePrimitiveValues(that.bindings.value.get(), widget.options.dataValueField)); } } } } }, destroy: function () { var widget = this.widget; widget.unbind('dataBinding', this._dataBinding); widget.unbind('dataBound', this._dataBound); widget.unbind('itemChange', this._itemChange); } }); } binders.widget = { events: Binder.extend({ init: function (widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this.widget = widget; this.handlers = {}; }, refresh: function (key) { var binding = this.bindings.events[key], handler = this.handlers[key]; if (handler) { this.widget.unbind(key, handler); } handler = binding.get(); this.handlers[key] = function (e) { e.data = binding.source; handler(e); if (e.data === binding.source) { delete e.data; } }; this.widget.bind(key, this.handlers[key]); }, destroy: function () { var handler; for (handler in this.handlers) { this.widget.unbind(handler, this.handlers[handler]); } } }), checked: Binder.extend({ init: function (widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this.widget = widget; this._change = proxy(this.change, this); this.widget.bind(CHANGE, this._change); }, change: function () { this.bindings[CHECKED].set(this.value()); }, refresh: function () { this.widget.check(this.bindings[CHECKED].get() === true); }, value: function () { var element = this.element, value = element.value; if (value == 'on' || value == 'off') { value = element.checked; } return value; }, destroy: function () { this.widget.unbind(CHANGE, this._change); } }), visible: Binder.extend({ init: function (widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this.widget = widget; }, refresh: function () { var visible = this.bindings.visible.get(); this.widget.wrapper[0].style.display = visible ? '' : 'none'; } }), invisible: Binder.extend({ init: function (widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this.widget = widget; }, refresh: function () { var invisible = this.bindings.invisible.get(); this.widget.wrapper[0].style.display = invisible ? 'none' : ''; } }), enabled: Binder.extend({ init: function (widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this.widget = widget; }, refresh: function () { if (this.widget.enable) { this.widget.enable(this.bindings.enabled.get()); } } }), disabled: Binder.extend({ init: function (widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this.widget = widget; }, refresh: function () { if (this.widget.enable) { this.widget.enable(!this.bindings.disabled.get()); } } }), source: dataSourceBinding('source', 'dataSource', 'setDataSource'), value: Binder.extend({ init: function (widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this.widget = widget; this._change = $.proxy(this.change, this); this.widget.first(CHANGE, this._change); var value = this.bindings.value.get(); this._valueIsObservableObject = !options.valuePrimitive && (value == null || value instanceof ObservableObject); this._valueIsObservableArray = value instanceof ObservableArray; this._initChange = false; }, _source: function () { var source; if (this.widget.dataItem) { source = this.widget.dataItem(); if (source && source instanceof ObservableObject) { return [source]; } } if (this.bindings.source) { source = this.bindings.source.get(); } if (!source || source instanceof kendo.data.DataSource) { source = this.widget.dataSource.flatView(); } return source; }, change: function () { var value = this.widget.value(), field = this.options.dataValueField || this.options.dataTextField, isArray = toString.call(value) === '[object Array]', isObservableObject = this._valueIsObservableObject, valueIndex, valueLength, values = [], sourceItem, sourceValue, idx, length, source; this._initChange = true; if (field) { if (value === '' && (isObservableObject || this.options.valuePrimitive)) { value = null; } else { source = this._source(); if (isArray) { valueLength = value.length; values = value.slice(0); } for (idx = 0, length = source.length; idx < length; idx++) { sourceItem = source[idx]; sourceValue = sourceItem.get(field); if (isArray) { for (valueIndex = 0; valueIndex < valueLength; valueIndex++) { if (sourceValue == values[valueIndex]) { values[valueIndex] = sourceItem; break; } } } else if (sourceValue == value) { value = isObservableObject ? sourceItem : sourceValue; break; } } if (values[0]) { if (this._valueIsObservableArray) { value = values; } else if (isObservableObject || !field) { value = values[0]; } else { value = values[0].get(field); } } } } this.bindings.value.set(value); this._initChange = false; }, refresh: function () { if (!this._initChange) { var widget = this.widget; var options = widget.options; var textField = options.dataTextField; var valueField = options.dataValueField || textField; var value = this.bindings.value.get(); var text = options.text || ''; var idx = 0, length; var values = []; if (value === undefined) { value = null; } if (valueField) { if (value instanceof ObservableArray) { for (length = value.length; idx < length; idx++) { values[idx] = value[idx].get(valueField); } value = values; } else if (value instanceof ObservableObject) { text = value.get(textField); value = value.get(valueField); } } if (options.autoBind === false && !options.cascadeFrom && widget.listView && !widget.listView.bound()) { if (textField === valueField && !text) { text = value; } if (!text && (value || value === 0) && options.valuePrimitive) { widget.value(value); } else { widget._preselect(value, text); } } else { widget.value(value); } } this._initChange = false; }, destroy: function () { this.widget.unbind(CHANGE, this._change); } }), gantt: { dependencies: dataSourceBinding('dependencies', 'dependencies', 'setDependenciesDataSource') }, multiselect: { value: Binder.extend({ init: function (widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this.widget = widget; this._change = $.proxy(this.change, this); this.widget.first(CHANGE, this._change); this._initChange = false; }, change: function () { var that = this, oldValues = that.bindings[VALUE].get(), valuePrimitive = that.options.valuePrimitive, newValues = valuePrimitive ? that.widget.value() : that.widget.dataItems(); var field = this.options.dataValueField || this.options.dataTextField; newValues = newValues.slice(0); that._initChange = true; if (oldValues instanceof ObservableArray) { var remove = []; var newLength = newValues.length; var i = 0, j = 0; var old = oldValues[i]; var same = false; var removeIndex; var newValue; var found; while (old !== undefined) { found = false; for (j = 0; j < newLength; j++) { if (valuePrimitive) { same = newValues[j] == old; } else { newValue = newValues[j]; newValue = newValue.get ? newValue.get(field) : newValue; same = newValue == (old.get ? old.get(field) : old); } if (same) { newValues.splice(j, 1); newLength -= 1; found = true; break; } } if (!found) { remove.push(old); arraySplice(oldValues, i, 1); removeIndex = i; } else { i += 1; } old = oldValues[i]; } arraySplice(oldValues, oldValues.length, 0, newValues); if (remove.length) { oldValues.trigger('change', { action: 'remove', items: remove, index: removeIndex }); } if (newValues.length) { oldValues.trigger('change', { action: 'add', items: newValues, index: oldValues.length - 1 }); } } else { that.bindings[VALUE].set(newValues); } that._initChange = false; }, refresh: function () { if (!this._initChange) { var options = this.options, widget = this.widget, field = options.dataValueField || options.dataTextField, value = this.bindings.value.get(), data = value, idx = 0, length, values = [], selectedValue; if (value === undefined) { value = null; } if (field) { if (value instanceof ObservableArray) { for (length = value.length; idx < length; idx++) { selectedValue = value[idx]; values[idx] = selectedValue.get ? selectedValue.get(field) : selectedValue; } value = values; } else if (value instanceof ObservableObject) { value = value.get(field); } } if (options.autoBind === false && options.valuePrimitive !== true && !widget._isBound()) { widget._preselect(data, value); } else { widget.value(value); } } }, destroy: function () { this.widget.unbind(CHANGE, this._change); } }) }, scheduler: { source: dataSourceBinding('source', 'dataSource', 'setDataSource').extend({ dataBound: function (e) { var idx; var length; var widget = this.widget; var elements = e.addedItems || widget.items(); var data, parents; if (elements.length) { data = e.addedDataItems || widget.dataItems(); parents = this.bindings.source._parents(); for (idx = 0, length = data.length; idx < length; idx++) { bindElement(elements[idx], data[idx], this._ns(e.ns), [data[idx]].concat(parents)); } } } }) } }; var arraySplice = function (arr, idx, remove, add) { add = add || []; remove = remove || 0; var addLength = add.length; var oldLength = arr.length; var shifted = [].slice.call(arr, idx + remove); var shiftedLength = shifted.length; var index; if (addLength) { addLength = idx + addLength; index = 0; for (; idx < addLength; idx++) { arr[idx] = add[index]; index++; } arr.length = addLength; } else if (remove) { arr.length = idx; remove += idx; while (idx < remove) { delete arr[--remove]; } } if (shiftedLength) { shiftedLength = idx + shiftedLength; index = 0; for (; idx < shiftedLength; idx++) { arr[idx] = shifted[index]; index++; } arr.length = shiftedLength; } idx = arr.length; while (idx < oldLength) { delete arr[idx]; idx++; } }; var BindingTarget = Class.extend({ init: function (target, options) { this.target = target; this.options = options; this.toDestroy = []; }, bind: function (bindings) { var key, hasValue, hasSource, hasEvents, hasChecked, hasCss, widgetBinding = this instanceof WidgetBindingTarget, specificBinders = this.binders(); for (key in bindings) { if (key == VALUE) { hasValue = true; } else if (key == SOURCE) { hasSource = true; } else if (key == EVENTS && !widgetBinding) { hasEvents = true; } else if (key == CHECKED) { hasChecked = true; } else if (key == CSS) { hasCss = true; } else { this.applyBinding(key, bindings, specificBinders); } } if (hasSource) { this.applyBinding(SOURCE, bindings, specificBinders); } if (hasValue) { this.applyBinding(VALUE, bindings, specificBinders); } if (hasChecked) { this.applyBinding(CHECKED, bindings, specificBinders); } if (hasEvents && !widgetBinding) { this.applyBinding(EVENTS, bindings, specificBinders); } if (hasCss && !widgetBinding) { this.applyBinding(CSS, bindings, specificBinders); } }, binders: function () { return binders[this.target.nodeName.toLowerCase()] || {}; }, applyBinding: function (name, bindings, specificBinders) { var binder = specificBinders[name] || binders[name], toDestroy = this.toDestroy, attribute, binding = bindings[name]; if (binder) { binder = new binder(this.target, bindings, this.options); toDestroy.push(binder); if (binding instanceof Binding) { binder.bind(binding); toDestroy.push(binding); } else { for (attribute in binding) { binder.bind(binding, attribute); toDestroy.push(binding[attribute]); } } } else if (name !== 'template') { throw new Error('The ' + name + ' binding is not supported by the ' + this.target.nodeName.toLowerCase() + ' element'); } }, destroy: function () { var idx, length, toDestroy = this.toDestroy; for (idx = 0, length = toDestroy.length; idx < length; idx++) { toDestroy[idx].destroy(); } } }); var WidgetBindingTarget = BindingTarget.extend({ binders: function () { return binders.widget[this.target.options.name.toLowerCase()] || {}; }, applyBinding: function (name, bindings, specificBinders) { var binder = specificBinders[name] || binders.widget[name], toDestroy = this.toDestroy, attribute, binding = bindings[name]; if (binder) { binder = new binder(this.target, bindings, this.target.options); toDestroy.push(binder); if (binding instanceof Binding) { binder.bind(binding); toDestroy.push(binding); } else { for (attribute in binding) { binder.bind(binding, attribute); toDestroy.push(binding[attribute]); } } } else { throw new Error('The ' + name + ' binding is not supported by the ' + this.target.options.name + ' widget'); } } }); function bindingTargetForRole(element, roles) { var widget = kendo.initWidget(element, {}, roles); if (widget) { return new WidgetBindingTarget(widget); } } var keyValueRegExp = /[A-Za-z0-9_\-]+:(\{([^}]*)\}|[^,}]+)/g, whiteSpaceRegExp = /\s/g; function parseBindings(bind) { var result = {}, idx, length, token, colonIndex, key, value, tokens; tokens = bind.match(keyValueRegExp); for (idx = 0, length = tokens.length; idx < length; idx++) { token = tokens[idx]; colonIndex = token.indexOf(':'); key = token.substring(0, colonIndex); value = token.substring(colonIndex + 1); if (value.charAt(0) == '{') { value = parseBindings(value); } result[key] = value; } return result; } function createBindings(bindings, source, type) { var binding, result = {}; for (binding in bindings) { result[binding] = new type(source, bindings[binding]); } return result; } function bindElement(element, source, roles, parents) { var role = element.getAttribute('data-' + kendo.ns + 'role'), idx, bind = element.getAttribute('data-' + kendo.ns + 'bind'), children = element.children, childrenCopy = [], deep = true, bindings, options = {}, target; parents = parents || [source]; if (role || bind) { unbindElement(element, false); } if (role) { target = bindingTargetForRole(element, roles); } if (bind) { bind = parseBindings(bind.replace(whiteSpaceRegExp, '')); if (!target) { options = kendo.parseOptions(element, { textField: '', valueField: '', template: '', valueUpdate: CHANGE, valuePrimitive: false, autoBind: true }); options.roles = roles; target = new BindingTarget(element, options); } target.source = source; bindings = createBindings(bind, parents, Binding); if (options.template) { bindings.template = new TemplateBinding(parents, '', options.template); } if (bindings.click) { bind.events = bind.events || {}; bind.events.click = bind.click; bindings.click.destroy(); delete bindings.click; } if (bindings.source) { deep = false; } if (bind.attr) { bindings.attr = createBindings(bind.attr, parents, Binding); } if (bind.style) { bindings.style = createBindings(bind.style, parents, Binding); } if (bind.events) { bindings.events = createBindings(bind.events, parents, EventBinding); } if (bind.css) { bindings.css = createBindings(bind.css, parents, Binding); } target.bind(bindings); } if (target) { element.kendoBindingTarget = target; } if (deep && children) { for (idx = 0; idx < children.length; idx++) { childrenCopy[idx] = children[idx]; } for (idx = 0; idx < childrenCopy.length; idx++) { bindElement(childrenCopy[idx], source, roles, parents); } } } function bind(dom, object) { var idx, length, node, roles = kendo.rolesFromNamespaces([].slice.call(arguments, 2)); object = kendo.observable(object); dom = $(dom); for (idx = 0, length = dom.length; idx < length; idx++) { node = dom[idx]; if (node.nodeType === 1) { bindElement(node, object, roles); } } } function unbindElement(element, destroyWidget) { var bindingTarget = element.kendoBindingTarget; if (bindingTarget) { bindingTarget.destroy(); if (deleteExpando) { delete element.kendoBindingTarget; } else if (element.removeAttribute) { element.removeAttribute('kendoBindingTarget'); } else { element.kendoBindingTarget = null; } } if (destroyWidget) { var widget = kendo.widgetInstance($(element)); if (widget && typeof widget.destroy === FUNCTION) { widget.destroy(); } } } function unbindElementTree(element, destroyWidgets) { unbindElement(element, destroyWidgets); unbindElementChildren(element, destroyWidgets); } function unbindElementChildren(element, destroyWidgets) { var children = element.children; if (children) { for (var idx = 0, length = children.length; idx < length; idx++) { unbindElementTree(children[idx], destroyWidgets); } } } function unbind(dom) { var idx, length; dom = $(dom); for (idx = 0, length = dom.length; idx < length; idx++) { unbindElementTree(dom[idx], false); } } function notify(widget, namespace) { var element = widget.element, bindingTarget = element[0].kendoBindingTarget; if (bindingTarget) { bind(element, bindingTarget.source, namespace); } } function retrievePrimitiveValues(value, valueField) { var values = []; var idx = 0; var length; var item; if (!valueField) { return value; } if (value instanceof ObservableArray) { for (length = value.length; idx < length; idx++) { item = value[idx]; values[idx] = item.get ? item.get(valueField) : item[valueField]; } value = values; } else if (value instanceof ObservableObject) { value = value.get(valueField); } return value; } kendo.unbind = unbind; kendo.bind = bind; kendo.data.binders = binders; kendo.data.Binder = Binder; kendo.notify = notify; kendo.observable = function (object) { if (!(object instanceof ObservableObject)) { object = new ObservableObject(object); } return object; }; kendo.observableHierarchy = function (array) { var dataSource = kendo.data.HierarchicalDataSource.create(array); function recursiveRead(data) { var i, children; for (i = 0; i < data.length; i++) { data[i]._initChildren(); children = data[i].children; children.fetch(); data[i].items = children.data(); recursiveRead(data[i].items); } } dataSource.fetch(); recursiveRead(dataSource.data()); dataSource._data._dataSource = dataSource; return dataSource._data; }; }(window.kendo.jQuery)); return window.kendo; }, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) { (a3 || a2)(); }));