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

JavaScript

开发平台:

JavaScript

  1.          if(fn.call(scope||cs[i], cs[i]) === true){
  2.              return cs[i];
  3.          }
  4.         }
  5.         return null;
  6.     },
  7.     /**
  8.      * Sorts this nodes children using the supplied sort function.
  9.      * @param {Function} fn A function which, when passed two Nodes, returns -1, 0 or 1 depending upon required sort order.
  10.      * @param {Object} scope (optional)The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
  11.      */
  12.     sort : function(fn, scope){
  13.         var cs = this.childNodes;
  14.         var len = cs.length;
  15.         if(len > 0){
  16.             var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
  17.             cs.sort(sortFn);
  18.             for(var i = 0; i < len; i++){
  19.                 var n = cs[i];
  20.                 n.previousSibling = cs[i-1];
  21.                 n.nextSibling = cs[i+1];
  22.                 if(i === 0){
  23.                     this.setFirstChild(n);
  24.                 }
  25.                 if(i == len-1){
  26.                     this.setLastChild(n);
  27.                 }
  28.             }
  29.         }
  30.     },
  31.     /**
  32.      * Returns true if this node is an ancestor (at any point) of the passed node.
  33.      * @param {Node} node
  34.      * @return {Boolean}
  35.      */
  36.     contains : function(node){
  37.         return node.isAncestor(this);
  38.     },
  39.     /**
  40.      * Returns true if the passed node is an ancestor (at any point) of this node.
  41.      * @param {Node} node
  42.      * @return {Boolean}
  43.      */
  44.     isAncestor : function(node){
  45.         var p = this.parentNode;
  46.         while(p){
  47.             if(p == node){
  48.                 return true;
  49.             }
  50.             p = p.parentNode;
  51.         }
  52.         return false;
  53.     },
  54.     toString : function(){
  55.         return "[Node"+(this.id?" "+this.id:"")+"]";
  56.     }
  57. });/**
  58.  * @class Ext.tree.TreeNode
  59.  * @extends Ext.data.Node
  60.  * @cfg {String} text The text for this node
  61.  * @cfg {Boolean} expanded true to start the node expanded
  62.  * @cfg {Boolean} allowDrag False to make this node undraggable if {@link #draggable} = true (defaults to true)
  63.  * @cfg {Boolean} allowDrop False if this node cannot have child nodes dropped on it (defaults to true)
  64.  * @cfg {Boolean} disabled true to start the node disabled
  65.  * @cfg {String} icon The path to an icon for the node. The preferred way to do this
  66.  * is to use the cls or iconCls attributes and add the icon via a CSS background image.
  67.  * @cfg {String} cls A css class to be added to the node
  68.  * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
  69.  * @cfg {String} href URL of the link used for the node (defaults to #)
  70.  * @cfg {String} hrefTarget target frame for the link
  71.  * @cfg {Boolean} hidden True to render hidden. (Defaults to false).
  72.  * @cfg {String} qtip An Ext QuickTip for the node
  73.  * @cfg {Boolean} expandable If set to true, the node will always show a plus/minus icon, even when empty
  74.  * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
  75.  * @cfg {Boolean} singleClickExpand True for single click expand on this node
  76.  * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Ext.tree.TreeNodeUI)
  77.  * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
  78.  * (defaults to undefined with no checkbox rendered)
  79.  * @cfg {Boolean} draggable True to make this node draggable (defaults to false)
  80.  * @cfg {Boolean} isTarget False to not allow this node to act as a drop target (defaults to true)
  81.  * @cfg {Boolean} allowChildren False to not allow this node to have child nodes (defaults to true)
  82.  * @cfg {Boolean} editable False to not allow this node to be edited by an {@link Ext.tree.TreeEditor} (defaults to true)
  83.  * @constructor
  84.  * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
  85.  */
  86. Ext.tree.TreeNode = function(attributes){
  87.     attributes = attributes || {};
  88.     if(Ext.isString(attributes)){
  89.         attributes = {text: attributes};
  90.     }
  91.     this.childrenRendered = false;
  92.     this.rendered = false;
  93.     Ext.tree.TreeNode.superclass.constructor.call(this, attributes);
  94.     this.expanded = attributes.expanded === true;
  95.     this.isTarget = attributes.isTarget !== false;
  96.     this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
  97.     this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
  98.     /**
  99.      * Read-only. The text for this node. To change it use <code>{@link #setText}</code>.
  100.      * @type String
  101.      */
  102.     this.text = attributes.text;
  103.     /**
  104.      * True if this node is disabled.
  105.      * @type Boolean
  106.      */
  107.     this.disabled = attributes.disabled === true;
  108.     /**
  109.      * True if this node is hidden.
  110.      * @type Boolean
  111.      */
  112.     this.hidden = attributes.hidden === true;
  113.     this.addEvents(
  114.         /**
  115.         * @event textchange
  116.         * Fires when the text for this node is changed
  117.         * @param {Node} this This node
  118.         * @param {String} text The new text
  119.         * @param {String} oldText The old text
  120.         */
  121.         'textchange',
  122.         /**
  123.         * @event beforeexpand
  124.         * Fires before this node is expanded, return false to cancel.
  125.         * @param {Node} this This node
  126.         * @param {Boolean} deep
  127.         * @param {Boolean} anim
  128.         */
  129.         'beforeexpand',
  130.         /**
  131.         * @event beforecollapse
  132.         * Fires before this node is collapsed, return false to cancel.
  133.         * @param {Node} this This node
  134.         * @param {Boolean} deep
  135.         * @param {Boolean} anim
  136.         */
  137.         'beforecollapse',
  138.         /**
  139.         * @event expand
  140.         * Fires when this node is expanded
  141.         * @param {Node} this This node
  142.         */
  143.         'expand',
  144.         /**
  145.         * @event disabledchange
  146.         * Fires when the disabled status of this node changes
  147.         * @param {Node} this This node
  148.         * @param {Boolean} disabled
  149.         */
  150.         'disabledchange',
  151.         /**
  152.         * @event collapse
  153.         * Fires when this node is collapsed
  154.         * @param {Node} this This node
  155.         */
  156.         'collapse',
  157.         /**
  158.         * @event beforeclick
  159.         * Fires before click processing. Return false to cancel the default action.
  160.         * @param {Node} this This node
  161.         * @param {Ext.EventObject} e The event object
  162.         */
  163.         'beforeclick',
  164.         /**
  165.         * @event click
  166.         * Fires when this node is clicked
  167.         * @param {Node} this This node
  168.         * @param {Ext.EventObject} e The event object
  169.         */
  170.         'click',
  171.         /**
  172.         * @event checkchange
  173.         * Fires when a node with a checkbox's checked property changes
  174.         * @param {Node} this This node
  175.         * @param {Boolean} checked
  176.         */
  177.         'checkchange',
  178.         /**
  179.         * @event beforedblclick
  180.         * Fires before double click processing. Return false to cancel the default action.
  181.         * @param {Node} this This node
  182.         * @param {Ext.EventObject} e The event object
  183.         */
  184.         'beforedblclick',
  185.         /**
  186.         * @event dblclick
  187.         * Fires when this node is double clicked
  188.         * @param {Node} this This node
  189.         * @param {Ext.EventObject} e The event object
  190.         */
  191.         'dblclick',
  192.         /**
  193.         * @event contextmenu
  194.         * Fires when this node is right clicked
  195.         * @param {Node} this This node
  196.         * @param {Ext.EventObject} e The event object
  197.         */
  198.         'contextmenu',
  199.         /**
  200.         * @event beforechildrenrendered
  201.         * Fires right before the child nodes for this node are rendered
  202.         * @param {Node} this This node
  203.         */
  204.         'beforechildrenrendered'
  205.     );
  206.     var uiClass = this.attributes.uiProvider || this.defaultUI || Ext.tree.TreeNodeUI;
  207.     /**
  208.      * Read-only. The UI for this node
  209.      * @type TreeNodeUI
  210.      */
  211.     this.ui = new uiClass(this);
  212. };
  213. Ext.extend(Ext.tree.TreeNode, Ext.data.Node, {
  214.     preventHScroll : true,
  215.     /**
  216.      * Returns true if this node is expanded
  217.      * @return {Boolean}
  218.      */
  219.     isExpanded : function(){
  220.         return this.expanded;
  221.     },
  222. /**
  223.  * Returns the UI object for this node.
  224.  * @return {TreeNodeUI} The object which is providing the user interface for this tree
  225.  * node. Unless otherwise specified in the {@link #uiProvider}, this will be an instance
  226.  * of {@link Ext.tree.TreeNodeUI}
  227.  */
  228.     getUI : function(){
  229.         return this.ui;
  230.     },
  231.     getLoader : function(){
  232.         var owner;
  233.         return this.loader || ((owner = this.getOwnerTree()) && owner.loader ? owner.loader : (this.loader = new Ext.tree.TreeLoader()));
  234.     },
  235.     // private override
  236.     setFirstChild : function(node){
  237.         var of = this.firstChild;
  238.         Ext.tree.TreeNode.superclass.setFirstChild.call(this, node);
  239.         if(this.childrenRendered && of && node != of){
  240.             of.renderIndent(true, true);
  241.         }
  242.         if(this.rendered){
  243.             this.renderIndent(true, true);
  244.         }
  245.     },
  246.     // private override
  247.     setLastChild : function(node){
  248.         var ol = this.lastChild;
  249.         Ext.tree.TreeNode.superclass.setLastChild.call(this, node);
  250.         if(this.childrenRendered && ol && node != ol){
  251.             ol.renderIndent(true, true);
  252.         }
  253.         if(this.rendered){
  254.             this.renderIndent(true, true);
  255.         }
  256.     },
  257.     // these methods are overridden to provide lazy rendering support
  258.     // private override
  259.     appendChild : function(n){
  260.         if(!n.render && !Ext.isArray(n)){
  261.             n = this.getLoader().createNode(n);
  262.         }
  263.         var node = Ext.tree.TreeNode.superclass.appendChild.call(this, n);
  264.         if(node && this.childrenRendered){
  265.             node.render();
  266.         }
  267.         this.ui.updateExpandIcon();
  268.         return node;
  269.     },
  270.     // private override
  271.     removeChild : function(node, destroy){
  272.         this.ownerTree.getSelectionModel().unselect(node);
  273.         Ext.tree.TreeNode.superclass.removeChild.apply(this, arguments);
  274.         // if it's been rendered remove dom node
  275.         if(node.ui.rendered){
  276.             node.ui.remove();
  277.         }
  278.         if(this.childNodes.length < 1){
  279.             this.collapse(false, false);
  280.         }else{
  281.             this.ui.updateExpandIcon();
  282.         }
  283.         if(!this.firstChild && !this.isHiddenRoot()) {
  284.             this.childrenRendered = false;
  285.         }
  286.         return node;
  287.     },
  288.     // private override
  289.     insertBefore : function(node, refNode){
  290.         if(!node.render){
  291.             node = this.getLoader().createNode(node);
  292.         }
  293.         var newNode = Ext.tree.TreeNode.superclass.insertBefore.call(this, node, refNode);
  294.         if(newNode && refNode && this.childrenRendered){
  295.             node.render();
  296.         }
  297.         this.ui.updateExpandIcon();
  298.         return newNode;
  299.     },
  300.     /**
  301.      * Sets the text for this node
  302.      * @param {String} text
  303.      */
  304.     setText : function(text){
  305.         var oldText = this.text;
  306.         this.text = this.attributes.text = text;
  307.         if(this.rendered){ // event without subscribing
  308.             this.ui.onTextChange(this, text, oldText);
  309.         }
  310.         this.fireEvent('textchange', this, text, oldText);
  311.     },
  312.     /**
  313.      * Triggers selection of this node
  314.      */
  315.     select : function(){
  316.         var t = this.getOwnerTree();
  317.         if(t){
  318.             t.getSelectionModel().select(this);
  319.         }
  320.     },
  321.     /**
  322.      * Triggers deselection of this node
  323.      * @param {Boolean} silent (optional) True to stop selection change events from firing.
  324.      */
  325.     unselect : function(silent){
  326.         var t = this.getOwnerTree();
  327.         if(t){
  328.             t.getSelectionModel().unselect(this, silent);
  329.         }
  330.     },
  331.     /**
  332.      * Returns true if this node is selected
  333.      * @return {Boolean}
  334.      */
  335.     isSelected : function(){
  336.         var t = this.getOwnerTree();
  337.         return t ? t.getSelectionModel().isSelected(this) : false;
  338.     },
  339.     /**
  340.      * Expand this node.
  341.      * @param {Boolean} deep (optional) True to expand all children as well
  342.      * @param {Boolean} anim (optional) false to cancel the default animation
  343.      * @param {Function} callback (optional) A callback to be called when
  344.      * expanding this node completes (does not wait for deep expand to complete).
  345.      * Called with 1 parameter, this node.
  346.      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this TreeNode.
  347.      */
  348.     expand : function(deep, anim, callback, scope){
  349.         if(!this.expanded){
  350.             if(this.fireEvent('beforeexpand', this, deep, anim) === false){
  351.                 return;
  352.             }
  353.             if(!this.childrenRendered){
  354.                 this.renderChildren();
  355.             }
  356.             this.expanded = true;
  357.             if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
  358.                 this.ui.animExpand(function(){
  359.                     this.fireEvent('expand', this);
  360.                     this.runCallback(callback, scope || this, [this]);
  361.                     if(deep === true){
  362.                         this.expandChildNodes(true);
  363.                     }
  364.                 }.createDelegate(this));
  365.                 return;
  366.             }else{
  367.                 this.ui.expand();
  368.                 this.fireEvent('expand', this);
  369.                 this.runCallback(callback, scope || this, [this]);
  370.             }
  371.         }else{
  372.            this.runCallback(callback, scope || this, [this]);
  373.         }
  374.         if(deep === true){
  375.             this.expandChildNodes(true);
  376.         }
  377.     },
  378.     runCallback : function(cb, scope, args){
  379.         if(Ext.isFunction(cb)){
  380.             cb.apply(scope, args);
  381.         }
  382.     },
  383.     isHiddenRoot : function(){
  384.         return this.isRoot && !this.getOwnerTree().rootVisible;
  385.     },
  386.     /**
  387.      * Collapse this node.
  388.      * @param {Boolean} deep (optional) True to collapse all children as well
  389.      * @param {Boolean} anim (optional) false to cancel the default animation
  390.      * @param {Function} callback (optional) A callback to be called when
  391.      * expanding this node completes (does not wait for deep expand to complete).
  392.      * Called with 1 parameter, this node.
  393.      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this TreeNode.
  394.      */
  395.     collapse : function(deep, anim, callback, scope){
  396.         if(this.expanded && !this.isHiddenRoot()){
  397.             if(this.fireEvent('beforecollapse', this, deep, anim) === false){
  398.                 return;
  399.             }
  400.             this.expanded = false;
  401.             if((this.getOwnerTree().animate && anim !== false) || anim){
  402.                 this.ui.animCollapse(function(){
  403.                     this.fireEvent('collapse', this);
  404.                     this.runCallback(callback, scope || this, [this]);
  405.                     if(deep === true){
  406.                         this.collapseChildNodes(true);
  407.                     }
  408.                 }.createDelegate(this));
  409.                 return;
  410.             }else{
  411.                 this.ui.collapse();
  412.                 this.fireEvent('collapse', this);
  413.                 this.runCallback(callback, scope || this, [this]);
  414.             }
  415.         }else if(!this.expanded){
  416.             this.runCallback(callback, scope || this, [this]);
  417.         }
  418.         if(deep === true){
  419.             var cs = this.childNodes;
  420.             for(var i = 0, len = cs.length; i < len; i++) {
  421.              cs[i].collapse(true, false);
  422.             }
  423.         }
  424.     },
  425.     // private
  426.     delayedExpand : function(delay){
  427.         if(!this.expandProcId){
  428.             this.expandProcId = this.expand.defer(delay, this);
  429.         }
  430.     },
  431.     // private
  432.     cancelExpand : function(){
  433.         if(this.expandProcId){
  434.             clearTimeout(this.expandProcId);
  435.         }
  436.         this.expandProcId = false;
  437.     },
  438.     /**
  439.      * Toggles expanded/collapsed state of the node
  440.      */
  441.     toggle : function(){
  442.         if(this.expanded){
  443.             this.collapse();
  444.         }else{
  445.             this.expand();
  446.         }
  447.     },
  448.     /**
  449.      * Ensures all parent nodes are expanded, and if necessary, scrolls
  450.      * the node into view.
  451.      * @param {Function} callback (optional) A function to call when the node has been made visible.
  452.      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this TreeNode.
  453.      */
  454.     ensureVisible : function(callback, scope){
  455.         var tree = this.getOwnerTree();
  456.         tree.expandPath(this.parentNode ? this.parentNode.getPath() : this.getPath(), false, function(){
  457.             var node = tree.getNodeById(this.id);  // Somehow if we don't do this, we lose changes that happened to node in the meantime
  458.             tree.getTreeEl().scrollChildIntoView(node.ui.anchor);
  459.             this.runCallback(callback, scope || this, [this]);
  460.         }.createDelegate(this));
  461.     },
  462.     /**
  463.      * Expand all child nodes
  464.      * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
  465.      */
  466.     expandChildNodes : function(deep){
  467.         var cs = this.childNodes;
  468.         for(var i = 0, len = cs.length; i < len; i++) {
  469.          cs[i].expand(deep);
  470.         }
  471.     },
  472.     /**
  473.      * Collapse all child nodes
  474.      * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
  475.      */
  476.     collapseChildNodes : function(deep){
  477.         var cs = this.childNodes;
  478.         for(var i = 0, len = cs.length; i < len; i++) {
  479.          cs[i].collapse(deep);
  480.         }
  481.     },
  482.     /**
  483.      * Disables this node
  484.      */
  485.     disable : function(){
  486.         this.disabled = true;
  487.         this.unselect();
  488.         if(this.rendered && this.ui.onDisableChange){ // event without subscribing
  489.             this.ui.onDisableChange(this, true);
  490.         }
  491.         this.fireEvent('disabledchange', this, true);
  492.     },
  493.     /**
  494.      * Enables this node
  495.      */
  496.     enable : function(){
  497.         this.disabled = false;
  498.         if(this.rendered && this.ui.onDisableChange){ // event without subscribing
  499.             this.ui.onDisableChange(this, false);
  500.         }
  501.         this.fireEvent('disabledchange', this, false);
  502.     },
  503.     // private
  504.     renderChildren : function(suppressEvent){
  505.         if(suppressEvent !== false){
  506.             this.fireEvent('beforechildrenrendered', this);
  507.         }
  508.         var cs = this.childNodes;
  509.         for(var i = 0, len = cs.length; i < len; i++){
  510.             cs[i].render(true);
  511.         }
  512.         this.childrenRendered = true;
  513.     },
  514.     // private
  515.     sort : function(fn, scope){
  516.         Ext.tree.TreeNode.superclass.sort.apply(this, arguments);
  517.         if(this.childrenRendered){
  518.             var cs = this.childNodes;
  519.             for(var i = 0, len = cs.length; i < len; i++){
  520.                 cs[i].render(true);
  521.             }
  522.         }
  523.     },
  524.     // private
  525.     render : function(bulkRender){
  526.         this.ui.render(bulkRender);
  527.         if(!this.rendered){
  528.             // make sure it is registered
  529.             this.getOwnerTree().registerNode(this);
  530.             this.rendered = true;
  531.             if(this.expanded){
  532.                 this.expanded = false;
  533.                 this.expand(false, false);
  534.             }
  535.         }
  536.     },
  537.     // private
  538.     renderIndent : function(deep, refresh){
  539.         if(refresh){
  540.             this.ui.childIndent = null;
  541.         }
  542.         this.ui.renderIndent();
  543.         if(deep === true && this.childrenRendered){
  544.             var cs = this.childNodes;
  545.             for(var i = 0, len = cs.length; i < len; i++){
  546.                 cs[i].renderIndent(true, refresh);
  547.             }
  548.         }
  549.     },
  550.     beginUpdate : function(){
  551.         this.childrenRendered = false;
  552.     },
  553.     endUpdate : function(){
  554.         if(this.expanded && this.rendered){
  555.             this.renderChildren();
  556.         }
  557.     },
  558.     destroy : function(){
  559.         this.unselect(true);
  560.         Ext.tree.TreeNode.superclass.destroy.call(this);
  561.         Ext.destroy(this.ui, this.loader);
  562.         this.ui = this.loader = null;
  563.     },
  564.     // private
  565.     onIdChange : function(id){
  566.         this.ui.onIdChange(id);
  567.     }
  568. });
  569. Ext.tree.TreePanel.nodeTypes.node = Ext.tree.TreeNode;/**
  570.  * @class Ext.tree.AsyncTreeNode
  571.  * @extends Ext.tree.TreeNode
  572.  * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
  573.  * @constructor
  574.  * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node 
  575.  */
  576.  Ext.tree.AsyncTreeNode = function(config){
  577.     this.loaded = config && config.loaded === true;
  578.     this.loading = false;
  579.     Ext.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
  580.     /**
  581.     * @event beforeload
  582.     * Fires before this node is loaded, return false to cancel
  583.     * @param {Node} this This node
  584.     */
  585.     this.addEvents('beforeload', 'load');
  586.     /**
  587.     * @event load
  588.     * Fires when this node is loaded
  589.     * @param {Node} this This node
  590.     */
  591.     /**
  592.      * The loader used by this node (defaults to using the tree's defined loader)
  593.      * @type TreeLoader
  594.      * @property loader
  595.      */
  596. };
  597. Ext.extend(Ext.tree.AsyncTreeNode, Ext.tree.TreeNode, {
  598.     expand : function(deep, anim, callback, scope){
  599.         if(this.loading){ // if an async load is already running, waiting til it's done
  600.             var timer;
  601.             var f = function(){
  602.                 if(!this.loading){ // done loading
  603.                     clearInterval(timer);
  604.                     this.expand(deep, anim, callback, scope);
  605.                 }
  606.             }.createDelegate(this);
  607.             timer = setInterval(f, 200);
  608.             return;
  609.         }
  610.         if(!this.loaded){
  611.             if(this.fireEvent("beforeload", this) === false){
  612.                 return;
  613.             }
  614.             this.loading = true;
  615.             this.ui.beforeLoad(this);
  616.             var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
  617.             if(loader){
  618.                 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback, scope]), this);
  619.                 return;
  620.             }
  621.         }
  622.         Ext.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback, scope);
  623.     },
  624.     
  625.     /**
  626.      * Returns true if this node is currently loading
  627.      * @return {Boolean}
  628.      */
  629.     isLoading : function(){
  630.         return this.loading;  
  631.     },
  632.     
  633.     loadComplete : function(deep, anim, callback, scope){
  634.         this.loading = false;
  635.         this.loaded = true;
  636.         this.ui.afterLoad(this);
  637.         this.fireEvent("load", this);
  638.         this.expand(deep, anim, callback, scope);
  639.     },
  640.     
  641.     /**
  642.      * Returns true if this node has been loaded
  643.      * @return {Boolean}
  644.      */
  645.     isLoaded : function(){
  646.         return this.loaded;
  647.     },
  648.     
  649.     hasChildNodes : function(){
  650.         if(!this.isLeaf() && !this.loaded){
  651.             return true;
  652.         }else{
  653.             return Ext.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
  654.         }
  655.     },
  656.     /**
  657.      * Trigger a reload for this node
  658.      * @param {Function} callback
  659.      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this Node.
  660.      */
  661.     reload : function(callback, scope){
  662.         this.collapse(false, false);
  663.         while(this.firstChild){
  664.             this.removeChild(this.firstChild).destroy();
  665.         }
  666.         this.childrenRendered = false;
  667.         this.loaded = false;
  668.         if(this.isHiddenRoot()){
  669.             this.expanded = false;
  670.         }
  671.         this.expand(false, false, callback, scope);
  672.     }
  673. });
  674. Ext.tree.TreePanel.nodeTypes.async = Ext.tree.AsyncTreeNode;/**
  675.  * @class Ext.tree.TreeNodeUI
  676.  * This class provides the default UI implementation for Ext TreeNodes.
  677.  * The TreeNode UI implementation is separate from the
  678.  * tree implementation, and allows customizing of the appearance of
  679.  * tree nodes.<br>
  680.  * <p>
  681.  * If you are customizing the Tree's user interface, you
  682.  * may need to extend this class, but you should never need to instantiate this class.<br>
  683.  * <p>
  684.  * This class provides access to the user interface components of an Ext TreeNode, through
  685.  * {@link Ext.tree.TreeNode#getUI}
  686.  */
  687. Ext.tree.TreeNodeUI = function(node){
  688.     this.node = node;
  689.     this.rendered = false;
  690.     this.animating = false;
  691.     this.wasLeaf = true;
  692.     this.ecc = 'x-tree-ec-icon x-tree-elbow';
  693.     this.emptyIcon = Ext.BLANK_IMAGE_URL;
  694. };
  695. Ext.tree.TreeNodeUI.prototype = {
  696.     // private
  697.     removeChild : function(node){
  698.         if(this.rendered){
  699.             this.ctNode.removeChild(node.ui.getEl());
  700.         } 
  701.     },
  702.     // private
  703.     beforeLoad : function(){
  704.          this.addClass("x-tree-node-loading");
  705.     },
  706.     // private
  707.     afterLoad : function(){
  708.          this.removeClass("x-tree-node-loading");
  709.     },
  710.     // private
  711.     onTextChange : function(node, text, oldText){
  712.         if(this.rendered){
  713.             this.textNode.innerHTML = text;
  714.         }
  715.     },
  716.     // private
  717.     onDisableChange : function(node, state){
  718.         this.disabled = state;
  719.         if (this.checkbox) {
  720.             this.checkbox.disabled = state;
  721.         }        
  722.         if(state){
  723.             this.addClass("x-tree-node-disabled");
  724.         }else{
  725.             this.removeClass("x-tree-node-disabled");
  726.         } 
  727.     },
  728.     // private
  729.     onSelectedChange : function(state){
  730.         if(state){
  731.             this.focus();
  732.             this.addClass("x-tree-selected");
  733.         }else{
  734.             //this.blur();
  735.             this.removeClass("x-tree-selected");
  736.         }
  737.     },
  738.     // private
  739.     onMove : function(tree, node, oldParent, newParent, index, refNode){
  740.         this.childIndent = null;
  741.         if(this.rendered){
  742.             var targetNode = newParent.ui.getContainer();
  743.             if(!targetNode){//target not rendered
  744.                 this.holder = document.createElement("div");
  745.                 this.holder.appendChild(this.wrap);
  746.                 return;
  747.             }
  748.             var insertBefore = refNode ? refNode.ui.getEl() : null;
  749.             if(insertBefore){
  750.                 targetNode.insertBefore(this.wrap, insertBefore);
  751.             }else{
  752.                 targetNode.appendChild(this.wrap);
  753.             }
  754.             this.node.renderIndent(true, oldParent != newParent);
  755.         }
  756.     },
  757. /**
  758.  * Adds one or more CSS classes to the node's UI element.
  759.  * Duplicate classes are automatically filtered out.
  760.  * @param {String/Array} className The CSS class to add, or an array of classes
  761.  */
  762.     addClass : function(cls){
  763.         if(this.elNode){
  764.             Ext.fly(this.elNode).addClass(cls);
  765.         }
  766.     },
  767. /**
  768.  * Removes one or more CSS classes from the node's UI element.
  769.  * @param {String/Array} className The CSS class to remove, or an array of classes
  770.  */
  771.     removeClass : function(cls){
  772.         if(this.elNode){
  773.             Ext.fly(this.elNode).removeClass(cls);  
  774.         }
  775.     },
  776.     // private
  777.     remove : function(){
  778.         if(this.rendered){
  779.             this.holder = document.createElement("div");
  780.             this.holder.appendChild(this.wrap);
  781.         }  
  782.     },
  783.     // private
  784.     fireEvent : function(){
  785.         return this.node.fireEvent.apply(this.node, arguments);  
  786.     },
  787.     // private
  788.     initEvents : function(){
  789.         this.node.on("move", this.onMove, this);
  790.         if(this.node.disabled){
  791.             this.onDisableChange(this.node, true);            
  792.         }
  793.         if(this.node.hidden){
  794.             this.hide();
  795.         }
  796.         var ot = this.node.getOwnerTree();
  797.         var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
  798.         if(dd && (!this.node.isRoot || ot.rootVisible)){
  799.             Ext.dd.Registry.register(this.elNode, {
  800.                 node: this.node,
  801.                 handles: this.getDDHandles(),
  802.                 isHandle: false
  803.             });
  804.         }
  805.     },
  806.     // private
  807.     getDDHandles : function(){
  808.         return [this.iconNode, this.textNode, this.elNode];
  809.     },
  810. /**
  811.  * Hides this node.
  812.  */
  813.     hide : function(){
  814.         this.node.hidden = true;
  815.         if(this.wrap){
  816.             this.wrap.style.display = "none";
  817.         }
  818.     },
  819. /**
  820.  * Shows this node.
  821.  */
  822.     show : function(){
  823.         this.node.hidden = false;
  824.         if(this.wrap){
  825.             this.wrap.style.display = "";
  826.         } 
  827.     },
  828.     // private
  829.     onContextMenu : function(e){
  830.         if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
  831.             e.preventDefault();
  832.             this.focus();
  833.             this.fireEvent("contextmenu", this.node, e);
  834.         }
  835.     },
  836.     // private
  837.     onClick : function(e){
  838.         if(this.dropping){
  839.             e.stopEvent();
  840.             return;
  841.         }
  842.         if(this.fireEvent("beforeclick", this.node, e) !== false){
  843.             var a = e.getTarget('a');
  844.             if(!this.disabled && this.node.attributes.href && a){
  845.                 this.fireEvent("click", this.node, e);
  846.                 return;
  847.             }else if(a && e.ctrlKey){
  848.                 e.stopEvent();
  849.             }
  850.             e.preventDefault();
  851.             if(this.disabled){
  852.                 return;
  853.             }
  854.             if(this.node.attributes.singleClickExpand && !this.animating && this.node.isExpandable()){
  855.                 this.node.toggle();
  856.             }
  857.             this.fireEvent("click", this.node, e);
  858.         }else{
  859.             e.stopEvent();
  860.         }
  861.     },
  862.     // private
  863.     onDblClick : function(e){
  864.         e.preventDefault();
  865.         if(this.disabled){
  866.             return;
  867.         }
  868.         if(this.fireEvent("beforedblclick", this.node, e) !== false){
  869.             if(this.checkbox){
  870.                 this.toggleCheck();
  871.             }
  872.             if(!this.animating && this.node.isExpandable()){
  873.                 this.node.toggle();
  874.             }
  875.             this.fireEvent("dblclick", this.node, e);
  876.         }
  877.     },
  878.     onOver : function(e){
  879.         this.addClass('x-tree-node-over');
  880.     },
  881.     onOut : function(e){
  882.         this.removeClass('x-tree-node-over');
  883.     },
  884.     // private
  885.     onCheckChange : function(){
  886.         var checked = this.checkbox.checked;
  887.         // fix for IE6
  888.         this.checkbox.defaultChecked = checked;        
  889.         this.node.attributes.checked = checked;
  890.         this.fireEvent('checkchange', this.node, checked);
  891.     },
  892.     // private
  893.     ecClick : function(e){
  894.         if(!this.animating && this.node.isExpandable()){
  895.             this.node.toggle();
  896.         }
  897.     },
  898.     // private
  899.     startDrop : function(){
  900.         this.dropping = true;
  901.     },
  902.     
  903.     // delayed drop so the click event doesn't get fired on a drop
  904.     endDrop : function(){ 
  905.        setTimeout(function(){
  906.            this.dropping = false;
  907.        }.createDelegate(this), 50); 
  908.     },
  909.     // private
  910.     expand : function(){
  911.         this.updateExpandIcon();
  912.         this.ctNode.style.display = "";
  913.     },
  914.     // private
  915.     focus : function(){
  916.         if(!this.node.preventHScroll){
  917.             try{this.anchor.focus();
  918.             }catch(e){}
  919.         }else{
  920.             try{
  921.                 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
  922.                 var l = noscroll.scrollLeft;
  923.                 this.anchor.focus();
  924.                 noscroll.scrollLeft = l;
  925.             }catch(e){}
  926.         }
  927.     },
  928. /**
  929.  * Sets the checked status of the tree node to the passed value, or, if no value was passed,
  930.  * toggles the checked status. If the node was rendered with no checkbox, this has no effect.
  931.  * @param {Boolean} (optional) The new checked status.
  932.  */
  933.     toggleCheck : function(value){
  934.         var cb = this.checkbox;
  935.         if(cb){
  936.             cb.checked = (value === undefined ? !cb.checked : value);
  937.             this.onCheckChange();
  938.         }
  939.     },
  940.     // private
  941.     blur : function(){
  942.         try{
  943.             this.anchor.blur();
  944.         }catch(e){} 
  945.     },
  946.     // private
  947.     animExpand : function(callback){
  948.         var ct = Ext.get(this.ctNode);
  949.         ct.stopFx();
  950.         if(!this.node.isExpandable()){
  951.             this.updateExpandIcon();
  952.             this.ctNode.style.display = "";
  953.             Ext.callback(callback);
  954.             return;
  955.         }
  956.         this.animating = true;
  957.         this.updateExpandIcon();
  958.         
  959.         ct.slideIn('t', {
  960.            callback : function(){
  961.                this.animating = false;
  962.                Ext.callback(callback);
  963.             },
  964.             scope: this,
  965.             duration: this.node.ownerTree.duration || .25
  966.         });
  967.     },
  968.     // private
  969.     highlight : function(){
  970.         var tree = this.node.getOwnerTree();
  971.         Ext.fly(this.wrap).highlight(
  972.             tree.hlColor || "C3DAF9",
  973.             {endColor: tree.hlBaseColor}
  974.         );
  975.     },
  976.     // private
  977.     collapse : function(){
  978.         this.updateExpandIcon();
  979.         this.ctNode.style.display = "none";
  980.     },
  981.     // private
  982.     animCollapse : function(callback){
  983.         var ct = Ext.get(this.ctNode);
  984.         ct.enableDisplayMode('block');
  985.         ct.stopFx();
  986.         this.animating = true;
  987.         this.updateExpandIcon();
  988.         ct.slideOut('t', {
  989.             callback : function(){
  990.                this.animating = false;
  991.                Ext.callback(callback);
  992.             },
  993.             scope: this,
  994.             duration: this.node.ownerTree.duration || .25
  995.         });
  996.     },
  997.     // private
  998.     getContainer : function(){
  999.         return this.ctNode;  
  1000.     },
  1001. /**
  1002.  * Returns the element which encapsulates this node.
  1003.  * @return {HtmlElement} The DOM element. The default implementation uses a <code>&lt;li></code>.
  1004.  */
  1005.     getEl : function(){
  1006.         return this.wrap;  
  1007.     },
  1008.     // private
  1009.     appendDDGhost : function(ghostNode){
  1010.         ghostNode.appendChild(this.elNode.cloneNode(true));
  1011.     },
  1012.     // private
  1013.     getDDRepairXY : function(){
  1014.         return Ext.lib.Dom.getXY(this.iconNode);
  1015.     },
  1016.     // private
  1017.     onRender : function(){
  1018.         this.render();    
  1019.     },
  1020.     // private
  1021.     render : function(bulkRender){
  1022.         var n = this.node, a = n.attributes;
  1023.         var targetNode = n.parentNode ? 
  1024.               n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
  1025.         
  1026.         if(!this.rendered){
  1027.             this.rendered = true;
  1028.             this.renderElements(n, a, targetNode, bulkRender);
  1029.             if(a.qtip){
  1030.                if(this.textNode.setAttributeNS){
  1031.                    this.textNode.setAttributeNS("ext", "qtip", a.qtip);
  1032.                    if(a.qtipTitle){
  1033.                        this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
  1034.                    }
  1035.                }else{
  1036.                    this.textNode.setAttribute("ext:qtip", a.qtip);
  1037.                    if(a.qtipTitle){
  1038.                        this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
  1039.                    }
  1040.                } 
  1041.             }else if(a.qtipCfg){
  1042.                 a.qtipCfg.target = Ext.id(this.textNode);
  1043.                 Ext.QuickTips.register(a.qtipCfg);
  1044.             }
  1045.             this.initEvents();
  1046.             if(!this.node.expanded){
  1047.                 this.updateExpandIcon(true);
  1048.             }
  1049.         }else{
  1050.             if(bulkRender === true) {
  1051.                 targetNode.appendChild(this.wrap);
  1052.             }
  1053.         }
  1054.     },
  1055.     // private
  1056.     renderElements : function(n, a, targetNode, bulkRender){
  1057.         // add some indent caching, this helps performance when rendering a large tree
  1058.         this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
  1059.         var cb = Ext.isBoolean(a.checked),
  1060.             nel,
  1061.             href = a.href ? a.href : Ext.isGecko ? "" : "#",
  1062.             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">',
  1063.             '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
  1064.             '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" />',
  1065.             '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
  1066.             cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '',
  1067.             '<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ',
  1068.              a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '><span unselectable="on">',n.text,"</span></a></div>",
  1069.             '<ul class="x-tree-node-ct" style="display:none;"></ul>',
  1070.             "</li>"].join('');
  1071.         if(bulkRender !== true && n.nextSibling && (nel = n.nextSibling.ui.getEl())){
  1072.             this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf);
  1073.         }else{
  1074.             this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf);
  1075.         }
  1076.         
  1077.         this.elNode = this.wrap.childNodes[0];
  1078.         this.ctNode = this.wrap.childNodes[1];
  1079.         var cs = this.elNode.childNodes;
  1080.         this.indentNode = cs[0];
  1081.         this.ecNode = cs[1];
  1082.         this.iconNode = cs[2];
  1083.         var index = 3;
  1084.         if(cb){
  1085.             this.checkbox = cs[3];
  1086.             // fix for IE6
  1087.             this.checkbox.defaultChecked = this.checkbox.checked;
  1088.             index++;
  1089.         }
  1090.         this.anchor = cs[index];
  1091.         this.textNode = cs[index].firstChild;
  1092.     },
  1093. /**
  1094.  * Returns the &lt;a> element that provides focus for the node's UI.
  1095.  * @return {HtmlElement} The DOM anchor element.
  1096.  */
  1097.     getAnchor : function(){
  1098.         return this.anchor;
  1099.     },
  1100.     
  1101. /**
  1102.  * Returns the text node.
  1103.  * @return {HtmlNode} The DOM text node.
  1104.  */
  1105.     getTextEl : function(){
  1106.         return this.textNode;
  1107.     },
  1108.     
  1109. /**
  1110.  * Returns the icon &lt;img> element.
  1111.  * @return {HtmlElement} The DOM image element.
  1112.  */
  1113.     getIconEl : function(){
  1114.         return this.iconNode;
  1115.     },
  1116. /**
  1117.  * Returns the checked status of the node. If the node was rendered with no
  1118.  * checkbox, it returns false.
  1119.  * @return {Boolean} The checked flag.
  1120.  */
  1121.     isChecked : function(){
  1122.         return this.checkbox ? this.checkbox.checked : false; 
  1123.     },
  1124.     // private
  1125.     updateExpandIcon : function(){
  1126.         if(this.rendered){
  1127.             var n = this.node, 
  1128.                 c1, 
  1129.                 c2,
  1130.                 cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow",
  1131.                 hasChild = n.hasChildNodes();
  1132.             if(hasChild || n.attributes.expandable){
  1133.                 if(n.expanded){
  1134.                     cls += "-minus";
  1135.                     c1 = "x-tree-node-collapsed";
  1136.                     c2 = "x-tree-node-expanded";
  1137.                 }else{
  1138.                     cls += "-plus";
  1139.                     c1 = "x-tree-node-expanded";
  1140.                     c2 = "x-tree-node-collapsed";
  1141.                 }
  1142.                 if(this.wasLeaf){
  1143.                     this.removeClass("x-tree-node-leaf");
  1144.                     this.wasLeaf = false;
  1145.                 }
  1146.                 if(this.c1 != c1 || this.c2 != c2){
  1147.                     Ext.fly(this.elNode).replaceClass(c1, c2);
  1148.                     this.c1 = c1; this.c2 = c2;
  1149.                 }
  1150.             }else{
  1151.                 if(!this.wasLeaf){
  1152.                     Ext.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
  1153.                     delete this.c1;
  1154.                     delete this.c2;
  1155.                     this.wasLeaf = true;
  1156.                 }
  1157.             }
  1158.             var ecc = "x-tree-ec-icon "+cls;
  1159.             if(this.ecc != ecc){
  1160.                 this.ecNode.className = ecc;
  1161.                 this.ecc = ecc;
  1162.             }
  1163.         }
  1164.     },
  1165.     
  1166.     // private
  1167.     onIdChange: function(id){
  1168.         if(this.rendered){
  1169.             this.elNode.setAttribute('ext:tree-node-id', id);
  1170.         }
  1171.     },
  1172.     // private
  1173.     getChildIndent : function(){
  1174.         if(!this.childIndent){
  1175.             var buf = [],
  1176.                 p = this.node;
  1177.             while(p){
  1178.                 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
  1179.                     if(!p.isLast()) {
  1180.                         buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
  1181.                     } else {
  1182.                         buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
  1183.                     }
  1184.                 }
  1185.                 p = p.parentNode;
  1186.             }
  1187.             this.childIndent = buf.join("");
  1188.         }
  1189.         return this.childIndent;
  1190.     },
  1191.     // private
  1192.     renderIndent : function(){
  1193.         if(this.rendered){
  1194.             var indent = "",
  1195.                 p = this.node.parentNode;
  1196.             if(p){
  1197.                 indent = p.ui.getChildIndent();
  1198.             }
  1199.             if(this.indentMarkup != indent){ // don't rerender if not required
  1200.                 this.indentNode.innerHTML = indent;
  1201.                 this.indentMarkup = indent;
  1202.             }
  1203.             this.updateExpandIcon();
  1204.         }
  1205.     },
  1206.     destroy : function(){
  1207.         if(this.elNode){
  1208.             Ext.dd.Registry.unregister(this.elNode.id);
  1209.         }
  1210.         
  1211.         Ext.each(['textnode', 'anchor', 'checkbox', 'indentNode', 'ecNode', 'iconNode', 'elNode', 'ctNode', 'wrap', 'holder'], function(el){
  1212.             if(this[el]){
  1213.                 Ext.fly(this[el]).remove();
  1214.                 delete this[el];
  1215.             }
  1216.         }, this);
  1217.         delete this.node;
  1218.     }
  1219. };
  1220. /**
  1221.  * @class Ext.tree.RootTreeNodeUI
  1222.  * This class provides the default UI implementation for <b>root</b> Ext TreeNodes.
  1223.  * The RootTreeNode UI implementation allows customizing the appearance of the root tree node.<br>
  1224.  * <p>
  1225.  * If you are customizing the Tree's user interface, you
  1226.  * may need to extend this class, but you should never need to instantiate this class.<br>
  1227.  */
  1228. Ext.tree.RootTreeNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
  1229.     // private
  1230.     render : function(){
  1231.         if(!this.rendered){
  1232.             var targetNode = this.node.ownerTree.innerCt.dom;
  1233.             this.node.expanded = true;
  1234.             targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
  1235.             this.wrap = this.ctNode = targetNode.firstChild;
  1236.         }
  1237.     },
  1238.     collapse : Ext.emptyFn,
  1239.     expand : Ext.emptyFn
  1240. });/**
  1241.  * @class Ext.tree.TreeLoader
  1242.  * @extends Ext.util.Observable
  1243.  * A TreeLoader provides for lazy loading of an {@link Ext.tree.TreeNode}'s child
  1244.  * nodes from a specified URL. The response must be a JavaScript Array definition
  1245.  * whose elements are node definition objects. e.g.:
  1246.  * <pre><code>
  1247.     [{
  1248.         id: 1,
  1249.         text: 'A leaf Node',
  1250.         leaf: true
  1251.     },{
  1252.         id: 2,
  1253.         text: 'A folder Node',
  1254.         children: [{
  1255.             id: 3,
  1256.             text: 'A child Node',
  1257.             leaf: true
  1258.         }]
  1259.    }]
  1260. </code></pre>
  1261.  * <br><br>
  1262.  * A server request is sent, and child nodes are loaded only when a node is expanded.
  1263.  * The loading node's id is passed to the server under the parameter name "node" to
  1264.  * enable the server to produce the correct child nodes.
  1265.  * <br><br>
  1266.  * To pass extra parameters, an event handler may be attached to the "beforeload"
  1267.  * event, and the parameters specified in the TreeLoader's baseParams property:
  1268.  * <pre><code>
  1269.     myTreeLoader.on("beforeload", function(treeLoader, node) {
  1270.         this.baseParams.category = node.attributes.category;
  1271.     }, this);
  1272. </code></pre>
  1273.  * This would pass an HTTP parameter called "category" to the server containing
  1274.  * the value of the Node's "category" attribute.
  1275.  * @constructor
  1276.  * Creates a new Treeloader.
  1277.  * @param {Object} config A config object containing config properties.
  1278.  */
  1279. Ext.tree.TreeLoader = function(config){
  1280.     this.baseParams = {};
  1281.     Ext.apply(this, config);
  1282.     this.addEvents(
  1283.         /**
  1284.          * @event beforeload
  1285.          * Fires before a network request is made to retrieve the Json text which specifies a node's children.
  1286.          * @param {Object} This TreeLoader object.
  1287.          * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
  1288.          * @param {Object} callback The callback function specified in the {@link #load} call.
  1289.          */
  1290.         "beforeload",
  1291.         /**
  1292.          * @event load
  1293.          * Fires when the node has been successfuly loaded.
  1294.          * @param {Object} This TreeLoader object.
  1295.          * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
  1296.          * @param {Object} response The response object containing the data from the server.
  1297.          */
  1298.         "load",
  1299.         /**
  1300.          * @event loadexception
  1301.          * Fires if the network request failed.
  1302.          * @param {Object} This TreeLoader object.
  1303.          * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
  1304.          * @param {Object} response The response object containing the data from the server.
  1305.          */
  1306.         "loadexception"
  1307.     );
  1308.     Ext.tree.TreeLoader.superclass.constructor.call(this);
  1309.     if(Ext.isString(this.paramOrder)){
  1310.         this.paramOrder = this.paramOrder.split(/[s,|]/);
  1311.     }
  1312. };
  1313. Ext.extend(Ext.tree.TreeLoader, Ext.util.Observable, {
  1314.     /**
  1315.     * @cfg {String} dataUrl The URL from which to request a Json string which
  1316.     * specifies an array of node definition objects representing the child nodes
  1317.     * to be loaded.
  1318.     */
  1319.     /**
  1320.      * @cfg {String} requestMethod The HTTP request method for loading data (defaults to the value of {@link Ext.Ajax#method}).
  1321.      */
  1322.     /**
  1323.      * @cfg {String} url Equivalent to {@link #dataUrl}.
  1324.      */
  1325.     /**
  1326.      * @cfg {Boolean} preloadChildren If set to true, the loader recursively loads "children" attributes when doing the first load on nodes.
  1327.      */
  1328.     /**
  1329.     * @cfg {Object} baseParams (optional) An object containing properties which
  1330.     * specify HTTP parameters to be passed to each request for child nodes.
  1331.     */
  1332.     /**
  1333.     * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
  1334.     * created by this loader. If the attributes sent by the server have an attribute in this object,
  1335.     * they take priority.
  1336.     */
  1337.     /**
  1338.     * @cfg {Object} uiProviders (optional) An object containing properties which
  1339.     * specify custom {@link Ext.tree.TreeNodeUI} implementations. If the optional
  1340.     * <i>uiProvider</i> attribute of a returned child node is a string rather
  1341.     * than a reference to a TreeNodeUI implementation, then that string value
  1342.     * is used as a property name in the uiProviders object.
  1343.     */
  1344.     uiProviders : {},
  1345.     /**
  1346.     * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
  1347.     * child nodes before loading.
  1348.     */
  1349.     clearOnLoad : true,
  1350.     /**
  1351.      * @cfg {Array/String} paramOrder Defaults to <tt>undefined</tt>. Only used when using directFn.
  1352.      * A list of params to be executed
  1353.      * server side.  Specify the params in the order in which they must be executed on the server-side
  1354.      * as either (1) an Array of String values, or (2) a String of params delimited by either whitespace,
  1355.      * comma, or pipe. For example,
  1356.      * any of the following would be acceptable:<pre><code>
  1357. paramOrder: ['param1','param2','param3']
  1358. paramOrder: 'param1 param2 param3'
  1359. paramOrder: 'param1,param2,param3'
  1360. paramOrder: 'param1|param2|param'
  1361.      </code></pre>
  1362.      */
  1363.     paramOrder: undefined,
  1364.     /**
  1365.      * @cfg {Boolean} paramsAsHash Only used when using directFn.
  1366.      * Send parameters as a collection of named arguments (defaults to <tt>false</tt>). Providing a
  1367.      * <tt>{@link #paramOrder}</tt> nullifies this configuration.
  1368.      */
  1369.     paramsAsHash: false,
  1370.     
  1371.     /**
  1372.      * @cfg {String} nodeParameter The name of the parameter sent to the server which contains
  1373.      * the identifier of the node. Defaults to <tt>'node'</tt>.
  1374.      */
  1375.     nodeParameter: 'node',
  1376.     /**
  1377.      * @cfg {Function} directFn
  1378.      * Function to call when executing a request.
  1379.      */
  1380.     directFn : undefined,
  1381.     /**
  1382.      * Load an {@link Ext.tree.TreeNode} from the URL specified in the constructor.
  1383.      * This is called automatically when a node is expanded, but may be used to reload
  1384.      * a node (or append new children if the {@link #clearOnLoad} option is false.)
  1385.      * @param {Ext.tree.TreeNode} node
  1386.      * @param {Function} callback Function to call after the node has been loaded. The 
  1387.      * function is passed the TreeNode which was requested to be loaded.
  1388.      * @param (Object) scope The cope (<code>this</code> reference) in which the callback is executed.
  1389.      * defaults to the loaded TreeNode.
  1390.      */
  1391.     load : function(node, callback, scope){
  1392.         if(this.clearOnLoad){
  1393.             while(node.firstChild){
  1394.                 node.removeChild(node.firstChild);
  1395.             }
  1396.         }
  1397.         if(this.doPreload(node)){ // preloaded json children
  1398.             this.runCallback(callback, scope || node, [node]);
  1399.         }else if(this.directFn || this.dataUrl || this.url){
  1400.             this.requestData(node, callback, scope || node);
  1401.         }
  1402.     },
  1403.     doPreload : function(node){
  1404.         if(node.attributes.children){
  1405.             if(node.childNodes.length < 1){ // preloaded?
  1406.                 var cs = node.attributes.children;
  1407.                 node.beginUpdate();
  1408.                 for(var i = 0, len = cs.length; i < len; i++){
  1409.                     var cn = node.appendChild(this.createNode(cs[i]));
  1410.                     if(this.preloadChildren){
  1411.                         this.doPreload(cn);
  1412.                     }
  1413.                 }
  1414.                 node.endUpdate();
  1415.             }
  1416.             return true;
  1417.         }
  1418.         return false;
  1419.     },
  1420.     getParams: function(node){
  1421.         var buf = [], bp = this.baseParams;
  1422.         if(this.directFn){
  1423.             buf.push(node.id);
  1424.             if(bp){
  1425.                 if(this.paramOrder){
  1426.                     for(var i = 0, len = this.paramOrder.length; i < len; i++){
  1427.                         buf.push(bp[this.paramOrder[i]]);
  1428.                     }
  1429.                 }else if(this.paramsAsHash){
  1430.                     buf.push(bp);
  1431.                 }
  1432.             }
  1433.             return buf;
  1434.         }else{
  1435.             var o = Ext.apply({}, bp);
  1436.             o[this.nodeParameter] = node.id;
  1437.             return o;
  1438.         }
  1439.     },
  1440.     requestData : function(node, callback, scope){
  1441.         if(this.fireEvent("beforeload", this, node, callback) !== false){
  1442.             if(this.directFn){
  1443.                 var args = this.getParams(node);
  1444.                 args.push(this.processDirectResponse.createDelegate(this, [{callback: callback, node: node, scope: scope}], true));
  1445.                 this.directFn.apply(window, args);
  1446.             }else{
  1447.                 this.transId = Ext.Ajax.request({
  1448.                     method:this.requestMethod,
  1449.                     url: this.dataUrl||this.url,
  1450.                     success: this.handleResponse,
  1451.                     failure: this.handleFailure,
  1452.                     scope: this,
  1453.                     argument: {callback: callback, node: node, scope: scope},
  1454.                     params: this.getParams(node)
  1455.                 });
  1456.             }
  1457.         }else{
  1458.             // if the load is cancelled, make sure we notify
  1459.             // the node that we are done
  1460.             this.runCallback(callback, scope || node, []);
  1461.         }
  1462.     },
  1463.     processDirectResponse: function(result, response, args){
  1464.         if(response.status){
  1465.             this.handleResponse({
  1466.                 responseData: Ext.isArray(result) ? result : null,
  1467.                 responseText: result,
  1468.                 argument: args
  1469.             });
  1470.         }else{
  1471.             this.handleFailure({
  1472.                 argument: args
  1473.             });
  1474.         }
  1475.     },
  1476.     // private
  1477.     runCallback: function(cb, scope, args){
  1478.         if(Ext.isFunction(cb)){
  1479.             cb.apply(scope, args);
  1480.         }
  1481.     },
  1482.     isLoading : function(){
  1483.         return !!this.transId;
  1484.     },
  1485.     abort : function(){
  1486.         if(this.isLoading()){
  1487.             Ext.Ajax.abort(this.transId);
  1488.         }
  1489.     },
  1490.     /**
  1491.     * <p>Override this function for custom TreeNode node implementation, or to
  1492.     * modify the attributes at creation time.</p>
  1493.     * Example:<pre><code>
  1494. new Ext.tree.TreePanel({
  1495.     ...
  1496.     loader: new Ext.tree.TreeLoader({
  1497.         url: 'dataUrl',
  1498.         createNode: function(attr) {
  1499. //          Allow consolidation consignments to have
  1500. //          consignments dropped into them.
  1501.             if (attr.isConsolidation) {
  1502.                 attr.iconCls = 'x-consol',
  1503.                 attr.allowDrop = true;
  1504.             }
  1505.             return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
  1506.         }
  1507.     }),
  1508.     ...
  1509. });
  1510. </code></pre>
  1511.     * @param attr {Object} The attributes from which to create the new node.
  1512.     */
  1513.     createNode : function(attr){
  1514.         // apply baseAttrs, nice idea Corey!
  1515.         if(this.baseAttrs){
  1516.             Ext.applyIf(attr, this.baseAttrs);
  1517.         }
  1518.         if(this.applyLoader !== false && !attr.loader){
  1519.             attr.loader = this;
  1520.         }
  1521.         if(Ext.isString(attr.uiProvider)){
  1522.            attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider);
  1523.         }
  1524.         if(attr.nodeType){
  1525.             return new Ext.tree.TreePanel.nodeTypes[attr.nodeType](attr);
  1526.         }else{
  1527.             return attr.leaf ?
  1528.                         new Ext.tree.TreeNode(attr) :
  1529.                         new Ext.tree.AsyncTreeNode(attr);
  1530.         }
  1531.     },
  1532.     processResponse : function(response, node, callback, scope){
  1533.         var json = response.responseText;
  1534.         try {
  1535.             var o = response.responseData || Ext.decode(json);
  1536.             node.beginUpdate();
  1537.             for(var i = 0, len = o.length; i < len; i++){
  1538.                 var n = this.createNode(o[i]);
  1539.                 if(n){
  1540.                     node.appendChild(n);
  1541.                 }
  1542.             }
  1543.             node.endUpdate();
  1544.             this.runCallback(callback, scope || node, [node]);
  1545.         }catch(e){
  1546.             this.handleFailure(response);
  1547.         }
  1548.     },
  1549.     handleResponse : function(response){
  1550.         this.transId = false;
  1551.         var a = response.argument;
  1552.         this.processResponse(response, a.node, a.callback, a.scope);
  1553.         this.fireEvent("load", this, a.node, response);
  1554.     },
  1555.     handleFailure : function(response){
  1556.         this.transId = false;
  1557.         var a = response.argument;
  1558.         this.fireEvent("loadexception", this, a.node, response);
  1559.         this.runCallback(a.callback, a.scope || a.node, [a.node]);
  1560.     },
  1561.     
  1562.     destroy : function(){
  1563.         this.purgeListeners();
  1564.     }
  1565. });/**  * @class Ext.tree.TreeFilter  * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes  * @param {TreePanel} tree  * @param {Object} config (optional)  */ Ext.tree.TreeFilter = function(tree, config){     this.tree = tree;     this.filtered = {};     Ext.apply(this, config); }; Ext.tree.TreeFilter.prototype = {     clearBlank:false,     reverse:false,     autoClear:false,     remove:false,      /**      * Filter the data by a specific attribute.      * @param {String/RegExp} value Either string that the attribute value      * should start with or a RegExp to test against the attribute      * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".      * @param {TreeNode} startNode (optional) The node to start the filter at.      */     filter : function(value, attr, startNode){         attr = attr || "text";         var f;         if(typeof value == "string"){             var vlen = value.length;             // auto clear empty filter             if(vlen == 0 && this.clearBlank){                 this.clear();                 return;             }             value = value.toLowerCase();             f = function(n){                 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;             };         }else if(value.exec){ // regex?             f = function(n){                 return value.test(n.attributes[attr]);             };         }else{             throw 'Illegal filter type, must be string or regex';         }         this.filterBy(f, null, startNode); },     /**      * Filter by a function. The passed function will be called with each      * 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 (<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;         if(this.autoClear){             this.clear();         }         var af = this.filtered, rv = this.reverse;         var f = function(n){             if(n == startNode){                 return true;             }             if(af[n.id]){                 return false;             }             var m = fn.call(scope || n, n);             if(!m || rv){                 af[n.id] = n;                 n.ui.hide();                 return false;             }             return true;         };         startNode.cascade(f);         if(this.remove){            for(var id in af){                if(typeof id != "function"){                    var n = af[id];                    if(n && n.parentNode){                        n.parentNode.removeChild(n);                    }                }            }         }     },     /**      * Clears the current filter. Note: with the "remove" option      * set a filter cannot be cleared.      */     clear : function(){         var t = this.tree;         var af = this.filtered;         for(var id in af){             if(typeof id != "function"){                 var n = af[id];                 if(n){                     n.ui.show();                 }             }         }         this.filtered = {};     } }; /**
  1566.  * @class Ext.tree.TreeSorter
  1567.  * Provides sorting of nodes in a {@link Ext.tree.TreePanel}.  The TreeSorter automatically monitors events on the 
  1568.  * associated TreePanel that might affect the tree's sort order (beforechildrenrendered, append, insert and textchange).
  1569.  * Example usage:<br />
  1570.  * <pre><code>
  1571. new Ext.tree.TreeSorter(myTree, {
  1572.     folderSort: true,
  1573.     dir: "desc",
  1574.     sortType: function(node) {
  1575.         // sort by a custom, typed attribute:
  1576.         return parseInt(node.id, 10);
  1577.     }
  1578. });
  1579. </code></pre>
  1580.  * @constructor
  1581.  * @param {TreePanel} tree
  1582.  * @param {Object} config
  1583.  */
  1584. Ext.tree.TreeSorter = function(tree, config){
  1585.     /**
  1586.      * @cfg {Boolean} folderSort True to sort leaf nodes under non-leaf nodes (defaults to false)
  1587.      */
  1588.     /** 
  1589.      * @cfg {String} property The named attribute on the node to sort by (defaults to "text").  Note that this 
  1590.      * property is only used if no {@link #sortType} function is specified, otherwise it is ignored.
  1591.      */
  1592.     /** 
  1593.      * @cfg {String} dir The direction to sort ("asc" or "desc," case-insensitive, defaults to "asc")
  1594.      */
  1595.     /** 
  1596.      * @cfg {String} leafAttr The attribute used to determine leaf nodes when {@link #folderSort} = true (defaults to "leaf")
  1597.      */
  1598.     /** 
  1599.      * @cfg {Boolean} caseSensitive true for case-sensitive sort (defaults to false)
  1600.      */
  1601.     /** 
  1602.      * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting.  The function
  1603.      * will be called with a single parameter (the {@link Ext.tree.TreeNode} being evaluated) and is expected to return
  1604.      * the node's sort value cast to the specific data type required for sorting.  This could be used, for example, when
  1605.      * a node's text (or other attribute) should be sorted as a date or numeric value.  See the class description for 
  1606.      * example usage.  Note that if a sortType is specified, any {@link #property} config will be ignored.
  1607.      */
  1608.     
  1609.     Ext.apply(this, config);
  1610.     tree.on("beforechildrenrendered", this.doSort, this);
  1611.     tree.on("append", this.updateSort, this);
  1612.     tree.on("insert", this.updateSort, this);
  1613.     tree.on("textchange", this.updateSortParent, this);
  1614.     
  1615.     var dsc = this.dir && this.dir.toLowerCase() == "desc";
  1616.     var p = this.property || "text";
  1617.     var sortType = this.sortType;
  1618.     var fs = this.folderSort;
  1619.     var cs = this.caseSensitive === true;
  1620.     var leafAttr = this.leafAttr || 'leaf';
  1621.     this.sortFn = function(n1, n2){
  1622.         if(fs){
  1623.             if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
  1624.                 return 1;
  1625.             }
  1626.             if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
  1627.                 return -1;
  1628.             }
  1629.         }
  1630.      var v1 = sortType ? sortType(n1.attributes[p]) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
  1631.      var v2 = sortType ? sortType(n2.attributes[p]) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
  1632.      if(v1 < v2){
  1633. return dsc ? +1 : -1;
  1634. }else if(v1 > v2){
  1635. return dsc ? -1 : +1;
  1636.         }else{
  1637.      return 0;
  1638.         }
  1639.     };
  1640. };
  1641. Ext.tree.TreeSorter.prototype = {
  1642.     doSort : function(node){
  1643.         node.sort(this.sortFn);
  1644.     },
  1645.     
  1646.     compareNodes : function(n1, n2){
  1647.         return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
  1648.     },
  1649.     
  1650.     updateSort : function(tree, node){
  1651.         if(node.childrenRendered){
  1652.             this.doSort.defer(1, this, [node]);
  1653.         }
  1654.     },
  1655.     
  1656.     updateSortParent : function(node){
  1657. var p = node.parentNode;
  1658. if(p && p.childrenRendered){
  1659.             this.doSort.defer(1, this, [p]);
  1660.         }
  1661.     }
  1662. };/**
  1663.  * @class Ext.tree.TreeDropZone
  1664.  * @extends Ext.dd.DropZone
  1665.  * @constructor
  1666.  * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dropping
  1667.  * @param {Object} config
  1668.  */
  1669. if(Ext.dd.DropZone){
  1670.     
  1671. Ext.tree.TreeDropZone = function(tree, config){
  1672.     /**
  1673.      * @cfg {Boolean} allowParentInsert
  1674.      * Allow inserting a dragged node between an expanded parent node and its first child that will become a
  1675.      * sibling of the parent when dropped (defaults to false)
  1676.      */
  1677.     this.allowParentInsert = config.allowParentInsert || false;
  1678.     /**
  1679.      * @cfg {String} allowContainerDrop
  1680.      * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false)
  1681.      */
  1682.     this.allowContainerDrop = config.allowContainerDrop || false;
  1683.     /**
  1684.      * @cfg {String} appendOnly
  1685.      * True if the tree should only allow append drops (use for trees which are sorted, defaults to false)
  1686.      */
  1687.     this.appendOnly = config.appendOnly || false;
  1688.     Ext.tree.TreeDropZone.superclass.constructor.call(this, tree.getTreeEl(), config);
  1689.     /**
  1690.     * The TreePanel for this drop zone
  1691.     * @type Ext.tree.TreePanel
  1692.     * @property
  1693.     */
  1694.     this.tree = tree;
  1695.     /**
  1696.     * Arbitrary data that can be associated with this tree and will be included in the event object that gets
  1697.     * passed to any nodedragover event handler (defaults to {})
  1698.     * @type Ext.tree.TreePanel
  1699.     * @property
  1700.     */
  1701.     this.dragOverData = {};
  1702.     // private
  1703.     this.lastInsertClass = "x-tree-no-status";
  1704. };
  1705. Ext.extend(Ext.tree.TreeDropZone, Ext.dd.DropZone, {
  1706.     /**
  1707.      * @cfg {String} ddGroup
  1708.      * A named drag drop group to which this object belongs.  If a group is specified, then this object will only
  1709.      * interact with other drag drop objects in the same group (defaults to 'TreeDD').
  1710.      */
  1711.     ddGroup : "TreeDD",
  1712.     /**
  1713.      * @cfg {String} expandDelay
  1714.      * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node
  1715.      * over the target (defaults to 1000)
  1716.      */
  1717.     expandDelay : 1000,
  1718.     // private
  1719.     expandNode : function(node){
  1720.         if(node.hasChildNodes() && !node.isExpanded()){
  1721.             node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
  1722.         }
  1723.     },
  1724.     // private
  1725.     queueExpand : function(node){
  1726.         this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
  1727.     },
  1728.     // private
  1729.     cancelExpand : function(){
  1730.         if(this.expandProcId){
  1731.             clearTimeout(this.expandProcId);
  1732.             this.expandProcId = false;
  1733.         }
  1734.     },
  1735.     // private
  1736.     isValidDropPoint : function(n, pt, dd, e, data){
  1737.         if(!n || !data){ return false; }
  1738.         var targetNode = n.node;
  1739.         var dropNode = data.node;
  1740.         // default drop rules
  1741.         if(!(targetNode && targetNode.isTarget && pt)){
  1742.             return false;
  1743.         }
  1744.         if(pt == "append" && targetNode.allowChildren === false){
  1745.             return false;
  1746.         }
  1747.         if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
  1748.             return false;
  1749.         }
  1750.         if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
  1751.             return false;
  1752.         }
  1753.         // reuse the object
  1754.         var overEvent = this.dragOverData;
  1755.         overEvent.tree = this.tree;
  1756.         overEvent.target = targetNode;
  1757.         overEvent.data = data;
  1758.         overEvent.point = pt;
  1759.         overEvent.source = dd;
  1760.         overEvent.rawEvent = e;
  1761.         overEvent.dropNode = dropNode;
  1762.         overEvent.cancel = false;  
  1763.         var result = this.tree.fireEvent("nodedragover", overEvent);
  1764.         return overEvent.cancel === false && result !== false;
  1765.     },
  1766.     // private
  1767.     getDropPoint : function(e, n, dd){
  1768.         var tn = n.node;
  1769.         if(tn.isRoot){
  1770.             return tn.allowChildren !== false ? "append" : false; // always append for root
  1771.         }
  1772.         var dragEl = n.ddel;
  1773.         var t = Ext.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
  1774.         var y = Ext.lib.Event.getPageY(e);
  1775.         var noAppend = tn.allowChildren === false || tn.isLeaf();
  1776.         if(this.appendOnly || tn.parentNode.allowChildren === false){
  1777.             return noAppend ? false : "append";
  1778.         }
  1779.         var noBelow = false;
  1780.         if(!this.allowParentInsert){
  1781.             noBelow = tn.hasChildNodes() && tn.isExpanded();
  1782.         }
  1783.         var q = (b - t) / (noAppend ? 2 : 3);
  1784.         if(y >= t && y < (t + q)){
  1785.             return "above";
  1786.         }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
  1787.             return "below";
  1788.         }else{
  1789.             return "append";
  1790.         }
  1791.     },
  1792.     // private
  1793.     onNodeEnter : function(n, dd, e, data){
  1794.         this.cancelExpand();
  1795.     },
  1796.     
  1797.     onContainerOver : function(dd, e, data) {
  1798.         if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
  1799.             return this.dropAllowed;
  1800.         }
  1801.         return this.dropNotAllowed;
  1802.     },
  1803.     // private
  1804.     onNodeOver : function(n, dd, e, data){
  1805.         var pt = this.getDropPoint(e, n, dd);
  1806.         var node = n.node;
  1807.         
  1808.         // auto node expand check
  1809.         if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
  1810.             this.queueExpand(node);
  1811.         }else if(pt != "append"){
  1812.             this.cancelExpand();
  1813.         }
  1814.         
  1815.         // set the insert point style on the target node
  1816.         var returnCls = this.dropNotAllowed;
  1817.         if(this.isValidDropPoint(n, pt, dd, e, data)){
  1818.            if(pt){
  1819.                var el = n.ddel;
  1820.                var cls;
  1821.                if(pt == "above"){
  1822.                    returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
  1823.                    cls = "x-tree-drag-insert-above";
  1824.                }else if(pt == "below"){
  1825.                    returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
  1826.                    cls = "x-tree-drag-insert-below";
  1827.                }else{
  1828.                    returnCls = "x-tree-drop-ok-append";
  1829.                    cls = "x-tree-drag-append";
  1830.                }
  1831.                if(this.lastInsertClass != cls){
  1832.                    Ext.fly(el).replaceClass(this.lastInsertClass, cls);
  1833.                    this.lastInsertClass = cls;
  1834.                }
  1835.            }
  1836.        }
  1837.        return returnCls;
  1838.     },
  1839.     // private
  1840.     onNodeOut : function(n, dd, e, data){
  1841.         this.cancelExpand();
  1842.         this.removeDropIndicators(n);
  1843.     },
  1844.     // private
  1845.     onNodeDrop : function(n, dd, e, data){
  1846.         var point = this.getDropPoint(e, n, dd);
  1847.         var targetNode = n.node;
  1848.         targetNode.ui.startDrop();
  1849.         if(!this.isValidDropPoint(n, point, dd, e, data)){
  1850.             targetNode.ui.endDrop();
  1851.             return false;
  1852.         }
  1853.         // first try to find the drop node
  1854.         var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
  1855.         return this.processDrop(targetNode, data, point, dd, e, dropNode);
  1856.     },
  1857.     
  1858.     onContainerDrop : function(dd, e, data){
  1859.         if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
  1860.             var targetNode = this.tree.getRootNode();       
  1861.             targetNode.ui.startDrop();
  1862.             var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, 'append', e) : null);
  1863.             return this.processDrop(targetNode, data, 'append', dd, e, dropNode);
  1864.         }
  1865.         return false;
  1866.     },
  1867.     
  1868.     // private
  1869.     processDrop: function(target, data, point, dd, e, dropNode){
  1870.         var dropEvent = {
  1871.             tree : this.tree,
  1872.             target: target,
  1873.             data: data,
  1874.             point: point,
  1875.             source: dd,
  1876.             rawEvent: e,
  1877.             dropNode: dropNode,
  1878.             cancel: !dropNode,
  1879.             dropStatus: false
  1880.         };
  1881.         var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
  1882.         if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
  1883.             target.ui.endDrop();
  1884.             return dropEvent.dropStatus;
  1885.         }
  1886.     
  1887.         target = dropEvent.target;
  1888.         if(point == 'append' && !target.isExpanded()){
  1889.             target.expand(false, null, function(){
  1890.                 this.completeDrop(dropEvent);
  1891.             }.createDelegate(this));
  1892.         }else{
  1893.             this.completeDrop(dropEvent);
  1894.         }
  1895.         return true;
  1896.     },
  1897.     // private
  1898.     completeDrop : function(de){
  1899.         var ns = de.dropNode, p = de.point, t = de.target;
  1900.         if(!Ext.isArray(ns)){
  1901.             ns = [ns];
  1902.         }
  1903.         var n;
  1904.         for(var i = 0, len = ns.length; i < len; i++){
  1905.             n = ns[i];
  1906.             if(p == "above"){
  1907.                 t.parentNode.insertBefore(n, t);
  1908.             }else if(p == "below"){
  1909.                 t.parentNode.insertBefore(n, t.nextSibling);
  1910.             }else{
  1911.                 t.appendChild(n);
  1912.             }
  1913.         }
  1914.         n.ui.focus();
  1915.         if(Ext.enableFx && this.tree.hlDrop){
  1916.             n.ui.highlight();
  1917.         }
  1918.         t.ui.endDrop();
  1919.         this.tree.fireEvent("nodedrop", de);
  1920.     },
  1921.     // private
  1922.     afterNodeMoved : function(dd, data, e, targetNode, dropNode){
  1923.         if(Ext.enableFx && this.tree.hlDrop){
  1924.             dropNode.ui.focus();
  1925.             dropNode.ui.highlight();
  1926.         }
  1927.         this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
  1928.     },
  1929.     // private
  1930.     getTree : function(){
  1931.         return this.tree;
  1932.     },
  1933.     // private
  1934.     removeDropIndicators : function(n){
  1935.         if(n && n.ddel){
  1936.             var el = n.ddel;
  1937.             Ext.fly(el).removeClass([
  1938.                     "x-tree-drag-insert-above",
  1939.                     "x-tree-drag-insert-below",
  1940.                     "x-tree-drag-append"]);
  1941.             this.lastInsertClass = "_noclass";
  1942.         }
  1943.     },
  1944.     // private
  1945.     beforeDragDrop : function(target, e, id){
  1946.         this.cancelExpand();
  1947.         return true;
  1948.     },
  1949.     // private
  1950.     afterRepair : function(data){
  1951.         if(data && Ext.enableFx){
  1952.             data.node.ui.highlight();
  1953.         }
  1954.         this.hideProxy();
  1955.     }    
  1956. });
  1957. }/**
  1958.  * @class Ext.tree.TreeDragZone
  1959.  * @extends Ext.dd.DragZone
  1960.  * @constructor
  1961.  * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dragging
  1962.  * @param {Object} config
  1963.  */
  1964. if(Ext.dd.DragZone){
  1965. Ext.tree.TreeDragZone = function(tree, config){
  1966.     Ext.tree.TreeDragZone.superclass.constructor.call(this, tree.innerCt, config);
  1967.     /**
  1968.     * The TreePanel for this drag zone
  1969.     * @type Ext.tree.TreePanel
  1970.     * @property
  1971.     */
  1972.     this.tree = tree;
  1973. };
  1974. Ext.extend(Ext.tree.TreeDragZone, Ext.dd.DragZone, {
  1975.     /**
  1976.      * @cfg {String} ddGroup
  1977.      * A named drag drop group to which this object belongs.  If a group is specified, then this object will only
  1978.      * interact with other drag drop objects in the same group (defaults to 'TreeDD').
  1979.      */
  1980.     ddGroup : "TreeDD",
  1981.     // private
  1982.     onBeforeDrag : function(data, e){
  1983.         var n = data.node;
  1984.         return n && n.draggable && !n.disabled;
  1985.     },
  1986.     // private
  1987.     onInitDrag : function(e){
  1988.         var data = this.dragData;
  1989.         this.tree.getSelectionModel().select(data.node);
  1990.         this.tree.eventModel.disable();
  1991.         this.proxy.update("");
  1992.         data.node.ui.appendDDGhost(this.proxy.ghost.dom);
  1993.         this.tree.fireEvent("startdrag", this.tree, data.node, e);
  1994.     },
  1995.     // private
  1996.     getRepairXY : function(e, data){
  1997.         return data.node.ui.getDDRepairXY();
  1998.     },
  1999.     // private
  2000.     onEndDrag : function(data, e){
  2001.         this.tree.eventModel.enable.defer(100, this.tree.eventModel);
  2002.         this.tree.fireEvent("enddrag", this.tree, data.node, e);
  2003.     },
  2004.     // private
  2005.     onValidDrop : function(dd, e, id){
  2006.         this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
  2007.         this.hideProxy();
  2008.     },
  2009.     // private
  2010.     beforeInvalidDrop : function(e, id){
  2011.         // this scrolls the original position back into view
  2012.         var sm = this.tree.getSelectionModel();
  2013.         sm.clearSelections();
  2014.         sm.select(this.dragData.node);
  2015.     },
  2016.     
  2017.     // private
  2018.     afterRepair : function(){
  2019.         if (Ext.enableFx && this.tree.hlDrop) {
  2020.             Ext.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
  2021.         }
  2022.         this.dragging = false;
  2023.     }
  2024. });
  2025. }/**  * @class Ext.tree.TreeEditor  * @extends Ext.Editor  * Provides editor functionality for inline tree node editing.  Any valid {@link Ext.form.Field} subclass can be used  * as the editor field.  * @constructor  * @param {TreePanel} tree  * @param {Object} fieldConfig (optional) Either a prebuilt {@link Ext.form.Field} instance or a Field config object  * that will be applied to the default field instance (defaults to a {@link Ext.form.TextField}).  * @param {Object} config (optional) A TreeEditor config object  */ 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;     if(!tree.rendered){         tree.on('render', this.initEditor, this);     }else{         this.initEditor(tree);     } }; Ext.extend(Ext.tree.TreeEditor, Ext.Editor, {     /**      * @cfg {String} alignment      * The position to align to (see {@link Ext.Element#alignTo} for more details, defaults to "l-l").      */     alignment: "l-l",     // inherit     autoSize: false,     /**      * @cfg {Boolean} hideEl      * True to hide the bound element while the editor is displayed (defaults to false)      */     hideEl : false,     /**      * @cfg {String} cls      * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")      */     cls: "x-small-editor x-tree-editor",     /**      * @cfg {Boolean} shim      * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)      */     shim:false,     // inherit     shadow:"frame",     /**      * @cfg {Number} maxWidth      * The maximum width in pixels of the editor field (defaults to 250).  Note that if the maxWidth would exceed      * the containing tree element's size, it will be automatically limited for you to the container width, taking      * scroll and client offsets into account prior to each edit.      */     maxWidth: 250,     /**      * @cfg {Number} editDelay The number of milliseconds between clicks to register a double-click that will trigger      * editing on the current node (defaults to 350).  If two clicks occur on the same node within this time span,      * the editor for the node will display, otherwise it will be processed as a regular click.      */     editDelay : 350,     initEditor : function(tree){         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});     },     // private     fitToTree : function(ed, el){         var td = this.tree.getTreeEl().dom, nd = el.dom;         if(td.scrollLeft >  nd.offsetLeft){ // ensure the node left point is visible             td.scrollLeft = nd.offsetLeft;         }         var w = Math.min(                 this.maxWidth,                 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);         this.setSize(w, '');     },     /**      * Edit the text of the passed {@link Ext.tree.TreeNode TreeNode}.      * @param node {Ext.tree.TreeNode} The TreeNode to edit. The TreeNode must be {@link Ext.tree.TreeNode#editable editable}.      */     triggerEdit : function(node, defer){         this.completeEdit(); if(node.attributes.editable !== false){            /**             * The {@link Ext.tree.TreeNode TreeNode} this editor is bound to. Read-only.             * @type Ext.tree.TreeNode             * @property editNode             */ this.editNode = node;             if(this.tree.autoScroll){                 Ext.fly(node.ui.getEl()).scrollIntoView(this.tree.body);             }             var value = node.text || '';             if (!Ext.isGecko && Ext.isEmpty(node.text)){                 node.setText('&#160;');             }             this.autoEditTimer = this.startEdit.defer(this.editDelay, this, [node.ui.textNode, value]);             return false;         }     },     // private     bindScroll : function(){         this.tree.getTreeEl().on('scroll', this.cancelEdit, this);     },     // private     beforeNodeClick : function(node, e){         clearTimeout(this.autoEditTimer);         if(this.tree.getSelectionModel().isSelected(node)){             e.stopEvent();             return this.triggerEdit(node);         }     },     onNodeDblClick : function(node, e){         clearTimeout(this.autoEditTimer);     },     // private     updateNode : function(ed, value){         this.tree.getTreeEl().un('scroll', this.cancelEdit, this);         this.editNode.setText(value);     },     // private     onHide : function(){         Ext.tree.TreeEditor.superclass.onHide.call(this);         if(this.editNode){             this.editNode.ui.focus.defer(50, this.editNode.ui);         }     },     // private     onSpecialKey : function(field, e){         var k = e.getKey();         if(k == e.ESC){             e.stopEvent();             this.cancelEdit();         }else if(k == e.ENTER && !e.hasModifier()){             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);     } });