📄 tree.js
字号:
// A tree is treated as a leaf, not as a node with children (like a grid), // but defining destroyRecursive for back-compat. this.destroy(); }});dojo.declare( "dijit.tree.TreeStoreModel", null,{ // summary // Implements dijit.Tree.model connecting to a store with a single // root item. Any methods passed into the constructor will override // the ones defined here. // store: dojo.data.Store // Underlying store store: null, // childrenAttrs: String[] // one ore more attributes that holds children of a tree node childrenAttrs: ["children"], // root: 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, constructor: function(/* Object */ args){ // summary: passed the arguments listed above (store, etc) dojo.mixin(this, args); this.connects = []; var store = this.store; if(!store.getFeatures()['dojo.data.api.Identity']){ throw new Error("dijit.Tree: 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([ dojo.connect(store, "onNew", this, "_onNewItem"), dojo.connect(store, "onDelete", this, "_onDeleteItem"), dojo.connect(store, "onSet", this, "_onSetItem") ]); } }, destroy: function(){ dojo.forEach(this.connects, dojo.disconnect); }, // ======================================================================= // 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: dojo.hitch(this, function(items){ if(items.length != 1){ throw new Error(this.declaredClass + ": query " + query + " returned " + items.length + " items, but must return exactly one item"); } 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 dojo.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; // get children of specified item var childItems = []; for (var i=0; i<this.childrenAttrs.length; i++){ var vals = store.getValues(parentItem, this.childrenAttrs[i]); childItems = childItems.concat(vals); } // count how many items need to be loaded var _waitCount = 0; dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } }); if(_waitCount == 0){ // all items are already loaded. proceed... onComplete(childItems); }else{ // still waiting for some or all of the items to load var onItem = function onItem(item){ if(--_waitCount == 0){ // all nodes have been loaded, send them to the tree onComplete(childItems); } } dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ store.loadItem({ item: item, onItem: onItem, onError: onError }); } }); } }, // ======================================================================= // Inspecting items getIdentity: function(/* item */ item){ return this.store.getIdentity(item); // Object }, getLabel: function(/*dojo.data.Item*/ item){ // summary: get the label for an item return this.store.getLabel(item); // String }, // ======================================================================= // Write interface newItem: function(/* Object? */ args, /*Item*/ parent){ // 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. var pInfo = {parent: parent, attribute: this.childrenAttrs[0]}; return this.store.newItem(args, pInfo); }, pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy){ // summary // Move or copy an item from one parent item to another. // Used in drag & drop var store = this.store, parentAttr = this.childrenAttrs[0]; // name of "children" attr in parent item // remove child from source item, and record the attributee that child occurred in if(oldParentItem){ dojo.forEach(this.childrenAttrs, function(attr){ if(store.containsValue(oldParentItem, attr, childItem)){ if(!bCopy){ var values = dojo.filter(store.getValues(oldParentItem, attr), function(x){ return x != childItem; }); store.setValues(oldParentItem, attr, values); } parentAttr = attr; } }); } // modify target item's children attribute to include this item if(newParentItem){ store.setValues(newParentItem, parentAttr, store.getValues(newParentItem, parentAttr).concat(childItem)); } }, // ======================================================================= // Callbacks onChange: function(/*dojo.data.Item*/ item){ // summary // Callback whenever an item has changed, so that Tree // can update the label, icon, etc. Note that changes // to an item's children or parent(s) will trigger an // onChildrenChange() so you can ignore those changes here. }, onChildrenChange: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){ // summary // Callback to do notifications about new, updated, or deleted items. }, // ======================================================================= ///Events from data store _onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){ // summary: handler for when new items appear in the store. // In this case there's no correspond onSet() call on the parent of this // item, so need to get the new children list of the parent manually somehow. if(!parentInfo){ return; } this.getChildren(parentInfo.item, dojo.hitch(this, function(children){ // NOTE: maybe can be optimized since parentInfo contains the new and old attribute value this.onChildrenChange(parentInfo.item, children); })); }, _onDeleteItem: function(/*Object*/ item){ // summary: handler for delete notifications from underlying store }, _onSetItem: function(/* item */ item, /* attribute-name-string */ attribute, /* object | array */ oldValue, /* object | array */ newValue){ //summary: set data event on an item in the store if(dojo.indexOf(this.childrenAttrs, attribute) != -1){ // item's children list changed this.getChildren(item, dojo.hitch(this, function(children){ // NOTE: maybe can be optimized since parentInfo contains the new and old attribute value this.onChildrenChange(item, children); })); }else{ // item's label/icon/etc. changed. this.onChange(item); } }});dojo.declare("dijit.tree.ForestStoreModel", dijit.tree.TreeStoreModel, { // summary // Interface between Tree and a dojo.store that doesn't have a root item, ie, // has multiple "top level" items. // // description // Use this class to wrap a dojo.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. // It allows dijit.Tree to assume a single root item, even if the store doesn't have one. // 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){ // 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) 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: dojo.hitch(this, function(items){ this.root.children = items; callback(items); }), onError: onError }); } }else{ this.inherited(arguments); } }, // ======================================================================= // Inspecting items 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(/* Object? */ args, /*Item*/ parent){ // 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(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){ // 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); } } dijit.tree.TreeStoreModel.prototype.pasteItem.call(this, childItem, oldParentItem === this.root ? null : oldParentItem, newParentItem === this.root ? null : newParentItem ); 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); } }, // ======================================================================= // Callbacks onAddToRoot: function(/* item */ item){ // summary // Called when item added to root of tree; user must override // to modify the item so that it matches the query for top level items // example // | store.setValue(item, "root", true); console.log(this, ": item ", item, " added to root"); }, onLeaveRoot: function(/* item */ item){ // summary // Called when item removed from root of tree; user must override // to modify the item so it doesn't match the query for top level items // example // | store.unsetAttribute(item, "root"); 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 _this = this, oldChildren = this.root.children; this.store.fetch({ query: this.query, onComplete: function(newChildren){ _this.root.children = newChildren; // If the list of children or the order of children has changed... if(oldChildren.length != newChildren.length || dojo.some(oldChildren, function(item, idx){ return newChildren[idx] != item;})){ _this.onChildrenChange(_this.root, newChildren); } } }); }, _onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){ // summary: handler for when new items appear in the store. // In theory, any new item could be a top level item. // Do the safe but inefficient thing by requerying the top // level items. User can override this function to do something // more efficient. 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(dojo.indexOf(this.root.children, item) != -1){ this._requeryTop(); } this.inherited(arguments); }});}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -