Upgrade to ExtJS 3.1.1 - Released 02/08/2010
[extjs.git] / pkgs / pkg-tree-debug.js
index 848afea..639fb78 100644 (file)
@@ -1,6 +1,6 @@
 /*!
- * Ext JS Library 3.0.0
- * Copyright(c) 2006-2009 Ext JS, LLC
+ * Ext JS Library 3.1.1
+ * Copyright(c) 2006-2010 Ext JS, LLC
  * licensing@extjs.com
  * http://www.extjs.com/license
  */
@@ -118,11 +118,19 @@ new Ext.Viewport({
  */\r
 Ext.tree.TreePanel = Ext.extend(Ext.Panel, {\r
     rootVisible : true,\r
-    animate: Ext.enableFx,\r
+    animate : Ext.enableFx,\r
     lines : true,\r
     enableDD : false,\r
     hlDrop : Ext.enableFx,\r
-    pathSeparator: "/",\r
+    pathSeparator : '/',\r
+\r
+    /**\r
+     * @cfg {Array} bubbleEvents\r
+     * <p>An array of events that, when fired, should be bubbled to any parent container.\r
+     * See {@link Ext.util.Observable#enableBubble}.\r
+     * Defaults to <tt>[]</tt>.\r
+     */\r
+    bubbleEvents : [],\r
 \r
     initComponent : function(){\r
         Ext.tree.TreePanel.superclass.initComponent.call(this);\r
@@ -138,7 +146,7 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
                 dataUrl: this.dataUrl,\r
                 requestMethod: this.requestMethod\r
             });\r
-        }else if(typeof l == 'object' && !l.load){\r
+        }else if(Ext.isObject(l) && !l.load){\r
             l = new Ext.tree.TreeLoader(l);\r
         }\r
         this.loader = l;\r
@@ -167,7 +175,7 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
             * @param {Node} node The newly appended node\r
             * @param {Number} index The index of the newly appended node\r
             */\r
-           "append",\r
+           'append',\r
            /**\r
             * @event remove\r
             * Fires when a child node is removed from a node in this tree.\r
@@ -175,7 +183,7 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
             * @param {Node} parent The parent node\r
             * @param {Node} node The child node removed\r
             */\r
-           "remove",\r
+           'remove',\r
            /**\r
             * @event movenode\r
             * Fires when a node is moved to a new location in the tree\r
@@ -185,7 +193,7 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
             * @param {Node} newParent The new parent of this node\r
             * @param {Number} index The index it was moved to\r
             */\r
-           "movenode",\r
+           'movenode',\r
            /**\r
             * @event insert\r
             * Fires when a new child node is inserted in a node in this tree.\r
@@ -194,7 +202,7 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
             * @param {Node} node The child node inserted\r
             * @param {Node} refNode The child node the node was inserted before\r
             */\r
-           "insert",\r
+           'insert',\r
            /**\r
             * @event beforeappend\r
             * Fires before a new child is appended to a node in this tree, return false to cancel the append.\r
@@ -202,7 +210,7 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
             * @param {Node} parent The parent node\r
             * @param {Node} node The child node to be appended\r
             */\r
-           "beforeappend",\r
+           'beforeappend',\r
            /**\r
             * @event beforeremove\r
             * Fires before a child is removed from a node in this tree, return false to cancel the remove.\r
@@ -210,7 +218,7 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
             * @param {Node} parent The parent node\r
             * @param {Node} node The child node to be removed\r
             */\r
-           "beforeremove",\r
+           'beforeremove',\r
            /**\r
             * @event beforemovenode\r
             * Fires before a node is moved to a new location in the tree. Return false to cancel the move.\r
@@ -220,7 +228,7 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
             * @param {Node} newParent The new parent the node is moving to\r
             * @param {Number} index The index it is being moved to\r
             */\r
-           "beforemovenode",\r
+           'beforemovenode',\r
            /**\r
             * @event beforeinsert\r
             * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.\r
@@ -229,20 +237,20 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
             * @param {Node} node The child node to be inserted\r
             * @param {Node} refNode The child node the node is being inserted before\r
             */\r
-            "beforeinsert",\r
+            'beforeinsert',\r
 \r
             /**\r
             * @event beforeload\r
             * Fires before a node is loaded, return false to cancel\r
             * @param {Node} node The node being loaded\r
             */\r
-            "beforeload",\r
+            'beforeload',\r
             /**\r
             * @event load\r
             * Fires when a node is loaded\r
             * @param {Node} node The node that was loaded\r
             */\r
-            "load",\r
+            'load',\r
             /**\r
             * @event textchange\r
             * Fires when the text for a node is changed\r
@@ -250,7 +258,7 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
             * @param {String} text The new text\r
             * @param {String} oldText The old text\r
             */\r
-            "textchange",\r
+            'textchange',\r
             /**\r
             * @event beforeexpandnode\r
             * Fires before a node is expanded, return false to cancel.\r
@@ -258,7 +266,7 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
             * @param {Boolean} deep\r
             * @param {Boolean} anim\r
             */\r
-            "beforeexpandnode",\r
+            'beforeexpandnode',\r
             /**\r
             * @event beforecollapsenode\r
             * Fires before a node is collapsed, return false to cancel.\r
@@ -266,54 +274,75 @@ Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
             * @param {Boolean} deep\r
             * @param {Boolean} anim\r
             */\r
-            "beforecollapsenode",\r
+            'beforecollapsenode',\r
             /**\r
             * @event expandnode\r
             * Fires when a node is expanded\r
             * @param {Node} node The node\r
             */\r
-            "expandnode",\r
+            'expandnode',\r
             /**\r
             * @event disabledchange\r
             * Fires when the disabled status of a node changes\r
             * @param {Node} node The node\r
             * @param {Boolean} disabled\r
             */\r
-            "disabledchange",\r
+            'disabledchange',\r
             /**\r
             * @event collapsenode\r
             * Fires when a node is collapsed\r
             * @param {Node} node The node\r
             */\r
-            "collapsenode",\r
+            'collapsenode',\r
             /**\r
             * @event beforeclick\r
             * Fires before click processing on a node. Return false to cancel the default action.\r
             * @param {Node} node The node\r
             * @param {Ext.EventObject} e The event object\r
             */\r
-            "beforeclick",\r
+            'beforeclick',\r
             /**\r
             * @event click\r
             * Fires when a node is clicked\r
             * @param {Node} node The node\r
             * @param {Ext.EventObject} e The event object\r
             */\r
-            "click",\r
+            'click',\r
+            /**\r
+            * @event containerclick\r
+            * Fires when the tree container is clicked\r
+            * @param {Tree} this\r
+            * @param {Ext.EventObject} e The event object\r
+            */\r
+            'containerclick',\r
             /**\r
             * @event checkchange\r
             * Fires when a node with a checkbox's checked property changes\r
             * @param {Node} this This node\r
             * @param {Boolean} checked\r
             */\r
-            "checkchange",\r
+            'checkchange',\r
+            /**\r
+            * @event beforedblclick\r
+            * Fires before double click processing on a node. Return false to cancel the default action.\r
+            * @param {Node} node The node\r
+            * @param {Ext.EventObject} e The event object\r
+            */\r
+            'beforedblclick',\r
             /**\r
             * @event dblclick\r
             * Fires when a node is double clicked\r
             * @param {Node} node The node\r
             * @param {Ext.EventObject} e The event object\r
             */\r
-            "dblclick",\r
+            'dblclick',\r
+            /**\r
+            * @event containerdblclick\r
+            * Fires when the tree container is double clicked\r
+            * @param {Tree} this\r
+            * @param {Ext.EventObject} e The event object\r
+            */\r
+            'containerdblclick',\r
             /**\r
             * @event contextmenu\r
             * Fires when a node is right clicked. To display a context menu in response to this\r
@@ -361,13 +390,20 @@ new Ext.tree.TreePanel({
             * @param {Node} node The node\r
             * @param {Ext.EventObject} e The event object\r
             */\r
-            "contextmenu",\r
+            'contextmenu',\r
+            /**\r
+            * @event containercontextmenu\r
+            * Fires when the tree container is right clicked\r
+            * @param {Tree} this\r
+            * @param {Ext.EventObject} e The event object\r
+            */\r
+            'containercontextmenu',\r
             /**\r
             * @event beforechildrenrendered\r
             * Fires right before the child nodes for a node are rendered\r
             * @param {Node} node The node\r
             */\r
-            "beforechildrenrendered",\r
+            'beforechildrenrendered',\r
            /**\r
              * @event startdrag\r
              * Fires when a node starts being dragged\r
@@ -375,7 +411,7 @@ new Ext.tree.TreePanel({
              * @param {Ext.tree.TreeNode} node\r
              * @param {event} e The raw browser event\r
              */\r
-            "startdrag",\r
+            'startdrag',\r
             /**\r
              * @event enddrag\r
              * Fires when a drag operation is complete\r
@@ -383,7 +419,7 @@ new Ext.tree.TreePanel({
              * @param {Ext.tree.TreeNode} node\r
              * @param {event} e The raw browser event\r
              */\r
-            "enddrag",\r
+            'enddrag',\r
             /**\r
              * @event dragdrop\r
              * Fires when a dragged node is dropped on a valid DD target\r
@@ -392,7 +428,7 @@ new Ext.tree.TreePanel({
              * @param {DD} dd The dd it was dropped on\r
              * @param {event} e The raw browser event\r
              */\r
-            "dragdrop",\r
+            'dragdrop',\r
             /**\r
              * @event beforenodedrop\r
              * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent\r
@@ -408,11 +444,11 @@ new Ext.tree.TreePanel({
              * to be inserted by setting them on this object.</li>\r
              * <li>cancel - Set this to true to cancel the drop.</li>\r
              * <li>dropStatus - If the default drop action is cancelled but the drop is valid, setting this to true\r
-             * will prevent the animated "repair" from appearing.</li>\r
+             * will prevent the animated 'repair' from appearing.</li>\r
              * </ul>\r
              * @param {Object} dropEvent\r
              */\r
-            "beforenodedrop",\r
+            'beforenodedrop',\r
             /**\r
              * @event nodedrop\r
              * Fires after a DD object is dropped on a node in this tree. The dropEvent\r
@@ -428,7 +464,7 @@ new Ext.tree.TreePanel({
              * </ul>\r
              * @param {Object} dropEvent\r
              */\r
-            "nodedrop",\r
+            'nodedrop',\r
              /**\r
              * @event nodedragover\r
              * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent\r
@@ -445,10 +481,10 @@ new Ext.tree.TreePanel({
              * </ul>\r
              * @param {Object} dragOverEvent\r
              */\r
-            "nodedragover"\r
+            'nodedragover'\r
         );\r
         if(this.singleExpand){\r
-            this.on("beforeexpandnode", this.restrictExpand, this);\r
+            this.on('beforeexpandnode', this.restrictExpand, this);\r
         }\r
     },\r
 \r
