3 * Copyright(c) 2006-2010 Ext JS, Inc.
5 * http://www.extjs.com/license
8 * @class Ext.tree.TreePanel
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({
22 containerScroll: true,
24 // auto create TreeLoader
25 dataUrl: 'get-nodes.php',
35 tree.getRootNode().expand();
37 * <p>The example above would work with a data packet similar to this:</p><pre><code>
40 "id": "source\/adapter",
48 "id": "source\/debug.js",
53 * <p>An example of tree within a Viewport:</p><pre><code>
64 loader: new Ext.tree.TreeLoader(),
65 root: new Ext.tree.AsyncTreeNode({
68 text: 'Menu Option 1',
71 text: 'Menu Option 2',
74 text: 'Menu Option 3',
81 Ext.Msg.alert('Navigation Tree Click', 'You clicked: "' + n.attributes.text + '"');
87 // remaining code not shown ...
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}).
116 * @param {Object} config
119 Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
121 animate : Ext.enableFx,
124 hlDrop : Ext.enableFx,
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>.
135 initComponent : function(){
136 Ext.tree.TreePanel.superclass.initComponent.call(this);
138 if(!this.eventModel){
139 this.eventModel = new Ext.tree.TreeEventModel(this);
142 // initialize the loader
145 l = new Ext.tree.TreeLoader({
146 dataUrl: this.dataUrl,
147 requestMethod: this.requestMethod
149 }else if(Ext.isObject(l) && !l.load){
150 l = new Ext.tree.TreeLoader(l);
157 * The root node of this tree.
158 * @type Ext.tree.TreeNode
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
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
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
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
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
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
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
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
244 * Fires before a node is loaded, return false to cancel
245 * @param {Node} node The node being loaded
250 * Fires when a node is loaded
251 * @param {Node} node The node that was loaded
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
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
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
277 'beforecollapsenode',
280 * Fires when a node is expanded
281 * @param {Node} node The node
285 * @event disabledchange
286 * Fires when the disabled status of a node changes
287 * @param {Node} node The node
288 * @param {Boolean} disabled
292 * @event collapsenode
293 * Fires when a node is collapsed
294 * @param {Node} node The node
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
306 * Fires when a node is clicked
307 * @param {Node} node The node
308 * @param {Ext.EventObject} e The event object
312 * @event containerclick
313 * Fires when the tree container is clicked
315 * @param {Ext.EventObject} e The event object
320 * Fires when a node with a checkbox's checked property changes
321 * @param {Node} this This node
322 * @param {Boolean} checked
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
334 * Fires when a node is double clicked
335 * @param {Node} node The node
336 * @param {Ext.EventObject} e The event object
340 * @event containerdblclick
341 * Fires when the tree container is double clicked
343 * @param {Ext.EventObject} e The event object
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({
356 { text: 'Child node 1', leaf: true },
357 { text: 'Child node 2', leaf: true }
360 contextMenu: new Ext.menu.Menu({
366 itemclick: function(item) {
369 var n = item.parentMenu.contextNode;
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.
383 var c = node.getOwnerTree().contextMenu;
384 c.contextNode = node;
390 * @param {Node} node The node
391 * @param {Ext.EventObject} e The event object
395 * @event containercontextmenu
396 * Fires when the tree container is right clicked
398 * @param {Ext.EventObject} e The event object
400 'containercontextmenu',
402 * @event beforechildrenrendered
403 * Fires right before the child nodes for a node are rendered
404 * @param {Node} node The node
406 'beforechildrenrendered',
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
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
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
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>
449 * @param {Object} dropEvent
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>
465 * @param {Object} dropEvent
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>
482 * @param {Object} dragOverEvent
486 if(this.singleExpand){
487 this.on('beforeexpandnode', this.restrictExpand, this);
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';
496 // args inline for performance while bubbling events
497 return this.fireEvent(ename, a1, a2, a3, a4, a5, a6);
502 * Returns this root node for this tree
505 getRootNode : function(){
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.
515 setRootNode : function(node){
517 if(!node.render){ // attributes passed
518 node = this.loader.createNode(node);
521 node.ownerTree = this;
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);
535 clearInnerCt : function(){
536 this.innerCt.update('');
540 renderRoot : function(){
542 if(!this.rootVisible){
543 this.root.renderChildren();
548 * Gets a node in this tree by its id
552 getNodeById : function(id){
553 return this.nodeHash[id];
557 registerNode : function(node){
558 this.nodeHash[node.id] = node;
562 unregisterNode : function(node){
563 delete this.nodeHash[node.id];
567 toString : function(){
568 return '[Tree'+(this.id?' '+this.id:'')+']';
572 restrictExpand : function(node){
573 var p = node.parentNode;
575 if(p.expandedChild && p.expandedChild.parentNode == p){
576 p.expandedChild.collapse();
578 p.expandedChild = node;
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
588 getChecked : function(a, startNode){
589 startNode = startNode || this.root;
592 if(this.attributes.checked){
593 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
596 startNode.cascade(f);
601 * Returns the default {@link Ext.tree.TreeLoader} for this TreePanel.
602 * @return {Ext.tree.TreeLoader} The TreeLoader for this TreePanel.
604 getLoader : function(){
611 expandAll : function(){
612 this.root.expand(true);
618 collapseAll : function(){
619 this.root.collapse(true);
623 * Returns the selection model used by this TreePanel.
624 * @return {TreeSelectionModel} The selection model used by this TreePanel
626 getSelectionModel : function(){
628 this.selModel = new Ext.tree.DefaultSelectionModel();
630 return this.selModel;
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.
640 expandPath : function(path, attr, callback){
642 var keys = path.split(this.pathSeparator);
643 var curNode = this.root;
644 if(curNode.attributes[attr] != keys[1]){ // invalid root
646 callback(false, null);
652 if(++index == keys.length){
654 callback(true, curNode);
658 var c = curNode.findChild(attr, keys[index]);
661 callback(false, curNode);
666 c.expand(false, false, f);
668 curNode.expand(false, false, f);
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.
678 selectPath : function(path, attr, callback){
680 var keys = path.split(this.pathSeparator),
683 var f = function(success, node){
685 var n = node.findChild(attr, v);
700 this.expandPath(keys.join(this.pathSeparator), attr, f);
704 callback(true, this.root);
710 * Returns the underlying Element for this tree
711 * @return {Ext.Element} The Element
713 getTreeEl : function(){
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')});
727 initEvents : function(){
728 Ext.tree.TreePanel.superclass.initEvents.call(this);
730 if(this.containerScroll){
731 Ext.dd.ScrollManager.register(this.body);
733 if((this.enableDD || this.enableDrop) && !this.dropZone){
735 * The dropZone used by this tree if drop is enabled (see {@link #enableDD} or {@link #enableDrop})
737 * @type Ext.tree.TreeDropZone
739 this.dropZone = new Ext.tree.TreeDropZone(this, this.dropConfig || {
740 ddGroup: this.ddGroup || 'TreeDD', appendOnly: this.ddAppendOnly === true
743 if((this.enableDD || this.enableDrag) && !this.dragZone){
745 * The dragZone used by this tree if drag is enabled (see {@link #enableDD} or {@link #enableDrag})
747 * @type Ext.tree.TreeDragZone
749 this.dragZone = new Ext.tree.TreeDragZone(this, this.dragConfig || {
750 ddGroup: this.ddGroup || 'TreeDD',
751 scroll: this.ddScroll
754 this.getSelectionModel().init(this);
758 afterRender : function(){
759 Ext.tree.TreePanel.superclass.afterRender.call(this);
763 beforeDestroy : function(){
765 Ext.dd.ScrollManager.unregister(this.body);
766 Ext.destroy(this.dropZone, this.dragZone);
769 Ext.destroy(this.loader);
770 this.nodeHash = this.root = this.loader = null;
771 Ext.tree.TreePanel.superclass.beforeDestroy.call(this);
775 * Destroy the root node. Not included by itself because we need to pass the silent parameter.
778 destroyRoot : function(){
779 if(this.root && this.root.destroy){
780 this.root.destroy(true);
785 * @cfg {String/Number} activeItem
789 * @cfg {Boolean} autoDestroy
793 * @cfg {Object/String/Function} autoLoad
797 * @cfg {Boolean} autoWidth
801 * @cfg {Boolean/Number} bufferResize
805 * @cfg {String} defaultType
809 * @cfg {Object} defaults
813 * @cfg {Boolean} hideBorders
821 * @cfg {String} layout
825 * @cfg {Object} layoutConfig
829 * @cfg {Boolean} monitorResize
861 * @method getComponent
901 * @event beforeremove
912 * @cfg {String} allowDomMove @hide
915 * @cfg {String} autoEl @hide
918 * @cfg {String} applyTo @hide
921 * @cfg {String} contentEl @hide
924 * @cfg {Mixed} data @hide
927 * @cfg {Mixed} tpl @hide
930 * @cfg {String} tplWriteMode @hide
933 * @cfg {String} disabledClass @hide
936 * @cfg {String} elements @hide
939 * @cfg {String} html @hide
942 * @cfg {Boolean} preventBodyReset
950 * @method applyToMarkup
962 * @method setDisabled
967 Ext.tree.TreePanel.nodeTypes = {};
969 Ext.reg('treepanel', Ext.tree.TreePanel);