TreePanel.js
上传用户:dawnssy
上传日期:2022-08-06
资源大小:9345k
文件大小:31k
源码类别:

JavaScript

开发平台:

JavaScript

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