UNPKG

@progress/kendo-ui

Version:

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

1,447 lines (1,180 loc) 72.7 kB
import './kendo.core.js'; import './kendo.data.js'; import './kendo.licensing.js'; import '@progress/kendo-licensing'; import './kendo.data.odata.js'; import './kendo.data.xml.js'; const __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$1) { var kendo = window.kendo, encode = kendo.htmlEncode, Observable = kendo.Observable, ObservableObject = kendo.data.ObservableObject, ObservableArray = kendo.data.ObservableArray, toString = {}.toString, binders = {}, Class = kendo.Class, 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); // Traverse the observable hierarchy if the binding is not resolved at the current level. while (result === undefined$1 && source) { source = that.parents[++index]; if (source instanceof ObservableObject) { result = source.get(path); } } // second pass try to get the parent from the object hierarchy if (result === undefined$1) { source = that.source; //get the initial source while (result === undefined$1 && source) { source = source.parent(); if (source instanceof ObservableObject) { result = source.get(path); } } } // If the result is a function - invoke it if (typeof result === "function") { index = path.lastIndexOf("."); // If the function is a member of a nested observable object make that nested observable the context (this) of the function if (index > 0) { source = source.get(path.substring(0, index)); } // Invoke the function that.start(source); if (source !== that.source) { result = result.call(source, that.source); } else { result = result.call(source); } that.stop(source); } // If the binding is resolved by a parent object if (source && source !== that.source) { that.currentSource = source; // save parent object // Listen for changes in the parent object 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); } } if (!handler) { return; } return handler.bind(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-" + kendo.ns + "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-" + kendo.ns + "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 = this.change.bind(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 = (data) => { const valueAttr = kendo.getter(options.valueField || options.textField)(data); const innerText = kendo.getter(options.textField || options.valueField)(data); return `<option value="${encode(valueAttr)}">${encode(innerText)}</option>`; }; } else { template = (data) => `<option>${encode(data)}</option>`; } } else if (nodeName == "tbody") { template = (data) => `<tr><td>${encode(data)}</td></tr>`; } else if (nodeName == "ul" || nodeName == "ol") { template = (data) => `<li>${encode(data)}</li>`; } else { template = (data) => `${encode(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); if (child.parentNode == element) { 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 = this.change.bind(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") { 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 (value !== null && typeof(value) !== "undefined" && 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$1) { 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 = this.change.bind(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; } if (field) { values.push(value); } else { 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 = source[idx].get(field); 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$1 || !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, 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; } } } }, 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 = that.dataBinding.bind(that); that._dataBound = that.dataBound.bind(that); that._itemChange = that.itemChange.bind(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) { // suppress binding of HDS items, because calling view() on root // will return only root items, and widget.items() returns all items return; } if (items.length) { view = e.addedDataItems || dataSource.flatView(); parents = this.bindings[bindingName]._parents(); for (idx = 0, length = view.length; idx < length; idx++) { if (items[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, dropdowntree; 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 && source) { if (source instanceof kendo.data.DataSource) { widget[setter](source); } else if (source._dataSource) { widget[setter](source._dataSource); } else { select = kendo.ui.Select && widget instanceof kendo.ui.Select; multiselect = kendo.ui.MultiSelect && widget instanceof kendo.ui.MultiSelect; dropdowntree = kendo.ui.DropDownTree && widget instanceof kendo.ui.DropDownTree; if (!dropdowntree) { widget[fieldName].data(source); } else { widget.treeview[fieldName].data(source); } 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(); if (handler) { 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 = this.change.bind(this); this.widget.bind(CHANGE, this._change); }, change: function() { this.bindings[CHECKED].set(this.value()); }, refresh: function() { var val = this.bindings[CHECKED].get(); if (this.element.type === "radio") { if (val !== undefined$1) { this.widget.check(val.toString() === this.value()); } else { this.widget.check(false); } } else { this.widget.check(val === true); } }, value: function() { var element = this.element, value = element.value; if (value == "on" || value == "off" || this.element.type == "checkbox") { value = element.checked; } return value; }, destroy: function() { this.widget.unbind(CHANGE, this._change); } }), start: Binder.extend({ init: function(widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this._change = this.change.bind(this); this.widget = widget; this.widget.bind(CHANGE, this._change); }, change: function() { this.bindings.start.set(this.widget.range().start); }, refresh: function() { var that = this; var start = this.bindings.start.get(); var end = that.widget._range ? that.widget._range.end : null; this.widget.range({ start: start, end: end }); }, destroy: function() { this.widget.unbind(CHANGE, this._change); } }), end: Binder.extend({ init: function(widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this._change = this.change.bind(this); this.widget = widget; this.widget.bind(CHANGE, this._change); }, change: function() { this.bindings.end.set(this.widget.range().end); }, refresh: function() { var that = this; var end = this.bindings.end.get(); var start = that.widget._range ? that.widget._range.start : null; this.widget.range({ start: start, end: end }); }, 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" : ""; } }), floatingLabel: Binder.extend({ init: function(widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); if (!widget.floatingLabel) { return; } widget.floatingLabel.refresh(); } }), enabled: Binder.extend({ init: function(widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this.widget = widget; this.readonly = this.element.readOnly; }, refresh: function() { if (this.widget.enable) { this.widget.enable(this.bindings.enabled.get()); } if (this.readonly && this.widget.readonly) { this.widget.readonly(this.readonly); } } }), 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 = this.change.bind(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$1) { 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); } }), dropdowntree: { value: Binder.extend({ init: function(widget, bindings, options) { Binder.fn.init.call(this, widget.element[0], bindings, options); this.widget = widget; this._change = this.change.bind(this); this.widget.first(CHANGE, this._change); this._initChange = false; }, change: function() { var that = this, oldValues = that.bindings[VALUE].get(), valuePrimitive = that.options.valuePrimitive, selectedNode = that.widget.treeview.select(), nonPrimitiveValues = that.widget._isMultipleSelection() ? that.widget._getAllChecked() : (that.widget.treeview.dataItem(selectedNode) || that.widget.value()), newValues = (valuePrimitive || that.widget.options.autoBind === false) ? that.widget.value() : nonPrimitiveValues; var field = this.options.dataValueField || this.options.dataTextField; newValues = newValues.slice ? newValues.slice(0) : newValues; 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$1) { 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 }); }