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

中间件编程

开发平台:

JavaScript

  1.         if(!forceRefresh && vd && this.el){
  2.             var t = date.getTime();
  3.             if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
  4.                 this.cells.removeClass('x-date-selected');
  5.                 this.cells.each(function(c){
  6.                    if(c.dom.firstChild.dateValue == t){
  7.                        c.addClass('x-date-selected');
  8.                        if(vis){
  9.                            Ext.fly(c.dom.firstChild).focus(50);
  10.                        }
  11.                        return false;
  12.                    }
  13.                 });
  14.                 return;
  15.             }
  16.         }
  17.         var days = date.getDaysInMonth();
  18.         var firstOfMonth = date.getFirstDateOfMonth();
  19.         var startingPos = firstOfMonth.getDay()-this.startDay;
  20.         if(startingPos <= this.startDay){
  21.             startingPos += 7;
  22.         }
  23.         var pm = date.add('mo', -1);
  24.         var prevStart = pm.getDaysInMonth()-startingPos;
  25.         var cells = this.cells.elements;
  26.         var textEls = this.textNodes;
  27.         days += startingPos;
  28.         // convert everything to numbers so it's fast
  29.         var day = 86400000;
  30.         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
  31.         var today = new Date().clearTime().getTime();
  32.         var sel = date.clearTime().getTime();
  33.         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
  34.         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
  35.         var ddMatch = this.disabledDatesRE;
  36.         var ddText = this.disabledDatesText;
  37.         var ddays = this.disabledDays ? this.disabledDays.join('') : false;
  38.         var ddaysText = this.disabledDaysText;
  39.         var format = this.format;
  40.         if(this.showToday){
  41.             var td = new Date().clearTime();
  42.             var disable = (td < min || td > max ||
  43.                 (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
  44.                 (ddays && ddays.indexOf(td.getDay()) != -1));
  45.             if(!this.disabled){
  46.                 this.todayBtn.setDisabled(disable);
  47.                 this.todayKeyListener[disable ? 'disable' : 'enable']();
  48.             }
  49.         }
  50.         var setCellClass = function(cal, cell){
  51.             cell.title = '';
  52.             var t = d.getTime();
  53.             cell.firstChild.dateValue = t;
  54.             if(t == today){
  55.                 cell.className += ' x-date-today';
  56.                 cell.title = cal.todayText;
  57.             }
  58.             if(t == sel){
  59.                 cell.className += ' x-date-selected';
  60.                 if(vis){
  61.                     Ext.fly(cell.firstChild).focus(50);
  62.                 }
  63.             }
  64.             // disabling
  65.             if(t < min) {
  66.                 cell.className = ' x-date-disabled';
  67.                 cell.title = cal.minText;
  68.                 return;
  69.             }
  70.             if(t > max) {
  71.                 cell.className = ' x-date-disabled';
  72.                 cell.title = cal.maxText;
  73.                 return;
  74.             }
  75.             if(ddays){
  76.                 if(ddays.indexOf(d.getDay()) != -1){
  77.                     cell.title = ddaysText;
  78.                     cell.className = ' x-date-disabled';
  79.                 }
  80.             }
  81.             if(ddMatch && format){
  82.                 var fvalue = d.dateFormat(format);
  83.                 if(ddMatch.test(fvalue)){
  84.                     cell.title = ddText.replace('%0', fvalue);
  85.                     cell.className = ' x-date-disabled';
  86.                 }
  87.             }
  88.         };
  89.         var i = 0;
  90.         for(; i < startingPos; i++) {
  91.             textEls[i].innerHTML = (++prevStart);
  92.             d.setDate(d.getDate()+1);
  93.             cells[i].className = 'x-date-prevday';
  94.             setCellClass(this, cells[i]);
  95.         }
  96.         for(; i < days; i++){
  97.             var intDay = i - startingPos + 1;
  98.             textEls[i].innerHTML = (intDay);
  99.             d.setDate(d.getDate()+1);
  100.             cells[i].className = 'x-date-active';
  101.             setCellClass(this, cells[i]);
  102.         }
  103.         var extraDays = 0;
  104.         for(; i < 42; i++) {
  105.              textEls[i].innerHTML = (++extraDays);
  106.              d.setDate(d.getDate()+1);
  107.              cells[i].className = 'x-date-nextday';
  108.              setCellClass(this, cells[i]);
  109.         }
  110.         this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());
  111.         if(!this.internalRender){
  112.             var main = this.el.dom.firstChild;
  113.             var w = main.offsetWidth;
  114.             this.el.setWidth(w + this.el.getBorderWidth('lr'));
  115.             Ext.fly(main).setWidth(w);
  116.             this.internalRender = true;
  117.             // opera does not respect the auto grow header center column
  118.             // then, after it gets a width opera refuses to recalculate
  119.             // without a second pass
  120.             if(Ext.isOpera && !this.secondPass){
  121.                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
  122.                 this.secondPass = true;
  123.                 this.update.defer(10, this, [date]);
  124.             }
  125.         }
  126.     },
  127.     // private
  128.     beforeDestroy : function() {
  129.         if(this.rendered){
  130.             this.keyNav.disable();
  131.             this.keyNav = null;
  132.             Ext.destroy(
  133.                 this.leftClickRpt,
  134.                 this.rightClickRpt,
  135.                 this.monthPicker,
  136.                 this.eventEl,
  137.                 this.mbtn,
  138.                 this.todayBtn
  139.             );
  140.         }
  141.     }
  142.     /**
  143.      * @cfg {String} autoEl @hide
  144.      */
  145. });
  146. Ext.reg('datepicker', Ext.DatePicker);
  147. /**  * @class Ext.LoadMask  * A simple utility class for generically masking elements while loading data.  If the {@link #store}  * config option is specified, the masking will be automatically synchronized with the store's loading  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the  * element's Updater load indicator and will be destroyed after the initial load.  * <p>Example usage:</p>  *<pre><code> // Basic mask: var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."}); myMask.show(); </code></pre>  * @constructor  * Create a new LoadMask  * @param {Mixed} el The element or DOM node, or its id  * @param {Object} config The config object  */ Ext.LoadMask = function(el, config){     this.el = Ext.get(el);     Ext.apply(this, config);     if(this.store){         this.store.on('beforeload', this.onBeforeLoad, this);         this.store.on('load', this.onLoad, this);         this.store.on('exception', this.onLoad, this);         this.removeMask = Ext.value(this.removeMask, false);     }else{         var um = this.el.getUpdater();         um.showLoadIndicator = false; // disable the default indicator         um.on('beforeupdate', this.onBeforeLoad, this);         um.on('update', this.onLoad, this);         um.on('failure', this.onLoad, this);         this.removeMask = Ext.value(this.removeMask, true);     } }; Ext.LoadMask.prototype = {     /**      * @cfg {Ext.data.Store} store      * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and      * hidden on either load sucess, or load fail.      */     /**      * @cfg {Boolean} removeMask      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.      */     /**      * @cfg {String} msg      * The text to display in a centered loading message box (defaults to 'Loading...')      */     msg : 'Loading...',     /**      * @cfg {String} msgCls      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")      */     msgCls : 'x-mask-loading',     /**      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)      * @type Boolean      */     disabled: false,     /**      * Disables the mask to prevent it from being displayed      */     disable : function(){        this.disabled = true;     },     /**      * Enables the mask so that it can be displayed      */     enable : function(){         this.disabled = false;     },     // private     onLoad : function(){         this.el.unmask(this.removeMask);     },     // private     onBeforeLoad : function(){         if(!this.disabled){             this.el.mask(this.msg, this.msgCls);         }     },     /**      * Show this LoadMask over the configured Element.      */     show: function(){         this.onBeforeLoad();     },     /**      * Hide this LoadMask.      */     hide: function(){         this.onLoad();     },     // private     destroy : function(){         if(this.store){             this.store.un('beforeload', this.onBeforeLoad, this);             this.store.un('load', this.onLoad, this);             this.store.un('exception', this.onLoad, this);         }else{             var um = this.el.getUpdater();             um.un('beforeupdate', this.onBeforeLoad, this);             um.un('update', this.onLoad, this);             um.un('failure', this.onLoad, this);         }     } };/**
  148.  * @class Ext.Slider
  149.  * @extends Ext.BoxComponent
  150.  * Slider which supports vertical or horizontal orientation, keyboard adjustments,
  151.  * configurable snapping, axis clicking and animation. Can be added as an item to
  152.  * any container. Example usage:
  153. <pre><code>
  154. new Ext.Slider({
  155.     renderTo: Ext.getBody(),
  156.     width: 200,
  157.     value: 50,
  158.     increment: 10,
  159.     minValue: 0,
  160.     maxValue: 100
  161. });
  162. </code></pre>
  163.  */
  164. Ext.Slider = Ext.extend(Ext.BoxComponent, {
  165. /**
  166.  * @cfg {Number} value The value to initialize the slider with. Defaults to minValue.
  167.  */
  168. /**
  169.  * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.
  170.  */
  171.     vertical: false,
  172. /**
  173.  * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.
  174.  */
  175.     minValue: 0,
  176. /**
  177.  * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.
  178.  */
  179.     maxValue: 100,
  180.     /**
  181.      * @cfg {Number/Boolean} decimalPrecision.
  182.      * <p>The number of decimal places to which to round the Slider's value. Defaults to 0.</p>
  183.      * <p>To disable rounding, configure as <tt><b>false</b></tt>.</p>
  184.      */
  185.     decimalPrecision: 0,
  186. /**
  187.  * @cfg {Number} keyIncrement How many units to change the Slider when adjusting with keyboard navigation. Defaults to 1. If the increment config is larger, it will be used instead.
  188.  */
  189.     keyIncrement: 1,
  190. /**
  191.  * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
  192.  */
  193.     increment: 0,
  194. // private
  195.     clickRange: [5,15],
  196. /**
  197.  * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true
  198.  */
  199.     clickToChange : true,
  200. /**
  201.  * @cfg {Boolean} animate Turn on or off animation. Defaults to true
  202.  */
  203.     animate: true,
  204.     /**
  205.      * True while the thumb is in a drag operation
  206.      * @type boolean
  207.      */
  208.     dragging: false,
  209.     // private override
  210.     initComponent : function(){
  211.         if(!Ext.isDefined(this.value)){
  212.             this.value = this.minValue;
  213.         }
  214.         Ext.Slider.superclass.initComponent.call(this);
  215.         this.keyIncrement = Math.max(this.increment, this.keyIncrement);
  216.         this.addEvents(
  217.             /**
  218.              * @event beforechange
  219.              * Fires before the slider value is changed. By returning false from an event handler,
  220.              * you can cancel the event and prevent the slider from changing.
  221.  * @param {Ext.Slider} slider The slider
  222.  * @param {Number} newValue The new value which the slider is being changed to.
  223.  * @param {Number} oldValue The old value which the slider was previously.
  224.              */
  225. 'beforechange',
  226. /**
  227.  * @event change
  228.  * Fires when the slider value is changed.
  229.  * @param {Ext.Slider} slider The slider
  230.  * @param {Number} newValue The new value which the slider has been changed to.
  231.  */
  232. 'change',
  233. /**
  234.  * @event changecomplete
  235.  * Fires when the slider value is changed by the user and any drag operations have completed.
  236.  * @param {Ext.Slider} slider The slider
  237.  * @param {Number} newValue The new value which the slider has been changed to.
  238.  */
  239. 'changecomplete',
  240. /**
  241.  * @event dragstart
  242.              * Fires after a drag operation has started.
  243.  * @param {Ext.Slider} slider The slider
  244.  * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
  245.  */
  246. 'dragstart',
  247. /**
  248.  * @event drag
  249.              * Fires continuously during the drag operation while the mouse is moving.
  250.  * @param {Ext.Slider} slider The slider
  251.  * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
  252.  */
  253. 'drag',
  254. /**
  255.  * @event dragend
  256.              * Fires after the drag operation has completed.
  257.  * @param {Ext.Slider} slider The slider
  258.  * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
  259.  */
  260. 'dragend'
  261. );
  262.         if(this.vertical){
  263.             Ext.apply(this, Ext.Slider.Vertical);
  264.         }
  265.     },
  266. // private override
  267.     onRender : function(){
  268.         this.autoEl = {
  269.             cls: 'x-slider ' + (this.vertical ? 'x-slider-vert' : 'x-slider-horz'),
  270.             cn:{cls:'x-slider-end',cn:{cls:'x-slider-inner',cn:[{cls:'x-slider-thumb'},{tag:'a', cls:'x-slider-focus', href:"#", tabIndex: '-1', hidefocus:'on'}]}}
  271.         };
  272.         Ext.Slider.superclass.onRender.apply(this, arguments);
  273.         this.endEl = this.el.first();
  274.         this.innerEl = this.endEl.first();
  275.         this.thumb = this.innerEl.first();
  276.         this.halfThumb = (this.vertical ? this.thumb.getHeight() : this.thumb.getWidth())/2;
  277.         this.focusEl = this.thumb.next();
  278.         this.initEvents();
  279.     },
  280. // private override
  281.     initEvents : function(){
  282.         this.thumb.addClassOnOver('x-slider-thumb-over');
  283.         this.mon(this.el, {
  284.             scope: this,
  285.             mousedown: this.onMouseDown,
  286.             keydown: this.onKeyDown
  287.         });
  288.         this.focusEl.swallowEvent("click", true);
  289.         this.tracker = new Ext.dd.DragTracker({
  290.             onBeforeStart: this.onBeforeDragStart.createDelegate(this),
  291.             onStart: this.onDragStart.createDelegate(this),
  292.             onDrag: this.onDrag.createDelegate(this),
  293.             onEnd: this.onDragEnd.createDelegate(this),
  294.             tolerance: 3,
  295.             autoStart: 300
  296.         });
  297.         this.tracker.initEl(this.thumb);
  298.         this.on('beforedestroy', this.tracker.destroy, this.tracker);
  299.     },
  300. // private override
  301.     onMouseDown : function(e){
  302.         if(this.disabled) {return;}
  303.         if(this.clickToChange && e.target != this.thumb.dom){
  304.             var local = this.innerEl.translatePoints(e.getXY());
  305.             this.onClickChange(local);
  306.         }
  307.         this.focus();
  308.     },
  309. // private
  310.     onClickChange : function(local){
  311.         if(local.top > this.clickRange[0] && local.top < this.clickRange[1]){
  312.             this.setValue(Ext.util.Format.round(this.reverseValue(local.left), this.decimalPrecision), undefined, true);
  313.         }
  314.     },
  315. // private
  316.     onKeyDown : function(e){
  317.         if(this.disabled){e.preventDefault();return;}
  318.         var k = e.getKey();
  319.         switch(k){
  320.             case e.UP:
  321.             case e.RIGHT:
  322.                 e.stopEvent();
  323.                 if(e.ctrlKey){
  324.                     this.setValue(this.maxValue, undefined, true);
  325.                 }else{
  326.                     this.setValue(this.value+this.keyIncrement, undefined, true);
  327.                 }
  328.             break;
  329.             case e.DOWN:
  330.             case e.LEFT:
  331.                 e.stopEvent();
  332.                 if(e.ctrlKey){
  333.                     this.setValue(this.minValue, undefined, true);
  334.                 }else{
  335.                     this.setValue(this.value-this.keyIncrement, undefined, true);
  336.                 }
  337.             break;
  338.             default:
  339.                 e.preventDefault();
  340.         }
  341.     },
  342. // private
  343.     doSnap : function(value){
  344.         if(!this.increment || this.increment == 1 || !value) {
  345.             return value;
  346.         }
  347.         var newValue = value, inc = this.increment;
  348.         var m = value % inc;
  349.         if(m != 0){
  350.             newValue -= m;
  351.             if(m * 2 > inc){
  352.                 newValue += inc;
  353.             }else if(m * 2 < -inc){
  354.                 newValue -= inc;
  355.             }
  356.         }
  357.         return newValue.constrain(this.minValue,  this.maxValue);
  358.     },
  359. // private
  360.     afterRender : function(){
  361.         Ext.Slider.superclass.afterRender.apply(this, arguments);
  362.         if(this.value !== undefined){
  363.             var v = this.normalizeValue(this.value);
  364.             if(v !== this.value){
  365.                 delete this.value;
  366.                 this.setValue(v, false);
  367.             }else{
  368.                 this.moveThumb(this.translateValue(v), false);
  369.             }
  370.         }
  371.     },
  372. // private
  373.     getRatio : function(){
  374.         var w = this.innerEl.getWidth();
  375.         var v = this.maxValue - this.minValue;
  376.         return v == 0 ? w : (w/v);
  377.     },
  378. // private
  379.     normalizeValue : function(v){
  380.         v = this.doSnap(v);
  381.         v = Ext.util.Format.round(v, this.decimalPrecision);
  382.         v = v.constrain(this.minValue, this.maxValue);
  383.         return v;
  384.     },
  385. /**
  386.  * Programmatically sets the value of the Slider. Ensures that the value is constrained within
  387.  * the minValue and maxValue.
  388.  * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
  389.  * @param {Boolean} animate Turn on or off animation, defaults to true
  390.  */
  391.     setValue : function(v, animate, changeComplete){
  392.         v = this.normalizeValue(v);
  393.         if(v !== this.value && this.fireEvent('beforechange', this, v, this.value) !== false){
  394.             this.value = v;
  395.             this.moveThumb(this.translateValue(v), animate !== false);
  396.             this.fireEvent('change', this, v);
  397.             if(changeComplete){
  398.                 this.fireEvent('changecomplete', this, v);
  399.             }
  400.         }
  401.     },
  402. // private
  403.     translateValue : function(v){
  404.         var ratio = this.getRatio();
  405.         return (v * ratio)-(this.minValue * ratio)-this.halfThumb;
  406.     },
  407. reverseValue : function(pos){
  408.         var ratio = this.getRatio();
  409.         return (pos+this.halfThumb+(this.minValue * ratio))/ratio;
  410.     },
  411. // private
  412.     moveThumb: function(v, animate){
  413.         if(!animate || this.animate === false){
  414.             this.thumb.setLeft(v);
  415.         }else{
  416.             this.thumb.shift({left: v, stopFx: true, duration:.35});
  417.         }
  418.     },
  419. // private
  420.     focus : function(){
  421.         this.focusEl.focus(10);
  422.     },
  423. // private
  424.     onBeforeDragStart : function(e){
  425.         return !this.disabled;
  426.     },
  427. // private
  428.     onDragStart: function(e){
  429.         this.thumb.addClass('x-slider-thumb-drag');
  430.         this.dragging = true;
  431.         this.dragStartValue = this.value;
  432.         this.fireEvent('dragstart', this, e);
  433.     },
  434. // private
  435.     onDrag: function(e){
  436.         var pos = this.innerEl.translatePoints(this.tracker.getXY());
  437.         this.setValue(Ext.util.Format.round(this.reverseValue(pos.left), this.decimalPrecision), false);
  438.         this.fireEvent('drag', this, e);
  439.     },
  440. // private
  441.     onDragEnd: function(e){
  442.         this.thumb.removeClass('x-slider-thumb-drag');
  443.         this.dragging = false;
  444.         this.fireEvent('dragend', this, e);
  445.         if(this.dragStartValue != this.value){
  446.             this.fireEvent('changecomplete', this, this.value);
  447.         }
  448.     },
  449. // private
  450.     onResize : function(w, h){
  451.         this.innerEl.setWidth(w - (this.el.getPadding('l') + this.endEl.getPadding('r')));
  452.         this.syncThumb();
  453.     },
  454.     
  455.     //private
  456.     onDisable: function(){
  457.         Ext.Slider.superclass.onDisable.call(this);
  458.         this.thumb.addClass(this.disabledClass);
  459.         if(Ext.isIE){
  460.             //IE breaks when using overflow visible and opacity other than 1.
  461.             //Create a place holder for the thumb and display it.
  462.             var xy = this.thumb.getXY();
  463.             this.thumb.hide();
  464.             this.innerEl.addClass(this.disabledClass).dom.disabled = true;
  465.             if (!this.thumbHolder){
  466.                 this.thumbHolder = this.endEl.createChild({cls: 'x-slider-thumb ' + this.disabledClass});    
  467.             }
  468.             this.thumbHolder.show().setXY(xy);
  469.         }
  470.     },
  471.     
  472.     //private
  473.     onEnable: function(){
  474.         Ext.Slider.superclass.onEnable.call(this);
  475.         this.thumb.removeClass(this.disabledClass);
  476.         if(Ext.isIE){
  477.             this.innerEl.removeClass(this.disabledClass).dom.disabled = false;
  478.             if (this.thumbHolder){
  479.                 this.thumbHolder.hide();
  480.             }
  481.             this.thumb.show();
  482.             this.syncThumb();
  483.         }
  484.     },
  485.     
  486.     /**
  487.      * Synchronizes the thumb position to the proper proportion of the total component width based
  488.      * on the current slider {@link #value}.  This will be called automatically when the Slider
  489.      * is resized by a layout, but if it is rendered auto width, this method can be called from
  490.      * another resize handler to sync the Slider if necessary.
  491.      */
  492.     syncThumb : function(){
  493.         if(this.rendered){
  494.             this.moveThumb(this.translateValue(this.value));
  495.         }
  496.     },
  497. /**
  498.  * Returns the current value of the slider
  499.  * @return {Number} The current value of the slider
  500.  */
  501.     getValue : function(){
  502.         return this.value;
  503.     }
  504. });
  505. Ext.reg('slider', Ext.Slider);
  506. // private class to support vertical sliders
  507. Ext.Slider.Vertical = {
  508.     onResize : function(w, h){
  509.         this.innerEl.setHeight(h - (this.el.getPadding('t') + this.endEl.getPadding('b')));
  510.         this.syncThumb();
  511.     },
  512.     getRatio : function(){
  513.         var h = this.innerEl.getHeight();
  514.         var v = this.maxValue - this.minValue;
  515.         return h/v;
  516.     },
  517.     moveThumb: function(v, animate){
  518.         if(!animate || this.animate === false){
  519.             this.thumb.setBottom(v);
  520.         }else{
  521.             this.thumb.shift({bottom: v, stopFx: true, duration:.35});
  522.         }
  523.     },
  524.     onDrag: function(e){
  525.         var pos = this.innerEl.translatePoints(this.tracker.getXY());
  526.         var bottom = this.innerEl.getHeight()-pos.top;
  527.         this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), false);
  528.         this.fireEvent('drag', this, e);
  529.     },
  530.     onClickChange : function(local){
  531.         if(local.left > this.clickRange[0] && local.left < this.clickRange[1]){
  532.             var bottom = this.innerEl.getHeight()-local.top;
  533.             this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), undefined, true);
  534.         }
  535.     }
  536. };/**
  537.  * @class Ext.ProgressBar
  538.  * @extends Ext.BoxComponent
  539.  * <p>An updateable progress bar component.  The progress bar supports two different modes: manual and automatic.</p>
  540.  * <p>In manual mode, you are responsible for showing, updating (via {@link #updateProgress}) and clearing the
  541.  * progress bar as needed from your own code.  This method is most appropriate when you want to show progress
  542.  * throughout an operation that has predictable points of interest at which you can update the control.</p>
  543.  * <p>In automatic mode, you simply call {@link #wait} and let the progress bar run indefinitely, only clearing it
  544.  * once the operation is complete.  You can optionally have the progress bar wait for a specific amount of time
  545.  * and then clear itself.  Automatic mode is most appropriate for timed operations or asynchronous operations in
  546.  * which you have no need for indicating intermediate progress.</p>
  547.  * @cfg {Float} value A floating point value between 0 and 1 (e.g., .5, defaults to 0)
  548.  * @cfg {String} text The progress bar text (defaults to '')
  549.  * @cfg {Mixed} textEl The element to render the progress text to (defaults to the progress
  550.  * bar's internal text element)
  551.  * @cfg {String} id The progress bar element's id (defaults to an auto-generated id)
  552.  * @xtype progress
  553.  */
  554. Ext.ProgressBar = Ext.extend(Ext.BoxComponent, {
  555.    /**
  556.     * @cfg {String} baseCls
  557.     * The base CSS class to apply to the progress bar's wrapper element (defaults to 'x-progress')
  558.     */
  559.     baseCls : 'x-progress',
  560.     
  561.     /**
  562.     * @cfg {Boolean} animate
  563.     * True to animate the progress bar during transitions (defaults to false)
  564.     */
  565.     animate : false,
  566.     // private
  567.     waitTimer : null,
  568.     // private
  569.     initComponent : function(){
  570.         Ext.ProgressBar.superclass.initComponent.call(this);
  571.         this.addEvents(
  572.             /**
  573.              * @event update
  574.              * Fires after each update interval
  575.              * @param {Ext.ProgressBar} this
  576.              * @param {Number} The current progress value
  577.              * @param {String} The current progress text
  578.              */
  579.             "update"
  580.         );
  581.     },
  582.     // private
  583.     onRender : function(ct, position){
  584.         var tpl = new Ext.Template(
  585.             '<div class="{cls}-wrap">',
  586.                 '<div class="{cls}-inner">',
  587.                     '<div class="{cls}-bar">',
  588.                         '<div class="{cls}-text">',
  589.                             '<div>&#160;</div>',
  590.                         '</div>',
  591.                     '</div>',
  592.                     '<div class="{cls}-text {cls}-text-back">',
  593.                         '<div>&#160;</div>',
  594.                     '</div>',
  595.                 '</div>',
  596.             '</div>'
  597.         );
  598.         this.el = position ? tpl.insertBefore(position, {cls: this.baseCls}, true)
  599.          : tpl.append(ct, {cls: this.baseCls}, true);
  600.         
  601.         if(this.id){
  602.             this.el.dom.id = this.id;
  603.         }
  604.         var inner = this.el.dom.firstChild;
  605.         this.progressBar = Ext.get(inner.firstChild);
  606.         if(this.textEl){
  607.             //use an external text el
  608.             this.textEl = Ext.get(this.textEl);
  609.             delete this.textTopEl;
  610.         }else{
  611.             //setup our internal layered text els
  612.             this.textTopEl = Ext.get(this.progressBar.dom.firstChild);
  613.             var textBackEl = Ext.get(inner.childNodes[1]);
  614.             this.textTopEl.setStyle("z-index", 99).addClass('x-hidden');
  615.             this.textEl = new Ext.CompositeElement([this.textTopEl.dom.firstChild, textBackEl.dom.firstChild]);
  616.             this.textEl.setWidth(inner.offsetWidth);
  617.         }
  618.         this.progressBar.setHeight(inner.offsetHeight);
  619.     },
  620.     
  621.     // private
  622.     afterRender : function(){
  623.         Ext.ProgressBar.superclass.afterRender.call(this);
  624.         if(this.value){
  625.             this.updateProgress(this.value, this.text);
  626.         }else{
  627.             this.updateText(this.text);
  628.         }
  629.     },
  630.     /**
  631.      * Updates the progress bar value, and optionally its text.  If the text argument is not specified,
  632.      * any existing text value will be unchanged.  To blank out existing text, pass ''.  Note that even
  633.      * if the progress bar value exceeds 1, it will never automatically reset -- you are responsible for
  634.      * determining when the progress is complete and calling {@link #reset} to clear and/or hide the control.
  635.      * @param {Float} value (optional) A floating point value between 0 and 1 (e.g., .5, defaults to 0)
  636.      * @param {String} text (optional) The string to display in the progress text element (defaults to '')
  637.      * @param {Boolean} animate (optional) Whether to animate the transition of the progress bar. If this value is
  638.      * not specified, the default for the class is used (default to false)
  639.      * @return {Ext.ProgressBar} this
  640.      */
  641.     updateProgress : function(value, text, animate){
  642.         this.value = value || 0;
  643.         if(text){
  644.             this.updateText(text);
  645.         }
  646.         if(this.rendered){
  647.             var w = Math.floor(value*this.el.dom.firstChild.offsetWidth);
  648.             this.progressBar.setWidth(w, animate === true || (animate !== false && this.animate));
  649.             if(this.textTopEl){
  650.                 //textTopEl should be the same width as the bar so overflow will clip as the bar moves
  651.                 this.textTopEl.removeClass('x-hidden').setWidth(w);
  652.             }
  653.         }
  654.         this.fireEvent('update', this, value, text);
  655.         return this;
  656.     },
  657.     /**
  658.      * Initiates an auto-updating progress bar.  A duration can be specified, in which case the progress
  659.      * bar will automatically reset after a fixed amount of time and optionally call a callback function
  660.      * if specified.  If no duration is passed in, then the progress bar will run indefinitely and must
  661.      * be manually cleared by calling {@link #reset}.  The wait method accepts a config object with
  662.      * the following properties:
  663.      * <pre>
  664. Property   Type          Description
  665. ---------- ------------  ----------------------------------------------------------------------
  666. duration   Number        The length of time in milliseconds that the progress bar should
  667.                          run before resetting itself (defaults to undefined, in which case it
  668.                          will run indefinitely until reset is called)
  669. interval   Number        The length of time in milliseconds between each progress update
  670.                          (defaults to 1000 ms)
  671. animate    Boolean       Whether to animate the transition of the progress bar. If this value is
  672.                          not specified, the default for the class is used.                                                   
  673. increment  Number        The number of progress update segments to display within the progress
  674.                          bar (defaults to 10).  If the bar reaches the end and is still
  675.                          updating, it will automatically wrap back to the beginning.
  676. text       String        Optional text to display in the progress bar element (defaults to '').
  677. fn         Function      A callback function to execute after the progress bar finishes auto-
  678.                          updating.  The function will be called with no arguments.  This function
  679.                          will be ignored if duration is not specified since in that case the
  680.                          progress bar can only be stopped programmatically, so any required function
  681.                          should be called by the same code after it resets the progress bar.
  682. scope      Object        The scope that is passed to the callback function (only applies when
  683.                          duration and fn are both passed).
  684. </pre>
  685.          *
  686.          * Example usage:
  687.          * <pre><code>
  688. var p = new Ext.ProgressBar({
  689.    renderTo: 'my-el'
  690. });
  691. //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
  692. p.wait({
  693.    interval: 100, //bar will move fast!
  694.    duration: 5000,
  695.    increment: 15,
  696.    text: 'Updating...',
  697.    scope: this,
  698.    fn: function(){
  699.       Ext.fly('status').update('Done!');
  700.    }
  701. });
  702. //Or update indefinitely until some async action completes, then reset manually
  703. p.wait();
  704. myAction.on('complete', function(){
  705.     p.reset();
  706.     Ext.fly('status').update('Done!');
  707. });
  708. </code></pre>
  709.      * @param {Object} config (optional) Configuration options
  710.      * @return {Ext.ProgressBar} this
  711.      */
  712.     wait : function(o){
  713.         if(!this.waitTimer){
  714.             var scope = this;
  715.             o = o || {};
  716.             this.updateText(o.text);
  717.             this.waitTimer = Ext.TaskMgr.start({
  718.                 run: function(i){
  719.                     var inc = o.increment || 10;
  720.                     this.updateProgress(((((i+inc)%inc)+1)*(100/inc))*0.01, null, o.animate);
  721.                 },
  722.                 interval: o.interval || 1000,
  723.                 duration: o.duration,
  724.                 onStop: function(){
  725.                     if(o.fn){
  726.                         o.fn.apply(o.scope || this);
  727.                     }
  728.                     this.reset();
  729.                 },
  730.                 scope: scope
  731.             });
  732.         }
  733.         return this;
  734.     },
  735.     /**
  736.      * Returns true if the progress bar is currently in a {@link #wait} operation
  737.      * @return {Boolean} True if waiting, else false
  738.      */
  739.     isWaiting : function(){
  740.         return this.waitTimer !== null;
  741.     },
  742.     /**
  743.      * Updates the progress bar text.  If specified, textEl will be updated, otherwise the progress
  744.      * bar itself will display the updated text.
  745.      * @param {String} text (optional) The string to display in the progress text element (defaults to '')
  746.      * @return {Ext.ProgressBar} this
  747.      */
  748.     updateText : function(text){
  749.         this.text = text || '&#160;';
  750.         if(this.rendered){
  751.             this.textEl.update(this.text);
  752.         }
  753.         return this;
  754.     },
  755.     
  756.     /**
  757.      * Synchronizes the inner bar width to the proper proportion of the total componet width based
  758.      * on the current progress {@link #value}.  This will be called automatically when the ProgressBar
  759.      * is resized by a layout, but if it is rendered auto width, this method can be called from
  760.      * another resize handler to sync the ProgressBar if necessary.
  761.      */
  762.     syncProgressBar : function(){
  763.         if(this.value){
  764.             this.updateProgress(this.value, this.text);
  765.         }
  766.         return this;
  767.     },
  768.     /**
  769.      * Sets the size of the progress bar.
  770.      * @param {Number} width The new width in pixels
  771.      * @param {Number} height The new height in pixels
  772.      * @return {Ext.ProgressBar} this
  773.      */
  774.     setSize : function(w, h){
  775.         Ext.ProgressBar.superclass.setSize.call(this, w, h);
  776.         if(this.textTopEl){
  777.             var inner = this.el.dom.firstChild;
  778.             this.textEl.setSize(inner.offsetWidth, inner.offsetHeight);
  779.         }
  780.         this.syncProgressBar();
  781.         return this;
  782.     },
  783.     /**
  784.      * Resets the progress bar value to 0 and text to empty string.  If hide = true, the progress
  785.      * bar will also be hidden (using the {@link #hideMode} property internally).
  786.      * @param {Boolean} hide (optional) True to hide the progress bar (defaults to false)
  787.      * @return {Ext.ProgressBar} this
  788.      */
  789.     reset : function(hide){
  790.         this.updateProgress(0);
  791.         if(this.textTopEl){
  792.             this.textTopEl.addClass('x-hidden');
  793.         }
  794.         if(this.waitTimer){
  795.             this.waitTimer.onStop = null; //prevent recursion
  796.             Ext.TaskMgr.stop(this.waitTimer);
  797.             this.waitTimer = null;
  798.         }
  799.         if(hide === true){
  800.             this.hide();
  801.         }
  802.         return this;
  803.     }
  804. });
  805. Ext.reg('progress', Ext.ProgressBar);/*  * These classes are derivatives of the similarly named classes in the YUI Library.  * The original license:  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.  * Code licensed under the BSD License:  * http://developer.yahoo.net/yui/license.txt  */ (function() { var Event=Ext.EventManager; var Dom=Ext.lib.Dom; /**  * @class Ext.dd.DragDrop  * Defines the interface and base operation of items that that can be  * dragged or can be drop targets.  It was designed to be extended, overriding  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.  * Up to three html elements can be associated with a DragDrop instance:  * <ul>  * <li>linked element: the element that is passed into the constructor.  * This is the element which defines the boundaries for interaction with  * other DragDrop objects.</li>  * <li>handle element(s): The drag operation only occurs if the element that  * was clicked matches a handle element.  By default this is the linked  * element, but there are times that you will want only a portion of the  * linked element to initiate the drag operation, and the setHandleElId()  * method provides a way to define this.</li>  * <li>drag element: this represents the element that would be moved along  * with the cursor during a drag operation.  By default, this is the linked  * element itself as in {@link Ext.dd.DD}.  setDragElId() lets you define  * a separate element that would be moved, as in {@link Ext.dd.DDProxy}.  * </li>  * </ul>  * This class should not be instantiated until the onload event to ensure that  * the associated elements are available.  * The following would define a DragDrop obj that would interact with any  * other DragDrop obj in the "group1" group:  * <pre>  *  dd = new Ext.dd.DragDrop("div1", "group1");  * </pre>  * Since none of the event handlers have been implemented, nothing would  * actually happen if you were to run the code above.  Normally you would  * override this class or one of the default implementations, but you can  * also override the methods you want on an instance of the class...  * <pre>  *  dd.onDragDrop = function(e, id) {  *  &nbsp;&nbsp;alert("dd was dropped on " + id);  *  }  * </pre>  * @constructor  * @param {String} id of the element that is linked to this instance  * @param {String} sGroup the group of related DragDrop objects  * @param {object} config an object containing configurable attributes  *                Valid properties for DragDrop:  *                    padding, isTarget, maintainOffset, primaryButtonOnly  */ Ext.dd.DragDrop = function(id, sGroup, config) {     if(id) {         this.init(id, sGroup, config);     } }; Ext.dd.DragDrop.prototype = {     /**      * Set to false to enable a DragDrop object to fire drag events while dragging      * over its own Element. Defaults to true - DragDrop objects do not by default      * fire drag events to themselves.      * @property ignoreSelf      * @type Boolean      */     /**      * The id of the element associated with this object.  This is what we      * refer to as the "linked element" because the size and position of      * this element is used to determine when the drag and drop objects have      * interacted.      * @property id      * @type String      */     id: null,     /**      * Configuration attributes passed into the constructor      * @property config      * @type object      */     config: null,     /**      * The id of the element that will be dragged.  By default this is same      * as the linked element , but could be changed to another element. Ex:      * Ext.dd.DDProxy      * @property dragElId      * @type String      * @private      */     dragElId: null,     /**      * The ID of the element that initiates the drag operation.  By default      * this is the linked element, but could be changed to be a child of this      * element.  This lets us do things like only starting the drag when the      * header element within the linked html element is clicked.      * @property handleElId      * @type String      * @private      */     handleElId: null,     /**      * An object who's property names identify HTML tags to be considered invalid as drag handles.      * A non-null property value identifies the tag as invalid. Defaults to the       * following value which prevents drag operations from being initiated by &lt;a> elements:<pre><code> {     A: "A" }</code></pre>      * @property invalidHandleTypes      * @type Object      */     invalidHandleTypes: null,     /**      * An object who's property names identify the IDs of elements to be considered invalid as drag handles.      * A non-null property value identifies the ID as invalid. For example, to prevent      * dragging from being initiated on element ID "foo", use:<pre><code> {     foo: true }</code></pre>      * @property invalidHandleIds      * @type Object      */     invalidHandleIds: null,     /**      * An Array of CSS class names for elements to be considered in valid as drag handles.      * @property invalidHandleClasses      * @type Array      */     invalidHandleClasses: null,     /**      * The linked element's absolute X position at the time the drag was      * started      * @property startPageX      * @type int      * @private      */     startPageX: 0,     /**      * The linked element's absolute X position at the time the drag was      * started      * @property startPageY      * @type int      * @private      */     startPageY: 0,     /**      * The group defines a logical collection of DragDrop objects that are      * related.  Instances only get events when interacting with other      * DragDrop object in the same group.  This lets us define multiple      * groups using a single DragDrop subclass if we want.      * @property groups      * @type object An object in the format {'group1':true, 'group2':true}      */     groups: null,     /**      * Individual drag/drop instances can be locked.  This will prevent      * onmousedown start drag.      * @property locked      * @type boolean      * @private      */     locked: false,     /**      * Lock this instance      * @method lock      */     lock: function() { this.locked = true; },     /**      * When set to true, other DD objects in cooperating DDGroups do not receive      * notification events when this DD object is dragged over them. Defaults to false.      * @property moveOnly      * @type boolean      */     moveOnly: false,     /**      * Unlock this instace      * @method unlock      */     unlock: function() { this.locked = false; },     /**      * By default, all instances can be a drop target.  This can be disabled by      * setting isTarget to false.      * @property isTarget      * @type boolean      */     isTarget: true,     /**      * The padding configured for this drag and drop object for calculating      * the drop zone intersection with this object.      * @property padding      * @type int[] An array containing the 4 padding values: [top, right, bottom, left]      */     padding: null,     /**      * Cached reference to the linked element      * @property _domRef      * @private      */     _domRef: null,     /**      * Internal typeof flag      * @property __ygDragDrop      * @private      */     __ygDragDrop: true,     /**      * Set to true when horizontal contraints are applied      * @property constrainX      * @type boolean      * @private      */     constrainX: false,     /**      * Set to true when vertical contraints are applied      * @property constrainY      * @type boolean      * @private      */     constrainY: false,     /**      * The left constraint      * @property minX      * @type int      * @private      */     minX: 0,     /**      * The right constraint      * @property maxX      * @type int      * @private      */     maxX: 0,     /**      * The up constraint      * @property minY      * @type int      * @type int      * @private      */     minY: 0,     /**      * The down constraint      * @property maxY      * @type int      * @private      */     maxY: 0,     /**      * Maintain offsets when we resetconstraints.  Set to true when you want      * the position of the element relative to its parent to stay the same      * when the page changes      *      * @property maintainOffset      * @type boolean      */     maintainOffset: false,     /**      * Array of pixel locations the element will snap to if we specified a      * horizontal graduation/interval.  This array is generated automatically      * when you define a tick interval.      * @property xTicks      * @type int[]      */     xTicks: null,     /**      * Array of pixel locations the element will snap to if we specified a      * vertical graduation/interval.  This array is generated automatically      * when you define a tick interval.      * @property yTicks      * @type int[]      */     yTicks: null,     /**      * By default the drag and drop instance will only respond to the primary      * button click (left button for a right-handed mouse).  Set to true to      * allow drag and drop to start with any mouse click that is propogated      * by the browser      * @property primaryButtonOnly      * @type boolean      */     primaryButtonOnly: true,     /**      * The availabe property is false until the linked dom element is accessible.      * @property available      * @type boolean      */     available: false,     /**      * By default, drags can only be initiated if the mousedown occurs in the      * region the linked element is.  This is done in part to work around a      * bug in some browsers that mis-report the mousedown if the previous      * mouseup happened outside of the window.  This property is set to true      * if outer handles are defined.      *      * @property hasOuterHandles      * @type boolean      * @default false      */     hasOuterHandles: false,     /**      * Code that executes immediately before the startDrag event      * @method b4StartDrag      * @private      */     b4StartDrag: function(x, y) { },     /**      * Abstract method called after a drag/drop object is clicked      * and the drag or mousedown time thresholds have beeen met.      * @method startDrag      * @param {int} X click location      * @param {int} Y click location      */     startDrag: function(x, y) { /* override this */ },     /**      * Code that executes immediately before the onDrag event      * @method b4Drag      * @private      */     b4Drag: function(e) { },     /**      * Abstract method called during the onMouseMove event while dragging an      * object.      * @method onDrag      * @param {Event} e the mousemove event      */     onDrag: function(e) { /* override this */ },     /**      * Abstract method called when this element fist begins hovering over      * another DragDrop obj      * @method onDragEnter      * @param {Event} e the mousemove event      * @param {String|DragDrop[]} id In POINT mode, the element      * id this is hovering over.  In INTERSECT mode, an array of one or more      * dragdrop items being hovered over.      */     onDragEnter: function(e, id) { /* override this */ },     /**      * Code that executes immediately before the onDragOver event      * @method b4DragOver      * @private      */     b4DragOver: function(e) { },     /**      * Abstract method called when this element is hovering over another      * DragDrop obj      * @method onDragOver      * @param {Event} e the mousemove event      * @param {String|DragDrop[]} id In POINT mode, the element      * id this is hovering over.  In INTERSECT mode, an array of dd items      * being hovered over.      */     onDragOver: function(e, id) { /* override this */ },     /**      * Code that executes immediately before the onDragOut event      * @method b4DragOut      * @private      */     b4DragOut: function(e) { },     /**      * Abstract method called when we are no longer hovering over an element      * @method onDragOut      * @param {Event} e the mousemove event      * @param {String|DragDrop[]} id In POINT mode, the element      * id this was hovering over.  In INTERSECT mode, an array of dd items      * that the mouse is no longer over.      */     onDragOut: function(e, id) { /* override this */ },     /**      * Code that executes immediately before the onDragDrop event      * @method b4DragDrop      * @private      */     b4DragDrop: function(e) { },     /**      * Abstract method called when this item is dropped on another DragDrop      * obj      * @method onDragDrop      * @param {Event} e the mouseup event      * @param {String|DragDrop[]} id In POINT mode, the element      * id this was dropped on.  In INTERSECT mode, an array of dd items this      * was dropped on.      */     onDragDrop: function(e, id) { /* override this */ },     /**      * Abstract method called when this item is dropped on an area with no      * drop target      * @method onInvalidDrop      * @param {Event} e the mouseup event      */     onInvalidDrop: function(e) { /* override this */ },     /**      * Code that executes immediately before the endDrag event      * @method b4EndDrag      * @private      */     b4EndDrag: function(e) { },     /**      * Fired when we are done dragging the object      * @method endDrag      * @param {Event} e the mouseup event      */     endDrag: function(e) { /* override this */ },     /**      * Code executed immediately before the onMouseDown event      * @method b4MouseDown      * @param {Event} e the mousedown event      * @private      */     b4MouseDown: function(e) {  },     /**      * Event handler that fires when a drag/drop obj gets a mousedown      * @method onMouseDown      * @param {Event} e the mousedown event      */     onMouseDown: function(e) { /* override this */ },     /**      * Event handler that fires when a drag/drop obj gets a mouseup      * @method onMouseUp      * @param {Event} e the mouseup event      */     onMouseUp: function(e) { /* override this */ },     /**      * Override the onAvailable method to do what is needed after the initial      * position was determined.      * @method onAvailable      */     onAvailable: function () {     },     /**      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).      * @type Object      */     defaultPadding : {left:0, right:0, top:0, bottom:0},     /**      * Initializes the drag drop object's constraints to restrict movement to a certain element.  *  * Usage:  <pre><code>  var dd = new Ext.dd.DDProxy("dragDiv1", "proxytest",                 { dragElId: "existingProxyDiv" });  dd.startDrag = function(){      this.constrainTo("parent-id");  };  </code></pre>  * Or you can initalize it using the {@link Ext.Element} object:  <pre><code>  Ext.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {      startDrag : function(){          this.constrainTo("parent-id");      }  });  </code></pre>      * @param {Mixed} constrainTo The element to constrain to.      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or      * an object containing the sides to pad. For example: {right:10, bottom:10}      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)      */     constrainTo : function(constrainTo, pad, inContent){         if(typeof pad == "number"){             pad = {left: pad, right:pad, top:pad, bottom:pad};         }         pad = pad || this.defaultPadding;         var b = Ext.get(this.getEl()).getBox();         var ce = Ext.get(constrainTo);         var s = ce.getScroll();         var c, cd = ce.dom;         if(cd == document.body){             c = { x: s.left, y: s.top, width: Ext.lib.Dom.getViewWidth(), height: Ext.lib.Dom.getViewHeight()};         }else{             var xy = ce.getXY();             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};         }         var topSpace = b.y - c.y;         var leftSpace = b.x - c.x;         this.resetConstraints();         this.setXConstraint(leftSpace - (pad.left||0), // left                 c.width - leftSpace - b.width - (pad.right||0), //right this.xTickSize         );         this.setYConstraint(topSpace - (pad.top||0), //top                 c.height - topSpace - b.height - (pad.bottom||0), //bottom this.yTickSize         );     },     /**      * Returns a reference to the linked element      * @method getEl      * @return {HTMLElement} the html element      */     getEl: function() {         if (!this._domRef) {             this._domRef = Ext.getDom(this.id);         }         return this._domRef;     },     /**      * Returns a reference to the actual element to drag.  By default this is      * the same as the html element, but it can be assigned to another      * element. An example of this can be found in Ext.dd.DDProxy      * @method getDragEl      * @return {HTMLElement} the html element      */     getDragEl: function() {         return Ext.getDom(this.dragElId);     },     /**      * Sets up the DragDrop object.  Must be called in the constructor of any      * Ext.dd.DragDrop subclass      * @method init      * @param id the id of the linked element      * @param {String} sGroup the group of related items      * @param {object} config configuration attributes      */     init: function(id, sGroup, config) {         this.initTarget(id, sGroup, config);         Event.on(this.id, "mousedown", this.handleMouseDown, this);         // Event.on(this.id, "selectstart", Event.preventDefault);     },     /**      * Initializes Targeting functionality only... the object does not      * get a mousedown handler.      * @method initTarget      * @param id the id of the linked element      * @param {String} sGroup the group of related items      * @param {object} config configuration attributes      */     initTarget: function(id, sGroup, config) {         // configuration attributes         this.config = config || {};         // create a local reference to the drag and drop manager         this.DDM = Ext.dd.DDM;         // initialize the groups array         this.groups = {};         // assume that we have an element reference instead of an id if the         // parameter is not a string         if (typeof id !== "string") {             id = Ext.id(id);         }         // set the id         this.id = id;         // add to an interaction group         this.addToGroup((sGroup) ? sGroup : "default");         // We don't want to register this as the handle with the manager         // so we just set the id rather than calling the setter.         this.handleElId = id;         // the linked element is the element that gets dragged by default         this.setDragElId(id);         // by default, clicked anchors will not start drag operations.         this.invalidHandleTypes = { A: "A" };         this.invalidHandleIds = {};         this.invalidHandleClasses = [];         this.applyConfig();         this.handleOnAvailable();     },     /**      * Applies the configuration parameters that were passed into the constructor.      * This is supposed to happen at each level through the inheritance chain.  So      * a DDProxy implentation will execute apply config on DDProxy, DD, and      * DragDrop in order to get all of the parameters that are available in      * each object.      * @method applyConfig      */     applyConfig: function() {         // configurable properties:         //    padding, isTarget, maintainOffset, primaryButtonOnly         this.padding           = this.config.padding || [0, 0, 0, 0];         this.isTarget          = (this.config.isTarget !== false);         this.maintainOffset    = (this.config.maintainOffset);         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);     },     /**      * Executed when the linked element is available      * @method handleOnAvailable      * @private      */     handleOnAvailable: function() {         this.available = true;         this.resetConstraints();         this.onAvailable();     },      /**      * Configures the padding for the target zone in px.  Effectively expands      * (or reduces) the virtual object size for targeting calculations.      * Supports css-style shorthand; if only one parameter is passed, all sides      * will have that padding, and if only two are passed, the top and bottom      * will have the first param, the left and right the second.      * @method setPadding      * @param {int} iTop    Top pad      * @param {int} iRight  Right pad      * @param {int} iBot    Bot pad      * @param {int} iLeft   Left pad      */     setPadding: function(iTop, iRight, iBot, iLeft) {         // this.padding = [iLeft, iRight, iTop, iBot];         if (!iRight && 0 !== iRight) {             this.padding = [iTop, iTop, iTop, iTop];         } else if (!iBot && 0 !== iBot) {             this.padding = [iTop, iRight, iTop, iRight];         } else {             this.padding = [iTop, iRight, iBot, iLeft];         }     },     /**      * Stores the initial placement of the linked element.      * @method setInitPosition      * @param {int} diffX   the X offset, default 0      * @param {int} diffY   the Y offset, default 0      */     setInitPosition: function(diffX, diffY) {         var el = this.getEl();         if (!this.DDM.verifyEl(el)) {             return;         }         var dx = diffX || 0;         var dy = diffY || 0;         var p = Dom.getXY( el );         this.initPageX = p[0] - dx;         this.initPageY = p[1] - dy;         this.lastPageX = p[0];         this.lastPageY = p[1];         this.setStartPosition(p);     },     /**      * Sets the start position of the element.  This is set when the obj      * is initialized, the reset when a drag is started.      * @method setStartPosition      * @param pos current position (from previous lookup)      * @private      */     setStartPosition: function(pos) {         var p = pos || Dom.getXY( this.getEl() );         this.deltaSetXY = null;         this.startPageX = p[0];         this.startPageY = p[1];     },     /**      * Add this instance to a group of related drag/drop objects.  All      * instances belong to at least one group, and can belong to as many      * groups as needed.      * @method addToGroup      * @param sGroup {string} the name of the group      */     addToGroup: function(sGroup) {         this.groups[sGroup] = true;         this.DDM.regDragDrop(this, sGroup);     },     /**      * Remove's this instance from the supplied interaction group      * @method removeFromGroup      * @param {string}  sGroup  The group to drop      */     removeFromGroup: function(sGroup) {         if (this.groups[sGroup]) {             delete this.groups[sGroup];         }         this.DDM.removeDDFromGroup(this, sGroup);     },     /**      * Allows you to specify that an element other than the linked element      * will be moved with the cursor during a drag      * @method setDragElId      * @param id {string} the id of the element that will be used to initiate the drag      */     setDragElId: function(id) {         this.dragElId = id;     },     /**      * Allows you to specify a child of the linked element that should be      * used to initiate the drag operation.  An example of this would be if      * you have a content div with text and links.  Clicking anywhere in the      * content area would normally start the drag operation.  Use this method      * to specify that an element inside of the content div is the element      * that starts the drag operation.      * @method setHandleElId      * @param id {string} the id of the element that will be used to      * initiate the drag.      */     setHandleElId: function(id) {         if (typeof id !== "string") {             id = Ext.id(id);         }         this.handleElId = id;         this.DDM.regHandle(this.id, id);     },     /**      * Allows you to set an element outside of the linked element as a drag      * handle      * @method setOuterHandleElId      * @param id the id of the element that will be used to initiate the drag      */     setOuterHandleElId: function(id) {         if (typeof id !== "string") {             id = Ext.id(id);         }         Event.on(id, "mousedown",                 this.handleMouseDown, this);         this.setHandleElId(id);         this.hasOuterHandles = true;     },     /**      * Remove all drag and drop hooks for this element      * @method unreg      */     unreg: function() {         Event.un(this.id, "mousedown",                 this.handleMouseDown);         this._domRef = null;         this.DDM._remove(this);     },     destroy : function(){         this.unreg();     },     /**      * Returns true if this instance is locked, or the drag drop mgr is locked      * (meaning that all drag/drop is disabled on the page.)      * @method isLocked      * @return {boolean} true if this obj or all drag/drop is locked, else      * false      */     isLocked: function() {         return (this.DDM.isLocked() || this.locked);     },     /**      * Fired when this object is clicked      * @method handleMouseDown      * @param {Event} e      * @param {Ext.dd.DragDrop} oDD the clicked dd object (this dd obj)      * @private      */     handleMouseDown: function(e, oDD){         if (this.primaryButtonOnly && e.button != 0) {             return;         }         if (this.isLocked()) {             return;         }         this.DDM.refreshCache(this.groups);         var pt = new Ext.lib.Point(Ext.lib.Event.getPageX(e), Ext.lib.Event.getPageY(e));         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {         } else {             if (this.clickValidator(e)) {                 // set the initial element position                 this.setStartPosition();                 this.b4MouseDown(e);                 this.onMouseDown(e);                 this.DDM.handleMouseDown(e, this);                 this.DDM.stopEvent(e);             } else {             }         }     },     clickValidator: function(e) {         var target = e.getTarget();         return ( this.isValidHandleChild(target) &&                     (this.id == this.handleElId ||                         this.DDM.handleWasClicked(target, this.id)) );     },     /**      * Allows you to specify a tag name that should not start a drag operation      * when clicked.  This is designed to facilitate embedding links within a      * drag handle that do something other than start the drag.      * @method addInvalidHandleType      * @param {string} tagName the type of element to exclude      */     addInvalidHandleType: function(tagName) {         var type = tagName.toUpperCase();         this.invalidHandleTypes[type] = type;     },     /**      * Lets you to specify an element id for a child of a drag handle      * that should not initiate a drag      * @method addInvalidHandleId      * @param {string} id the element id of the element you wish to ignore      */     addInvalidHandleId: function(id) {         if (typeof id !== "string") {             id = Ext.id(id);         }         this.invalidHandleIds[id] = id;     },     /**      * Lets you specify a css class of elements that will not initiate a drag      * @method addInvalidHandleClass      * @param {string} cssClass the class of the elements you wish to ignore      */     addInvalidHandleClass: function(cssClass) {         this.invalidHandleClasses.push(cssClass);     },     /**      * Unsets an excluded tag name set by addInvalidHandleType      * @method removeInvalidHandleType      * @param {string} tagName the type of element to unexclude      */     removeInvalidHandleType: function(tagName) {         var type = tagName.toUpperCase();         // this.invalidHandleTypes[type] = null;         delete this.invalidHandleTypes[type];     },     /**      * Unsets an invalid handle id      * @method removeInvalidHandleId      * @param {string} id the id of the element to re-enable      */     removeInvalidHandleId: function(id) {         if (typeof id !== "string") {             id = Ext.id(id);         }         delete this.invalidHandleIds[id];     },     /**      * Unsets an invalid css class      * @method removeInvalidHandleClass      * @param {string} cssClass the class of the element(s) you wish to      * re-enable      */     removeInvalidHandleClass: function(cssClass) {         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {             if (this.invalidHandleClasses[i] == cssClass) {                 delete this.invalidHandleClasses[i];             }         }     },     /**      * Checks the tag exclusion list to see if this click should be ignored      * @method isValidHandleChild      * @param {HTMLElement} node the HTMLElement to evaluate      * @return {boolean} true if this is a valid tag type, false if not      */     isValidHandleChild: function(node) {         var valid = true;         // var n = (node.nodeName == "#text") ? node.parentNode : node;         var nodeName;         try {             nodeName = node.nodeName.toUpperCase();         } catch(e) {             nodeName = node.nodeName;         }         valid = valid && !this.invalidHandleTypes[nodeName];         valid = valid && !this.invalidHandleIds[node.id];         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {             valid = !Ext.fly(node).hasClass(this.invalidHandleClasses[i]);         }         return valid;     },     /**      * Create the array of horizontal tick marks if an interval was specified      * in setXConstraint().      * @method setXTicks      * @private      */     setXTicks: function(iStartX, iTickSize) {         this.xTicks = [];         this.xTickSize = iTickSize;         var tickMap = {};         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {             if (!tickMap[i]) {                 this.xTicks[this.xTicks.length] = i;                 tickMap[i] = true;             }         }         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {             if (!tickMap[i]) {                 this.xTicks[this.xTicks.length] = i;                 tickMap[i] = true;             }         }         this.xTicks.sort(this.DDM.numericSort) ;     },     /**      * Create the array of vertical tick marks if an interval was specified in      * setYConstraint().      * @method setYTicks      * @private      */     setYTicks: function(iStartY, iTickSize) {         this.yTicks = [];         this.yTickSize = iTickSize;         var tickMap = {};         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {             if (!tickMap[i]) {                 this.yTicks[this.yTicks.length] = i;                 tickMap[i] = true;             }         }         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {             if (!tickMap[i]) {                 this.yTicks[this.yTicks.length] = i;                 tickMap[i] = true;             }         }         this.yTicks.sort(this.DDM.numericSort) ;     },     /**      * By default, the element can be dragged any place on the screen.  Use      * this method to limit the horizontal travel of the element.  Pass in      * 0,0 for the parameters if you want to lock the drag to the y axis.      * @method setXConstraint      * @param {int} iLeft the number of pixels the element can move to the left      * @param {int} iRight the number of pixels the element can move to the      * right      * @param {int} iTickSize optional parameter for specifying that the      * element      * should move iTickSize pixels at a time.      */     setXConstraint: function(iLeft, iRight, iTickSize) {         this.leftConstraint = iLeft;         this.rightConstraint = iRight;         this.minX = this.initPageX - iLeft;         this.maxX = this.initPageX + iRight;         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }         this.constrainX = true;     },     /**      * Clears any constraints applied to this instance.  Also clears ticks      * since they can't exist independent of a constraint at this time.      * @method clearConstraints      */     clearConstraints: function() {         this.constrainX = false;         this.constrainY = false;         this.clearTicks();     },     /**      * Clears any tick interval defined for this instance      * @method clearTicks      */     clearTicks: function() {         this.xTicks = null;         this.yTicks = null;         this.xTickSize = 0;         this.yTickSize = 0;     },     /**      * By default, the element can be dragged any place on the screen.  Set      * this to limit the vertical travel of the element.  Pass in 0,0 for the      * parameters if you want to lock the drag to the x axis.      * @method setYConstraint      * @param {int} iUp the number of pixels the element can move up      * @param {int} iDown the number of pixels the element can move down      * @param {int} iTickSize optional parameter for specifying that the      * element should move iTickSize pixels at a time.      */     setYConstraint: function(iUp, iDown, iTickSize) {         this.topConstraint = iUp;         this.bottomConstraint = iDown;         this.minY = this.initPageY - iUp;         this.maxY = this.initPageY + iDown;         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }         this.constrainY = true;     },     /**      * resetConstraints must be called if you manually reposition a dd element.      * @method resetConstraints      * @param {boolean} maintainOffset      */     resetConstraints: function() {         // Maintain offsets if necessary         if (this.initPageX || this.initPageX === 0) {             // figure out how much this thing has moved             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;             this.setInitPosition(dx, dy);         // This is the first time we have detected the element's position         } else {             this.setInitPosition();         }         if (this.constrainX) {             this.setXConstraint( this.leftConstraint,                                  this.rightConstraint,                                  this.xTickSize        );         }         if (this.constrainY) {             this.setYConstraint( this.topConstraint,                                  this.bottomConstraint,                                  this.yTickSize         );         }     },     /**      * Normally the drag element is moved pixel by pixel, but we can specify      * that it move a number of pixels at a time.  This method resolves the      * location when we have it set up like this.      * @method getTick      * @param {int} val where we want to place the object      * @param {int[]} tickArray sorted array of valid points      * @return {int} the closest tick      * @private      */     getTick: function(val, tickArray) {         if (!tickArray) {             // If tick interval is not defined, it is effectively 1 pixel,             // so we return the value passed to us.             return val;         } else if (tickArray[0] >= val) {             // The value is lower than the first tick, so we return the first             // tick.             return tickArray[0];         } else {             for (var i=0, len=tickArray.length; i<len; ++i) {                 var next = i + 1;                 if (tickArray[next] && tickArray[next] >= val) {                     var diff1 = val - tickArray[i];                     var diff2 = tickArray[next] - val;                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];                 }             }             // The value is larger than the last tick, so we return the last             // tick.             return tickArray[tickArray.length - 1];         }     },     /**      * toString method      * @method toString      * @return {string} string representation of the dd obj      */     toString: function() {         return ("DragDrop " + this.id);     } }; })(); /**  * The drag and drop utility provides a framework for building drag and drop  * applications.  In addition to enabling drag and drop for specific elements,  * the drag and drop elements are tracked by the manager class, and the  * interactions between the various elements are tracked during the drag and  * the implementing code is notified about these important moments.  */ // Only load the library once.  Rewriting the manager class would orphan // existing drag and drop instances. if (!Ext.dd.DragDropMgr) { /**  * @class Ext.dd.DragDropMgr  * DragDropMgr is a singleton that tracks the element interaction for  * all DragDrop items in the window.  Generally, you will not call  * this class directly, but it does have helper methods that could  * be useful in your DragDrop implementations.  * @singleton  */ Ext.dd.DragDropMgr = function() {     var Event = Ext.EventManager;     return {         /**          * Two dimensional Array of registered DragDrop objects.  The first          * dimension is the DragDrop item group, the second the DragDrop          * object.          * @property ids          * @type {string: string}          * @private          * @static          */         ids: {},         /**          * Array of element ids defined as drag handles.  Used to determine          * if the element that generated the mousedown event is actually the          * handle and not the html element itself.          * @property handleIds          * @type {string: string}          * @private          * @static          */         handleIds: {},         /**          * the DragDrop object that is currently being dragged          * @property dragCurrent          * @type DragDrop          * @private          * @static          **/         dragCurrent: null,         /**          * the DragDrop object(s) that are being hovered over          * @property dragOvers          * @type Array          * @private          * @static          */         dragOvers: {},         /**          * the X distance between the cursor and the object being dragged          * @property deltaX          * @type int          * @private          * @static          */         deltaX: 0,         /**          * the Y distance between the cursor and the object being dragged          * @property deltaY          * @type int          * @private          * @static          */         deltaY: 0,         /**          * Flag to determine if we should prevent the default behavior of the          * events we define. By default this is true, but this can be set to          * false if you need the default behavior (not recommended)          * @property preventDefault          * @type boolean          * @static          */         preventDefault: true,         /**          * Flag to determine if we should stop the propagation of the events          * we generate. This is true by default but you may want to set it to          * false if the html element contains other features that require the          * mouse click.          * @property stopPropagation          * @type boolean          * @static          */         stopPropagation: true,         /**          * Internal flag that is set to true when drag and drop has been          * intialized          * @property initialized          * @private          * @static          */         initialized: false,         /**          * All drag and drop can be disabled.          * @property locked          * @private          * @static          */         locked: false,         /**          * Called the first time an element is registered.          * @method init          * @private          * @static          */         init: function() {             this.initialized = true;         },         /**          * In point mode, drag and drop interaction is defined by the          * location of the cursor during the drag/drop          * @property POINT          * @type int          * @static          */         POINT: 0,         /**          * In intersect mode, drag and drop interaction is defined by the          * overlap of two or more drag and drop objects.          * @property INTERSECT          * @type int          * @static          */         INTERSECT: 1,         /**          * The current drag and drop mode.  Default: POINT          * @property mode          * @type int          * @static          */         mode: 0,         /**          * Runs method on all drag and drop objects          * @method _execOnAll          * @private          * @static          */         _execOnAll: function(sMethod, args) {             for (var i in this.ids) {                 for (var j in this.ids[i]) {                     var oDD = this.ids[i][j];                     if (! this.isTypeOfDD(oDD)) {                         continue;                     }                     oDD[sMethod].apply(oDD, args);                 }             }         },         /**          * Drag and drop initialization.  Sets up the global event handlers          * @method _onLoad          * @private          * @static          */         _onLoad: function() {             this.init();             Event.on(document, "mouseup",   this.handleMouseUp, this, true);             Event.on(document, "mousemove", this.handleMouseMove, this, true);             Event.on(window,   "unload",    this._onUnload, this, true);             Event.on(window,   "resize",    this._onResize, this, true);             // Event.on(window,   "mouseout",    this._test);         },         /**          * Reset constraints on all drag and drop objs          * @method _onResize          * @private          * @static          */         _onResize: function(e) {             this._execOnAll("resetConstraints", []);         },         /**          * Lock all drag and drop functionality          * @method lock          * @static          */         lock: function() { this.locked = true; },         /**          * Unlock all drag and drop functionality          * @method unlock          * @static          */         unlock: function() { this.locked = false; },         /**          * Is drag and drop locked?          * @method isLocked          * @return {boolean} True if drag and drop is locked, false otherwise.          * @static          */         isLocked: function() { return this.locked; },         /**          * Location cache that is set for all drag drop objects when a drag is          * initiated, cleared when the drag is finished.          * @property locationCache          * @private          * @static          */         locationCache: {},         /**          * Set useCache to false if you want to force object the lookup of each          * drag and drop linked element constantly during a drag.          * @property useCache          * @type boolean          * @static          */         useCache: true,         /**          * The number of pixels that the mouse needs to move after the          * mousedown before the drag is initiated.  Default=3;          * @property clickPixelThresh          * @type int          * @static          */         clickPixelThresh: 3,         /**          * The number of milliseconds after the mousedown event to initiate the          * drag if we don't get a mouseup event. Default=1000          * @property clickTimeThresh          * @type int          * @static          */         clickTimeThresh: 350,         /**          * Flag that indicates that either the drag pixel threshold or the          * mousdown time threshold has been met          * @property dragThreshMet          * @type boolean          * @private          * @static          */         dragThreshMet: false,         /**          * Timeout used for the click time threshold          * @property clickTimeout          * @type Object          * @private          * @static          */         clickTimeout: null,         /**          * The X position of the mousedown event stored for later use when a          * drag threshold is met.          * @property startX          * @type int          * @private          * @static          */         startX: 0,         /**          * The Y position of the mousedown event stored for later use when a          * drag threshold is met.          * @property startY          * @type int          * @private          * @static          */         startY: 0,         /**          * Each DragDrop instance must be registered with the DragDropMgr.          * This is executed in DragDrop.init()          * @method regDragDrop          * @param {DragDrop} oDD the DragDrop object to register          * @param {String} sGroup the name of the group this element belongs to          * @static          */         regDragDrop: function(oDD, sGroup) {             if (!this.initialized) { this.init(); }             if (!this.ids[sGroup]) {                 this.ids[sGroup] = {};             }             this.ids[sGroup][oDD.id] = oDD;         },         /**          * Removes the supplied dd instance from the supplied group. Executed          * by DragDrop.removeFromGroup, so don't call this function directly.          * @method removeDDFromGroup          * @private          * @static          */         removeDDFromGroup: function(oDD, sGroup) {             if (!this.ids[sGroup]) {                 this.ids[sGroup] = {};             }             var obj = this.ids[sGroup];             if (obj && obj[oDD.id]) {                 delete obj[oDD.id];             }         },         /**          * Unregisters a drag and drop item.  This is executed in          * DragDrop.unreg, use that method instead of calling this directly.          * @method _remove          * @private          * @static          */         _remove: function(oDD) {             for (var g in oDD.groups) {                 if (g && this.ids[g] && this.ids[g][oDD.id]) {                     delete this.ids[g][oDD.id];                 }             }             delete this.handleIds[oDD.id];         },         /**          * Each DragDrop handle element must be registered.  This is done          * automatically when executing DragDrop.setHandleElId()          * @method regHandle          * @param {String} sDDId the DragDrop id this element is a handle for          * @param {String} sHandleId the id of the element that is the drag          * handle          * @static          */         regHandle: function(sDDId, sHandleId) {             if (!this.handleIds[sDDId]) {                 this.handleIds[sDDId] = {};             }             this.handleIds[sDDId][sHandleId] = sHandleId;         },         /**          * Utility function to determine if a given element has been          * registered as a drag drop item.          * @method isDragDrop          * @param {String} id the element id to check          * @return {boolean} true if this element is a DragDrop item,          * false otherwise          * @static          */         isDragDrop: function(id) {             return ( this.getDDById(id) ) ? true : false;         },         /**          * Returns the drag and drop instances that are in all groups the          * passed in instance belongs to.          * @method getRelated          * @param {DragDrop} p_oDD the obj to get related data for          * @param {boolean} bTargetsOnly if true, only return targetable objs          * @return {DragDrop[]} the related instances          * @static          */         getRelated: function(p_oDD, bTargetsOnly) {             var oDDs = [];             for (var i in p_oDD.groups) {                 for (var j in this.ids[i]) {                     var dd = this.ids[i][j];                     if (! this.isTypeOfDD(dd)) {                         continue;                     }                     if (!bTargetsOnly || dd.isTarget) {                         oDDs[oDDs.length] = dd;                     }                 }             }             return oDDs;         },         /**          * Returns true if the specified dd target is a legal target for          * the specifice drag obj          * @method isLegalTarget          * @param {DragDrop} the drag obj          * @param {DragDrop} the target          * @return {boolean} true if the target is a legal target for the          * dd obj          * @static          */         isLegalTarget: function (oDD, oTargetDD) {             var targets = this.getRelated(oDD, true);             for (var i=0, len=targets.length;i<len;++i) {                 if (targets[i].id == oTargetDD.id) {                     return true;                 }             }             return false;         },         /**          * My goal is to be able to transparently determine if an object is          * typeof DragDrop, and the exact subclass of DragDrop.  typeof          * returns "object", oDD.constructor.toString() always returns          * "DragDrop" and not the name of the subclass.  So for now it just          * evaluates a well-known variable in DragDrop.          * @method isTypeOfDD          * @param {Object} the object to evaluate          * @return {boolean} true if typeof oDD = DragDrop          * @static          */         isTypeOfDD: function (oDD) {             return (oDD && oDD.__ygDragDrop);         },         /**          * Utility function to determine if a given element has been          * registered as a drag drop handle for the given Drag Drop object.          * @method isHandle          * @param {String} id the element id to check          * @return {boolean} true if this element is a DragDrop handle, false          * otherwise          * @static          */         isHandle: function(sDDId, sHandleId) {             return ( this.handleIds[sDDId] &&                             this.handleIds[sDDId][sHandleId] );         },         /**          * Returns the DragDrop instance for a given id          * @method getDDById          * @param {String} id the id of the DragDrop object          * @return {DragDrop} the drag drop object, null if it is not found          * @static          */         getDDById: function(id) {             for (var i in this.ids) {                 if (this.ids[i][id]) {                     return this.ids[i][id];                 }             }             return null;         },         /**          * Fired after a registered DragDrop object gets the mousedown event.          * Sets up the events required to track the object being dragged          * @method handleMouseDown          * @param {Event} e the event          * @param oDD the DragDrop object being dragged          * @private          * @static          */         handleMouseDown: function(e, oDD) {             if(Ext.QuickTips){                 Ext.QuickTips.disable();             }             if(this.dragCurrent){                 // the original browser mouseup wasn't handled (e.g. outside FF browser window)                 // so clean up first to avoid breaking the next drag                 this.handleMouseUp(e);             }                          this.currentTarget = e.getTarget();             this.dragCurrent = oDD;             var el = oDD.getEl();             // track start position             this.startX = e.getPageX();             this.startY = e.getPageY();             this.deltaX = this.startX - el.offsetLeft;             this.deltaY = this.startY - el.offsetTop;             this.dragThreshMet = false;             this.clickTimeout = setTimeout(                     function() {                         var DDM = Ext.dd.DDM;                         DDM.startDrag(DDM.startX, DDM.startY);                     },                     this.clickTimeThresh );         },         /**          * Fired when either the drag pixel threshol or the mousedown hold          * time threshold has been met.          * @method startDrag          * @param x {int} the X position of the original mousedown          * @param y {int} the Y position of the original mousedown          * @static          */         startDrag: function(x, y) {             clearTimeout(this.clickTimeout);             if (this.dragCurrent) {                 this.dragCurrent.b4StartDrag(x, y);                 this.dragCurrent.startDrag(x, y);             }             this.dragThreshMet = true;         },         /**          * Internal function to handle the mouseup event.  Will be invoked          * from the context of the document.          * @method handleMouseUp          * @param {Event} e the event          * @private          * @static          */         handleMouseUp: function(e) {             if(Ext.QuickTips){                 Ext.QuickTips.enable();             }             if (! this.dragCurrent) {                 return;             }             clearTimeout(this.clickTimeout);             if (this.dragThreshMet) {                 this.fireEvents(e, true);             } else {             }             this.stopDrag(e);             this.stopEvent(e);         },         /**          * Utility to stop event propagation and event default, if these          * features are turned on.          * @method stopEvent          * @param {Event} e the event as returned by this.getEvent()          * @static          */         stopEvent: function(e){             if(this.stopPropagation) {                 e.stopPropagation();             }             if (this.preventDefault) {                 e.preventDefault();             }         },         /**          * Internal function to clean up event handlers after the drag          * operation is complete          * @method stopDrag          * @param {Event} e the event          * @private          * @static          */         stopDrag: function(e) {             // Fire the drag end event for the item that was dragged             if (this.dragCurrent) {                 if (this.dragThreshMet) {                     this.dragCurrent.b4EndDrag(e);                     this.dragCurrent.endDrag(e);                 }                 this.dragCurrent.onMouseUp(e);             }             this.dragCurrent = null;             this.dragOvers = {};         },         /**          * Internal function to handle the mousemove event.  Will be invoked          * from the context of the html element.          *          * @TODO figure out what we can do about mouse events lost when the          * user drags objects beyond the window boundary.  Currently we can          * detect this in internet explorer by verifying that the mouse is          * down during the mousemove event.  Firefox doesn't give us the          * button state on the mousemove event.          * @method handleMouseMove          * @param {Event} e the event          * @private          * @static          */         handleMouseMove: function(e) {             if (! this.dragCurrent) {                 return true;             }             // var button = e.which || e.button;             // check for IE mouseup outside of page boundary             if (Ext.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {                 this.stopEvent(e);                 return this.handleMouseUp(e);             }             if (!this.dragThreshMet) {                 var diffX = Math.abs(this.startX - e.getPageX());                 var diffY = Math.abs(this.startY - e.getPageY());                 if (diffX > this.clickPixelThresh ||                             diffY > this.clickPixelThresh) {                     this.startDrag(this.startX, this.startY);                 }             }             if (this.dragThreshMet) {                 this.dragCurrent.b4Drag(e);                 this.dragCurrent.onDrag(e);                 if(!this.dragCurrent.moveOnly){                     this.fireEvents(e, false);                 }             }             this.stopEvent(e);             return true;         },         /**          * Iterates over all of the DragDrop elements to find ones we are          * hovering over or dropping on          * @method fireEvents          * @param {Event} e the event          * @param {boolean} isDrop is this a drop op or a mouseover op?          * @private          * @static          */         fireEvents: function(e, isDrop) {             var dc = this.dragCurrent;             // If the user did the mouse up outside of the window, we could             // get here even though we have ended the drag.             if (!dc || dc.isLocked()) {                 return;             }             var pt = e.getPoint();             // cache the previous dragOver array             var oldOvers = [];             var outEvts   = [];             var overEvts  = [];             var dropEvts  = [];             var enterEvts = [];             // Check to see if the object(s) we were hovering over is no longer             // being hovered over so we can fire the onDragOut event             for (var i in this.dragOvers) {                 var ddo = this.dragOvers[i];                 if (! this.isTypeOfDD(ddo)) {                     continue;                 }                 if (! this.isOverTarget(pt, ddo, this.mode)) {                     outEvts.push( ddo );                 }                 oldOvers[i] = true;                 delete this.dragOvers[i];             }             for (var sGroup in dc.groups) {                 if ("string" != typeof sGroup) {                     continue;                 }                 for (i in this.ids[sGroup]) {                     var oDD = this.ids[sGroup][i];                     if (! this.isTypeOfDD(oDD)) {                         continue;                     }                     if (oDD.isTarget && !oDD.isLocked() && ((oDD != dc) || (dc.ignoreSelf === false))) {                         if (this.isOverTarget(pt, oDD, this.mode)) {                             // look for drop interactions                             if (isDrop) {                                 dropEvts.push( oDD );                             // look for drag enter and drag over interactions                             } else {                                 // initial drag over: dragEnter fires                                 if (!oldOvers[oDD.id]) {                                     enterEvts.push( oDD );                                 // subsequent drag overs: dragOver fires                                 } else {                                     overEvts.push( oDD );                                 }                                 this.dragOvers[oDD.id] = oDD;                             }                         }                     }                 }             }             if (this.mode) {                 if (outEvts.length) {                     dc.b4DragOut(e, outEvts);                     dc.onDragOut(e, outEvts);                 }                 if (enterEvts.length) {                     dc.onDragEnter(e, enterEvts);                 }                 if (overEvts.length) {                     dc.b4DragOver(e, overEvts);                     dc.onDragOver(e, overEvts);                 }                 if (dropEvts.length) {                     dc.b4DragDrop(e, dropEvts);                     dc.onDragDrop(e, dropEvts);                 }             } else {                 // fire dragout events                 var len = 0;                 for (i=0, len=outEvts.length; i<len; ++i) {                     dc.b4DragOut(e, outEvts[i].id);                     dc.onDragOut(e, outEvts[i].id);                 }                 // fire enter events                 for (i=0,len=enterEvts.length; i<len; ++i) {                     // dc.b4DragEnter(e, oDD.id);                     dc.onDragEnter(e, enterEvts[i].id);                 }                 // fire over events                 for (i=0,len=overEvts.length; i<len; ++i) {                     dc.b4DragOver(e, overEvts[i].id);                     dc.onDragOver(e, overEvts[i].id);                 }                 // fire drop events                 for (i=0, len=dropEvts.length; i<len; ++i) {                     dc.b4DragDrop(e, dropEvts[i].id);                     dc.onDragDrop(e, dropEvts[i].id);                 }             }             // notify about a drop that did not find a target             if (isDrop && !dropEvts.length) {                 dc.onInvalidDrop(e);             }         },         /**          * Helper function for getting the best match from the list of drag          * and drop objects returned by the drag and drop events when we are          * in INTERSECT mode.  It returns either the first object that the          * cursor is over, or the object that has the greatest overlap with          * the dragged element.          * @method getBestMatch          * @param  {DragDrop[]} dds The array of drag and drop objects          * targeted          * @return {DragDrop}       The best single match          * @static          */         getBestMatch: function(dds) {             var winner = null;             // Return null if the input is not what we expect             //if (!dds || !dds.length || dds.length == 0) {                // winner = null;             // If there is only one item, it wins             //} else if (dds.length == 1) {             var len = dds.length;             if (len == 1) {                 winner = dds[0];             } else {                 // Loop through the targeted items                 for (var i=0; i<len; ++i) {                     var dd = dds[i];                     // If the cursor is over the object, it wins.  If the                     // cursor is over multiple matches, the first one we come                     // to wins.                     if (dd.cursorIsOver) {                         winner = dd;                         break;                     // Otherwise the object with the most overlap wins                     } else {                         if (!winner ||                             winner.overlap.getArea() < dd.overlap.getArea()) {                             winner = dd;                         }                     }                 }             }             return winner;         },         /**          * Refreshes the cache of the top-left and bottom-right points of the          * drag and drop objects in the specified group(s).  This is in the          * format that is stored in the drag and drop instance, so typical          * usage is:          * <code>          * Ext.dd.DragDropMgr.refreshCache(ddinstance.groups);          * </code>          * Alternatively:          * <code>          * Ext.dd.DragDropMgr.refreshCache({group1:true, group2:true});          * </code>          * @TODO this really should be an indexed array.  Alternatively this          * method could accept both.          * @method refreshCache          * @param {Object} groups an associative array of groups to refresh          * @static          */         refreshCache: function(groups) {             for (var sGroup in groups) {                 if ("string" != typeof sGroup) {                     continue;                 }                 for (var i in this.ids[sGroup]) {                     var oDD = this.ids[sGroup][i];                     if (this.isTypeOfDD(oDD)) {                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {                         var loc = this.getLocation(oDD);                         if (loc) {                             this.locationCache[oDD.id] = loc;                         } else {                             delete this.locationCache[oDD.id];                             // this will unregister the drag and drop object if                             // the element is not in a usable state                             // oDD.unreg();                         }                     }                 }             }         },         /**          * This checks to make sure an element exists and is in the DOM.  The          * main purpose is to handle cases where innerHTML is used to remove          * drag and drop objects from the DOM.  IE provides an 'unspecified          * error' when trying to access the offsetParent of such an element          * @method verifyEl          * @param {HTMLElement} el the element to check          * @return {boolean} true if the element looks usable          * @static          */         verifyEl: function(el) {             if (el) {                 var parent;                 if(Ext.isIE){                     try{                         parent = el.offsetParent;                     }catch(e){}                 }else{                     parent = el.offsetParent;                 }                 if (parent) {                     return true;                 }             }             return false;         },         /**          * Returns a Region object containing the drag and drop element's position          * and size, including the padding configured for it          * @method getLocation          * @param {DragDrop} oDD the drag and drop object to get the          *                       location for          * @return {Ext.lib.Region} a Region object representing the total area          *                             the element occupies, including any padding          *                             the instance is configured for.          * @static          */         getLocation: function(oDD) {             if (! this.isTypeOfDD(oDD)) {                 return null;             }             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;             try {                 pos= Ext.lib.Dom.getXY(el);             } catch (e) { }             if (!pos) {                 return null;             }             x1 = pos[0];             x2 = x1 + el.offsetWidth;             y1 = pos[1];             y2 = y1 + el.offsetHeight;             t = y1 - oDD.padding[0];             r = x2 + oDD.padding[1];             b = y2 + oDD.padding[2];             l = x1 - oDD.padding[3];             return new Ext.lib.Region( t, r, b, l );         },         /**          * Checks the cursor location to see if it over the target          * @method isOverTarget          * @param {Ext.lib.Point} pt The point to evaluate          * @param {DragDrop} oTarget the DragDrop object we are inspecting          * @return {boolean} true if the mouse is over the target          * @private          * @static          */         isOverTarget: function(pt, oTarget, intersect) {             // use cache if available             var loc = this.locationCache[oTarget.id];             if (!loc || !this.useCache) {                 loc = this.getLocation(oTarget);                 this.locationCache[oTarget.id] = loc;             }             if (!loc) {                 return false;             }             oTarget.cursorIsOver = loc.contains( pt );             // DragDrop is using this as a sanity check for the initial mousedown             // in this case we are done.  In POINT mode, if the drag obj has no             // contraints, we are also done. Otherwise we need to evaluate the             // location of the target as related to the actual location of the             // dragged element.             var dc = this.dragCurrent;             if (!dc || !dc.getTargetCoord ||                     (!intersect && !dc.constrainX && !dc.constrainY)) {                 return oTarget.cursorIsOver;             }             oTarget.overlap = null;             // Get the current location of the drag element, this is the             // location of the mouse event less the delta that represents             // where the original mousedown happened on the element.  We             // need to consider constraints and ticks as well.             var pos = dc.getTargetCoord(pt.x, pt.y);             var el = dc.getDragEl();             var curRegion = new Ext.lib.Region( pos.y,                                                    pos.x + el.offsetWidth,                                                    pos.y + el.offsetHeight,                                                    pos.x );             var overlap = curRegion.intersect(loc);             if (overlap) {                 oTarget.overlap = overlap;                 return (intersect) ? true : oTarget.cursorIsOver;             } else {                 return false;             }         },         /**          * unload event handler          * @method _onUnload          * @private          * @static          */         _onUnload: function(e, me) {             Ext.dd.DragDropMgr.unregAll();         },         /**          * Cleans up the drag and drop events and objects.          * @method unregAll          * @private          * @static          */         unregAll: function() {             if (this.dragCurrent) {                 this.stopDrag();                 this.dragCurrent = null;             }             this._execOnAll("unreg", []);             for (var i in this.elementCache) {                 delete this.elementCache[i];             }             this.elementCache = {};             this.ids = {};         },         /**          * A cache of DOM elements          * @property elementCache          * @private          * @static          */         elementCache: {},         /**          * Get the wrapper for the DOM element specified          * @method getElWrapper          * @param {String} id the id of the element to get          * @return {Ext.dd.DDM.ElementWrapper} the wrapped element          * @private          * @deprecated This wrapper isn't that useful          * @static          */         getElWrapper: function(id) {             var oWrapper = this.elementCache[id];             if (!oWrapper || !oWrapper.el) {                 oWrapper = this.elementCache[id] =                     new this.ElementWrapper(Ext.getDom(id));             }             return oWrapper;         },         /**          * Returns the actual DOM element          * @method getElement          * @param {String} id the id of the elment to get          * @return {Object} The element          * @deprecated use Ext.lib.Ext.getDom instead          * @static          */         getElement: function(id) {             return Ext.getDom(id);         },         /**          * Returns the style property for the DOM element (i.e.,          * document.getElById(id).style)          * @method getCss          * @param {String} id the id of the elment to get          * @return {Object} The style property of the element          * @deprecated use Ext.lib.Dom instead          * @static          */         getCss: function(id) {             var el = Ext.getDom(id);             return (el) ? el.style : null;         },         /**          * Inner class for cached elements          * @class DragDropMgr.ElementWrapper          * @for DragDropMgr          * @private          * @deprecated          */         ElementWrapper: function(el) {                 /**                  * The element                  * @property el                  */                 this.el = el || null;                 /**                  * The element id                  * @property id                  */                 this.id = this.el && el.id;                 /**                  * A reference to the style property                  * @property css                  */                 this.css = this.el && el.style;             },         /**          * Returns the X position of an html element          * @method getPosX          * @param el the element for which to get the position          * @return {int} the X coordinate          * @for DragDropMgr          * @deprecated use Ext.lib.Dom.getX instead          * @static          */         getPosX: function(el) {             return Ext.lib.Dom.getX(el);         },         /**          * Returns the Y position of an html element          * @method getPosY          * @param el the element for which to get the position          * @return {int} the Y coordinate          * @deprecated use Ext.lib.Dom.getY instead          * @static          */         getPosY: function(el) {             return Ext.lib.Dom.getY(el);         },         /**          * Swap two nodes.  In IE, we use the native method, for others we          * emulate the IE behavior          * @method swapNode          * @param n1 the first node to swap          * @param n2 the other node to swap          * @static          */         swapNode: function(n1, n2) {             if (n1.swapNode) {                 n1.swapNode(n2);             } else {                 var p = n2.parentNode;                 var s = n2.nextSibling;                 if (s == n1) {                     p.insertBefore(n1, n2);                 } else if (n2 == n1.nextSibling) {                     p.insertBefore(n2, n1);                 } else {                     n1.parentNode.replaceChild(n2, n1);                     p.insertBefore(n1, s);                 }             }         },         /**          * Returns the current scroll position          * @method getScroll          * @private          * @static          */         getScroll: function () {             var t, l, dde=document.documentElement, db=document.body;             if (dde && (dde.scrollTop || dde.scrollLeft)) {                 t = dde.scrollTop;                 l = dde.scrollLeft;             } else if (db) {                 t = db.scrollTop;                 l = db.scrollLeft;             } else {             }             return { top: t, left: l };         },         /**          * Returns the specified element style property          * @method getStyle          * @param {HTMLElement} el          the element          * @param {string}      styleProp   the style property          * @return {string} The value of the style property          * @deprecated use Ext.lib.Dom.getStyle          * @static          */         getStyle: function(el, styleProp) {             return Ext.fly(el).getStyle(styleProp);         },         /**          * Gets the scrollTop          * @method getScrollTop          * @return {int} the document's scrollTop          * @static          */         getScrollTop: function () { return this.getScroll().top; },         /**          * Gets the scrollLeft          * @method getScrollLeft          * @return {int} the document's scrollTop          * @static          */         getScrollLeft: function () { return this.getScroll().left; },         /**          * Sets the x/y position of an element to the location of the          * target element.          * @method moveToEl          * @param {HTMLElement} moveEl      The element to move          * @param {HTMLElement} targetEl    The position reference element          * @static          */         moveToEl: function (moveEl, targetEl) {             var aCoord = Ext.lib.Dom.getXY(targetEl);             Ext.lib.Dom.setXY(moveEl, aCoord);         },         /**          * Numeric array sort function          * @method numericSort          * @static          */         numericSort: function(a, b) { return (a - b); },         /**          * Internal counter          * @property _timeoutCount          * @private          * @static          */         _timeoutCount: 0,         /**          * Trying to make the load order less important.  Without this we get          * an error if this file is loaded before the Event Utility.          * @method _addListeners          * @private          * @static          */         _addListeners: function() {             var DDM = Ext.dd.DDM;             if ( Ext.lib.Event && document ) {                 DDM._onLoad();             } else {                 if (DDM._timeoutCount > 2000) {                 } else {                     setTimeout(DDM._addListeners, 10);                     if (document && document.body) {                         DDM._timeoutCount += 1;                     }                 }             }         },         /**          * Recursively searches the immediate parent and all child nodes for          * the handle element in order to determine wheter or not it was          * clicked.          * @method handleWasClicked          * @param node the html element to inspect          * @static          */         handleWasClicked: function(node, id) {             if (this.isHandle(id, node.id)) {                 return true;             } else {                 // check to see if this is a text node child of the one we want                 var p = node.parentNode;                 while (p) {                     if (this.isHandle(id, p.id)) {                         return true;                     } else {                         p = p.parentNode;                     }                 }             }             return false;         }     }; }(); // shorter alias, save a few bytes Ext.dd.DDM = Ext.dd.DragDropMgr; Ext.dd.DDM._addListeners(); } /**  * @class Ext.dd.DD  * A DragDrop implementation where the linked element follows the  * mouse cursor during a drag.  * @extends Ext.dd.DragDrop  * @constructor  * @param {String} id the id of the linked element  * @param {String} sGroup the group of related DragDrop items  * @param {object} config an object containing configurable attributes  *                Valid properties for DD:  *                    scroll  */ Ext.dd.DD = function(id, sGroup, config) {     if (id) {         this.init(id, sGroup, config);     } }; Ext.extend(Ext.dd.DD, Ext.dd.DragDrop, {     /**      * When set to true, the utility automatically tries to scroll the browser      * window when a drag and drop element is dragged near the viewport boundary.      * Defaults to true.      * @property scroll      * @type boolean      */     scroll: true,     /**      * Sets the pointer offset to the distance between the linked element's top      * left corner and the location the element was clicked      * @method autoOffset      * @param {int} iPageX the X coordinate of the click      * @param {int} iPageY the Y coordinate of the click      */     autoOffset: function(iPageX, iPageY) {         var x = iPageX - this.startPageX;         var y = iPageY - this.startPageY;         this.setDelta(x, y);     },     /**      * Sets the pointer offset.  You can call this directly to force the      * offset to be in a particular location (e.g., pass in 0,0 to set it      * to the center of the object)      * @method setDelta      * @param {int} iDeltaX the distance from the left      * @param {int} iDeltaY the distance from the top      */     setDelta: function(iDeltaX, iDeltaY) {         this.deltaX = iDeltaX;         this.deltaY = iDeltaY;     },     /**      * Sets the drag element to the location of the mousedown or click event,      * maintaining the cursor location relative to the location on the element      * that was clicked.  Override this if you want to place the element in a      * location other than where the cursor is.      * @method setDragElPos      * @param {int} iPageX the X coordinate of the mousedown or drag event      * @param {int} iPageY the Y coordinate of the mousedown or drag event      */     setDragElPos: function(iPageX, iPageY) {         // the first time we do this, we are going to check to make sure         // the element has css positioning         var el = this.getDragEl();         this.alignElWithMouse(el, iPageX, iPageY);     },     /**      * Sets the element to the location of the mousedown or click event,      * maintaining the cursor location relative to the location on the element      * that was clicked.  Override this if you want to place the element in a      * location other than where the cursor is.      * @method alignElWithMouse      * @param {HTMLElement} el the element to move      * @param {int} iPageX the X coordinate of the mousedown or drag event      * @param {int} iPageY the Y coordinate of the mousedown or drag event      */     alignElWithMouse: function(el, iPageX, iPageY) {         var oCoord = this.getTargetCoord(iPageX, iPageY);         var fly = el.dom ? el : Ext.fly(el, '_dd');         if (!this.deltaSetXY) {             var aCoord = [oCoord.x, oCoord.y];             fly.setXY(aCoord);             var newLeft = fly.getLeft(true);             var newTop  = fly.getTop(true);             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];         } else {             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);         }         this.cachePosition(oCoord.x, oCoord.y);         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);         return oCoord;     },     /**      * Saves the most recent position so that we can reset the constraints and      * tick marks on-demand.  We need to know this so that we can calculate the      * number of pixels the element is offset from its original position.      * @method cachePosition      * @param iPageX the current x position (optional, this just makes it so we      * don't have to look it up again)      * @param iPageY the current y position (optional, this just makes it so we      * don't have to look it up again)      */     cachePosition: function(iPageX, iPageY) {         if (iPageX) {             this.lastPageX = iPageX;             this.lastPageY = iPageY;         } else {             var aCoord = Ext.lib.Dom.getXY(this.getEl());             this.lastPageX = aCoord[0];             this.lastPageY = aCoord[1];         }     },     /**      * Auto-scroll the window if the dragged object has been moved beyond the      * visible window boundary.      * @method autoScroll      * @param {int} x the drag element's x position      * @param {int} y the drag element's y position      * @param {int} h the height of the drag element      * @param {int} w the width of the drag element      * @private      */     autoScroll: function(x, y, h, w) {         if (this.scroll) {             // The client height             var clientH = Ext.lib.Dom.getViewHeight();             // The client width             var clientW = Ext.lib.Dom.getViewWidth();             // The amt scrolled down             var st = this.DDM.getScrollTop();             // The amt scrolled right             var sl = this.DDM.getScrollLeft();             // Location of the bottom of the element             var bot = h + y;             // Location of the right of the element             var right = w + x;             // The distance from the cursor to the bottom of the visible area,             // adjusted so that we don't scroll if the cursor is beyond the             // element drag constraints             var toBot = (clientH + st - y - this.deltaY);             // The distance from the cursor to the right of the visible area             var toRight = (clientW + sl - x - this.deltaX);             // How close to the edge the cursor must be before we scroll             // var thresh = (document.all) ? 100 : 40;             var thresh = 40;             // How many pixels to scroll per autoscroll op.  This helps to reduce             // clunky scrolling. IE is more sensitive about this ... it needs this             // value to be higher.             var scrAmt = (document.all) ? 80 : 30;             // Scroll down if we are near the bottom of the visible page and the             // obj extends below the crease             if ( bot > clientH && toBot < thresh ) {                 window.scrollTo(sl, st + scrAmt);             }             // Scroll up if the window is scrolled down and the top of the object             // goes above the top border             if ( y < st && st > 0 && y - st < thresh ) {                 window.scrollTo(sl, st - scrAmt);             }             // Scroll right if the obj is beyond the right border and the cursor is             // near the border.             if ( right > clientW && toRight < thresh ) {                 window.scrollTo(sl + scrAmt, st);             }             // Scroll left if the window has been scrolled to the right and the obj             // extends past the left border             if ( x < sl && sl > 0 && x - sl < thresh ) {                 window.scrollTo(sl - scrAmt, st);             }         }     },     /**      * Finds the location the element should be placed if we want to move      * it to where the mouse location less the click offset would place us.      * @method getTargetCoord      * @param {int} iPageX the X coordinate of the click      * @param {int} iPageY the Y coordinate of the click      * @return an object that contains the coordinates (Object.x and Object.y)      * @private      */     getTargetCoord: function(iPageX, iPageY) {         var x = iPageX - this.deltaX;         var y = iPageY - this.deltaY;         if (this.constrainX) {             if (x < this.minX) { x = this.minX; }             if (x > this.maxX) { x = this.maxX; }         }         if (this.constrainY) {             if (y < this.minY) { y = this.minY; }             if (y > this.maxY) { y = this.maxY; }         }         x = this.getTick(x, this.xTicks);         y = this.getTick(y, this.yTicks);         return {x:x, y:y};     },     /**      * Sets up config options specific to this class. Overrides      * Ext.dd.DragDrop, but all versions of this method through the      * inheritance chain are called      */     applyConfig: function() {         Ext.dd.DD.superclass.applyConfig.call(this);         this.scroll = (this.config.scroll !== false);     },     /**      * Event that fires prior to the onMouseDown event.  Overrides      * Ext.dd.DragDrop.      */     b4MouseDown: function(e) {         // this.resetConstraints();         this.autoOffset(e.getPageX(),                             e.getPageY());     },     /**      * Event that fires prior to the onDrag event.  Overrides      * Ext.dd.DragDrop.      */     b4Drag: function(e) {         this.setDragElPos(e.getPageX(),                             e.getPageY());     },     toString: function() {         return ("DD " + this.id);     }     //////////////////////////////////////////////////////////////////////////     // Debugging ygDragDrop events that can be overridden     //////////////////////////////////////////////////////////////////////////     /*     startDrag: function(x, y) {     },     onDrag: function(e) {     },     onDragEnter: function(e, id) {     },     onDragOver: function(e, id) {     },     onDragOut: function(e, id) {     },     onDragDrop: function(e, id) {     },     endDrag: function(e) {     }     */ }); /**  * @class Ext.dd.DDProxy  * A DragDrop implementation that inserts an empty, bordered div into  * the document that follows the cursor during drag operations.  At the time of  * the click, the frame div is resized to the dimensions of the linked html  * element, and moved to the exact location of the linked element.  *  * References to the "frame" element refer to the single proxy element that  * was created to be dragged in place of all DDProxy elements on the  * page.  *  * @extends Ext.dd.DD  * @constructor  * @param {String} id the id of the linked html element  * @param {String} sGroup the group of related DragDrop objects  * @param {object} config an object containing configurable attributes  *                Valid properties for DDProxy in addition to those in DragDrop:  *                   resizeFrame, centerFrame, dragElId  */ Ext.dd.DDProxy = function(id, sGroup, config) {     if (id) {         this.init(id, sGroup, config);         this.initFrame();     } }; /**  * The default drag frame div id  * @property Ext.dd.DDProxy.dragElId  * @type String  * @static  */ Ext.dd.DDProxy.dragElId = "ygddfdiv"; Ext.extend(Ext.dd.DDProxy, Ext.dd.DD, {     /**      * By default we resize the drag frame to be the same size as the element      * we want to drag (this is to get the frame effect).  We can turn it off      * if we want a different behavior.      * @property resizeFrame      * @type boolean      */     resizeFrame: true,     /**      * By default the frame is positioned exactly where the drag element is, so      * we use the cursor offset provided by Ext.dd.DD.  Another option that works only if      * you do not have constraints on the obj is to have the drag frame centered      * around the cursor.  Set centerFrame to true for this effect.      * @property centerFrame      * @type boolean      */     centerFrame: false,     /**      * Creates the proxy element if it does not yet exist      * @method createFrame      */     createFrame: function() {         var self = this;         var body = document.body;         if (!body || !body.firstChild) {             setTimeout( function() { self.createFrame(); }, 50 );             return;         }         var div = this.getDragEl();         if (!div) {             div    = document.createElement("div");             div.id = this.dragElId;             var s  = div.style;             s.position   = "absolute";             s.visibility = "hidden";             s.cursor     = "move";             s.border     = "2px solid #aaa";             s.zIndex     = 999;             // appendChild can blow up IE if invoked prior to the window load event             // while rendering a table.  It is possible there are other scenarios             // that would cause this to happen as well.             body.insertBefore(div, body.firstChild);         }     },     /**      * Initialization for the drag frame element.  Must be called in the      * constructor of all subclasses      * @method initFrame      */     initFrame: function() {         this.createFrame();     },     applyConfig: function() {         Ext.dd.DDProxy.superclass.applyConfig.call(this);         this.resizeFrame = (this.config.resizeFrame !== false);         this.centerFrame = (this.config.centerFrame);         this.setDragElId(this.config.dragElId || Ext.dd.DDProxy.dragElId);     },     /**      * Resizes the drag frame to the dimensions of the clicked object, positions      * it over the object, and finally displays it      * @method showFrame      * @param {int} iPageX X click position      * @param {int} iPageY Y click position      * @private      */     showFrame: function(iPageX, iPageY) {         var el = this.getEl();         var dragEl = this.getDragEl();         var s = dragEl.style;         this._resizeProxy();         if (this.centerFrame) {             this.setDelta( Math.round(parseInt(s.width,  10)/2),                            Math.round(parseInt(s.height, 10)/2) );         }         this.setDragElPos(iPageX, iPageY);         Ext.fly(dragEl).show();     },     /**      * The proxy is automatically resized to the dimensions of the linked      * element when a drag is initiated, unless resizeFrame is set to false      * @method _resizeProxy      * @private      */     _resizeProxy: function() {         if (this.resizeFrame) {             var el = this.getEl();             Ext.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);         }     },     // overrides Ext.dd.DragDrop     b4MouseDown: function(e) {         var x = e.getPageX();         var y = e.getPageY();         this.autoOffset(x, y);         this.setDragElPos(x, y);     },     // overrides Ext.dd.DragDrop     b4StartDrag: function(x, y) {         // show the drag frame         this.showFrame(x, y);     },     // overrides Ext.dd.DragDrop     b4EndDrag: function(e) {         Ext.fly(this.getDragEl()).hide();     },     // overrides Ext.dd.DragDrop     // By default we try to move the element to the last location of the frame.     // This is so that the default behavior mirrors that of Ext.dd.DD.     endDrag: function(e) {         var lel = this.getEl();         var del = this.getDragEl();         // Show the drag frame briefly so we can get its position         del.style.visibility = "";         this.beforeMove();         // Hide the linked element before the move to get around a Safari         // rendering bug.         lel.style.visibility = "hidden";         Ext.dd.DDM.moveToEl(lel, del);         del.style.visibility = "hidden";         lel.style.visibility = "";         this.afterDrag();     },     beforeMove : function(){     },     afterDrag : function(){     },     toString: function() {         return ("DDProxy " + this.id);     } }); /**  * @class Ext.dd.DDTarget  * A DragDrop implementation that does not move, but can be a drop  * target.  You would get the same result by simply omitting implementation  * for the event callbacks, but this way we reduce the processing cost of the  * event listener and the callbacks.  * @extends Ext.dd.DragDrop  * @constructor  * @param {String} id the id of the element that is a drop target  * @param {String} sGroup the group of related DragDrop objects  * @param {object} config an object containing configurable attributes  *                 Valid properties for DDTarget in addition to those in  *                 DragDrop:  *                    none  */ Ext.dd.DDTarget = function(id, sGroup, config) {     if (id) {         this.initTarget(id, sGroup, config);     } }; // Ext.dd.DDTarget.prototype = new Ext.dd.DragDrop(); Ext.extend(Ext.dd.DDTarget, Ext.dd.DragDrop, {     toString: function() {         return ("DDTarget " + this.id);     } }); /**
  806.  * @class Ext.dd.DragTracker
  807.  * @extends Ext.util.Observable
  808.  */
  809. Ext.dd.DragTracker = function(config){
  810.     Ext.apply(this, config);
  811.     this.addEvents(
  812.         /**
  813.          * @event mousedown
  814.          * @param {Object} this
  815.          * @param {Object} e event object
  816.          */
  817.         'mousedown',
  818.         /**
  819.          * @event mouseup
  820.          * @param {Object} this
  821.          * @param {Object} e event object
  822.          */
  823.         'mouseup',
  824.         /**
  825.          * @event mousemove
  826.          * @param {Object} this
  827.          * @param {Object} e event object
  828.          */
  829.         'mousemove',
  830.         /**
  831.          * @event dragstart
  832.          * @param {Object} this
  833.          * @param {Object} startXY the page coordinates of the event
  834.          */
  835.         'dragstart',
  836.         /**
  837.          * @event dragend
  838.          * @param {Object} this
  839.          * @param {Object} e event object
  840.          */
  841.         'dragend',
  842.         /**
  843.          * @event drag
  844.          * @param {Object} this
  845.          * @param {Object} e event object
  846.          */
  847.         'drag'
  848.     );
  849.     this.dragRegion = new Ext.lib.Region(0,0,0,0);
  850.     if(this.el){
  851.         this.initEl(this.el);
  852.     }
  853. }
  854. Ext.extend(Ext.dd.DragTracker, Ext.util.Observable,  {
  855.     /**
  856.      * @cfg {Boolean} active
  857.  * Defaults to <tt>false</tt>.
  858.  */
  859.     active: false,
  860.     /**
  861.      * @cfg {Number} tolerance
  862.  * Defaults to <tt>5</tt>.
  863.  */
  864.     tolerance: 5,
  865.     /**
  866.      * @cfg {Boolean/Number} autoStart
  867.  * Defaults to <tt>false</tt>. Specify <tt>true</tt> to defer trigger start by 1000 ms.
  868.  * Specify a Number for the number of milliseconds to defer trigger start.
  869.  */
  870.     autoStart: false,
  871.     initEl: function(el){
  872.         this.el = Ext.get(el);
  873.         el.on('mousedown', this.onMouseDown, this,
  874.                 this.delegate ? {delegate: this.delegate} : undefined);
  875.     },
  876.     destroy : function(){
  877.         this.el.un('mousedown', this.onMouseDown, this);
  878.     },
  879.     onMouseDown: function(e, target){
  880.         if(this.fireEvent('mousedown', this, e) !== false && this.onBeforeStart(e) !== false){
  881.             this.startXY = this.lastXY = e.getXY();
  882.             this.dragTarget = this.delegate ? target : this.el.dom;
  883.             if(this.preventDefault !== false){
  884.                 e.preventDefault();
  885.             }
  886.             var doc = Ext.getDoc();
  887.             doc.on('mouseup', this.onMouseUp, this);
  888.             doc.on('mousemove', this.onMouseMove, this);
  889.             doc.on('selectstart', this.stopSelect, this);
  890.             if(this.autoStart){
  891.                 this.timer = this.triggerStart.defer(this.autoStart === true ? 1000 : this.autoStart, this);
  892.             }
  893.         }
  894.     },
  895.     onMouseMove: function(e, target){
  896.         // HACK: IE hack to see if button was released outside of window. */
  897.         if(this.active && Ext.isIE && !e.browserEvent.button){
  898.             e.preventDefault();
  899.             this.onMouseUp(e);
  900.             return;
  901.         }
  902.         e.preventDefault();
  903.         var xy = e.getXY(), s = this.startXY;
  904.         this.lastXY = xy;
  905.         if(!this.active){
  906.             if(Math.abs(s[0]-xy[0]) > this.tolerance || Math.abs(s[1]-xy[1]) > this.tolerance){
  907.                 this.triggerStart();
  908.             }else{
  909.                 return;
  910.             }
  911.         }
  912.         this.fireEvent('mousemove', this, e);
  913.         this.onDrag(e);
  914.         this.fireEvent('drag', this, e);
  915.     },
  916.     onMouseUp: function(e){
  917.         var doc = Ext.getDoc();
  918.         doc.un('mousemove', this.onMouseMove, this);
  919.         doc.un('mouseup', this.onMouseUp, this);
  920.         doc.un('selectstart', this.stopSelect, this);
  921.         e.preventDefault();
  922.         this.clearStart();
  923.         var wasActive = this.active;
  924.         this.active = false;
  925.         delete this.elRegion;
  926.         this.fireEvent('mouseup', this, e);
  927.         if(wasActive){
  928.             this.onEnd(e);
  929.             this.fireEvent('dragend', this, e);
  930.         }
  931.     },
  932.     triggerStart: function(isTimer){
  933.         this.clearStart();
  934.         this.active = true;
  935.         this.onStart(this.startXY);
  936.         this.fireEvent('dragstart', this, this.startXY);
  937.     },
  938.     clearStart : function(){
  939.         if(this.timer){
  940.             clearTimeout(this.timer);
  941.             delete this.timer;
  942.         }
  943.     },
  944.     stopSelect : function(e){
  945.         e.stopEvent();
  946.         return false;
  947.     },
  948.     onBeforeStart : function(e){
  949.     },
  950.     onStart : function(xy){
  951.     },
  952.     onDrag : function(e){
  953.     },
  954.     onEnd : function(e){
  955.     },
  956.     getDragTarget : function(){
  957.         return this.dragTarget;
  958.     },
  959.     getDragCt : function(){
  960.         return this.el;
  961.     },
  962.     getXY : function(constrain){
  963.         return constrain ?
  964.                this.constrainModes[constrain].call(this, this.lastXY) : this.lastXY;
  965.     },
  966.     getOffset : function(constrain){
  967.         var xy = this.getXY(constrain);
  968.         var s = this.startXY;
  969.         return [s[0]-xy[0], s[1]-xy[1]];
  970.     },
  971.     constrainModes: {
  972.         'point' : function(xy){
  973.             if(!this.elRegion){
  974.                 this.elRegion = this.getDragCt().getRegion();
  975.             }
  976.             var dr = this.dragRegion;
  977.             dr.left = xy[0];
  978.             dr.top = xy[1];
  979.             dr.right = xy[0];
  980.             dr.bottom = xy[1];
  981.             dr.constrainTo(this.elRegion);
  982.             return [dr.left, dr.top];
  983.         }
  984.     }
  985. });/**
  986.  * @class Ext.dd.ScrollManager
  987.  * <p>Provides automatic scrolling of overflow regions in the page during drag operations.</p>
  988.  * <p>The ScrollManager configs will be used as the defaults for any scroll container registered with it,
  989.  * but you can also override most of the configs per scroll container by adding a 
  990.  * <tt>ddScrollConfig</tt> object to the target element that contains these properties: {@link #hthresh},
  991.  * {@link #vthresh}, {@link #increment} and {@link #frequency}.  Example usage:
  992.  * <pre><code>
  993. var el = Ext.get('scroll-ct');
  994. el.ddScrollConfig = {
  995.     vthresh: 50,
  996.     hthresh: -1,
  997.     frequency: 100,
  998.     increment: 200
  999. };
  1000. Ext.dd.ScrollManager.register(el);
  1001. </code></pre>
  1002.  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
  1003.  * @singleton
  1004.  */
  1005. Ext.dd.ScrollManager = function(){
  1006.     var ddm = Ext.dd.DragDropMgr;
  1007.     var els = {};
  1008.     var dragEl = null;
  1009.     var proc = {};
  1010.     
  1011.     var onStop = function(e){
  1012.         dragEl = null;
  1013.         clearProc();
  1014.     };
  1015.     
  1016.     var triggerRefresh = function(){
  1017.         if(ddm.dragCurrent){
  1018.              ddm.refreshCache(ddm.dragCurrent.groups);
  1019.         }
  1020.     };
  1021.     
  1022.     var doScroll = function(){
  1023.         if(ddm.dragCurrent){
  1024.             var dds = Ext.dd.ScrollManager;
  1025.             var inc = proc.el.ddScrollConfig ?
  1026.                       proc.el.ddScrollConfig.increment : dds.increment;
  1027.             if(!dds.animate){
  1028.                 if(proc.el.scroll(proc.dir, inc)){
  1029.                     triggerRefresh();
  1030.                 }
  1031.             }else{
  1032.                 proc.el.scroll(proc.dir, inc, true, dds.animDuration, triggerRefresh);
  1033.             }
  1034.         }
  1035.     };
  1036.     
  1037.     var clearProc = function(){
  1038.         if(proc.id){
  1039.             clearInterval(proc.id);
  1040.         }
  1041.         proc.id = 0;
  1042.         proc.el = null;
  1043.         proc.dir = "";
  1044.     };
  1045.     
  1046.     var startProc = function(el, dir){
  1047.         clearProc();
  1048.         proc.el = el;
  1049.         proc.dir = dir;
  1050.         var freq = (el.ddScrollConfig && el.ddScrollConfig.frequency) ? 
  1051.                 el.ddScrollConfig.frequency : Ext.dd.ScrollManager.frequency;
  1052.         proc.id = setInterval(doScroll, freq);
  1053.     };
  1054.     
  1055.     var onFire = function(e, isDrop){
  1056.         if(isDrop || !ddm.dragCurrent){ return; }
  1057.         var dds = Ext.dd.ScrollManager;
  1058.         if(!dragEl || dragEl != ddm.dragCurrent){
  1059.             dragEl = ddm.dragCurrent;
  1060.             // refresh regions on drag start
  1061.             dds.refreshCache();
  1062.         }
  1063.         
  1064.         var xy = Ext.lib.Event.getXY(e);
  1065.         var pt = new Ext.lib.Point(xy[0], xy[1]);
  1066.         for(var id in els){
  1067.             var el = els[id], r = el._region;
  1068.             var c = el.ddScrollConfig ? el.ddScrollConfig : dds;
  1069.             if(r && r.contains(pt) && el.isScrollable()){
  1070.                 if(r.bottom - pt.y <= c.vthresh){
  1071.                     if(proc.el != el){
  1072.                         startProc(el, "down");
  1073.                     }
  1074.                     return;
  1075.                 }else if(r.right - pt.x <= c.hthresh){
  1076.                     if(proc.el != el){
  1077.                         startProc(el, "left");
  1078.                     }
  1079.                     return;
  1080.                 }else if(pt.y - r.top <= c.vthresh){
  1081.                     if(proc.el != el){
  1082.                         startProc(el, "up");
  1083.                     }
  1084.                     return;
  1085.                 }else if(pt.x - r.left <= c.hthresh){
  1086.                     if(proc.el != el){
  1087.                         startProc(el, "right");
  1088.                     }
  1089.                     return;
  1090.                 }
  1091.             }
  1092.         }
  1093.         clearProc();
  1094.     };
  1095.     
  1096.     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
  1097.     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
  1098.     
  1099.     return {
  1100.         /**
  1101.          * Registers new overflow element(s) to auto scroll
  1102.          * @param {Mixed/Array} el The id of or the element to be scrolled or an array of either
  1103.          */
  1104.         register : function(el){
  1105.             if(Ext.isArray(el)){
  1106.                 for(var i = 0, len = el.length; i < len; i++) {
  1107.                  this.register(el[i]);
  1108.                 }
  1109.             }else{
  1110.                 el = Ext.get(el);
  1111.                 els[el.id] = el;
  1112.             }
  1113.         },
  1114.         
  1115.         /**
  1116.          * Unregisters overflow element(s) so they are no longer scrolled
  1117.          * @param {Mixed/Array} el The id of or the element to be removed or an array of either
  1118.          */
  1119.         unregister : function(el){
  1120.             if(Ext.isArray(el)){
  1121.                 for(var i = 0, len = el.length; i < len; i++) {
  1122.                  this.unregister(el[i]);
  1123.                 }
  1124.             }else{
  1125.                 el = Ext.get(el);
  1126.                 delete els[el.id];
  1127.             }
  1128.         },
  1129.         
  1130.         /**
  1131.          * The number of pixels from the top or bottom edge of a container the pointer needs to be to
  1132.          * trigger scrolling (defaults to 25)
  1133.          * @type Number
  1134.          */
  1135.         vthresh : 25,
  1136.         /**
  1137.          * The number of pixels from the right or left edge of a container the pointer needs to be to
  1138.          * trigger scrolling (defaults to 25)
  1139.          * @type Number
  1140.          */
  1141.         hthresh : 25,
  1142.         /**
  1143.          * The number of pixels to scroll in each scroll increment (defaults to 50)
  1144.          * @type Number
  1145.          */
  1146.         increment : 100,
  1147.         
  1148.         /**
  1149.          * The frequency of scrolls in milliseconds (defaults to 500)
  1150.          * @type Number
  1151.          */
  1152.         frequency : 500,
  1153.         
  1154.         /**
  1155.          * True to animate the scroll (defaults to true)
  1156.          * @type Boolean
  1157.          */
  1158.         animate: true,
  1159.         
  1160.         /**
  1161.          * The animation duration in seconds - 
  1162.          * MUST BE less than Ext.dd.ScrollManager.frequency! (defaults to .4)
  1163.          * @type Number
  1164.          */
  1165.         animDuration: .4,
  1166.         
  1167.         /**
  1168.          * Manually trigger a cache refresh.
  1169.          */
  1170.         refreshCache : function(){
  1171.             for(var id in els){
  1172.                 if(typeof els[id] == 'object'){ // for people extending the object prototype
  1173.                     els[id]._region = els[id].getRegion();
  1174.                 }
  1175.             }
  1176.         }
  1177.     };
  1178. }();/**
  1179.  * @class Ext.dd.Registry
  1180.  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
  1181.  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
  1182.  * @singleton
  1183.  */
  1184. Ext.dd.Registry = function(){
  1185.     var elements = {}; 
  1186.     var handles = {}; 
  1187.     var autoIdSeed = 0;
  1188.     var getId = function(el, autogen){
  1189.         if(typeof el == "string"){
  1190.             return el;
  1191.         }
  1192.         var id = el.id;
  1193.         if(!id && autogen !== false){
  1194.             id = "extdd-" + (++autoIdSeed);
  1195.             el.id = id;
  1196.         }
  1197.         return id;
  1198.     };
  1199.     
  1200.     return {
  1201.     /**
  1202.      * Resgister a drag drop element
  1203.      * @param {String/HTMLElement) element The id or DOM node to register
  1204.      * @param {Object} data (optional) An custom data object that will be passed between the elements that are involved
  1205.      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
  1206.      * knows how to interpret, plus there are some specific properties known to the Registry that should be
  1207.      * populated in the data object (if applicable):
  1208.      * <pre>
  1209. Value      Description<br />
  1210. ---------  ------------------------------------------<br />
  1211. handles    Array of DOM nodes that trigger dragging<br />
  1212.            for the element being registered<br />
  1213. isHandle   True if the element passed in triggers<br />
  1214.            dragging itself, else false
  1215. </pre>
  1216.      */
  1217.         register : function(el, data){
  1218.             data = data || {};
  1219.             if(typeof el == "string"){
  1220.                 el = document.getElementById(el);
  1221.             }
  1222.             data.ddel = el;
  1223.             elements[getId(el)] = data;
  1224.             if(data.isHandle !== false){
  1225.                 handles[data.ddel.id] = data;
  1226.             }
  1227.             if(data.handles){
  1228.                 var hs = data.handles;
  1229.                 for(var i = 0, len = hs.length; i < len; i++){
  1230.                  handles[getId(hs[i])] = data;
  1231.                 }
  1232.             }
  1233.         },
  1234.     /**
  1235.      * Unregister a drag drop element
  1236.      * @param {String/HTMLElement) element The id or DOM node to unregister
  1237.      */
  1238.         unregister : function(el){
  1239.             var id = getId(el, false);
  1240.             var data = elements[id];
  1241.             if(data){
  1242.                 delete elements[id];
  1243.                 if(data.handles){
  1244.                     var hs = data.handles;
  1245.                     for(var i = 0, len = hs.length; i < len; i++){
  1246.                      delete handles[getId(hs[i], false)];
  1247.                     }
  1248.                 }
  1249.             }
  1250.         },
  1251.     /**
  1252.      * Returns the handle registered for a DOM Node by id
  1253.      * @param {String/HTMLElement} id The DOM node or id to look up
  1254.      * @return {Object} handle The custom handle data
  1255.      */
  1256.         getHandle : function(id){
  1257.             if(typeof id != "string"){ // must be element?
  1258.                 id = id.id;
  1259.             }
  1260.             return handles[id];
  1261.         },
  1262.     /**
  1263.      * Returns the handle that is registered for the DOM node that is the target of the event
  1264.      * @param {Event} e The event
  1265.      * @return {Object} handle The custom handle data
  1266.      */
  1267.         getHandleFromEvent : function(e){
  1268.             var t = Ext.lib.Event.getTarget(e);
  1269.             return t ? handles[t.id] : null;
  1270.         },
  1271.     /**
  1272.      * Returns a custom data object that is registered for a DOM node by id
  1273.      * @param {String/HTMLElement} id The DOM node or id to look up
  1274.      * @return {Object} data The custom data
  1275.      */
  1276.         getTarget : function(id){
  1277.             if(typeof id != "string"){ // must be element?
  1278.                 id = id.id;
  1279.             }
  1280.             return elements[id];
  1281.         },
  1282.     /**
  1283.      * Returns a custom data object that is registered for the DOM node that is the target of the event
  1284.      * @param {Event} e The event
  1285.      * @return {Object} data The custom data
  1286.      */
  1287.         getTargetFromEvent : function(e){
  1288.             var t = Ext.lib.Event.getTarget(e);
  1289.             return t ? elements[t.id] || handles[t.id] : null;
  1290.         }
  1291.     };
  1292. }();/**
  1293.  * @class Ext.dd.StatusProxy
  1294.  * A specialized drag proxy that supports a drop status icon, {@link Ext.Layer} styles and auto-repair.  This is the
  1295.  * default drag proxy used by all Ext.dd components.
  1296.  * @constructor
  1297.  * @param {Object} config
  1298.  */
  1299. Ext.dd.StatusProxy = function(config){
  1300.     Ext.apply(this, config);
  1301.     this.id = this.id || Ext.id();
  1302.     this.el = new Ext.Layer({
  1303.         dh: {
  1304.             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
  1305.                 {tag: "div", cls: "x-dd-drop-icon"},
  1306.                 {tag: "div", cls: "x-dd-drag-ghost"}
  1307.             ]
  1308.         }, 
  1309.         shadow: !config || config.shadow !== false
  1310.     });
  1311.     this.ghost = Ext.get(this.el.dom.childNodes[1]);
  1312.     this.dropStatus = this.dropNotAllowed;
  1313. };
  1314. Ext.dd.StatusProxy.prototype = {
  1315.     /**
  1316.      * @cfg {String} dropAllowed
  1317.      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
  1318.      */
  1319.     dropAllowed : "x-dd-drop-ok",
  1320.     /**
  1321.      * @cfg {String} dropNotAllowed
  1322.      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
  1323.      */
  1324.     dropNotAllowed : "x-dd-drop-nodrop",
  1325.     /**
  1326.      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
  1327.      * over the current target element.
  1328.      * @param {String} cssClass The css class for the new drop status indicator image
  1329.      */
  1330.     setStatus : function(cssClass){
  1331.         cssClass = cssClass || this.dropNotAllowed;
  1332.         if(this.dropStatus != cssClass){
  1333.             this.el.replaceClass(this.dropStatus, cssClass);
  1334.             this.dropStatus = cssClass;
  1335.         }
  1336.     },
  1337.     /**
  1338.      * Resets the status indicator to the default dropNotAllowed value
  1339.      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
  1340.      */
  1341.     reset : function(clearGhost){
  1342.         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
  1343.         this.dropStatus = this.dropNotAllowed;
  1344.         if(clearGhost){
  1345.             this.ghost.update("");
  1346.         }
  1347.     },
  1348.     /**
  1349.      * Updates the contents of the ghost element
  1350.      * @param {String/HTMLElement} html The html that will replace the current innerHTML of the ghost element, or a
  1351.      * DOM node to append as the child of the ghost element (in which case the innerHTML will be cleared first).
  1352.      */
  1353.     update : function(html){
  1354.         if(typeof html == "string"){
  1355.             this.ghost.update(html);
  1356.         }else{
  1357.             this.ghost.update("");
  1358.             html.style.margin = "0";
  1359.             this.ghost.dom.appendChild(html);
  1360.         }
  1361.         var el = this.ghost.dom.firstChild; 
  1362.         if(el){
  1363.             Ext.fly(el).setStyle('float', 'none');
  1364.         }
  1365.     },
  1366.     /**
  1367.      * Returns the underlying proxy {@link Ext.Layer}
  1368.      * @return {Ext.Layer} el
  1369.     */
  1370.     getEl : function(){
  1371.         return this.el;
  1372.     },
  1373.     /**
  1374.      * Returns the ghost element
  1375.      * @return {Ext.Element} el
  1376.      */
  1377.     getGhost : function(){
  1378.         return this.ghost;
  1379.     },
  1380.     /**
  1381.      * Hides the proxy
  1382.      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
  1383.      */
  1384.     hide : function(clear){
  1385.         this.el.hide();
  1386.         if(clear){
  1387.             this.reset(true);
  1388.         }
  1389.     },
  1390.     /**
  1391.      * Stops the repair animation if it's currently running
  1392.      */
  1393.     stop : function(){
  1394.         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
  1395.             this.anim.stop();
  1396.         }
  1397.     },
  1398.     /**
  1399.      * Displays this proxy
  1400.      */
  1401.     show : function(){
  1402.         this.el.show();
  1403.     },
  1404.     /**
  1405.      * Force the Layer to sync its shadow and shim positions to the element
  1406.      */
  1407.     sync : function(){
  1408.         this.el.sync();
  1409.     },
  1410.     /**
  1411.      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
  1412.      * invalid drop operation by the item being dragged.
  1413.      * @param {Array} xy The XY position of the element ([x, y])
  1414.      * @param {Function} callback The function to call after the repair is complete
  1415.      * @param {Object} scope The scope in which to execute the callback
  1416.      */
  1417.     repair : function(xy, callback, scope){
  1418.         this.callback = callback;
  1419.         this.scope = scope;
  1420.         if(xy && this.animRepair !== false){
  1421.             this.el.addClass("x-dd-drag-repair");
  1422.             this.el.hideUnders(true);
  1423.             this.anim = this.el.shift({
  1424.                 duration: this.repairDuration || .5,
  1425.                 easing: 'easeOut',
  1426.                 xy: xy,
  1427.                 stopFx: true,
  1428.                 callback: this.afterRepair,
  1429.                 scope: this
  1430.             });
  1431.         }else{
  1432.             this.afterRepair();
  1433.         }
  1434.     },
  1435.     // private
  1436.     afterRepair : function(){
  1437.         this.hide(true);
  1438.         if(typeof this.callback == "function"){
  1439.             this.callback.call(this.scope || this);
  1440.         }
  1441.         this.callback = null;
  1442.         this.scope = null;
  1443.     }
  1444. };/**
  1445.  * @class Ext.dd.DragSource
  1446.  * @extends Ext.dd.DDProxy
  1447.  * A simple class that provides the basic implementation needed to make any element draggable.
  1448.  * @constructor
  1449.  * @param {Mixed} el The container element
  1450.  * @param {Object} config
  1451.  */
  1452. Ext.dd.DragSource = function(el, config){
  1453.     this.el = Ext.get(el);
  1454.     if(!this.dragData){
  1455.         this.dragData = {};
  1456.     }
  1457.     
  1458.     Ext.apply(this, config);
  1459.     
  1460.     if(!this.proxy){
  1461.         this.proxy = new Ext.dd.StatusProxy();
  1462.     }
  1463.     Ext.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group, 
  1464.           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
  1465.     
  1466.     this.dragging = false;
  1467. };
  1468. Ext.extend(Ext.dd.DragSource, Ext.dd.DDProxy, {
  1469.     /**
  1470.      * @cfg {String} ddGroup
  1471.      * A named drag drop group to which this object belongs.  If a group is specified, then this object will only
  1472.      * interact with other drag drop objects in the same group (defaults to undefined).
  1473.      */
  1474.     /**
  1475.      * @cfg {String} dropAllowed
  1476.      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
  1477.      */
  1478.     dropAllowed : "x-dd-drop-ok",
  1479.     /**
  1480.      * @cfg {String} dropNotAllowed
  1481.      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
  1482.      */
  1483.     dropNotAllowed : "x-dd-drop-nodrop",
  1484.     /**
  1485.      * Returns the data object associated with this drag source
  1486.      * @return {Object} data An object containing arbitrary data
  1487.      */
  1488.     getDragData : function(e){
  1489.         return this.dragData;
  1490.     },
  1491.     // private
  1492.     onDragEnter : function(e, id){
  1493.         var target = Ext.dd.DragDropMgr.getDDById(id);
  1494.         this.cachedTarget = target;
  1495.         if(this.beforeDragEnter(target, e, id) !== false){
  1496.             if(target.isNotifyTarget){
  1497.                 var status = target.notifyEnter(this, e, this.dragData);
  1498.                 this.proxy.setStatus(status);
  1499.             }else{
  1500.                 this.proxy.setStatus(this.dropAllowed);
  1501.             }
  1502.             
  1503.             if(this.afterDragEnter){
  1504.                 /**
  1505.                  * An empty function by default, but provided so that you can perform a custom action
  1506.                  * when the dragged item enters the drop target by providing an implementation.
  1507.                  * @param {Ext.dd.DragDrop} target The drop target
  1508.                  * @param {Event} e The event object
  1509.                  * @param {String} id The id of the dragged element
  1510.                  * @method afterDragEnter
  1511.                  */
  1512.                 this.afterDragEnter(target, e, id);
  1513.             }
  1514.         }
  1515.     },
  1516.     /**
  1517.      * An empty function by default, but provided so that you can perform a custom action
  1518.      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
  1519.      * @param {Ext.dd.DragDrop} target The drop target
  1520.      * @param {Event} e The event object
  1521.      * @param {String} id The id of the dragged element
  1522.      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
  1523.      */
  1524.     beforeDragEnter : function(target, e, id){
  1525.         return true;
  1526.     },
  1527.     // private
  1528.     alignElWithMouse: function() {
  1529.         Ext.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
  1530.         this.proxy.sync();
  1531.     },