Upgrade to ExtJS 3.0.3 - Released 10/11/2009
[extjs.git] / docs / source / TreePanel.html
1 <html>
2 <head>
3   <title>The source code</title>
4     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
5     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
6 </head>
7 <body  onload="prettyPrint();">
8     <pre class="prettyprint lang-js">/*!
9  * Ext JS Library 3.0.3
10  * Copyright(c) 2006-2009 Ext JS, LLC
11  * licensing@extjs.com
12  * http://www.extjs.com/license
13  */
14 <div id="cls-Ext.tree.TreePanel"></div>/**\r
15  * @class Ext.tree.TreePanel\r
16  * @extends Ext.Panel\r
17  * <p>The TreePanel provides tree-structured UI representation of tree-structured data.</p>\r
18  * <p>{@link Ext.tree.TreeNode TreeNode}s added to the TreePanel may each contain metadata\r
19  * used by your application in their {@link Ext.tree.TreeNode#attributes attributes} property.</p>\r
20  * <p><b>A TreePanel must have a {@link #root} node before it is rendered.</b> This may either be\r
21  * specified using the {@link #root} config option, or using the {@link #setRootNode} method.\r
22  * <p>An example of tree rendered to an existing div:</p><pre><code>\r
23 var tree = new Ext.tree.TreePanel({\r
24     renderTo: 'tree-div',\r
25     useArrows: true,\r
26     autoScroll: true,\r
27     animate: true,\r
28     enableDD: true,\r
29     containerScroll: true,\r
30     border: false,\r
31     // auto create TreeLoader\r
32     dataUrl: 'get-nodes.php',\r
33 \r
34     root: {\r
35         nodeType: 'async',\r
36         text: 'Ext JS',\r
37         draggable: false,\r
38         id: 'source'\r
39     }\r
40 });\r
41 \r
42 tree.getRootNode().expand();\r
43  * </code></pre>\r
44  * <p>The example above would work with a data packet similar to this:</p><pre><code>\r
45 [{\r
46     "text": "adapter",\r
47     "id": "source\/adapter",\r
48     "cls": "folder"\r
49 }, {\r
50     "text": "dd",\r
51     "id": "source\/dd",\r
52     "cls": "folder"\r
53 }, {\r
54     "text": "debug.js",\r
55     "id": "source\/debug.js",\r
56     "leaf": true,\r
57     "cls": "file"\r
58 }]\r
59  * </code></pre>\r
60  * <p>An example of tree within a Viewport:</p><pre><code>\r
61 new Ext.Viewport({\r
62     layout: 'border',\r
63     items: [{\r
64         region: 'west',\r
65         collapsible: true,\r
66         title: 'Navigation',\r
67         xtype: 'treepanel',\r
68         width: 200,\r
69         autoScroll: true,\r
70         split: true,\r
71         loader: new Ext.tree.TreeLoader(),\r
72         root: new Ext.tree.AsyncTreeNode({\r
73             expanded: true,\r
74             children: [{\r
75                 text: 'Menu Option 1',\r
76                 leaf: true\r
77             }, {\r
78                 text: 'Menu Option 2',\r
79                 leaf: true\r
80             }, {\r
81                 text: 'Menu Option 3',\r
82                 leaf: true\r
83             }]\r
84         }),\r
85         rootVisible: false,\r
86         listeners: {\r
87             click: function(n) {\r
88                 Ext.Msg.alert('Navigation Tree Click', 'You clicked: "' + n.attributes.text + '"');\r
89             }\r
90         }\r
91     }, {\r
92         region: 'center',\r
93         xtype: 'tabpanel',\r
94         // remaining code not shown ...\r
95     }]\r
96 });\r
97 </code></pre>\r
98  *\r
99  * @cfg {Ext.tree.TreeNode} root The root node for the tree.\r
100  * @cfg {Boolean} rootVisible <tt>false</tt> to hide the root node (defaults to <tt>true</tt>)\r
101  * @cfg {Boolean} lines <tt>false</tt> to disable tree lines (defaults to <tt>true</tt>)\r
102  * @cfg {Boolean} enableDD <tt>true</tt> to enable drag and drop\r
103  * @cfg {Boolean} enableDrag <tt>true</tt> to enable just drag\r
104  * @cfg {Boolean} enableDrop <tt>true</tt> to enable just drop\r
105  * @cfg {Object} dragConfig Custom config to pass to the {@link Ext.tree.TreeDragZone} instance\r
106  * @cfg {Object} dropConfig Custom config to pass to the {@link Ext.tree.TreeDropZone} instance\r
107  * @cfg {String} ddGroup The DD group this TreePanel belongs to\r
108  * @cfg {Boolean} ddAppendOnly <tt>true</tt> if the tree should only allow append drops (use for trees which are sorted)\r
109  * @cfg {Boolean} ddScroll <tt>true</tt> to enable body scrolling\r
110  * @cfg {Boolean} containerScroll <tt>true</tt> to register this container with ScrollManager\r
111  * @cfg {Boolean} hlDrop <tt>false</tt> to disable node highlight on drop (defaults to the value of {@link Ext#enableFx})\r
112  * @cfg {String} hlColor The color of the node highlight (defaults to <tt>'C3DAF9'</tt>)\r
113  * @cfg {Boolean} animate <tt>true</tt> to enable animated expand/collapse (defaults to the value of {@link Ext#enableFx})\r
114  * @cfg {Boolean} singleExpand <tt>true</tt> if only 1 node per branch may be expanded\r
115  * @cfg {Object} selModel A tree selection model to use with this TreePanel (defaults to an {@link Ext.tree.DefaultSelectionModel})\r
116  * @cfg {Boolean} trackMouseOver <tt>false</tt> to disable mouse over highlighting\r
117  * @cfg {Ext.tree.TreeLoader} loader A {@link Ext.tree.TreeLoader} for use with this TreePanel\r
118  * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to <tt>'/'</tt>)\r
119  * @cfg {Boolean} useArrows <tt>true</tt> to use Vista-style arrows in the tree (defaults to <tt>false</tt>)\r
120  * @cfg {String} requestMethod The HTTP request method for loading data (defaults to the value of {@link Ext.Ajax#method}).\r
121  *\r
122  * @constructor\r
123  * @param {Object} config\r
124  * @xtype treepanel\r
125  */\r
126 Ext.tree.TreePanel = Ext.extend(Ext.Panel, {\r
127     rootVisible : true,\r
128     animate: Ext.enableFx,\r
129     lines : true,\r
130     enableDD : false,\r
131     hlDrop : Ext.enableFx,\r
132     pathSeparator: "/",\r
133     \r
134     /**\r
135      * @cfg {Array} bubbleEvents\r
136      * <p>An array of events that, when fired, should be bubbled to any parent container.\r
137      * Defaults to <tt>['add', 'remove']</tt>.\r
138      */\r
139     bubbleEvents: [],\r
140 \r
141     initComponent : function(){\r
142         Ext.tree.TreePanel.superclass.initComponent.call(this);\r
143 \r
144         if(!this.eventModel){\r
145             this.eventModel = new Ext.tree.TreeEventModel(this);\r
146         }\r
147 \r
148         // initialize the loader\r
149         var l = this.loader;\r
150         if(!l){\r
151             l = new Ext.tree.TreeLoader({\r
152                 dataUrl: this.dataUrl,\r
153                 requestMethod: this.requestMethod\r
154             });\r
155         }else if(typeof l == 'object' && !l.load){\r
156             l = new Ext.tree.TreeLoader(l);\r
157         }\r
158         this.loader = l;\r
159 \r
160         this.nodeHash = {};\r
161 \r
162         /**\r
163         * The root node of this tree.\r
164         * @type Ext.tree.TreeNode\r
165         * @property root\r
166         */\r
167         if(this.root){\r
168             var r = this.root;\r
169             delete this.root;\r
170             this.setRootNode(r);\r
171         }\r
172 \r
173 \r
174         this.addEvents(\r
175 \r
176             /**\r
177             * @event append\r
178             * Fires when a new child node is appended to a node in this tree.\r
179             * @param {Tree} tree The owner tree\r
180             * @param {Node} parent The parent node\r
181             * @param {Node} node The newly appended node\r
182             * @param {Number} index The index of the newly appended node\r
183             */\r
184            "append",\r
185            /**\r
186             * @event remove\r
187             * Fires when a child node is removed from a node in this tree.\r
188             * @param {Tree} tree The owner tree\r
189             * @param {Node} parent The parent node\r
190             * @param {Node} node The child node removed\r
191             */\r
192            "remove",\r
193            /**\r
194             * @event movenode\r
195             * Fires when a node is moved to a new location in the tree\r
196             * @param {Tree} tree The owner tree\r
197             * @param {Node} node The node moved\r
198             * @param {Node} oldParent The old parent of this node\r
199             * @param {Node} newParent The new parent of this node\r
200             * @param {Number} index The index it was moved to\r
201             */\r
202            "movenode",\r
203            /**\r
204             * @event insert\r
205             * Fires when a new child node is inserted in a node in this tree.\r
206             * @param {Tree} tree The owner tree\r
207             * @param {Node} parent The parent node\r
208             * @param {Node} node The child node inserted\r
209             * @param {Node} refNode The child node the node was inserted before\r
210             */\r
211            "insert",\r
212            /**\r
213             * @event beforeappend\r
214             * Fires before a new child is appended to a node in this tree, return false to cancel the append.\r
215             * @param {Tree} tree The owner tree\r
216             * @param {Node} parent The parent node\r
217             * @param {Node} node The child node to be appended\r
218             */\r
219            "beforeappend",\r
220            /**\r
221             * @event beforeremove\r
222             * Fires before a child is removed from a node in this tree, return false to cancel the remove.\r
223             * @param {Tree} tree The owner tree\r
224             * @param {Node} parent The parent node\r
225             * @param {Node} node The child node to be removed\r
226             */\r
227            "beforeremove",\r
228            /**\r
229             * @event beforemovenode\r
230             * Fires before a node is moved to a new location in the tree. Return false to cancel the move.\r
231             * @param {Tree} tree The owner tree\r
232             * @param {Node} node The node being moved\r
233             * @param {Node} oldParent The parent of the node\r
234             * @param {Node} newParent The new parent the node is moving to\r
235             * @param {Number} index The index it is being moved to\r
236             */\r
237            "beforemovenode",\r
238            /**\r
239             * @event beforeinsert\r
240             * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.\r
241             * @param {Tree} tree The owner tree\r
242             * @param {Node} parent The parent node\r
243             * @param {Node} node The child node to be inserted\r
244             * @param {Node} refNode The child node the node is being inserted before\r
245             */\r
246             "beforeinsert",\r
247 \r
248             /**\r
249             * @event beforeload\r
250             * Fires before a node is loaded, return false to cancel\r
251             * @param {Node} node The node being loaded\r
252             */\r
253             "beforeload",\r
254             /**\r
255             * @event load\r
256             * Fires when a node is loaded\r
257             * @param {Node} node The node that was loaded\r
258             */\r
259             "load",\r
260             /**\r
261             * @event textchange\r
262             * Fires when the text for a node is changed\r
263             * @param {Node} node The node\r
264             * @param {String} text The new text\r
265             * @param {String} oldText The old text\r
266             */\r
267             "textchange",\r
268             /**\r
269             * @event beforeexpandnode\r
270             * Fires before a node is expanded, return false to cancel.\r
271             * @param {Node} node The node\r
272             * @param {Boolean} deep\r
273             * @param {Boolean} anim\r
274             */\r
275             "beforeexpandnode",\r
276             /**\r
277             * @event beforecollapsenode\r
278             * Fires before a node is collapsed, return false to cancel.\r
279             * @param {Node} node The node\r
280             * @param {Boolean} deep\r
281             * @param {Boolean} anim\r
282             */\r
283             "beforecollapsenode",\r
284             /**\r
285             * @event expandnode\r
286             * Fires when a node is expanded\r
287             * @param {Node} node The node\r
288             */\r
289             "expandnode",\r
290             /**\r
291             * @event disabledchange\r
292             * Fires when the disabled status of a node changes\r
293             * @param {Node} node The node\r
294             * @param {Boolean} disabled\r
295             */\r
296             "disabledchange",\r
297             /**\r
298             * @event collapsenode\r
299             * Fires when a node is collapsed\r
300             * @param {Node} node The node\r
301             */\r
302             "collapsenode",\r
303             /**\r
304             * @event beforeclick\r
305             * Fires before click processing on a node. Return false to cancel the default action.\r
306             * @param {Node} node The node\r
307             * @param {Ext.EventObject} e The event object\r
308             */\r
309             "beforeclick",\r
310             /**\r
311             * @event click\r
312             * Fires when a node is clicked\r
313             * @param {Node} node The node\r
314             * @param {Ext.EventObject} e The event object\r
315             */\r
316             "click",\r
317             /**\r
318             * @event checkchange\r
319             * Fires when a node with a checkbox's checked property changes\r
320             * @param {Node} this This node\r
321             * @param {Boolean} checked\r
322             */\r
323             "checkchange",\r
324             /**\r
325             * @event beforedblclick\r
326             * Fires before double click processing on a node. Return false to cancel the default action.\r
327             * @param {Node} node The node\r
328             * @param {Ext.EventObject} e The event object\r
329             */\r
330             "beforedblclick",\r
331             /**\r
332             * @event dblclick\r
333             * Fires when a node is double clicked\r
334             * @param {Node} node The node\r
335             * @param {Ext.EventObject} e The event object\r
336             */\r
337             "dblclick",\r
338             /**\r
339             * @event contextmenu\r
340             * Fires when a node is right clicked. To display a context menu in response to this\r
341             * event, first create a Menu object (see {@link Ext.menu.Menu} for details), then add\r
342             * a handler for this event:<pre><code>\r
343 new Ext.tree.TreePanel({\r
344     title: 'My TreePanel',\r
345     root: new Ext.tree.AsyncTreeNode({\r
346         text: 'The Root',\r
347         children: [\r
348             { text: 'Child node 1', leaf: true },\r
349             { text: 'Child node 2', leaf: true }\r
350         ]\r
351     }),\r
352     contextMenu: new Ext.menu.Menu({\r
353         items: [{\r
354             id: 'delete-node',\r
355             text: 'Delete Node'\r
356         }],\r
357         listeners: {\r
358             itemclick: function(item) {\r
359                 switch (item.id) {\r
360                     case 'delete-node':\r
361                         var n = item.parentMenu.contextNode;\r
362                         if (n.parentNode) {\r
363                             n.remove();\r
364                         }\r
365                         break;\r
366                 }\r
367             }\r
368         }\r
369     }),\r
370     listeners: {\r
371         contextmenu: function(node, e) {\r
372 //          Register the context node with the menu so that a Menu Item's handler function can access\r
373 //          it via its {@link Ext.menu.BaseItem#parentMenu parentMenu} property.\r
374             node.select();\r
375             var c = node.getOwnerTree().contextMenu;\r
376             c.contextNode = node;\r
377             c.showAt(e.getXY());\r
378         }\r
379     }\r
380 });\r
381 </code></pre>\r
382             * @param {Node} node The node\r
383             * @param {Ext.EventObject} e The event object\r
384             */\r
385             "contextmenu",\r
386             /**\r
387             * @event beforechildrenrendered\r
388             * Fires right before the child nodes for a node are rendered\r
389             * @param {Node} node The node\r
390             */\r
391             "beforechildrenrendered",\r
392            /**\r
393              * @event startdrag\r
394              * Fires when a node starts being dragged\r
395              * @param {Ext.tree.TreePanel} this\r
396              * @param {Ext.tree.TreeNode} node\r
397              * @param {event} e The raw browser event\r
398              */\r
399             "startdrag",\r
400             /**\r
401              * @event enddrag\r
402              * Fires when a drag operation is complete\r
403              * @param {Ext.tree.TreePanel} this\r
404              * @param {Ext.tree.TreeNode} node\r
405              * @param {event} e The raw browser event\r
406              */\r
407             "enddrag",\r
408             /**\r
409              * @event dragdrop\r
410              * Fires when a dragged node is dropped on a valid DD target\r
411              * @param {Ext.tree.TreePanel} this\r
412              * @param {Ext.tree.TreeNode} node\r
413              * @param {DD} dd The dd it was dropped on\r
414              * @param {event} e The raw browser event\r
415              */\r
416             "dragdrop",\r
417             /**\r
418              * @event beforenodedrop\r
419              * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent\r
420              * passed to handlers has the following properties:<br />\r
421              * <ul style="padding:5px;padding-left:16px;">\r
422              * <li>tree - The TreePanel</li>\r
423              * <li>target - The node being targeted for the drop</li>\r
424              * <li>data - The drag data from the drag source</li>\r
425              * <li>point - The point of the drop - append, above or below</li>\r
426              * <li>source - The drag source</li>\r
427              * <li>rawEvent - Raw mouse event</li>\r
428              * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)\r
429              * to be inserted by setting them on this object.</li>\r
430              * <li>cancel - Set this to true to cancel the drop.</li>\r
431              * <li>dropStatus - If the default drop action is cancelled but the drop is valid, setting this to true\r
432              * will prevent the animated "repair" from appearing.</li>\r
433              * </ul>\r
434              * @param {Object} dropEvent\r
435              */\r
436             "beforenodedrop",\r
437             /**\r
438              * @event nodedrop\r
439              * Fires after a DD object is dropped on a node in this tree. The dropEvent\r
440              * passed to handlers has the following properties:<br />\r
441              * <ul style="padding:5px;padding-left:16px;">\r
442              * <li>tree - The TreePanel</li>\r
443              * <li>target - The node being targeted for the drop</li>\r
444              * <li>data - The drag data from the drag source</li>\r
445              * <li>point - The point of the drop - append, above or below</li>\r
446              * <li>source - The drag source</li>\r
447              * <li>rawEvent - Raw mouse event</li>\r
448              * <li>dropNode - Dropped node(s).</li>\r
449              * </ul>\r
450              * @param {Object} dropEvent\r
451              */\r
452             "nodedrop",\r
453              /**\r
454              * @event nodedragover\r
455              * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent\r
456              * passed to handlers has the following properties:<br />\r
457              * <ul style="padding:5px;padding-left:16px;">\r
458              * <li>tree - The TreePanel</li>\r
459              * <li>target - The node being targeted for the drop</li>\r
460              * <li>data - The drag data from the drag source</li>\r
461              * <li>point - The point of the drop - append, above or below</li>\r
462              * <li>source - The drag source</li>\r
463              * <li>rawEvent - Raw mouse event</li>\r
464              * <li>dropNode - Drop node(s) provided by the source.</li>\r
465              * <li>cancel - Set this to true to signal drop not allowed.</li>\r
466              * </ul>\r
467              * @param {Object} dragOverEvent\r
468              */\r
469             "nodedragover"\r
470         );\r
471         if(this.singleExpand){\r
472             this.on("beforeexpandnode", this.restrictExpand, this);\r
473         }\r
474     },\r
475 \r
476     // private\r
477     proxyNodeEvent : function(ename, a1, a2, a3, a4, a5, a6){\r
478         if(ename == 'collapse' || ename == 'expand' || ename == 'beforecollapse' || ename == 'beforeexpand' || ename == 'move' || ename == 'beforemove'){\r
479             ename = ename+'node';\r
480         }\r
481         // args inline for performance while bubbling events\r
482         return this.fireEvent(ename, a1, a2, a3, a4, a5, a6);\r
483     },\r
484 \r
485 \r
486     /**\r
487      * Returns this root node for this tree\r
488      * @return {Node}\r
489      */\r
490     getRootNode : function(){\r
491         return this.root;\r
492     },\r
493 \r
494     /**\r
495      * Sets the root node for this tree. If the TreePanel has already rendered a root node, the\r
496      * previous root node (and all of its descendants) are destroyed before the new root node is rendered.\r
497      * @param {Node} node\r
498      * @return {Node}\r
499      */\r
500     setRootNode : function(node){\r
501         Ext.destroy(this.root);\r
502         if(!node.render){ // attributes passed\r
503             node = this.loader.createNode(node);\r
504         }\r
505         this.root = node;\r
506         node.ownerTree = this;\r
507         node.isRoot = true;\r
508         this.registerNode(node);\r
509         if(!this.rootVisible){\r
510             var uiP = node.attributes.uiProvider;\r
511             node.ui = uiP ? new uiP(node) : new Ext.tree.RootTreeNodeUI(node);\r
512         }\r
513         if (this.innerCt) {\r
514             this.innerCt.update('');\r
515             this.afterRender();\r
516         }\r
517         return node;\r
518     },\r
519 \r
520     /**\r
521      * Gets a node in this tree by its id\r
522      * @param {String} id\r
523      * @return {Node}\r
524      */\r
525     getNodeById : function(id){\r
526         return this.nodeHash[id];\r
527     },\r
528 \r
529     // private\r
530     registerNode : function(node){\r
531         this.nodeHash[node.id] = node;\r
532     },\r
533 \r
534     // private\r
535     unregisterNode : function(node){\r
536         delete this.nodeHash[node.id];\r
537     },\r
538 \r
539     // private\r
540     toString : function(){\r
541         return "[Tree"+(this.id?" "+this.id:"")+"]";\r
542     },\r
543 \r
544     // private\r
545     restrictExpand : function(node){\r
546         var p = node.parentNode;\r
547         if(p){\r
548             if(p.expandedChild && p.expandedChild.parentNode == p){\r
549                 p.expandedChild.collapse();\r
550             }\r
551             p.expandedChild = node;\r
552         }\r
553     },\r
554 \r
555     /**\r
556      * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")\r
557      * @param {String} attribute (optional) Defaults to null (return the actual nodes)\r
558      * @param {TreeNode} startNode (optional) The node to start from, defaults to the root\r
559      * @return {Array}\r
560      */\r
561     getChecked : function(a, startNode){\r
562         startNode = startNode || this.root;\r
563         var r = [];\r
564         var f = function(){\r
565             if(this.attributes.checked){\r
566                 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));\r
567             }\r
568         };\r
569         startNode.cascade(f);\r
570         return r;\r
571     },\r
572 \r
573     /**\r
574      * Returns the container element for this TreePanel.\r
575      * @return {Element} The container element for this TreePanel.\r
576      */\r
577     getEl : function(){\r
578         return this.el;\r
579     },\r
580 \r
581     /**\r
582      * Returns the default {@link Ext.tree.TreeLoader} for this TreePanel.\r
583      * @return {Ext.tree.TreeLoader} The TreeLoader for this TreePanel.\r
584      */\r
585     getLoader : function(){\r
586         return this.loader;\r
587     },\r
588 \r
589     /**\r
590      * Expand all nodes\r
591      */\r
592     expandAll : function(){\r
593         this.root.expand(true);\r
594     },\r
595 \r
596     /**\r
597      * Collapse all nodes\r
598      */\r
599     collapseAll : function(){\r
600         this.root.collapse(true);\r
601     },\r
602 \r
603     /**\r
604      * Returns the selection model used by this TreePanel.\r
605      * @return {TreeSelectionModel} The selection model used by this TreePanel\r
606      */\r
607     getSelectionModel : function(){\r
608         if(!this.selModel){\r
609             this.selModel = new Ext.tree.DefaultSelectionModel();\r
610         }\r
611         return this.selModel;\r
612     },\r
613 \r
614     /**\r
615      * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Ext.data.Node#getPath}\r
616      * @param {String} path\r
617      * @param {String} attr (optional) The attribute used in the path (see {@link Ext.data.Node#getPath} for more info)\r
618      * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with\r
619      * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.\r
620      */\r
621     expandPath : function(path, attr, callback){\r
622         attr = attr || "id";\r
623         var keys = path.split(this.pathSeparator);\r
624         var curNode = this.root;\r
625         if(curNode.attributes[attr] != keys[1]){ // invalid root\r
626             if(callback){\r
627                 callback(false, null);\r
628             }\r
629             return;\r
630         }\r
631         var index = 1;\r
632         var f = function(){\r
633             if(++index == keys.length){\r
634                 if(callback){\r
635                     callback(true, curNode);\r
636                 }\r
637                 return;\r
638             }\r
639             var c = curNode.findChild(attr, keys[index]);\r
640             if(!c){\r
641                 if(callback){\r
642                     callback(false, curNode);\r
643                 }\r
644                 return;\r
645             }\r
646             curNode = c;\r
647             c.expand(false, false, f);\r
648         };\r
649         curNode.expand(false, false, f);\r
650     },\r
651 \r
652     /**\r
653      * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Ext.data.Node#getPath}\r
654      * @param {String} path\r
655      * @param {String} attr (optional) The attribute used in the path (see {@link Ext.data.Node#getPath} for more info)\r
656      * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with\r
657      * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.\r
658      */\r
659     selectPath : function(path, attr, callback){\r
660         attr = attr || "id";\r
661         var keys = path.split(this.pathSeparator),\r
662             v = keys.pop();\r
663         if(keys.length > 1){\r
664             var f = function(success, node){\r
665                 if(success && node){\r
666                     var n = node.findChild(attr, v);\r
667                     if(n){\r
668                         n.select();\r
669                         if(callback){\r
670                             callback(true, n);\r
671                         }\r
672                     }else if(callback){\r
673                         callback(false, n);\r
674                     }\r
675                 }else{\r
676                     if(callback){\r
677                         callback(false, n);\r
678                     }\r
679                 }\r
680             };\r
681             this.expandPath(keys.join(this.pathSeparator), attr, f);\r
682         }else{\r
683             this.root.select();\r
684             if(callback){\r
685                 callback(true, this.root);\r
686             }\r
687         }\r
688     },\r
689 \r
690     /**\r
691      * Returns the underlying Element for this tree\r
692      * @return {Ext.Element} The Element\r
693      */\r
694     getTreeEl : function(){\r
695         return this.body;\r
696     },\r
697 \r
698     // private\r
699     onRender : function(ct, position){\r
700         Ext.tree.TreePanel.superclass.onRender.call(this, ct, position);\r
701         this.el.addClass('x-tree');\r
702         this.innerCt = this.body.createChild({tag:"ul",\r
703                cls:"x-tree-root-ct " +\r
704                (this.useArrows ? 'x-tree-arrows' : this.lines ? "x-tree-lines" : "x-tree-no-lines")});\r
705     },\r
706 \r
707     // private\r
708     initEvents : function(){\r
709         Ext.tree.TreePanel.superclass.initEvents.call(this);\r
710 \r
711         if(this.containerScroll){\r
712             Ext.dd.ScrollManager.register(this.body);\r
713         }\r
714         if((this.enableDD || this.enableDrop) && !this.dropZone){\r
715            /**\r
716             * The dropZone used by this tree if drop is enabled (see {@link #enableDD} or {@link #enableDrop})\r
717             * @property dropZone\r
718             * @type Ext.tree.TreeDropZone\r
719             */\r
720              this.dropZone = new Ext.tree.TreeDropZone(this, this.dropConfig || {\r
721                ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true\r
722            });\r
723         }\r
724         if((this.enableDD || this.enableDrag) && !this.dragZone){\r
725            /**\r
726             * The dragZone used by this tree if drag is enabled (see {@link #enableDD} or {@link #enableDrag})\r
727             * @property dragZone\r
728             * @type Ext.tree.TreeDragZone\r
729             */\r
730             this.dragZone = new Ext.tree.TreeDragZone(this, this.dragConfig || {\r
731                ddGroup: this.ddGroup || "TreeDD",\r
732                scroll: this.ddScroll\r
733            });\r
734         }\r
735         this.getSelectionModel().init(this);\r
736     },\r
737 \r
738     // private\r
739     afterRender : function(){\r
740         Ext.tree.TreePanel.superclass.afterRender.call(this);\r
741         this.root.render();\r
742         if(!this.rootVisible){\r
743             this.root.renderChildren();\r
744         }\r
745     },\r
746 \r
747     onDestroy : function(){\r
748         if(this.rendered){\r
749             this.body.removeAllListeners();\r
750             Ext.dd.ScrollManager.unregister(this.body);\r
751             if(this.dropZone){\r
752                 this.dropZone.unreg();\r
753             }\r
754             if(this.dragZone){\r
755                this.dragZone.unreg();\r
756             }\r
757         }\r
758         this.root.destroy();\r
759         this.nodeHash = null;\r
760         Ext.tree.TreePanel.superclass.onDestroy.call(this);\r
761     }\r
762 \r
763     /**\r
764      * @cfg {String/Number} activeItem\r
765      * @hide\r
766      */\r
767     /**\r
768      * @cfg {Boolean} autoDestroy\r
769      * @hide\r
770      */\r
771     /**\r
772      * @cfg {Object/String/Function} autoLoad\r
773      * @hide\r
774      */\r
775     /**\r
776      * @cfg {Boolean} autoWidth\r
777      * @hide\r
778      */\r
779     /**\r
780      * @cfg {Boolean/Number} bufferResize\r
781      * @hide\r
782      */\r
783     /**\r
784      * @cfg {String} defaultType\r
785      * @hide\r
786      */\r
787     /**\r
788      * @cfg {Object} defaults\r
789      * @hide\r
790      */\r
791     /**\r
792      * @cfg {Boolean} hideBorders\r
793      * @hide\r
794      */\r
795     /**\r
796      * @cfg {Mixed} items\r
797      * @hide\r
798      */\r
799     /**\r
800      * @cfg {String} layout\r
801      * @hide\r
802      */\r
803     /**\r
804      * @cfg {Object} layoutConfig\r
805      * @hide\r
806      */\r
807     /**\r
808      * @cfg {Boolean} monitorResize\r
809      * @hide\r
810      */\r
811     /**\r
812      * @property items\r
813      * @hide\r
814      */\r
815     /**\r
816      * @method cascade\r
817      * @hide\r
818      */\r
819     /**\r
820      * @method doLayout\r
821      * @hide\r
822      */\r
823     /**\r
824      * @method find\r
825      * @hide\r
826      */\r
827     /**\r
828      * @method findBy\r
829      * @hide\r
830      */\r
831     /**\r
832      * @method findById\r
833      * @hide\r
834      */\r
835     /**\r
836      * @method findByType\r
837      * @hide\r
838      */\r
839     /**\r
840      * @method getComponent\r
841      * @hide\r
842      */\r
843     /**\r
844      * @method getLayout\r
845      * @hide\r
846      */\r
847     /**\r
848      * @method getUpdater\r
849      * @hide\r
850      */\r
851     /**\r
852      * @method insert\r
853      * @hide\r
854      */\r
855     /**\r
856      * @method load\r
857      * @hide\r
858      */\r
859     /**\r
860      * @method remove\r
861      * @hide\r
862      */\r
863     /**\r
864      * @event add\r
865      * @hide\r
866      */\r
867     /**\r
868      * @method removeAll\r
869      * @hide\r
870      */\r
871     /**\r
872      * @event afterLayout\r
873      * @hide\r
874      */\r
875     /**\r
876      * @event beforeadd\r
877      * @hide\r
878      */\r
879     /**\r
880      * @event beforeremove\r
881      * @hide\r
882      */\r
883     /**\r
884      * @event remove\r
885      * @hide\r
886      */\r
887 \r
888 \r
889 \r
890     /**\r
891      * @cfg {String} allowDomMove  @hide\r
892      */\r
893     /**\r
894      * @cfg {String} autoEl @hide\r
895      */\r
896     /**\r
897      * @cfg {String} applyTo  @hide\r
898      */\r
899     /**\r
900      * @cfg {String} contentEl  @hide\r
901      */\r
902     /**\r
903      * @cfg {String} disabledClass  @hide\r
904      */\r
905     /**\r
906      * @cfg {String} elements  @hide\r
907      */\r
908     /**\r
909      * @cfg {String} html  @hide\r
910      */\r
911     /**\r
912      * @cfg {Boolean} preventBodyReset\r
913      * @hide\r
914      */\r
915     /**\r
916      * @property disabled\r
917      * @hide\r
918      */\r
919     /**\r
920      * @method applyToMarkup\r
921      * @hide\r
922      */\r
923     /**\r
924      * @method enable\r
925      * @hide\r
926      */\r
927     /**\r
928      * @method disable\r
929      * @hide\r
930      */\r
931     /**\r
932      * @method setDisabled\r
933      * @hide\r
934      */\r
935 });\r
936 \r
937 Ext.tree.TreePanel.nodeTypes = {};\r
938 \r
939 Ext.reg('treepanel', Ext.tree.TreePanel);</pre>
940 </body>
941 </html>