diff options
Diffstat (limited to 'contexts/data/lib/closure-library/closure/goog/datasource/fastdatanode.js')
-rw-r--r-- | contexts/data/lib/closure-library/closure/goog/datasource/fastdatanode.js | 812 |
1 files changed, 0 insertions, 812 deletions
diff --git a/contexts/data/lib/closure-library/closure/goog/datasource/fastdatanode.js b/contexts/data/lib/closure-library/closure/goog/datasource/fastdatanode.js deleted file mode 100644 index d745cff..0000000 --- a/contexts/data/lib/closure-library/closure/goog/datasource/fastdatanode.js +++ /dev/null @@ -1,812 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview - * Efficient implementation of DataNode API. - * - * The implementation consists of three concrete classes for modelling - * DataNodes with different characteristics: FastDataNode, - * FastPrimitiveDataNode and FastListNode. - * - * FastDataNode is for bean-like or map-like objects that consists of - * key/value mappings and where the primary access pattern is by key. - * - * FastPrimitiveDataNode wraps primitives like strings, boolean, and numbers. - * - * FastListNode is for array-like data nodes. It also supports key-based - * lookups if the data nodes have an "id" property or if child nodes are - * explicitly added by name. It is most efficient if these features are not - * used. - * - * FastDataNodes can be constructed from JSON-like objects via the function - * goog.ds.FastDataNode.fromJs. - - */ - -goog.provide('goog.ds.AbstractFastDataNode'); -goog.provide('goog.ds.FastDataNode'); -goog.provide('goog.ds.FastListNode'); -goog.provide('goog.ds.PrimitiveFastDataNode'); - -goog.require('goog.ds.DataManager'); -goog.require('goog.ds.EmptyNodeList'); -goog.require('goog.string'); - -/* - * Implementation note: In order to reduce the number of objects, - * FastDataNode stores its key/value mappings directly in the FastDataNode - * object iself (instead of a separate map). To make this work we have to - * sure that there are no name clashes with other attribute names used by - * FastDataNode (like dataName and parent). This is especially difficult in - * the light of automatic renaming by the JavaScript compiler. For this reason, - * all internal attributes start with "__" so that they are not renamed - * by the compiler. - */ - -/** - * Creates a new abstract data node. - * @param {string} dataName Name of the datanode. - * @param {goog.ds.DataNode=} opt_parent Parent of this data node. - * @constructor - * @extends {goog.ds.DataNodeList} - */ -// TODO(arv): Use interfaces when available. -goog.ds.AbstractFastDataNode = function(dataName, opt_parent) { - if (!dataName) { - throw Error('Cannot create a fast data node without a data name'); - } - this['__dataName'] = dataName; - this['__parent'] = opt_parent; -}; - - -/** - * Return the name of this data node. - * @return {string} Name of this data noden. - * @override - */ -goog.ds.AbstractFastDataNode.prototype.getDataName = function() { - return this['__dataName']; -}; - - -/** - * Set the name of this data node. - * @param {string} value Name. - * @override - */ -goog.ds.AbstractFastDataNode.prototype.setDataName = function(value) { - this['__dataName'] = value; -}; - - -/** - * Get the path leading to this data node. - * @return {string} Data path. - * @override - */ -goog.ds.AbstractFastDataNode.prototype.getDataPath = function() { - var parentPath; - if (this['__parent']) { - parentPath = this['__parent'].getDataPath() + goog.ds.STR_PATH_SEPARATOR; - } else { - parentPath = ''; - } - return parentPath + this.getDataName(); -}; - - - -/** - * Creates a new fast data node, using the properties of root. - * @param {Object} root JSON-like object to initialize data node from. - * @param {string} dataName Name of this data node. - * @param {goog.ds.DataNode=} opt_parent Parent of this data node. - * @extends {goog.ds.AbstractFastDataNode} - * @constructor - */ -goog.ds.FastDataNode = function(root, dataName, opt_parent) { - goog.ds.AbstractFastDataNode.call(this, dataName, opt_parent); - this.extendWith_(root); -}; -goog.inherits(goog.ds.FastDataNode, goog.ds.AbstractFastDataNode); - - -/** - * Add all attributes of object to this data node. - * @param {Object} object Object to add attributes from. - * @protected - * @suppress {underscore} - */ -goog.ds.FastDataNode.prototype.extendWith_ = function(object) { - for (var key in object) { - this[key] = object[key]; - } -}; - - -/** - * Creates a new FastDataNode structure initialized from object. This will - * return an instance of the most suitable sub-class of FastDataNode. - * - * You should not modify object after creating a fast data node from it - * or assume that changing object changes the data node. Doing so results - * in undefined behaviour. - * - * @param {Object|number|boolean|string} object Object to initialize data - * node from. - * @param {string} dataName Name of data node. - * @param {goog.ds.DataNode=} opt_parent Parent of data node. - * @return {goog.ds.AbstractFastDataNode} Data node representing object. - */ -goog.ds.FastDataNode.fromJs = function(object, dataName, opt_parent) { - if (goog.isArray(object)) { - return new goog.ds.FastListNode(object, dataName, opt_parent); - } else if (goog.isObject(object)) { - return new goog.ds.FastDataNode(object, dataName, opt_parent); - } else { - return new goog.ds.PrimitiveFastDataNode(object || !!object, - dataName, - opt_parent); - } -}; - - -/** - * Static instance of an empty list. - * @type {goog.ds.EmptyNodeList} - * @private - */ -goog.ds.FastDataNode.emptyList_ = new goog.ds.EmptyNodeList(); - - -/** - * Not supported for normal FastDataNodes. - * @param {*} value Value to set data node to. - * @override - */ -goog.ds.FastDataNode.prototype.set = function(value) { - throw 'Not implemented yet'; -}; - - -/** @override */ -goog.ds.FastDataNode.prototype.getChildNodes = function(opt_selector) { - if (!opt_selector || opt_selector == goog.ds.STR_ALL_CHILDREN_SELECTOR) { - return this; - } else if (opt_selector.indexOf(goog.ds.STR_WILDCARD) == -1) { - var child = this.getChildNode(opt_selector); - return child ? new goog.ds.FastListNode([child], '') : - new goog.ds.EmptyNodeList(); - } else { - throw Error('Unsupported selector: ' + opt_selector); - } -}; - - -/** - * Makes sure that a named child is wrapped in a data node structure. - * @param {string} name Name of child to wrap. - * @private - */ -goog.ds.FastDataNode.prototype.wrapChild_ = function(name) { - var child = this[name]; - if (child != null && !child.getDataName) { - this[name] = goog.ds.FastDataNode.fromJs(this[name], name, this); - } -}; - - -/** - * Get a child node by name. - * @param {string} name Name of child node. - * @param {boolean=} opt_create Whether to create the child if it does not - * exist. - * @return {goog.ds.DataNode} Child node. - * @override - */ -goog.ds.FastDataNode.prototype.getChildNode = function(name, opt_create) { - this.wrapChild_(name); - // this[name] always is a data node object, so using "||" is fine. - var child = this[name] || null; - if (child == null && opt_create) { - child = new goog.ds.FastDataNode({}, name, this); - this[name] = child; - } - return child; -}; - - -/** - * Sets a child node. Creates the child if it does not exist. - * - * Calling this function makes any child nodes previously obtained for name - * invalid. You should not use these child nodes but instead obtain a new - * instance by calling getChildNode. - * - * @override - */ -goog.ds.FastDataNode.prototype.setChildNode = function(name, value) { - if (value != null) { - this[name] = value; - } else { - delete this[name]; - } - goog.ds.DataManager.getInstance().fireDataChange(this.getDataPath() + - goog.ds.STR_PATH_SEPARATOR + name); - return null; -}; - - -/** - * Returns the value of a child node. By using this method you can avoid - * the need to create PrimitiveFastData nodes. - * @param {string} name Name of child node. - * @return {Object} Value of child node. - * @override - */ -goog.ds.FastDataNode.prototype.getChildNodeValue = function(name) { - var child = this[name]; - if (child != null) { - return (child.getDataName ? child.get() : child); - } else { - return null; - } -}; - - -/** - * Returns whether this data node is a list. Always returns false for - * instances of FastDataNode but may return true for subclasses. - * @return {boolean} Whether this data node is array-like. - * @override - */ -goog.ds.FastDataNode.prototype.isList = function() { - return false; -}; - - -/** - * Returns a javascript object representation of this data node. You should - * not modify the object returned by this function. - * @return {Object} Javascript object representation of this data node. - */ -goog.ds.FastDataNode.prototype.getJsObject = function() { - var result = {}; - for (var key in this) { - if (!goog.string.startsWith(key, '__') && !goog.isFunction(this[key])) { - result[key] = (this[key]['__dataName'] ? this[key].getJsObject() : - this[key]); - } - } - return result; -}; - - -/** - * Creates a deep copy of this data node. - * @return {goog.ds.FastDataNode} Clone of this data node. - */ -goog.ds.FastDataNode.prototype.clone = function() { - return /** @type {goog.ds.FastDataNode} */(goog.ds.FastDataNode.fromJs( - this.getJsObject(), this.getDataName())); -}; - - -/* - * Implementation of goog.ds.DataNodeList for FastDataNode. - */ - - -/** - * Adds a child to this data node. - * @param {goog.ds.DataNode} value Child node to add. - * @override - */ -goog.ds.FastDataNode.prototype.add = function(value) { - this.setChildNode(value.getDataName(), value); -}; - - -/** - * Gets the value of this data node (if called without opt_key) or - * gets a child node (if called with opt_key). - * @param {string=} opt_key Name of child node. - * @return {*} This data node or a child node. - * @override - */ -goog.ds.FastDataNode.prototype.get = function(opt_key) { - if (!goog.isDef(opt_key)) { - // if there is no key, DataNode#get was called - return this; - } else { - return this.getChildNode(opt_key); - } -}; - - -/** - * Gets a child node by index. This method has a complexity of O(n) where - * n is the number of children. If you need a faster implementation of this - * method, you should use goog.ds.FastListNode. - * @param {number} index Index of child node (starting from 0). - * @return {goog.ds.DataNode} Child node at specified index. - * @override - */ -goog.ds.FastDataNode.prototype.getByIndex = function(index) { - var i = 0; - for (var key in this) { - if (!goog.string.startsWith(key, '__') && !goog.isFunction(this[key])) { - if (i == index) { - this.wrapChild_(key); - return this[key]; - } - ++i; - } - } - return null; -}; - - -/** - * Gets the number of child nodes. This method has a complexity of O(n) where - * n is the number of children. If you need a faster implementation of this - * method, you should use goog.ds.FastListNode. - * @return {number} Number of child nodes. - * @override - */ -goog.ds.FastDataNode.prototype.getCount = function() { - var count = 0; - for (var key in this) { - if (!goog.string.startsWith(key, '__') && !goog.isFunction(this[key])) { - ++count; - } - } - // maybe cache this? - return count; -}; - - -/** - * Sets a child node. - * @param {string} name Name of child node. - * @param {Object} value Value of child node. - * @override - */ -goog.ds.FastDataNode.prototype.setNode = function(name, value) { - this.setChildNode(name, value); -}; - - -/** - * Removes a child node. - * @override - */ -goog.ds.FastDataNode.prototype.removeNode = function(name) { - delete this[name]; - return false; -}; - - - -/** - * Creates a new data node wrapping a primitive value. - * @param {number|boolean|string} value Value the value to wrap. - * @param {string} dataName name Name of this data node. - * @param {goog.ds.DataNode=} opt_parent Parent of this data node. - * @extends {goog.ds.AbstractFastDataNode} - * @constructor - */ -goog.ds.PrimitiveFastDataNode = function(value, dataName, opt_parent) { - this.value_ = value; - goog.ds.AbstractFastDataNode.call(this, dataName, opt_parent); -}; -goog.inherits(goog.ds.PrimitiveFastDataNode, goog.ds.AbstractFastDataNode); - - -/** - * Returns the value of this data node. - * @return {(boolean|number|string)} Value of this data node. - * @override - */ -goog.ds.PrimitiveFastDataNode.prototype.get = function() { - return this.value_; -}; - - -/** - * Sets this data node to a new value. - * @param {*} value Value to set data node to. - * @override - */ -goog.ds.PrimitiveFastDataNode.prototype.set = function(value) { - if (goog.isArray(value) || goog.isObject(value)) { - throw Error('can only set PrimitiveFastDataNode to primitive values'); - } - this.value_ = value; - goog.ds.DataManager.getInstance().fireDataChange(this.getDataPath()); -}; - - -/** - * Returns child nodes of this data node. Always returns an unmodifiable, - * empty list. - * @return {goog.ds.DataNodeList} (Empty) list of child nodes. - * @override - */ -goog.ds.PrimitiveFastDataNode.prototype.getChildNodes = function() { - return goog.ds.FastDataNode.emptyList_; -}; - - -/** - * Get a child node by name. Always returns null. - * @param {string} name Name of child node. - * @return {goog.ds.DataNode} Child node. - * @override - */ -goog.ds.PrimitiveFastDataNode.prototype.getChildNode = function(name) { - return null; -}; - - -/** - * Returns the value of a child node. Always returns null. - * @param {string} name Name of child node. - * @return {Object} Value of child node. - * @override - */ -goog.ds.PrimitiveFastDataNode.prototype.getChildNodeValue = function(name) { - return null; -}; - - -/** - * Not supported by primitive data nodes. - * @param {string} name Name of child node. - * @param {Object} value Value of child node. - * @override - */ -goog.ds.PrimitiveFastDataNode.prototype.setChildNode = - function(name, value) { - throw Error('Cannot set a child node for a PrimitiveFastDataNode'); -}; - - -/** - * Returns whether this data node is a list. Always returns false for - * instances of PrimitiveFastDataNode. - * @return {boolean} Whether this data node is array-like. - * @override - */ -goog.ds.PrimitiveFastDataNode.prototype.isList = function() { - return false; -}; - - -/** - * Returns a javascript object representation of this data node. You should - * not modify the object returned by this function. - * @return {*} Javascript object representation of this data node. - */ -goog.ds.PrimitiveFastDataNode.prototype.getJsObject = function() { - return this.value_; -}; - - -/** - * Creates a new list node from an array. - * @param {Array} values values hold by this list node. - * @param {string} dataName name of this node. - * @param {goog.ds.DataNode=} opt_parent parent of this node. - * @extends {goog.ds.AbstractFastDataNode} - * @constructor - */ -// TODO(arv): Use interfaces when available. This implements DataNodeList -// as well. -goog.ds.FastListNode = function(values, dataName, opt_parent) { - this.values_ = []; - for (var i = 0; i < values.length; ++i) { - var name = values[i].id || ('[' + i + ']'); - this.values_.push(goog.ds.FastDataNode.fromJs(values[i], name, this)); - if (values[i].id) { - if (!this.map_) { - this.map_ = {}; - } - this.map_[values[i].id] = i; - } - } - goog.ds.AbstractFastDataNode.call(this, dataName, opt_parent); -}; -goog.inherits(goog.ds.FastListNode, goog.ds.AbstractFastDataNode); - - -/** - * Not supported for FastListNodes. - * @param {*} value Value to set data node to. - * @override - */ -goog.ds.FastListNode.prototype.set = function(value) { - throw Error('Cannot set a FastListNode to a new value'); -}; - - -/** - * Returns child nodes of this data node. Currently, only supports - * returning all children. - * @return {goog.ds.DataNodeList} List of child nodes. - * @override - */ -goog.ds.FastListNode.prototype.getChildNodes = function() { - return this; -}; - - -/** - * Get a child node by name. - * @param {string} key Name of child node. - * @param {boolean=} opt_create Whether to create the child if it does not - * exist. - * @return {goog.ds.DataNode} Child node. - * @override - */ -goog.ds.FastListNode.prototype.getChildNode = function(key, opt_create) { - var index = this.getKeyAsNumber_(key); - if (index == null && this.map_) { - index = this.map_[key]; - } - if (index != null && this.values_[index]) { - return this.values_[index]; - } else if (opt_create) { - this.setChildNode(key, {}); - return this.getChildNode(key); - } else { - return null; - } -}; - - -/** - * Returns the value of a child node. - * @param {string} key Name of child node. - * @return {*} Value of child node. - * @override - */ -goog.ds.FastListNode.prototype.getChildNodeValue = function(key) { - var child = this.getChildNode(key); - return (child ? child.get() : null); -}; - - -/** - * Tries to interpret key as a numeric index enclosed by square brakcets. - * @param {string} key Key that should be interpreted as a number. - * @return {?number} Numeric index or null if key is not of the form - * described above. - * @private - */ -goog.ds.FastListNode.prototype.getKeyAsNumber_ = function(key) { - if (key.charAt(0) == '[' && key.charAt(key.length - 1) == ']') { - return Number(key.substring(1, key.length - 1)); - } else { - return null; - } -}; - - -/** - * Sets a child node. Creates the child if it does not exist. To set - * children at a certain index, use a key of the form '[index]'. Note, that - * you can only set values at existing numeric indices. To add a new node - * to this list, you have to use the add method. - * - * Calling this function makes any child nodes previously obtained for name - * invalid. You should not use these child nodes but instead obtain a new - * instance by calling getChildNode. - * - * @override - */ -goog.ds.FastListNode.prototype.setChildNode = function(key, value) { - var count = this.values_.length; - if (value != null) { - if (!value.getDataName) { - value = goog.ds.FastDataNode.fromJs(value, key, this); - } - var index = this.getKeyAsNumber_(key); - if (index != null) { - if (index < 0 || index >= this.values_.length) { - throw Error('List index out of bounds: ' + index); - } - this.values_[key] = value; - } else { - if (!this.map_) { - this.map_ = {}; - } - this.values_.push(value); - this.map_[key] = this.values_.length - 1; - } - } else { - this.removeNode(key); - } - var dm = goog.ds.DataManager.getInstance(); - dm.fireDataChange(this.getDataPath() + goog.ds.STR_PATH_SEPARATOR + key); - if (this.values_.length != count) { - this.listSizeChanged_(); - } - return null; -}; - - -/** - * Fire data changes that are appropriate when the size of this list changes. - * Should be called whenever the list size has changed. - * @private - */ -goog.ds.FastListNode.prototype.listSizeChanged_ = function() { - var dm = goog.ds.DataManager.getInstance(); - dm.fireDataChange(this.getDataPath()); - dm.fireDataChange(this.getDataPath() + goog.ds.STR_PATH_SEPARATOR + - 'count()'); -}; - - -/** - * Returns whether this data node is a list. Always returns true. - * @return {boolean} Whether this data node is array-like. - * @override - */ -goog.ds.FastListNode.prototype.isList = function() { - return true; -}; - - -/** - * Returns a javascript object representation of this data node. You should - * not modify the object returned by this function. - * @return {Object} Javascript object representation of this data node. - */ -goog.ds.FastListNode.prototype.getJsObject = function() { - var result = []; - for (var i = 0; i < this.values_.length; ++i) { - result.push(this.values_[i].getJsObject()); - } - return result; -}; - - -/* - * Implementation of goog.ds.DataNodeList for FastListNode. - */ - - -/** - * Adds a child to this data node - * @param {goog.ds.DataNode} value Child node to add. - * @override - */ -goog.ds.FastListNode.prototype.add = function(value) { - if (!value.getDataName) { - value = goog.ds.FastDataNode.fromJs(value, - String('[' + (this.values_.length) + ']'), this); - } - this.values_.push(value); - var dm = goog.ds.DataManager.getInstance(); - dm.fireDataChange(this.getDataPath() + goog.ds.STR_PATH_SEPARATOR + - '[' + (this.values_.length - 1) + ']'); - this.listSizeChanged_(); -}; - - -/** - * Gets the value of this data node (if called without opt_key) or - * gets a child node (if called with opt_key). - * @param {string=} opt_key Name of child node. - * @return {Array|goog.ds.DataNode} Array of child nodes (if called without - * opt_key), or a named child node otherwise. - * @override - */ -goog.ds.FastListNode.prototype.get = function(opt_key) { - // if there are no arguments, DataNode.get was called - if (!goog.isDef(opt_key)) { - return this.values_; - } else { - return this.getChildNode(opt_key); - } -}; - - -/** - * Gets a child node by (numeric) index. - * @param {number} index Index of child node (starting from 0). - * @return {goog.ds.DataNode} Child node at specified index. - * @override - */ -goog.ds.FastListNode.prototype.getByIndex = function(index) { - var child = this.values_[index]; - return (child != null ? child : null); // never return undefined -}; - - -/** - * Gets the number of child nodes. - * @return {number} Number of child nodes. - * @override - */ -goog.ds.FastListNode.prototype.getCount = function() { - return this.values_.length; -}; - - -/** - * Sets a child node. - * @param {string} name Name of child node. - * @param {Object} value Value of child node. - * @override - */ -goog.ds.FastListNode.prototype.setNode = function(name, value) { - throw Error('Setting child nodes of a FastListNode is not implemented, yet'); -}; - - -/** - * Removes a child node. - * @override - */ -goog.ds.FastListNode.prototype.removeNode = function(name) { - var index = this.getKeyAsNumber_(name); - if (index == null && this.map_) { - index = this.map_[name]; - } - if (index != null) { - this.values_.splice(index, 1); - if (this.map_) { - var keyToDelete = null; - for (var key in this.map_) { - if (this.map_[key] == index) { - keyToDelete = key; - } else if (this.map_[key] > index) { - --this.map_[key]; - } - } - if (keyToDelete) { - delete this.map_[keyToDelete]; - } - } - var dm = goog.ds.DataManager.getInstance(); - dm.fireDataChange(this.getDataPath() + goog.ds.STR_PATH_SEPARATOR + - '[' + index + ']'); - this.listSizeChanged_(); - } - return false; -}; - - -/** - * Returns the index of a named child nodes. This method only works if - * this list uses mixed name/indexed lookup, i.e. if its child node have - * an 'id' attribute. - * @param {string} name Name of child node to determine index of. - * @return {number} Index of child node named name. - */ -goog.ds.FastListNode.prototype.indexOf = function(name) { - var index = this.getKeyAsNumber_(name); - if (index == null && this.map_) { - index = this.map_[name]; - } - if (index == null) { - throw Error('Cannot determine index for: ' + name); - } - return /** @type {number} */(index); -}; |