Changeset 12309
- Timestamp:
- 02/07/08 08:42:43 (11 months ago)
- Location:
- dijit/trunk
- Files:
-
- 1 added
- 5 modified
-
tests/tree/test_Tree_DnD.html (modified) (1 diff)
-
Tree.js (modified) (20 diffs)
-
_tree/dndSource.js (modified) (2 diffs)
-
_tree/ForestStoreDecorator.js (added)
-
_tree/Node.html (modified) (1 diff)
-
_tree/Tree.html (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
dijit/trunk/tests/tree/test_Tree_DnD.html
r12020 r12309 83 83 //create a custom label for tree one consisting of the label property pluss the value of the numberOfItems Column 84 84 function tree1CustomLabel(item){ 85 var label = catStore.getLabel(item); 86 var num = catStore.getValues(item,"numberOfItems"); 87 //return the new label 85 var label = catStore.getLabel(item); 86 var num = catStore.hasAttribute(item, "numberOfItems") ? catStore.getValues(item,"numberOfItems") : "?"; 88 87 return label + ' (' + num+ ')'; 89 88 } 90 89 91 //on tree two, we only want to drop on containers, not on items in the containers90 //on tree two, we only want to drop on containers, or the root node itself, not on items in the containers 92 91 function tree2CheckItemAcceptance(node,source) { 93 92 var item = dijit.getEnclosingWidget(node).item; 94 if (item && this.tree.store.hasAttribute(item,"numberOfItems")){ 95 var numItems=this.tree.store.getValues(item, "numberOfItems"); 93 if (item && (item.root || this.tree.store.hasAttribute(item,"numberOfItems"))){ 96 94 return true; 97 95 } -
dijit/trunk/Tree.js
r12273 r12309 7 7 dojo.require("dijit._Container"); 8 8 dojo.require("dojo.cookie"); 9 10 // Maps a forest of top level item into a single (fake) top level item 11 // with the other items as children of the fake root. 12 dojo.require("dijit._tree.ForestStoreDecorator"); 9 13 10 14 dojo.declare( … … 41 45 this.setLabelNode(this.label); 42 46 43 if(this.parent || !this._hideRoot){ 44 // set expand icon for leaf 45 this._setExpando(); 46 47 // set icon and label class based on item 48 this._updateItemClasses(this.item); 49 } 47 // set expand icon for leaf 48 this._setExpando(); 49 50 // set icon and label class based on item 51 this._updateItemClasses(this.item); 50 52 51 53 if(this.isExpandable){ … … 66 68 67 69 _updateItemClasses: function(item){ 68 // summary: set appropriate CSS classes for item (used to allow for item updates to change respective CSS) 69 this.iconNode.className = "dijitInline dijitTreeIcon " + this.tree.getIconClass(item, this.isExpanded); 70 this.labelNode.className = "dijitTreeLabel " + this.tree.getLabelClass(item, this.isExpanded); 71 }, 72 70 // summary: set appropriate CSS classes for icon and label dom node (used to allow for item updates to change respective CSS) 71 var tree = this.tree, store = tree.store; 72 if(tree._v10Compat && item === store.root){ 73 // For back-compat with 1.0, need to use null to specify root item (TODO: remove in 2.0) 74 item = null; 75 } 76 this.iconNode.className = "dijitInline dijitTreeIcon " + tree.getIconClass(item, this.isExpanded); 77 this.labelNode.className = "dijitTreeLabel " + tree.getLabelClass(item, this.isExpanded); 78 }, 79 73 80 _updateLayout: function(){ 74 81 // summary: set appropriate CSS classes for this.domNode 75 82 var parent = this.getParent(); 76 if( parent && parent.isTree && parent._hideRoot){83 if(!parent || parent.rowNode.style.display == "none"){ 77 84 /* if we are hiding the root node then make every first level child look like a root node */ 78 85 dojo.addClass(this.domNode, "dijitTreeIsRoot"); … … 206 213 } 207 214 208 if(this.isTree && this._hideRoot){ 209 // put first child in tab index if one exists. 210 var fc = this.getChildren()[0]; 211 var tabnode = fc ? fc.labelNode : this.domNode; 215 // On initial tree show, put focus on either the root node of the tree, 216 // or the first child, if the root node is hidden 217 // TODO: move to Tree.postCreate? (but can't execute until root node and child nodes finish loading) 218 if(!this.parent){ 219 var fc = this.tree.showRoot ? this : this.getChildren()[0], 220 tabnode = fc ? fc.labelNode : this.domNode; 212 221 tabnode.setAttribute("tabIndex", "0"); 213 222 } … … 245 254 dojo.declare( 246 255 "dijit.Tree", 247 dijit._TreeNode,256 [dijit._Widget, dijit._Templated], 248 257 { 249 258 // summary … … 261 270 store: null, 262 271 272 // root: String 273 // id of item in store corresponding to root of tree 274 root: "", 275 263 276 // query: String 264 // query to get top level node(s) of tree (ex: {type:'continent'}) 277 // Deprecated. Use dijit._tree.ForestStoreDecorator directly instead. 278 // Specifies a set of "top level" items for the tree, rather than just a single item. 279 // If a label is also specified, the tree is given a fake root node (not corresponding to an item in 280 // the data store), whose children are the items that match this query. 281 // 282 // example: 283 // {type:'continent'} 265 284 query: null, 285 286 // label: String 287 // Deprecated. Use dijit._tree.ForestStoreDecorator directly instead. 288 // Used in conjunction with query parameter. 289 // If a query is specified (rather than a root node id), and a label is also specified, 290 // then a fake root node is created and displayed, with this label. 291 label: "", 292 293 // showRoot: Boolean 294 // Should the root node be displayed, or hidden? 295 showRoot: true, 266 296 267 297 // childrenAttr: String … … 305 335 postMixInProperties: function(){ 306 336 this.tree = this; 307 this.lastFocused = this.labelNode;308 337 309 338 this._itemNodeMap={}; 310 339 311 this._hideRoot = !this.label; 340 if(!this.root){ 341 // 1.0 compatible behavior. 342 // Provide (possibly hidden) fake root node not corresponding to any data store item, 343 // which fathers all the items returned by fetch({query: this.query}) 344 dojo.deprecated("Tree: from version 2.0, must specify root item id (using root parameter) rather than query/label parameters when constructing a dijit.Tree; use dijit._tree.ForestStoreDecorator if your data store has no root item."); 345 this._v10Compat = true; 346 this.underlyingStore = this.store; 347 this.root = "$root$"; 348 this.store = new dijit._tree.ForestStoreDecorator({ 349 id: this.id + "_ForestStoreDecorator", 350 store: this.underlyingStore, 351 query: this.query, 352 childrenAttr: this.childrenAttr[0], 353 rootId: this.root, 354 rootLabel: this.label||"ROOT" 355 }); 356 357 // For backwards compatibility, the visibility of the root node is controlled by 358 // whether or not the user has specified a label 359 this.showRoot = Boolean(this.label); 360 } 312 361 313 362 if(!this.store.getFeatures()['dojo.data.api.Identity']){ … … 347 396 this.containerNodeTemplate = div; 348 397 349 if(this._hideRoot){ 350 this.rowNode.style.display="none"; 351 } 398 // load root node (possibly hidden) and it's children 399 var _this = this; 400 this.store.fetchItemByIdentity({ 401 identity: this.root, 402 onItem: function(item){ 403 _this.rootItem = item; 404 405 var rn = _this.rootNode = new dijit._TreeNode({ 406 item: item, 407 tree: _this, 408 isExpandable: true, 409 label: _this.label || _this.getLabel(item) 410 }); 411 if(!_this.showRoot){ 412 rn.rowNode.style.display="none"; 413 } 414 _this.domNode.appendChild(rn.domNode); 415 _this._itemNodeMap[_this.root] = rn; 416 417 rn._updateLayout(); // sets "dijitTreeIsRoot" CSS classname 418 419 // load top level children 420 _this._expandNode(rn); 421 } 422 }); 352 423 353 424 this.inherited("postCreate", arguments); 354 355 // load top level children356 this._expandNode(this);357 425 358 426 if(this.dndController){ … … 392 460 // User overridable function that return array of child items of given parent item, 393 461 // or if parentItem==null then return top items in tree 462 // TODO: 463 // Remove this in 2.0 because: 464 // - no way to override this function and support updates to the tree, 465 // - if acceess of children is non-standard then user can write decorator store like dijit._tree.ForestStoreDecorator 394 466 var store = this.store; 395 if(parentItem == null){ 396 // get top level nodes 397 store.fetch({ query: this.query, onComplete: onComplete}); 467 parentItem = parentItem || this.store.root; 468 469 // get children of specified item 470 var childItems = []; 471 for (var i=0; i<this.childrenAttr.length; i++){ 472 var vals = store.getValues(parentItem, this.childrenAttr[i]); 473 childItems = childItems.concat(vals); 474 } 475 476 // count how many items need to be loaded 477 var _waitCount = 0; 478 dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } }); 479 480 if(_waitCount == 0){ 481 // all items are already loaded. proceed... 482 onComplete(childItems); 398 483 }else{ 399 // get children of specified node 400 var childItems = []; 401 for (var i=0; i<this.childrenAttr.length; i++){ 402 childItems= childItems.concat(store.getValues(parentItem, this.childrenAttr[i])); 403 } 404 // count how many items need to be loaded 405 var _waitCount = 0; 406 dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } }); 407 408 if(_waitCount == 0){ 409 // all items are already loaded. proceed.. 410 onComplete(childItems); 411 }else{ 412 // still waiting for some or all of the items to load 413 var onItem = function onItem(item){ 414 if(--_waitCount == 0){ 415 // all nodes have been loaded, send them to the tree 416 onComplete(childItems); 417 } 484 // still waiting for some or all of the items to load 485 var onItem = function onItem(item){ 486 if(--_waitCount == 0){ 487 // all nodes have been loaded, send them to the tree 488 onComplete(childItems); 418 489 } 419 dojo.forEach(childItems, function(item){420 if(!store.isItemLoaded(item)){421 store.loadItem({422 item: item,423 onItem: onItem424 });425 } 426 } );427 } 490 } 491 dojo.forEach(childItems, function(item){ 492 if(!store.isItemLoaded(item)){ 493 store.loadItem({ 494 item: item, 495 onItem: onItem 496 }); 497 } 498 }); 428 499 } 429 500 }, … … 434 505 // on a newItem() call to the data store (or null if no parent specified). 435 506 // It's called with args from dojo.store.Notification.onNew. 507 // TODO: remove in 2.0 436 508 return this.store.getIdentity(parentInfo.item); // String 437 509 }, … … 530 602 // unless the parent is the root of a tree with a hidden root 531 603 var parent = node.getParent(); 532 if(!( this._hideRoot && parent === this)){604 if(!(!this.showRoot && parent === this.rootNode)){ 533 605 node = parent; 534 606 } … … 672 744 _getRootOrFirstNode: function(){ 673 745 // summary: get first visible node 674 return this. _hideRoot ? this.getChildren()[0] : this;746 return this.showRoot ? this.rootNode : this.rootNode.getChildren()[0]; 675 747 }, 676 748 … … 705 777 706 778 // clicking the expando node might have erased focus from the current item; restore it 707 var t = node.tree; 708 if(t.lastFocused){ t.focusNode(t.lastFocused); } 779 if(this.lastFocused){ this.focusNode(this.lastFocused); } 709 780 710 781 if(!node.isExpandable){ … … 712 783 } 713 784 714 var store = this.store ;715 var getValue = this.store.getValue;785 var store = this.store, 786 item = node.item; 716 787 717 788 switch(node.state){ … … 728 799 _this._onLoadAllItems(node, childItems, true); 729 800 }; 730 this.getItemChildren( node.item, onComplete);801 this.getItemChildren((this._v10Compat && item === store.root) ? null : item, onComplete); 731 802 break; 732 803 733 804 default: 734 805 // data is already loaded; just proceed 735 if(node.expand){ // top level Tree doesn't have expand() method 736 node.expand(); 737 if(this.persist && node.item){ 738 this._openedItemIds[this.store.getIdentity(node.item)] = true; 739 this._saveState(); 740 } 806 node.expand(); 807 if(this.persist && item){ 808 this._openedItemIds[store.getIdentity(item)] = true; 809 this._saveState(); 741 810 } 742 811 } … … 796 865 _onNewItem: function(/* dojo.data.Item */ item, parentInfo){ 797 866 //summary: callback when new item has been added to the store. 798 parentInfo ? this.onNewChildItem(item, parentInfo) : this.onNewTopItem(item);799 },800 801 onNewChildItem: function(/* dojo.data.Item */ item, parentInfo){802 // summary: called when store.newItem(item, parentInfo) has been called with non-null parentInfo 867 868 if(!parentInfo){ 869 return; 870 } 871 803 872 var parentNode = this._itemNodeMap[this.getItemParentIdentity(item, parentInfo)]; 804 873 … … 818 887 }, 819 888 820 onNewTopItem: function(/* dojo.data.Item */ item){821 // summary:822 // Called when store.newItem(item, null) has been called with null parentInfo.823 // By default reruns the query for all top level items; user should override824 // with more efficient function.825 this.reload();826 },827 828 reload: function(){829 // summary: reload the list of top level items in the tree830 this.markProcessing();831 var _this = this;832 var onComplete = function(childItems){833 _this.unmarkProcessing();834 _this._onLoadAllItems(_this, childItems, false);835 };836 this.getItemChildren(null, onComplete);837 },838 839 889 _onDeleteItem: function(/*Object*/ item){ 840 890 //summary: delete event from the store 841 //since the object has just been deleted, we need to 842 //use the name directly 891 843 892 var identity = this.store.getIdentity(item); 844 893 var node = this._itemNodeMap[identity]; … … 860 909 /* object | array */ newValue){ 861 910 //summary: set data event on an item in the store 862 var identity = this.store.getIdentity(item), 911 var store = this.store, 912 identity = store.getIdentity(item), 863 913 node = this._itemNodeMap[identity]; 864 914 865 915 if(node){ 866 node.setLabelNode(this.getLabel(item)); 867 node._updateItemClasses(item); 868 916 if(!(this._v10Compat && item === store.root)){ 917 node.setLabelNode(this.getLabel(item)); 918 node._updateItemClasses(item); 919 } 920 869 921 // If this item's children have changed, update tree accordingly. 870 922 // Have to download the new nodes, which may be an async operation. … … 876 928 _this._onLoadAllItems(node, childItems, false); 877 929 }; 878 this.getItemChildren( node.item, onComplete);930 this.getItemChildren((this._v10Compat && item === store.root) ? null : item, onComplete); 879 931 } 880 932 } … … 891 943 } 892 944 dojo.cookie(this.cookieName, ary.join(",")); 945 }, 946 947 destroy: function(){ 948 if(this.rootNode){ 949 this.rootNode.destroyRecursive(); 950 } 951 this.rootNode = null; 952 this.inherited(arguments); 953 }, 954 955 destroyRecursive: function(){ 956 // A tree is treated as a leaf, not as a node with children (like a grid), 957 // but defining destroyRecursive for back-compat. 958 this.destroy(); 893 959 } 894 960 }); -
dijit/trunk/_tree/dndSource.js
r12020 r12309 260 260 this.isDragging = false; 261 261 262 // Compute the new parent item (if we are *not* dropping at the top level)262 // Compute the new parent item 263 263 var targetWidget = dijit.getEnclosingWidget(target), 264 newParentItem; 265 if(targetWidget && targetWidget.item){ 266 // dropping onto another item 267 newParentItem = targetWidget.item; 268 }else{ 269 // dropping onto root 270 requeryRoot = true; 271 } 264 newParentItem = (targetWidget && targetWidget.item) || tree.item; 272 265 273 266 // If we are dragging from another source (or at least, another source … … 292 285 oldParentItem = childTreeNode.getParent().item; 293 286 294 if( oldParentItem ){ 295 dojo.forEach(tree.childrenAttr, function(attr){ 296 if(store.containsValue(oldParentItem, attr, childItem)){ 297 var values = dojo.filter(store.getValues(oldParentItem, attr), function(x){ 298 return x != childItem; 299 }); 300 store.setValues(oldParentItem, attr, values); 301 parentAttr = attr; 302 } 303 }); 304 } 305 306 if(newParentItem){ 307 // modify target item's children attribute to include this item 308 store.setValues(newParentItem, parentAttr, 309 store.getValues(newParentItem, parentAttr).concat(childItem)); 310 } 287 dojo.forEach(tree.childrenAttr, function(attr){ 288 if(store.containsValue(oldParentItem, attr, childItem)){ 289 var values = dojo.filter(store.getValues(oldParentItem, attr), function(x){ 290 return x != childItem; 291 }); 292 store.setValues(oldParentItem, attr, values); 293 parentAttr = attr; 294 } 295 }); 296 297 // modify target item's children attribute to include this item 298 store.setValues(newParentItem, parentAttr, 299 store.getValues(newParentItem, parentAttr).concat(childItem)); 311 300 }else{ 312 var pInfo = newParentItem ? {parent: newParentItem, attribute: parentAttr} : null;301 var pInfo = {parent: newParentItem, attribute: parentAttr}; 313 302 store.newItem(newItemsParams[idx], pInfo); 314 303 } 315 304 }, this); 316 if(requeryRoot){317 // The list of top level children changed, so update it.318 tree.reload();319 }320 305 } 321 306 this.onDndCancel(); -
dijit/trunk/_tree/Node.html
r11200 r12309 1 <div class="dijitTreeNode dijitTreeExpandLeaf dijitTreeChildrenNo" waiRole="presentation" 2 ><span dojoAttachPoint="expandoNode" class="dijitTreeExpando" waiRole="presentation" 3 ></span 4 ><span dojoAttachPoint="expandoNodeText" class="dijitExpandoText" waiRole="presentation" 5 ></span 6 > 7 <div dojoAttachPoint="contentNode" class="dijitTreeContent" waiRole="presentation"> 8 <div dojoAttachPoint="iconNode" class="dijitInline dijitTreeIcon" waiRole="presentation"></div> 9 <span dojoAttachPoint="labelNode" class="dijitTreeLabel" wairole="treeitem" tabindex="-1"></span> 10 </div> 1 <div class="dijitTreeNode" waiRole="presentation" 2 ><div dojoAttachPoint="rowNode" 3 ><span dojoAttachPoint="expandoNode" class="dijitTreeExpando" waiRole="presentation" 4 ></span 5 ><span dojoAttachPoint="expandoNodeText" class="dijitExpandoText" waiRole="presentation" 6