123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658 |
- // Copyright 2006 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 Generic rich data access API.
- *
- * Abstraction for data sources that allows listening for changes at different
- * levels of the data tree and updating the data via XHR requests
- *
- */
- goog.provide('goog.ds.BaseDataNode');
- goog.provide('goog.ds.BasicNodeList');
- goog.provide('goog.ds.DataNode');
- goog.provide('goog.ds.DataNodeList');
- goog.provide('goog.ds.EmptyNodeList');
- goog.provide('goog.ds.LoadState');
- goog.provide('goog.ds.SortedNodeList');
- goog.provide('goog.ds.Util');
- goog.provide('goog.ds.logger');
- goog.require('goog.array');
- goog.require('goog.log');
- /**
- * Interface for node in rich data tree.
- *
- * Names that are reserved for system use and shouldn't be used for data node
- * names: eval, toSource, toString, unwatch, valueOf, watch. Behavior is
- * undefined if these names are used.
- *
- * @constructor
- */
- goog.ds.DataNode = function() {};
- /**
- * Get the value of the node
- * @param {...?} var_args Do not check arity of arguments, because
- * some subclasses require args.
- * @return {*} The value of the node, or null if no value.
- */
- goog.ds.DataNode.prototype.get = goog.abstractMethod;
- /**
- * Set the value of the node
- * @param {*} value The new value of the node.
- */
- goog.ds.DataNode.prototype.set = goog.abstractMethod;
- /**
- * Gets all of the child nodes of the current node.
- * Should return an empty DataNode list if no child nodes.
- * @param {string=} opt_selector String selector to choose child nodes.
- * @return {!goog.ds.DataNodeList} The child nodes.
- */
- goog.ds.DataNode.prototype.getChildNodes = goog.abstractMethod;
- /**
- * Gets a named child node of the current node
- * @param {string} name The node name.
- * @param {boolean=} opt_canCreate Whether to create a child node if it does not
- * exist.
- * @return {goog.ds.DataNode} The child node, or null
- * if no node of this name exists.
- */
- goog.ds.DataNode.prototype.getChildNode = goog.abstractMethod;
- /**
- * Gets the value of a child node
- * @param {string} name The node name.
- * @return {*} The value of the node, or null if no value or the child node
- * doesn't exist.
- */
- goog.ds.DataNode.prototype.getChildNodeValue = goog.abstractMethod;
- /**
- * Sets a named child node of the current node.
- *
- * @param {string} name The node name.
- * @param {Object} value The value to set, can be DataNode, object, property,
- * or null. If value is null, removes the child node.
- * @return {Object} The child node, if the node was set.
- */
- goog.ds.DataNode.prototype.setChildNode = goog.abstractMethod;
- /**
- * Get the name of the node relative to the parent node
- * @return {string} The name of the node.
- */
- goog.ds.DataNode.prototype.getDataName = goog.abstractMethod;
- /**
- * Set the name of the node relative to the parent node
- * @param {string} name The name of the node.
- */
- goog.ds.DataNode.prototype.setDataName = goog.abstractMethod;
- /**
- * Gets the a qualified data path to this node
- * @return {string} The data path.
- */
- goog.ds.DataNode.prototype.getDataPath = goog.abstractMethod;
- /**
- * Load or reload the backing data for this node
- */
- goog.ds.DataNode.prototype.load = goog.abstractMethod;
- /**
- * Gets the state of the backing data for this node
- * @return {goog.ds.LoadState} The state.
- */
- goog.ds.DataNode.prototype.getLoadState = goog.abstractMethod;
- /**
- * Whether the value of this node is a homogeneous list of data
- * @return {boolean} True if a list.
- */
- goog.ds.DataNode.prototype.isList = goog.abstractMethod;
- /**
- * Enum for load state of a DataNode.
- * @enum {string}
- */
- goog.ds.LoadState = {
- LOADED: 'LOADED',
- LOADING: 'LOADING',
- FAILED: 'FAILED',
- NOT_LOADED: 'NOT_LOADED'
- };
- /**
- * Base class for data node functionality, has default implementations for
- * many of the functions.
- *
- * implements {goog.ds.DataNode}
- * @constructor
- */
- goog.ds.BaseDataNode = function() {};
- /**
- * Set the value of the node
- * @param {Object} value The new value of the node.
- */
- goog.ds.BaseDataNode.prototype.set = goog.abstractMethod;
- /**
- * Gets all of the child nodes of the current node.
- * Should return an empty DataNode list if no child nodes.
- * @param {string=} opt_selector String selector to choose child nodes.
- * @return {!goog.ds.DataNodeList} The child nodes.
- */
- goog.ds.BaseDataNode.prototype.getChildNodes = function(opt_selector) {
- return new goog.ds.EmptyNodeList();
- };
- /**
- * Gets a named child node of the current node
- * @param {string} name The node name.
- * @param {boolean=} opt_canCreate Whether you can create the child node if
- * it doesn't exist already.
- * @return {goog.ds.DataNode} The child node, or null if no node of
- * this name exists and opt_create is false.
- */
- goog.ds.BaseDataNode.prototype.getChildNode = function(name, opt_canCreate) {
- return null;
- };
- /**
- * Gets the value of a child node
- * @param {string} name The node name.
- * @return {Object} The value of the node, or null if no value or the
- * child node doesn't exist.
- */
- goog.ds.BaseDataNode.prototype.getChildNodeValue = function(name) {
- return null;
- };
- /**
- * Get the name of the node relative to the parent node
- * @return {string} The name of the node.
- */
- goog.ds.BaseDataNode.prototype.getDataName = goog.abstractMethod;
- /**
- * Gets the a qualified data path to this node
- * @return {string} The data path.
- */
- goog.ds.BaseDataNode.prototype.getDataPath = function() {
- var parentPath = '';
- var myName = this.getDataName();
- if (this.getParent()) {
- parentPath = this.getParent().getDataPath() +
- (myName.indexOf(
- /** @suppress {missingRequire} */ goog.ds.STR_ARRAY_START) != -1 ?
- '' :
- /** @suppress {missingRequire} */ goog.ds.STR_PATH_SEPARATOR);
- }
- return parentPath + myName;
- };
- /**
- * Load or reload the backing data for this node
- */
- goog.ds.BaseDataNode.prototype.load = goog.nullFunction;
- /**
- * Gets the state of the backing data for this node
- * @return {goog.ds.LoadState} The state.
- */
- goog.ds.BaseDataNode.prototype.getLoadState = function() {
- return goog.ds.LoadState.LOADED;
- };
- /**
- * Gets the parent node. Subclasses implement this function
- * @return {?goog.ds.DataNode}
- * @protected
- */
- goog.ds.BaseDataNode.prototype.getParent = goog.abstractMethod;
- /**
- * Interface for node list in rich data tree.
- *
- * Has both map and list-style accessors
- *
- * @constructor
- * @extends {goog.ds.DataNode}
- */
- // TODO(arv): Use interfaces when available.
- goog.ds.DataNodeList = function() {};
- /**
- * Add a node to the node list.
- * If the node has a dataName, uses this for the key in the map.
- *
- * @param {goog.ds.DataNode} node The node to add.
- */
- goog.ds.DataNodeList.prototype.add = goog.abstractMethod;
- /**
- * Get a node by string key.
- * Returns null if node doesn't exist.
- *
- * @param {string} key String lookup key.
- * @return {*} The node, or null if doesn't exist.
- * @override
- */
- goog.ds.DataNodeList.prototype.get = goog.abstractMethod;
- /**
- * Get a node by index
- * Returns null if the index is out of range
- *
- * @param {number} index The index of the node.
- * @return {goog.ds.DataNode} The node, or null if doesn't exist.
- */
- goog.ds.DataNodeList.prototype.getByIndex = goog.abstractMethod;
- /**
- * Gets the size of the node list
- *
- * @return {number} The size of the list.
- */
- goog.ds.DataNodeList.prototype.getCount = goog.abstractMethod;
- /**
- * Sets a node in the list of a given name
- * @param {string} name Name of the node.
- * @param {goog.ds.DataNode} node The node.
- */
- goog.ds.DataNodeList.prototype.setNode = goog.abstractMethod;
- /**
- * Removes a node in the list of a given name
- * @param {string} name Name of the node.
- * @return {boolean} True if node existed and was deleted.
- */
- goog.ds.DataNodeList.prototype.removeNode = goog.abstractMethod;
- /**
- * Simple node list implementation with underlying array and map
- * implements goog.ds.DataNodeList.
- *
- * Names that are reserved for system use and shouldn't be used for data node
- * names: eval, toSource, toString, unwatch, valueOf, watch. Behavior is
- * undefined if these names are used.
- *
- * @param {Array<goog.ds.DataNode>=} opt_nodes optional nodes to add to list.
- * @constructor
- * @extends {goog.ds.DataNodeList}
- */
- // TODO(arv): Use interfaces when available.
- goog.ds.BasicNodeList = function(opt_nodes) {
- this.map_ = {};
- this.list_ = [];
- this.indexMap_ = {};
- if (opt_nodes) {
- for (var i = 0, node; node = opt_nodes[i]; i++) {
- this.add(node);
- }
- }
- };
- /**
- * Add a node to the node list.
- * If the node has a dataName, uses this for the key in the map.
- * TODO(user) Remove function as well
- *
- * @param {goog.ds.DataNode} node The node to add.
- * @override
- */
- goog.ds.BasicNodeList.prototype.add = function(node) {
- this.list_.push(node);
- var dataName = node.getDataName();
- if (dataName) {
- this.map_[dataName] = node;
- this.indexMap_[dataName] = this.list_.length - 1;
- }
- };
- /**
- * Get a node by string key.
- * Returns null if node doesn't exist.
- *
- * @param {string} key String lookup key.
- * @return {goog.ds.DataNode} The node, or null if doesn't exist.
- * @override
- */
- goog.ds.BasicNodeList.prototype.get = function(key) {
- return this.map_[key] || null;
- };
- /**
- * Get a node by index
- * Returns null if the index is out of range
- *
- * @param {number} index The index of the node.
- * @return {goog.ds.DataNode} The node, or null if doesn't exist.
- * @override
- */
- goog.ds.BasicNodeList.prototype.getByIndex = function(index) {
- return this.list_[index] || null;
- };
- /**
- * Gets the size of the node list
- *
- * @return {number} The size of the list.
- * @override
- */
- goog.ds.BasicNodeList.prototype.getCount = function() {
- return this.list_.length;
- };
- /**
- * Sets a node in the list of a given name
- * @param {string} name Name of the node.
- * @param {goog.ds.DataNode} node The node.
- * @override
- */
- goog.ds.BasicNodeList.prototype.setNode = function(name, node) {
- if (node == null) {
- this.removeNode(name);
- } else {
- var existingNode = this.indexMap_[name];
- if (existingNode != null) {
- this.map_[name] = node;
- this.list_[existingNode] = node;
- } else {
- this.add(node);
- }
- }
- };
- /**
- * Removes a node in the list of a given name
- * @param {string} name Name of the node.
- * @return {boolean} True if node existed and was deleted.
- * @override
- */
- goog.ds.BasicNodeList.prototype.removeNode = function(name) {
- var existingNode = this.indexMap_[name];
- if (existingNode != null) {
- this.list_.splice(existingNode, 1);
- delete this.map_[name];
- delete this.indexMap_[name];
- for (var index in this.indexMap_) {
- if (this.indexMap_[index] > existingNode) {
- this.indexMap_[index]--;
- }
- }
- }
- return existingNode != null;
- };
- /**
- * Get the index of a named node
- * @param {string} name The name of the node to get the index of.
- * @return {number|undefined} The index.
- */
- goog.ds.BasicNodeList.prototype.indexOf = function(name) {
- return this.indexMap_[name];
- };
- /**
- * Immulatable empty node list
- * @extends {goog.ds.BasicNodeList}
- * @constructor
- * @final
- */
- goog.ds.EmptyNodeList = function() {
- goog.ds.BasicNodeList.call(this);
- };
- goog.inherits(goog.ds.EmptyNodeList, goog.ds.BasicNodeList);
- /**
- * Add a node to the node list.
- * If the node has a dataName, uses this for the key in the map.
- *
- * @param {goog.ds.DataNode} node The node to add.
- * @override
- */
- goog.ds.EmptyNodeList.prototype.add = function(node) {
- throw Error('Can\'t add to EmptyNodeList');
- };
- /**
- * Node list implementation which maintains sort order during insertion and
- * modification operations based on a comparison function.
- *
- * The SortedNodeList does not guarantee sort order will be maintained if
- * the underlying data nodes are modified externally.
- *
- * Names that are reserved for system use and shouldn't be used for data node
- * names: eval, toSource, toString, unwatch, valueOf, watch. Behavior is
- * undefined if these names are used.
- *
- * @param {Function} compareFn Comparison function by which the
- * node list is sorted. Should take 2 arguments to compare, and return a
- * negative integer, zero, or a positive integer depending on whether the
- * first argument is less than, equal to, or greater than the second.
- * @param {Array<goog.ds.DataNode>=} opt_nodes optional nodes to add to list;
- * these are assumed to be in sorted order.
- * @extends {goog.ds.BasicNodeList}
- * @constructor
- */
- goog.ds.SortedNodeList = function(compareFn, opt_nodes) {
- this.compareFn_ = compareFn;
- goog.ds.BasicNodeList.call(this, opt_nodes);
- };
- goog.inherits(goog.ds.SortedNodeList, goog.ds.BasicNodeList);
- /**
- * Add a node to the node list, maintaining sort order.
- * If the node has a dataName, uses this for the key in the map.
- *
- * @param {goog.ds.DataNode} node The node to add.
- * @override
- */
- goog.ds.SortedNodeList.prototype.add = function(node) {
- if (!this.compareFn_) {
- this.append(node);
- return;
- }
- var searchLoc = goog.array.binarySearch(this.list_, node, this.compareFn_);
- // if there is another node that is "equal" according to the comparison
- // function, insert before that one; otherwise insert at the location
- // goog.array.binarySearch indicated
- if (searchLoc < 0) {
- searchLoc = -(searchLoc + 1);
- }
- // update any indexes that are after the insertion point
- for (var index in this.indexMap_) {
- if (this.indexMap_[index] >= searchLoc) {
- this.indexMap_[index]++;
- }
- }
- goog.array.insertAt(this.list_, node, searchLoc);
- var dataName = node.getDataName();
- if (dataName) {
- this.map_[dataName] = node;
- this.indexMap_[dataName] = searchLoc;
- }
- };
- /**
- * Adds the given node to the end of the SortedNodeList. This should
- * only be used when the caller can guarantee that the sort order will
- * be maintained according to this SortedNodeList's compareFn (e.g.
- * when initializing a new SortedNodeList from a list of nodes that has
- * already been sorted).
- * @param {goog.ds.DataNode} node The node to append.
- */
- goog.ds.SortedNodeList.prototype.append = function(node) {
- goog.ds.SortedNodeList.superClass_.add.call(this, node);
- };
- /**
- * Sets a node in the list of a given name, maintaining sort order.
- * @param {string} name Name of the node.
- * @param {goog.ds.DataNode} node The node.
- * @override
- */
- goog.ds.SortedNodeList.prototype.setNode = function(name, node) {
- if (node == null) {
- this.removeNode(name);
- } else {
- var existingNode = this.indexMap_[name];
- if (existingNode != null) {
- if (this.compareFn_) {
- var compareResult = this.compareFn_(this.list_[existingNode], node);
- if (compareResult == 0) {
- // the new node can just replace the old one
- this.map_[name] = node;
- this.list_[existingNode] = node;
- } else {
- // remove the old node, then add the new one
- this.removeNode(name);
- this.add(node);
- }
- }
- } else {
- this.add(node);
- }
- }
- };
- /**
- * The character denoting an attribute.
- * @type {string}
- */
- goog.ds.STR_ATTRIBUTE_START = '@';
- /**
- * The character denoting all children.
- * @type {string}
- */
- goog.ds.STR_ALL_CHILDREN_SELECTOR = '*';
- /**
- * The wildcard character.
- * @type {string}
- */
- goog.ds.STR_WILDCARD = '*';
- /**
- * The character denoting path separation.
- * @type {string}
- */
- goog.ds.STR_PATH_SEPARATOR = '/';
- /**
- * The character denoting the start of an array.
- * @type {string}
- */
- goog.ds.STR_ARRAY_START = '[';
- /**
- * Shared logger instance for data package
- * @type {goog.log.Logger}
- */
- goog.ds.logger = goog.log.getLogger('goog.ds');
- /**
- * Create a data node that references another data node,
- * useful for pointer-like functionality.
- * All functions will return same values as the original node except for
- * getDataName()
- * @param {!goog.ds.DataNode} node The original node.
- * @param {string} name The new name.
- * @return {!goog.ds.DataNode} The new data node.
- */
- goog.ds.Util.makeReferenceNode = function(node, name) {
- /**
- * @constructor
- * @extends {goog.ds.DataNode}
- * @final
- */
- var nodeCreator = function() {};
- nodeCreator.prototype = node;
- var newNode = new nodeCreator();
- newNode.getDataName = function() { return name; };
- return newNode;
- };
|