@@ -489,12 +525,24 @@ new Ext.tree.TreePanel({
             var uiP = node.attributes.uiProvider;\r
             node.ui = uiP ? new uiP(node) : new Ext.tree.RootTreeNodeUI(node);\r
         }\r
-        if (this.innerCt) {\r
-            this.innerCt.update('');\r
-            this.afterRender();\r
+        if(this.innerCt){\r
+            this.clearInnerCt();\r
+            this.renderRoot();\r
         }\r
         return node;\r
     },\r
+    \r
+    clearInnerCt : function(){\r
+        this.innerCt.update('');    \r
+    },\r
+    \r
+    // private\r
+    renderRoot : function(){\r
+        this.root.render();\r
+        if(!this.rootVisible){\r
+            this.root.renderChildren();\r
+        }\r
+    },\r
 \r
     /**\r
      * Gets a node in this tree by its id\r
@@ -517,7 +565,7 @@ new Ext.tree.TreePanel({
 \r
     // private\r
     toString : function(){\r
-        return "[Tree"+(this.id?" "+this.id:"")+"]";\r
+        return '[Tree'+(this.id?' '+this.id:'')+']';\r
     },\r
 \r
     // private\r
@@ -532,7 +580,7 @@ new Ext.tree.TreePanel({
     },\r
 \r
     /**\r
-     * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")\r
+     * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. 'id')\r
      * @param {String} attribute (optional) Defaults to null (return the actual nodes)\r
      * @param {TreeNode} startNode (optional) The node to start from, defaults to the root\r
      * @return {Array}\r
@@ -549,14 +597,6 @@ new Ext.tree.TreePanel({
         return r;\r
     },\r
 \r
-    /**\r
-     * Returns the container element for this TreePanel.\r
-     * @return {Element} The container element for this TreePanel.\r
-     */\r
-    getEl : function(){\r
-        return this.el;\r
-    },\r
-\r
     /**\r
      * Returns the default {@link Ext.tree.TreeLoader} for this TreePanel.\r
      * @return {Ext.tree.TreeLoader} The TreeLoader for this TreePanel.\r
@@ -598,7 +638,7 @@ new Ext.tree.TreePanel({
      * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.\r
      */\r
     expandPath : function(path, attr, callback){\r
-        attr = attr || "id";\r
+        attr = attr || 'id';\r
         var keys = path.split(this.pathSeparator);\r
         var curNode = this.root;\r
         if(curNode.attributes[attr] != keys[1]){ // invalid root\r
@@ -636,10 +676,10 @@ new Ext.tree.TreePanel({
      * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.\r
      */\r
     selectPath : function(path, attr, callback){\r
-        attr = attr || "id";\r
-        var keys = path.split(this.pathSeparator);\r
-        var v = keys.pop();\r
-        if(keys.length > 0){\r
+        attr = attr || 'id';\r
+        var keys = path.split(this.pathSeparator),\r
+            v = keys.pop();\r
+        if(keys.length > 1){\r
             var f = function(success, node){\r
                 if(success && node){\r
                     var n = node.findChild(attr, v);\r
@@ -678,9 +718,9 @@ new Ext.tree.TreePanel({
     onRender : function(ct, position){\r
         Ext.tree.TreePanel.superclass.onRender.call(this, ct, position);\r
         this.el.addClass('x-tree');\r
-        this.innerCt = this.body.createChild({tag:"ul",\r
-               cls:"x-tree-root-ct " +\r
-               (this.useArrows ? 'x-tree-arrows' : this.lines ? "x-tree-lines" : "x-tree-no-lines")});\r
+        this.innerCt = this.body.createChild({tag:'ul',\r
+               cls:'x-tree-root-ct ' +\r
+               (this.useArrows ? 'x-tree-arrows' : this.lines ? 'x-tree-lines' : 'x-tree-no-lines')});\r
     },\r
 \r
     // private\r
@@ -697,7 +737,7 @@ new Ext.tree.TreePanel({
             * @type Ext.tree.TreeDropZone\r
             */\r
              this.dropZone = new Ext.tree.TreeDropZone(this, this.dropConfig || {\r
-               ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true\r
+               ddGroup: this.ddGroup || 'TreeDD', appendOnly: this.ddAppendOnly === true\r
            });\r
         }\r
         if((this.enableDD || this.enableDrag) && !this.dragZone){\r
@@ -707,7 +747,7 @@ new Ext.tree.TreePanel({
             * @type Ext.tree.TreeDragZone\r
             */\r
             this.dragZone = new Ext.tree.TreeDragZone(this, this.dragConfig || {\r
-               ddGroup: this.ddGroup || "TreeDD",\r
+               ddGroup: this.ddGroup || 'TreeDD',\r
                scroll: this.ddScroll\r
            });\r
         }\r
@@ -717,26 +757,17 @@ new Ext.tree.TreePanel({
     // private\r
     afterRender : function(){\r
         Ext.tree.TreePanel.superclass.afterRender.call(this);\r
-        this.root.render();\r
-        if(!this.rootVisible){\r
-            this.root.renderChildren();\r
-        }\r
+        this.renderRoot();\r
     },\r
 \r
-    onDestroy : function(){\r
+    beforeDestroy : function(){\r
         if(this.rendered){\r
-            this.body.removeAllListeners();\r
             Ext.dd.ScrollManager.unregister(this.body);\r
-            if(this.dropZone){\r
-                this.dropZone.unreg();\r
-            }\r
-            if(this.dragZone){\r
-               this.dragZone.unreg();\r
-            }\r
+            Ext.destroy(this.dropZone, this.dragZone);\r
         }\r
-        this.root.destroy();\r
-        this.nodeHash = null;\r
-        Ext.tree.TreePanel.superclass.onDestroy.call(this);\r
+        Ext.destroy(this.root, this.loader);\r
+        this.nodeHash = this.root = this.loader = null;\r
+        Ext.tree.TreePanel.superclass.beforeDestroy.call(this);\r
     }\r
 \r
     /**\r
@@ -878,6 +909,15 @@ new Ext.tree.TreePanel({
     /**\r
      * @cfg {String} contentEl  @hide\r
      */\r
+    /**\r
+     * @cfg {Mixed} data  @hide\r
+     */\r
+    /**\r
+     * @cfg {Mixed} tpl  @hide\r
+     */\r
+    /**\r
+     * @cfg {String} tplWriteMode  @hide\r
+     */\r
     /**\r
      * @cfg {String} disabledClass  @hide\r
      */\r
@@ -922,14 +962,21 @@ Ext.reg('treepanel', Ext.tree.TreePanel);Ext.tree.TreeEventModel = function(tree
 \r
 Ext.tree.TreeEventModel.prototype = {\r
     initEvents : function(){\r
-        var el = this.tree.getTreeEl();\r
-        el.on('click', this.delegateClick, this);\r
-        if(this.tree.trackMouseOver !== false){\r
-            this.tree.innerCt.on('mouseover', this.delegateOver, this);\r
-            this.tree.innerCt.on('mouseout', this.delegateOut, this);\r
+        var t = this.tree;\r
+\r
+        if(t.trackMouseOver !== false){\r
+            t.mon(t.innerCt, {\r
+                scope: this,\r
+                mouseover: this.delegateOver,\r
+                mouseout: this.delegateOut\r
+            });\r
         }\r
-        el.on('dblclick', this.delegateDblClick, this);\r
-        el.on('contextmenu', this.delegateContextMenu, this);\r
+        t.mon(t.getTreeEl(), {\r
+            scope: this,\r
+            click: this.delegateClick,\r
+            dblclick: this.delegateDblClick,\r
+            contextmenu: this.delegateContextMenu\r
+        });\r
     },\r
 \r
     getNode : function(e){\r
@@ -989,42 +1036,55 @@ Ext.tree.TreeEventModel.prototype = {
     },\r
 \r
     trackExit : function(e){\r
-        if(this.lastOverNode && !e.within(this.lastOverNode.ui.getEl())){\r
-            this.onNodeOut(e, this.lastOverNode);\r
+        if(this.lastOverNode){\r
+            if(this.lastOverNode.ui && !e.within(this.lastOverNode.ui.getEl())){\r
+                this.onNodeOut(e, this.lastOverNode);\r
+            }\r
             delete this.lastOverNode;\r
             Ext.getBody().un('mouseover', this.trackExit, this);\r
             this.trackingDoc = false;\r
         }\r
+\r
     },\r
 \r
     delegateClick : function(e, t){\r
-        if(!this.beforeEvent(e)){\r
-            return;\r
-        }\r
-\r
-        if(e.getTarget('input[type=checkbox]', 1)){\r
-            this.onCheckboxClick(e, this.getNode(e));\r
-        }\r
-        else if(e.getTarget('.x-tree-ec-icon', 1)){\r
-            this.onIconClick(e, this.getNode(e));\r
-        }\r
-        else if(this.getNodeTarget(e)){\r
-            this.onNodeClick(e, this.getNode(e));\r
+        if(this.beforeEvent(e)){\r
+            if(e.getTarget('input[type=checkbox]', 1)){\r
+                this.onCheckboxClick(e, this.getNode(e));\r
+            }else if(e.getTarget('.x-tree-ec-icon', 1)){\r
+                this.onIconClick(e, this.getNode(e));\r
+            }else if(this.getNodeTarget(e)){\r
+                this.onNodeClick(e, this.getNode(e));\r
+            }else{\r
+                this.onContainerEvent(e, 'click');\r
+            }\r
         }\r
     },\r
 \r
     delegateDblClick : function(e, t){\r
-        if(this.beforeEvent(e) && this.getNodeTarget(e)){\r
-            this.onNodeDblClick(e, this.getNode(e));\r
+        if(this.beforeEvent(e)){\r
+            if(this.getNodeTarget(e)){\r
+                this.onNodeDblClick(e, this.getNode(e));\r
+            }else{\r
+                this.onContainerEvent(e, 'dblclick');\r
+            }\r
         }\r
     },\r
 \r
     delegateContextMenu : function(e, t){\r
-        if(this.beforeEvent(e) && this.getNodeTarget(e)){\r
-            this.onNodeContextMenu(e, this.getNode(e));\r
+        if(this.beforeEvent(e)){\r
+            if(this.getNodeTarget(e)){\r
+                this.onNodeContextMenu(e, this.getNode(e));\r
+            }else{\r
+                this.onContainerEvent(e, 'contextmenu');\r
+            }\r
         }\r
     },\r
 \r
+    onContainerEvent: function(e, type){\r
+        this.tree.fireEvent('container' + type, this.tree, e);\r
+    },\r
+\r
     onNodeClick : function(e, node){\r
         node.ui.onClick(e);\r
     },\r
@@ -1063,7 +1123,8 @@ Ext.tree.TreeEventModel.prototype = {
     },\r
 \r
     beforeEvent : function(e){\r
-        if(this.disabled){\r
+        var node = this.getNode(e);\r
+        if(this.disabled || !node || !node.ui){\r
             e.stopEvent();\r
             return false;\r
         }\r
@@ -1092,7 +1153,7 @@ Ext.tree.DefaultSelectionModel = function(config){
         * @param {DefaultSelectionModel} this\r
         * @param {TreeNode} node the new selection\r
         */\r
-       "selectionchange",\r
+       'selectionchange',\r
 \r
        /**\r
         * @event beforeselect\r
@@ -1101,7 +1162,7 @@ Ext.tree.DefaultSelectionModel = function(config){
         * @param {TreeNode} node the new selection\r
         * @param {TreeNode} node the old selection\r
         */\r
-       "beforeselect"\r
+       'beforeselect'\r
    );\r
 \r
     Ext.apply(this, config);\r
@@ -1111,8 +1172,8 @@ Ext.tree.DefaultSelectionModel = function(config){
 Ext.extend(Ext.tree.DefaultSelectionModel, Ext.util.Observable, {\r
     init : function(tree){\r
         this.tree = tree;\r
-        tree.getTreeEl().on("keydown", this.onKeyDown, this);\r
-        tree.on("click", this.onNodeClick, this);\r
+        tree.mon(tree.getTreeEl(), 'keydown', this.onKeyDown, this);\r
+        tree.on('click', this.onNodeClick, this);\r
     },\r
     \r
     onNodeClick : function(node, e){\r
@@ -1124,17 +1185,21 @@ Ext.extend(Ext.tree.DefaultSelectionModel, Ext.util.Observable, {
      * @param {TreeNode} node The node to select\r
      * @return {TreeNode} The selected node\r
      */\r
-    select : function(node){\r
+    select : function(node, /* private*/ selectNextNode){\r
+        // If node is hidden, select the next node in whatever direction was being moved in.\r
+        if (!Ext.fly(node.ui.wrap).isVisible() && selectNextNode) {\r
+            return selectNextNode.call(this, node);\r
+        }\r
         var last = this.selNode;\r
         if(node == last){\r
             node.ui.onSelectedChange(true);\r
         }else if(this.fireEvent('beforeselect', this, node, last) !== false){\r
-            if(last){\r
+            if(last && last.ui){\r
                 last.ui.onSelectedChange(false);\r
             }\r
             this.selNode = node;\r
             node.ui.onSelectedChange(true);\r
-            this.fireEvent("selectionchange", this, node, last);\r
+            this.fireEvent('selectionchange', this, node, last);\r
         }\r
         return node;\r
     },\r
@@ -1142,22 +1207,26 @@ Ext.extend(Ext.tree.DefaultSelectionModel, Ext.util.Observable, {
     /**\r
      * Deselect a node.\r
      * @param {TreeNode} node The node to unselect\r
+     * @param {Boolean} silent True to stop the selectionchange event from firing.\r
      */\r
-    unselect : function(node){\r
+    unselect : function(node, silent){\r
         if(this.selNode == node){\r
-            this.clearSelections();\r
+            this.clearSelections(silent);\r
         }    \r
     },\r
     \r
     /**\r
      * Clear all selections\r
+     * @param {Boolean} silent True to stop the selectionchange event from firing.\r
      */\r
-    clearSelections : function(){\r
+    clearSelections : function(silent){\r
         var n = this.selNode;\r
         if(n){\r
             n.ui.onSelectedChange(false);\r
             this.selNode = null;\r
-            this.fireEvent("selectionchange", this, null);\r
+            if(silent !== true){\r
+                this.fireEvent('selectionchange', this, null);\r
+            }\r
         }\r
         return n;\r
     },\r
@@ -1183,24 +1252,24 @@ Ext.extend(Ext.tree.DefaultSelectionModel, Ext.util.Observable, {
      * Selects the node above the selected node in the tree, intelligently walking the nodes\r
      * @return TreeNode The new selection\r
      */\r
-    selectPrevious : function(){\r
-        var s = this.selNode || this.lastSelNode;\r
-        if(!s){\r
+    selectPrevious : function(/* private */ s){\r
+        if(!(s = s || this.selNode || this.lastSelNode)){\r
             return null;\r
         }\r
+        // Here we pass in the current function to select to indicate the direction we're moving\r
         var ps = s.previousSibling;\r
         if(ps){\r
             if(!ps.isExpanded() || ps.childNodes.length < 1){\r
-                return this.select(ps);\r
+                return this.select(ps, this.selectPrevious);\r
             } else{\r
                 var lc = ps.lastChild;\r
-                while(lc && lc.isExpanded() && lc.childNodes.length > 0){\r
+                while(lc && lc.isExpanded() && Ext.fly(lc.ui.wrap).isVisible() && lc.childNodes.length > 0){\r
                     lc = lc.lastChild;\r
                 }\r
-                return this.select(lc);\r
+                return this.select(lc, this.selectPrevious);\r
             }\r
         } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){\r
-            return this.select(s.parentNode);\r
+            return this.select(s.parentNode, this.selectPrevious);\r
         }\r
         return null;\r
     },\r
@@ -1209,20 +1278,20 @@ Ext.extend(Ext.tree.DefaultSelectionModel, Ext.util.Observable, {
      * Selects the node above the selected node in the tree, intelligently walking the nodes\r
      * @return TreeNode The new selection\r
      */\r
-    selectNext : function(){\r
-        var s = this.selNode || this.lastSelNode;\r
-        if(!s){\r
+    selectNext : function(/* private */ s){\r
+        if(!(s = s || this.selNode || this.lastSelNode)){\r
             return null;\r
         }\r
-        if(s.firstChild && s.isExpanded()){\r
-             return this.select(s.firstChild);\r
+        // Here we pass in the current function to select to indicate the direction we're moving\r
+        if(s.firstChild && s.isExpanded() && Ext.fly(s.ui.wrap).isVisible()){\r
+             return this.select(s.firstChild, this.selectNext);\r
          }else if(s.nextSibling){\r
-             return this.select(s.nextSibling);\r
+             return this.select(s.nextSibling, this.selectNext);\r
          }else if(s.parentNode){\r
             var newS = null;\r
             s.parentNode.bubble(function(){\r
                 if(this.nextSibling){\r
-                    newS = this.getOwnerTree().selModel.select(this.nextSibling);\r
+                    newS = this.getOwnerTree().selModel.select(this.nextSibling, this.selectNext);\r
                     return false;\r
                 }\r
             });\r
@@ -1285,7 +1354,7 @@ Ext.tree.MultiSelectionModel = function(config){
         * @param {MultiSelectionModel} this\r
         * @param {Array} nodes Array of the selected nodes\r
         */\r
-       "selectionchange"\r
+       'selectionchange'\r
    );\r
     Ext.apply(this, config);\r
     Ext.tree.MultiSelectionModel.superclass.constructor.call(this);\r
@@ -1294,8 +1363,8 @@ Ext.tree.MultiSelectionModel = function(config){
 Ext.extend(Ext.tree.MultiSelectionModel, Ext.util.Observable, {\r
     init : function(tree){\r
         this.tree = tree;\r
-        tree.getTreeEl().on("keydown", this.onKeyDown, this);\r
-        tree.on("click", this.onNodeClick, this);\r
+        tree.mon(tree.getTreeEl(), 'keydown', this.onKeyDown, this);\r
+        tree.on('click', this.onNodeClick, this);\r
     },\r
     \r
     onNodeClick : function(node, e){\r
@@ -1325,7 +1394,7 @@ Ext.extend(Ext.tree.MultiSelectionModel, Ext.util.Observable, {
         this.selMap[node.id] = node;\r
         this.lastSelNode = node;\r
         node.ui.onSelectedChange(true);\r
-        this.fireEvent("selectionchange", this, this.selNodes);\r
+        this.fireEvent('selectionchange', this, this.selNodes);\r
         return node;\r
     },\r
     \r
@@ -1342,7 +1411,7 @@ Ext.extend(Ext.tree.MultiSelectionModel, Ext.util.Observable, {
                 this.selNodes.splice(index, 1);\r
             }\r
             delete this.selMap[node.id];\r
-            this.fireEvent("selectionchange", this, this.selNodes);\r
+            this.fireEvent('selectionchange', this, this.selNodes);\r
         }\r
     },\r
     \r
@@ -1358,7 +1427,7 @@ Ext.extend(Ext.tree.MultiSelectionModel, Ext.util.Observable, {
             this.selNodes = [];\r
             this.selMap = {};\r
             if(suppressEvent !== true){\r
-                this.fireEvent("selectionchange", this, this.selNodes);\r
+                this.fireEvent('selectionchange', this, this.selNodes);\r
             }\r
         }\r
     },\r
@@ -1798,9 +1867,10 @@ Ext.extend(Ext.data.Node, Ext.util.Observable, {
     /**\r
      * Removes a child node from this node.\r
      * @param {Node} node The node to remove\r
+     * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.\r
      * @return {Node} The removed node\r
      */\r
-    removeChild : function(node){\r
+    removeChild : function(node, destroy){\r
         var index = this.childNodes.indexOf(node);\r
         if(index == -1){\r
             return false;\r
@@ -1828,14 +1898,35 @@ Ext.extend(Ext.data.Node, Ext.util.Observable, {
             this.setLastChild(node.previousSibling);\r
         }\r
 \r
-        node.setOwnerTree(null);\r
-        // clear any references from the node\r
-        node.parentNode = null;\r
-        node.previousSibling = null;\r
-        node.nextSibling = null;\r
+        node.clear();\r
         this.fireEvent("remove", this.ownerTree, this, node);\r
+        if(destroy){\r
+            node.destroy();\r
+        }\r
         return node;\r
     },\r
+    \r
+    // private\r
+    clear : function(destroy){\r
+        // clear any references from the node\r
+        this.setOwnerTree(null, destroy);\r
+        this.parentNode = this.previousSibling = this.nextSibling = null\r
+        if(destroy){\r
+            this.firstChild = this.lastChild = null; \r
+        }\r
+    },\r
+    \r
+    /**\r
+     * Destroys the node.\r
+     */\r
+    destroy : function(){\r
+        this.purgeListeners();\r
+        this.clear(true);  \r
+        Ext.each(this.childNodes, function(n){\r
+            n.destroy();\r
+        });\r
+        this.childNodes = null;\r
+    },\r
 \r
     /**\r
      * Inserts the first node before the second node in this nodes childNodes collection.\r
@@ -1895,10 +1986,25 @@ Ext.extend(Ext.data.Node, Ext.util.Observable, {
 \r
     /**\r
      * Removes this node from its parent\r
+     * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.\r
      * @return {Node} this\r
      */\r
-    remove : function(){\r
-        this.parentNode.removeChild(this);\r
+    remove : function(destroy){\r
+        this.parentNode.removeChild(this, destroy);\r
+        return this;\r
+    },\r
+    \r
+    /**\r
+     * Removes all child nodes from this node.\r
+     * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.\r
+     * @return {Node} this\r
+     */\r
+    removeAll : function(destroy){\r
+        var cn = this.childNodes,\r
+            n;\r
+        while((n = cn[0])){\r
+            this.removeChild(n, destroy);\r
+        }\r
         return this;\r
     },\r
 \r
@@ -1967,16 +2073,18 @@ Ext.extend(Ext.data.Node, Ext.util.Observable, {
     },\r
 \r
     // private\r
-    setOwnerTree : function(tree){\r
+    setOwnerTree : function(tree, destroy){\r
         // if it is a move, we need to update everyone\r
         if(tree != this.ownerTree){\r
             if(this.ownerTree){\r
                 this.ownerTree.unregisterNode(this);\r
             }\r
             this.ownerTree = tree;\r
-            var cs = this.childNodes;\r
-            for(var i = 0, len = cs.length; i < len; i++) {\r
-               cs[i].setOwnerTree(tree);\r
+            // If we're destroying, we don't need to recurse since it will be called on each child node\r
+            if(destroy !== true){\r
+                Ext.each(this.childNodes, function(n){\r
+                    n.setOwnerTree(tree);\r
+                });\r
             }\r
             if(tree){\r
                 tree.registerNode(this);\r
@@ -1994,7 +2102,7 @@ Ext.extend(Ext.data.Node, Ext.util.Observable, {
             if(t){\r
                 t.unregisterNode(this);\r
             }\r
-            this.id = id;\r
+            this.id = this.attributes.id = id;\r
             if(t){\r
                 t.registerNode(this);\r
             }\r
@@ -2023,13 +2131,12 @@ Ext.extend(Ext.data.Node, Ext.util.Observable, {
     },\r
 \r
     /**\r
-     * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of\r
-     * function call will be the scope provided or the current node. The arguments to the function\r
+     * Bubbles up the tree from this node, calling the specified function with each node. The arguments to the function\r
      * will be the args provided or the current node. If the function returns false at any point,\r
      * the bubble is stopped.\r
      * @param {Function} fn The function to call\r
-     * @param {Object} scope (optional) The scope of the function (defaults to current node)\r
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)\r
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node.\r
+     * @param {Array} args (optional) The args to call the function with (default to passing the current Node)\r
      */\r
     bubble : function(fn, scope, args){\r
         var p = this;\r
@@ -2042,13 +2149,12 @@ Ext.extend(Ext.data.Node, Ext.util.Observable, {
     },\r
 \r
     /**\r
-     * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of\r
-     * function call will be the scope provided or the current node. The arguments to the function\r
+     * Cascades down the tree from this node, calling the specified function with each node. The arguments to the function\r
      * will be the args provided or the current node. If the function returns false at any point,\r
      * the cascade is stopped on that branch.\r
      * @param {Function} fn The function to call\r
-     * @param {Object} scope (optional) The scope of the function (defaults to current node)\r
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)\r
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node.\r
+     * @param {Array} args (optional) The args to call the function with (default to passing the current Node)\r
      */\r
     cascade : function(fn, scope, args){\r
         if(fn.apply(scope || this, args || [this]) !== false){\r
@@ -2060,13 +2166,12 @@ Ext.extend(Ext.data.Node, Ext.util.Observable, {
     },\r
 \r
     /**\r
-     * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of\r
-     * function call will be the scope provided or the current node. The arguments to the function\r
+     * Interates the child nodes of this node, calling the specified function with each node. The arguments to the function\r
      * will be the args provided or the current node. If the function returns false at any point,\r
      * the iteration stops.\r
      * @param {Function} fn The function to call\r
-     * @param {Object} scope (optional) The scope of the function (defaults to current node)\r
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)\r
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node in the iteration.\r
+     * @param {Array} args (optional) The args to call the function with (default to passing the current Node)\r
      */\r
     eachChild : function(fn, scope, args){\r
         var cs = this.childNodes;\r
@@ -2094,10 +2199,9 @@ Ext.extend(Ext.data.Node, Ext.util.Observable, {
     },\r
 \r
     /**\r
-     * Finds the first child by a custom function. The child matches if the function passed\r
-     * returns true.\r
-     * @param {Function} fn\r
-     * @param {Object} scope (optional)\r
+     * Finds the first child by a custom function. The child matches if the function passed returns <code>true</code>.\r
+     * @param {Function} fn A function which must return <code>true</code> if the passed Node is the required Node.\r
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Node being tested.\r
      * @return {Node} The found child or null if none was found\r
      */\r
     findChildBy : function(fn, scope){\r
@@ -2111,9 +2215,9 @@ Ext.extend(Ext.data.Node, Ext.util.Observable, {
     },\r
 \r
     /**\r
-     * Sorts this nodes children using the supplied sort function\r
-     * @param {Function} fn\r
-     * @param {Object} scope (optional)\r
+     * Sorts this nodes children using the supplied sort function.\r
+     * @param {Function} fn A function which, when passed two Nodes, returns -1, 0 or 1 depending upon required sort order.\r
+     * @param {Object} scope (optional)The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.\r
      */\r
     sort : function(fn, scope){\r
         var cs = this.childNodes;\r
@@ -2163,545 +2267,571 @@ Ext.extend(Ext.data.Node, Ext.util.Observable, {
     toString : function(){\r
         return "[Node"+(this.id?" "+this.id:"")+"]";\r
     }\r
-});/**\r
- * @class Ext.tree.TreeNode\r
- * @extends Ext.data.Node\r
- * @cfg {String} text The text for this node\r
- * @cfg {Boolean} expanded true to start the node expanded\r
- * @cfg {Boolean} allowDrag False to make this node undraggable if {@link #draggable} = true (defaults to true)\r
- * @cfg {Boolean} allowDrop False if this node cannot have child nodes dropped on it (defaults to true)\r
- * @cfg {Boolean} disabled true to start the node disabled\r
- * @cfg {String} icon The path to an icon for the node. The preferred way to do this\r
- * is to use the cls or iconCls attributes and add the icon via a CSS background image.\r
- * @cfg {String} cls A css class to be added to the node\r
- * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images\r
- * @cfg {String} href URL of the link used for the node (defaults to #)\r
- * @cfg {String} hrefTarget target frame for the link\r
- * @cfg {Boolean} hidden True to render hidden. (Defaults to false).\r
- * @cfg {String} qtip An Ext QuickTip for the node\r
- * @cfg {Boolean} expandable If set to true, the node will always show a plus/minus icon, even when empty\r
- * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)\r
- * @cfg {Boolean} singleClickExpand True for single click expand on this node\r
- * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Ext.tree.TreeNodeUI)\r
- * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox\r
- * (defaults to undefined with no checkbox rendered)\r
- * @cfg {Boolean} draggable True to make this node draggable (defaults to false)\r
- * @cfg {Boolean} isTarget False to not allow this node to act as a drop target (defaults to true)\r
- * @cfg {Boolean} allowChildren False to not allow this node to have child nodes (defaults to true)\r
- * @cfg {Boolean} editable False to not allow this node to be edited by an (@link Ext.tree.TreeEditor} (defaults to true)\r
- * @constructor\r
- * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node\r
- */\r
-Ext.tree.TreeNode = function(attributes){\r
-    attributes = attributes || {};\r
-    if(typeof attributes == "string"){\r
-        attributes = {text: attributes};\r
-    }\r
-    this.childrenRendered = false;\r
-    this.rendered = false;\r
-    Ext.tree.TreeNode.superclass.constructor.call(this, attributes);\r
-    this.expanded = attributes.expanded === true;\r
-    this.isTarget = attributes.isTarget !== false;\r
-    this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;\r
-    this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;\r
-\r
-    /**\r
-     * Read-only. The text for this node. To change it use setText().\r
-     * @type String\r
-     */\r
-    this.text = attributes.text;\r
-    /**\r
-     * True if this node is disabled.\r
-     * @type Boolean\r
-     */\r
-    this.disabled = attributes.disabled === true;\r
-    /**\r
-     * True if this node is hidden.\r
-     * @type Boolean\r
-     */\r
-    this.hidden = attributes.hidden === true;\r
-\r
-    this.addEvents(\r
-        /**\r
-        * @event textchange\r
-        * Fires when the text for this node is changed\r
-        * @param {Node} this This node\r
-        * @param {String} text The new text\r
-        * @param {String} oldText The old text\r
-        */\r
-        "textchange",\r
-        /**\r
-        * @event beforeexpand\r
-        * Fires before this node is expanded, return false to cancel.\r
-        * @param {Node} this This node\r
-        * @param {Boolean} deep\r
-        * @param {Boolean} anim\r
-        */\r
-        "beforeexpand",\r
-        /**\r
-        * @event beforecollapse\r
-        * Fires before this node is collapsed, return false to cancel.\r
-        * @param {Node} this This node\r
-        * @param {Boolean} deep\r
-        * @param {Boolean} anim\r
-        */\r
-        "beforecollapse",\r
-        /**\r
-        * @event expand\r
-        * Fires when this node is expanded\r
-        * @param {Node} this This node\r
-        */\r
-        "expand",\r
-        /**\r
-        * @event disabledchange\r
-        * Fires when the disabled status of this node changes\r
-        * @param {Node} this This node\r
-        * @param {Boolean} disabled\r
-        */\r
-        "disabledchange",\r
-        /**\r
-        * @event collapse\r
-        * Fires when this node is collapsed\r
-        * @param {Node} this This node\r
-        */\r
-        "collapse",\r
-        /**\r
-        * @event beforeclick\r
-        * Fires before click processing. Return false to cancel the default action.\r
-        * @param {Node} this This node\r
-        * @param {Ext.EventObject} e The event object\r
-        */\r
-        "beforeclick",\r
-        /**\r
-        * @event click\r
-        * Fires when this node is clicked\r
-        * @param {Node} this This node\r
-        * @param {Ext.EventObject} e The event object\r
-        */\r
-        "click",\r
-        /**\r
-        * @event checkchange\r
-        * Fires when a node with a checkbox's checked property changes\r
-        * @param {Node} this This node\r
-        * @param {Boolean} checked\r
-        */\r
-        "checkchange",\r
-        /**\r
-        * @event dblclick\r
-        * Fires when this node is double clicked\r
-        * @param {Node} this This node\r
-        * @param {Ext.EventObject} e The event object\r
-        */\r
-        "dblclick",\r
-        /**\r
-        * @event contextmenu\r
-        * Fires when this node is right clicked\r
-        * @param {Node} this This node\r
-        * @param {Ext.EventObject} e The event object\r
-        */\r
-        "contextmenu",\r
-        /**\r
-        * @event beforechildrenrendered\r
-        * Fires right before the child nodes for this node are rendered\r
-        * @param {Node} this This node\r
-        */\r
-        "beforechildrenrendered"\r
-    );\r
-\r
-    var uiClass = this.attributes.uiProvider || this.defaultUI || Ext.tree.TreeNodeUI;\r
-\r
-    /**\r
-     * Read-only. The UI for this node\r
-     * @type TreeNodeUI\r
-     */\r
-    this.ui = new uiClass(this);\r
-};\r
-Ext.extend(Ext.tree.TreeNode, Ext.data.Node, {\r
-    preventHScroll: true,\r
-    /**\r
-     * Returns true if this node is expanded\r
-     * @return {Boolean}\r
-     */\r
-    isExpanded : function(){\r
-        return this.expanded;\r
-    },\r
-\r
-/**\r
- * Returns the UI object for this node.\r
- * @return {TreeNodeUI} The object which is providing the user interface for this tree\r
- * node. Unless otherwise specified in the {@link #uiProvider}, this will be an instance\r
- * of {@link Ext.tree.TreeNodeUI}\r
- */\r
-    getUI : function(){\r
-        return this.ui;\r
-    },\r
-\r
-    getLoader : function(){\r
-        var owner;\r
-        return this.loader || ((owner = this.getOwnerTree()) && owner.loader ? owner.loader : new Ext.tree.TreeLoader());\r
-    },\r
-\r
-    // private override\r
-    setFirstChild : function(node){\r
-        var of = this.firstChild;\r
-        Ext.tree.TreeNode.superclass.setFirstChild.call(this, node);\r
-        if(this.childrenRendered && of && node != of){\r
-            of.renderIndent(true, true);\r
-        }\r
-        if(this.rendered){\r
-            this.renderIndent(true, true);\r
-        }\r
-    },\r
-\r
-    // private override\r
-    setLastChild : function(node){\r
-        var ol = this.lastChild;\r
-        Ext.tree.TreeNode.superclass.setLastChild.call(this, node);\r
-        if(this.childrenRendered && ol && node != ol){\r
-            ol.renderIndent(true, true);\r
-        }\r
-        if(this.rendered){\r
-            this.renderIndent(true, true);\r
-        }\r
-    },\r
-\r
-    // these methods are overridden to provide lazy rendering support\r
-    // private override\r
-    appendChild : function(n){\r
-        if(!n.render && !Ext.isArray(n)){\r
-            n = this.getLoader().createNode(n);\r
-        }\r
-        var node = Ext.tree.TreeNode.superclass.appendChild.call(this, n);\r
-        if(node && this.childrenRendered){\r
-            node.render();\r
-        }\r
-        this.ui.updateExpandIcon();\r
-        return node;\r
-    },\r
-\r
-    // private override\r
-    removeChild : function(node){\r
-        this.ownerTree.getSelectionModel().unselect(node);\r
-        Ext.tree.TreeNode.superclass.removeChild.apply(this, arguments);\r
-        // if it's been rendered remove dom node\r
-        if(this.childrenRendered){\r
-            node.ui.remove();\r
-        }\r
-        if(this.childNodes.length < 1){\r
-            this.collapse(false, false);\r
-        }else{\r
-            this.ui.updateExpandIcon();\r
-        }\r
-        if(!this.firstChild && !this.isHiddenRoot()) {\r
-            this.childrenRendered = false;\r
-        }\r
-        return node;\r
-    },\r
-\r
-    // private override\r
-    insertBefore : function(node, refNode){\r
-        if(!node.render){ \r
-            node = this.getLoader().createNode(node);\r
-        }\r
-        var newNode = Ext.tree.TreeNode.superclass.insertBefore.call(this, node, refNode);\r
-        if(newNode && refNode && this.childrenRendered){\r
-            node.render();\r
-        }\r
-        this.ui.updateExpandIcon();\r
-        return newNode;\r
-    },\r
-\r
-    /**\r
-     * Sets the text for this node\r
-     * @param {String} text\r
-     */\r
-    setText : function(text){\r
-        var oldText = this.text;\r
-        this.text = text;\r
-        this.attributes.text = text;\r
-        if(this.rendered){ // event without subscribing\r
-            this.ui.onTextChange(this, text, oldText);\r
-        }\r
-        this.fireEvent("textchange", this, text, oldText);\r
-    },\r
-\r
-    /**\r
-     * Triggers selection of this node\r
-     */\r
-    select : function(){\r
-        this.getOwnerTree().getSelectionModel().select(this);\r
-    },\r
-\r
-    /**\r
-     * Triggers deselection of this node\r
-     */\r
-    unselect : function(){\r
-        this.getOwnerTree().getSelectionModel().unselect(this);\r
-    },\r
-\r
-    /**\r
-     * Returns true if this node is selected\r
-     * @return {Boolean}\r
-     */\r
-    isSelected : function(){\r
-        return this.getOwnerTree().getSelectionModel().isSelected(this);\r
-    },\r
-\r
-    /**\r
-     * Expand this node.\r
-     * @param {Boolean} deep (optional) True to expand all children as well\r
-     * @param {Boolean} anim (optional) false to cancel the default animation\r
-     * @param {Function} callback (optional) A callback to be called when\r
-     * expanding this node completes (does not wait for deep expand to complete).\r
-     * Called with 1 parameter, this node.\r
-     * @param {Object} scope (optional) The scope in which to execute the callback.\r
-     */\r
-    expand : function(deep, anim, callback, scope){\r
-        if(!this.expanded){\r
-            if(this.fireEvent("beforeexpand", this, deep, anim) === false){\r
-                return;\r
-            }\r
-            if(!this.childrenRendered){\r
-                this.renderChildren();\r
-            }\r
-            this.expanded = true;\r
-            if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){\r
-                this.ui.animExpand(function(){\r
-                    this.fireEvent("expand", this);\r
-                    this.runCallback(callback, scope || this, [this]);\r
-                    if(deep === true){\r
-                        this.expandChildNodes(true);\r
-                    }\r
-                }.createDelegate(this));\r
-                return;\r
-            }else{\r
-                this.ui.expand();\r
-                this.fireEvent("expand", this);\r
-                this.runCallback(callback, scope || this, [this]);\r
-            }\r
-        }else{\r
-           this.runCallback(callback, scope || this, [this]);\r
-        }\r
-        if(deep === true){\r
-            this.expandChildNodes(true);\r
-        }\r
-    },\r
-    \r
-    runCallback: function(cb, scope, args){\r
-        if(Ext.isFunction(cb)){\r
-            cb.apply(scope, args);\r
-        }\r
-    },\r
-\r
-    isHiddenRoot : function(){\r
-        return this.isRoot && !this.getOwnerTree().rootVisible;\r
-    },\r
-\r
-    /**\r
-     * Collapse this node.\r
-     * @param {Boolean} deep (optional) True to collapse all children as well\r
-     * @param {Boolean} anim (optional) false to cancel the default animation\r
-     * @param {Function} callback (optional) A callback to be called when\r
-     * expanding this node completes (does not wait for deep expand to complete).\r
-     * Called with 1 parameter, this node.\r
-     * @param {Object} scope (optional) The scope in which to execute the callback.\r
-     */\r
-    collapse : function(deep, anim, callback, scope){\r
-        if(this.expanded && !this.isHiddenRoot()){\r
-            if(this.fireEvent("beforecollapse", this, deep, anim) === false){\r
-                return;\r
-            }\r
-            this.expanded = false;\r
-            if((this.getOwnerTree().animate && anim !== false) || anim){\r
-                this.ui.animCollapse(function(){\r
-                    this.fireEvent("collapse", this);\r
-                    this.runCallback(callback, scope || this, [this]);\r
-                    if(deep === true){\r
-                        this.collapseChildNodes(true);\r
-                    }\r
-                }.createDelegate(this));\r
-                return;\r
-            }else{\r
-                this.ui.collapse();\r
-                this.fireEvent("collapse", this);\r
-                this.runCallback(callback, scope || this, [this]);\r
-            }\r
-        }else if(!this.expanded){\r
-            this.runCallback(callback, scope || this, [this]);\r
-        }\r
-        if(deep === true){\r
-            var cs = this.childNodes;\r
-            for(var i = 0, len = cs.length; i < len; i++) {\r
-               cs[i].collapse(true, false);\r
-            }\r
-        }\r
-    },\r
-\r
-    // private\r
-    delayedExpand : function(delay){\r
-        if(!this.expandProcId){\r
-            this.expandProcId = this.expand.defer(delay, this);\r
-        }\r
-    },\r
-\r
-    // private\r
-    cancelExpand : function(){\r
-        if(this.expandProcId){\r
-            clearTimeout(this.expandProcId);\r
-        }\r
-        this.expandProcId = false;\r
-    },\r
-\r
-    /**\r
-     * Toggles expanded/collapsed state of the node\r
-     */\r
-    toggle : function(){\r
-        if(this.expanded){\r
-            this.collapse();\r
-        }else{\r
-            this.expand();\r
-        }\r
-    },\r
-\r
-    /**\r
-     * Ensures all parent nodes are expanded, and if necessary, scrolls\r
-     * the node into view.\r
-     * @param {Function} callback (optional) A function to call when the node has been made visible.\r
-     * @param {Object} scope (optional) The scope in which to execute the callback.\r
-     */\r
-    ensureVisible : function(callback, scope){\r
-        var tree = this.getOwnerTree();\r
-        tree.expandPath(this.parentNode ? this.parentNode.getPath() : this.getPath(), false, function(){\r
-            var node = tree.getNodeById(this.id);  // Somehow if we don't do this, we lose changes that happened to node in the meantime\r
-            tree.getTreeEl().scrollChildIntoView(node.ui.anchor);\r
-            this.runCallback(callback, scope || this, [this]);\r
-        }.createDelegate(this));\r
-    },\r
-\r
-    /**\r
-     * Expand all child nodes\r
-     * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes\r
-     */\r
-    expandChildNodes : function(deep){\r
-        var cs = this.childNodes;\r
-        for(var i = 0, len = cs.length; i < len; i++) {\r
-               cs[i].expand(deep);\r
-        }\r
-    },\r
-\r
-    /**\r
-     * Collapse all child nodes\r
-     * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes\r
-     */\r
-    collapseChildNodes : function(deep){\r
-        var cs = this.childNodes;\r
-        for(var i = 0, len = cs.length; i < len; i++) {\r
-               cs[i].collapse(deep);\r
-        }\r
-    },\r
-\r
-    /**\r
-     * Disables this node\r
-     */\r
-    disable : function(){\r
-        this.disabled = true;\r
-        this.unselect();\r
-        if(this.rendered && this.ui.onDisableChange){ // event without subscribing\r
-            this.ui.onDisableChange(this, true);\r
-        }\r
-        this.fireEvent("disabledchange", this, true);\r
-    },\r
-\r
-    /**\r
-     * Enables this node\r
-     */\r
-    enable : function(){\r
-        this.disabled = false;\r
-        if(this.rendered && this.ui.onDisableChange){ // event without subscribing\r
-            this.ui.onDisableChange(this, false);\r
-        }\r
-        this.fireEvent("disabledchange", this, false);\r
-    },\r
-\r
-    // private\r
-    renderChildren : function(suppressEvent){\r
-        if(suppressEvent !== false){\r
-            this.fireEvent("beforechildrenrendered", this);\r
-        }\r
-        var cs = this.childNodes;\r
-        for(var i = 0, len = cs.length; i < len; i++){\r
-            cs[i].render(true);\r
-        }\r
-        this.childrenRendered = true;\r
-    },\r
-\r
-    // private\r
-    sort : function(fn, scope){\r
-        Ext.tree.TreeNode.superclass.sort.apply(this, arguments);\r
-        if(this.childrenRendered){\r
-            var cs = this.childNodes;\r
-            for(var i = 0, len = cs.length; i < len; i++){\r
-                cs[i].render(true);\r
-            }\r
-        }\r
-    },\r
-\r
-    // private\r
-    render : function(bulkRender){\r
-        this.ui.render(bulkRender);\r
-        if(!this.rendered){\r
-            // make sure it is registered\r
-            this.getOwnerTree().registerNode(this);\r
-            this.rendered = true;\r
-            if(this.expanded){\r
-                this.expanded = false;\r
-                this.expand(false, false);\r
-            }\r
-        }\r
-    },\r
-\r
-    // private\r
-    renderIndent : function(deep, refresh){\r
-        if(refresh){\r
-            this.ui.childIndent = null;\r
-        }\r
-        this.ui.renderIndent();\r
-        if(deep === true && this.childrenRendered){\r
-            var cs = this.childNodes;\r
-            for(var i = 0, len = cs.length; i < len; i++){\r
-                cs[i].renderIndent(true, refresh);\r
-            }\r
-        }\r
-    },\r
-\r
-    beginUpdate : function(){\r
-        this.childrenRendered = false;\r
-    },\r
-\r
-    endUpdate : function(){\r
-        if(this.expanded && this.rendered){\r
-            this.renderChildren();\r
-        }\r
-    },\r
-\r
-    destroy : function(){\r
-        if(this.childNodes){\r
-            for(var i = 0,l = this.childNodes.length; i < l; i++){\r
-                this.childNodes[i].destroy();\r
-            }\r
-            this.childNodes = null;\r
-        }\r
-        if(this.ui.destroy){\r
-            this.ui.destroy();\r
-        }\r
-    },\r
-    \r
-    // private\r
-    onIdChange: function(id){\r
-        this.ui.onIdChange(id);\r
-    }\r
-});\r
-\r
+});/**
+ * @class Ext.tree.TreeNode
+ * @extends Ext.data.Node
+ * @cfg {String} text The text for this node
+ * @cfg {Boolean} expanded true to start the node expanded
+ * @cfg {Boolean} allowDrag False to make this node undraggable if {@link #draggable} = true (defaults to true)
+ * @cfg {Boolean} allowDrop False if this node cannot have child nodes dropped on it (defaults to true)
+ * @cfg {Boolean} disabled true to start the node disabled
+ * @cfg {String} icon The path to an icon for the node. The preferred way to do this
+ * is to use the cls or iconCls attributes and add the icon via a CSS background image.
+ * @cfg {String} cls A css class to be added to the node
+ * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
+ * @cfg {String} href URL of the link used for the node (defaults to #)
+ * @cfg {String} hrefTarget target frame for the link
+ * @cfg {Boolean} hidden True to render hidden. (Defaults to false).
+ * @cfg {String} qtip An Ext QuickTip for the node
+ * @cfg {Boolean} expandable If set to true, the node will always show a plus/minus icon, even when empty
+ * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
+ * @cfg {Boolean} singleClickExpand True for single click expand on this node
+ * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Ext.tree.TreeNodeUI)
+ * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
+ * (defaults to undefined with no checkbox rendered)
+ * @cfg {Boolean} draggable True to make this node draggable (defaults to false)
+ * @cfg {Boolean} isTarget False to not allow this node to act as a drop target (defaults to true)
+ * @cfg {Boolean} allowChildren False to not allow this node to have child nodes (defaults to true)
+ * @cfg {Boolean} editable False to not allow this node to be edited by an {@link Ext.tree.TreeEditor} (defaults to true)
+ * @constructor
+ * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
+ */
+Ext.tree.TreeNode = function(attributes){
+    attributes = attributes || {};
+    if(Ext.isString(attributes)){
+        attributes = {text: attributes};
+    }
+    this.childrenRendered = false;
+    this.rendered = false;
+    Ext.tree.TreeNode.superclass.constructor.call(this, attributes);
+    this.expanded = attributes.expanded === true;
+    this.isTarget = attributes.isTarget !== false;
+    this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
+    this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
+
+    /**
+     * Read-only. The text for this node. To change it use <code>{@link #setText}</code>.
+     * @type String
+     */
+    this.text = attributes.text;
+    /**
+     * True if this node is disabled.
+     * @type Boolean
+     */
+    this.disabled = attributes.disabled === true;
+    /**
+     * True if this node is hidden.
+     * @type Boolean
+     */
+    this.hidden = attributes.hidden === true;
+
+    this.addEvents(
+        /**
+        * @event textchange
+        * Fires when the text for this node is changed
+        * @param {Node} this This node
+        * @param {String} text The new text
+        * @param {String} oldText The old text
+        */
+        'textchange',
+        /**
+        * @event beforeexpand
+        * Fires before this node is expanded, return false to cancel.
+        * @param {Node} this This node
+        * @param {Boolean} deep
+        * @param {Boolean} anim
+        */
+        'beforeexpand',
+        /**
+        * @event beforecollapse
+        * Fires before this node is collapsed, return false to cancel.
+        * @param {Node} this This node
+        * @param {Boolean} deep
+        * @param {Boolean} anim
+        */
+        'beforecollapse',
+        /**
+        * @event expand
+        * Fires when this node is expanded
+        * @param {Node} this This node
+        */
+        'expand',
+        /**
+        * @event disabledchange
+        * Fires when the disabled status of this node changes
+        * @param {Node} this This node
+        * @param {Boolean} disabled
+        */
+        'disabledchange',
+        /**
+        * @event collapse
+        * Fires when this node is collapsed
+        * @param {Node} this This node
+        */
+        'collapse',
+        /**
+        * @event beforeclick
+        * Fires before click processing. Return false to cancel the default action.
+        * @param {Node} this This node
+        * @param {Ext.EventObject} e The event object
+        */
+        'beforeclick',
+        /**
+        * @event click
+        * Fires when this node is clicked
+        * @param {Node} this This node
+        * @param {Ext.EventObject} e The event object
+        */
+        'click',
+        /**
+        * @event checkchange
+        * Fires when a node with a checkbox's checked property changes
+        * @param {Node} this This node
+        * @param {Boolean} checked
+        */
+        'checkchange',
+        /**
+        * @event beforedblclick
+        * Fires before double click processing. Return false to cancel the default action.
+        * @param {Node} this This node
+        * @param {Ext.EventObject} e The event object
+        */
+        'beforedblclick',
+        /**
+        * @event dblclick
+        * Fires when this node is double clicked
+        * @param {Node} this This node
+        * @param {Ext.EventObject} e The event object
+        */
+        'dblclick',
+        /**
+        * @event contextmenu
+        * Fires when this node is right clicked
+        * @param {Node} this This node
+        * @param {Ext.EventObject} e The event object
+        */
+        'contextmenu',
+        /**
+        * @event beforechildrenrendered
+        * Fires right before the child nodes for this node are rendered
+        * @param {Node} this This node
+        */
+        'beforechildrenrendered'
+    );
+
+    var uiClass = this.attributes.uiProvider || this.defaultUI || Ext.tree.TreeNodeUI;
+
+    /**
+     * Read-only. The UI for this node
+     * @type TreeNodeUI
+     */
+    this.ui = new uiClass(this);
+};
+Ext.extend(Ext.tree.TreeNode, Ext.data.Node, {
+    preventHScroll : true,
+    /**
+     * Returns true if this node is expanded
+     * @return {Boolean}
+     */
+    isExpanded : function(){
+        return this.expanded;
+    },
+
+/**
+ * Returns the UI object for this node.
+ * @return {TreeNodeUI} The object which is providing the user interface for this tree
+ * node. Unless otherwise specified in the {@link #uiProvider}, this will be an instance
+ * of {@link Ext.tree.TreeNodeUI}
+ */
+    getUI : function(){
+        return this.ui;
+    },
+
+    getLoader : function(){
+        var owner;
+        return this.loader || ((owner = this.getOwnerTree()) && owner.loader ? owner.loader : (this.loader = new Ext.tree.TreeLoader()));
+    },
+
+    // private override
+    setFirstChild : function(node){
+        var of = this.firstChild;
+        Ext.tree.TreeNode.superclass.setFirstChild.call(this, node);
+        if(this.childrenRendered && of && node != of){
+            of.renderIndent(true, true);
+        }
+        if(this.rendered){
+            this.renderIndent(true, true);
+        }
+    },
+
+    // private override
+    setLastChild : function(node){
+        var ol = this.lastChild;
+        Ext.tree.TreeNode.superclass.setLastChild.call(this, node);
+        if(this.childrenRendered && ol && node != ol){
+            ol.renderIndent(true, true);
+        }
+        if(this.rendered){
+            this.renderIndent(true, true);
+        }
+    },
+
+    // these methods are overridden to provide lazy rendering support
+    // private override
+    appendChild : function(n){
+        var node, exists;
+        if(!n.render && !Ext.isArray(n)){
+            n = this.getLoader().createNode(n);
+        }else{
+            exists = !n.parentNode;
+        }
+        node = Ext.tree.TreeNode.superclass.appendChild.call(this, n);
+        if(node){
+            this.afterAdd(node, exists);
+        }
+        this.ui.updateExpandIcon();
+        return node;
+    },
+
+    // private override
+    removeChild : function(node, destroy){
+        this.ownerTree.getSelectionModel().unselect(node);
+        Ext.tree.TreeNode.superclass.removeChild.apply(this, arguments);
+        // if it's been rendered remove dom node
+        if(node.ui.rendered){
+            node.ui.remove();
+        }
+        if(this.childNodes.length < 1){
+            this.collapse(false, false);
+        }else{
+            this.ui.updateExpandIcon();
+        }
+        if(!this.firstChild && !this.isHiddenRoot()) {
+            this.childrenRendered = false;
+        }
+        return node;
+    },
+
+    // private override
+    insertBefore : function(node, refNode){
+        var newNode, exists;
+        if(!node.render){
+            node = this.getLoader().createNode(node);
+        } else {
+            exists = Ext.isObject(node.parentNode);
+        }
+        newNode = Ext.tree.TreeNode.superclass.insertBefore.call(this, node, refNode);
+        if(newNode && refNode){
+            this.afterAdd(newNode, exists);
+        }
+        this.ui.updateExpandIcon();
+        return newNode;
+    },
+    
+    // private
+    afterAdd : function(node, exists){
+        if(this.childrenRendered){
+            // bulk render if the node already exists
+            node.render(exists);
+        }else if(exists){
+            // make sure we update the indent
+            node.renderIndent(true, true);
+        }
+    },
+
+    /**
+     * Sets the text for this node
+     * @param {String} text
+     */
+    setText : function(text){
+        var oldText = this.text;
+        this.text = this.attributes.text = text;
+        if(this.rendered){ // event without subscribing
+            this.ui.onTextChange(this, text, oldText);
+        }
+        this.fireEvent('textchange', this, text, oldText);
+    },
+
+    /**
+     * Triggers selection of this node
+     */
+    select : function(){
+        var t = this.getOwnerTree();
+        if(t){
+            t.getSelectionModel().select(this);
+        }
+    },
+
+    /**
+     * Triggers deselection of this node
+     * @param {Boolean} silent (optional) True to stop selection change events from firing.
+     */
+    unselect : function(silent){
+        var t = this.getOwnerTree();
+        if(t){
+            t.getSelectionModel().unselect(this, silent);
+        }
+    },
+
+    /**
+     * Returns true if this node is selected
+     * @return {Boolean}
+     */
+    isSelected : function(){
+        var t = this.getOwnerTree();
+        return t ? t.getSelectionModel().isSelected(this) : false;
+    },
+
+    /**
+     * Expand this node.
+     * @param {Boolean} deep (optional) True to expand all children as well
+     * @param {Boolean} anim (optional) false to cancel the default animation
+     * @param {Function} callback (optional) A callback to be called when
+     * expanding this node completes (does not wait for deep expand to complete).
+     * Called with 1 parameter, this node.
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this TreeNode.
+     */
+    expand : function(deep, anim, callback, scope){
+        if(!this.expanded){
+            if(this.fireEvent('beforeexpand', this, deep, anim) === false){
+                return;
+            }
+            if(!this.childrenRendered){
+                this.renderChildren();
+            }
+            this.expanded = true;
+            if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
+                this.ui.animExpand(function(){
+                    this.fireEvent('expand', this);
+                    this.runCallback(callback, scope || this, [this]);
+                    if(deep === true){
+                        this.expandChildNodes(true);
+                    }
+                }.createDelegate(this));
+                return;
+            }else{
+                this.ui.expand();
+                this.fireEvent('expand', this);
+                this.runCallback(callback, scope || this, [this]);
+            }
+        }else{
+           this.runCallback(callback, scope || this, [this]);
+        }
+        if(deep === true){
+            this.expandChildNodes(true);
+        }
+    },
+
+    runCallback : function(cb, scope, args){
+        if(Ext.isFunction(cb)){
+            cb.apply(scope, args);
+        }
+    },
+
+    isHiddenRoot : function(){
+        return this.isRoot && !this.getOwnerTree().rootVisible;
+    },
+
+    /**
+     * Collapse this node.
+     * @param {Boolean} deep (optional) True to collapse all children as well
+     * @param {Boolean} anim (optional) false to cancel the default animation
+     * @param {Function} callback (optional) A callback to be called when
+     * expanding this node completes (does not wait for deep expand to complete).
+     * Called with 1 parameter, this node.
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this TreeNode.
+     */
+    collapse : function(deep, anim, callback, scope){
+        if(this.expanded && !this.isHiddenRoot()){
+            if(this.fireEvent('beforecollapse', this, deep, anim) === false){
+                return;
+            }
+            this.expanded = false;
+            if((this.getOwnerTree().animate && anim !== false) || anim){
+                this.ui.animCollapse(function(){
+                    this.fireEvent('collapse', this);
+                    this.runCallback(callback, scope || this, [this]);
+                    if(deep === true){
+                        this.collapseChildNodes(true);
+                    }
+                }.createDelegate(this));
+                return;
+            }else{
+                this.ui.collapse();
+                this.fireEvent('collapse', this);
+                this.runCallback(callback, scope || this, [this]);
+            }
+        }else if(!this.expanded){
+            this.runCallback(callback, scope || this, [this]);
+        }
+        if(deep === true){
+            var cs = this.childNodes;
+            for(var i = 0, len = cs.length; i < len; i++) {
+               cs[i].collapse(true, false);
+            }
+        }
+    },
+
+    // private
+    delayedExpand : function(delay){
+        if(!this.expandProcId){
+            this.expandProcId = this.expand.defer(delay, this);
+        }
+    },
+
+    // private
+    cancelExpand : function(){
+        if(this.expandProcId){
+            clearTimeout(this.expandProcId);
+        }
+        this.expandProcId = false;
+    },
+
+    /**
+     * Toggles expanded/collapsed state of the node
+     */
+    toggle : function(){
+        if(this.expanded){
+            this.collapse();
+        }else{
+            this.expand();
+        }
+    },
+
+    /**
+     * Ensures all parent nodes are expanded, and if necessary, scrolls
+     * the node into view.
+     * @param {Function} callback (optional) A function to call when the node has been made visible.
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this TreeNode.
+     */
+    ensureVisible : function(callback, scope){
+        var tree = this.getOwnerTree();
+        tree.expandPath(this.parentNode ? this.parentNode.getPath() : this.getPath(), false, function(){
+            var node = tree.getNodeById(this.id);  // Somehow if we don't do this, we lose changes that happened to node in the meantime
+            tree.getTreeEl().scrollChildIntoView(node.ui.anchor);
+            this.runCallback(callback, scope || this, [this]);
+        }.createDelegate(this));
+    },
+
+    /**
+     * Expand all child nodes
+     * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
+     */
+    expandChildNodes : function(deep){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               cs[i].expand(deep);
+        }
+    },
+
+    /**
+     * Collapse all child nodes
+     * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
+     */
+    collapseChildNodes : function(deep){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               cs[i].collapse(deep);
+        }
+    },
+
+    /**
+     * Disables this node
+     */
+    disable : function(){
+        this.disabled = true;
+        this.unselect();
+        if(this.rendered && this.ui.onDisableChange){ // event without subscribing
+            this.ui.onDisableChange(this, true);
+        }
+        this.fireEvent('disabledchange', this, true);
+    },
+
+    /**
+     * Enables this node
+     */
+    enable : function(){
+        this.disabled = false;
+        if(this.rendered && this.ui.onDisableChange){ // event without subscribing
+            this.ui.onDisableChange(this, false);
+        }
+        this.fireEvent('disabledchange', this, false);
+    },
+
+    // private
+    renderChildren : function(suppressEvent){
+        if(suppressEvent !== false){
+            this.fireEvent('beforechildrenrendered', this);
+        }
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++){
+            cs[i].render(true);
+        }
+        this.childrenRendered = true;
+    },
+
+    // private
+    sort : function(fn, scope){
+        Ext.tree.TreeNode.superclass.sort.apply(this, arguments);
+        if(this.childrenRendered){
+            var cs = this.childNodes;
+            for(var i = 0, len = cs.length; i < len; i++){
+                cs[i].render(true);
+            }
+        }
+    },
+
+    // private
+    render : function(bulkRender){
+        this.ui.render(bulkRender);
+        if(!this.rendered){
+            // make sure it is registered
+            this.getOwnerTree().registerNode(this);
+            this.rendered = true;
+            if(this.expanded){
+                this.expanded = false;
+                this.expand(false, false);
+            }
+        }
+    },
+
+    // private
+    renderIndent : function(deep, refresh){
+        if(refresh){
+            this.ui.childIndent = null;
+        }
+        this.ui.renderIndent();
+        if(deep === true && this.childrenRendered){
+            var cs = this.childNodes;
+            for(var i = 0, len = cs.length; i < len; i++){
+                cs[i].renderIndent(true, refresh);
+            }
+        }
+    },
+
+    beginUpdate : function(){
+        this.childrenRendered = false;
+    },
+
+    endUpdate : function(){
+        if(this.expanded && this.rendered){
+            this.renderChildren();
+        }
+    },
+
+    destroy : function(){
+        this.unselect(true);
+        Ext.tree.TreeNode.superclass.destroy.call(this);
+        Ext.destroy(this.ui, this.loader);
+        this.ui = this.loader = null;
+    },
+
+    // private
+    onIdChange : function(id){
+        this.ui.onIdChange(id);
+    }
+});
+
 Ext.tree.TreePanel.nodeTypes.node = Ext.tree.TreeNode;/**\r
  * @class Ext.tree.AsyncTreeNode\r
  * @extends Ext.tree.TreeNode\r
@@ -2793,7 +2923,7 @@ Ext.extend(Ext.tree.AsyncTreeNode, Ext.tree.TreeNode, {
     /**\r
      * Trigger a reload for this node\r
      * @param {Function} callback\r
-     * @param {Object} scope (optional) The scope in which to execute the callback.\r
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this Node.\r
      */\r
     reload : function(callback, scope){\r
         this.collapse(false, false);\r
@@ -2836,7 +2966,7 @@ Ext.tree.TreeNodeUI.prototype = {
     removeChild : function(node){\r
         if(this.rendered){\r
             this.ctNode.removeChild(node.ui.getEl());\r
-        } \r
+        }\r
     },\r
 \r
     // private\r
@@ -2859,14 +2989,14 @@ Ext.tree.TreeNodeUI.prototype = {
     // private\r
     onDisableChange : function(node, state){\r
         this.disabled = state;\r
-               if (this.checkbox) {\r
-                       this.checkbox.disabled = state;\r
-               }        \r
+        if (this.checkbox) {\r
+            this.checkbox.disabled = state;\r
+        }\r
         if(state){\r
             this.addClass("x-tree-node-disabled");\r
         }else{\r
             this.removeClass("x-tree-node-disabled");\r
-        } \r
+        }\r
     },\r
 \r
     // private\r
@@ -2917,7 +3047,7 @@ Ext.tree.TreeNodeUI.prototype = {
  */\r
     removeClass : function(cls){\r
         if(this.elNode){\r
-            Ext.fly(this.elNode).removeClass(cls);  \r
+            Ext.fly(this.elNode).removeClass(cls);\r
         }\r
     },\r
 \r
@@ -2926,12 +3056,12 @@ Ext.tree.TreeNodeUI.prototype = {
         if(this.rendered){\r
             this.holder = document.createElement("div");\r
             this.holder.appendChild(this.wrap);\r
-        }  \r
+        }\r
     },\r
 \r
     // private\r
     fireEvent : function(){\r
-        return this.node.fireEvent.apply(this.node, arguments);  \r
+        return this.node.fireEvent.apply(this.node, arguments);\r
     },\r
 \r
     // private\r
@@ -2939,10 +3069,7 @@ Ext.tree.TreeNodeUI.prototype = {
         this.node.on("move", this.onMove, this);\r
 \r
         if(this.node.disabled){\r
-            this.addClass("x-tree-node-disabled");\r
-                       if (this.checkbox) {\r
-                               this.checkbox.disabled = true;\r
-                       }            \r
+            this.onDisableChange(this.node, true);\r
         }\r
         if(this.node.hidden){\r
             this.hide();\r
@@ -2980,7 +3107,7 @@ Ext.tree.TreeNodeUI.prototype = {
         this.node.hidden = false;\r
         if(this.wrap){\r
             this.wrap.style.display = "";\r
-        } \r
+        }\r
     },\r
 \r
     // private\r
@@ -3027,13 +3154,15 @@ Ext.tree.TreeNodeUI.prototype = {
         if(this.disabled){\r
             return;\r
         }\r
-        if(this.checkbox){\r
-            this.toggleCheck();\r
-        }\r
-        if(!this.animating && this.node.isExpandable()){\r
-            this.node.toggle();\r
+        if(this.fireEvent("beforedblclick", this.node, e) !== false){\r
+            if(this.checkbox){\r
+                this.toggleCheck();\r
+            }\r
+            if(!this.animating && this.node.isExpandable()){\r
+                this.node.toggle();\r
+            }\r
+            this.fireEvent("dblclick", this.node, e);\r
         }\r
-        this.fireEvent("dblclick", this.node, e);\r
     },\r
 \r
     onOver : function(e){\r
@@ -3047,8 +3176,8 @@ Ext.tree.TreeNodeUI.prototype = {
     // private\r
     onCheckChange : function(){\r
         var checked = this.checkbox.checked;\r
-               // fix for IE6\r
-               this.checkbox.defaultChecked = checked;         \r
+        // fix for IE6\r
+        this.checkbox.defaultChecked = checked;\r
         this.node.attributes.checked = checked;\r
         this.fireEvent('checkchange', this.node, checked);\r
     },\r
@@ -3064,12 +3193,12 @@ Ext.tree.TreeNodeUI.prototype = {
     startDrop : function(){\r
         this.dropping = true;\r
     },\r
-    \r
+\r
     // delayed drop so the click event doesn't get fired on a drop\r
-    endDrop : function(){ \r
+    endDrop : function(){\r
        setTimeout(function(){\r
            this.dropping = false;\r
-       }.createDelegate(this), 50); \r
+       }.createDelegate(this), 50);\r
     },\r
 \r
     // private\r
@@ -3110,7 +3239,7 @@ Ext.tree.TreeNodeUI.prototype = {
     blur : function(){\r
         try{\r
             this.anchor.blur();\r
-        }catch(e){} \r
+        }catch(e){}\r
     },\r
 \r
     // private\r
@@ -3125,7 +3254,7 @@ Ext.tree.TreeNodeUI.prototype = {
         }\r
         this.animating = true;\r
         this.updateExpandIcon();\r
-        \r
+\r
         ct.slideIn('t', {\r
            callback : function(){\r
                this.animating = false;\r
@@ -3172,12 +3301,15 @@ Ext.tree.TreeNodeUI.prototype = {
 \r
     // private\r
     getContainer : function(){\r
-        return this.ctNode;  \r
+        return this.ctNode;\r
     },\r
 \r
-    // private\r
+/**\r
+ * Returns the element which encapsulates this node.\r
+ * @return {HtmlElement} The DOM element. The default implementation uses a <code>&lt;li></code>.\r
+ */\r
     getEl : function(){\r
-        return this.wrap;  \r
+        return this.wrap;\r
     },\r
 \r
     // private\r
@@ -3192,15 +3324,15 @@ Ext.tree.TreeNodeUI.prototype = {
 \r
     // private\r
     onRender : function(){\r
-        this.render();    \r
+        this.render();\r
     },\r
 \r
     // private\r
     render : function(bulkRender){\r
         var n = this.node, a = n.attributes;\r
-        var targetNode = n.parentNode ? \r
+        var targetNode = n.parentNode ?\r
               n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;\r
-        \r
+\r
         if(!this.rendered){\r
             this.rendered = true;\r
 \r
@@ -3217,7 +3349,7 @@ Ext.tree.TreeNodeUI.prototype = {
                    if(a.qtipTitle){\r
                        this.textNode.setAttribute("ext:qtitle", a.qtipTitle);\r
                    }\r
-               } \r
+               }\r
             }else if(a.qtipCfg){\r
                 a.qtipCfg.target = Ext.id(this.textNode);\r
                 Ext.QuickTips.register(a.qtipCfg);\r
@@ -3238,10 +3370,10 @@ Ext.tree.TreeNodeUI.prototype = {
         // add some indent caching, this helps performance when rendering a large tree\r
         this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';\r
 \r
-        var cb = typeof a.checked == 'boolean';\r
-\r
-        var href = a.href ? a.href : Ext.isGecko ? "" : "#";\r
-        var buf = ['<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf x-unselectable ', a.cls,'" unselectable="on">',\r
+        var cb = Ext.isBoolean(a.checked),\r
+            nel,\r
+            href = a.href ? a.href : Ext.isGecko ? "" : "#",\r
+            buf = ['<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf x-unselectable ', a.cls,'" unselectable="on">',\r
             '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",\r
             '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" />',\r
             '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',\r
@@ -3251,13 +3383,12 @@ Ext.tree.TreeNodeUI.prototype = {
             '<ul class="x-tree-node-ct" style="display:none;"></ul>',\r
             "</li>"].join('');\r
 \r
-        var nel;\r
         if(bulkRender !== true && n.nextSibling && (nel = n.nextSibling.ui.getEl())){\r
             this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf);\r
         }else{\r
             this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf);\r
         }\r
-        \r
+\r
         this.elNode = this.wrap.childNodes[0];\r
         this.ctNode = this.wrap.childNodes[1];\r
         var cs = this.elNode.childNodes;\r
@@ -3267,8 +3398,8 @@ Ext.tree.TreeNodeUI.prototype = {
         var index = 3;\r
         if(cb){\r
             this.checkbox = cs[3];\r
-                       // fix for IE6\r
-                       this.checkbox.defaultChecked = this.checkbox.checked;                                           \r
+            // fix for IE6\r
+            this.checkbox.defaultChecked = this.checkbox.checked;\r
             index++;\r
         }\r
         this.anchor = cs[index];\r
@@ -3282,7 +3413,7 @@ Ext.tree.TreeNodeUI.prototype = {
     getAnchor : function(){\r
         return this.anchor;\r
     },\r
-    \r
+\r
 /**\r
  * Returns the text node.\r
  * @return {HtmlNode} The DOM text node.\r
@@ -3290,7 +3421,7 @@ Ext.tree.TreeNodeUI.prototype = {
     getTextEl : function(){\r
         return this.textNode;\r
     },\r
-    \r
+\r
 /**\r
  * Returns the icon &lt;img> element.\r
  * @return {HtmlElement} The DOM image element.\r
@@ -3305,15 +3436,17 @@ Ext.tree.TreeNodeUI.prototype = {
  * @return {Boolean} The checked flag.\r
  */\r
     isChecked : function(){\r
-        return this.checkbox ? this.checkbox.checked : false; \r
+        return this.checkbox ? this.checkbox.checked : false;\r
     },\r
 \r
     // private\r
     updateExpandIcon : function(){\r
         if(this.rendered){\r
-            var n = this.node, c1, c2;\r
-            var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";\r
-            var hasChild = n.hasChildNodes();\r
+            var n = this.node,\r
+                c1,\r
+                c2,\r
+                cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow",\r
+                hasChild = n.hasChildNodes();\r
             if(hasChild || n.attributes.expandable){\r
                 if(n.expanded){\r
                     cls += "-minus";\r
@@ -3334,7 +3467,7 @@ Ext.tree.TreeNodeUI.prototype = {
                 }\r
             }else{\r
                 if(!this.wasLeaf){\r
-                    Ext.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");\r
+                    Ext.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-collapsed");\r
                     delete this.c1;\r
                     delete this.c2;\r
                     this.wasLeaf = true;\r
@@ -3347,7 +3480,7 @@ Ext.tree.TreeNodeUI.prototype = {
             }\r
         }\r
     },\r
-    \r
+\r
     // private\r
     onIdChange: function(id){\r
         if(this.rendered){\r
@@ -3358,8 +3491,8 @@ Ext.tree.TreeNodeUI.prototype = {
     // private\r
     getChildIndent : function(){\r
         if(!this.childIndent){\r
-            var buf = [];\r
-            var p = this.node;\r
+            var buf = [],\r
+                p = this.node;\r
             while(p){\r
                 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){\r
                     if(!p.isLast()) {\r
@@ -3378,8 +3511,8 @@ Ext.tree.TreeNodeUI.prototype = {
     // private\r
     renderIndent : function(){\r
         if(this.rendered){\r
-            var indent = "";\r
-            var p = this.node.parentNode;\r
+            var indent = "",\r
+                p = this.node.parentNode;\r
             if(p){\r
                 indent = p.ui.getChildIndent();\r
             }\r
@@ -3395,23 +3528,14 @@ Ext.tree.TreeNodeUI.prototype = {
         if(this.elNode){\r
             Ext.dd.Registry.unregister(this.elNode.id);\r
         }\r
-        delete this.elNode;\r
-        delete this.ctNode;\r
-        delete this.indentNode;\r
-        delete this.ecNode;\r
-        delete this.iconNode;\r
-        delete this.checkbox;\r
-        delete this.anchor;\r
-        delete this.textNode;\r
-        \r
-        if (this.holder){\r
-             delete this.wrap;\r
-             Ext.removeNode(this.holder);\r
-             delete this.holder;\r
-        }else{\r
-            Ext.removeNode(this.wrap);\r
-            delete this.wrap;\r
-        }\r
+\r
+        Ext.each(['textnode', 'anchor', 'checkbox', 'indentNode', 'ecNode', 'iconNode', 'elNode', 'ctNode', 'wrap', 'holder'], function(el){\r
+            if(this[el]){\r
+                Ext.fly(this[el]).remove();\r
+                delete this[el];\r
+            }\r
+        }, this);\r
+        delete this.node;\r
     }\r
 };\r
 \r
@@ -3505,7 +3629,7 @@ Ext.tree.TreeLoader = function(config){
         "loadexception"\r
     );\r
     Ext.tree.TreeLoader.superclass.constructor.call(this);\r
-    if(typeof this.paramOrder == 'string'){\r
+    if(Ext.isString(this.paramOrder)){\r
         this.paramOrder = this.paramOrder.split(/[\s,|]/);\r
     }\r
 };\r
@@ -3551,15 +3675,15 @@ Ext.extend(Ext.tree.TreeLoader, Ext.util.Observable, {
 \r
     /**\r
      * @cfg {Array/String} paramOrder Defaults to <tt>undefined</tt>. Only used when using directFn.\r
-     * A list of params to be executed\r
-     * server side.  Specify the params in the order in which they must be executed on the server-side\r
+     * Specifies the params in the order in which they must be passed to the server-side Direct method\r
      * as either (1) an Array of String values, or (2) a String of params delimited by either whitespace,\r
      * comma, or pipe. For example,\r
      * any of the following would be acceptable:<pre><code>\r
+nodeParameter: 'node',\r
 paramOrder: ['param1','param2','param3']\r
-paramOrder: 'param1 param2 param3'\r
-paramOrder: 'param1,param2,param3'\r
-paramOrder: 'param1|param2|param'\r
+paramOrder: 'node param1 param2 param3'\r
+paramOrder: 'param1,node,param2,param3'\r
+paramOrder: 'param1|param2|param|node'\r
      </code></pre>\r
      */\r
     paramOrder: undefined,\r
@@ -3571,6 +3695,12 @@ paramOrder: 'param1|param2|param'
      */\r
     paramsAsHash: false,\r
 \r
+    /**\r
+     * @cfg {String} nodeParameter The name of the parameter sent to the server which contains\r
+     * the identifier of the node. Defaults to <tt>'node'</tt>.\r
+     */\r
+    nodeParameter: 'node',\r
+\r
     /**\r
      * @cfg {Function} directFn\r
      * Function to call when executing a request.\r
@@ -3582,8 +3712,10 @@ paramOrder: 'param1|param2|param'
      * This is called automatically when a node is expanded, but may be used to reload\r
      * a node (or append new children if the {@link #clearOnLoad} option is false.)\r
      * @param {Ext.tree.TreeNode} node\r
-     * @param {Function} callback\r
-     * @param (Object) scope\r
+     * @param {Function} callback Function to call after the node has been loaded. The\r
+     * function is passed the TreeNode which was requested to be loaded.\r
+     * @param (Object) scope The cope (<code>this</code> reference) in which the callback is executed.\r
+     * defaults to the loaded TreeNode.\r
      */\r
     load : function(node, callback, scope){\r
         if(this.clearOnLoad){\r
@@ -3592,7 +3724,7 @@ paramOrder: 'param1|param2|param'
             }\r
         }\r
         if(this.doPreload(node)){ // preloaded json children\r
-            this.runCallback(callback, scope || node, []);\r
+            this.runCallback(callback, scope || node, [node]);\r
         }else if(this.directFn || this.dataUrl || this.url){\r
             this.requestData(node, callback, scope || node);\r
         }\r
@@ -3617,27 +3749,29 @@ paramOrder: 'param1|param2|param'
     },\r
 \r
     getParams: function(node){\r
-        var buf = [], bp = this.baseParams;\r
+        var bp = Ext.apply({}, this.baseParams),\r
+            np = this.nodeParameter,\r
+            po = this.paramOrder;\r
+\r
+        np && (bp[ np ] = node.id);\r
+\r
         if(this.directFn){\r
-            buf.push(node.id);\r
-            if(bp){\r
-                if(this.paramOrder){\r
-                    for(var i = 0, len = this.paramOrder.length; i < len; i++){\r
-                        buf.push(bp[this.paramOrder[i]]);\r
-                    }\r
-                }else if(this.paramsAsHash){\r
-                    buf.push(bp);\r
+            var buf = [node.id];\r
+            if(po){\r
+                // reset 'buf' if the nodeParameter was included in paramOrder\r
+                if(np && po.indexOf(np) > -1){\r
+                    buf = [];\r
                 }\r
+\r
+                for(var i = 0, len = po.length; i < len; i++){\r
+                    buf.push(bp[ po[i] ]);\r
+                }\r
+            }else if(this.paramsAsHash){\r
+                buf = [bp];\r
             }\r
             return buf;\r
         }else{\r
-            for(var key in bp){\r
-                if(!Ext.isFunction(bp[key])){\r
-                    buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");\r
-                }\r
-            }\r
-            buf.push("node=", encodeURIComponent(node.id));\r
-            return buf.join("");\r
+            return bp;\r
         }\r
     },\r
 \r
@@ -3702,7 +3836,7 @@ paramOrder: 'param1|param2|param'
     * Example:<pre><code>\r
 new Ext.tree.TreePanel({\r
     ...\r
-    new Ext.tree.TreeLoader({\r
+    loader: new Ext.tree.TreeLoader({\r
         url: 'dataUrl',\r
         createNode: function(attr) {\r
 //          Allow consolidation consignments to have\r
@@ -3711,7 +3845,7 @@ new Ext.tree.TreePanel({
                 attr.iconCls = 'x-consol',\r
                 attr.allowDrop = true;\r
             }\r
-            return Ext.tree.TreeLoader.prototype.call(this, attr);\r
+            return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);\r
         }\r
     }),\r
     ...\r
@@ -3724,10 +3858,10 @@ new Ext.tree.TreePanel({
         if(this.baseAttrs){\r
             Ext.applyIf(attr, this.baseAttrs);\r
         }\r
-        if(this.applyLoader !== false){\r
+        if(this.applyLoader !== false && !attr.loader){\r
             attr.loader = this;\r
         }\r
-        if(typeof attr.uiProvider == 'string'){\r
+        if(Ext.isString(attr.uiProvider)){\r
            attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider);\r
         }\r
         if(attr.nodeType){\r
@@ -3769,6 +3903,11 @@ new Ext.tree.TreePanel({
         var a = response.argument;\r
         this.fireEvent("loadexception", this, a.node, response);\r
         this.runCallback(a.callback, a.scope || a.node, [a.node]);\r
+    },\r
+\r
+    destroy : function(){\r
+        this.abort();\r
+        this.purgeListeners();\r
     }\r
 });/**
  * @class Ext.tree.TreeFilter
@@ -3824,7 +3963,7 @@ Ext.tree.TreeFilter.prototype = {
      * node in the tree (or from the startNode). If the function returns true, the node is kept
      * otherwise it is filtered. If a node is filtered, its children are also filtered.
      * @param {Function} fn The filter function
-     * @param {Object} scope (optional) The scope of the function (defaults to the current node)
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node.
      */
     filterBy : function(fn, scope, startNode){
         startNode = startNode || this.tree.root;
@@ -3880,7 +4019,7 @@ Ext.tree.TreeFilter.prototype = {
 };
 /**\r
  * @class Ext.tree.TreeSorter\r
- * Provides sorting of nodes in a {@link Ext.tree.TreePanel}.  The TreeSorter automatically monitors events on the \r
+ * Provides sorting of nodes in a {@link Ext.tree.TreePanel}.  The TreeSorter automatically monitors events on the\r
  * associated TreePanel that might affect the tree's sort order (beforechildrenrendered, append, insert and textchange).\r
  * Example usage:<br />\r
  * <pre><code>\r
@@ -3901,33 +4040,33 @@ Ext.tree.TreeSorter = function(tree, config){
     /**\r
      * @cfg {Boolean} folderSort True to sort leaf nodes under non-leaf nodes (defaults to false)\r
      */\r
-    /** \r
-     * @cfg {String} property The named attribute on the node to sort by (defaults to "text").  Note that this \r
+    /**\r
+     * @cfg {String} property The named attribute on the node to sort by (defaults to "text").  Note that this\r
      * property is only used if no {@link #sortType} function is specified, otherwise it is ignored.\r
      */\r
-    /** \r
+    /**\r
      * @cfg {String} dir The direction to sort ("asc" or "desc," case-insensitive, defaults to "asc")\r
      */\r
-    /** \r
+    /**\r
      * @cfg {String} leafAttr The attribute used to determine leaf nodes when {@link #folderSort} = true (defaults to "leaf")\r
      */\r
-    /** \r
+    /**\r
      * @cfg {Boolean} caseSensitive true for case-sensitive sort (defaults to false)\r
      */\r
-    /** \r
+    /**\r
      * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting.  The function\r
      * will be called with a single parameter (the {@link Ext.tree.TreeNode} being evaluated) and is expected to return\r
      * the node's sort value cast to the specific data type required for sorting.  This could be used, for example, when\r
-     * a node's text (or other attribute) should be sorted as a date or numeric value.  See the class description for \r
+     * a node's text (or other attribute) should be sorted as a date or numeric value.  See the class description for\r
      * example usage.  Note that if a sortType is specified, any {@link #property} config will be ignored.\r
      */\r
-    \r
+\r
     Ext.apply(this, config);\r
     tree.on("beforechildrenrendered", this.doSort, this);\r
     tree.on("append", this.updateSort, this);\r
     tree.on("insert", this.updateSort, this);\r
     tree.on("textchange", this.updateSortParent, this);\r
-    \r
+\r
     var dsc = this.dir && this.dir.toLowerCase() == "desc";\r
     var p = this.property || "text";\r
     var sortType = this.sortType;\r
@@ -3944,14 +4083,14 @@ Ext.tree.TreeSorter = function(tree, config){
                 return -1;\r
             }\r
         }\r
-       var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());\r
-       var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());\r
-       if(v1 < v2){\r
-                       return dsc ? +1 : -1;\r
-               }else if(v1 > v2){\r
-                       return dsc ? -1 : +1;\r
+        var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());\r
+        var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());\r
+        if(v1 < v2){\r
+            return dsc ? +1 : -1;\r
+        }else if(v1 > v2){\r
+            return dsc ? -1 : +1;\r
         }else{\r
-               return 0;\r
+            return 0;\r
         }\r
     };\r
 };\r
@@ -3960,20 +4099,20 @@ Ext.tree.TreeSorter.prototype = {
     doSort : function(node){\r
         node.sort(this.sortFn);\r
     },\r
-    \r
+\r
     compareNodes : function(n1, n2){\r
         return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);\r
     },\r
-    \r
+\r
     updateSort : function(tree, node){\r
         if(node.childrenRendered){\r
             this.doSort.defer(1, this, [node]);\r
         }\r
     },\r
-    \r
+\r
     updateSortParent : function(node){\r
-               var p = node.parentNode;\r
-               if(p && p.childrenRendered){\r
+        var p = node.parentNode;\r
+        if(p && p.childrenRendered){\r
             this.doSort.defer(1, this, [p]);\r
         }\r
     }\r
@@ -4380,6 +4519,7 @@ Ext.extend(Ext.tree.TreeDragZone, Ext.dd.DragZone, {
 Ext.tree.TreeEditor = function(tree, fc, config){
     fc = fc || {};
     var field = fc.events ? fc : new Ext.form.TextField(fc);
+    
     Ext.tree.TreeEditor.superclass.constructor.call(this, field, config);
 
     this.tree = tree;
@@ -4431,12 +4571,20 @@ Ext.extend(Ext.tree.TreeEditor, Ext.Editor, {
     editDelay : 350,
 
     initEditor : function(tree){
-        tree.on('beforeclick', this.beforeNodeClick, this);
-        tree.on('dblclick', this.onNodeDblClick, this);
-        this.on('complete', this.updateNode, this);
-        this.on('beforestartedit', this.fitToTree, this);
+        tree.on({
+            scope      : this,
+            beforeclick: this.beforeNodeClick,
+            dblclick   : this.onNodeDblClick
+        });
+        
+        this.on({
+            scope          : this,
+            complete       : this.updateNode,
+            beforestartedit: this.fitToTree,
+            specialkey     : this.onSpecialKey
+        });
+        
         this.on('startedit', this.bindScroll, this, {delay:10});
-        this.on('specialkey', this.onSpecialKey, this);
     },
 
     // private
@@ -4518,5 +4666,13 @@ Ext.extend(Ext.tree.TreeEditor, Ext.Editor, {
             e.stopEvent();
             this.completeEdit();
         }
+    },
+    
+    onDestroy : function(){
+        clearTimeout(this.autoEditTimer);
+        Ext.tree.TreeEditor.superclass.onDestroy.call(this);
+        var tree = this.tree;
+        tree.un('beforeclick', this.beforeNodeClick, this);
+        tree.un('dblclick', this.onNodeDblClick, this);
     }
 });
\ No newline at end of file