From 9023f791a29978fb798cf7bb352d0df0c885b219 Mon Sep 17 00:00:00 2001 From: Bill Keese Date: Tue, 22 Jan 2013 10:58:38 +0900 Subject: [PATCH] Tree: remove support for dojo/data, direct store argument, etc., refs #4 --- Tree.js | 163 ++--------------- _tree/dndSource.js | 20 -- tree/ForestStoreModel.js | 279 ---------------------------- tree/TreeStoreModel.js | 387 --------------------------------------- 4 files changed, 12 insertions(+), 837 deletions(-) delete mode 100644 _tree/dndSource.js delete mode 100644 tree/ForestStoreModel.js delete mode 100644 tree/TreeStoreModel.js diff --git a/Tree.js b/Tree.js index ef3e5f1ca..fbed7403a 100644 --- a/Tree.js +++ b/Tree.js @@ -31,32 +31,16 @@ define([ "./_KeyNavMixin", "dojo/text!./templates/TreeNode.html", "dojo/text!./templates/Tree.html", - "./tree/TreeStoreModel", - "./tree/ForestStoreModel", "./tree/_dndSelector", "dojo/query!css2" // needed when on.selector() used with a string for the selector ], function(array, aspect, connect, cookie, declare, Deferred, all, dom, domClass, domGeometry, domStyle, createError, fxUtils, has, kernel, keys, lang, on, topic, touch, when, focus, registry, manager, _Widget, _TemplatedMixin, _Container, _Contained, _CssStateMixin, _KeyNavMixin, - treeNodeTemplate, treeTemplate, TreeStoreModel, ForestStoreModel, _dndSelector){ + treeNodeTemplate, treeTemplate, _dndSelector){ // module: // dijit/Tree -function shimmedPromise(/*Deferred|Promise*/ d){ - // summary: - // Return a Promise based on given Deferred or Promise, with back-compat addCallback() and addErrback() shims - // added (TODO: remove those back-compat shims, and this method, for 2.0) - - return lang.delegate(d.promise || d, { - addCallback: function(callback){ - this.then(callback); - }, - addErrback: function(errback){ - this.otherwise(errback); - } - }); -} var TreeNode = declare("dijit._TreeNode", [_Widget, _TemplatedMixin, _Container, _Contained, _CssStateMixin], { // summary: @@ -166,10 +150,7 @@ var TreeNode = declare("dijit._TreeNode", [_Widget, _TemplatedMixin, _Container, // tags: // private var tree = this.tree, model = tree.model; - if(tree._v10Compat && item === model.root){ - // For back-compat with 1.0, need to use null to specify root item (TODO: remove in 2.0) - item = null; - } + this._applyClassAndStyle(item, "icon", "Icon"); this._applyClassAndStyle(item, "label", "Label"); this._applyClassAndStyle(item, "row", "Row"); @@ -244,7 +225,7 @@ var TreeNode = declare("dijit._TreeNode", [_Widget, _TemplatedMixin, _Container, // If there's already an expand in progress or we are already expanded, just return if(this._expandDeferred){ - return shimmedPromise(this._expandDeferred); // dojo/promise/Promise + return this._expandDeferred.promise; // dojo/promise/Promise } // cancel in progress collapse operation @@ -285,7 +266,7 @@ var TreeNode = declare("dijit._TreeNode", [_Widget, _TemplatedMixin, _Container, wipeIn.play(); - return shimmedPromise(def); // dojo/promise/Promise + return def.promise; // dojo/promise/Promise }, collapse: function(){ @@ -296,7 +277,7 @@ var TreeNode = declare("dijit._TreeNode", [_Widget, _TemplatedMixin, _Container, if(this._collapseDeferred){ // Node is already collapsed, or there's a collapse in progress, just return that Deferred - return shimmedPromise(this._collapseDeferred); + return this._collapseDeferred.promise; } // cancel in progress expand operation @@ -331,7 +312,7 @@ var TreeNode = declare("dijit._TreeNode", [_Widget, _TemplatedMixin, _Container, wipeOut.play(); - return shimmedPromise(def); // dojo/promise/Promise + return def.promise; // dojo/promise/Promise }, // indent: Integer @@ -474,7 +455,7 @@ var TreeNode = declare("dijit._TreeNode", [_Widget, _TemplatedMixin, _Container, var def = all(defs); this.tree._startPaint(def); // to reset TreeNode widths after an item is added/removed from the Tree - return shimmedPromise(def); // dojo/promise/Promise + return def.promise; // dojo/promise/Promise }, getTreePath: function(){ @@ -507,17 +488,6 @@ var TreeNode = declare("dijit._TreeNode", [_Widget, _TemplatedMixin, _Container, }); }, - makeExpandable: function(){ - // summary: - // if this node wasn't already showing the expando node, - // turn it into one and call _setExpando() - - // TODO: hmm this isn't called from anywhere, maybe should remove it for 2.0 - - this.isExpandable = true; - this._setExpando(false); - }, - setSelected: function(/*Boolean*/ selected){ // summary: // A Tree has a (single) currently selected node. @@ -554,47 +524,21 @@ var Tree = declare("dijit.Tree", [_Widget, _KeyNavMixin, _TemplatedMixin, _CssSt baseClass: "dijitTree", - // store: [deprecated] String|dojo/data/Store - // Deprecated. Use "model" parameter instead. - // The store to get data to display in the tree. - store: null, - // model: [const] dijit/tree/model // Interface to read tree data, get notifications of changes to tree data, // and for handling drop operations (i.e drag and drop onto the tree) model: null, - // query: [deprecated] anything - // Deprecated. User should specify query to the model directly instead. - // Specifies datastore query to return the root item or top items for the tree. - query: null, - - // label: [deprecated] String - // Deprecated. Use dijit/tree/ForestStoreModel directly instead. - // Used in conjunction with query parameter. - // If a query is specified (rather than a root node id), and a label is also specified, - // then a fake root node is created and displayed, with this label. - label: "", - // showRoot: [const] Boolean // Should the root node be displayed, or hidden? showRoot: true, - // childrenAttr: [deprecated] String[] - // Deprecated. This information should be specified in the model. - // One ore more attributes that holds children of a tree node - childrenAttr: ["children"], - // paths: String[][] or Item[][] // Full paths from rootNode to selected nodes expressed as array of items or array of ids. // Since setting the paths may be asynchronous (because of waiting on dojo.data), set("paths", ...) // returns a Promise to indicate when the set is complete. paths: [], - // path: String[] or Item[] - // Backward compatible singular variant of paths. - path: [], - // selectedItems: [readonly] Item[] // The currently selected items in this tree. // This property can only be set (via set('selectedItems', ...)) when that item is already @@ -602,10 +546,6 @@ var Tree = declare("dijit.Tree", [_Widget, _KeyNavMixin, _TemplatedMixin, _CssSt // Should generally use `paths` attribute to set the selected items instead. selectedItems: null, - // selectedItem: [readonly] Item - // Backward compatible singular variant of selectedItems. - selectedItem: null, - // openOnClick: Boolean // If true, clicking a folder node's label will open it, rather than calling onClick() openOnClick: false, @@ -784,11 +724,6 @@ var Tree = declare("dijit.Tree", [_Widget, _KeyNavMixin, _TemplatedMixin, _CssSt }) ); - // Create glue between store and Tree, if not specified directly by user - if(!this.model){ - this._store2model(); - } - // monitor changes to items this.own( aspect.after(this.model, "onChange", lang.hitch(this, "_onItemChange"), true), @@ -827,41 +762,10 @@ var Tree = declare("dijit.Tree", [_Widget, _KeyNavMixin, _TemplatedMixin, _CssSt // onLoadDeferred should fire when all commands that are part of initialization have completed. // It will include all the set("paths", ...) commands that happen during initialization. - this.onLoadDeferred = shimmedPromise(this.pendingCommandsPromise); - + this.onLoadDeferred = this.pendingCommandsPromise; this.onLoadDeferred.then(lang.hitch(this, "onLoad")); }, - _store2model: function(){ - // summary: - // User specified a store&query rather than model, so create model from store/query - this._v10Compat = true; - kernel.deprecated("Tree: from version 2.0, should specify a model object rather than a store/query"); - - var modelParams = { - id: this.id + "_ForestStoreModel", - store: this.store, - query: this.query, - childrenAttrs: this.childrenAttr - }; - - // Only override the model's mayHaveChildren() method if the user has specified an override - if(this.params.mayHaveChildren){ - modelParams.mayHaveChildren = lang.hitch(this, "mayHaveChildren"); - } - - if(this.params.getItemChildren){ - modelParams.getChildren = lang.hitch(this, function(item, onComplete, onError){ - this.getItemChildren((this._v10Compat && item === this.model.root) ? null : item, onComplete, onError); - }); - } - this.model = new ForestStoreModel(modelParams); - - // For backwards compatibility, the visibility of the root node is controlled by - // whether or not the user has specified a label - this.showRoot = Boolean(this.label); - }, - onLoad: function(){ // summary: // Called when tree finishes loading and expanding. @@ -951,10 +855,6 @@ var Tree = declare("dijit.Tree", [_Widget, _KeyNavMixin, _TemplatedMixin, _CssSt return [].concat(this._itemNodesMap[identity]); }, - _setSelectedItemAttr: function(/*Item or id*/ item){ - this.set('selectedItems', [item]); - }, - _setSelectedItemsAttr: function(/*Items or ids*/ items){ // summary: // Select tree nodes related to passed items. @@ -973,17 +873,6 @@ var Tree = declare("dijit.Tree", [_Widget, _KeyNavMixin, _TemplatedMixin, _CssSt })); }, - _setPathAttr: function(/*Item[]|String[]*/ path){ - // summary: - // Singular variant of _setPathsAttr - if(path.length){ - return this.set("paths", [path]); - }else{ - // Empty list is interpreted as "select nothing" - return this.set("paths", []); - } - }, - _setPathsAttr: function(/*Item[][]|String[][]*/ paths){ // summary: // Select the tree nodes identified by passed paths. @@ -996,7 +885,7 @@ var Tree = declare("dijit.Tree", [_Widget, _KeyNavMixin, _TemplatedMixin, _CssSt // Let any previous set("path", ...) commands complete before this one starts. // TODO for 2.0: make the user do this wait themselves? - return shimmedPromise(this.pendingCommandsPromise = this.pendingCommandsPromise.always(function(){ + return this.pendingCommandsPromise = this.pendingCommandsPromise.always(function(){ // We may need to wait for some nodes to expand, so setting // each path will involve a Deferred. We bring those deferreds // together with a dojo/promise/all. @@ -1012,7 +901,7 @@ var Tree = declare("dijit.Tree", [_Widget, _KeyNavMixin, _TemplatedMixin, _CssSt throw new Tree.PathError("Empty path"); } })); - }).then(setNodes)); + }).then(setNodes); function selectPath(path, nodes){ // Traverse path, returning Promise for node at the end of the path. @@ -1041,9 +930,6 @@ var Tree = declare("dijit.Tree", [_Widget, _KeyNavMixin, _TemplatedMixin, _CssSt } }, - _setSelectedNodeAttr: function(node){ - this.set('selectedNodes', [node]); - }, _setSelectedNodesAttr: function(nodes){ // summary: // Marks the specified TreeNodes as selected. @@ -1074,7 +960,7 @@ var Tree = declare("dijit.Tree", [_Widget, _KeyNavMixin, _TemplatedMixin, _CssSt }); } - return shimmedPromise(expand(this.rootNode)); + return expand(this.rootNode); }, collapseAll: function(){ @@ -1104,32 +990,7 @@ var Tree = declare("dijit.Tree", [_Widget, _KeyNavMixin, _TemplatedMixin, _CssSt } } - return shimmedPromise(collapse(this.rootNode)); - }, - - ////////////// Data store related functions ////////////////////// - // These just get passed to the model; they are here for back-compat - - mayHaveChildren: function(/*dojo/data/Item*/ /*===== item =====*/){ - // summary: - // Deprecated. This should be specified on the model itself. - // - // Overridable function to tell if an item has or may have children. - // Controls whether or not +/- expando icon is shown. - // (For efficiency reasons we may not want to check if an element actually - // has children until user clicks the expando node) - // tags: - // deprecated - }, - - getItemChildren: function(/*===== parentItem, onComplete =====*/){ - // summary: - // Deprecated. This should be specified on the model itself. - // - // Overridable function that return array of child items of given parent item, - // or if parentItem==null then return top items in tree - // tags: - // deprecated + return collapse(this.rootNode); }, /////////////////////////////////////////////////////// diff --git a/_tree/dndSource.js b/_tree/dndSource.js deleted file mode 100644 index e4db35119..000000000 --- a/_tree/dndSource.js +++ /dev/null @@ -1,20 +0,0 @@ -define([ - "dojo/_base/kernel", // kernel.deprecated - "dojo/_base/lang", // lang.setObject - "../tree/dndSource" -], function(kernel, lang, dndSource){ - // module: - // dijit/_tree/dndSource - - /*===== - return { - // summary: - // Deprecated module, use dijit/tree/dndSource instead. - }; - =====*/ - - // TODO: remove this file in 2.0 - kernel.deprecated("dijit._tree.dndSource has been moved to dijit.tree.dndSource, use that instead", "", "2.0"); - - lang.setObject("dijit._tree.dndSource", dndSource); -}); diff --git a/tree/ForestStoreModel.js b/tree/ForestStoreModel.js deleted file mode 100644 index 0096ce4f6..000000000 --- a/tree/ForestStoreModel.js +++ /dev/null @@ -1,279 +0,0 @@ -define([ - "dojo/_base/array", // array.indexOf array.some - "dojo/_base/declare", // declare - "dojo/_base/kernel", // global - "dojo/_base/lang", // lang.hitch - "./TreeStoreModel" -], function(array, declare, kernel, lang, TreeStoreModel){ - -// module: -// dijit/tree/ForestStoreModel - -return declare("dijit.tree.ForestStoreModel", TreeStoreModel, { - // summary: - // Interface between a dijit.Tree and a dojo.data store that doesn't have a root item, - // a.k.a. a store that has multiple "top level" items. - // - // description: - // Use this class to wrap a dojo.data store, making all the items matching the specified query - // appear as children of a fabricated "root item". If no query is specified then all the - // items returned by fetch() on the underlying store become children of the root item. - // This class allows dijit.Tree to assume a single root item, even if the store doesn't have one. - // - // When using this class the developer must override a number of methods according to their app and - // data, including: - // - // - onNewRootItem - // - onAddToRoot - // - onLeaveRoot - // - onNewItem - // - onSetItem - - // Parameters to constructor - - // rootId: String - // ID of fabricated root item - rootId: "$root$", - - // rootLabel: String - // Label of fabricated root item - rootLabel: "ROOT", - - // query: String - // Specifies the set of children of the root item. - // example: - // | {type:'continent'} - query: null, - - // End of parameters to constructor - - constructor: function(params){ - // summary: - // Sets up variables, etc. - // tags: - // private - - // Make dummy root item - this.root = { - store: this, - root: true, - id: params.rootId, - label: params.rootLabel, - children: params.rootChildren // optional param - }; - }, - - // ======================================================================= - // Methods for traversing hierarchy - - mayHaveChildren: function(/*dojo/data/Item*/ item){ - // summary: - // Tells if an item has or may have children. Implementing logic here - // avoids showing +/- expando icon for nodes that we know don't have children. - // (For efficiency reasons we may not want to check if an element actually - // has children until user clicks the expando node) - // tags: - // extension - return item === this.root || this.inherited(arguments); - }, - - getChildren: function(/*dojo/data/Item*/ parentItem, /*function(items)*/ callback, /*function*/ onError){ - // summary: - // Calls onComplete() with array of child items of given parent item, all loaded. - if(parentItem === this.root){ - if(this.root.children){ - // already loaded, just return - callback(this.root.children); - }else{ - this.store.fetch({ - query: this.query, - onComplete: lang.hitch(this, function(items){ - this.root.children = items; - callback(items); - }), - onError: onError - }); - } - }else{ - this.inherited(arguments); - } - }, - - // ======================================================================= - // Inspecting items - - isItem: function(/* anything */ something){ - return (something === this.root) ? true : this.inherited(arguments); - }, - - fetchItemByIdentity: function(/* object */ keywordArgs){ - if(keywordArgs.identity == this.root.id){ - var scope = keywordArgs.scope || kernel.global; - if(keywordArgs.onItem){ - keywordArgs.onItem.call(scope, this.root); - } - }else{ - this.inherited(arguments); - } - }, - - getIdentity: function(/* item */ item){ - return (item === this.root) ? this.root.id : this.inherited(arguments); - }, - - getLabel: function(/* item */ item){ - return (item === this.root) ? this.root.label : this.inherited(arguments); - }, - - // ======================================================================= - // Write interface - - newItem: function(/* dijit/tree/dndSource.__Item */ args, /*Item*/ parent, /*int?*/ insertIndex){ - // summary: - // Creates a new item. See dojo/data/api/Write for details on args. - // Used in drag & drop when item from external source dropped onto tree. - if(parent === this.root){ - this.onNewRootItem(args); - return this.store.newItem(args); - }else{ - return this.inherited(arguments); - } - }, - - onNewRootItem: function(/* dijit/tree/dndSource.__Item */ /*===== args =====*/){ - // summary: - // User can override this method to modify a new element that's being - // added to the root of the tree, for example to add a flag like root=true - }, - - pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){ - // summary: - // Move or copy an item from one parent item to another. - // Used in drag & drop - if(oldParentItem === this.root){ - if(!bCopy){ - // It's onLeaveRoot()'s responsibility to modify the item so it no longer matches - // this.query... thus triggering an onChildrenChange() event to notify the Tree - // that this element is no longer a child of the root node - this.onLeaveRoot(childItem); - } - } - this.inherited(arguments, [childItem, - oldParentItem === this.root ? null : oldParentItem, - newParentItem === this.root ? null : newParentItem, - bCopy, - insertIndex - ]); - if(newParentItem === this.root){ - // It's onAddToRoot()'s responsibility to modify the item so it matches - // this.query... thus triggering an onChildrenChange() event to notify the Tree - // that this element is now a child of the root node - this.onAddToRoot(childItem); - } - }, - - // ======================================================================= - // Handling for top level children - - onAddToRoot: function(/* item */ item){ - // summary: - // Called when item added to root of tree; user must override this method - // to modify the item so that it matches the query for top level items - // example: - // | store.setValue(item, "root", true); - // tags: - // extension - console.log(this, ": item ", item, " added to root"); - }, - - onLeaveRoot: function(/* item */ item){ - // summary: - // Called when item removed from root of tree; user must override this method - // to modify the item so it doesn't match the query for top level items - // example: - // | store.unsetAttribute(item, "root"); - // tags: - // extension - console.log(this, ": item ", item, " removed from root"); - }, - - // ======================================================================= - // Events from data store - - _requeryTop: function(){ - // reruns the query for the children of the root node, - // sending out an onSet notification if those children have changed - var oldChildren = this.root.children || []; - this.store.fetch({ - query: this.query, - onComplete: lang.hitch(this, function(newChildren){ - this.root.children = newChildren; - - // If the list of children or the order of children has changed... - if(oldChildren.length != newChildren.length || - array.some(oldChildren, function(item, idx){ return newChildren[idx] != item;})){ - this.onChildrenChange(this.root, newChildren); - } - }) - }); - }, - - onNewItem: function(/* dojo/data/api/Item */ item, /* Object */ parentInfo){ - // summary: - // Handler for when new items appear in the store. Developers should override this - // method to be more efficient based on their app/data. - // description: - // Note that the default implementation requeries the top level items every time - // a new item is created, since any new item could be a top level item (even in - // addition to being a child of another item, since items can have multiple parents). - // - // If developers can detect which items are possible top level items (based on the item and the - // parentInfo parameters), they should override this method to only call _requeryTop() for top - // level items. Often all top level items have parentInfo==null, but - // that will depend on which store you use and what your data is like. - // tags: - // extension - this._requeryTop(); - - this.inherited(arguments); - }, - - onDeleteItem: function(/*Object*/ item){ - // summary: - // Handler for delete notifications from underlying store - - // check if this was a child of root, and if so send notification that root's children - // have changed - if(array.indexOf(this.root.children, item) != -1){ - this._requeryTop(); - } - - this.inherited(arguments); - }, - - onSetItem: function(/* item */ item, - /* attribute-name-string */ attribute, - /* Object|Array */ oldValue, - /* Object|Array */ newValue){ - // summary: - // Updates the tree view according to changes to an item in the data store. - // Developers should override this method to be more efficient based on their app/data. - // description: - // Handles updates to an item's children by calling onChildrenChange(), and - // other updates to an item by calling onChange(). - // - // Also, any change to any item re-executes the query for the tree's top-level items, - // since this modified item may have started/stopped matching the query for top level items. - // - // If possible, developers should override this function to only call _requeryTop() when - // the change to the item has caused it to stop/start being a top level item in the tree. - // tags: - // extension - - this._requeryTop(); - this.inherited(arguments); - } - -}); - -}); diff --git a/tree/TreeStoreModel.js b/tree/TreeStoreModel.js deleted file mode 100644 index 36556ddc7..000000000 --- a/tree/TreeStoreModel.js +++ /dev/null @@ -1,387 +0,0 @@ -define([ - "dojo/_base/array", // array.filter array.forEach array.indexOf array.some - "dojo/aspect", // aspect.after - "dojo/_base/declare", // declare - "dojo/_base/lang" // lang.hitch -], function(array, aspect, declare, lang){ - - // module: - // dijit/tree/TreeStoreModel - - return declare("dijit.tree.TreeStoreModel", null, { - // summary: - // Implements dijit/Tree/model connecting to a dojo.data store with a single - // root item. Any methods passed into the constructor will override - // the ones defined here. - - // store: dojo/data/api/Read - // Underlying store - store: null, - - // childrenAttrs: String[] - // One or more attribute names (attributes in the dojo.data item) that specify that item's children - childrenAttrs: ["children"], - - // newItemIdAttr: String - // Name of attribute in the Object passed to newItem() that specifies the id. - // - // If newItemIdAttr is set then it's used when newItem() is called to see if an - // item with the same id already exists, and if so just links to the old item - // (so that the old item ends up with two parents). - // - // Setting this to null or "" will make every drop create a new item. - newItemIdAttr: "id", - - // labelAttr: String - // If specified, get label for tree node from this attribute, rather - // than by calling store.getLabel() - labelAttr: "", - - // root: [readonly] dojo/data/Item - // Pointer to the root item (read only, not a parameter) - root: null, - - // query: anything - // Specifies datastore query to return the root item for the tree. - // Must only return a single item. Alternately can just pass in pointer - // to root item. - // example: - // | {id:'ROOT'} - query: null, - - // deferItemLoadingUntilExpand: Boolean - // Setting this to true will cause the TreeStoreModel to defer calling loadItem on nodes - // until they are expanded. This allows for lazying loading where only one - // loadItem (and generally one network call, consequently) per expansion - // (rather than one for each child). - // This relies on partial loading of the children items; each children item of a - // fully loaded item should contain the label and info about having children. - deferItemLoadingUntilExpand: false, - - constructor: function(/* Object */ args){ - // summary: - // Passed the arguments listed above (store, etc) - // tags: - // private - - lang.mixin(this, args); - - this.connects = []; - - var store = this.store; - if(!store.getFeatures()['dojo.data.api.Identity']){ - throw new Error("dijit.tree.TreeStoreModel: store must support dojo.data.Identity"); - } - - // if the store supports Notification, subscribe to the notification events - if(store.getFeatures()['dojo.data.api.Notification']){ - this.connects = this.connects.concat([ - aspect.after(store, "onNew", lang.hitch(this, "onNewItem"), true), - aspect.after(store, "onDelete", lang.hitch(this, "onDeleteItem"), true), - aspect.after(store, "onSet", lang.hitch(this, "onSetItem"), true) - ]); - } - }, - - destroy: function(){ - var h; - while(h = this.connects.pop()){ h.remove(); } - // TODO: should cancel any in-progress processing of getRoot(), getChildren() - }, - - // ======================================================================= - // Methods for traversing hierarchy - - getRoot: function(onItem, onError){ - // summary: - // Calls onItem with the root item for the tree, possibly a fabricated item. - // Calls onError on error. - if(this.root){ - onItem(this.root); - }else{ - this.store.fetch({ - query: this.query, - onComplete: lang.hitch(this, function(items){ - if(items.length != 1){ - throw new Error("dijit.tree.TreeStoreModel: root query returned " + items.length + - " items, but must return exactly one"); - } - this.root = items[0]; - onItem(this.root); - }), - onError: onError - }); - } - }, - - mayHaveChildren: function(/*dojo/data/Item*/ item){ - // summary: - // Tells if an item has or may have children. Implementing logic here - // avoids showing +/- expando icon for nodes that we know don't have children. - // (For efficiency reasons we may not want to check if an element actually - // has children until user clicks the expando node) - return array.some(this.childrenAttrs, function(attr){ - return this.store.hasAttribute(item, attr); - }, this); - }, - - getChildren: function(/*dojo/data/Item*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError){ - // summary: - // Calls onComplete() with array of child items of given parent item, all loaded. - - var store = this.store; - if(!store.isItemLoaded(parentItem)){ - // The parent is not loaded yet, we must be in deferItemLoadingUntilExpand - // mode, so we will load it and just return the children (without loading each - // child item) - var getChildren = lang.hitch(this, arguments.callee); - store.loadItem({ - item: parentItem, - onItem: function(parentItem){ - getChildren(parentItem, onComplete, onError); - }, - onError: onError - }); - return; - } - // get children of specified item - var childItems = []; - for(var i=0; i