Created
February 22, 2019 21:09
-
-
Save alejandrolechuga/39353b2c429448e24ddbc3d11a369d02 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (function() { | |
| var CSS_CLASS_DELIM, QuickdrawError, VirtualDomNode, dispatchEvent, exports, qd, qdInternal, | |
| slice = [].slice, | |
| indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, | |
| hasProp = {}.hasOwnProperty; | |
| qd = {}; | |
| if (typeof window !== "undefined" && window !== null) { | |
| if (window.qd != null) { | |
| throw new Error("Quickdraw already defined on `window` - this probably isn't what you want. Check your `node_modules/` directory for multiple copies of quickdrawjs."); | |
| } else { | |
| window['qd'] = qd; | |
| } | |
| } else { | |
| if (this.qd != null) { | |
| throw new Error("Quickdraw already defined in current scope - this probably isn't what you want. Check your `node_modules/` directory for multiple copies of quickdrawjs."); | |
| } else { | |
| this.qd = qd; | |
| } | |
| } | |
| if (typeof module !== "undefined" && module !== null) { | |
| exports = module.exports = qd; | |
| } else if (exports != null) { | |
| exports.qd = qd; | |
| } else { | |
| if ((typeof define !== "undefined" && define !== null) && define.amd) { | |
| define(function() { | |
| return qd; | |
| }); | |
| } | |
| } | |
| qd._ = qdInternal = { | |
| config: { | |
| bindingAttribute: 'data-bind', | |
| maxQueuedUpdates: 25, | |
| updatesEnabled: true, | |
| updatesAsync: true, | |
| renderEnabled: true, | |
| renderAsync: true, | |
| defaultUpdateTimeout: 50, | |
| baseModelKey: 'base-view-model', | |
| nodeDataKey: '_qdData', | |
| defaultCacheSize: -1 | |
| }, | |
| state: { | |
| current: { | |
| model: null, | |
| element: null, | |
| handler: null | |
| }, | |
| binding: { | |
| functions: {}, | |
| handlers: {}, | |
| order: [] | |
| }, | |
| error: { | |
| handlers: [] | |
| }, | |
| updates: { | |
| key: null, | |
| immediate: false, | |
| queue: [] | |
| }, | |
| render: { | |
| key: null, | |
| enqueuedNodes: {}, | |
| queue: [] | |
| }, | |
| templates: { | |
| cache: null, | |
| nodes: {}, | |
| aliases: {}, | |
| html: {} | |
| } | |
| }, | |
| updateCurrentState: function(updates) { | |
| var key, oldValues, value; | |
| if (updates == null) { | |
| updates = {}; | |
| } | |
| oldValues = {}; | |
| for (key in updates) { | |
| value = updates[key]; | |
| oldValues[key] = qdInternal.state.current[key]; | |
| qdInternal.state.current[key] = value; | |
| } | |
| return function() { | |
| var results; | |
| results = []; | |
| for (key in oldValues) { | |
| value = oldValues[key]; | |
| results.push(qdInternal.state.current[key] = value); | |
| } | |
| return results; | |
| }; | |
| } | |
| }; | |
| qd.setConfig = function(configName, configValue) { | |
| qdInternal.config[configName] = configValue; | |
| }; | |
| qd.getConfig = function(configName) { | |
| var ref; | |
| return (ref = qdInternal.config[configName]) != null ? ref : null; | |
| }; | |
| qdInternal.async = { | |
| immediate: function(callback) { | |
| return qdInternal.async.delayed(callback); | |
| }, | |
| delayed: function(callback, time) { | |
| var wrappedCallback; | |
| if (time == null) { | |
| time = 0; | |
| } | |
| wrappedCallback = function() { | |
| var err; | |
| try { | |
| return callback(); | |
| } catch (error1) { | |
| err = error1; | |
| return qdInternal.errors["throw"](new QuickdrawError('Error occurred on async callback', err)); | |
| } | |
| }; | |
| return setTimeout(wrappedCallback, time); | |
| }, | |
| cancel: function(timerId) { | |
| clearTimeout(timerId); | |
| } | |
| }; | |
| qdInternal.binding = { | |
| getBindingFunction: function(node) { | |
| var bindingFunction, bindingString, err, error, functionBody, toParse; | |
| if ((node != null ? node.getAttribute : void 0) == null) { | |
| return null; | |
| } | |
| bindingString = node.getAttribute(qd.getConfig('bindingAttribute')); | |
| if (bindingString == null) { | |
| return null; | |
| } | |
| if (qdInternal.state.binding.functions[bindingString] == null) { | |
| toParse = bindingString; | |
| if (bindingString.trim()[0] !== '{') { | |
| toParse = '{' + toParse + '}'; | |
| } | |
| toParse = toParse.replace(/(with|if)\s*:/g, '\'$1\' :'); | |
| functionBody = 'with($context) {' + ' with($data) {' + ' return ' + toParse + ' }' + '}'; | |
| bindingFunction = null; | |
| try { | |
| bindingFunction = new Function('$context', '$element', functionBody); | |
| } catch (error1) { | |
| err = error1; | |
| error = new QuickdrawError("Error in parsing binding '" + toParse + "', " + err.message); | |
| error.setOriginalError(err); | |
| error.setDomNode(node); | |
| return qdInternal.errors["throw"](error); | |
| } | |
| qdInternal.state.binding.functions[bindingString] = bindingFunction; | |
| } | |
| return qdInternal.state.binding.functions[bindingString]; | |
| }, | |
| getEvaluatedBindingObject: function(domNode, bindingContext) { | |
| var bindingFunction, err, error; | |
| bindingFunction = this.getBindingFunction(domNode); | |
| if (bindingFunction == null) { | |
| return null; | |
| } | |
| try { | |
| return bindingFunction(bindingContext, qdInternal.dom.unwrap(domNode)); | |
| } catch (error1) { | |
| err = error1; | |
| error = new QuickdrawError("'" + err.message + "' in binding '" + (domNode.getAttribute(qd.getConfig('bindingAttribute'))) + "'", err); | |
| error.setBindingContext(bindingContext); | |
| qdInternal.errors["throw"](error); | |
| return null; | |
| } | |
| }, | |
| bindModel: function(viewModel, domRoot, context) { | |
| var error, stateMemento; | |
| if (viewModel == null) { | |
| return qdInternal.errors["throw"](new QuickdrawError('Attempting binding of a null View Model')); | |
| } | |
| if (domRoot == null) { | |
| return qdInternal.errors["throw"](new QuickdrawError('Attempting to bind to a null Dom Root')); | |
| } | |
| if (context == null) { | |
| return qdInternal.errors["throw"](new QuickdrawError('Attempting binding with a null context')); | |
| } | |
| if (!qdInternal.models.isModel(viewModel)) { | |
| return qdInternal.errors["throw"](new QuickdrawError('Internal binding called with non-qd view model, must use models.create')); | |
| } | |
| domRoot = qdInternal.dom.virtualize(domRoot); | |
| qdInternal.models.setParent(viewModel, qdInternal.state.current.model); | |
| stateMemento = qdInternal.updateCurrentState({ | |
| model: viewModel | |
| }); | |
| this.bindDomTree(domRoot, context); | |
| if (viewModel !== qdInternal.state.current.model) { | |
| error = new QuickdrawError('After updating view, view model and applying bindings no longer match'); | |
| error.setBindingContext(context); | |
| error.setDomNode(domRoot); | |
| error.setViewModel(viewModel); | |
| qdInternal.errors["throw"](error); | |
| } | |
| stateMemento(); | |
| }, | |
| bindDomTree: function(domRoot, bindingContext) { | |
| var child, j, len, ref; | |
| if (this.bindDomNode(domRoot, bindingContext)) { | |
| ref = domRoot.getChildren(); | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| child = ref[j]; | |
| this.bindDomTree(child, bindingContext); | |
| } | |
| } | |
| }, | |
| bindDomNode: function(domNode, bindingContext) { | |
| var bindingObject, handlers, initialize, j, len, name, ref, shouldContinue, stateMemento; | |
| shouldContinue = true; | |
| stateMemento = qdInternal.updateCurrentState({ | |
| element: domNode, | |
| handler: null | |
| }); | |
| bindingObject = this.getEvaluatedBindingObject(domNode, bindingContext); | |
| if (bindingObject == null) { | |
| stateMemento(); | |
| return shouldContinue; | |
| } | |
| handlers = {}; | |
| ref = qdInternal.state.binding.order; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| name = ref[j]; | |
| if (!bindingObject.hasOwnProperty(name)) { | |
| continue; | |
| } | |
| initialize = qdInternal.handlers.getInitialize(name); | |
| if (typeof initialize === "function") { | |
| initialize(bindingObject[name], domNode, bindingContext); | |
| } | |
| handlers[name] = true; | |
| } | |
| qdInternal.storage.setInternalValue(domNode, 'handlers', handlers); | |
| shouldContinue = this.updateDomNode(domNode, bindingContext, bindingObject); | |
| stateMemento(); | |
| return shouldContinue; | |
| }, | |
| updateDomNode: function(domNode, bindingContext, bindingObject) { | |
| var handler, handlers, j, len, ref, ref1, shouldContinue, stateMemento, update; | |
| if (bindingObject == null) { | |
| bindingObject = null; | |
| } | |
| shouldContinue = true; | |
| stateMemento = qdInternal.updateCurrentState({ | |
| element: domNode, | |
| handler: null | |
| }); | |
| if (bindingObject == null) { | |
| bindingObject = this.getEvaluatedBindingObject(domNode, bindingContext); | |
| } | |
| if (bindingObject == null) { | |
| stateMemento(); | |
| return shouldContinue; | |
| } | |
| handlers = qdInternal.storage.getInternalValue(domNode, 'handlers'); | |
| ref = qdInternal.state.binding.order; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| handler = ref[j]; | |
| if (!handlers[handler]) { | |
| continue; | |
| } | |
| update = qdInternal.handlers.getUpdate(handler); | |
| shouldContinue = ((ref1 = typeof update === "function" ? update(bindingObject[handler], domNode, bindingContext) : void 0) != null ? ref1 : true) && shouldContinue; | |
| handlers[handler] = false; | |
| } | |
| stateMemento(); | |
| return shouldContinue; | |
| }, | |
| unbindDomTree: function(domNode) { | |
| var boundHandlers, child, cleanup, handler, j, k, l, len, len1, observable, observables, ref, ref1, ref2, ref3; | |
| domNode = qdInternal.dom.virtualize(domNode); | |
| observables = (ref = qdInternal.storage.getInternalValue(domNode, 'observables')) != null ? ref : []; | |
| for (j = 0, len = observables.length; j < len; j++) { | |
| observable = observables[j]; | |
| qdInternal.observables.removeDependency.call(observable, domNode); | |
| } | |
| boundHandlers = (ref1 = qdInternal.storage.getInternalValue(domNode, 'handlers')) != null ? ref1 : []; | |
| ref2 = qdInternal.state.binding.order; | |
| for (k = ref2.length - 1; k >= 0; k += -1) { | |
| handler = ref2[k]; | |
| if (boundHandlers[handler] == null) { | |
| continue; | |
| } | |
| cleanup = qdInternal.handlers.getCleanup(handler); | |
| if (typeof cleanup === "function") { | |
| cleanup(domNode); | |
| } | |
| } | |
| domNode.clearValues(); | |
| ref3 = domNode.getChildren(); | |
| for (l = 0, len1 = ref3.length; l < len1; l++) { | |
| child = ref3[l]; | |
| this.unbindDomTree(child); | |
| } | |
| } | |
| }; | |
| qd.bindModel = function(viewModel, domRoot) { | |
| var baseContext; | |
| if (viewModel == null) { | |
| return qdInternal.errors["throw"](new QuickdrawError("Bind model called with null view model")); | |
| } | |
| viewModel = qdInternal.models.create(viewModel); | |
| baseContext = qdInternal.context.create(viewModel); | |
| qdInternal.binding.bindModel(viewModel, domRoot, baseContext); | |
| qdInternal.templates.clearCache(); | |
| qdInternal.renderer.schedule(); | |
| }; | |
| qd.unbindModel = function(domRoot) { | |
| if (domRoot == null) { | |
| return; | |
| } | |
| qdInternal.binding.unbindDomTree(domRoot); | |
| }; | |
| qdInternal.cache = { | |
| create: function(generator, cacheSize) { | |
| if (cacheSize == null) { | |
| cacheSize = qd.getConfig('defaultCacheSize'); | |
| } | |
| return { | |
| _cache: {}, | |
| get: function() { | |
| var args, id, ref, ref1; | |
| id = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; | |
| if (((ref = (ref1 = this._cache[id]) != null ? ref1.length : void 0) != null ? ref : 0) === 0) { | |
| return generator.apply(null, [id].concat(slice.call(args))); | |
| } | |
| return this._cache[id].shift(); | |
| }, | |
| put: function(id, object) { | |
| var base; | |
| if ((base = this._cache)[id] == null) { | |
| base[id] = []; | |
| } | |
| if (this._cache[id].length < cacheSize || cacheSize === -1) { | |
| this._cache[id].push(object); | |
| } | |
| }, | |
| clear: function() { | |
| this._cache = {}; | |
| } | |
| }; | |
| } | |
| }; | |
| qdInternal.context = { | |
| create: function(viewModel) { | |
| var current, extend, parent, parentModels, parents, ref, ref1, ref2, ref3; | |
| if (viewModel.__context != null) { | |
| return viewModel.__context; | |
| } | |
| extend = function(child) { | |
| var rawChildModel; | |
| child = qdInternal.models.create(child); | |
| rawChildModel = qdInternal.models.unwrap(child); | |
| child.__context = { | |
| $data: qd.unwrapObservable(rawChildModel), | |
| $rawData: rawChildModel, | |
| $parents: [this.$data].concat(this.$parents), | |
| $parent: this.$data, | |
| $parentContext: this, | |
| $root: this.$root, | |
| $extend: extend | |
| }; | |
| return child.__context; | |
| }; | |
| parents = []; | |
| parentModels = []; | |
| current = viewModel; | |
| while ((parent = qdInternal.models.getParent(current)) != null) { | |
| parentModels.push(parent); | |
| parents.push(parent.raw); | |
| current = parent; | |
| } | |
| viewModel.__context = { | |
| $data: qd.unwrapObservable(viewModel.raw), | |
| $rawData: viewModel.raw, | |
| $parents: parents, | |
| $parent: (ref = parents[0]) != null ? ref : null, | |
| $parentContext: (ref1 = (ref2 = parentModels[0]) != null ? ref2.__context : void 0) != null ? ref1 : null, | |
| $root: qd.unwrapObservable((ref3 = parents[parents.length - 1]) != null ? ref3 : viewModel.raw), | |
| $extend: extend | |
| }; | |
| return viewModel.__context; | |
| }, | |
| get: function(domNode) { | |
| var baseViewModel; | |
| baseViewModel = qdInternal.storage.getInternalValue(domNode, qd.getConfig('baseModelKey')); | |
| if (baseViewModel == null) { | |
| return null; | |
| } | |
| return this.create(baseViewModel); | |
| }, | |
| set: function(domNode, context) { | |
| qdInternal.storage.setInternalValue(domNode, qd.getConfig('baseModelKey'), context); | |
| } | |
| }; | |
| qdInternal.dom = { | |
| _uniqueIdentifier: 0, | |
| uniqueId: function(node) { | |
| if (qdInternal.storage.getInternalValue(node, 'id') == null) { | |
| qdInternal.storage.setInternalValue(node, 'id', ++this._uniqueIdentifier); | |
| } | |
| return qdInternal.storage.getInternalValue(node, 'id'); | |
| }, | |
| virtualize: function(domNode) { | |
| var ref; | |
| if (domNode instanceof qdInternal.dom.VirtualDomNode) { | |
| return domNode; | |
| } | |
| return (ref = qdInternal.storage.getInternalValue(domNode, 'virtual')) != null ? ref : new qdInternal.dom.VirtualDomNode(domNode); | |
| }, | |
| unwrap: function(domNode) { | |
| if (domNode == null) { | |
| return null; | |
| } | |
| if (domNode instanceof qdInternal.dom.VirtualDomNode) { | |
| return domNode.getRawNode(); | |
| } else { | |
| return domNode; | |
| } | |
| }, | |
| importNode: function(document, node, deep) { | |
| var virtualNode; | |
| if (deep == null) { | |
| deep = true; | |
| } | |
| virtualNode = qdInternal.dom.virtualize(node); | |
| return virtualNode.cloneNode(deep, document); | |
| }, | |
| VirtualDomNode: VirtualDomNode = (function() { | |
| var uniqueIds; | |
| uniqueIds = 0; | |
| function VirtualDomNode(domNode) { | |
| this._changes = { | |
| properties: null, | |
| attributes: null, | |
| styles: null, | |
| children: null | |
| }; | |
| this._state = { | |
| id: uniqueIds++, | |
| rawNode: domNode, | |
| hasModifications: false, | |
| templateName: null | |
| }; | |
| qdInternal.storage.setInternalValue(domNode, 'virtual', this); | |
| qdInternal.eventing.add(this); | |
| this._resetChangeState(); | |
| } | |
| VirtualDomNode.prototype.dispose = function() { | |
| var child, j, len, ref, ref1; | |
| ref1 = (ref = this._changes.children) != null ? ref : []; | |
| for (j = 0, len = ref1.length; j < len; j++) { | |
| child = ref1[j]; | |
| child.dispose(); | |
| } | |
| this._resetChangeState(); | |
| this._changes = null; | |
| qdInternal.storage.setInternalValue(this._state.rawNode, 'virtual', null); | |
| return delete this._state.rawNode; | |
| }; | |
| VirtualDomNode.prototype.getUniqueId = function() { | |
| return this._state.id; | |
| }; | |
| VirtualDomNode.prototype.getRawNode = function() { | |
| return this._state.rawNode; | |
| }; | |
| VirtualDomNode.prototype.generatePatch = function() { | |
| var patchSet; | |
| if (!this._state.hasModifications) { | |
| return null; | |
| } | |
| patchSet = { | |
| node: this._state.rawNode, | |
| properties: this._changes.properties, | |
| attributes: this._changes.attributes, | |
| styles: this._changes.styles, | |
| children: this._generateChildrenActions() | |
| }; | |
| this._resetChangeState(); | |
| return patchSet; | |
| }; | |
| VirtualDomNode.prototype.getParentNode = function() { | |
| var rawNode; | |
| if (!this._state.hasOwnProperty('parent')) { | |
| rawNode = this._state.rawNode; | |
| if ((rawNode.parentNode != null) && rawNode.parentNode !== rawNode.ownerDocument) { | |
| this._state.parent = qdInternal.dom.virtualize(rawNode.parentNode); | |
| } else { | |
| this._state.parent = null; | |
| } | |
| } | |
| return this._state.parent; | |
| }; | |
| VirtualDomNode.prototype.setParentNode = function(virtualNode, removeFromOldParent) { | |
| var curParent; | |
| if (removeFromOldParent == null) { | |
| removeFromOldParent = true; | |
| } | |
| if ((virtualNode != null) && !(virtualNode instanceof VirtualDomNode)) { | |
| qdInternal.errors["throw"](new QuickdrawError("Attempting to set non-virtual node to parent of a virtual node")); | |
| } | |
| curParent = this.getParentNode(); | |
| if (virtualNode === curParent) { | |
| return; | |
| } | |
| if (removeFromOldParent) { | |
| if (curParent != null) { | |
| curParent.removeChild(this); | |
| } | |
| } | |
| return this._state.parent = virtualNode; | |
| }; | |
| VirtualDomNode.prototype.getTemplateName = function() { | |
| return this._state.templateName; | |
| }; | |
| VirtualDomNode.prototype.setTemplateName = function(templateName) { | |
| return this._state.templateName = templateName; | |
| }; | |
| VirtualDomNode.prototype.getValue = function(key, namespace) { | |
| return qdInternal.storage.getValue(this._state.rawNode, key, namespace); | |
| }; | |
| VirtualDomNode.prototype.setValue = function(key, value, namespace) { | |
| qdInternal.storage.setValue(this._state.rawNode, key, value, namespace); | |
| }; | |
| VirtualDomNode.prototype.clearValues = function() { | |
| qdInternal.storage.clearValues(this._state.rawNode); | |
| qdInternal.storage.setInternalValue(this._state.rawNode, 'virtual', this); | |
| }; | |
| VirtualDomNode.prototype.getProperty = function(name) { | |
| var ref, ref1; | |
| return (ref = (ref1 = this._changes.properties) != null ? ref1[name] : void 0) != null ? ref : this._state.rawNode[name]; | |
| }; | |
| VirtualDomNode.prototype.setProperty = function(name, value) { | |
| var base; | |
| this._changeWillOccur(); | |
| if ((base = this._changes).properties == null) { | |
| base.properties = {}; | |
| } | |
| this._changes.properties[name] = value; | |
| }; | |
| VirtualDomNode.prototype.getAttribute = function(name) { | |
| var ref; | |
| if ((ref = this._changes.attributes) != null ? ref.hasOwnProperty(name) : void 0) { | |
| return this._changes.attributes[name]; | |
| } | |
| return this._state.rawNode.getAttribute(name); | |
| }; | |
| VirtualDomNode.prototype.setAttribute = function(name, value) { | |
| var base; | |
| this._changeWillOccur(); | |
| if ((base = this._changes).attributes == null) { | |
| base.attributes = {}; | |
| } | |
| this._changes.attributes[name] = value; | |
| }; | |
| VirtualDomNode.prototype.removeAttribute = function(name) { | |
| var base; | |
| this._changeWillOccur(); | |
| if ((base = this._changes).attributes == null) { | |
| base.attributes = {}; | |
| } | |
| this._changes.attributes[name] = null; | |
| }; | |
| VirtualDomNode.prototype.hasAttribute = function(name) { | |
| var ref; | |
| if ((ref = this._changes.attributes) != null ? ref.hasOwnProperty(name) : void 0) { | |
| return this._changes.attributes[name] != null; | |
| } | |
| return this._state.rawNode.hasAttribute(name); | |
| }; | |
| VirtualDomNode.prototype.getStyle = function(name) { | |
| var ref, ref1; | |
| return (ref = (ref1 = this._changes.styles) != null ? ref1[name] : void 0) != null ? ref : this._state.rawNode.style[name]; | |
| }; | |
| VirtualDomNode.prototype.setStyle = function(name, value) { | |
| var base; | |
| this._changeWillOccur(); | |
| if ((base = this._changes).styles == null) { | |
| base.styles = {}; | |
| } | |
| this._changes.styles[name] = value; | |
| }; | |
| VirtualDomNode.prototype.addEventListener = function() { | |
| var args, ref; | |
| args = 1 <= arguments.length ? slice.call(arguments, 0) : []; | |
| return (ref = this._state.rawNode).addEventListener.apply(ref, args); | |
| }; | |
| VirtualDomNode.prototype.removeEventListener = function() { | |
| var args, ref; | |
| args = 1 <= arguments.length ? slice.call(arguments, 0) : []; | |
| return (ref = this._state.rawNode).removeEventListener.apply(ref, args); | |
| }; | |
| VirtualDomNode.prototype.getChildren = function(copy) { | |
| if (copy == null) { | |
| copy = false; | |
| } | |
| this._generateVirtualChildren(); | |
| if (!copy) { | |
| return this._changes.children; | |
| } | |
| return this._changes.children.slice(); | |
| }; | |
| VirtualDomNode.prototype.isChild = function(child) { | |
| var virtualChild; | |
| this._generateVirtualChildren(); | |
| virtualChild = qdInternal.dom.virtualize(child); | |
| return (indexOf.call(this._changes.children, virtualChild) >= 0); | |
| }; | |
| VirtualDomNode.prototype.removeChild = function(child) { | |
| var index, virtualChild; | |
| this._generateVirtualChildren(); | |
| this._changeWillOccur(); | |
| virtualChild = qdInternal.dom.virtualize(child); | |
| index = this._changes.children.indexOf(virtualChild); | |
| if (index === -1) { | |
| return qdInternal.errors["throw"](new QuickdrawError("Given element is not a child of this node")); | |
| } | |
| this._changes.children.splice(index, 1); | |
| virtualChild.setParentNode(null, false); | |
| return virtualChild; | |
| }; | |
| VirtualDomNode.prototype.appendChild = function(child) { | |
| var index, virtualChild; | |
| this._generateVirtualChildren(); | |
| this._changeWillOccur(); | |
| virtualChild = qdInternal.dom.virtualize(child); | |
| index = this._changes.children.indexOf(virtualChild); | |
| if (index !== -1) { | |
| if (index === this._changes.children.length - 1) { | |
| return virtualChild; | |
| } | |
| this._changes.children.splice(index, 1); | |
| } | |
| this._changes.children.push(virtualChild); | |
| virtualChild.setParentNode(this); | |
| return virtualChild; | |
| }; | |
| VirtualDomNode.prototype.insertBefore = function(child, referenceNode) { | |
| var childIndex, referenceIndex, virtualChild, virtualReference; | |
| this._generateVirtualChildren(); | |
| this._changeWillOccur(); | |
| if (referenceNode == null) { | |
| return this.appendChild(child); | |
| } | |
| virtualChild = qdInternal.dom.virtualize(child); | |
| virtualReference = qdInternal.dom.virtualize(referenceNode); | |
| childIndex = this._changes.children.indexOf(virtualChild); | |
| referenceIndex = this._changes.children.indexOf(virtualReference); | |
| if (referenceIndex === -1) { | |
| return qdInternal.errors["throw"](new QuickdrawError("Reference node is not a child of this node")); | |
| } | |
| if (childIndex !== -1) { | |
| if (childIndex + 1 === referenceIndex) { | |
| return virtualChild; | |
| } | |
| this._changes.children.splice(childIndex, 1); | |
| referenceIndex = this._changes.children.indexOf(virtualReference); | |
| } | |
| this._changes.children.splice(referenceIndex, 0, virtualChild); | |
| virtualChild.setParentNode(this); | |
| return virtualChild; | |
| }; | |
| VirtualDomNode.prototype.clearChildren = function() { | |
| var child, j, len, ref; | |
| this._generateVirtualChildren(); | |
| this._changeWillOccur(); | |
| ref = this._changes.children; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| child = ref[j]; | |
| child.setParentNode(null, false); | |
| } | |
| this._changes.children.length = 0; | |
| }; | |
| VirtualDomNode.prototype.setChildren = function(children) { | |
| var child, j, len, virtualChild; | |
| this.clearChildren(); | |
| for (j = 0, len = children.length; j < len; j++) { | |
| child = children[j]; | |
| virtualChild = qdInternal.dom.virtualize(child); | |
| virtualChild.setParentNode(this); | |
| this._changes.children.push(virtualChild); | |
| } | |
| }; | |
| VirtualDomNode.prototype.cloneNode = function(deep, document) { | |
| var attribute, changedProperty, child, copy, i, j, len, newChild, property, ref, ref1, ref2, ref3, style, value, virtualCopy; | |
| if (deep == null) { | |
| deep = true; | |
| } | |
| if (document == null) { | |
| document = this._state.rawNode.ownerDocument; | |
| } | |
| if (document === this._state.rawNode.ownerDocument) { | |
| copy = this._state.rawNode.cloneNode(false); | |
| } else { | |
| copy = document.importNode(this._state.rawNode, false); | |
| } | |
| virtualCopy = qdInternal.dom.virtualize(copy); | |
| changedProperty = false; | |
| if (this._changes.properties != null) { | |
| virtualCopy._changes.properties = {}; | |
| ref = this._changes.properties; | |
| for (property in ref) { | |
| value = ref[property]; | |
| changedProperty = true; | |
| virtualCopy._changes.properties[property] = value; | |
| } | |
| } | |
| if (this._changes.attributes != null) { | |
| virtualCopy._changes.attributes = {}; | |
| ref1 = this._changes.attributes; | |
| for (attribute in ref1) { | |
| value = ref1[attribute]; | |
| changedProperty = true; | |
| virtualCopy._changes.attributes[attribute] = value; | |
| } | |
| } | |
| if (this._changes.styles != null) { | |
| virtualCopy._changes.styles = {}; | |
| ref2 = this._changes.styles; | |
| for (style in ref2) { | |
| value = ref2[style]; | |
| changedProperty = true; | |
| virtualCopy._changes.styles[style] = value; | |
| } | |
| } | |
| if (changedProperty) { | |
| virtualCopy._changeWillOccur(); | |
| } | |
| if (deep) { | |
| this._generateVirtualChildren(); | |
| ref3 = this._changes.children; | |
| for (i = j = 0, len = ref3.length; j < len; i = ++j) { | |
| child = ref3[i]; | |
| newChild = child.cloneNode(true, document); | |
| copy.appendChild(newChild.getRawNode()); | |
| } | |
| virtualCopy.getChildren(); | |
| } | |
| return virtualCopy; | |
| }; | |
| VirtualDomNode.prototype._resetChangeState = function() { | |
| this._state.hasModifications = false; | |
| delete this._state.parent; | |
| this._changes.properties = null; | |
| this._changes.attributes = null; | |
| this._changes.styles = null; | |
| this._changes.children = null; | |
| }; | |
| VirtualDomNode.prototype._changeWillOccur = function() { | |
| if (!this._state.hasModifications) { | |
| this._state.hasModifications = true; | |
| qdInternal.renderer.enqueue(this); | |
| } | |
| }; | |
| VirtualDomNode.prototype._generateVirtualChildren = function() { | |
| var child, j, len, ref, virtualChild; | |
| if (this._changes.children != null) { | |
| return; | |
| } | |
| this._changes.children = []; | |
| ref = this._state.rawNode.children; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| child = ref[j]; | |
| virtualChild = qdInternal.dom.virtualize(child); | |
| virtualChild.setParentNode(this); | |
| this._changes.children.push(virtualChild); | |
| } | |
| }; | |
| VirtualDomNode.prototype._generateChildrenActions = function() { | |
| var actions, actionsBackward, actionsForward, arrayBackward, arrayForward, child, correctIndex, curIndex, currentChildren, expectedChildren, i, index, j, k, l, len, len1, len2, len3, m, map, mappingArray, n, prunedChildren, ref, ref1, ref2, ref3, value; | |
| if (this._changes.children == null) { | |
| return []; | |
| } | |
| currentChildren = this._state.rawNode.children; | |
| expectedChildren = new Array(this._changes.children.length); | |
| ref = this._changes.children; | |
| for (i = j = 0, len = ref.length; j < len; i = ++j) { | |
| child = ref[i]; | |
| expectedChildren[i] = child.getRawNode(); | |
| } | |
| actions = []; | |
| prunedChildren = []; | |
| for (k = 0, len1 = currentChildren.length; k < len1; k++) { | |
| child = currentChildren[k]; | |
| if (!(indexOf.call(expectedChildren, child) >= 0)) { | |
| actions.push({ | |
| type: "remove", | |
| value: child | |
| }); | |
| } else { | |
| prunedChildren.push(child); | |
| } | |
| } | |
| mappingArray = new Array(expectedChildren.length); | |
| for (index = l = 0, len2 = expectedChildren.length; l < len2; index = ++l) { | |
| value = expectedChildren[index]; | |
| mappingArray[index] = { | |
| leads: (ref1 = expectedChildren[index + 1]) != null ? ref1 : null, | |
| follows: (ref2 = expectedChildren[index - 1]) != null ? ref2 : null, | |
| value: value | |
| }; | |
| } | |
| actionsForward = actions; | |
| arrayForward = prunedChildren; | |
| actionsBackward = actions.slice(); | |
| arrayBackward = prunedChildren.slice(); | |
| for (index = m = 0, len3 = mappingArray.length; m < len3; index = m += 1) { | |
| map = mappingArray[index]; | |
| curIndex = arrayForward.indexOf(map.value); | |
| if (curIndex === index) { | |
| continue; | |
| } | |
| if (curIndex !== -1) { | |
| arrayForward.splice(curIndex, 1); | |
| } | |
| actionsForward.push({ | |
| type: "insert", | |
| value: map.value, | |
| follows: map.follows | |
| }); | |
| arrayForward.splice(index, 0, map.value); | |
| } | |
| for (index = n = 0, ref3 = mappingArray.length; 0 <= ref3 ? n < ref3 : n > ref3; index = 0 <= ref3 ? ++n : --n) { | |
| map = mappingArray[mappingArray.length - 1 - index]; | |
| curIndex = arrayBackward.indexOf(map.value); | |
| correctIndex = Math.max(0, arrayBackward.length - 1 - index); | |
| if (correctIndex === curIndex) { | |
| continue; | |
| } | |
| if (curIndex !== -1) { | |
| arrayBackward.splice(curIndex, 1); | |
| } | |
| if (map.leads === null) { | |
| correctIndex = arrayBackward.length; | |
| } else { | |
| correctIndex = arrayBackward.indexOf(map.leads); | |
| } | |
| actionsBackward.push({ | |
| type: "insert", | |
| value: map.value, | |
| leads: map.leads | |
| }); | |
| arrayBackward.splice(correctIndex, 0, map.value); | |
| } | |
| if (actionsForward.length > actionsBackward.length) { | |
| return actionsBackward; | |
| } else { | |
| return actionsForward; | |
| } | |
| }; | |
| return VirtualDomNode; | |
| })() | |
| }; | |
| qdInternal.errors = { | |
| "throw": function(error) { | |
| var handler, j, len, ref; | |
| if (qdInternal.state.error.handlers.length === 0) { | |
| throw error; | |
| } | |
| ref = qdInternal.state.error.handlers; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| handler = ref[j]; | |
| handler(error); | |
| } | |
| } | |
| }; | |
| qdInternal.errors.QuickdrawError = QuickdrawError = (function() { | |
| function QuickdrawError(message, originalError) { | |
| var ref, ref1, ref2; | |
| this.message = message; | |
| this._current = { | |
| duringBinding: qdInternal.state.current.element !== null, | |
| error: originalError, | |
| context: null, | |
| observable: null, | |
| domNode: qdInternal.dom.unwrap((ref = qdInternal.state.current.element) != null ? ref : null), | |
| handler: (ref1 = qdInternal.state.current.handler) != null ? ref1 : null, | |
| viewModel: (ref2 = qdInternal.models.unwrap(qdInternal.state.current.model)) != null ? ref2 : null | |
| }; | |
| } | |
| QuickdrawError.prototype.setOriginalError = function(error) { | |
| this._current.error = error; | |
| }; | |
| QuickdrawError.prototype.setBindingContext = function(context) { | |
| this._current.context = context; | |
| }; | |
| QuickdrawError.prototype.setDomNode = function(domNode) { | |
| this._current.domNode = qdInternal.dom.unwrap(domNode); | |
| }; | |
| QuickdrawError.prototype.setObservable = function(observable) { | |
| this._current.observable = observable; | |
| }; | |
| QuickdrawError.prototype.setViewModel = function(viewModel) { | |
| if (viewModel == null) { | |
| return; | |
| } | |
| this._current.viewModel = qdInternal.models.unwrap(viewModel); | |
| }; | |
| QuickdrawError.prototype.errorInfo = function() { | |
| return this._current; | |
| }; | |
| return QuickdrawError; | |
| })(); | |
| qd.registerErrorHandler = function(callback) { | |
| qdInternal.state.error.handlers.push(callback); | |
| }; | |
| qdInternal.eventing = { | |
| _on: function(eventType, callback) { | |
| var registrations; | |
| registrations = this.__eventRegistrations != null ? this.__eventRegistrations : this.__eventRegistrations = {}; | |
| if (registrations[eventType] == null) { | |
| registrations[eventType] = []; | |
| } | |
| registrations[eventType].push(callback); | |
| }, | |
| _once: function(eventType, callback) { | |
| var wrappedCallback; | |
| wrappedCallback = (function(_this) { | |
| return function() { | |
| var args; | |
| args = 1 <= arguments.length ? slice.call(arguments, 0) : []; | |
| callback.apply(_this, arguments); | |
| return _this.removeListener(eventType, wrappedCallback); | |
| }; | |
| })(this); | |
| this.on(eventType, wrappedCallback); | |
| }, | |
| _removeListener: function(eventType, callback) { | |
| var reg, registrations; | |
| registrations = this.__eventRegistrations; | |
| if ((registrations != null ? registrations[eventType] : void 0) != null) { | |
| registrations[eventType] = (function() { | |
| var j, len, ref, results; | |
| ref = registrations[eventType]; | |
| results = []; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| reg = ref[j]; | |
| if (reg !== callback) { | |
| results.push(reg); | |
| } | |
| } | |
| return results; | |
| })(); | |
| } | |
| }, | |
| _emit: function(eventType, args, async) { | |
| var callbacks, emitCallback; | |
| if (async == null) { | |
| async = true; | |
| } | |
| if (!((this.__eventRegistrations != null) && (this.__eventRegistrations[eventType] != null))) { | |
| return; | |
| } | |
| callbacks = this.__eventRegistrations[eventType]; | |
| emitCallback = (function(_this) { | |
| return function() { | |
| var callback, j, len; | |
| for (j = 0, len = callbacks.length; j < len; j++) { | |
| callback = callbacks[j]; | |
| callback.apply(_this, args); | |
| } | |
| }; | |
| })(this); | |
| if (async) { | |
| qdInternal.async.immediate(emitCallback); | |
| } else { | |
| emitCallback(); | |
| } | |
| }, | |
| add: function(obj) { | |
| var evt; | |
| evt = qdInternal.eventing; | |
| obj.on = evt._on; | |
| obj.once = evt._once; | |
| obj.removeListener = evt._removeListener; | |
| obj.emit = evt._emit; | |
| return obj; | |
| } | |
| }; | |
| qdInternal.eventing.add(qd); | |
| qdInternal.handlers = { | |
| getInitialize: function(keyword) { | |
| var ref, ref1; | |
| return (ref = (ref1 = qdInternal.state.binding.handlers[keyword]) != null ? ref1.methods.initialize : void 0) != null ? ref : null; | |
| }, | |
| getUpdate: function(keyword) { | |
| var ref, ref1; | |
| return (ref = (ref1 = qdInternal.state.binding.handlers[keyword]) != null ? ref1.methods.update : void 0) != null ? ref : null; | |
| }, | |
| getCleanup: function(keyword) { | |
| var ref, ref1; | |
| return (ref = (ref1 = qdInternal.state.binding.handlers[keyword]) != null ? ref1.methods.cleanup : void 0) != null ? ref : null; | |
| }, | |
| exists: function(keyword) { | |
| return qdInternal.state.binding.handlers[keyword] != null; | |
| } | |
| }; | |
| qd.registerBindingHandler = function(keyword, handler, follows, override) { | |
| var dependencyCount, dependencyMap, handlerOrder, handlers, j, k, l, len, len1, len2, name, precursor, ref, ref1, ref2, ref3, toProcess, type, valid; | |
| if (follows == null) { | |
| follows = []; | |
| } | |
| if (override == null) { | |
| override = false; | |
| } | |
| if (!((keyword != null) && keyword.length > 0)) { | |
| return qdInternal.errors["throw"](new QuickdrawError("Binding handler must have a valid name")); | |
| } | |
| if (qdInternal.handlers.exists(keyword) && !override) { | |
| return qdInternal.errors["throw"](new QuickdrawError("Binding handler already registered for '" + keyword + "'")); | |
| } | |
| if (!((handler.initialize != null) || (handler.update != null))) { | |
| return qdInternal.errors["throw"](new QuickdrawError("A binding handler must at least specify an 'initialize'/'update' callback")); | |
| } | |
| ref = ['initialize', 'update', 'cleanup']; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| type = ref[j]; | |
| if (handler[type] == null) { | |
| continue; | |
| } | |
| handler[type] = (function(type, callback) { | |
| return function() { | |
| var args, err, result, stateMemento; | |
| args = 1 <= arguments.length ? slice.call(arguments, 0) : []; | |
| stateMemento = qdInternal.updateCurrentState({ | |
| handler: keyword | |
| }); | |
| try { | |
| result = callback.apply(qdInternal, args); | |
| } catch (error1) { | |
| err = error1; | |
| qdInternal.errors["throw"](new QuickdrawError("Error in '" + type + "' of '" + keyword + "' binding handler: \"" + err.message + "\"", err)); | |
| } finally { | |
| stateMemento(); | |
| } | |
| return result; | |
| }; | |
| })(type, handler[type]); | |
| } | |
| handlers = qdInternal.state.binding.handlers; | |
| handlers[keyword] = { | |
| methods: handler, | |
| follows: follows | |
| }; | |
| toProcess = []; | |
| dependencyMap = {}; | |
| dependencyCount = {}; | |
| for (name in handlers) { | |
| handler = handlers[name]; | |
| valid = 0; | |
| ref1 = handler.follows; | |
| for (k = 0, len1 = ref1.length; k < len1; k++) { | |
| precursor = ref1[k]; | |
| if (handlers[precursor] == null) { | |
| continue; | |
| } | |
| if (dependencyMap[precursor] == null) { | |
| dependencyMap[precursor] = []; | |
| } | |
| dependencyMap[precursor].push(name); | |
| valid++; | |
| } | |
| if (valid === 0) { | |
| toProcess.push(name); | |
| } else { | |
| dependencyCount[name] = valid; | |
| } | |
| } | |
| handlerOrder = qdInternal.state.binding.order; | |
| handlerOrder.length = 0; | |
| while (toProcess.length > 0) { | |
| name = toProcess.shift(); | |
| handlerOrder.push(name); | |
| ref3 = (ref2 = dependencyMap[name]) != null ? ref2 : []; | |
| for (l = 0, len2 = ref3.length; l < len2; l++) { | |
| handler = ref3[l]; | |
| dependencyCount[handler]--; | |
| if (dependencyCount[handler] === 0) { | |
| toProcess.push(handler); | |
| } | |
| } | |
| } | |
| return handlers[keyword].methods; | |
| }; | |
| qdInternal.models = { | |
| create: function(rawObject) { | |
| if (this.isModel(rawObject)) { | |
| return rawObject; | |
| } | |
| return { | |
| raw: rawObject, | |
| __isModel: true, | |
| __parent: null | |
| }; | |
| }, | |
| isModel: function(object) { | |
| return (object != null) && (object.__isModel != null) && object.__isModel; | |
| }, | |
| get: function(domNode) { | |
| return qdInternal.storage.getInternalValue(domNode, qd.getConfig('baseModelKey')); | |
| }, | |
| setParent: function(model, parent) { | |
| if (!this.isModel(model) || (parent == null) || model === parent) { | |
| return; | |
| } | |
| return model.__parent = parent; | |
| }, | |
| getParent: function(model, parent) { | |
| if (!this.isModel(model)) { | |
| return null; | |
| } | |
| return model.__parent; | |
| }, | |
| unwrap: function(model) { | |
| if (this.isModel(model)) { | |
| return model.raw; | |
| } | |
| return model; | |
| } | |
| }; | |
| qd.getModel = function(domNode) { | |
| return qdInternal.models.unwrap(qdInternal.models.get(domNode)); | |
| }; | |
| qdInternal.observables = { | |
| addDependency: function(model, element, handler) { | |
| var dependencyObject, matchingElms, observables, ref; | |
| if (model == null) { | |
| model = qdInternal.state.current.model; | |
| } | |
| if (element == null) { | |
| element = qdInternal.state.current.element; | |
| } | |
| if (handler == null) { | |
| handler = qdInternal.state.current.handler; | |
| } | |
| if (!((model != null) && (element != null))) { | |
| return; | |
| } | |
| element = qdInternal.dom.unwrap(element); | |
| qdInternal.context.set(element, model); | |
| if (this.__dependencies == null) { | |
| this.__dependencies = []; | |
| } | |
| matchingElms = this.__dependencies.filter(function(elm) { | |
| return elm.domNode === element; | |
| }); | |
| if (matchingElms.length > 0) { | |
| dependencyObject = matchingElms[0]; | |
| } else { | |
| dependencyObject = { | |
| domNode: element, | |
| handlers: [] | |
| }; | |
| this.__dependencies.push(dependencyObject); | |
| this.emit('bound', [model, element]); | |
| } | |
| if (handler != null) { | |
| if (indexOf.call(dependencyObject.handlers, handler) < 0) { | |
| dependencyObject.handlers.push(handler); | |
| } | |
| } else { | |
| dependencyObject.unspecific = true; | |
| } | |
| observables = (ref = qdInternal.storage.getInternalValue(element, 'observables')) != null ? ref : []; | |
| if (indexOf.call(observables, this) < 0) { | |
| observables.push(this); | |
| } | |
| qdInternal.storage.setInternalValue(element, 'observables', observables); | |
| }, | |
| addComputedDependency: function(computed) { | |
| if (this.__computedDependencies == null) { | |
| this.__computedDependencies = []; | |
| } | |
| if (indexOf.call(this.__computedDependencies, computed) < 0) { | |
| this.__computedDependencies.push(computed); | |
| } | |
| }, | |
| getDependencies: function() { | |
| var computed, dependencies, j, len, ref, ref1, ref2; | |
| dependencies = (ref = this.__dependencies) != null ? ref : []; | |
| ref2 = (ref1 = this.__computedDependencies) != null ? ref1 : []; | |
| for (j = 0, len = ref2.length; j < len; j++) { | |
| computed = ref2[j]; | |
| dependencies = dependencies.concat(qdInternal.observables.getDependencies.call(computed)); | |
| } | |
| return dependencies; | |
| }, | |
| removeDependency: function(element) { | |
| var dependency; | |
| element = qdInternal.dom.unwrap(element); | |
| this.__dependencies = (function() { | |
| var j, len, ref, results; | |
| ref = this.__dependencies; | |
| results = []; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| dependency = ref[j]; | |
| if (dependency.domNode !== element) { | |
| results.push(dependency); | |
| } | |
| } | |
| return results; | |
| }).call(this); | |
| this.emit('unbound', [element]); | |
| }, | |
| hasDependencies: function() { | |
| return qdInternal.observables.getDependencies.call(this).length > 0; | |
| }, | |
| updateDependencies: function(immediate) { | |
| var dependencies, dependency, element, handler, handlers, immediateRebinds, j, k, len, len1, ref; | |
| if (immediate == null) { | |
| immediate = false; | |
| } | |
| dependencies = qdInternal.observables.getDependencies.call(this); | |
| if (!(dependencies.length > 0)) { | |
| return; | |
| } | |
| immediateRebinds = []; | |
| for (j = 0, len = dependencies.length; j < len; j++) { | |
| dependency = dependencies[j]; | |
| element = dependency.domNode; | |
| handlers = qdInternal.storage.getInternalValue(element, 'handlers'); | |
| if (!handlers) { | |
| continue; | |
| } | |
| if (dependency.unspecific) { | |
| for (handler in handlers) { | |
| handlers[handler] = true; | |
| } | |
| } else { | |
| ref = dependency.handlers; | |
| for (k = 0, len1 = ref.length; k < len1; k++) { | |
| handler = ref[k]; | |
| handlers[handler] = true; | |
| } | |
| } | |
| if (immediate) { | |
| immediateRebinds.push(element); | |
| } else { | |
| qdInternal.updates.enqueue(element); | |
| } | |
| } | |
| if (immediate) { | |
| qdInternal.updates.updateNodeSet(immediateRebinds); | |
| qdInternal.renderer.render(); | |
| } else { | |
| qdInternal.updates.schedule(); | |
| } | |
| this.emit('set'); | |
| }, | |
| helpers: { | |
| immediate: function(newValue) { | |
| return this(newValue, true); | |
| }, | |
| silent: function(newValue) { | |
| return this(newValue, false, false); | |
| }, | |
| not: function(newValue, immediate, alertDependencies) { | |
| return !this(newValue, immediate, alertDependencies); | |
| }, | |
| indexOf: function(find) { | |
| var i, item, j, len, ref; | |
| ref = this.value; | |
| for (i = j = 0, len = ref.length; j < len; i = ++j) { | |
| item = ref[i]; | |
| if (item === find) { | |
| return i; | |
| } | |
| } | |
| return -1; | |
| }, | |
| slice: function() { | |
| var ret; | |
| ret = this.value.slice.apply(this.value, arguments); | |
| qdInternal.observables.updateDependencies.call(this); | |
| return ret; | |
| }, | |
| push: function(item) { | |
| this.value.push(item); | |
| qdInternal.observables.updateDependencies.call(this); | |
| }, | |
| pop: function() { | |
| var ret; | |
| ret = this.value.pop(); | |
| qdInternal.observables.updateDependencies.call(this); | |
| return ret; | |
| }, | |
| unshift: function(item) { | |
| this.value.unshift(item); | |
| qdInternal.observables.updateDependencies.call(this); | |
| }, | |
| shift: function() { | |
| var ret; | |
| ret = this.value.shift(); | |
| qdInternal.observables.updateDependencies.call(this); | |
| return ret; | |
| }, | |
| reverse: function() { | |
| this.value.reverse(); | |
| qdInternal.observables.updateDependencies.call(this); | |
| }, | |
| sort: function(func) { | |
| this.value.sort(func); | |
| qdInternal.observables.updateDependencies.call(this); | |
| }, | |
| splice: function() { | |
| var count, elements, first, ref, ret; | |
| first = arguments[0], count = arguments[1], elements = 3 <= arguments.length ? slice.call(arguments, 2) : []; | |
| ret = (ref = this.value).splice.apply(ref, [first, count].concat(slice.call(elements))); | |
| qdInternal.observables.updateDependencies.call(this); | |
| return ret; | |
| }, | |
| remove: function(find) { | |
| var drop, item, j, len, newBack, ref, ref1, removed; | |
| newBack = []; | |
| removed = []; | |
| ref = this.value; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| item = ref[j]; | |
| drop = (ref1 = typeof find === "function" ? find(item) : void 0) != null ? ref1 : item === find; | |
| (drop ? removed : newBack).push(item); | |
| } | |
| this.value = newBack; | |
| qdInternal.observables.updateDependencies.call(this); | |
| return removed; | |
| }, | |
| removeAll: function(items) { | |
| var item, j, len, newBack, ref, removed; | |
| removed = []; | |
| if (items != null) { | |
| newBack = []; | |
| ref = this.value; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| item = ref[j]; | |
| if (indexOf.call(items, item) >= 0) { | |
| removed.push(item); | |
| } else { | |
| newBack.push(item); | |
| } | |
| } | |
| this.value = newBack; | |
| } else { | |
| removed = this.value; | |
| this.value = []; | |
| } | |
| qdInternal.observables.updateDependencies.call(this); | |
| return removed; | |
| } | |
| }, | |
| extendFunctions: function(obs) { | |
| obs.isObservable = true; | |
| obs.isBound = this.hasDependencies; | |
| obs.immediate = this.helpers.immediate; | |
| obs.silent = this.helpers.silent; | |
| obs.not = (function(_this) { | |
| return function() { | |
| return _this.helpers.not.apply(obs, arguments); | |
| }; | |
| })(this); | |
| obs.not.isObservable = true; | |
| qdInternal.eventing.add(obs); | |
| return obs; | |
| } | |
| }; | |
| qd.observable = function(initialValue) { | |
| var obv; | |
| obv = function(newValue, immediate, alertDependencies) { | |
| if (immediate == null) { | |
| immediate = false; | |
| } | |
| if (alertDependencies == null) { | |
| alertDependencies = true; | |
| } | |
| if (qdInternal.state.current.model != null) { | |
| qdInternal.observables.addDependency.call(obv); | |
| } | |
| if (typeof newValue !== "undefined") { | |
| obv.value = newValue; | |
| if (alertDependencies) { | |
| qdInternal.observables.updateDependencies.call(obv, immediate); | |
| } | |
| } else { | |
| if (alertDependencies) { | |
| obv.emit('access', [], false); | |
| obv.emit('accessed'); | |
| } | |
| } | |
| return obv.value; | |
| }; | |
| obv.value = initialValue; | |
| return qdInternal.observables.extendFunctions(obv); | |
| }; | |
| qd.computed = function(computedValue, thisBinding, observables) { | |
| var compute, j, len, observe; | |
| if (thisBinding == null) { | |
| qdInternal.errors["throw"](new QuickdrawError("Creating computed without specifying the appropriate this context to evaluate in")); | |
| } | |
| if ((observables == null) || observables.length === 0) { | |
| qdInternal.errors["throw"](new QuickdrawError("Creating computed without specifying the appropriate observables the computed uses")); | |
| } | |
| compute = function() { | |
| var params; | |
| params = 1 <= arguments.length ? slice.call(arguments, 0) : []; | |
| if (qdInternal.state.current.model != null) { | |
| qdInternal.observables.addDependency.call(compute); | |
| } | |
| return computedValue.apply(thisBinding, params); | |
| }; | |
| for (j = 0, len = observables.length; j < len; j++) { | |
| observe = observables[j]; | |
| if (observe == null) { | |
| qdInternal.errors["throw"](new QuickdrawError("Creating computed with undefined or null observables is not allowed")); | |
| continue; | |
| } | |
| qdInternal.observables.addComputedDependency.call(observe, compute); | |
| } | |
| return qdInternal.observables.extendFunctions(compute); | |
| }; | |
| qd.observableArray = function(initialValue) { | |
| var arr, helpers; | |
| if (initialValue == null) { | |
| initialValue = []; | |
| } | |
| arr = qd.observable(initialValue); | |
| helpers = qdInternal.observables.helpers; | |
| arr.indexOf = helpers.indexOf; | |
| arr.slice = helpers.slice; | |
| arr.push = helpers.push; | |
| arr.pop = helpers.pop; | |
| arr.unshift = helpers.unshift; | |
| arr.shift = helpers.shift; | |
| arr.reverse = helpers.reverse; | |
| arr.sort = helpers.sort; | |
| arr.splice = helpers.splice; | |
| arr.remove = helpers.remove; | |
| arr.removeAll = helpers.removeAll; | |
| return arr; | |
| }; | |
| qd.isObservable = function(value) { | |
| return !!(value != null ? value.isObservable : void 0); | |
| }; | |
| qd.unwrapObservable = function(possible, recursive) { | |
| var index, j, key, len, recursed, ref, unwrapped, value; | |
| if (recursive == null) { | |
| recursive = false; | |
| } | |
| if (possible == null) { | |
| return possible; | |
| } | |
| unwrapped = possible; | |
| if (qd.isObservable(possible)) { | |
| unwrapped = (ref = typeof possible.silent === "function" ? possible.silent() : void 0) != null ? ref : possible(); | |
| } | |
| if (unwrapped == null) { | |
| return unwrapped; | |
| } | |
| if (recursive && typeof unwrapped === 'object') { | |
| if (Object.prototype.toString.call(unwrapped) === '[object Array]') { | |
| recursed = new Array(unwrapped.length); | |
| for (index = j = 0, len = unwrapped.length; j < len; index = ++j) { | |
| value = unwrapped[index]; | |
| recursed[index] = qd.unwrapObservable(value, true); | |
| } | |
| } else { | |
| recursed = {}; | |
| for (key in unwrapped) { | |
| value = unwrapped[key]; | |
| recursed[key] = qd.unwrapObservable(value, true); | |
| } | |
| } | |
| unwrapped = recursed; | |
| } | |
| return unwrapped; | |
| }; | |
| qdInternal.renderer = { | |
| enqueue: function(virtualNode) { | |
| var renderState; | |
| if ((virtualNode == null) || !(virtualNode instanceof qdInternal.dom.VirtualDomNode)) { | |
| return qdInternal.errors["throw"](new QuickdrawError("Cannot queue a non-virtual node for render")); | |
| } | |
| renderState = qdInternal.state.render; | |
| if (!renderState.enqueuedNodes[virtualNode.getUniqueId()]) { | |
| renderState.enqueuedNodes[virtualNode.getUniqueId()] = true; | |
| qdInternal.state.render.queue.push(virtualNode); | |
| } | |
| }, | |
| schedule: function() { | |
| if (qd.getConfig('renderAsync')) { | |
| if (qdInternal.state.render.key == null) { | |
| if (window.requestAnimationFrame != null) { | |
| qdInternal.state.render.key = -1; | |
| window.requestAnimationFrame(qdInternal.renderer.render); | |
| } else { | |
| qdInternal.state.render.key = qdInternal.async.immediate(qdInternal.renderer.render); | |
| } | |
| return qd.emit('renderScheduled', [ | |
| { | |
| usingAnimationFrame: window.requestAnimationFrame != null | |
| } | |
| ], false); | |
| } | |
| } else { | |
| return qdInternal.renderer.render(); | |
| } | |
| }, | |
| render: function() { | |
| var j, k, l, len, len1, len2, node, patch, patchesToRender, ref, ref1; | |
| qdInternal.async.cancel(qdInternal.state.render.key); | |
| if (qd.getConfig('renderEnabled')) { | |
| qd.emit('renderWillOccur', null, false); | |
| patchesToRender = []; | |
| ref = qdInternal.state.render.queue; | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| node = ref[j]; | |
| patch = node.generatePatch(); | |
| if (patch != null) { | |
| patchesToRender.push(patch); | |
| } | |
| } | |
| for (k = 0, len1 = patchesToRender.length; k < len1; k++) { | |
| patch = patchesToRender[k]; | |
| qdInternal.renderer.renderPatch(patch); | |
| } | |
| ref1 = qdInternal.state.render.queue; | |
| for (l = 0, len2 = ref1.length; l < len2; l++) { | |
| node = ref1[l]; | |
| node.emit('render', null, false); | |
| } | |
| qdInternal.state.render.queue = []; | |
| qdInternal.state.render.enqueuedNodes = {}; | |
| qd.emit('renderHasOccurred', null, false); | |
| } | |
| qdInternal.state.render.key = null; | |
| }, | |
| renderPatch: function(patch) { | |
| var action, beforeReference, garbage, j, key, len, node, parent, ref, ref1, ref2, ref3, ref4, value; | |
| node = patch.node; | |
| if (patch.properties != null) { | |
| ref = patch.properties; | |
| for (key in ref) { | |
| value = ref[key]; | |
| node[key] = value; | |
| } | |
| } | |
| if (patch.attributes != null) { | |
| ref1 = patch.attributes; | |
| for (key in ref1) { | |
| value = ref1[key]; | |
| if (value === null) { | |
| node.removeAttribute(key); | |
| } else { | |
| node.setAttribute(key, value); | |
| } | |
| } | |
| } | |
| if (patch.styles != null) { | |
| ref2 = patch.styles; | |
| for (key in ref2) { | |
| value = ref2[key]; | |
| node.style[key] = value; | |
| } | |
| } | |
| if (patch.children == null) { | |
| return; | |
| } | |
| ref3 = patch.children; | |
| for (j = 0, len = ref3.length; j < len; j++) { | |
| action = ref3[j]; | |
| if (action.type === "remove") { | |
| parent = action.value.parentNode; | |
| if (node === parent) { | |
| garbage = parent.removeChild(action.value); | |
| } | |
| } else { | |
| beforeReference = null; | |
| if ((action.follows != null) || (action.leads != null)) { | |
| beforeReference = (ref4 = action.leads) != null ? ref4 : action.follows.nextSibling; | |
| } else if (action.hasOwnProperty('follows')) { | |
| beforeReference = node.firstChild; | |
| } | |
| garbage = node.insertBefore(action.value, beforeReference); | |
| } | |
| } | |
| } | |
| }; | |
| qd.disableRendering = function() { | |
| qd.setConfig('renderEnabled', false); | |
| }; | |
| qd.enableRendering = function() { | |
| qd.setConfig('renderEnabled', true); | |
| qdInternal.renderer.render(); | |
| }; | |
| qdInternal.storage = { | |
| setInternalValue: function(node, name, value) { | |
| this.setValue(qdInternal.dom.unwrap(node), name, value, '_'); | |
| }, | |
| getInternalValue: function(node, name) { | |
| return this.getValue(qdInternal.dom.unwrap(node), name, '_'); | |
| }, | |
| setValue: function(node, name, value, namespace) { | |
| var base, storageKey; | |
| if (namespace == null) { | |
| namespace = qdInternal.state.current.handler; | |
| } | |
| storageKey = qd.getConfig('nodeDataKey'); | |
| if (node[storageKey] == null) { | |
| node[storageKey] = {}; | |
| } | |
| if ((base = node[storageKey])[namespace] == null) { | |
| base[namespace] = {}; | |
| } | |
| node[storageKey][namespace][name] = value; | |
| }, | |
| getValue: function(node, name, namespace) { | |
| var ref, ref1, ref2; | |
| if (namespace == null) { | |
| namespace = qdInternal.state.current.handler; | |
| } | |
| return (ref = (ref1 = node[qd.getConfig('nodeDataKey')]) != null ? (ref2 = ref1[namespace]) != null ? ref2[name] : void 0 : void 0) != null ? ref : null; | |
| }, | |
| clearValues: function(node) { | |
| var storageKey; | |
| storageKey = qd.getConfig('nodeDataKey'); | |
| if (node[storageKey] == null) { | |
| return; | |
| } | |
| delete node[storageKey]; | |
| } | |
| }; | |
| qdInternal.strings = { | |
| appendWithDelimiter: function(string, item, delimiter) { | |
| var result; | |
| result = string; | |
| if (result.length > 0 && result[result.length - 1] !== delimiter) { | |
| result += delimiter; | |
| } | |
| result += item; | |
| return result; | |
| }, | |
| tokenizer: (function() { | |
| function _Class(string1, delimiter1) { | |
| this.string = string1; | |
| this.delimiter = delimiter1; | |
| this.pos = 0; | |
| } | |
| _Class.prototype.nextToken = function() { | |
| var nextpos, token; | |
| if (this.string == null) { | |
| return null; | |
| } | |
| while (this.string[this.pos] === this.delimiter && this.pos < this.string.length) { | |
| ++this.pos; | |
| } | |
| nextpos = this.pos; | |
| while (nextpos < this.string.length && this.string[nextpos] !== this.delimiter) { | |
| ++nextpos; | |
| } | |
| if (nextpos > this.pos) { | |
| token = this.string.substring(this.pos, nextpos); | |
| this.pos = nextpos; | |
| return token; | |
| } | |
| return null; | |
| }; | |
| _Class.prototype.map = function(callback) { | |
| var nextToken; | |
| while ((nextToken = this.nextToken()) !== null) { | |
| callback(nextToken); | |
| } | |
| }; | |
| _Class.prototype.toArray = function() { | |
| var values; | |
| values = []; | |
| this.map(function(token) { | |
| return values.push(token); | |
| }); | |
| return values; | |
| }; | |
| return _Class; | |
| })() | |
| }; | |
| qdInternal.templates = { | |
| _uniqueId: 0, | |
| _generator: function(name, doc) { | |
| var index, j, len, newNodes, node, nodes; | |
| nodes = qdInternal.state.templates.nodes[name]; | |
| newNodes = new Array(nodes.length); | |
| for (index = j = 0, len = nodes.length; j < len; index = ++j) { | |
| node = nodes[index]; | |
| if (doc != null) { | |
| newNodes[index] = doc.importNode(node, true); | |
| } else { | |
| newNodes[index] = node.cloneNode(true); | |
| } | |
| } | |
| return newNodes; | |
| }, | |
| resolve: function(name) { | |
| var ref; | |
| return (ref = qdInternal.state.templates.aliases[name]) != null ? ref : name; | |
| }, | |
| exists: function(name) { | |
| var realName, ref; | |
| realName = (ref = qdInternal.state.templates.aliases[name]) != null ? ref : name; | |
| return qdInternal.state.templates.nodes[realName] != null; | |
| }, | |
| get: function(name, doc) { | |
| var i, j, node, nodes, realName, ref, ref1, templateState; | |
| templateState = qdInternal.state.templates; | |
| realName = (ref = templateState.aliases[name]) != null ? ref : name; | |
| if (templateState.nodes[realName] == null) { | |
| return qdInternal.errors["throw"](new QuickdrawError("No template defined for given name")); | |
| } | |
| if (templateState.cache == null) { | |
| templateState.cache = qdInternal.cache.create(qdInternal.templates._generator); | |
| } | |
| nodes = templateState.cache.get(realName, doc); | |
| for (i = j = 0, ref1 = nodes.length; 0 <= ref1 ? j < ref1 : j > ref1; i = 0 <= ref1 ? ++j : --j) { | |
| node = nodes[i]; | |
| if ((doc != null) && node.ownerDocument !== doc) { | |
| node = doc.adoptNode(node); | |
| } | |
| nodes[i] = qdInternal.dom.virtualize(node); | |
| nodes[i].setTemplateName(realName); | |
| } | |
| return nodes; | |
| }, | |
| "return": function(name, nodes) { | |
| var i, j, len, node, realName, ref, storageNodes, templateState; | |
| templateState = qdInternal.state.templates; | |
| realName = (ref = templateState.aliases[name]) != null ? ref : name; | |
| if (templateState.nodes[realName] == null) { | |
| return qdInternal.errors["throw"](new QuickdrawError("Given name is not a valid template name")); | |
| } | |
| storageNodes = new Array(nodes.length); | |
| for (i = j = 0, len = nodes.length; j < len; i = ++j) { | |
| node = nodes[i]; | |
| storageNodes[i] = qdInternal.dom.unwrap(node); | |
| } | |
| templateState.cache.put(realName, storageNodes); | |
| }, | |
| register: function(nodes, name) { | |
| var cleanNodes, html, i, j, len, node, templateName, templateState; | |
| templateState = qdInternal.state.templates; | |
| if (templateState.aliases[name] != null) { | |
| return qdInternal.errors["throw"](new QuickdrawError("Template already defined for given name `" + name + "`")); | |
| } | |
| if ((nodes[0] != null) && (nodes[0] instanceof qdInternal.dom.VirtualDomNode)) { | |
| templateName = nodes[0].getTemplateName(); | |
| } | |
| if (templateName == null) { | |
| html = ""; | |
| cleanNodes = new Array(nodes.length); | |
| for (i = j = 0, len = nodes.length; j < len; i = ++j) { | |
| node = nodes[i]; | |
| node = qdInternal.dom.unwrap(node); | |
| cleanNodes[i] = node; | |
| qdInternal.storage.clearValues(node); | |
| html += node.outerHTML; | |
| } | |
| if (templateState.html[html] == null) { | |
| templateName = qdInternal.templates._uniqueId++; | |
| templateState.html[html] = templateName; | |
| templateState.nodes[templateName] = cleanNodes; | |
| } else { | |
| templateName = templateState.html[html]; | |
| } | |
| } | |
| if (name != null) { | |
| templateState.aliases[name] = templateName; | |
| } | |
| return name != null ? name : templateName; | |
| }, | |
| unregister: function(name) { | |
| delete qdInternal.state.templates.aliases[name]; | |
| }, | |
| clearCache: function() { | |
| var ref; | |
| if ((ref = qdInternal.state.templates.cache) != null) { | |
| ref.clear(); | |
| } | |
| } | |
| }; | |
| qd.registerTemplate = function(name, templateNodes) { | |
| if (!(templateNodes instanceof Array)) { | |
| return qdInternal.errors["throw"](new QuickdrawError("Nodes for template must be given as an array")); | |
| } | |
| return qdInternal.templates.register(templateNodes, name); | |
| }; | |
| qdInternal.updates = { | |
| run: function() { | |
| qdInternal.async.cancel(qdInternal.state.updates.key); | |
| if (qd.getConfig('updatesEnabled')) { | |
| qdInternal.updates.updateNodeSet(qdInternal.state.updates.queue); | |
| qdInternal.state.updates.queue.length = 0; | |
| } | |
| qdInternal.state.updates.key = null; | |
| qdInternal.state.updates.immediate = false; | |
| }, | |
| updateNodeSet: function(nodes) { | |
| var bindingContext, dependency, i; | |
| qd.emit("updatesWillOccur", null, false); | |
| i = 0; | |
| while (i < nodes.length) { | |
| dependency = qdInternal.dom.virtualize(nodes[i++]); | |
| bindingContext = qdInternal.context.get(dependency); | |
| if (bindingContext == null) { | |
| continue; | |
| } | |
| qdInternal.binding.updateDomNode(dependency, bindingContext); | |
| } | |
| qdInternal.templates.clearCache(); | |
| qdInternal.renderer.schedule(); | |
| qd.emit("updatesHaveOccurred", null, false); | |
| }, | |
| schedule: function(immediately) { | |
| var updatesState; | |
| if (immediately == null) { | |
| immediately = false; | |
| } | |
| if (qd.getConfig('updatesAsync')) { | |
| updatesState = qdInternal.state.updates; | |
| if (updatesState.queue.length >= qd.getConfig('maxQueuedUpdates') || immediately) { | |
| if (!updatesState.immediate) { | |
| qdInternal.async.cancel(updatesState.key); | |
| updatesState.key = qdInternal.async.immediate(qdInternal.updates.run); | |
| updatesState.immediate = true; | |
| } | |
| } else if (updatesState.key == null) { | |
| updatesState.key = qdInternal.async.delayed(qdInternal.updates.run, qd.getConfig('defaultUpdateTimeout')); | |
| } | |
| } else { | |
| qdInternal.updates.run(); | |
| } | |
| }, | |
| enqueue: function(domNode) { | |
| if (indexOf.call(qdInternal.state.updates.queue, domNode) < 0) { | |
| qdInternal.state.updates.queue.push(domNode); | |
| } | |
| } | |
| }; | |
| qd.disableUpdates = function() { | |
| qd.setConfig('updatesEnabled', false); | |
| qdInternal.async.cancel(qdInternal.state.updates.key); | |
| qdInternal.state.updates.key = null; | |
| }; | |
| qd.enableUpdates = function(runEnqueuedSynchronously) { | |
| if (runEnqueuedSynchronously == null) { | |
| runEnqueuedSynchronously = false; | |
| } | |
| qd.setConfig('updatesEnabled', true); | |
| if (qdInternal.state.updates.queue.length > 0) { | |
| qdInternal.updates.schedule(true); | |
| if (runEnqueuedSynchronously) { | |
| qdInternal.updates.run(); | |
| } | |
| } | |
| }; | |
| qd.registerBindingHandler('attr', { | |
| update: function(bindingData, node) { | |
| var attrName, boundAttributes, newValue, oldValue, ref, ref1, value; | |
| boundAttributes = (ref = node.getValue('attributes')) != null ? ref : {}; | |
| ref1 = qd.unwrapObservable(bindingData); | |
| for (attrName in ref1) { | |
| if (!hasProp.call(ref1, attrName)) continue; | |
| value = ref1[attrName]; | |
| newValue = qd.unwrapObservable(value); | |
| oldValue = node.getAttribute(attrName); | |
| boundAttributes[attrName] = true; | |
| if ((newValue != null) && oldValue !== newValue) { | |
| node.setAttribute(attrName, newValue); | |
| } else if (newValue == null) { | |
| node.removeAttribute(attrName); | |
| } | |
| } | |
| node.setValue('attributes', boundAttributes); | |
| return true; | |
| }, | |
| cleanup: function(node) { | |
| var attrName, ref, value; | |
| ref = node.getValue('attributes'); | |
| for (attrName in ref) { | |
| value = ref[attrName]; | |
| node.removeAttribute(attrName); | |
| } | |
| } | |
| }); | |
| qd.registerBindingHandler('complete', { | |
| initialize: function(bindingData, node, bindingContext) { | |
| var error; | |
| if (typeof bindingData !== 'function') { | |
| error = new this.errors.QuickdrawError("Binding data for complete handler must be a callback function"); | |
| error.setBindingContext(bindingContext); | |
| return this.errors["throw"](error); | |
| } | |
| return this.async.immediate(function() { | |
| return bindingData(); | |
| }); | |
| } | |
| }); | |
| CSS_CLASS_DELIM = " "; | |
| qd.registerBindingHandler('css', { | |
| initialize: function(bindingData, node) { | |
| var ref, tokenizer; | |
| tokenizer = new this.strings.tokenizer((ref = node.getProperty('className')) != null ? ref : "", CSS_CLASS_DELIM); | |
| return node.setValue('original', tokenizer.toArray()); | |
| }, | |
| update: function(bindingData, node) { | |
| var aClass, className, classString, j, keep, len, original, toKeep, tokenizer, truth, value; | |
| toKeep = {}; | |
| original = node.getValue('original'); | |
| tokenizer = new this.strings.tokenizer(node.getProperty('className'), CSS_CLASS_DELIM); | |
| bindingData = qd.unwrapObservable(bindingData); | |
| for (j = 0, len = original.length; j < len; j++) { | |
| value = original[j]; | |
| toKeep[value] = true; | |
| } | |
| if (typeof bindingData === 'object') { | |
| tokenizer.map(function(token) { | |
| if (bindingData[token] != null) { | |
| return toKeep[token] = true; | |
| } | |
| }); | |
| for (className in bindingData) { | |
| if (!hasProp.call(bindingData, className)) continue; | |
| truth = bindingData[className]; | |
| truth = qd.unwrapObservable(truth); | |
| if (className === '_$') { | |
| toKeep[truth] = true; | |
| } else { | |
| toKeep[className] = truth; | |
| } | |
| } | |
| } else if (bindingData != null) { | |
| toKeep[bindingData] = true; | |
| } | |
| classString = ""; | |
| for (aClass in toKeep) { | |
| keep = toKeep[aClass]; | |
| if (keep) { | |
| classString = this.strings.appendWithDelimiter(classString, aClass, CSS_CLASS_DELIM); | |
| } | |
| } | |
| node.setProperty('className', classString); | |
| return true; | |
| }, | |
| cleanup: function(node) { | |
| var original, ref; | |
| original = (ref = node.getValue('original')) != null ? ref : []; | |
| return node.setProperty('className', original.join(CSS_CLASS_DELIM)); | |
| } | |
| }); | |
| qd.registerBindingHandler('disable', { | |
| update: function(bindingData, node) { | |
| var shouldDisable; | |
| shouldDisable = qd.unwrapObservable(bindingData); | |
| node.setProperty('disabled', shouldDisable ? true : false); | |
| return true; | |
| } | |
| }); | |
| qd.registerBindingHandler('enable', { | |
| update: function(bindingData, node) { | |
| var shouldEnable; | |
| shouldEnable = qd.unwrapObservable(bindingData); | |
| node.setProperty('disabled', !shouldEnable ? true : false); | |
| return true; | |
| } | |
| }); | |
| dispatchEvent = function(event) { | |
| var callback, context, currentTarget, eventName; | |
| currentTarget = event.target; | |
| eventName = event.type; | |
| callback = null; | |
| while ((currentTarget != null) && (callback == null)) { | |
| callback = this.storage.getValue(currentTarget, eventName, 'event'); | |
| if (callback == null) { | |
| currentTarget = currentTarget.parentElement; | |
| } | |
| } | |
| if (callback != null) { | |
| event.stopPropagation(); | |
| context = this.context.get(currentTarget); | |
| if (callback(context, event) !== true) { | |
| event.preventDefault(); | |
| } | |
| } | |
| return true; | |
| }; | |
| qd.registerBindingHandler('event', { | |
| initialize: function(bindingData, node) { | |
| var callback, document, eventName, globalRegistry, ref; | |
| document = node.getProperty('ownerDocument'); | |
| globalRegistry = (ref = this.storage.getValue(document, 'registry')) != null ? ref : {}; | |
| for (eventName in bindingData) { | |
| if (!hasProp.call(bindingData, eventName)) continue; | |
| callback = bindingData[eventName]; | |
| if (callback == null) { | |
| continue; | |
| } | |
| if (globalRegistry[eventName] == null) { | |
| globalRegistry[eventName] = (function(_this) { | |
| return function(event) { | |
| return dispatchEvent.call(_this, event); | |
| }; | |
| })(this); | |
| document.addEventListener(eventName, globalRegistry[eventName], true); | |
| } | |
| node.setValue(eventName, callback); | |
| } | |
| this.storage.setValue(document, 'registry', globalRegistry); | |
| if (this.state.current.model != null) { | |
| this.context.set(node, this.state.current.model); | |
| } | |
| } | |
| }); | |
| qd.registerBindingHandler('foreach', { | |
| initialize: function(bindingData, node) { | |
| var children, ref, templateName; | |
| children = node.getChildren(); | |
| templateName = (ref = children[0]) != null ? ref.getTemplateName() : void 0; | |
| if (templateName != null) { | |
| this.templates["return"](templateName, children); | |
| } else { | |
| templateName = this.templates.register(children); | |
| } | |
| node.setValue('childTemplate', templateName); | |
| node.clearChildren(); | |
| }, | |
| update: function(bindingData, node, bindingContext) { | |
| var child, childContext, context, curPos, currentChildren, declaredTemplate, doc, groupStartIndex, i, index, indexChanged, j, k, l, leftover, len, len1, len2, model, modelTemplate, newChildren, newIndex, nextModel, nodeGroup, nodes, nodesReused, pieces, rawBindingData, ref, ref1, ref2, ref3, ref4, ref5, templateName, useTemplatesFromModels; | |
| doc = node.getProperty('ownerDocument') || document; | |
| templateName = node.getValue('childTemplate'); | |
| rawBindingData = qd.unwrapObservable(bindingData); | |
| if (!(rawBindingData instanceof Array)) { | |
| useTemplatesFromModels = rawBindingData.templatesFromModels; | |
| rawBindingData = qd.unwrapObservable(rawBindingData.data); | |
| } | |
| if (useTemplatesFromModels == null) { | |
| useTemplatesFromModels = false; | |
| } | |
| pieces = {}; | |
| currentChildren = node.getChildren(); | |
| groupStartIndex = 0; | |
| while (groupStartIndex < currentChildren.length) { | |
| child = currentChildren[groupStartIndex]; | |
| index = child.getValue('index'); | |
| if (index != null) { | |
| nodeGroup = []; | |
| curPos = groupStartIndex; | |
| while (curPos < currentChildren.length && currentChildren[curPos].getValue('index') === index) { | |
| nodeGroup.push(currentChildren[curPos++]); | |
| } | |
| model = child.getValue('model'); | |
| modelTemplate = nodeGroup[0].getTemplateName(); | |
| newIndex = rawBindingData.indexOf(model); | |
| if (newIndex !== -1) { | |
| pieces[newIndex] = { | |
| model: model, | |
| indexChanged: newIndex !== index | |
| }; | |
| declaredTemplate = qd.unwrapObservable(rawBindingData[newIndex].template); | |
| declaredTemplate = this.templates.resolve(declaredTemplate); | |
| if (!useTemplatesFromModels || modelTemplate === declaredTemplate) { | |
| pieces[newIndex].nodes = nodeGroup; | |
| } | |
| } | |
| if (((ref = pieces[newIndex]) != null ? ref.nodes : void 0) == null) { | |
| for (j = 0, len = nodeGroup.length; j < len; j++) { | |
| leftover = nodeGroup[j]; | |
| qd.unbindModel(leftover); | |
| } | |
| this.templates["return"](modelTemplate, nodeGroup); | |
| } | |
| if (newIndex === -1 && qd.isObservable(model.template)) { | |
| this.observables.removeDependency.call(model.template, node); | |
| } | |
| groupStartIndex += nodeGroup.length; | |
| } else { | |
| groupStartIndex++; | |
| } | |
| } | |
| newChildren = []; | |
| for (i = k = 0, len1 = rawBindingData.length; k < len1; i = ++k) { | |
| model = rawBindingData[i]; | |
| modelTemplate = templateName; | |
| if (useTemplatesFromModels) { | |
| if (model.template == null) { | |
| this.errors["throw"](new QuickdrawError("Foreach told to use template from model but model does not specify one")); | |
| } | |
| modelTemplate = qd.unwrapObservable(model.template); | |
| if (qd.isObservable(model.template)) { | |
| this.observables.addDependency.call(model.template, this.models.get(node), node, 'foreach'); | |
| } | |
| } | |
| nodes = (ref1 = (ref2 = pieces[i]) != null ? ref2.nodes : void 0) != null ? ref1 : this.templates.get(modelTemplate, doc); | |
| indexChanged = (ref3 = (ref4 = pieces[i]) != null ? ref4.indexChanged : void 0) != null ? ref3 : true; | |
| nodesReused = ((ref5 = pieces[i]) != null ? ref5.nodes : void 0) != null; | |
| for (l = 0, len2 = nodes.length; l < len2; l++) { | |
| child = nodes[l]; | |
| child.setValue('index', i); | |
| child.setValue('model', model); | |
| newChildren.push(child); | |
| if (child.getProperty('nodeType') === 1) { | |
| if (nodesReused && indexChanged) { | |
| context = child.getValue('context'); | |
| context.$index(i); | |
| } else if (!nodesReused) { | |
| nextModel = this.models.create(model); | |
| childContext = bindingContext.$extend(nextModel); | |
| childContext.$index = qd.observable(i); | |
| this.binding.bindModel(nextModel, child, childContext); | |
| child.setValue('context', childContext); | |
| } | |
| } | |
| } | |
| } | |
| node.setChildren(newChildren); | |
| rawBindingData = null; | |
| pieces = null; | |
| nodeGroup = null; | |
| child = null; | |
| node = null; | |
| leftover = null; | |
| return false; | |
| }, | |
| cleanup: function(node) { | |
| var child, children, curPos, dispose, groupStartIndex, groupTemplate, index, j, len, nodeGroup, originalChildren, ref, templateName; | |
| templateName = node.getValue('childTemplate'); | |
| children = node.getChildren(); | |
| groupStartIndex = 0; | |
| while (groupStartIndex < children.length) { | |
| child = children[groupStartIndex]; | |
| index = child.getValue('index'); | |
| if (index != null) { | |
| nodeGroup = []; | |
| curPos = groupStartIndex; | |
| while (curPos < children.length && children[curPos].getValue('index') === index) { | |
| nodeGroup.push(children[curPos++]); | |
| } | |
| groupTemplate = (ref = child.getTemplateName()) != null ? ref : templateName; | |
| for (j = 0, len = nodeGroup.length; j < len; j++) { | |
| dispose = nodeGroup[j]; | |
| qd.unbindModel(dispose); | |
| } | |
| this.templates["return"](groupTemplate, nodeGroup); | |
| groupStartIndex += nodeGroup.length; | |
| } else { | |
| groupStartIndex++; | |
| } | |
| } | |
| originalChildren = this.templates.get(templateName, node.getProperty('ownerDocument')); | |
| node.setChildren(originalChildren); | |
| children = null; | |
| child = null; | |
| nodeGroup = null; | |
| } | |
| }, ["template"]); | |
| qd.registerBindingHandler('html', { | |
| update: function(bindingData, node) { | |
| var dataToSet; | |
| dataToSet = qd.unwrapObservable(bindingData); | |
| node.setProperty('innerHTML', dataToSet); | |
| return true; | |
| } | |
| }); | |
| qd.registerBindingHandler('if', { | |
| initialize: function(bindingData, node) { | |
| var children, ref, templateName; | |
| children = node.getChildren(); | |
| templateName = (ref = children[0]) != null ? ref.getTemplateName() : void 0; | |
| if (templateName != null) { | |
| this.templates["return"](templateName, children); | |
| } else { | |
| templateName = this.templates.register(children); | |
| } | |
| node.setValue('template', templateName); | |
| node.setValue('hasNodes', false); | |
| this.context.set(node, this.state.current.model); | |
| return node.clearChildren(); | |
| }, | |
| update: function(bindingData, node, bindingContext) { | |
| var child, children, hasNodes, j, k, len, len1, ref, templateName, truthValue; | |
| truthValue = qd.unwrapObservable(bindingData); | |
| templateName = node.getValue('template'); | |
| hasNodes = node.getValue('hasNodes'); | |
| children = node.getChildren(); | |
| if (truthValue && !hasNodes) { | |
| node.setChildren(this.templates.get(templateName, node.getProperty('ownerDocument'))); | |
| ref = node.getChildren(); | |
| for (j = 0, len = ref.length; j < len; j++) { | |
| child = ref[j]; | |
| if (child.getProperty('nodeType') === 1) { | |
| this.binding.bindModel(this.models.get(node), child, bindingContext); | |
| } | |
| } | |
| node.setValue('hasNodes', true); | |
| } else if (!truthValue && hasNodes) { | |
| for (k = 0, len1 = children.length; k < len1; k++) { | |
| child = children[k]; | |
| qd.unbindModel(child); | |
| } | |
| this.templates["return"](templateName, children); | |
| node.clearChildren(); | |
| node.setValue('hasNodes', false); | |
| } | |
| return false; | |
| }, | |
| cleanup: function(node) { | |
| var hasNodes, templateName; | |
| hasNodes = node.getValue('hasNodes'); | |
| templateName = node.getValue('template'); | |
| if (!hasNodes) { | |
| node.setChildren(this.templates.get(templateName, node.getProperty('ownerDocument'))); | |
| } | |
| } | |
| }, ["template"]); | |
| qd.registerBindingHandler('style', { | |
| update: function(bindingData, node) { | |
| var changes, newValue, oldValue, styleName, value; | |
| changes = node.getValue('changes'); | |
| for (styleName in bindingData) { | |
| if (!hasProp.call(bindingData, styleName)) continue; | |
| value = bindingData[styleName]; | |
| newValue = qd.unwrapObservable(value); | |
| oldValue = node.getStyle(styleName); | |
| if (oldValue !== newValue) { | |
| if (changes == null) { | |
| changes = {}; | |
| } | |
| if (changes[styleName] == null) { | |
| changes[styleName] = oldValue; | |
| } | |
| node.setStyle(styleName, newValue); | |
| } | |
| } | |
| if (changes != null) { | |
| node.setValue('changes', changes); | |
| } | |
| return true; | |
| }, | |
| cleanup: function(node) { | |
| var changes, key, value; | |
| changes = node.getValue('changes'); | |
| if (changes != null) { | |
| for (key in changes) { | |
| value = changes[key]; | |
| node.setStyle(key, value); | |
| } | |
| } | |
| } | |
| }); | |
| qd.registerBindingHandler('template', { | |
| initialize: function(templateName, containerNode, bindingContext) { | |
| var error, templateNodes; | |
| templateName = qd.unwrapObservable(templateName); | |
| if (templateName == null) { | |
| return true; | |
| } | |
| if (!this.templates.exists(templateName)) { | |
| error = new this.errors.QuickdrawError("Given template `" + templateName + "` has not been registered with Quickdraw"); | |
| error.setBindingContext(bindingContext); | |
| return this.errors["throw"](error); | |
| } | |
| containerNode.setValue('template', templateName); | |
| templateNodes = this.templates.get(templateName, containerNode.getProperty('ownerDocument')); | |
| containerNode.setChildren(templateNodes); | |
| return true; | |
| }, | |
| cleanup: function(node) { | |
| var child, children, j, len, templateName; | |
| children = node.getChildren(); | |
| for (j = 0, len = children.length; j < len; j++) { | |
| child = children[j]; | |
| this.binding.unbindDomTree(child); | |
| } | |
| templateName = node.getValue('template'); | |
| this.templates["return"](templateName, children); | |
| node.clearChildren(); | |
| } | |
| }); | |
| qd.registerBindingHandler('text', { | |
| update: function(bindingData, node) { | |
| var dataToSet; | |
| dataToSet = qd.unwrapObservable(bindingData); | |
| node.setProperty('textContent', dataToSet); | |
| return true; | |
| } | |
| }); | |
| qd.registerBindingHandler('uniqueName', { | |
| initialize: function(bindingData, node) { | |
| var nodeId; | |
| nodeId = this.dom.uniqueId(node); | |
| return node.setAttribute('name', 'qd_' + nodeId); | |
| } | |
| }); | |
| qd.registerBindingHandler('visible', { | |
| update: function(bindingData, node) { | |
| node.setStyle('display', qd.unwrapObservable(bindingData) ? "" : "none"); | |
| return true; | |
| } | |
| }); | |
| qd.registerBindingHandler('with', { | |
| initialize: function(bindingData, node) { | |
| var children, ref, templateName; | |
| children = node.getChildren(); | |
| templateName = (ref = children[0]) != null ? ref.getTemplateName() : void 0; | |
| if (templateName != null) { | |
| this.templates["return"](templateName, children); | |
| } else { | |
| templateName = this.templates.register(children); | |
| } | |
| node.setValue('originalTemplate', templateName); | |
| node.clearChildren(); | |
| }, | |
| update: function(bindingData, node, bindingContext) { | |
| var child, childBindingData, childContext, children, currentTemplate, dataHasChanged, dataToBind, j, k, len, len1, ref, templateHasChanged, templateName, useTemplateFromModel; | |
| dataToBind = qd.unwrapObservable(bindingData); | |
| templateName = node.getValue('originalTemplate'); | |
| if ((dataToBind != null) && (dataToBind.templateFromModel != null)) { | |
| useTemplateFromModel = dataToBind.templateFromModel; | |
| if (!dataToBind.hasOwnProperty('model')) { | |
| this.errors["throw"](new QuickdrawError("When specifing options to 'with' you must specify a model to use for child binding")); | |
| } | |
| dataToBind = qd.unwrapObservable(dataToBind.model); | |
| if ((dataToBind != null) && useTemplateFromModel) { | |
| if (dataToBind.template == null) { | |
| this.errors["throw"](new QuickdrawError("You have requested 'with' to use templates from the model but have not specified one")); | |
| } | |
| templateName = qd.unwrapObservable(dataToBind.template); | |
| } | |
| } | |
| currentTemplate = node.getValue('template'); | |
| templateHasChanged = templateName !== currentTemplate; | |
| dataHasChanged = dataToBind !== node.getValue('model'); | |
| if ((currentTemplate != null) && (dataHasChanged || templateHasChanged)) { | |
| children = node.getChildren(); | |
| for (j = 0, len = children.length; j < len; j++) { | |
| child = children[j]; | |
| qd.unbindModel(child); | |
| } | |
| node.setValue('model', null); | |
| if ((dataToBind == null) || templateHasChanged) { | |
| this.templates["return"](currentTemplate, children); | |
| node.setValue('template', null); | |
| node.clearChildren(); | |
| } | |
| } | |
| if (dataToBind == null) { | |
| return false; | |
| } | |
| if (templateHasChanged) { | |
| node.setChildren(this.templates.get(templateName, node.getProperty('ownerDocument'))); | |
| node.setValue('template', templateName); | |
| } | |
| if (dataHasChanged || templateHasChanged) { | |
| childBindingData = this.models.create(dataToBind); | |
| childContext = bindingContext.$extend(childBindingData); | |
| ref = node.getChildren(); | |
| for (k = 0, len1 = ref.length; k < len1; k++) { | |
| child = ref[k]; | |
| if (child.getProperty('nodeType') === 1) { | |
| this.binding.bindModel(childBindingData, child, childContext); | |
| } | |
| } | |
| node.setValue('model', dataToBind); | |
| } | |
| return false; | |
| }, | |
| cleanup: function(node) { | |
| var child, children, currentTemplate, j, len, templateName; | |
| currentTemplate = node.getValue('template'); | |
| templateName = node.getValue('originalTemplate'); | |
| if (currentTemplate != null) { | |
| children = node.getChildren(); | |
| for (j = 0, len = children.length; j < len; j++) { | |
| child = children[j]; | |
| qd.unbindModel(child); | |
| } | |
| this.templates["return"](currentTemplate, children); | |
| } | |
| node.setChildren(this.templates.get(templateName, node.getProperty('ownerDocument'))); | |
| } | |
| }, ["template"]); | |
| }).call(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment