Created
February 22, 2019 21:09
-
-
Save alejandrolechuga/39353b2c429448e24ddbc3d11a369d02 to your computer and use it in GitHub Desktop.
This file contains 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