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

中间件编程

开发平台:

JavaScript

  1.     afterRender : function(){
  2.         Ext.ToolTip.superclass.afterRender.call(this);
  3.         this.anchorEl.setStyle('z-index', this.el.getZIndex() + 1);
  4.     },
  5.     /**
  6.      * Binds this ToolTip to the specified element. The tooltip will be displayed when the mouse moves over the element.
  7.      * @param {Mixed} t The Element, HtmlElement, or ID of an element to bind to
  8.      */
  9.     initTarget : function(target){
  10.         var t;
  11.         if((t = Ext.get(target))){
  12.             if(this.target){
  13.                 this.target = Ext.get(this.target);
  14.                 this.target.un('mouseover', this.onTargetOver, this);
  15.                 this.target.un('mouseout', this.onTargetOut, this);
  16.                 this.target.un('mousemove', this.onMouseMove, this);
  17.             }
  18.             this.mon(t, {
  19.                 mouseover: this.onTargetOver,
  20.                 mouseout: this.onTargetOut,
  21.                 mousemove: this.onMouseMove,
  22.                 scope: this
  23.             });
  24.             this.target = t;
  25.         }
  26.         if(this.anchor){
  27.             this.anchorTarget = this.target;
  28.         }
  29.     },
  30.     // private
  31.     onMouseMove : function(e){
  32.         var t = this.delegate ? e.getTarget(this.delegate) : this.triggerElement = true;
  33.         if (t) {
  34.             this.targetXY = e.getXY();
  35.             if (t === this.triggerElement) {
  36.                 if(!this.hidden && this.trackMouse){
  37.                     this.setPagePosition(this.getTargetXY());
  38.                 }
  39.             } else {
  40.                 this.hide();
  41.                 this.lastActive = new Date(0);
  42.                 this.onTargetOver(e);
  43.             }
  44.         } else if (!this.closable && this.isVisible()) {
  45.             this.hide();
  46.         }
  47.     },
  48.     // private
  49.     getTargetXY : function(){
  50.         if(this.anchor){
  51.             this.targetCounter++;
  52.             var offsets = this.getOffsets();
  53.             var xy = (this.anchorToTarget && !this.trackMouse) ?
  54.                 this.el.getAlignToXY(this.anchorTarget, this.getAnchorAlign()) :
  55.                 this.targetXY;
  56.             var dw = Ext.lib.Dom.getViewWidth()-5;
  57.             var dh = Ext.lib.Dom.getViewHeight()-5;
  58.             var scrollX = (document.documentElement.scrollLeft || document.body.scrollLeft || 0)+5;
  59.             var scrollY = (document.documentElement.scrollTop || document.body.scrollTop || 0)+5;
  60.             var axy = [xy[0] + offsets[0], xy[1] + offsets[1]];
  61.             var sz = this.getSize();
  62.             this.anchorEl.removeClass(this.anchorCls);
  63.             if(this.targetCounter < 2){
  64.                 if(axy[0] < scrollX){
  65.                     if(this.anchorToTarget){
  66.                         this.defaultAlign = 'l-r';
  67.                         if(this.mouseOffset){this.mouseOffset[0] *= -1;}
  68.                     }
  69.                     this.anchor = 'left';
  70.                     return this.getTargetXY();
  71.                 }
  72.                 if(axy[0]+sz.width > dw){
  73.                     if(this.anchorToTarget){
  74.                         this.defaultAlign = 'r-l';
  75.                         if(this.mouseOffset){this.mouseOffset[0] *= -1;}
  76.                     }
  77.                     this.anchor = 'right';
  78.                     return this.getTargetXY();
  79.                 }
  80.                 if(axy[1] < scrollY){
  81.                     if(this.anchorToTarget){
  82.                         this.defaultAlign = 't-b';
  83.                         if(this.mouseOffset){this.mouseOffset[1] *= -1;}
  84.                     }
  85.                     this.anchor = 'top';
  86.                     return this.getTargetXY();
  87.                 }
  88.                 if(axy[1]+sz.height > dh){
  89.                     if(this.anchorToTarget){
  90.                         this.defaultAlign = 'b-t';
  91.                         if(this.mouseOffset){this.mouseOffset[1] *= -1;}
  92.                     }
  93.                     this.anchor = 'bottom';
  94.                     return this.getTargetXY();
  95.                 }
  96.             }
  97.             this.anchorCls = 'x-tip-anchor-'+this.getAnchorPosition();
  98.             this.anchorEl.addClass(this.anchorCls);
  99.             this.targetCounter = 0;
  100.             return axy;
  101.         }else{
  102.             var mouseOffset = this.getMouseOffset();
  103.             return [this.targetXY[0]+mouseOffset[0], this.targetXY[1]+mouseOffset[1]];
  104.         }
  105.     },
  106.     getMouseOffset : function(){
  107.         var offset = this.anchor ? [0,0] : [15,18];
  108.         if(this.mouseOffset){
  109.             offset[0] += this.mouseOffset[0];
  110.             offset[1] += this.mouseOffset[1];
  111.         }
  112.         return offset;
  113.     },
  114.     // private
  115.     getAnchorPosition : function(){
  116.         if(this.anchor){
  117.             this.tipAnchor = this.anchor.charAt(0);
  118.         }else{
  119.             var m = this.defaultAlign.match(/^([a-z]+)-([a-z]+)(?)?$/);
  120.             if(!m){
  121.                throw "AnchorTip.defaultAlign is invalid";
  122.             }
  123.             this.tipAnchor = m[1].charAt(0);
  124.         }
  125.         switch(this.tipAnchor){
  126.             case 't': return 'top';
  127.             case 'b': return 'bottom';
  128.             case 'r': return 'right';
  129.         }
  130.         return 'left';
  131.     },
  132.     // private
  133.     getAnchorAlign : function(){
  134.         switch(this.anchor){
  135.             case 'top'  : return 'tl-bl';
  136.             case 'left' : return 'tl-tr';
  137.             case 'right': return 'tr-tl';
  138.             default     : return 'bl-tl';
  139.         }
  140.     },
  141.     // private
  142.     getOffsets: function(){
  143.         var offsets, ap = this.getAnchorPosition().charAt(0);
  144.         if(this.anchorToTarget && !this.trackMouse){
  145.             switch(ap){
  146.                 case 't':
  147.                     offsets = [0, 9];
  148.                     break;
  149.                 case 'b':
  150.                     offsets = [0, -13];
  151.                     break;
  152.                 case 'r':
  153.                     offsets = [-13, 0];
  154.                     break;
  155.                 default:
  156.                     offsets = [9, 0];
  157.                     break;
  158.             }
  159.         }else{
  160.             switch(ap){
  161.                 case 't':
  162.                     offsets = [-15-this.anchorOffset, 30];
  163.                     break;
  164.                 case 'b':
  165.                     offsets = [-19-this.anchorOffset, -13-this.el.dom.offsetHeight];
  166.                     break;
  167.                 case 'r':
  168.                     offsets = [-15-this.el.dom.offsetWidth, -13-this.anchorOffset];
  169.                     break;
  170.                 default:
  171.                     offsets = [25, -13-this.anchorOffset];
  172.                     break;
  173.             }
  174.         }
  175.         var mouseOffset = this.getMouseOffset();
  176.         offsets[0] += mouseOffset[0];
  177.         offsets[1] += mouseOffset[1];
  178.         return offsets;
  179.     },
  180.     // private
  181.     onTargetOver : function(e){
  182.         if(this.disabled || e.within(this.target.dom, true)){
  183.             return;
  184.         }
  185.         var t = e.getTarget(this.delegate);
  186.         if (t) {
  187.             this.triggerElement = t;
  188.             this.clearTimer('hide');
  189.             this.targetXY = e.getXY();
  190.             this.delayShow();
  191.         }
  192.     },
  193.     // private
  194.     delayShow : function(){
  195.         if(this.hidden && !this.showTimer){
  196.             if(this.lastActive.getElapsed() < this.quickShowInterval){
  197.                 this.show();
  198.             }else{
  199.                 this.showTimer = this.show.defer(this.showDelay, this);
  200.             }
  201.         }else if(!this.hidden && this.autoHide !== false){
  202.             this.show();
  203.         }
  204.     },
  205.     // private
  206.     onTargetOut : function(e){
  207.         if(this.disabled || e.within(this.target.dom, true)){
  208.             return;
  209.         }
  210.         this.clearTimer('show');
  211.         if(this.autoHide !== false){
  212.             this.delayHide();
  213.         }
  214.     },
  215.     // private
  216.     delayHide : function(){
  217.         if(!this.hidden && !this.hideTimer){
  218.             this.hideTimer = this.hide.defer(this.hideDelay, this);
  219.         }
  220.     },
  221.     /**
  222.      * Hides this tooltip if visible.
  223.      */
  224.     hide: function(){
  225.         this.clearTimer('dismiss');
  226.         this.lastActive = new Date();
  227.         if(this.anchorEl){
  228.             this.anchorEl.hide();
  229.         }
  230.         Ext.ToolTip.superclass.hide.call(this);
  231.         delete this.triggerElement;
  232.     },
  233.     /**
  234.      * Shows this tooltip at the current event target XY position.
  235.      */
  236.     show : function(){
  237.         if(this.anchor){
  238.             // pre-show it off screen so that the el will have dimensions
  239.             // for positioning calcs when getting xy next
  240.             this.showAt([-1000,-1000]);
  241.             this.origConstrainPosition = this.constrainPosition;
  242.             this.constrainPosition = false;
  243.             this.anchor = this.origAnchor;
  244.         }
  245.         this.showAt(this.getTargetXY());
  246.         if(this.anchor){
  247.             this.syncAnchor();
  248.             this.anchorEl.show();
  249.             this.constrainPosition = this.origConstrainPosition;
  250.         }else{
  251.             this.anchorEl.hide();
  252.         }
  253.     },
  254.     // inherit docs
  255.     showAt : function(xy){
  256.         this.lastActive = new Date();
  257.         this.clearTimers();
  258.         Ext.ToolTip.superclass.showAt.call(this, xy);
  259.         if(this.dismissDelay && this.autoHide !== false){
  260.             this.dismissTimer = this.hide.defer(this.dismissDelay, this);
  261.         }
  262.     },
  263.     // private
  264.     syncAnchor : function(){
  265.         var anchorPos, targetPos, offset;
  266.         switch(this.tipAnchor.charAt(0)){
  267.             case 't':
  268.                 anchorPos = 'b';
  269.                 targetPos = 'tl';
  270.                 offset = [20+this.anchorOffset, 2];
  271.                 break;
  272.             case 'r':
  273.                 anchorPos = 'l';
  274.                 targetPos = 'tr';
  275.                 offset = [-2, 11+this.anchorOffset];
  276.                 break;
  277.             case 'b':
  278.                 anchorPos = 't';
  279.                 targetPos = 'bl';
  280.                 offset = [20+this.anchorOffset, -2];
  281.                 break;
  282.             default:
  283.                 anchorPos = 'r';
  284.                 targetPos = 'tl';
  285.                 offset = [2, 11+this.anchorOffset];
  286.                 break;
  287.         }
  288.         this.anchorEl.alignTo(this.el, anchorPos+'-'+targetPos, offset);
  289.     },
  290.     // private
  291.     setPagePosition : function(x, y){
  292.         Ext.ToolTip.superclass.setPagePosition.call(this, x, y);
  293.         if(this.anchor){
  294.             this.syncAnchor();
  295.         }
  296.     },
  297.     // private
  298.     clearTimer : function(name){
  299.         name = name + 'Timer';
  300.         clearTimeout(this[name]);
  301.         delete this[name];
  302.     },
  303.     // private
  304.     clearTimers : function(){
  305.         this.clearTimer('show');
  306.         this.clearTimer('dismiss');
  307.         this.clearTimer('hide');
  308.     },
  309.     // private
  310.     onShow : function(){
  311.         Ext.ToolTip.superclass.onShow.call(this);
  312.         Ext.getDoc().on('mousedown', this.onDocMouseDown, this);
  313.     },
  314.     // private
  315.     onHide : function(){
  316.         Ext.ToolTip.superclass.onHide.call(this);
  317.         Ext.getDoc().un('mousedown', this.onDocMouseDown, this);
  318.     },
  319.     // private
  320.     onDocMouseDown : function(e){
  321.         if(this.autoHide !== true && !this.closable && !e.within(this.el.dom)){
  322.             this.disable();
  323.             this.enable.defer(100, this);
  324.         }
  325.     },
  326.     // private
  327.     onDisable : function(){
  328.         this.clearTimers();
  329.         this.hide();
  330.     },
  331.     // private
  332.     adjustPosition : function(x, y){
  333.         if(this.contstrainPosition){
  334.             var ay = this.targetXY[1], h = this.getSize().height;
  335.             if(y <= ay && (y+h) >= ay){
  336.                 y = ay-h-5;
  337.             }
  338.         }
  339.         return {x : x, y: y};
  340.     },
  341.     // private
  342.     onDestroy : function(){
  343.         Ext.getDoc().un('mousedown', this.onDocMouseDown, this);
  344.         Ext.ToolTip.superclass.onDestroy.call(this);
  345.     }
  346. });/**
  347.  * @class Ext.QuickTip
  348.  * @extends Ext.ToolTip
  349.  * A specialized tooltip class for tooltips that can be specified in markup and automatically managed by the global
  350.  * {@link Ext.QuickTips} instance.  See the QuickTips class header for additional usage details and examples.
  351.  * @constructor
  352.  * Create a new Tip
  353.  * @param {Object} config The configuration options
  354.  */
  355. Ext.QuickTip = Ext.extend(Ext.ToolTip, {
  356.     /**
  357.      * @cfg {Mixed} target The target HTMLElement, Ext.Element or id to associate with this quicktip (defaults to the document).
  358.      */
  359.     /**
  360.      * @cfg {Boolean} interceptTitles True to automatically use the element's DOM title value if available (defaults to false).
  361.      */
  362.     interceptTitles : false,
  363.     // private
  364.     tagConfig : {
  365.         namespace : "ext",
  366.         attribute : "qtip",
  367.         width : "qwidth",
  368.         target : "target",
  369.         title : "qtitle",
  370.         hide : "hide",
  371.         cls : "qclass",
  372.         align : "qalign",
  373.         anchor : "anchor"
  374.     },
  375.     // private
  376.     initComponent : function(){
  377.         this.target = this.target || Ext.getDoc();
  378.         this.targets = this.targets || {};
  379.         Ext.QuickTip.superclass.initComponent.call(this);
  380.     },
  381.     /**
  382.      * Configures a new quick tip instance and assigns it to a target element.  The following config values are
  383.      * supported (for example usage, see the {@link Ext.QuickTips} class header):
  384.      * <div class="mdetail-params"><ul>
  385.      * <li>autoHide</li>
  386.      * <li>cls</li>
  387.      * <li>dismissDelay (overrides the singleton value)</li>
  388.      * <li>target (required)</li>
  389.      * <li>text (required)</li>
  390.      * <li>title</li>
  391.      * <li>width</li></ul></div>
  392.      * @param {Object} config The config object
  393.      */
  394.     register : function(config){
  395.         var cs = Ext.isArray(config) ? config : arguments;
  396.         for(var i = 0, len = cs.length; i < len; i++){
  397.             var c = cs[i];
  398.             var target = c.target;
  399.             if(target){
  400.                 if(Ext.isArray(target)){
  401.                     for(var j = 0, jlen = target.length; j < jlen; j++){
  402.                         this.targets[Ext.id(target[j])] = c;
  403.                     }
  404.                 } else{
  405.                     this.targets[Ext.id(target)] = c;
  406.                 }
  407.             }
  408.         }
  409.     },
  410.     /**
  411.      * Removes this quick tip from its element and destroys it.
  412.      * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
  413.      */
  414.     unregister : function(el){
  415.         delete this.targets[Ext.id(el)];
  416.     },
  417.     
  418.     /**
  419.      * Hides a visible tip or cancels an impending show for a particular element.
  420.      * @param {String/HTMLElement/Element} el The element that is the target of the tip.
  421.      */
  422.     cancelShow: function(el){
  423.         var at = this.activeTarget;
  424.         el = Ext.get(el).dom;
  425.         if(this.isVisible()){
  426.             if(at && at.el == el){
  427.                 this.hide();
  428.             }
  429.         }else if(at && at.el == el){
  430.             this.clearTimer('show');
  431.         }
  432.     },
  433.     // private
  434.     onTargetOver : function(e){
  435.         if(this.disabled){
  436.             return;
  437.         }
  438.         this.targetXY = e.getXY();
  439.         var t = e.getTarget();
  440.         if(!t || t.nodeType !== 1 || t == document || t == document.body){
  441.             return;
  442.         }
  443.         if(this.activeTarget && t == this.activeTarget.el){
  444.             this.clearTimer('hide');
  445.             this.show();
  446.             return;
  447.         }
  448.         if(t && this.targets[t.id]){
  449.             this.activeTarget = this.targets[t.id];
  450.             this.activeTarget.el = t;
  451.             this.anchor = this.activeTarget.anchor;
  452.             if(this.anchor){
  453.                 this.anchorTarget = t;
  454.             }
  455.             this.delayShow();
  456.             return;
  457.         }
  458.         
  459.         var ttp, et = Ext.fly(t), cfg = this.tagConfig;
  460.         var ns = cfg.namespace;
  461.         if(this.interceptTitles && t.title){
  462.             ttp = t.title;
  463.             t.qtip = ttp;
  464.             t.removeAttribute("title");
  465.             e.preventDefault();
  466.         } else{
  467.             ttp = t.qtip || et.getAttribute(cfg.attribute, ns);
  468.         }
  469.         if(ttp){
  470.             var autoHide = et.getAttribute(cfg.hide, ns);
  471.             this.activeTarget = {
  472.                 el: t,
  473.                 text: ttp,
  474.                 width: et.getAttribute(cfg.width, ns),
  475.                 autoHide: autoHide != "user" && autoHide !== 'false',
  476.                 title: et.getAttribute(cfg.title, ns),
  477.                 cls: et.getAttribute(cfg.cls, ns),
  478.                 align: et.getAttribute(cfg.align, ns)
  479.                 
  480.             };
  481.             this.anchor = et.getAttribute(cfg.anchor, ns);
  482.             if(this.anchor){
  483.                 this.anchorTarget = t;
  484.             }
  485.             this.delayShow();
  486.         }
  487.     },
  488.     // private
  489.     onTargetOut : function(e){
  490.         this.clearTimer('show');
  491.         if(this.autoHide !== false){
  492.             this.delayHide();
  493.         }
  494.     },
  495.     // inherit docs
  496.     showAt : function(xy){
  497.         var t = this.activeTarget;
  498.         if(t){
  499.             if(!this.rendered){
  500.                 this.render(Ext.getBody());
  501.                 this.activeTarget = t;
  502.             }
  503.             if(t.width){
  504.                 this.setWidth(t.width);
  505.                 this.body.setWidth(this.adjustBodyWidth(t.width - this.getFrameWidth()));
  506.                 this.measureWidth = false;
  507.             } else{
  508.                 this.measureWidth = true;
  509.             }
  510.             this.setTitle(t.title || '');
  511.             this.body.update(t.text);
  512.             this.autoHide = t.autoHide;
  513.             this.dismissDelay = t.dismissDelay || this.dismissDelay;
  514.             if(this.lastCls){
  515.                 this.el.removeClass(this.lastCls);
  516.                 delete this.lastCls;
  517.             }
  518.             if(t.cls){
  519.                 this.el.addClass(t.cls);
  520.                 this.lastCls = t.cls;
  521.             }
  522.             if(this.anchor){
  523.                 this.constrainPosition = false;
  524.             }else if(t.align){ // TODO: this doesn't seem to work consistently
  525.                 xy = this.el.getAlignToXY(t.el, t.align);
  526.                 this.constrainPosition = false;
  527.             }else{
  528.                 this.constrainPosition = true;
  529.             }
  530.         }
  531.         Ext.QuickTip.superclass.showAt.call(this, xy);
  532.     },
  533.     // inherit docs
  534.     hide: function(){
  535.         delete this.activeTarget;
  536.         Ext.QuickTip.superclass.hide.call(this);
  537.     }
  538. });/**
  539.  * @class Ext.QuickTips
  540.  * <p>Provides attractive and customizable tooltips for any element. The QuickTips
  541.  * singleton is used to configure and manage tooltips globally for multiple elements
  542.  * in a generic manner.  To create individual tooltips with maximum customizability,
  543.  * you should consider either {@link Ext.Tip} or {@link Ext.ToolTip}.</p>
  544.  * <p>Quicktips can be configured via tag attributes directly in markup, or by
  545.  * registering quick tips programmatically via the {@link #register} method.</p>
  546.  * <p>The singleton's instance of {@link Ext.QuickTip} is available via
  547.  * {@link #getQuickTip}, and supports all the methods, and all the all the
  548.  * configuration properties of Ext.QuickTip. These settings will apply to all
  549.  * tooltips shown by the singleton.</p>
  550.  * <p>Below is the summary of the configuration properties which can be used.
  551.  * For detailed descriptions see {@link #getQuickTip}</p>
  552.  * <p><b>QuickTips singleton configs (all are optional)</b></p>
  553.  * <div class="mdetail-params"><ul><li>dismissDelay</li>
  554.  * <li>hideDelay</li>
  555.  * <li>maxWidth</li>
  556.  * <li>minWidth</li>
  557.  * <li>showDelay</li>
  558.  * <li>trackMouse</li></ul></div>
  559.  * <p><b>Target element configs (optional unless otherwise noted)</b></p>
  560.  * <div class="mdetail-params"><ul><li>autoHide</li>
  561.  * <li>cls</li>
  562.  * <li>dismissDelay (overrides singleton value)</li>
  563.  * <li>target (required)</li>
  564.  * <li>text (required)</li>
  565.  * <li>title</li>
  566.  * <li>width</li></ul></div>
  567.  * <p>Here is an example showing how some of these config options could be used:</p>
  568.  * <pre><code>
  569. // Init the singleton.  Any tag-based quick tips will start working.
  570. Ext.QuickTips.init();
  571. // Apply a set of config properties to the singleton
  572. Ext.apply(Ext.QuickTips.getQuickTip(), {
  573.     maxWidth: 200,
  574.     minWidth: 100,
  575.     showDelay: 50,
  576.     trackMouse: true
  577. });
  578. // Manually register a quick tip for a specific element
  579. Ext.QuickTips.register({
  580.     target: 'my-div',
  581.     title: 'My Tooltip',
  582.     text: 'This tooltip was added in code',
  583.     width: 100,
  584.     dismissDelay: 20
  585. });
  586. </code></pre>
  587.  * <p>To register a quick tip in markup, you simply add one or more of the valid QuickTip attributes prefixed with
  588.  * the <b>ext:</b> namespace.  The HTML element itself is automatically set as the quick tip target. Here is the summary
  589.  * of supported attributes (optional unless otherwise noted):</p>
  590.  * <ul><li><b>hide</b>: Specifying "user" is equivalent to setting autoHide = false.  Any other value will be the
  591.  * same as autoHide = true.</li>
  592.  * <li><b>qclass</b>: A CSS class to be applied to the quick tip (equivalent to the 'cls' target element config).</li>
  593.  * <li><b>qtip (required)</b>: The quick tip text (equivalent to the 'text' target element config).</li>
  594.  * <li><b>qtitle</b>: The quick tip title (equivalent to the 'title' target element config).</li>
  595.  * <li><b>qwidth</b>: The quick tip width (equivalent to the 'width' target element config).</li></ul>
  596.  * <p>Here is an example of configuring an HTML element to display a tooltip from markup:</p>
  597.  * <pre><code>
  598. // Add a quick tip to an HTML button
  599. &lt;input type="button" value="OK" ext:qtitle="OK Button" ext:qwidth="100"
  600.      ext:qtip="This is a quick tip from markup!">&lt;/input>
  601. </code></pre>
  602.  * @singleton
  603.  */
  604. Ext.QuickTips = function(){
  605.     var tip, locks = [];
  606.     return {
  607.         /**
  608.          * Initialize the global QuickTips instance and prepare any quick tips.
  609.          * @param {Boolean} autoRender True to render the QuickTips container immediately to preload images. (Defaults to true) 
  610.          */
  611.         init : function(autoRender){
  612.             if(!tip){
  613.                 if(!Ext.isReady){
  614.                     Ext.onReady(function(){
  615.                         Ext.QuickTips.init(autoRender);
  616.                     });
  617.                     return;
  618.                 }
  619.                 tip = new Ext.QuickTip({elements:'header,body'});
  620.                 if(autoRender !== false){
  621.                     tip.render(Ext.getBody());
  622.                 }
  623.             }
  624.         },
  625.         /**
  626.          * Enable quick tips globally.
  627.          */
  628.         enable : function(){
  629.             if(tip){
  630.                 locks.pop();
  631.                 if(locks.length < 1){
  632.                     tip.enable();
  633.                 }
  634.             }
  635.         },
  636.         /**
  637.          * Disable quick tips globally.
  638.          */
  639.         disable : function(){
  640.             if(tip){
  641.                 tip.disable();
  642.             }
  643.             locks.push(1);
  644.         },
  645.         /**
  646.          * Returns true if quick tips are enabled, else false.
  647.          * @return {Boolean}
  648.          */
  649.         isEnabled : function(){
  650.             return tip !== undefined && !tip.disabled;
  651.         },
  652.         /**
  653.          * Gets the global QuickTips instance.
  654.          */
  655.         getQuickTip : function(){
  656.             return tip;
  657.         },
  658.         /**
  659.          * Configures a new quick tip instance and assigns it to a target element.  See
  660.          * {@link Ext.QuickTip#register} for details.
  661.          * @param {Object} config The config object
  662.          */
  663.         register : function(){
  664.             tip.register.apply(tip, arguments);
  665.         },
  666.         /**
  667.          * Removes any registered quick tip from the target element and destroys it.
  668.          * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
  669.          */
  670.         unregister : function(){
  671.             tip.unregister.apply(tip, arguments);
  672.         },
  673.         /**
  674.          * Alias of {@link #register}.
  675.          * @param {Object} config The config object
  676.          */
  677.         tips :function(){
  678.             tip.register.apply(tip, arguments);
  679.         }
  680.     }
  681. }();/**
  682.  * @class Ext.tree.TreePanel
  683.  * @extends Ext.Panel
  684.  * <p>The TreePanel provides tree-structured UI representation of tree-structured data.</p>
  685.  * <p>{@link Ext.tree.TreeNode TreeNode}s added to the TreePanel may each contain metadata
  686.  * used by your application in their {@link Ext.tree.TreeNode#attributes attributes} property.</p>
  687.  * <p><b>A TreePanel must have a {@link #root} node before it is rendered.</b> This may either be
  688.  * specified using the {@link #root} config option, or using the {@link #setRootNode} method.
  689.  * <p>An example of tree rendered to an existing div:</p><pre><code>
  690. var tree = new Ext.tree.TreePanel({
  691.     renderTo: 'tree-div',
  692.     useArrows: true,
  693.     autoScroll: true,
  694.     animate: true,
  695.     enableDD: true,
  696.     containerScroll: true,
  697.     border: false,
  698.     // auto create TreeLoader
  699.     dataUrl: 'get-nodes.php',
  700.     root: {
  701.         nodeType: 'async',
  702.         text: 'Ext JS',
  703.         draggable: false,
  704.         id: 'source'
  705.     }
  706. });
  707. tree.getRootNode().expand();
  708.  * </code></pre>
  709.  * <p>The example above would work with a data packet similar to this:</p><pre><code>
  710. [{
  711.     "text": "adapter",
  712.     "id": "source/adapter",
  713.     "cls": "folder"
  714. }, {
  715.     "text": "dd",
  716.     "id": "source/dd",
  717.     "cls": "folder"
  718. }, {
  719.     "text": "debug.js",
  720.     "id": "source/debug.js",
  721.     "leaf": true,
  722.     "cls": "file"
  723. }]
  724.  * </code></pre>
  725.  * <p>An example of tree within a Viewport:</p><pre><code>
  726. new Ext.Viewport({
  727.     layout: 'border',
  728.     items: [{
  729.         region: 'west',
  730.         collapsible: true,
  731.         title: 'Navigation',
  732.         xtype: 'treepanel',
  733.         width: 200,
  734.         autoScroll: true,
  735.         split: true,
  736.         loader: new Ext.tree.TreeLoader(),
  737.         root: new Ext.tree.AsyncTreeNode({
  738.             expanded: true,
  739.             children: [{
  740.                 text: 'Menu Option 1',
  741.                 leaf: true
  742.             }, {
  743.                 text: 'Menu Option 2',
  744.                 leaf: true
  745.             }, {
  746.                 text: 'Menu Option 3',
  747.                 leaf: true
  748.             }]
  749.         }),
  750.         rootVisible: false,
  751.         listeners: {
  752.             click: function(n) {
  753.                 Ext.Msg.alert('Navigation Tree Click', 'You clicked: "' + n.attributes.text + '"');
  754.             }
  755.         }
  756.     }, {
  757.         region: 'center',
  758.         xtype: 'tabpanel',
  759.         // remaining code not shown ...
  760.     }]
  761. });
  762. </code></pre>
  763.  *
  764.  * @cfg {Ext.tree.TreeNode} root The root node for the tree.
  765.  * @cfg {Boolean} rootVisible <tt>false</tt> to hide the root node (defaults to <tt>true</tt>)
  766.  * @cfg {Boolean} lines <tt>false</tt> to disable tree lines (defaults to <tt>true</tt>)
  767.  * @cfg {Boolean} enableDD <tt>true</tt> to enable drag and drop
  768.  * @cfg {Boolean} enableDrag <tt>true</tt> to enable just drag
  769.  * @cfg {Boolean} enableDrop <tt>true</tt> to enable just drop
  770.  * @cfg {Object} dragConfig Custom config to pass to the {@link Ext.tree.TreeDragZone} instance
  771.  * @cfg {Object} dropConfig Custom config to pass to the {@link Ext.tree.TreeDropZone} instance
  772.  * @cfg {String} ddGroup The DD group this TreePanel belongs to
  773.  * @cfg {Boolean} ddAppendOnly <tt>true</tt> if the tree should only allow append drops (use for trees which are sorted)
  774.  * @cfg {Boolean} ddScroll <tt>true</tt> to enable body scrolling
  775.  * @cfg {Boolean} containerScroll <tt>true</tt> to register this container with ScrollManager
  776.  * @cfg {Boolean} hlDrop <tt>false</tt> to disable node highlight on drop (defaults to the value of {@link Ext#enableFx})
  777.  * @cfg {String} hlColor The color of the node highlight (defaults to <tt>'C3DAF9'</tt>)
  778.  * @cfg {Boolean} animate <tt>true</tt> to enable animated expand/collapse (defaults to the value of {@link Ext#enableFx})
  779.  * @cfg {Boolean} singleExpand <tt>true</tt> if only 1 node per branch may be expanded
  780.  * @cfg {Object} selModel A tree selection model to use with this TreePanel (defaults to an {@link Ext.tree.DefaultSelectionModel})
  781.  * @cfg {Boolean} trackMouseOver <tt>false</tt> to disable mouse over highlighting
  782.  * @cfg {Ext.tree.TreeLoader} loader A {@link Ext.tree.TreeLoader} for use with this TreePanel
  783.  * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to <tt>'/'</tt>)
  784.  * @cfg {Boolean} useArrows <tt>true</tt> to use Vista-style arrows in the tree (defaults to <tt>false</tt>)
  785.  * @cfg {String} requestMethod The HTTP request method for loading data (defaults to the value of {@link Ext.Ajax#method}).
  786.  *
  787.  * @constructor
  788.  * @param {Object} config
  789.  * @xtype treepanel
  790.  */
  791. Ext.tree.TreePanel = Ext.extend(Ext.Panel, {
  792.     rootVisible : true,
  793.     animate: Ext.enableFx,
  794.     lines : true,
  795.     enableDD : false,
  796.     hlDrop : Ext.enableFx,
  797.     pathSeparator: "/",
  798.     initComponent : function(){
  799.         Ext.tree.TreePanel.superclass.initComponent.call(this);
  800.         if(!this.eventModel){
  801.             this.eventModel = new Ext.tree.TreeEventModel(this);
  802.         }
  803.         // initialize the loader
  804.         var l = this.loader;
  805.         if(!l){
  806.             l = new Ext.tree.TreeLoader({
  807.                 dataUrl: this.dataUrl,
  808.                 requestMethod: this.requestMethod
  809.             });
  810.         }else if(typeof l == 'object' && !l.load){
  811.             l = new Ext.tree.TreeLoader(l);
  812.         }
  813.         this.loader = l;
  814.         this.nodeHash = {};
  815.         /**
  816.         * The root node of this tree.
  817.         * @type Ext.tree.TreeNode
  818.         * @property root
  819.         */
  820.         if(this.root){
  821.             var r = this.root;
  822.             delete this.root;
  823.             this.setRootNode(r);
  824.         }
  825.         this.addEvents(
  826.             /**
  827.             * @event append
  828.             * Fires when a new child node is appended to a node in this tree.
  829.             * @param {Tree} tree The owner tree
  830.             * @param {Node} parent The parent node
  831.             * @param {Node} node The newly appended node
  832.             * @param {Number} index The index of the newly appended node
  833.             */
  834.            "append",
  835.            /**
  836.             * @event remove
  837.             * Fires when a child node is removed from a node in this tree.
  838.             * @param {Tree} tree The owner tree
  839.             * @param {Node} parent The parent node
  840.             * @param {Node} node The child node removed
  841.             */
  842.            "remove",
  843.            /**
  844.             * @event movenode
  845.             * Fires when a node is moved to a new location in the tree
  846.             * @param {Tree} tree The owner tree
  847.             * @param {Node} node The node moved
  848.             * @param {Node} oldParent The old parent of this node
  849.             * @param {Node} newParent The new parent of this node
  850.             * @param {Number} index The index it was moved to
  851.             */
  852.            "movenode",
  853.            /**
  854.             * @event insert
  855.             * Fires when a new child node is inserted in a node in this tree.
  856.             * @param {Tree} tree The owner tree
  857.             * @param {Node} parent The parent node
  858.             * @param {Node} node The child node inserted
  859.             * @param {Node} refNode The child node the node was inserted before
  860.             */
  861.            "insert",
  862.            /**
  863.             * @event beforeappend
  864.             * Fires before a new child is appended to a node in this tree, return false to cancel the append.
  865.             * @param {Tree} tree The owner tree
  866.             * @param {Node} parent The parent node
  867.             * @param {Node} node The child node to be appended
  868.             */
  869.            "beforeappend",
  870.            /**
  871.             * @event beforeremove
  872.             * Fires before a child is removed from a node in this tree, return false to cancel the remove.
  873.             * @param {Tree} tree The owner tree
  874.             * @param {Node} parent The parent node
  875.             * @param {Node} node The child node to be removed
  876.             */
  877.            "beforeremove",
  878.            /**
  879.             * @event beforemovenode
  880.             * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
  881.             * @param {Tree} tree The owner tree
  882.             * @param {Node} node The node being moved
  883.             * @param {Node} oldParent The parent of the node
  884.             * @param {Node} newParent The new parent the node is moving to
  885.             * @param {Number} index The index it is being moved to
  886.             */
  887.            "beforemovenode",
  888.            /**
  889.             * @event beforeinsert
  890.             * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
  891.             * @param {Tree} tree The owner tree
  892.             * @param {Node} parent The parent node
  893.             * @param {Node} node The child node to be inserted
  894.             * @param {Node} refNode The child node the node is being inserted before
  895.             */
  896.             "beforeinsert",
  897.             /**
  898.             * @event beforeload
  899.             * Fires before a node is loaded, return false to cancel
  900.             * @param {Node} node The node being loaded
  901.             */
  902.             "beforeload",
  903.             /**
  904.             * @event load
  905.             * Fires when a node is loaded
  906.             * @param {Node} node The node that was loaded
  907.             */
  908.             "load",
  909.             /**
  910.             * @event textchange
  911.             * Fires when the text for a node is changed
  912.             * @param {Node} node The node
  913.             * @param {String} text The new text
  914.             * @param {String} oldText The old text
  915.             */
  916.             "textchange",
  917.             /**
  918.             * @event beforeexpandnode
  919.             * Fires before a node is expanded, return false to cancel.
  920.             * @param {Node} node The node
  921.             * @param {Boolean} deep
  922.             * @param {Boolean} anim
  923.             */
  924.             "beforeexpandnode",
  925.             /**
  926.             * @event beforecollapsenode
  927.             * Fires before a node is collapsed, return false to cancel.
  928.             * @param {Node} node The node
  929.             * @param {Boolean} deep
  930.             * @param {Boolean} anim
  931.             */
  932.             "beforecollapsenode",
  933.             /**
  934.             * @event expandnode
  935.             * Fires when a node is expanded
  936.             * @param {Node} node The node
  937.             */
  938.             "expandnode",
  939.             /**
  940.             * @event disabledchange
  941.             * Fires when the disabled status of a node changes
  942.             * @param {Node} node The node
  943.             * @param {Boolean} disabled
  944.             */
  945.             "disabledchange",
  946.             /**
  947.             * @event collapsenode
  948.             * Fires when a node is collapsed
  949.             * @param {Node} node The node
  950.             */
  951.             "collapsenode",
  952.             /**
  953.             * @event beforeclick
  954.             * Fires before click processing on a node. Return false to cancel the default action.
  955.             * @param {Node} node The node
  956.             * @param {Ext.EventObject} e The event object
  957.             */
  958.             "beforeclick",
  959.             /**
  960.             * @event click
  961.             * Fires when a node is clicked
  962.             * @param {Node} node The node
  963.             * @param {Ext.EventObject} e The event object
  964.             */
  965.             "click",
  966.             /**
  967.             * @event checkchange
  968.             * Fires when a node with a checkbox's checked property changes
  969.             * @param {Node} this This node
  970.             * @param {Boolean} checked
  971.             */
  972.             "checkchange",
  973.             /**
  974.             * @event dblclick
  975.             * Fires when a node is double clicked
  976.             * @param {Node} node The node
  977.             * @param {Ext.EventObject} e The event object
  978.             */
  979.             "dblclick",
  980.             /**
  981.             * @event contextmenu
  982.             * Fires when a node is right clicked. To display a context menu in response to this
  983.             * event, first create a Menu object (see {@link Ext.menu.Menu} for details), then add
  984.             * a handler for this event:<pre><code>
  985. new Ext.tree.TreePanel({
  986.     title: 'My TreePanel',
  987.     root: new Ext.tree.AsyncTreeNode({
  988.         text: 'The Root',
  989.         children: [
  990.             { text: 'Child node 1', leaf: true },
  991.             { text: 'Child node 2', leaf: true }
  992.         ]
  993.     }),
  994.     contextMenu: new Ext.menu.Menu({
  995.         items: [{
  996.             id: 'delete-node',
  997.             text: 'Delete Node'
  998.         }],
  999.         listeners: {
  1000.             itemclick: function(item) {
  1001.                 switch (item.id) {
  1002.                     case 'delete-node':
  1003.                         var n = item.parentMenu.contextNode;
  1004.                         if (n.parentNode) {
  1005.                             n.remove();
  1006.                         }
  1007.                         break;
  1008.                 }
  1009.             }
  1010.         }
  1011.     }),
  1012.     listeners: {
  1013.         contextmenu: function(node, e) {
  1014. //          Register the context node with the menu so that a Menu Item's handler function can access
  1015. //          it via its {@link Ext.menu.BaseItem#parentMenu parentMenu} property.
  1016.             node.select();
  1017.             var c = node.getOwnerTree().contextMenu;
  1018.             c.contextNode = node;
  1019.             c.showAt(e.getXY());
  1020.         }
  1021.     }
  1022. });
  1023. </code></pre>
  1024.             * @param {Node} node The node
  1025.             * @param {Ext.EventObject} e The event object
  1026.             */
  1027.             "contextmenu",
  1028.             /**
  1029.             * @event beforechildrenrendered
  1030.             * Fires right before the child nodes for a node are rendered
  1031.             * @param {Node} node The node
  1032.             */
  1033.             "beforechildrenrendered",
  1034.            /**
  1035.              * @event startdrag
  1036.              * Fires when a node starts being dragged
  1037.              * @param {Ext.tree.TreePanel} this
  1038.              * @param {Ext.tree.TreeNode} node
  1039.              * @param {event} e The raw browser event
  1040.              */
  1041.             "startdrag",
  1042.             /**
  1043.              * @event enddrag
  1044.              * Fires when a drag operation is complete
  1045.              * @param {Ext.tree.TreePanel} this
  1046.              * @param {Ext.tree.TreeNode} node
  1047.              * @param {event} e The raw browser event
  1048.              */
  1049.             "enddrag",
  1050.             /**
  1051.              * @event dragdrop
  1052.              * Fires when a dragged node is dropped on a valid DD target
  1053.              * @param {Ext.tree.TreePanel} this
  1054.              * @param {Ext.tree.TreeNode} node
  1055.              * @param {DD} dd The dd it was dropped on
  1056.              * @param {event} e The raw browser event
  1057.              */
  1058.             "dragdrop",
  1059.             /**
  1060.              * @event beforenodedrop
  1061.              * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
  1062.              * passed to handlers has the following properties:<br />
  1063.              * <ul style="padding:5px;padding-left:16px;">
  1064.              * <li>tree - The TreePanel</li>
  1065.              * <li>target - The node being targeted for the drop</li>
  1066.              * <li>data - The drag data from the drag source</li>
  1067.              * <li>point - The point of the drop - append, above or below</li>
  1068.              * <li>source - The drag source</li>
  1069.              * <li>rawEvent - Raw mouse event</li>
  1070.              * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
  1071.              * to be inserted by setting them on this object.</li>
  1072.              * <li>cancel - Set this to true to cancel the drop.</li>
  1073.              * <li>dropStatus - If the default drop action is cancelled but the drop is valid, setting this to true
  1074.              * will prevent the animated "repair" from appearing.</li>
  1075.              * </ul>
  1076.              * @param {Object} dropEvent
  1077.              */
  1078.             "beforenodedrop",
  1079.             /**
  1080.              * @event nodedrop
  1081.              * Fires after a DD object is dropped on a node in this tree. The dropEvent
  1082.              * passed to handlers has the following properties:<br />
  1083.              * <ul style="padding:5px;padding-left:16px;">
  1084.              * <li>tree - The TreePanel</li>
  1085.              * <li>target - The node being targeted for the drop</li>
  1086.              * <li>data - The drag data from the drag source</li>
  1087.              * <li>point - The point of the drop - append, above or below</li>
  1088.              * <li>source - The drag source</li>
  1089.              * <li>rawEvent - Raw mouse event</li>
  1090.              * <li>dropNode - Dropped node(s).</li>
  1091.              * </ul>
  1092.              * @param {Object} dropEvent
  1093.              */
  1094.             "nodedrop",
  1095.              /**
  1096.              * @event nodedragover
  1097.              * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
  1098.              * passed to handlers has the following properties:<br />
  1099.              * <ul style="padding:5px;padding-left:16px;">
  1100.              * <li>tree - The TreePanel</li>
  1101.              * <li>target - The node being targeted for the drop</li>
  1102.              * <li>data - The drag data from the drag source</li>
  1103.              * <li>point - The point of the drop - append, above or below</li>
  1104.              * <li>source - The drag source</li>
  1105.              * <li>rawEvent - Raw mouse event</li>
  1106.              * <li>dropNode - Drop node(s) provided by the source.</li>
  1107.              * <li>cancel - Set this to true to signal drop not allowed.</li>
  1108.              * </ul>
  1109.              * @param {Object} dragOverEvent
  1110.              */
  1111.             "nodedragover"
  1112.         );
  1113.         if(this.singleExpand){
  1114.             this.on("beforeexpandnode", this.restrictExpand, this);
  1115.         }
  1116.     },
  1117.     // private
  1118.     proxyNodeEvent : function(ename, a1, a2, a3, a4, a5, a6){
  1119.         if(ename == 'collapse' || ename == 'expand' || ename == 'beforecollapse' || ename == 'beforeexpand' || ename == 'move' || ename == 'beforemove'){
  1120.             ename = ename+'node';
  1121.         }
  1122.         // args inline for performance while bubbling events
  1123.         return this.fireEvent(ename, a1, a2, a3, a4, a5, a6);
  1124.     },
  1125.     /**
  1126.      * Returns this root node for this tree
  1127.      * @return {Node}
  1128.      */
  1129.     getRootNode : function(){
  1130.         return this.root;
  1131.     },
  1132.     /**
  1133.      * Sets the root node for this tree. If the TreePanel has already rendered a root node, the
  1134.      * previous root node (and all of its descendants) are destroyed before the new root node is rendered.
  1135.      * @param {Node} node
  1136.      * @return {Node}
  1137.      */
  1138.     setRootNode : function(node){
  1139.         Ext.destroy(this.root);
  1140.         if(!node.render){ // attributes passed
  1141.             node = this.loader.createNode(node);
  1142.         }
  1143.         this.root = node;
  1144.         node.ownerTree = this;
  1145.         node.isRoot = true;
  1146.         this.registerNode(node);
  1147.         if(!this.rootVisible){
  1148.             var uiP = node.attributes.uiProvider;
  1149.             node.ui = uiP ? new uiP(node) : new Ext.tree.RootTreeNodeUI(node);
  1150.         }
  1151.         if (this.innerCt) {
  1152.             this.innerCt.update('');
  1153.             this.afterRender();
  1154.         }
  1155.         return node;
  1156.     },
  1157.     /**
  1158.      * Gets a node in this tree by its id
  1159.      * @param {String} id
  1160.      * @return {Node}
  1161.      */
  1162.     getNodeById : function(id){
  1163.         return this.nodeHash[id];
  1164.     },
  1165.     // private
  1166.     registerNode : function(node){
  1167.         this.nodeHash[node.id] = node;
  1168.     },
  1169.     // private
  1170.     unregisterNode : function(node){
  1171.         delete this.nodeHash[node.id];
  1172.     },
  1173.     // private
  1174.     toString : function(){
  1175.         return "[Tree"+(this.id?" "+this.id:"")+"]";
  1176.     },
  1177.     // private
  1178.     restrictExpand : function(node){
  1179.         var p = node.parentNode;
  1180.         if(p){
  1181.             if(p.expandedChild && p.expandedChild.parentNode == p){
  1182.                 p.expandedChild.collapse();
  1183.             }
  1184.             p.expandedChild = node;
  1185.         }
  1186.     },
  1187.     /**
  1188.      * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
  1189.      * @param {String} attribute (optional) Defaults to null (return the actual nodes)
  1190.      * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
  1191.      * @return {Array}
  1192.      */
  1193.     getChecked : function(a, startNode){
  1194.         startNode = startNode || this.root;
  1195.         var r = [];
  1196.         var f = function(){
  1197.             if(this.attributes.checked){
  1198.                 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
  1199.             }
  1200.         };
  1201.         startNode.cascade(f);
  1202.         return r;
  1203.     },
  1204.     /**
  1205.      * Returns the container element for this TreePanel.
  1206.      * @return {Element} The container element for this TreePanel.
  1207.      */
  1208.     getEl : function(){
  1209.         return this.el;
  1210.     },
  1211.     /**
  1212.      * Returns the default {@link Ext.tree.TreeLoader} for this TreePanel.
  1213.      * @return {Ext.tree.TreeLoader} The TreeLoader for this TreePanel.
  1214.      */
  1215.     getLoader : function(){
  1216.         return this.loader;
  1217.     },
  1218.     /**
  1219.      * Expand all nodes
  1220.      */
  1221.     expandAll : function(){
  1222.         this.root.expand(true);
  1223.     },
  1224.     /**
  1225.      * Collapse all nodes
  1226.      */
  1227.     collapseAll : function(){
  1228.         this.root.collapse(true);
  1229.     },
  1230.     /**
  1231.      * Returns the selection model used by this TreePanel.
  1232.      * @return {TreeSelectionModel} The selection model used by this TreePanel
  1233.      */
  1234.     getSelectionModel : function(){
  1235.         if(!this.selModel){
  1236.             this.selModel = new Ext.tree.DefaultSelectionModel();
  1237.         }
  1238.         return this.selModel;
  1239.     },
  1240.     /**
  1241.      * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Ext.data.Node#getPath}
  1242.      * @param {String} path
  1243.      * @param {String} attr (optional) The attribute used in the path (see {@link Ext.data.Node#getPath} for more info)
  1244.      * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
  1245.      * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
  1246.      */
  1247.     expandPath : function(path, attr, callback){
  1248.         attr = attr || "id";
  1249.         var keys = path.split(this.pathSeparator);
  1250.         var curNode = this.root;
  1251.         if(curNode.attributes[attr] != keys[1]){ // invalid root
  1252.             if(callback){
  1253.                 callback(false, null);
  1254.             }
  1255.             return;
  1256.         }
  1257.         var index = 1;
  1258.         var f = function(){
  1259.             if(++index == keys.length){
  1260.                 if(callback){
  1261.                     callback(true, curNode);
  1262.                 }
  1263.                 return;
  1264.             }
  1265.             var c = curNode.findChild(attr, keys[index]);
  1266.             if(!c){
  1267.                 if(callback){
  1268.                     callback(false, curNode);
  1269.                 }
  1270.                 return;
  1271.             }
  1272.             curNode = c;
  1273.             c.expand(false, false, f);
  1274.         };
  1275.         curNode.expand(false, false, f);
  1276.     },
  1277.     /**
  1278.      * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Ext.data.Node#getPath}
  1279.      * @param {String} path
  1280.      * @param {String} attr (optional) The attribute used in the path (see {@link Ext.data.Node#getPath} for more info)
  1281.      * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
  1282.      * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
  1283.      */
  1284.     selectPath : function(path, attr, callback){
  1285.         attr = attr || "id";
  1286.         var keys = path.split(this.pathSeparator);
  1287.         var v = keys.pop();
  1288.         if(keys.length > 0){
  1289.             var f = function(success, node){
  1290.                 if(success && node){
  1291.                     var n = node.findChild(attr, v);
  1292.                     if(n){
  1293.                         n.select();
  1294.                         if(callback){
  1295.                             callback(true, n);
  1296.                         }
  1297.                     }else if(callback){
  1298.                         callback(false, n);
  1299.                     }
  1300.                 }else{
  1301.                     if(callback){
  1302.                         callback(false, n);
  1303.                     }
  1304.                 }
  1305.             };
  1306.             this.expandPath(keys.join(this.pathSeparator), attr, f);
  1307.         }else{
  1308.             this.root.select();
  1309.             if(callback){
  1310.                 callback(true, this.root);
  1311.             }
  1312.         }
  1313.     },
  1314.     /**
  1315.      * Returns the underlying Element for this tree
  1316.      * @return {Ext.Element} The Element
  1317.      */
  1318.     getTreeEl : function(){
  1319.         return this.body;
  1320.     },
  1321.     // private
  1322.     onRender : function(ct, position){
  1323.         Ext.tree.TreePanel.superclass.onRender.call(this, ct, position);
  1324.         this.el.addClass('x-tree');
  1325.         this.innerCt = this.body.createChild({tag:"ul",
  1326.                cls:"x-tree-root-ct " +
  1327.                (this.useArrows ? 'x-tree-arrows' : this.lines ? "x-tree-lines" : "x-tree-no-lines")});
  1328.     },
  1329.     // private
  1330.     initEvents : function(){
  1331.         Ext.tree.TreePanel.superclass.initEvents.call(this);
  1332.         if(this.containerScroll){
  1333.             Ext.dd.ScrollManager.register(this.body);
  1334.         }
  1335.         if((this.enableDD || this.enableDrop) && !this.dropZone){
  1336.            /**
  1337.             * The dropZone used by this tree if drop is enabled (see {@link #enableDD} or {@link #enableDrop})
  1338.             * @property dropZone
  1339.             * @type Ext.tree.TreeDropZone
  1340.             */
  1341.              this.dropZone = new Ext.tree.TreeDropZone(this, this.dropConfig || {
  1342.                ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
  1343.            });
  1344.         }
  1345.         if((this.enableDD || this.enableDrag) && !this.dragZone){
  1346.            /**
  1347.             * The dragZone used by this tree if drag is enabled (see {@link #enableDD} or {@link #enableDrag})
  1348.             * @property dragZone
  1349.             * @type Ext.tree.TreeDragZone
  1350.             */
  1351.             this.dragZone = new Ext.tree.TreeDragZone(this, this.dragConfig || {
  1352.                ddGroup: this.ddGroup || "TreeDD",
  1353.                scroll: this.ddScroll
  1354.            });
  1355.         }
  1356.         this.getSelectionModel().init(this);
  1357.     },
  1358.     // private
  1359.     afterRender : function(){
  1360.         Ext.tree.TreePanel.superclass.afterRender.call(this);
  1361.         this.root.render();
  1362.         if(!this.rootVisible){
  1363.             this.root.renderChildren();
  1364.         }
  1365.     },
  1366.     onDestroy : function(){
  1367.         if(this.rendered){
  1368.             this.body.removeAllListeners();
  1369.             Ext.dd.ScrollManager.unregister(this.body);
  1370.             if(this.dropZone){
  1371.                 this.dropZone.unreg();
  1372.             }
  1373.             if(this.dragZone){
  1374.                this.dragZone.unreg();
  1375.             }
  1376.         }
  1377.         this.root.destroy();
  1378.         this.nodeHash = null;
  1379.         Ext.tree.TreePanel.superclass.onDestroy.call(this);
  1380.     }
  1381.     /**
  1382.      * @cfg {String/Number} activeItem
  1383.      * @hide
  1384.      */
  1385.     /**
  1386.      * @cfg {Boolean} autoDestroy
  1387.      * @hide
  1388.      */
  1389.     /**
  1390.      * @cfg {Object/String/Function} autoLoad
  1391.      * @hide
  1392.      */
  1393.     /**
  1394.      * @cfg {Boolean} autoWidth
  1395.      * @hide
  1396.      */
  1397.     /**
  1398.      * @cfg {Boolean/Number} bufferResize
  1399.      * @hide
  1400.      */
  1401.     /**
  1402.      * @cfg {String} defaultType
  1403.      * @hide
  1404.      */
  1405.     /**
  1406.      * @cfg {Object} defaults
  1407.      * @hide
  1408.      */
  1409.     /**
  1410.      * @cfg {Boolean} hideBorders
  1411.      * @hide
  1412.      */
  1413.     /**
  1414.      * @cfg {Mixed} items
  1415.      * @hide
  1416.      */
  1417.     /**
  1418.      * @cfg {String} layout
  1419.      * @hide
  1420.      */
  1421.     /**
  1422.      * @cfg {Object} layoutConfig
  1423.      * @hide
  1424.      */
  1425.     /**
  1426.      * @cfg {Boolean} monitorResize
  1427.      * @hide
  1428.      */
  1429.     /**
  1430.      * @property items
  1431.      * @hide
  1432.      */
  1433.     /**
  1434.      * @method cascade
  1435.      * @hide
  1436.      */
  1437.     /**
  1438.      * @method doLayout
  1439.      * @hide
  1440.      */
  1441.     /**
  1442.      * @method find
  1443.      * @hide
  1444.      */
  1445.     /**
  1446.      * @method findBy
  1447.      * @hide
  1448.      */
  1449.     /**
  1450.      * @method findById
  1451.      * @hide
  1452.      */
  1453.     /**
  1454.      * @method findByType
  1455.      * @hide
  1456.      */
  1457.     /**
  1458.      * @method getComponent
  1459.      * @hide
  1460.      */
  1461.     /**
  1462.      * @method getLayout
  1463.      * @hide
  1464.      */
  1465.     /**
  1466.      * @method getUpdater
  1467.      * @hide
  1468.      */
  1469.     /**
  1470.      * @method insert
  1471.      * @hide
  1472.      */
  1473.     /**
  1474.      * @method load
  1475.      * @hide
  1476.      */
  1477.     /**
  1478.      * @method remove
  1479.      * @hide
  1480.      */
  1481.     /**
  1482.      * @event add
  1483.      * @hide
  1484.      */
  1485.     /**
  1486.      * @method removeAll
  1487.      * @hide
  1488.      */
  1489.     /**
  1490.      * @event afterLayout
  1491.      * @hide
  1492.      */
  1493.     /**
  1494.      * @event beforeadd
  1495.      * @hide
  1496.      */
  1497.     /**
  1498.      * @event beforeremove
  1499.      * @hide
  1500.      */
  1501.     /**
  1502.      * @event remove
  1503.      * @hide
  1504.      */
  1505.     /**
  1506.      * @cfg {String} allowDomMove  @hide
  1507.      */
  1508.     /**
  1509.      * @cfg {String} autoEl @hide
  1510.      */
  1511.     /**
  1512.      * @cfg {String} applyTo  @hide
  1513.      */
  1514.     /**
  1515.      * @cfg {String} contentEl  @hide
  1516.      */
  1517.     /**
  1518.      * @cfg {String} disabledClass  @hide
  1519.      */
  1520.     /**
  1521.      * @cfg {String} elements  @hide
  1522.      */
  1523.     /**
  1524.      * @cfg {String} html  @hide
  1525.      */
  1526.     /**
  1527.      * @cfg {Boolean} preventBodyReset
  1528.      * @hide
  1529.      */
  1530.     /**
  1531.      * @property disabled
  1532.      * @hide
  1533.      */
  1534.     /**
  1535.      * @method applyToMarkup
  1536.      * @hide
  1537.      */
  1538.     /**
  1539.      * @method enable
  1540.      * @hide
  1541.      */
  1542.     /**
  1543.      * @method disable
  1544.      * @hide
  1545.      */
  1546.     /**
  1547.      * @method setDisabled
  1548.      * @hide
  1549.      */
  1550. });
  1551. Ext.tree.TreePanel.nodeTypes = {};
  1552. Ext.reg('treepanel', Ext.tree.TreePanel);Ext.tree.TreeEventModel = function(tree){
  1553.     this.tree = tree;
  1554.     this.tree.on('render', this.initEvents, this);