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