ext-all-debug.js
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:2341k
源码类别:

中间件编程

开发平台:

JavaScript

  1. }
  2. Ext.tree.TreeEventModel.prototype = {
  3.     initEvents : function(){
  4.         var el = this.tree.getTreeEl();
  5.         el.on('click', this.delegateClick, this);
  6.         if(this.tree.trackMouseOver !== false){
  7.             this.tree.innerCt.on('mouseover', this.delegateOver, this);
  8.             this.tree.innerCt.on('mouseout', this.delegateOut, this);
  9.         }
  10.         el.on('dblclick', this.delegateDblClick, this);
  11.         el.on('contextmenu', this.delegateContextMenu, this);
  12.     },
  13.     getNode : function(e){
  14.         var t;
  15.         if(t = e.getTarget('.x-tree-node-el', 10)){
  16.             var id = Ext.fly(t, '_treeEvents').getAttribute('tree-node-id', 'ext');
  17.             if(id){
  18.                 return this.tree.getNodeById(id);
  19.             }
  20.         }
  21.         return null;
  22.     },
  23.     getNodeTarget : function(e){
  24.         var t = e.getTarget('.x-tree-node-icon', 1);
  25.         if(!t){
  26.             t = e.getTarget('.x-tree-node-el', 6);
  27.         }
  28.         return t;
  29.     },
  30.     delegateOut : function(e, t){
  31.         if(!this.beforeEvent(e)){
  32.             return;
  33.         }
  34.         if(e.getTarget('.x-tree-ec-icon', 1)){
  35.             var n = this.getNode(e);
  36.             this.onIconOut(e, n);
  37.             if(n == this.lastEcOver){
  38.                 delete this.lastEcOver;
  39.             }
  40.         }
  41.         if((t = this.getNodeTarget(e)) && !e.within(t, true)){
  42.             this.onNodeOut(e, this.getNode(e));
  43.         }
  44.     },
  45.     delegateOver : function(e, t){
  46.         if(!this.beforeEvent(e)){
  47.             return;
  48.         }
  49.         if(Ext.isGecko && !this.trackingDoc){ // prevent hanging in FF
  50.             Ext.getBody().on('mouseover', this.trackExit, this);
  51.             this.trackingDoc = true;
  52.         }
  53.         if(this.lastEcOver){ // prevent hung highlight
  54.             this.onIconOut(e, this.lastEcOver);
  55.             delete this.lastEcOver;
  56.         }
  57.         if(e.getTarget('.x-tree-ec-icon', 1)){
  58.             this.lastEcOver = this.getNode(e);
  59.             this.onIconOver(e, this.lastEcOver);
  60.         }
  61.         if(t = this.getNodeTarget(e)){
  62.             this.onNodeOver(e, this.getNode(e));
  63.         }
  64.     },
  65.     trackExit : function(e){
  66.         if(this.lastOverNode && !e.within(this.lastOverNode.ui.getEl())){
  67.             this.onNodeOut(e, this.lastOverNode);
  68.             delete this.lastOverNode;
  69.             Ext.getBody().un('mouseover', this.trackExit, this);
  70.             this.trackingDoc = false;
  71.         }
  72.     },
  73.     delegateClick : function(e, t){
  74.         if(!this.beforeEvent(e)){
  75.             return;
  76.         }
  77.         if(e.getTarget('input[type=checkbox]', 1)){
  78.             this.onCheckboxClick(e, this.getNode(e));
  79.         }
  80.         else if(e.getTarget('.x-tree-ec-icon', 1)){
  81.             this.onIconClick(e, this.getNode(e));
  82.         }
  83.         else if(this.getNodeTarget(e)){
  84.             this.onNodeClick(e, this.getNode(e));
  85.         }
  86.     },
  87.     delegateDblClick : function(e, t){
  88.         if(this.beforeEvent(e) && this.getNodeTarget(e)){
  89.             this.onNodeDblClick(e, this.getNode(e));
  90.         }
  91.     },
  92.     delegateContextMenu : function(e, t){
  93.         if(this.beforeEvent(e) && this.getNodeTarget(e)){
  94.             this.onNodeContextMenu(e, this.getNode(e));
  95.         }
  96.     },
  97.     onNodeClick : function(e, node){
  98.         node.ui.onClick(e);
  99.     },
  100.     onNodeOver : function(e, node){
  101.         this.lastOverNode = node;
  102.         node.ui.onOver(e);
  103.     },
  104.     onNodeOut : function(e, node){
  105.         node.ui.onOut(e);
  106.     },
  107.     onIconOver : function(e, node){
  108.         node.ui.addClass('x-tree-ec-over');
  109.     },
  110.     onIconOut : function(e, node){
  111.         node.ui.removeClass('x-tree-ec-over');
  112.     },
  113.     onIconClick : function(e, node){
  114.         node.ui.ecClick(e);
  115.     },
  116.     onCheckboxClick : function(e, node){
  117.         node.ui.onCheckChange(e);
  118.     },
  119.     onNodeDblClick : function(e, node){
  120.         node.ui.onDblClick(e);
  121.     },
  122.     onNodeContextMenu : function(e, node){
  123.         node.ui.onContextMenu(e);
  124.     },
  125.     beforeEvent : function(e){
  126.         if(this.disabled){
  127.             e.stopEvent();
  128.             return false;
  129.         }
  130.         return true;
  131.     },
  132.     disable: function(){
  133.         this.disabled = true;
  134.     },
  135.     enable: function(){
  136.         this.disabled = false;
  137.     }
  138. };/**
  139.  * @class Ext.tree.DefaultSelectionModel
  140.  * @extends Ext.util.Observable
  141.  * The default single selection for a TreePanel.
  142.  */
  143. Ext.tree.DefaultSelectionModel = function(config){
  144.    this.selNode = null;
  145.    
  146.    this.addEvents(
  147.        /**
  148.         * @event selectionchange
  149.         * Fires when the selected node changes
  150.         * @param {DefaultSelectionModel} this
  151.         * @param {TreeNode} node the new selection
  152.         */
  153.        "selectionchange",
  154.        /**
  155.         * @event beforeselect
  156.         * Fires before the selected node changes, return false to cancel the change
  157.         * @param {DefaultSelectionModel} this
  158.         * @param {TreeNode} node the new selection
  159.         * @param {TreeNode} node the old selection
  160.         */
  161.        "beforeselect"
  162.    );
  163.     Ext.apply(this, config);
  164.     Ext.tree.DefaultSelectionModel.superclass.constructor.call(this);
  165. };
  166. Ext.extend(Ext.tree.DefaultSelectionModel, Ext.util.Observable, {
  167.     init : function(tree){
  168.         this.tree = tree;
  169.         tree.getTreeEl().on("keydown", this.onKeyDown, this);
  170.         tree.on("click", this.onNodeClick, this);
  171.     },
  172.     
  173.     onNodeClick : function(node, e){
  174.         this.select(node);
  175.     },
  176.     
  177.     /**
  178.      * Select a node.
  179.      * @param {TreeNode} node The node to select
  180.      * @return {TreeNode} The selected node
  181.      */
  182.     select : function(node){
  183.         var last = this.selNode;
  184.         if(node == last){
  185.             node.ui.onSelectedChange(true);
  186.         }else if(this.fireEvent('beforeselect', this, node, last) !== false){
  187.             if(last){
  188.                 last.ui.onSelectedChange(false);
  189.             }
  190.             this.selNode = node;
  191.             node.ui.onSelectedChange(true);
  192.             this.fireEvent("selectionchange", this, node, last);
  193.         }
  194.         return node;
  195.     },
  196.     
  197.     /**
  198.      * Deselect a node.
  199.      * @param {TreeNode} node The node to unselect
  200.      */
  201.     unselect : function(node){
  202.         if(this.selNode == node){
  203.             this.clearSelections();
  204.         }    
  205.     },
  206.     
  207.     /**
  208.      * Clear all selections
  209.      */
  210.     clearSelections : function(){
  211.         var n = this.selNode;
  212.         if(n){
  213.             n.ui.onSelectedChange(false);
  214.             this.selNode = null;
  215.             this.fireEvent("selectionchange", this, null);
  216.         }
  217.         return n;
  218.     },
  219.     
  220.     /**
  221.      * Get the selected node
  222.      * @return {TreeNode} The selected node
  223.      */
  224.     getSelectedNode : function(){
  225.         return this.selNode;    
  226.     },
  227.     
  228.     /**
  229.      * Returns true if the node is selected
  230.      * @param {TreeNode} node The node to check
  231.      * @return {Boolean}
  232.      */
  233.     isSelected : function(node){
  234.         return this.selNode == node;  
  235.     },
  236.     /**
  237.      * Selects the node above the selected node in the tree, intelligently walking the nodes
  238.      * @return TreeNode The new selection
  239.      */
  240.     selectPrevious : function(){
  241.         var s = this.selNode || this.lastSelNode;
  242.         if(!s){
  243.             return null;
  244.         }
  245.         var ps = s.previousSibling;
  246.         if(ps){
  247.             if(!ps.isExpanded() || ps.childNodes.length < 1){
  248.                 return this.select(ps);
  249.             } else{
  250.                 var lc = ps.lastChild;
  251.                 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
  252.                     lc = lc.lastChild;
  253.                 }
  254.                 return this.select(lc);
  255.             }
  256.         } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
  257.             return this.select(s.parentNode);
  258.         }
  259.         return null;
  260.     },
  261.     /**
  262.      * Selects the node above the selected node in the tree, intelligently walking the nodes
  263.      * @return TreeNode The new selection
  264.      */
  265.     selectNext : function(){
  266.         var s = this.selNode || this.lastSelNode;
  267.         if(!s){
  268.             return null;
  269.         }
  270.         if(s.firstChild && s.isExpanded()){
  271.              return this.select(s.firstChild);
  272.          }else if(s.nextSibling){
  273.              return this.select(s.nextSibling);
  274.          }else if(s.parentNode){
  275.             var newS = null;
  276.             s.parentNode.bubble(function(){
  277.                 if(this.nextSibling){
  278.                     newS = this.getOwnerTree().selModel.select(this.nextSibling);
  279.                     return false;
  280.                 }
  281.             });
  282.             return newS;
  283.          }
  284.         return null;
  285.     },
  286.     onKeyDown : function(e){
  287.         var s = this.selNode || this.lastSelNode;
  288.         // undesirable, but required
  289.         var sm = this;
  290.         if(!s){
  291.             return;
  292.         }
  293.         var k = e.getKey();
  294.         switch(k){
  295.              case e.DOWN:
  296.                  e.stopEvent();
  297.                  this.selectNext();
  298.              break;
  299.              case e.UP:
  300.                  e.stopEvent();
  301.                  this.selectPrevious();
  302.              break;
  303.              case e.RIGHT:
  304.                  e.preventDefault();
  305.                  if(s.hasChildNodes()){
  306.                      if(!s.isExpanded()){
  307.                          s.expand();
  308.                      }else if(s.firstChild){
  309.                          this.select(s.firstChild, e);
  310.                      }
  311.                  }
  312.              break;
  313.              case e.LEFT:
  314.                  e.preventDefault();
  315.                  if(s.hasChildNodes() && s.isExpanded()){
  316.                      s.collapse();
  317.                  }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
  318.                      this.select(s.parentNode, e);
  319.                  }
  320.              break;
  321.         };
  322.     }
  323. });
  324. /**
  325.  * @class Ext.tree.MultiSelectionModel
  326.  * @extends Ext.util.Observable
  327.  * Multi selection for a TreePanel.
  328.  */
  329. Ext.tree.MultiSelectionModel = function(config){
  330.    this.selNodes = [];
  331.    this.selMap = {};
  332.    this.addEvents(
  333.        /**
  334.         * @event selectionchange
  335.         * Fires when the selected nodes change
  336.         * @param {MultiSelectionModel} this
  337.         * @param {Array} nodes Array of the selected nodes
  338.         */
  339.        "selectionchange"
  340.    );
  341.     Ext.apply(this, config);
  342.     Ext.tree.MultiSelectionModel.superclass.constructor.call(this);
  343. };
  344. Ext.extend(Ext.tree.MultiSelectionModel, Ext.util.Observable, {
  345.     init : function(tree){
  346.         this.tree = tree;
  347.         tree.getTreeEl().on("keydown", this.onKeyDown, this);
  348.         tree.on("click", this.onNodeClick, this);
  349.     },
  350.     
  351.     onNodeClick : function(node, e){
  352.         if(e.ctrlKey && this.isSelected(node)){
  353.             this.unselect(node);
  354.         }else{
  355.             this.select(node, e, e.ctrlKey);
  356.         }
  357.     },
  358.     
  359.     /**
  360.      * Select a node.
  361.      * @param {TreeNode} node The node to select
  362.      * @param {EventObject} e (optional) An event associated with the selection
  363.      * @param {Boolean} keepExisting True to retain existing selections
  364.      * @return {TreeNode} The selected node
  365.      */
  366.     select : function(node, e, keepExisting){
  367.         if(keepExisting !== true){
  368.             this.clearSelections(true);
  369.         }
  370.         if(this.isSelected(node)){
  371.             this.lastSelNode = node;
  372.             return node;
  373.         }
  374.         this.selNodes.push(node);
  375.         this.selMap[node.id] = node;
  376.         this.lastSelNode = node;
  377.         node.ui.onSelectedChange(true);
  378.         this.fireEvent("selectionchange", this, this.selNodes);
  379.         return node;
  380.     },
  381.     
  382.     /**
  383.      * Deselect a node.
  384.      * @param {TreeNode} node The node to unselect
  385.      */
  386.     unselect : function(node){
  387.         if(this.selMap[node.id]){
  388.             node.ui.onSelectedChange(false);
  389.             var sn = this.selNodes;
  390.             var index = sn.indexOf(node);
  391.             if(index != -1){
  392.                 this.selNodes.splice(index, 1);
  393.             }
  394.             delete this.selMap[node.id];
  395.             this.fireEvent("selectionchange", this, this.selNodes);
  396.         }
  397.     },
  398.     
  399.     /**
  400.      * Clear all selections
  401.      */
  402.     clearSelections : function(suppressEvent){
  403.         var sn = this.selNodes;
  404.         if(sn.length > 0){
  405.             for(var i = 0, len = sn.length; i < len; i++){
  406.                 sn[i].ui.onSelectedChange(false);
  407.             }
  408.             this.selNodes = [];
  409.             this.selMap = {};
  410.             if(suppressEvent !== true){
  411.                 this.fireEvent("selectionchange", this, this.selNodes);
  412.             }
  413.         }
  414.     },
  415.     
  416.     /**
  417.      * Returns true if the node is selected
  418.      * @param {TreeNode} node The node to check
  419.      * @return {Boolean}
  420.      */
  421.     isSelected : function(node){
  422.         return this.selMap[node.id] ? true : false;  
  423.     },
  424.     
  425.     /**
  426.      * Returns an array of the selected nodes
  427.      * @return {Array}
  428.      */
  429.     getSelectedNodes : function(){
  430.         return this.selNodes;    
  431.     },
  432.     onKeyDown : Ext.tree.DefaultSelectionModel.prototype.onKeyDown,
  433.     selectNext : Ext.tree.DefaultSelectionModel.prototype.selectNext,
  434.     selectPrevious : Ext.tree.DefaultSelectionModel.prototype.selectPrevious
  435. });/**
  436.  * @class Ext.data.Tree
  437.  * @extends Ext.util.Observable
  438.  * Represents a tree data structure and bubbles all the events for its nodes. The nodes
  439.  * in the tree have most standard DOM functionality.
  440.  * @constructor
  441.  * @param {Node} root (optional) The root node
  442.  */
  443. Ext.data.Tree = function(root){
  444.    this.nodeHash = {};
  445.    /**
  446.     * The root node for this tree
  447.     * @type Node
  448.     */
  449.    this.root = null;
  450.    if(root){
  451.        this.setRootNode(root);
  452.    }
  453.    this.addEvents(
  454.        /**
  455.         * @event append
  456.         * Fires when a new child node is appended to a node in this tree.
  457.         * @param {Tree} tree The owner tree
  458.         * @param {Node} parent The parent node
  459.         * @param {Node} node The newly appended node
  460.         * @param {Number} index The index of the newly appended node
  461.         */
  462.        "append",
  463.        /**
  464.         * @event remove
  465.         * Fires when a child node is removed from a node in this tree.
  466.         * @param {Tree} tree The owner tree
  467.         * @param {Node} parent The parent node
  468.         * @param {Node} node The child node removed
  469.         */
  470.        "remove",
  471.        /**
  472.         * @event move
  473.         * Fires when a node is moved to a new location in the tree
  474.         * @param {Tree} tree The owner tree
  475.         * @param {Node} node The node moved
  476.         * @param {Node} oldParent The old parent of this node
  477.         * @param {Node} newParent The new parent of this node
  478.         * @param {Number} index The index it was moved to
  479.         */
  480.        "move",
  481.        /**
  482.         * @event insert
  483.         * Fires when a new child node is inserted in a node in this tree.
  484.         * @param {Tree} tree The owner tree
  485.         * @param {Node} parent The parent node
  486.         * @param {Node} node The child node inserted
  487.         * @param {Node} refNode The child node the node was inserted before
  488.         */
  489.        "insert",
  490.        /**
  491.         * @event beforeappend
  492.         * Fires before a new child is appended to a node in this tree, return false to cancel the append.
  493.         * @param {Tree} tree The owner tree
  494.         * @param {Node} parent The parent node
  495.         * @param {Node} node The child node to be appended
  496.         */
  497.        "beforeappend",
  498.        /**
  499.         * @event beforeremove
  500.         * Fires before a child is removed from a node in this tree, return false to cancel the remove.
  501.         * @param {Tree} tree The owner tree
  502.         * @param {Node} parent The parent node
  503.         * @param {Node} node The child node to be removed
  504.         */
  505.        "beforeremove",
  506.        /**
  507.         * @event beforemove
  508.         * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
  509.         * @param {Tree} tree The owner tree
  510.         * @param {Node} node The node being moved
  511.         * @param {Node} oldParent The parent of the node
  512.         * @param {Node} newParent The new parent the node is moving to
  513.         * @param {Number} index The index it is being moved to
  514.         */
  515.        "beforemove",
  516.        /**
  517.         * @event beforeinsert
  518.         * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
  519.         * @param {Tree} tree The owner tree
  520.         * @param {Node} parent The parent node
  521.         * @param {Node} node The child node to be inserted
  522.         * @param {Node} refNode The child node the node is being inserted before
  523.         */
  524.        "beforeinsert"
  525.    );
  526.     Ext.data.Tree.superclass.constructor.call(this);
  527. };
  528. Ext.extend(Ext.data.Tree, Ext.util.Observable, {
  529.     /**
  530.      * @cfg {String} pathSeparator
  531.      * The token used to separate paths in node ids (defaults to '/').
  532.      */
  533.     pathSeparator: "/",
  534.     // private
  535.     proxyNodeEvent : function(){
  536.         return this.fireEvent.apply(this, arguments);
  537.     },
  538.     /**
  539.      * Returns the root node for this tree.
  540.      * @return {Node}
  541.      */
  542.     getRootNode : function(){
  543.         return this.root;
  544.     },
  545.     /**
  546.      * Sets the root node for this tree.
  547.      * @param {Node} node
  548.      * @return {Node}
  549.      */
  550.     setRootNode : function(node){
  551.         this.root = node;
  552.         node.ownerTree = this;
  553.         node.isRoot = true;
  554.         this.registerNode(node);
  555.         return node;
  556.     },
  557.     /**
  558.      * Gets a node in this tree by its id.
  559.      * @param {String} id
  560.      * @return {Node}
  561.      */
  562.     getNodeById : function(id){
  563.         return this.nodeHash[id];
  564.     },
  565.     // private
  566.     registerNode : function(node){
  567.         this.nodeHash[node.id] = node;
  568.     },
  569.     // private
  570.     unregisterNode : function(node){
  571.         delete this.nodeHash[node.id];
  572.     },
  573.     toString : function(){
  574.         return "[Tree"+(this.id?" "+this.id:"")+"]";
  575.     }
  576. });
  577. /**
  578.  * @class Ext.data.Node
  579.  * @extends Ext.util.Observable
  580.  * @cfg {Boolean} leaf true if this node is a leaf and does not have children
  581.  * @cfg {String} id The id for this node. If one is not specified, one is generated.
  582.  * @constructor
  583.  * @param {Object} attributes The attributes/config for the node
  584.  */
  585. Ext.data.Node = function(attributes){
  586.     /**
  587.      * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
  588.      * @type {Object}
  589.      */
  590.     this.attributes = attributes || {};
  591.     this.leaf = this.attributes.leaf;
  592.     /**
  593.      * The node id. @type String
  594.      */
  595.     this.id = this.attributes.id;
  596.     if(!this.id){
  597.         this.id = Ext.id(null, "xnode-");
  598.         this.attributes.id = this.id;
  599.     }
  600.     /**
  601.      * All child nodes of this node. @type Array
  602.      */
  603.     this.childNodes = [];
  604.     if(!this.childNodes.indexOf){ // indexOf is a must
  605.         this.childNodes.indexOf = function(o){
  606.             for(var i = 0, len = this.length; i < len; i++){
  607.                 if(this[i] == o){
  608.                     return i;
  609.                 }
  610.             }
  611.             return -1;
  612.         };
  613.     }
  614.     /**
  615.      * The parent node for this node. @type Node
  616.      */
  617.     this.parentNode = null;
  618.     /**
  619.      * The first direct child node of this node, or null if this node has no child nodes. @type Node
  620.      */
  621.     this.firstChild = null;
  622.     /**
  623.      * The last direct child node of this node, or null if this node has no child nodes. @type Node
  624.      */
  625.     this.lastChild = null;
  626.     /**
  627.      * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
  628.      */
  629.     this.previousSibling = null;
  630.     /**
  631.      * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
  632.      */
  633.     this.nextSibling = null;
  634.     this.addEvents({
  635.        /**
  636.         * @event append
  637.         * Fires when a new child node is appended
  638.         * @param {Tree} tree The owner tree
  639.         * @param {Node} this This node
  640.         * @param {Node} node The newly appended node
  641.         * @param {Number} index The index of the newly appended node
  642.         */
  643.        "append" : true,
  644.        /**
  645.         * @event remove
  646.         * Fires when a child node is removed
  647.         * @param {Tree} tree The owner tree
  648.         * @param {Node} this This node
  649.         * @param {Node} node The removed node
  650.         */
  651.        "remove" : true,
  652.        /**
  653.         * @event move
  654.         * Fires when this node is moved to a new location in the tree
  655.         * @param {Tree} tree The owner tree
  656.         * @param {Node} this This node
  657.         * @param {Node} oldParent The old parent of this node
  658.         * @param {Node} newParent The new parent of this node
  659.         * @param {Number} index The index it was moved to
  660.         */
  661.        "move" : true,
  662.        /**
  663.         * @event insert
  664.         * Fires when a new child node is inserted.
  665.         * @param {Tree} tree The owner tree
  666.         * @param {Node} this This node
  667.         * @param {Node} node The child node inserted
  668.         * @param {Node} refNode The child node the node was inserted before
  669.         */
  670.        "insert" : true,
  671.        /**
  672.         * @event beforeappend
  673.         * Fires before a new child is appended, return false to cancel the append.
  674.         * @param {Tree} tree The owner tree
  675.         * @param {Node} this This node
  676.         * @param {Node} node The child node to be appended
  677.         */
  678.        "beforeappend" : true,
  679.        /**
  680.         * @event beforeremove
  681.         * Fires before a child is removed, return false to cancel the remove.
  682.         * @param {Tree} tree The owner tree
  683.         * @param {Node} this This node
  684.         * @param {Node} node The child node to be removed
  685.         */
  686.        "beforeremove" : true,
  687.        /**
  688.         * @event beforemove
  689.         * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
  690.         * @param {Tree} tree The owner tree
  691.         * @param {Node} this This node
  692.         * @param {Node} oldParent The parent of this node
  693.         * @param {Node} newParent The new parent this node is moving to
  694.         * @param {Number} index The index it is being moved to
  695.         */
  696.        "beforemove" : true,
  697.        /**
  698.         * @event beforeinsert
  699.         * Fires before a new child is inserted, return false to cancel the insert.
  700.         * @param {Tree} tree The owner tree
  701.         * @param {Node} this This node
  702.         * @param {Node} node The child node to be inserted
  703.         * @param {Node} refNode The child node the node is being inserted before
  704.         */
  705.        "beforeinsert" : true
  706.    });
  707.     this.listeners = this.attributes.listeners;
  708.     Ext.data.Node.superclass.constructor.call(this);
  709. };
  710. Ext.extend(Ext.data.Node, Ext.util.Observable, {
  711.     // private
  712.     fireEvent : function(evtName){
  713.         // first do standard event for this node
  714.         if(Ext.data.Node.superclass.fireEvent.apply(this, arguments) === false){
  715.             return false;
  716.         }
  717.         // then bubble it up to the tree if the event wasn't cancelled
  718.         var ot = this.getOwnerTree();
  719.         if(ot){
  720.             if(ot.proxyNodeEvent.apply(ot, arguments) === false){
  721.                 return false;
  722.             }
  723.         }
  724.         return true;
  725.     },
  726.     /**
  727.      * Returns true if this node is a leaf
  728.      * @return {Boolean}
  729.      */
  730.     isLeaf : function(){
  731.         return this.leaf === true;
  732.     },
  733.     // private
  734.     setFirstChild : function(node){
  735.         this.firstChild = node;
  736.     },
  737.     //private
  738.     setLastChild : function(node){
  739.         this.lastChild = node;
  740.     },
  741.     /**
  742.      * Returns true if this node is the last child of its parent
  743.      * @return {Boolean}
  744.      */
  745.     isLast : function(){
  746.        return (!this.parentNode ? true : this.parentNode.lastChild == this);
  747.     },
  748.     /**
  749.      * Returns true if this node is the first child of its parent
  750.      * @return {Boolean}
  751.      */
  752.     isFirst : function(){
  753.        return (!this.parentNode ? true : this.parentNode.firstChild == this);
  754.     },
  755.     /**
  756.      * Returns true if this node has one or more child nodes, else false.
  757.      * @return {Boolean}
  758.      */
  759.     hasChildNodes : function(){
  760.         return !this.isLeaf() && this.childNodes.length > 0;
  761.     },
  762.     
  763.     /**
  764.      * Returns true if this node has one or more child nodes, or if the <tt>expandable</tt>
  765.      * node attribute is explicitly specified as true (see {@link #attributes}), otherwise returns false.
  766.      * @return {Boolean}
  767.      */
  768.     isExpandable : function(){
  769.         return this.attributes.expandable || this.hasChildNodes();
  770.     },
  771.     /**
  772.      * Insert node(s) as the last child node of this node.
  773.      * @param {Node/Array} node The node or Array of nodes to append
  774.      * @return {Node} The appended node if single append, or null if an array was passed
  775.      */
  776.     appendChild : function(node){
  777.         var multi = false;
  778.         if(Ext.isArray(node)){
  779.             multi = node;
  780.         }else if(arguments.length > 1){
  781.             multi = arguments;
  782.         }
  783.         // if passed an array or multiple args do them one by one
  784.         if(multi){
  785.             for(var i = 0, len = multi.length; i < len; i++) {
  786.              this.appendChild(multi[i]);
  787.             }
  788.         }else{
  789.             if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
  790.                 return false;
  791.             }
  792.             var index = this.childNodes.length;
  793.             var oldParent = node.parentNode;
  794.             // it's a move, make sure we move it cleanly
  795.             if(oldParent){
  796.                 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
  797.                     return false;
  798.                 }
  799.                 oldParent.removeChild(node);
  800.             }
  801.             index = this.childNodes.length;
  802.             if(index === 0){
  803.                 this.setFirstChild(node);
  804.             }
  805.             this.childNodes.push(node);
  806.             node.parentNode = this;
  807.             var ps = this.childNodes[index-1];
  808.             if(ps){
  809.                 node.previousSibling = ps;
  810.                 ps.nextSibling = node;
  811.             }else{
  812.                 node.previousSibling = null;
  813.             }
  814.             node.nextSibling = null;
  815.             this.setLastChild(node);
  816.             node.setOwnerTree(this.getOwnerTree());
  817.             this.fireEvent("append", this.ownerTree, this, node, index);
  818.             if(oldParent){
  819.                 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
  820.             }
  821.             return node;
  822.         }
  823.     },
  824.     /**
  825.      * Removes a child node from this node.
  826.      * @param {Node} node The node to remove
  827.      * @return {Node} The removed node
  828.      */
  829.     removeChild : function(node){
  830.         var index = this.childNodes.indexOf(node);
  831.         if(index == -1){
  832.             return false;
  833.         }
  834.         if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
  835.             return false;
  836.         }
  837.         // remove it from childNodes collection
  838.         this.childNodes.splice(index, 1);
  839.         // update siblings
  840.         if(node.previousSibling){
  841.             node.previousSibling.nextSibling = node.nextSibling;
  842.         }
  843.         if(node.nextSibling){
  844.             node.nextSibling.previousSibling = node.previousSibling;
  845.         }
  846.         // update child refs
  847.         if(this.firstChild == node){
  848.             this.setFirstChild(node.nextSibling);
  849.         }
  850.         if(this.lastChild == node){
  851.             this.setLastChild(node.previousSibling);
  852.         }
  853.         node.setOwnerTree(null);
  854.         // clear any references from the node
  855.         node.parentNode = null;
  856.         node.previousSibling = null;
  857.         node.nextSibling = null;
  858.         this.fireEvent("remove", this.ownerTree, this, node);
  859.         return node;
  860.     },
  861.     /**
  862.      * Inserts the first node before the second node in this nodes childNodes collection.
  863.      * @param {Node} node The node to insert
  864.      * @param {Node} refNode The node to insert before (if null the node is appended)
  865.      * @return {Node} The inserted node
  866.      */
  867.     insertBefore : function(node, refNode){
  868.         if(!refNode){ // like standard Dom, refNode can be null for append
  869.             return this.appendChild(node);
  870.         }
  871.         // nothing to do
  872.         if(node == refNode){
  873.             return false;
  874.         }
  875.         if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
  876.             return false;
  877.         }
  878.         var index = this.childNodes.indexOf(refNode);
  879.         var oldParent = node.parentNode;
  880.         var refIndex = index;
  881.         // when moving internally, indexes will change after remove
  882.         if(oldParent == this && this.childNodes.indexOf(node) < index){
  883.             refIndex--;
  884.         }
  885.         // it's a move, make sure we move it cleanly
  886.         if(oldParent){
  887.             if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
  888.                 return false;
  889.             }
  890.             oldParent.removeChild(node);
  891.         }
  892.         if(refIndex === 0){
  893.             this.setFirstChild(node);
  894.         }
  895.         this.childNodes.splice(refIndex, 0, node);
  896.         node.parentNode = this;
  897.         var ps = this.childNodes[refIndex-1];
  898.         if(ps){
  899.             node.previousSibling = ps;
  900.             ps.nextSibling = node;
  901.         }else{
  902.             node.previousSibling = null;
  903.         }
  904.         node.nextSibling = refNode;
  905.         refNode.previousSibling = node;
  906.         node.setOwnerTree(this.getOwnerTree());
  907.         this.fireEvent("insert", this.ownerTree, this, node, refNode);
  908.         if(oldParent){
  909.             node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
  910.         }
  911.         return node;
  912.     },
  913.     /**
  914.      * Removes this node from its parent
  915.      * @return {Node} this
  916.      */
  917.     remove : function(){
  918.         this.parentNode.removeChild(this);
  919.         return this;
  920.     },
  921.     /**
  922.      * Returns the child node at the specified index.
  923.      * @param {Number} index
  924.      * @return {Node}
  925.      */
  926.     item : function(index){
  927.         return this.childNodes[index];
  928.     },
  929.     /**
  930.      * Replaces one child node in this node with another.
  931.      * @param {Node} newChild The replacement node
  932.      * @param {Node} oldChild The node to replace
  933.      * @return {Node} The replaced node
  934.      */
  935.     replaceChild : function(newChild, oldChild){
  936.         var s = oldChild ? oldChild.nextSibling : null;
  937.         this.removeChild(oldChild);
  938.         this.insertBefore(newChild, s);
  939.         return oldChild;
  940.     },
  941.     /**
  942.      * Returns the index of a child node
  943.      * @param {Node} node
  944.      * @return {Number} The index of the node or -1 if it was not found
  945.      */
  946.     indexOf : function(child){
  947.         return this.childNodes.indexOf(child);
  948.     },
  949.     /**
  950.      * Returns the tree this node is in.
  951.      * @return {Tree}
  952.      */
  953.     getOwnerTree : function(){
  954.         // if it doesn't have one, look for one
  955.         if(!this.ownerTree){
  956.             var p = this;
  957.             while(p){
  958.                 if(p.ownerTree){
  959.                     this.ownerTree = p.ownerTree;
  960.                     break;
  961.                 }
  962.                 p = p.parentNode;
  963.             }
  964.         }
  965.         return this.ownerTree;
  966.     },
  967.     /**
  968.      * Returns depth of this node (the root node has a depth of 0)
  969.      * @return {Number}
  970.      */
  971.     getDepth : function(){
  972.         var depth = 0;
  973.         var p = this;
  974.         while(p.parentNode){
  975.             ++depth;
  976.             p = p.parentNode;
  977.         }
  978.         return depth;
  979.     },
  980.     // private
  981.     setOwnerTree : function(tree){
  982.         // if it is a move, we need to update everyone
  983.         if(tree != this.ownerTree){
  984.             if(this.ownerTree){
  985.                 this.ownerTree.unregisterNode(this);
  986.             }
  987.             this.ownerTree = tree;
  988.             var cs = this.childNodes;
  989.             for(var i = 0, len = cs.length; i < len; i++) {
  990.              cs[i].setOwnerTree(tree);
  991.             }
  992.             if(tree){
  993.                 tree.registerNode(this);
  994.             }
  995.         }
  996.     },
  997.     
  998.     /**
  999.      * Changes the id of this node.
  1000.      * @param {String} id The new id for the node.
  1001.      */
  1002.     setId: function(id){
  1003.         if(id !== this.id){
  1004.             var t = this.ownerTree;
  1005.             if(t){
  1006.                 t.unregisterNode(this);
  1007.             }
  1008.             this.id = id;
  1009.             if(t){
  1010.                 t.registerNode(this);
  1011.             }
  1012.             this.onIdChange(id);
  1013.         }
  1014.     },
  1015.     
  1016.     // private
  1017.     onIdChange: Ext.emptyFn,
  1018.     /**
  1019.      * Returns the path for this node. The path can be used to expand or select this node programmatically.
  1020.      * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
  1021.      * @return {String} The path
  1022.      */
  1023.     getPath : function(attr){
  1024.         attr = attr || "id";
  1025.         var p = this.parentNode;
  1026.         var b = [this.attributes[attr]];
  1027.         while(p){
  1028.             b.unshift(p.attributes[attr]);
  1029.             p = p.parentNode;
  1030.         }
  1031.         var sep = this.getOwnerTree().pathSeparator;
  1032.         return sep + b.join(sep);
  1033.     },
  1034.     /**
  1035.      * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
  1036.      * function call will be the scope provided or the current node. The arguments to the function
  1037.      * will be the args provided or the current node. If the function returns false at any point,
  1038.      * the bubble is stopped.
  1039.      * @param {Function} fn The function to call
  1040.      * @param {Object} scope (optional) The scope of the function (defaults to current node)
  1041.      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
  1042.      */
  1043.     bubble : function(fn, scope, args){
  1044.         var p = this;
  1045.         while(p){
  1046.             if(fn.apply(scope || p, args || [p]) === false){
  1047.                 break;
  1048.             }
  1049.             p = p.parentNode;
  1050.         }
  1051.     },
  1052.     /**
  1053.      * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
  1054.      * function call will be the scope provided or the current node. The arguments to the function
  1055.      * will be the args provided or the current node. If the function returns false at any point,
  1056.      * the cascade is stopped on that branch.
  1057.      * @param {Function} fn The function to call
  1058.      * @param {Object} scope (optional) The scope of the function (defaults to current node)
  1059.      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
  1060.      */
  1061.     cascade : function(fn, scope, args){
  1062.         if(fn.apply(scope || this, args || [this]) !== false){
  1063.             var cs = this.childNodes;
  1064.             for(var i = 0, len = cs.length; i < len; i++) {
  1065.              cs[i].cascade(fn, scope, args);
  1066.             }
  1067.         }
  1068.     },
  1069.     /**
  1070.      * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
  1071.      * function call will be the scope provided or the current node. The arguments to the function
  1072.      * will be the args provided or the current node. If the function returns false at any point,
  1073.      * the iteration stops.
  1074.      * @param {Function} fn The function to call
  1075.      * @param {Object} scope (optional) The scope of the function (defaults to current node)
  1076.      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
  1077.      */
  1078.     eachChild : function(fn, scope, args){
  1079.         var cs = this.childNodes;
  1080.         for(var i = 0, len = cs.length; i < len; i++) {
  1081.          if(fn.apply(scope || this, args || [cs[i]]) === false){
  1082.              break;
  1083.          }
  1084.         }
  1085.     },
  1086.     /**
  1087.      * Finds the first child that has the attribute with the specified value.
  1088.      * @param {String} attribute The attribute name
  1089.      * @param {Mixed} value The value to search for
  1090.      * @return {Node} The found child or null if none was found
  1091.      */
  1092.     findChild : function(attribute, value){
  1093.         var cs = this.childNodes;
  1094.         for(var i = 0, len = cs.length; i < len; i++) {
  1095.          if(cs[i].attributes[attribute] == value){
  1096.              return cs[i];
  1097.          }
  1098.         }
  1099.         return null;
  1100.     },
  1101.     /**
  1102.      * Finds the first child by a custom function. The child matches if the function passed
  1103.      * returns true.
  1104.      * @param {Function} fn
  1105.      * @param {Object} scope (optional)
  1106.      * @return {Node} The found child or null if none was found
  1107.      */
  1108.     findChildBy : function(fn, scope){
  1109.         var cs = this.childNodes;
  1110.         for(var i = 0, len = cs.length; i < len; i++) {
  1111.          if(fn.call(scope||cs[i], cs[i]) === true){
  1112.              return cs[i];
  1113.          }
  1114.         }
  1115.         return null;
  1116.     },
  1117.     /**
  1118.      * Sorts this nodes children using the supplied sort function
  1119.      * @param {Function} fn
  1120.      * @param {Object} scope (optional)
  1121.      */
  1122.     sort : function(fn, scope){
  1123.         var cs = this.childNodes;
  1124.         var len = cs.length;
  1125.         if(len > 0){
  1126.             var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
  1127.             cs.sort(sortFn);
  1128.             for(var i = 0; i < len; i++){
  1129.                 var n = cs[i];
  1130.                 n.previousSibling = cs[i-1];
  1131.                 n.nextSibling = cs[i+1];
  1132.                 if(i === 0){
  1133.                     this.setFirstChild(n);
  1134.                 }
  1135.                 if(i == len-1){
  1136.                     this.setLastChild(n);
  1137.                 }
  1138.             }
  1139.         }
  1140.     },
  1141.     /**
  1142.      * Returns true if this node is an ancestor (at any point) of the passed node.
  1143.      * @param {Node} node
  1144.      * @return {Boolean}
  1145.      */
  1146.     contains : function(node){
  1147.         return node.isAncestor(this);
  1148.     },
  1149.     /**
  1150.      * Returns true if the passed node is an ancestor (at any point) of this node.
  1151.      * @param {Node} node
  1152.      * @return {Boolean}
  1153.      */
  1154.     isAncestor : function(node){
  1155.         var p = this.parentNode;
  1156.         while(p){
  1157.             if(p == node){
  1158.                 return true;
  1159.             }
  1160.             p = p.parentNode;
  1161.         }
  1162.         return false;
  1163.     },
  1164.     toString : function(){
  1165.         return "[Node"+(this.id?" "+this.id:"")+"]";
  1166.     }
  1167. });/**
  1168.  * @class Ext.tree.TreeNode
  1169.  * @extends Ext.data.Node
  1170.  * @cfg {String} text The text for this node
  1171.  * @cfg {Boolean} expanded true to start the node expanded
  1172.  * @cfg {Boolean} allowDrag False to make this node undraggable if {@link #draggable} = true (defaults to true)
  1173.  * @cfg {Boolean} allowDrop False if this node cannot have child nodes dropped on it (defaults to true)
  1174.  * @cfg {Boolean} disabled true to start the node disabled
  1175.  * @cfg {String} icon The path to an icon for the node. The preferred way to do this
  1176.  * is to use the cls or iconCls attributes and add the icon via a CSS background image.
  1177.  * @cfg {String} cls A css class to be added to the node
  1178.  * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
  1179.  * @cfg {String} href URL of the link used for the node (defaults to #)
  1180.  * @cfg {String} hrefTarget target frame for the link
  1181.  * @cfg {Boolean} hidden True to render hidden. (Defaults to false).
  1182.  * @cfg {String} qtip An Ext QuickTip for the node
  1183.  * @cfg {Boolean} expandable If set to true, the node will always show a plus/minus icon, even when empty
  1184.  * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
  1185.  * @cfg {Boolean} singleClickExpand True for single click expand on this node
  1186.  * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Ext.tree.TreeNodeUI)
  1187.  * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
  1188.  * (defaults to undefined with no checkbox rendered)
  1189.  * @cfg {Boolean} draggable True to make this node draggable (defaults to false)
  1190.  * @cfg {Boolean} isTarget False to not allow this node to act as a drop target (defaults to true)
  1191.  * @cfg {Boolean} allowChildren False to not allow this node to have child nodes (defaults to true)
  1192.  * @cfg {Boolean} editable False to not allow this node to be edited by an (@link Ext.tree.TreeEditor} (defaults to true)
  1193.  * @constructor
  1194.  * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
  1195.  */
  1196. Ext.tree.TreeNode = function(attributes){
  1197.     attributes = attributes || {};
  1198.     if(typeof attributes == "string"){
  1199.         attributes = {text: attributes};
  1200.     }
  1201.     this.childrenRendered = false;
  1202.     this.rendered = false;
  1203.     Ext.tree.TreeNode.superclass.constructor.call(this, attributes);
  1204.     this.expanded = attributes.expanded === true;
  1205.     this.isTarget = attributes.isTarget !== false;
  1206.     this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
  1207.     this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
  1208.     /**
  1209.      * Read-only. The text for this node. To change it use setText().
  1210.      * @type String
  1211.      */
  1212.     this.text = attributes.text;
  1213.     /**
  1214.      * True if this node is disabled.
  1215.      * @type Boolean
  1216.      */
  1217.     this.disabled = attributes.disabled === true;
  1218.     /**
  1219.      * True if this node is hidden.
  1220.      * @type Boolean
  1221.      */
  1222.     this.hidden = attributes.hidden === true;
  1223.     this.addEvents(
  1224.         /**
  1225.         * @event textchange
  1226.         * Fires when the text for this node is changed
  1227.         * @param {Node} this This node
  1228.         * @param {String} text The new text
  1229.         * @param {String} oldText The old text
  1230.         */
  1231.         "textchange",
  1232.         /**
  1233.         * @event beforeexpand
  1234.         * Fires before this node is expanded, return false to cancel.
  1235.         * @param {Node} this This node
  1236.         * @param {Boolean} deep
  1237.         * @param {Boolean} anim
  1238.         */
  1239.         "beforeexpand",
  1240.         /**
  1241.         * @event beforecollapse
  1242.         * Fires before this node is collapsed, return false to cancel.
  1243.         * @param {Node} this This node
  1244.         * @param {Boolean} deep
  1245.         * @param {Boolean} anim
  1246.         */
  1247.         "beforecollapse",
  1248.         /**
  1249.         * @event expand
  1250.         * Fires when this node is expanded
  1251.         * @param {Node} this This node
  1252.         */
  1253.         "expand",
  1254.         /**
  1255.         * @event disabledchange
  1256.         * Fires when the disabled status of this node changes
  1257.         * @param {Node} this This node
  1258.         * @param {Boolean} disabled
  1259.         */
  1260.         "disabledchange",
  1261.         /**
  1262.         * @event collapse
  1263.         * Fires when this node is collapsed
  1264.         * @param {Node} this This node
  1265.         */
  1266.         "collapse",
  1267.         /**
  1268.         * @event beforeclick
  1269.         * Fires before click processing. Return false to cancel the default action.
  1270.         * @param {Node} this This node
  1271.         * @param {Ext.EventObject} e The event object
  1272.         */
  1273.         "beforeclick",
  1274.         /**
  1275.         * @event click
  1276.         * Fires when this node is clicked
  1277.         * @param {Node} this This node
  1278.         * @param {Ext.EventObject} e The event object
  1279.         */
  1280.         "click",
  1281.         /**
  1282.         * @event checkchange
  1283.         * Fires when a node with a checkbox's checked property changes
  1284.         * @param {Node} this This node
  1285.         * @param {Boolean} checked
  1286.         */
  1287.         "checkchange",
  1288.         /**
  1289.         * @event dblclick
  1290.         * Fires when this node is double clicked
  1291.         * @param {Node} this This node
  1292.         * @param {Ext.EventObject} e The event object
  1293.         */
  1294.         "dblclick",
  1295.         /**
  1296.         * @event contextmenu
  1297.         * Fires when this node is right clicked
  1298.         * @param {Node} this This node
  1299.         * @param {Ext.EventObject} e The event object
  1300.         */
  1301.         "contextmenu",
  1302.         /**
  1303.         * @event beforechildrenrendered
  1304.         * Fires right before the child nodes for this node are rendered
  1305.         * @param {Node} this This node
  1306.         */
  1307.         "beforechildrenrendered"
  1308.     );
  1309.     var uiClass = this.attributes.uiProvider || this.defaultUI || Ext.tree.TreeNodeUI;
  1310.     /**
  1311.      * Read-only. The UI for this node
  1312.      * @type TreeNodeUI
  1313.      */
  1314.     this.ui = new uiClass(this);
  1315. };
  1316. Ext.extend(Ext.tree.TreeNode, Ext.data.Node, {
  1317.     preventHScroll: true,
  1318.     /**
  1319.      * Returns true if this node is expanded
  1320.      * @return {Boolean}
  1321.      */
  1322.     isExpanded : function(){
  1323.         return this.expanded;
  1324.     },
  1325. /**
  1326.  * Returns the UI object for this node.
  1327.  * @return {TreeNodeUI} The object which is providing the user interface for this tree
  1328.  * node. Unless otherwise specified in the {@link #uiProvider}, this will be an instance
  1329.  * of {@link Ext.tree.TreeNodeUI}
  1330.  */
  1331.     getUI : function(){
  1332.         return this.ui;
  1333.     },
  1334.     getLoader : function(){
  1335.         var owner;
  1336.         return this.loader || ((owner = this.getOwnerTree()) && owner.loader ? owner.loader : new Ext.tree.TreeLoader());
  1337.     },
  1338.     // private override
  1339.     setFirstChild : function(node){
  1340.         var of = this.firstChild;
  1341.         Ext.tree.TreeNode.superclass.setFirstChild.call(this, node);
  1342.         if(this.childrenRendered && of && node != of){
  1343.             of.renderIndent(true, true);
  1344.         }
  1345.         if(this.rendered){
  1346.             this.renderIndent(true, true);
  1347.         }
  1348.     },
  1349.     // private override
  1350.     setLastChild : function(node){
  1351.         var ol = this.lastChild;
  1352.         Ext.tree.TreeNode.superclass.setLastChild.call(this, node);
  1353.         if(this.childrenRendered && ol && node != ol){
  1354.             ol.renderIndent(true, true);
  1355.         }
  1356.         if(this.rendered){
  1357.             this.renderIndent(true, true);
  1358.         }
  1359.     },
  1360.     // these methods are overridden to provide lazy rendering support
  1361.     // private override
  1362.     appendChild : function(n){
  1363.         if(!n.render && !Ext.isArray(n)){
  1364.             n = this.getLoader().createNode(n);
  1365.         }
  1366.         var node = Ext.tree.TreeNode.superclass.appendChild.call(this, n);
  1367.         if(node && this.childrenRendered){
  1368.             node.render();
  1369.         }
  1370.         this.ui.updateExpandIcon();
  1371.         return node;
  1372.     },
  1373.     // private override
  1374.     removeChild : function(node){
  1375.         this.ownerTree.getSelectionModel().unselect(node);
  1376.         Ext.tree.TreeNode.superclass.removeChild.apply(this, arguments);
  1377.         // if it's been rendered remove dom node
  1378.         if(this.childrenRendered){
  1379.             node.ui.remove();
  1380.         }
  1381.         if(this.childNodes.length < 1){
  1382.             this.collapse(false, false);
  1383.         }else{
  1384.             this.ui.updateExpandIcon();
  1385.         }
  1386.         if(!this.firstChild && !this.isHiddenRoot()) {
  1387.             this.childrenRendered = false;
  1388.         }
  1389.         return node;
  1390.     },
  1391.     // private override
  1392.     insertBefore : function(node, refNode){
  1393.         if(!node.render){ 
  1394.             node = this.getLoader().createNode(node);
  1395.         }
  1396.         var newNode = Ext.tree.TreeNode.superclass.insertBefore.call(this, node, refNode);
  1397.         if(newNode && refNode && this.childrenRendered){
  1398.             node.render();
  1399.         }
  1400.         this.ui.updateExpandIcon();
  1401.         return newNode;
  1402.     },
  1403.     /**
  1404.      * Sets the text for this node
  1405.      * @param {String} text
  1406.      */
  1407.     setText : function(text){
  1408.         var oldText = this.text;
  1409.         this.text = text;
  1410.         this.attributes.text = text;
  1411.         if(this.rendered){ // event without subscribing
  1412.             this.ui.onTextChange(this, text, oldText);
  1413.         }
  1414.         this.fireEvent("textchange", this, text, oldText);
  1415.     },
  1416.     /**
  1417.      * Triggers selection of this node
  1418.      */
  1419.     select : function(){
  1420.         this.getOwnerTree().getSelectionModel().select(this);
  1421.     },
  1422.     /**
  1423.      * Triggers deselection of this node
  1424.      */
  1425.     unselect : function(){
  1426.         this.getOwnerTree().getSelectionModel().unselect(this);
  1427.     },
  1428.     /**
  1429.      * Returns true if this node is selected
  1430.      * @return {Boolean}
  1431.      */
  1432.     isSelected : function(){
  1433.         return this.getOwnerTree().getSelectionModel().isSelected(this);
  1434.     },
  1435.     /**
  1436.      * Expand this node.
  1437.      * @param {Boolean} deep (optional) True to expand all children as well
  1438.      * @param {Boolean} anim (optional) false to cancel the default animation
  1439.      * @param {Function} callback (optional) A callback to be called when
  1440.      * expanding this node completes (does not wait for deep expand to complete).
  1441.      * Called with 1 parameter, this node.
  1442.      * @param {Object} scope (optional) The scope in which to execute the callback.
  1443.      */
  1444.     expand : function(deep, anim, callback, scope){
  1445.         if(!this.expanded){
  1446.             if(this.fireEvent("beforeexpand", this, deep, anim) === false){
  1447.                 return;
  1448.             }
  1449.             if(!this.childrenRendered){
  1450.                 this.renderChildren();
  1451.             }
  1452.             this.expanded = true;
  1453.             if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
  1454.                 this.ui.animExpand(function(){
  1455.                     this.fireEvent("expand", this);
  1456.                     this.runCallback(callback, scope || this, [this]);
  1457.                     if(deep === true){
  1458.                         this.expandChildNodes(true);
  1459.                     }
  1460.                 }.createDelegate(this));
  1461.                 return;
  1462.             }else{
  1463.                 this.ui.expand();
  1464.                 this.fireEvent("expand", this);
  1465.                 this.runCallback(callback, scope || this, [this]);
  1466.             }
  1467.         }else{
  1468.            this.runCallback(callback, scope || this, [this]);
  1469.         }
  1470.         if(deep === true){
  1471.             this.expandChildNodes(true);
  1472.         }
  1473.     },
  1474.     
  1475.     runCallback: function(cb, scope, args){
  1476.         if(Ext.isFunction(cb)){
  1477.             cb.apply(scope, args);
  1478.         }
  1479.     },
  1480.     isHiddenRoot : function(){
  1481.         return this.isRoot && !this.getOwnerTree().rootVisible;
  1482.     },
  1483.     /**
  1484.      * Collapse this node.
  1485.      * @param {Boolean} deep (optional) True to collapse all children as well
  1486.      * @param {Boolean} anim (optional) false to cancel the default animation
  1487.      * @param {Function} callback (optional) A callback to be called when
  1488.      * expanding this node completes (does not wait for deep expand to complete).
  1489.      * Called with 1 parameter, this node.
  1490.      * @param {Object} scope (optional) The scope in which to execute the callback.
  1491.      */
  1492.     collapse : function(deep, anim, callback, scope){
  1493.         if(this.expanded && !this.isHiddenRoot()){
  1494.             if(this.fireEvent("beforecollapse", this, deep, anim) === false){
  1495.                 return;
  1496.             }
  1497.             this.expanded = false;
  1498.             if((this.getOwnerTree().animate && anim !== false) || anim){
  1499.                 this.ui.animCollapse(function(){
  1500.                     this.fireEvent("collapse", this);
  1501.                     this.runCallback(callback, scope || this, [this]);
  1502.                     if(deep === true){
  1503.                         this.collapseChildNodes(true);
  1504.                     }
  1505.                 }.createDelegate(this));
  1506.                 return;
  1507.             }else{
  1508.                 this.ui.collapse();
  1509.                 this.fireEvent("collapse", this);
  1510.                 this.runCallback(callback, scope || this, [this]);
  1511.             }
  1512.         }else if(!this.expanded){
  1513.             this.runCallback(callback, scope || this, [this]);
  1514.         }
  1515.         if(deep === true){
  1516.             var cs = this.childNodes;
  1517.             for(var i = 0, len = cs.length; i < len; i++) {
  1518.              cs[i].collapse(true, false);
  1519.             }
  1520.         }
  1521.     },
  1522.     // private
  1523.     delayedExpand : function(delay){
  1524.         if(!this.expandProcId){
  1525.             this.expandProcId = this.expand.defer(delay, this);
  1526.         }
  1527.     },
  1528.     // private
  1529.     cancelExpand : function(){
  1530.         if(this.expandProcId){
  1531.             clearTimeout(this.expandProcId);
  1532.         }
  1533.         this.expandProcId = false;
  1534.     },
  1535.     /**
  1536.      * Toggles expanded/collapsed state of the node
  1537.      */
  1538.     toggle : function(){
  1539.         if(this.expanded){
  1540.             this.collapse();
  1541.         }else{
  1542.             this.expand();