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

中间件编程

开发平台:

JavaScript

  1.         }
  2.     },
  3.     /**
  4.      * Ensures all parent nodes are expanded, and if necessary, scrolls
  5.      * the node into view.
  6.      * @param {Function} callback (optional) A function to call when the node has been made visible.
  7.      * @param {Object} scope (optional) The scope in which to execute the callback.
  8.      */
  9.     ensureVisible : function(callback, scope){
  10.         var tree = this.getOwnerTree();
  11.         tree.expandPath(this.parentNode ? this.parentNode.getPath() : this.getPath(), false, function(){
  12.             var node = tree.getNodeById(this.id);  // Somehow if we don't do this, we lose changes that happened to node in the meantime
  13.             tree.getTreeEl().scrollChildIntoView(node.ui.anchor);
  14.             this.runCallback(callback, scope || this, [this]);
  15.         }.createDelegate(this));
  16.     },
  17.     /**
  18.      * Expand all child nodes
  19.      * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
  20.      */
  21.     expandChildNodes : function(deep){
  22.         var cs = this.childNodes;
  23.         for(var i = 0, len = cs.length; i < len; i++) {
  24.          cs[i].expand(deep);
  25.         }
  26.     },
  27.     /**
  28.      * Collapse all child nodes
  29.      * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
  30.      */
  31.     collapseChildNodes : function(deep){
  32.         var cs = this.childNodes;
  33.         for(var i = 0, len = cs.length; i < len; i++) {
  34.          cs[i].collapse(deep);
  35.         }
  36.     },
  37.     /**
  38.      * Disables this node
  39.      */
  40.     disable : function(){
  41.         this.disabled = true;
  42.         this.unselect();
  43.         if(this.rendered && this.ui.onDisableChange){ // event without subscribing
  44.             this.ui.onDisableChange(this, true);
  45.         }
  46.         this.fireEvent("disabledchange", this, true);
  47.     },
  48.     /**
  49.      * Enables this node
  50.      */
  51.     enable : function(){
  52.         this.disabled = false;
  53.         if(this.rendered && this.ui.onDisableChange){ // event without subscribing
  54.             this.ui.onDisableChange(this, false);
  55.         }
  56.         this.fireEvent("disabledchange", this, false);
  57.     },
  58.     // private
  59.     renderChildren : function(suppressEvent){
  60.         if(suppressEvent !== false){
  61.             this.fireEvent("beforechildrenrendered", this);
  62.         }
  63.         var cs = this.childNodes;
  64.         for(var i = 0, len = cs.length; i < len; i++){
  65.             cs[i].render(true);
  66.         }
  67.         this.childrenRendered = true;
  68.     },
  69.     // private
  70.     sort : function(fn, scope){
  71.         Ext.tree.TreeNode.superclass.sort.apply(this, arguments);
  72.         if(this.childrenRendered){
  73.             var cs = this.childNodes;
  74.             for(var i = 0, len = cs.length; i < len; i++){
  75.                 cs[i].render(true);
  76.             }
  77.         }
  78.     },
  79.     // private
  80.     render : function(bulkRender){
  81.         this.ui.render(bulkRender);
  82.         if(!this.rendered){
  83.             // make sure it is registered
  84.             this.getOwnerTree().registerNode(this);
  85.             this.rendered = true;
  86.             if(this.expanded){
  87.                 this.expanded = false;
  88.                 this.expand(false, false);
  89.             }
  90.         }
  91.     },
  92.     // private
  93.     renderIndent : function(deep, refresh){
  94.         if(refresh){
  95.             this.ui.childIndent = null;
  96.         }
  97.         this.ui.renderIndent();
  98.         if(deep === true && this.childrenRendered){
  99.             var cs = this.childNodes;
  100.             for(var i = 0, len = cs.length; i < len; i++){
  101.                 cs[i].renderIndent(true, refresh);
  102.             }
  103.         }
  104.     },
  105.     beginUpdate : function(){
  106.         this.childrenRendered = false;
  107.     },
  108.     endUpdate : function(){
  109.         if(this.expanded && this.rendered){
  110.             this.renderChildren();
  111.         }
  112.     },
  113.     destroy : function(){
  114.         if(this.childNodes){
  115.             for(var i = 0,l = this.childNodes.length; i < l; i++){
  116.                 this.childNodes[i].destroy();
  117.             }
  118.             this.childNodes = null;
  119.         }
  120.         if(this.ui.destroy){
  121.             this.ui.destroy();
  122.         }
  123.     },
  124.     
  125.     // private
  126.     onIdChange: function(id){
  127.         this.ui.onIdChange(id);
  128.     }
  129. });
  130. Ext.tree.TreePanel.nodeTypes.node = Ext.tree.TreeNode;/**
  131.  * @class Ext.tree.AsyncTreeNode
  132.  * @extends Ext.tree.TreeNode
  133.  * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
  134.  * @constructor
  135.  * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node 
  136.  */
  137.  Ext.tree.AsyncTreeNode = function(config){
  138.     this.loaded = config && config.loaded === true;
  139.     this.loading = false;
  140.     Ext.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
  141.     /**
  142.     * @event beforeload
  143.     * Fires before this node is loaded, return false to cancel
  144.     * @param {Node} this This node
  145.     */
  146.     this.addEvents('beforeload', 'load');
  147.     /**
  148.     * @event load
  149.     * Fires when this node is loaded
  150.     * @param {Node} this This node
  151.     */
  152.     /**
  153.      * The loader used by this node (defaults to using the tree's defined loader)
  154.      * @type TreeLoader
  155.      * @property loader
  156.      */
  157. };
  158. Ext.extend(Ext.tree.AsyncTreeNode, Ext.tree.TreeNode, {
  159.     expand : function(deep, anim, callback, scope){
  160.         if(this.loading){ // if an async load is already running, waiting til it's done
  161.             var timer;
  162.             var f = function(){
  163.                 if(!this.loading){ // done loading
  164.                     clearInterval(timer);
  165.                     this.expand(deep, anim, callback, scope);
  166.                 }
  167.             }.createDelegate(this);
  168.             timer = setInterval(f, 200);
  169.             return;
  170.         }
  171.         if(!this.loaded){
  172.             if(this.fireEvent("beforeload", this) === false){
  173.                 return;
  174.             }
  175.             this.loading = true;
  176.             this.ui.beforeLoad(this);
  177.             var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
  178.             if(loader){
  179.                 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback, scope]), this);
  180.                 return;
  181.             }
  182.         }
  183.         Ext.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback, scope);
  184.     },
  185.     
  186.     /**
  187.      * Returns true if this node is currently loading
  188.      * @return {Boolean}
  189.      */
  190.     isLoading : function(){
  191.         return this.loading;  
  192.     },
  193.     
  194.     loadComplete : function(deep, anim, callback, scope){
  195.         this.loading = false;
  196.         this.loaded = true;
  197.         this.ui.afterLoad(this);
  198.         this.fireEvent("load", this);
  199.         this.expand(deep, anim, callback, scope);
  200.     },
  201.     
  202.     /**
  203.      * Returns true if this node has been loaded
  204.      * @return {Boolean}
  205.      */
  206.     isLoaded : function(){
  207.         return this.loaded;
  208.     },
  209.     
  210.     hasChildNodes : function(){
  211.         if(!this.isLeaf() && !this.loaded){
  212.             return true;
  213.         }else{
  214.             return Ext.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
  215.         }
  216.     },
  217.     /**
  218.      * Trigger a reload for this node
  219.      * @param {Function} callback
  220.      * @param {Object} scope (optional) The scope in which to execute the callback.
  221.      */
  222.     reload : function(callback, scope){
  223.         this.collapse(false, false);
  224.         while(this.firstChild){
  225.             this.removeChild(this.firstChild).destroy();
  226.         }
  227.         this.childrenRendered = false;
  228.         this.loaded = false;
  229.         if(this.isHiddenRoot()){
  230.             this.expanded = false;
  231.         }
  232.         this.expand(false, false, callback, scope);
  233.     }
  234. });
  235. Ext.tree.TreePanel.nodeTypes.async = Ext.tree.AsyncTreeNode;/**
  236.  * @class Ext.tree.TreeNodeUI
  237.  * This class provides the default UI implementation for Ext TreeNodes.
  238.  * The TreeNode UI implementation is separate from the
  239.  * tree implementation, and allows customizing of the appearance of
  240.  * tree nodes.<br>
  241.  * <p>
  242.  * If you are customizing the Tree's user interface, you
  243.  * may need to extend this class, but you should never need to instantiate this class.<br>
  244.  * <p>
  245.  * This class provides access to the user interface components of an Ext TreeNode, through
  246.  * {@link Ext.tree.TreeNode#getUI}
  247.  */
  248. Ext.tree.TreeNodeUI = function(node){
  249.     this.node = node;
  250.     this.rendered = false;
  251.     this.animating = false;
  252.     this.wasLeaf = true;
  253.     this.ecc = 'x-tree-ec-icon x-tree-elbow';
  254.     this.emptyIcon = Ext.BLANK_IMAGE_URL;
  255. };
  256. Ext.tree.TreeNodeUI.prototype = {
  257.     // private
  258.     removeChild : function(node){
  259.         if(this.rendered){
  260.             this.ctNode.removeChild(node.ui.getEl());
  261.         } 
  262.     },
  263.     // private
  264.     beforeLoad : function(){
  265.          this.addClass("x-tree-node-loading");
  266.     },
  267.     // private
  268.     afterLoad : function(){
  269.          this.removeClass("x-tree-node-loading");
  270.     },
  271.     // private
  272.     onTextChange : function(node, text, oldText){
  273.         if(this.rendered){
  274.             this.textNode.innerHTML = text;
  275.         }
  276.     },
  277.     // private
  278.     onDisableChange : function(node, state){
  279.         this.disabled = state;
  280. if (this.checkbox) {
  281. this.checkbox.disabled = state;
  282. }        
  283.         if(state){
  284.             this.addClass("x-tree-node-disabled");
  285.         }else{
  286.             this.removeClass("x-tree-node-disabled");
  287.         } 
  288.     },
  289.     // private
  290.     onSelectedChange : function(state){
  291.         if(state){
  292.             this.focus();
  293.             this.addClass("x-tree-selected");
  294.         }else{
  295.             //this.blur();
  296.             this.removeClass("x-tree-selected");
  297.         }
  298.     },
  299.     // private
  300.     onMove : function(tree, node, oldParent, newParent, index, refNode){
  301.         this.childIndent = null;
  302.         if(this.rendered){
  303.             var targetNode = newParent.ui.getContainer();
  304.             if(!targetNode){//target not rendered
  305.                 this.holder = document.createElement("div");
  306.                 this.holder.appendChild(this.wrap);
  307.                 return;
  308.             }
  309.             var insertBefore = refNode ? refNode.ui.getEl() : null;
  310.             if(insertBefore){
  311.                 targetNode.insertBefore(this.wrap, insertBefore);
  312.             }else{
  313.                 targetNode.appendChild(this.wrap);
  314.             }
  315.             this.node.renderIndent(true, oldParent != newParent);
  316.         }
  317.     },
  318. /**
  319.  * Adds one or more CSS classes to the node's UI element.
  320.  * Duplicate classes are automatically filtered out.
  321.  * @param {String/Array} className The CSS class to add, or an array of classes
  322.  */
  323.     addClass : function(cls){
  324.         if(this.elNode){
  325.             Ext.fly(this.elNode).addClass(cls);
  326.         }
  327.     },
  328. /**
  329.  * Removes one or more CSS classes from the node's UI element.
  330.  * @param {String/Array} className The CSS class to remove, or an array of classes
  331.  */
  332.     removeClass : function(cls){
  333.         if(this.elNode){
  334.             Ext.fly(this.elNode).removeClass(cls);  
  335.         }
  336.     },
  337.     // private
  338.     remove : function(){
  339.         if(this.rendered){
  340.             this.holder = document.createElement("div");
  341.             this.holder.appendChild(this.wrap);
  342.         }  
  343.     },
  344.     // private
  345.     fireEvent : function(){
  346.         return this.node.fireEvent.apply(this.node, arguments);  
  347.     },
  348.     // private
  349.     initEvents : function(){
  350.         this.node.on("move", this.onMove, this);
  351.         if(this.node.disabled){
  352.             this.addClass("x-tree-node-disabled");
  353. if (this.checkbox) {
  354. this.checkbox.disabled = true;
  355. }            
  356.         }
  357.         if(this.node.hidden){
  358.             this.hide();
  359.         }
  360.         var ot = this.node.getOwnerTree();
  361.         var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
  362.         if(dd && (!this.node.isRoot || ot.rootVisible)){
  363.             Ext.dd.Registry.register(this.elNode, {
  364.                 node: this.node,
  365.                 handles: this.getDDHandles(),
  366.                 isHandle: false
  367.             });
  368.         }
  369.     },
  370.     // private
  371.     getDDHandles : function(){
  372.         return [this.iconNode, this.textNode, this.elNode];
  373.     },
  374. /**
  375.  * Hides this node.
  376.  */
  377.     hide : function(){
  378.         this.node.hidden = true;
  379.         if(this.wrap){
  380.             this.wrap.style.display = "none";
  381.         }
  382.     },
  383. /**
  384.  * Shows this node.
  385.  */
  386.     show : function(){
  387.         this.node.hidden = false;
  388.         if(this.wrap){
  389.             this.wrap.style.display = "";
  390.         } 
  391.     },
  392.     // private
  393.     onContextMenu : function(e){
  394.         if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
  395.             e.preventDefault();
  396.             this.focus();
  397.             this.fireEvent("contextmenu", this.node, e);
  398.         }
  399.     },
  400.     // private
  401.     onClick : function(e){
  402.         if(this.dropping){
  403.             e.stopEvent();
  404.             return;
  405.         }
  406.         if(this.fireEvent("beforeclick", this.node, e) !== false){
  407.             var a = e.getTarget('a');
  408.             if(!this.disabled && this.node.attributes.href && a){
  409.                 this.fireEvent("click", this.node, e);
  410.                 return;
  411.             }else if(a && e.ctrlKey){
  412.                 e.stopEvent();
  413.             }
  414.             e.preventDefault();
  415.             if(this.disabled){
  416.                 return;
  417.             }
  418.             if(this.node.attributes.singleClickExpand && !this.animating && this.node.isExpandable()){
  419.                 this.node.toggle();
  420.             }
  421.             this.fireEvent("click", this.node, e);
  422.         }else{
  423.             e.stopEvent();
  424.         }
  425.     },
  426.     // private
  427.     onDblClick : function(e){
  428.         e.preventDefault();
  429.         if(this.disabled){
  430.             return;
  431.         }
  432.         if(this.checkbox){
  433.             this.toggleCheck();
  434.         }
  435.         if(!this.animating && this.node.isExpandable()){
  436.             this.node.toggle();
  437.         }
  438.         this.fireEvent("dblclick", this.node, e);
  439.     },
  440.     onOver : function(e){
  441.         this.addClass('x-tree-node-over');
  442.     },
  443.     onOut : function(e){
  444.         this.removeClass('x-tree-node-over');
  445.     },
  446.     // private
  447.     onCheckChange : function(){
  448.         var checked = this.checkbox.checked;
  449. // fix for IE6
  450. this.checkbox.defaultChecked = checked;
  451.         this.node.attributes.checked = checked;
  452.         this.fireEvent('checkchange', this.node, checked);
  453.     },
  454.     // private
  455.     ecClick : function(e){
  456.         if(!this.animating && this.node.isExpandable()){
  457.             this.node.toggle();
  458.         }
  459.     },
  460.     // private
  461.     startDrop : function(){
  462.         this.dropping = true;
  463.     },
  464.     
  465.     // delayed drop so the click event doesn't get fired on a drop
  466.     endDrop : function(){ 
  467.        setTimeout(function(){
  468.            this.dropping = false;
  469.        }.createDelegate(this), 50); 
  470.     },
  471.     // private
  472.     expand : function(){
  473.         this.updateExpandIcon();
  474.         this.ctNode.style.display = "";
  475.     },
  476.     // private
  477.     focus : function(){
  478.         if(!this.node.preventHScroll){
  479.             try{this.anchor.focus();
  480.             }catch(e){}
  481.         }else{
  482.             try{
  483.                 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
  484.                 var l = noscroll.scrollLeft;
  485.                 this.anchor.focus();
  486.                 noscroll.scrollLeft = l;
  487.             }catch(e){}
  488.         }
  489.     },
  490. /**
  491.  * Sets the checked status of the tree node to the passed value, or, if no value was passed,
  492.  * toggles the checked status. If the node was rendered with no checkbox, this has no effect.
  493.  * @param {Boolean} (optional) The new checked status.
  494.  */
  495.     toggleCheck : function(value){
  496.         var cb = this.checkbox;
  497.         if(cb){
  498.             cb.checked = (value === undefined ? !cb.checked : value);
  499.             this.onCheckChange();
  500.         }
  501.     },
  502.     // private
  503.     blur : function(){
  504.         try{
  505.             this.anchor.blur();
  506.         }catch(e){} 
  507.     },
  508.     // private
  509.     animExpand : function(callback){
  510.         var ct = Ext.get(this.ctNode);
  511.         ct.stopFx();
  512.         if(!this.node.isExpandable()){
  513.             this.updateExpandIcon();
  514.             this.ctNode.style.display = "";
  515.             Ext.callback(callback);
  516.             return;
  517.         }
  518.         this.animating = true;
  519.         this.updateExpandIcon();
  520.         
  521.         ct.slideIn('t', {
  522.            callback : function(){
  523.                this.animating = false;
  524.                Ext.callback(callback);
  525.             },
  526.             scope: this,
  527.             duration: this.node.ownerTree.duration || .25
  528.         });
  529.     },
  530.     // private
  531.     highlight : function(){
  532.         var tree = this.node.getOwnerTree();
  533.         Ext.fly(this.wrap).highlight(
  534.             tree.hlColor || "C3DAF9",
  535.             {endColor: tree.hlBaseColor}
  536.         );
  537.     },
  538.     // private
  539.     collapse : function(){
  540.         this.updateExpandIcon();
  541.         this.ctNode.style.display = "none";
  542.     },
  543.     // private
  544.     animCollapse : function(callback){
  545.         var ct = Ext.get(this.ctNode);
  546.         ct.enableDisplayMode('block');
  547.         ct.stopFx();
  548.         this.animating = true;
  549.         this.updateExpandIcon();
  550.         ct.slideOut('t', {
  551.             callback : function(){
  552.                this.animating = false;
  553.                Ext.callback(callback);
  554.             },
  555.             scope: this,
  556.             duration: this.node.ownerTree.duration || .25
  557.         });
  558.     },
  559.     // private
  560.     getContainer : function(){
  561.         return this.ctNode;  
  562.     },
  563.     // private
  564.     getEl : function(){
  565.         return this.wrap;  
  566.     },
  567.     // private
  568.     appendDDGhost : function(ghostNode){
  569.         ghostNode.appendChild(this.elNode.cloneNode(true));
  570.     },
  571.     // private
  572.     getDDRepairXY : function(){
  573.         return Ext.lib.Dom.getXY(this.iconNode);
  574.     },
  575.     // private
  576.     onRender : function(){
  577.         this.render();    
  578.     },
  579.     // private
  580.     render : function(bulkRender){
  581.         var n = this.node, a = n.attributes;
  582.         var targetNode = n.parentNode ? 
  583.               n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
  584.         
  585.         if(!this.rendered){
  586.             this.rendered = true;
  587.             this.renderElements(n, a, targetNode, bulkRender);
  588.             if(a.qtip){
  589.                if(this.textNode.setAttributeNS){
  590.                    this.textNode.setAttributeNS("ext", "qtip", a.qtip);
  591.                    if(a.qtipTitle){
  592.                        this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
  593.                    }
  594.                }else{
  595.                    this.textNode.setAttribute("ext:qtip", a.qtip);
  596.                    if(a.qtipTitle){
  597.                        this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
  598.                    }
  599.                } 
  600.             }else if(a.qtipCfg){
  601.                 a.qtipCfg.target = Ext.id(this.textNode);
  602.                 Ext.QuickTips.register(a.qtipCfg);
  603.             }
  604.             this.initEvents();
  605.             if(!this.node.expanded){
  606.                 this.updateExpandIcon(true);
  607.             }
  608.         }else{
  609.             if(bulkRender === true) {
  610.                 targetNode.appendChild(this.wrap);
  611.             }
  612.         }
  613.     },
  614.     // private
  615.     renderElements : function(n, a, targetNode, bulkRender){
  616.         // add some indent caching, this helps performance when rendering a large tree
  617.         this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
  618.         var cb = typeof a.checked == 'boolean';
  619.         var href = a.href ? a.href : Ext.isGecko ? "" : "#";
  620.         var buf = ['<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf x-unselectable ', a.cls,'" unselectable="on">',
  621.             '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
  622.             '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" />',
  623.             '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
  624.             cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '',
  625.             '<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ',
  626.              a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '><span unselectable="on">',n.text,"</span></a></div>",
  627.             '<ul class="x-tree-node-ct" style="display:none;"></ul>',
  628.             "</li>"].join('');
  629.         var nel;
  630.         if(bulkRender !== true && n.nextSibling && (nel = n.nextSibling.ui.getEl())){
  631.             this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf);
  632.         }else{
  633.             this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf);
  634.         }
  635.         
  636.         this.elNode = this.wrap.childNodes[0];
  637.         this.ctNode = this.wrap.childNodes[1];
  638.         var cs = this.elNode.childNodes;
  639.         this.indentNode = cs[0];
  640.         this.ecNode = cs[1];
  641.         this.iconNode = cs[2];
  642.         var index = 3;
  643.         if(cb){
  644.             this.checkbox = cs[3];
  645. // fix for IE6
  646. this.checkbox.defaultChecked = this.checkbox.checked;
  647.             index++;
  648.         }
  649.         this.anchor = cs[index];
  650.         this.textNode = cs[index].firstChild;
  651.     },
  652. /**
  653.  * Returns the &lt;a> element that provides focus for the node's UI.
  654.  * @return {HtmlElement} The DOM anchor element.
  655.  */
  656.     getAnchor : function(){
  657.         return this.anchor;
  658.     },
  659.     
  660. /**
  661.  * Returns the text node.
  662.  * @return {HtmlNode} The DOM text node.
  663.  */
  664.     getTextEl : function(){
  665.         return this.textNode;
  666.     },
  667.     
  668. /**
  669.  * Returns the icon &lt;img> element.
  670.  * @return {HtmlElement} The DOM image element.
  671.  */
  672.     getIconEl : function(){
  673.         return this.iconNode;
  674.     },
  675. /**
  676.  * Returns the checked status of the node. If the node was rendered with no
  677.  * checkbox, it returns false.
  678.  * @return {Boolean} The checked flag.
  679.  */
  680.     isChecked : function(){
  681.         return this.checkbox ? this.checkbox.checked : false; 
  682.     },
  683.     // private
  684.     updateExpandIcon : function(){
  685.         if(this.rendered){
  686.             var n = this.node, c1, c2;
  687.             var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
  688.             var hasChild = n.hasChildNodes();
  689.             if(hasChild || n.attributes.expandable){
  690.                 if(n.expanded){
  691.                     cls += "-minus";
  692.                     c1 = "x-tree-node-collapsed";
  693.                     c2 = "x-tree-node-expanded";
  694.                 }else{
  695.                     cls += "-plus";
  696.                     c1 = "x-tree-node-expanded";
  697.                     c2 = "x-tree-node-collapsed";
  698.                 }
  699.                 if(this.wasLeaf){
  700.                     this.removeClass("x-tree-node-leaf");
  701.                     this.wasLeaf = false;
  702.                 }
  703.                 if(this.c1 != c1 || this.c2 != c2){
  704.                     Ext.fly(this.elNode).replaceClass(c1, c2);
  705.                     this.c1 = c1; this.c2 = c2;
  706.                 }
  707.             }else{
  708.                 if(!this.wasLeaf){
  709.                     Ext.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
  710.                     delete this.c1;
  711.                     delete this.c2;
  712.                     this.wasLeaf = true;
  713.                 }
  714.             }
  715.             var ecc = "x-tree-ec-icon "+cls;
  716.             if(this.ecc != ecc){
  717.                 this.ecNode.className = ecc;
  718.                 this.ecc = ecc;
  719.             }
  720.         }
  721.     },
  722.     
  723.     // private
  724.     onIdChange: function(id){
  725.         if(this.rendered){
  726.             this.elNode.setAttribute('ext:tree-node-id', id);
  727.         }
  728.     },
  729.     // private
  730.     getChildIndent : function(){
  731.         if(!this.childIndent){
  732.             var buf = [];
  733.             var p = this.node;
  734.             while(p){
  735.                 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
  736.                     if(!p.isLast()) {
  737.                         buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
  738.                     } else {
  739.                         buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
  740.                     }
  741.                 }
  742.                 p = p.parentNode;
  743.             }
  744.             this.childIndent = buf.join("");
  745.         }
  746.         return this.childIndent;
  747.     },
  748.     // private
  749.     renderIndent : function(){
  750.         if(this.rendered){
  751.             var indent = "";
  752.             var p = this.node.parentNode;
  753.             if(p){
  754.                 indent = p.ui.getChildIndent();
  755.             }
  756.             if(this.indentMarkup != indent){ // don't rerender if not required
  757.                 this.indentNode.innerHTML = indent;
  758.                 this.indentMarkup = indent;
  759.             }
  760.             this.updateExpandIcon();
  761.         }
  762.     },
  763.     destroy : function(){
  764.         if(this.elNode){
  765.             Ext.dd.Registry.unregister(this.elNode.id);
  766.         }
  767.         delete this.elNode;
  768.         delete this.ctNode;
  769.         delete this.indentNode;
  770.         delete this.ecNode;
  771.         delete this.iconNode;
  772.         delete this.checkbox;
  773.         delete this.anchor;
  774.         delete this.textNode;
  775.         
  776.         if (this.holder){
  777.              delete this.wrap;
  778.              Ext.removeNode(this.holder);
  779.              delete this.holder;
  780.         }else{
  781.             Ext.removeNode(this.wrap);
  782.             delete this.wrap;
  783.         }
  784.     }
  785. };
  786. /**
  787.  * @class Ext.tree.RootTreeNodeUI
  788.  * This class provides the default UI implementation for <b>root</b> Ext TreeNodes.
  789.  * The RootTreeNode UI implementation allows customizing the appearance of the root tree node.<br>
  790.  * <p>
  791.  * If you are customizing the Tree's user interface, you
  792.  * may need to extend this class, but you should never need to instantiate this class.<br>
  793.  */
  794. Ext.tree.RootTreeNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
  795.     // private
  796.     render : function(){
  797.         if(!this.rendered){
  798.             var targetNode = this.node.ownerTree.innerCt.dom;
  799.             this.node.expanded = true;
  800.             targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
  801.             this.wrap = this.ctNode = targetNode.firstChild;
  802.         }
  803.     },
  804.     collapse : Ext.emptyFn,
  805.     expand : Ext.emptyFn
  806. });/**
  807.  * @class Ext.tree.TreeLoader
  808.  * @extends Ext.util.Observable
  809.  * A TreeLoader provides for lazy loading of an {@link Ext.tree.TreeNode}'s child
  810.  * nodes from a specified URL. The response must be a JavaScript Array definition
  811.  * whose elements are node definition objects. e.g.:
  812.  * <pre><code>
  813.     [{
  814.         id: 1,
  815.         text: 'A leaf Node',
  816.         leaf: true
  817.     },{
  818.         id: 2,
  819.         text: 'A folder Node',
  820.         children: [{
  821.             id: 3,
  822.             text: 'A child Node',
  823.             leaf: true
  824.         }]
  825.    }]
  826. </code></pre>
  827.  * <br><br>
  828.  * A server request is sent, and child nodes are loaded only when a node is expanded.
  829.  * The loading node's id is passed to the server under the parameter name "node" to
  830.  * enable the server to produce the correct child nodes.
  831.  * <br><br>
  832.  * To pass extra parameters, an event handler may be attached to the "beforeload"
  833.  * event, and the parameters specified in the TreeLoader's baseParams property:
  834.  * <pre><code>
  835.     myTreeLoader.on("beforeload", function(treeLoader, node) {
  836.         this.baseParams.category = node.attributes.category;
  837.     }, this);
  838. </code></pre>
  839.  * This would pass an HTTP parameter called "category" to the server containing
  840.  * the value of the Node's "category" attribute.
  841.  * @constructor
  842.  * Creates a new Treeloader.
  843.  * @param {Object} config A config object containing config properties.
  844.  */
  845. Ext.tree.TreeLoader = function(config){
  846.     this.baseParams = {};
  847.     Ext.apply(this, config);
  848.     this.addEvents(
  849.         /**
  850.          * @event beforeload
  851.          * Fires before a network request is made to retrieve the Json text which specifies a node's children.
  852.          * @param {Object} This TreeLoader object.
  853.          * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
  854.          * @param {Object} callback The callback function specified in the {@link #load} call.
  855.          */
  856.         "beforeload",
  857.         /**
  858.          * @event load
  859.          * Fires when the node has been successfuly loaded.
  860.          * @param {Object} This TreeLoader object.
  861.          * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
  862.          * @param {Object} response The response object containing the data from the server.
  863.          */
  864.         "load",
  865.         /**
  866.          * @event loadexception
  867.          * Fires if the network request failed.
  868.          * @param {Object} This TreeLoader object.
  869.          * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
  870.          * @param {Object} response The response object containing the data from the server.
  871.          */
  872.         "loadexception"
  873.     );
  874.     Ext.tree.TreeLoader.superclass.constructor.call(this);
  875.     if(typeof this.paramOrder == 'string'){
  876.         this.paramOrder = this.paramOrder.split(/[s,|]/);
  877.     }
  878. };
  879. Ext.extend(Ext.tree.TreeLoader, Ext.util.Observable, {
  880.     /**
  881.     * @cfg {String} dataUrl The URL from which to request a Json string which
  882.     * specifies an array of node definition objects representing the child nodes
  883.     * to be loaded.
  884.     */
  885.     /**
  886.      * @cfg {String} requestMethod The HTTP request method for loading data (defaults to the value of {@link Ext.Ajax#method}).
  887.      */
  888.     /**
  889.      * @cfg {String} url Equivalent to {@link #dataUrl}.
  890.      */
  891.     /**
  892.      * @cfg {Boolean} preloadChildren If set to true, the loader recursively loads "children" attributes when doing the first load on nodes.
  893.      */
  894.     /**
  895.     * @cfg {Object} baseParams (optional) An object containing properties which
  896.     * specify HTTP parameters to be passed to each request for child nodes.
  897.     */
  898.     /**
  899.     * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
  900.     * created by this loader. If the attributes sent by the server have an attribute in this object,
  901.     * they take priority.
  902.     */
  903.     /**
  904.     * @cfg {Object} uiProviders (optional) An object containing properties which
  905.     * specify custom {@link Ext.tree.TreeNodeUI} implementations. If the optional
  906.     * <i>uiProvider</i> attribute of a returned child node is a string rather
  907.     * than a reference to a TreeNodeUI implementation, then that string value
  908.     * is used as a property name in the uiProviders object.
  909.     */
  910.     uiProviders : {},
  911.     /**
  912.     * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
  913.     * child nodes before loading.
  914.     */
  915.     clearOnLoad : true,
  916.     /**
  917.      * @cfg {Array/String} paramOrder Defaults to <tt>undefined</tt>. Only used when using directFn.
  918.      * A list of params to be executed
  919.      * server side.  Specify the params in the order in which they must be executed on the server-side
  920.      * as either (1) an Array of String values, or (2) a String of params delimited by either whitespace,
  921.      * comma, or pipe. For example,
  922.      * any of the following would be acceptable:<pre><code>
  923. paramOrder: ['param1','param2','param3']
  924. paramOrder: 'param1 param2 param3'
  925. paramOrder: 'param1,param2,param3'
  926. paramOrder: 'param1|param2|param'
  927.      </code></pre>
  928.      */
  929.     paramOrder: undefined,
  930.     /**
  931.      * @cfg {Boolean} paramsAsHash Only used when using directFn.
  932.      * Send parameters as a collection of named arguments (defaults to <tt>false</tt>). Providing a
  933.      * <tt>{@link #paramOrder}</tt> nullifies this configuration.
  934.      */
  935.     paramsAsHash: false,
  936.     /**
  937.      * @cfg {Function} directFn
  938.      * Function to call when executing a request.
  939.      */
  940.     directFn : undefined,
  941.     /**
  942.      * Load an {@link Ext.tree.TreeNode} from the URL specified in the constructor.
  943.      * This is called automatically when a node is expanded, but may be used to reload
  944.      * a node (or append new children if the {@link #clearOnLoad} option is false.)
  945.      * @param {Ext.tree.TreeNode} node
  946.      * @param {Function} callback
  947.      * @param (Object) scope
  948.      */
  949.     load : function(node, callback, scope){
  950.         if(this.clearOnLoad){
  951.             while(node.firstChild){
  952.                 node.removeChild(node.firstChild);
  953.             }
  954.         }
  955.         if(this.doPreload(node)){ // preloaded json children
  956.             this.runCallback(callback, scope || node, []);
  957.         }else if(this.directFn || this.dataUrl || this.url){
  958.             this.requestData(node, callback, scope || node);
  959.         }
  960.     },
  961.     doPreload : function(node){
  962.         if(node.attributes.children){
  963.             if(node.childNodes.length < 1){ // preloaded?
  964.                 var cs = node.attributes.children;
  965.                 node.beginUpdate();
  966.                 for(var i = 0, len = cs.length; i < len; i++){
  967.                     var cn = node.appendChild(this.createNode(cs[i]));
  968.                     if(this.preloadChildren){
  969.                         this.doPreload(cn);
  970.                     }
  971.                 }
  972.                 node.endUpdate();
  973.             }
  974.             return true;
  975.         }
  976.         return false;
  977.     },
  978.     getParams: function(node){
  979.         var buf = [], bp = this.baseParams;
  980.         if(this.directFn){
  981.             buf.push(node.id);
  982.             if(bp){
  983.                 if(this.paramOrder){
  984.                     for(var i = 0, len = this.paramOrder.length; i < len; i++){
  985.                         buf.push(bp[this.paramOrder[i]]);
  986.                     }
  987.                 }else if(this.paramsAsHash){
  988.                     buf.push(bp);
  989.                 }
  990.             }
  991.             return buf;
  992.         }else{
  993.             for(var key in bp){
  994.                 if(!Ext.isFunction(bp[key])){
  995.                     buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
  996.                 }
  997.             }
  998.             buf.push("node=", encodeURIComponent(node.id));
  999.             return buf.join("");
  1000.         }
  1001.     },
  1002.     requestData : function(node, callback, scope){
  1003.         if(this.fireEvent("beforeload", this, node, callback) !== false){
  1004.             if(this.directFn){
  1005.                 var args = this.getParams(node);
  1006.                 args.push(this.processDirectResponse.createDelegate(this, [{callback: callback, node: node, scope: scope}], true));
  1007.                 this.directFn.apply(window, args);
  1008.             }else{
  1009.                 this.transId = Ext.Ajax.request({
  1010.                     method:this.requestMethod,
  1011.                     url: this.dataUrl||this.url,
  1012.                     success: this.handleResponse,
  1013.                     failure: this.handleFailure,
  1014.                     scope: this,
  1015.                     argument: {callback: callback, node: node, scope: scope},
  1016.                     params: this.getParams(node)
  1017.                 });
  1018.             }
  1019.         }else{
  1020.             // if the load is cancelled, make sure we notify
  1021.             // the node that we are done
  1022.             this.runCallback(callback, scope || node, []);
  1023.         }
  1024.     },
  1025.     processDirectResponse: function(result, response, args){
  1026.         if(response.status){
  1027.             this.handleResponse({
  1028.                 responseData: Ext.isArray(result) ? result : null,
  1029.                 responseText: result,
  1030.                 argument: args
  1031.             });
  1032.         }else{
  1033.             this.handleFailure({
  1034.                 argument: args
  1035.             });
  1036.         }
  1037.     },
  1038.     // private
  1039.     runCallback: function(cb, scope, args){
  1040.         if(Ext.isFunction(cb)){
  1041.             cb.apply(scope, args);
  1042.         }
  1043.     },
  1044.     isLoading : function(){
  1045.         return !!this.transId;
  1046.     },
  1047.     abort : function(){
  1048.         if(this.isLoading()){
  1049.             Ext.Ajax.abort(this.transId);
  1050.         }
  1051.     },
  1052.     /**
  1053.     * <p>Override this function for custom TreeNode node implementation, or to
  1054.     * modify the attributes at creation time.</p>
  1055.     * Example:<pre><code>
  1056. new Ext.tree.TreePanel({
  1057.     ...
  1058.     new Ext.tree.TreeLoader({
  1059.         url: 'dataUrl',
  1060.         createNode: function(attr) {
  1061. //          Allow consolidation consignments to have
  1062. //          consignments dropped into them.
  1063.             if (attr.isConsolidation) {
  1064.                 attr.iconCls = 'x-consol',
  1065.                 attr.allowDrop = true;
  1066.             }
  1067.             return Ext.tree.TreeLoader.prototype.call(this, attr);
  1068.         }
  1069.     }),
  1070.     ...
  1071. });
  1072. </code></pre>
  1073.     * @param attr {Object} The attributes from which to create the new node.
  1074.     */
  1075.     createNode : function(attr){
  1076.         // apply baseAttrs, nice idea Corey!
  1077.         if(this.baseAttrs){
  1078.             Ext.applyIf(attr, this.baseAttrs);
  1079.         }
  1080.         if(this.applyLoader !== false){
  1081.             attr.loader = this;
  1082.         }
  1083.         if(typeof attr.uiProvider == 'string'){
  1084.            attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider);
  1085.         }
  1086.         if(attr.nodeType){
  1087.             return new Ext.tree.TreePanel.nodeTypes[attr.nodeType](attr);
  1088.         }else{
  1089.             return attr.leaf ?
  1090.                         new Ext.tree.TreeNode(attr) :
  1091.                         new Ext.tree.AsyncTreeNode(attr);
  1092.         }
  1093.     },
  1094.     processResponse : function(response, node, callback, scope){
  1095.         var json = response.responseText;
  1096.         try {
  1097.             var o = response.responseData || Ext.decode(json);
  1098.             node.beginUpdate();
  1099.             for(var i = 0, len = o.length; i < len; i++){
  1100.                 var n = this.createNode(o[i]);
  1101.                 if(n){
  1102.                     node.appendChild(n);
  1103.                 }
  1104.             }
  1105.             node.endUpdate();
  1106.             this.runCallback(callback, scope || node, [node]);
  1107.         }catch(e){
  1108.             this.handleFailure(response);
  1109.         }
  1110.     },
  1111.     handleResponse : function(response){
  1112.         this.transId = false;
  1113.         var a = response.argument;
  1114.         this.processResponse(response, a.node, a.callback, a.scope);
  1115.         this.fireEvent("load", this, a.node, response);
  1116.     },
  1117.     handleFailure : function(response){
  1118.         this.transId = false;
  1119.         var a = response.argument;
  1120.         this.fireEvent("loadexception", this, a.node, response);
  1121.         this.runCallback(a.callback, a.scope || a.node, [a.node]);
  1122.     }
  1123. });/**  * @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 of the function (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 = {};     } }; /**
  1124.  * @class Ext.tree.TreeSorter
  1125.  * Provides sorting of nodes in a {@link Ext.tree.TreePanel}.  The TreeSorter automatically monitors events on the 
  1126.  * associated TreePanel that might affect the tree's sort order (beforechildrenrendered, append, insert and textchange).
  1127.  * Example usage:<br />
  1128.  * <pre><code>
  1129. new Ext.tree.TreeSorter(myTree, {
  1130.     folderSort: true,
  1131.     dir: "desc",
  1132.     sortType: function(node) {
  1133.         // sort by a custom, typed attribute:
  1134.         return parseInt(node.id, 10);
  1135.     }
  1136. });
  1137. </code></pre>
  1138.  * @constructor
  1139.  * @param {TreePanel} tree
  1140.  * @param {Object} config
  1141.  */
  1142. Ext.tree.TreeSorter = function(tree, config){
  1143.     /**
  1144.      * @cfg {Boolean} folderSort True to sort leaf nodes under non-leaf nodes (defaults to false)
  1145.      */
  1146.     /** 
  1147.      * @cfg {String} property The named attribute on the node to sort by (defaults to "text").  Note that this 
  1148.      * property is only used if no {@link #sortType} function is specified, otherwise it is ignored.
  1149.      */
  1150.     /** 
  1151.      * @cfg {String} dir The direction to sort ("asc" or "desc," case-insensitive, defaults to "asc")
  1152.      */
  1153.     /** 
  1154.      * @cfg {String} leafAttr The attribute used to determine leaf nodes when {@link #folderSort} = true (defaults to "leaf")
  1155.      */
  1156.     /** 
  1157.      * @cfg {Boolean} caseSensitive true for case-sensitive sort (defaults to false)
  1158.      */
  1159.     /** 
  1160.      * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting.  The function
  1161.      * will be called with a single parameter (the {@link Ext.tree.TreeNode} being evaluated) and is expected to return
  1162.      * the node's sort value cast to the specific data type required for sorting.  This could be used, for example, when
  1163.      * a node's text (or other attribute) should be sorted as a date or numeric value.  See the class description for 
  1164.      * example usage.  Note that if a sortType is specified, any {@link #property} config will be ignored.
  1165.      */
  1166.     
  1167.     Ext.apply(this, config);
  1168.     tree.on("beforechildrenrendered", this.doSort, this);
  1169.     tree.on("append", this.updateSort, this);
  1170.     tree.on("insert", this.updateSort, this);
  1171.     tree.on("textchange", this.updateSortParent, this);
  1172.     
  1173.     var dsc = this.dir && this.dir.toLowerCase() == "desc";
  1174.     var p = this.property || "text";
  1175.     var sortType = this.sortType;
  1176.     var fs = this.folderSort;
  1177.     var cs = this.caseSensitive === true;
  1178.     var leafAttr = this.leafAttr || 'leaf';
  1179.     this.sortFn = function(n1, n2){
  1180.         if(fs){
  1181.             if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
  1182.                 return 1;
  1183.             }
  1184.             if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
  1185.                 return -1;
  1186.             }
  1187.         }
  1188.      var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
  1189.      var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
  1190.      if(v1 < v2){
  1191. return dsc ? +1 : -1;
  1192. }else if(v1 > v2){
  1193. return dsc ? -1 : +1;
  1194.         }else{
  1195.      return 0;
  1196.         }
  1197.     };
  1198. };
  1199. Ext.tree.TreeSorter.prototype = {
  1200.     doSort : function(node){
  1201.         node.sort(this.sortFn);
  1202.     },
  1203.     
  1204.     compareNodes : function(n1, n2){
  1205.         return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
  1206.     },
  1207.     
  1208.     updateSort : function(tree, node){
  1209.         if(node.childrenRendered){
  1210.             this.doSort.defer(1, this, [node]);
  1211.         }
  1212.     },
  1213.     
  1214.     updateSortParent : function(node){
  1215. var p = node.parentNode;
  1216. if(p && p.childrenRendered){
  1217.             this.doSort.defer(1, this, [p]);
  1218.         }
  1219.     }
  1220. };/**
  1221.  * @class Ext.tree.TreeDropZone
  1222.  * @extends Ext.dd.DropZone
  1223.  * @constructor
  1224.  * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dropping
  1225.  * @param {Object} config
  1226.  */
  1227. if(Ext.dd.DropZone){
  1228.     
  1229. Ext.tree.TreeDropZone = function(tree, config){
  1230.     /**
  1231.      * @cfg {Boolean} allowParentInsert
  1232.      * Allow inserting a dragged node between an expanded parent node and its first child that will become a
  1233.      * sibling of the parent when dropped (defaults to false)
  1234.      */
  1235.     this.allowParentInsert = config.allowParentInsert || false;
  1236.     /**
  1237.      * @cfg {String} allowContainerDrop
  1238.      * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false)
  1239.      */
  1240.     this.allowContainerDrop = config.allowContainerDrop || false;
  1241.     /**
  1242.      * @cfg {String} appendOnly
  1243.      * True if the tree should only allow append drops (use for trees which are sorted, defaults to false)
  1244.      */
  1245.     this.appendOnly = config.appendOnly || false;
  1246.     Ext.tree.TreeDropZone.superclass.constructor.call(this, tree.getTreeEl(), config);
  1247.     /**
  1248.     * The TreePanel for this drop zone
  1249.     * @type Ext.tree.TreePanel
  1250.     * @property
  1251.     */
  1252.     this.tree = tree;
  1253.     /**
  1254.     * Arbitrary data that can be associated with this tree and will be included in the event object that gets
  1255.     * passed to any nodedragover event handler (defaults to {})
  1256.     * @type Ext.tree.TreePanel
  1257.     * @property
  1258.     */
  1259.     this.dragOverData = {};
  1260.     // private
  1261.     this.lastInsertClass = "x-tree-no-status";
  1262. };
  1263. Ext.extend(Ext.tree.TreeDropZone, Ext.dd.DropZone, {
  1264.     /**
  1265.      * @cfg {String} ddGroup
  1266.      * A named drag drop group to which this object belongs.  If a group is specified, then this object will only
  1267.      * interact with other drag drop objects in the same group (defaults to 'TreeDD').
  1268.      */
  1269.     ddGroup : "TreeDD",
  1270.     /**
  1271.      * @cfg {String} expandDelay
  1272.      * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node
  1273.      * over the target (defaults to 1000)
  1274.      */
  1275.     expandDelay : 1000,
  1276.     // private
  1277.     expandNode : function(node){
  1278.         if(node.hasChildNodes() && !node.isExpanded()){
  1279.             node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
  1280.         }
  1281.     },
  1282.     // private
  1283.     queueExpand : function(node){
  1284.         this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
  1285.     },
  1286.     // private
  1287.     cancelExpand : function(){
  1288.         if(this.expandProcId){
  1289.             clearTimeout(this.expandProcId);
  1290.             this.expandProcId = false;
  1291.         }
  1292.     },
  1293.     // private
  1294.     isValidDropPoint : function(n, pt, dd, e, data){
  1295.         if(!n || !data){ return false; }
  1296.         var targetNode = n.node;
  1297.         var dropNode = data.node;
  1298.         // default drop rules
  1299.         if(!(targetNode && targetNode.isTarget && pt)){
  1300.             return false;
  1301.         }
  1302.         if(pt == "append" && targetNode.allowChildren === false){
  1303.             return false;
  1304.         }
  1305.         if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
  1306.             return false;
  1307.         }
  1308.         if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
  1309.             return false;
  1310.         }
  1311.         // reuse the object
  1312.         var overEvent = this.dragOverData;
  1313.         overEvent.tree = this.tree;
  1314.         overEvent.target = targetNode;
  1315.         overEvent.data = data;
  1316.         overEvent.point = pt;
  1317.         overEvent.source = dd;
  1318.         overEvent.rawEvent = e;
  1319.         overEvent.dropNode = dropNode;
  1320.         overEvent.cancel = false;  
  1321.         var result = this.tree.fireEvent("nodedragover", overEvent);
  1322.         return overEvent.cancel === false && result !== false;
  1323.     },
  1324.     // private
  1325.     getDropPoint : function(e, n, dd){
  1326.         var tn = n.node;
  1327.         if(tn.isRoot){
  1328.             return tn.allowChildren !== false ? "append" : false; // always append for root
  1329.         }
  1330.         var dragEl = n.ddel;
  1331.         var t = Ext.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
  1332.         var y = Ext.lib.Event.getPageY(e);
  1333.         var noAppend = tn.allowChildren === false || tn.isLeaf();
  1334.         if(this.appendOnly || tn.parentNode.allowChildren === false){
  1335.             return noAppend ? false : "append";
  1336.         }
  1337.         var noBelow = false;
  1338.         if(!this.allowParentInsert){
  1339.             noBelow = tn.hasChildNodes() && tn.isExpanded();
  1340.         }
  1341.         var q = (b - t) / (noAppend ? 2 : 3);
  1342.         if(y >= t && y < (t + q)){
  1343.             return "above";
  1344.         }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
  1345.             return "below";
  1346.         }else{
  1347.             return "append";
  1348.         }
  1349.     },
  1350.     // private
  1351.     onNodeEnter : function(n, dd, e, data){
  1352.         this.cancelExpand();
  1353.     },
  1354.     
  1355.     onContainerOver : function(dd, e, data) {
  1356.         if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
  1357.             return this.dropAllowed;
  1358.         }
  1359.         return this.dropNotAllowed;
  1360.     },
  1361.     // private
  1362.     onNodeOver : function(n, dd, e, data){
  1363.         var pt = this.getDropPoint(e, n, dd);
  1364.         var node = n.node;
  1365.         
  1366.         // auto node expand check
  1367.         if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
  1368.             this.queueExpand(node);
  1369.         }else if(pt != "append"){
  1370.             this.cancelExpand();
  1371.         }
  1372.         
  1373.         // set the insert point style on the target node
  1374.         var returnCls = this.dropNotAllowed;
  1375.         if(this.isValidDropPoint(n, pt, dd, e, data)){
  1376.            if(pt){
  1377.                var el = n.ddel;
  1378.                var cls;
  1379.                if(pt == "above"){
  1380.                    returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
  1381.                    cls = "x-tree-drag-insert-above";
  1382.                }else if(pt == "below"){
  1383.                    returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
  1384.                    cls = "x-tree-drag-insert-below";
  1385.                }else{
  1386.                    returnCls = "x-tree-drop-ok-append";
  1387.                    cls = "x-tree-drag-append";
  1388.                }
  1389.                if(this.lastInsertClass != cls){
  1390.                    Ext.fly(el).replaceClass(this.lastInsertClass, cls);
  1391.                    this.lastInsertClass = cls;
  1392.                }
  1393.            }
  1394.        }
  1395.        return returnCls;
  1396.     },
  1397.     // private
  1398.     onNodeOut : function(n, dd, e, data){
  1399.         this.cancelExpand();
  1400.         this.removeDropIndicators(n);
  1401.     },
  1402.     // private
  1403.     onNodeDrop : function(n, dd, e, data){
  1404.         var point = this.getDropPoint(e, n, dd);
  1405.         var targetNode = n.node;
  1406.         targetNode.ui.startDrop();
  1407.         if(!this.isValidDropPoint(n, point, dd, e, data)){
  1408.             targetNode.ui.endDrop();
  1409.             return false;
  1410.         }
  1411.         // first try to find the drop node
  1412.         var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
  1413.         return this.processDrop(targetNode, data, point, dd, e, dropNode);
  1414.     },
  1415.     
  1416.     onContainerDrop : function(dd, e, data){
  1417.         if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
  1418.             var targetNode = this.tree.getRootNode();       
  1419.             targetNode.ui.startDrop();
  1420.             var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, 'append', e) : null);
  1421.             return this.processDrop(targetNode, data, 'append', dd, e, dropNode);
  1422.         }
  1423.         return false;
  1424.     },
  1425.     
  1426.     // private
  1427.     processDrop: function(target, data, point, dd, e, dropNode){
  1428.         var dropEvent = {
  1429.             tree : this.tree,
  1430.             target: target,
  1431.             data: data,
  1432.             point: point,
  1433.             source: dd,
  1434.             rawEvent: e,
  1435.             dropNode: dropNode,
  1436.             cancel: !dropNode,
  1437.             dropStatus: false
  1438.         };
  1439.         var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
  1440.         if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
  1441.             target.ui.endDrop();
  1442.             return dropEvent.dropStatus;
  1443.         }
  1444.     
  1445.         target = dropEvent.target;
  1446.         if(point == 'append' && !target.isExpanded()){
  1447.             target.expand(false, null, function(){
  1448.                 this.completeDrop(dropEvent);
  1449.             }.createDelegate(this));
  1450.         }else{
  1451.             this.completeDrop(dropEvent);
  1452.         }
  1453.         return true;
  1454.     },
  1455.     // private
  1456.     completeDrop : function(de){
  1457.         var ns = de.dropNode, p = de.point, t = de.target;
  1458.         if(!Ext.isArray(ns)){
  1459.             ns = [ns];
  1460.         }
  1461.         var n;
  1462.         for(var i = 0, len = ns.length; i < len; i++){
  1463.             n = ns[i];
  1464.             if(p == "above"){
  1465.                 t.parentNode.insertBefore(n, t);
  1466.             }else if(p == "below"){
  1467.                 t.parentNode.insertBefore(n, t.nextSibling);
  1468.             }else{
  1469.                 t.appendChild(n);
  1470.             }
  1471.         }
  1472.         n.ui.focus();
  1473.         if(Ext.enableFx && this.tree.hlDrop){
  1474.             n.ui.highlight();
  1475.         }
  1476.         t.ui.endDrop();
  1477.         this.tree.fireEvent("nodedrop", de);
  1478.     },
  1479.     // private
  1480.     afterNodeMoved : function(dd, data, e, targetNode, dropNode){
  1481.         if(Ext.enableFx && this.tree.hlDrop){
  1482.             dropNode.ui.focus();
  1483.             dropNode.ui.highlight();
  1484.         }
  1485.         this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
  1486.     },
  1487.     // private
  1488.     getTree : function(){
  1489.         return this.tree;
  1490.     },
  1491.     // private
  1492.     removeDropIndicators : function(n){
  1493.         if(n && n.ddel){
  1494.             var el = n.ddel;
  1495.             Ext.fly(el).removeClass([
  1496.                     "x-tree-drag-insert-above",
  1497.                     "x-tree-drag-insert-below",
  1498.                     "x-tree-drag-append"]);
  1499.             this.lastInsertClass = "_noclass";
  1500.         }
  1501.     },
  1502.     // private
  1503.     beforeDragDrop : function(target, e, id){
  1504.         this.cancelExpand();
  1505.         return true;
  1506.     },
  1507.     // private
  1508.     afterRepair : function(data){
  1509.         if(data && Ext.enableFx){
  1510.             data.node.ui.highlight();
  1511.         }
  1512.         this.hideProxy();
  1513.     }    
  1514. });
  1515. }/**
  1516.  * @class Ext.tree.TreeDragZone
  1517.  * @extends Ext.dd.DragZone
  1518.  * @constructor
  1519.  * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dragging
  1520.  * @param {Object} config
  1521.  */
  1522. if(Ext.dd.DragZone){
  1523. Ext.tree.TreeDragZone = function(tree, config){
  1524.     Ext.tree.TreeDragZone.superclass.constructor.call(this, tree.innerCt, config);
  1525.     /**
  1526.     * The TreePanel for this drag zone
  1527.     * @type Ext.tree.TreePanel
  1528.     * @property
  1529.     */
  1530.     this.tree = tree;
  1531. };
  1532. Ext.extend(Ext.tree.TreeDragZone, Ext.dd.DragZone, {