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

中间件编程

开发平台:

JavaScript

  1.     },
  2.     doForm : function(c, m, form, callback, scope){
  3.         var t = new Ext.Direct.Transaction({
  4.             provider: this,
  5.             action: c,
  6.             method: m.name,
  7.             args:[form, callback, scope],
  8.             cb: scope && Ext.isFunction(callback) ? callback.createDelegate(scope) : callback,
  9.             isForm: true
  10.         });
  11.         if(this.fireEvent('beforecall', this, t) !== false){
  12.             Ext.Direct.addTransaction(t);
  13.             var isUpload = String(form.getAttribute("enctype")).toLowerCase() == 'multipart/form-data',
  14.                 params = {
  15.                     extTID: t.tid,
  16.                     extAction: c,
  17.                     extMethod: m.name,
  18.                     extType: 'rpc',
  19.                     extUpload: String(isUpload)
  20.                 };
  21.             
  22.             // change made from typeof callback check to callback.params
  23.             // to support addl param passing in DirectSubmit EAC 6/2
  24.             Ext.apply(t, {
  25.                 form: Ext.getDom(form),
  26.                 isUpload: isUpload,
  27.                 params: callback && Ext.isObject(callback.params) ? Ext.apply(params, callback.params) : params
  28.             });
  29.             this.fireEvent('call', this, t);
  30.             this.processForm(t);
  31.         }
  32.     },
  33.     
  34.     processForm: function(t){
  35.         Ext.Ajax.request({
  36.             url: this.url,
  37.             params: t.params,
  38.             callback: this.onData,
  39.             scope: this,
  40.             form: t.form,
  41.             isUpload: t.isUpload,
  42.             ts: t
  43.         });
  44.     },
  45.     createMethod : function(c, m){
  46.         var f;
  47.         if(!m.formHandler){
  48.             f = function(){
  49.                 this.doCall(c, m, Array.prototype.slice.call(arguments, 0));
  50.             }.createDelegate(this);
  51.         }else{
  52.             f = function(form, callback, scope){
  53.                 this.doForm(c, m, form, callback, scope);
  54.             }.createDelegate(this);
  55.         }
  56.         f.directCfg = {
  57.             action: c,
  58.             method: m
  59.         };
  60.         return f;
  61.     },
  62.     getTransaction: function(opt){
  63.         return opt && opt.tid ? Ext.Direct.getTransaction(opt.tid) : null;
  64.     },
  65.     doCallback: function(t, e){
  66.         var fn = e.status ? 'success' : 'failure';
  67.         if(t && t.cb){
  68.             var hs = t.cb;
  69.             var result = e.result || e.data;
  70.             if(Ext.isFunction(hs)){
  71.                 hs(result, e);
  72.             } else{
  73.                 Ext.callback(hs[fn], hs.scope, [result, e]);
  74.                 Ext.callback(hs.callback, hs.scope, [result, e]);
  75.             }
  76.         }
  77.     }
  78. });
  79. Ext.Direct.PROVIDERS['remoting'] = Ext.direct.RemotingProvider;/**
  80.  * @class Ext.Resizable
  81.  * @extends Ext.util.Observable
  82.  * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element 
  83.  * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
  84.  * the textarea in a div and set 'resizeChild' to true (or to the id of the element), <b>or</b> set wrap:true in your config and
  85.  * the element will be wrapped for you automatically.</p>
  86.  * <p>Here is the list of valid resize handles:</p>
  87.  * <pre>
  88. Value   Description
  89. ------  -------------------
  90.  'n'     north
  91.  's'     south
  92.  'e'     east
  93.  'w'     west
  94.  'nw'    northwest
  95.  'sw'    southwest
  96.  'se'    southeast
  97.  'ne'    northeast
  98.  'all'   all
  99. </pre>
  100.  * <p>Here's an example showing the creation of a typical Resizable:</p>
  101.  * <pre><code>
  102. var resizer = new Ext.Resizable('element-id', {
  103.     handles: 'all',
  104.     minWidth: 200,
  105.     minHeight: 100,
  106.     maxWidth: 500,
  107.     maxHeight: 400,
  108.     pinned: true
  109. });
  110. resizer.on('resize', myHandler);
  111. </code></pre>
  112.  * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
  113.  * resizer.east.setDisplayed(false);</p>
  114.  * @constructor
  115.  * Create a new resizable component
  116.  * @param {Mixed} el The id or element to resize
  117.  * @param {Object} config configuration options
  118.   */
  119. Ext.Resizable = function(el, config){
  120.     this.el = Ext.get(el);
  121.     
  122.     if(config && config.wrap){
  123.         config.resizeChild = this.el;
  124.         this.el = this.el.wrap(typeof config.wrap == 'object' ? config.wrap : {cls:'xresizable-wrap'});
  125.         this.el.id = this.el.dom.id = config.resizeChild.id + '-rzwrap';
  126.         this.el.setStyle('overflow', 'hidden');
  127.         this.el.setPositioning(config.resizeChild.getPositioning());
  128.         config.resizeChild.clearPositioning();
  129.         if(!config.width || !config.height){
  130.             var csize = config.resizeChild.getSize();
  131.             this.el.setSize(csize.width, csize.height);
  132.         }
  133.         if(config.pinned && !config.adjustments){
  134.             config.adjustments = 'auto';
  135.         }
  136.     }
  137.     /**
  138.      * The proxy Element that is resized in place of the real Element during the resize operation.
  139.      * This may be queried using {@link Ext.Element#getBox} to provide the new area to resize to.
  140.      * Read only.
  141.      * @type Ext.Element.
  142.      * @property proxy
  143.      */
  144.     this.proxy = this.el.createProxy({tag: 'div', cls: 'x-resizable-proxy', id: this.el.id + '-rzproxy'}, Ext.getBody());
  145.     this.proxy.unselectable();
  146.     this.proxy.enableDisplayMode('block');
  147.     Ext.apply(this, config);
  148.     
  149.     if(this.pinned){
  150.         this.disableTrackOver = true;
  151.         this.el.addClass('x-resizable-pinned');
  152.     }
  153.     // if the element isn't positioned, make it relative
  154.     var position = this.el.getStyle('position');
  155.     if(position != 'absolute' && position != 'fixed'){
  156.         this.el.setStyle('position', 'relative');
  157.     }
  158.     if(!this.handles){ // no handles passed, must be legacy style
  159.         this.handles = 's,e,se';
  160.         if(this.multiDirectional){
  161.             this.handles += ',n,w';
  162.         }
  163.     }
  164.     if(this.handles == 'all'){
  165.         this.handles = 'n s e w ne nw se sw';
  166.     }
  167.     var hs = this.handles.split(/s*?[,;]s*?| /);
  168.     var ps = Ext.Resizable.positions;
  169.     for(var i = 0, len = hs.length; i < len; i++){
  170.         if(hs[i] && ps[hs[i]]){
  171.             var pos = ps[hs[i]];
  172.             this[pos] = new Ext.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
  173.         }
  174.     }
  175.     // legacy
  176.     this.corner = this.southeast;
  177.     
  178.     if(this.handles.indexOf('n') != -1 || this.handles.indexOf('w') != -1){
  179.         this.updateBox = true;
  180.     }   
  181.    
  182.     this.activeHandle = null;
  183.     
  184.     if(this.resizeChild){
  185.         if(typeof this.resizeChild == 'boolean'){
  186.             this.resizeChild = Ext.get(this.el.dom.firstChild, true);
  187.         }else{
  188.             this.resizeChild = Ext.get(this.resizeChild, true);
  189.         }
  190.     }
  191.     
  192.     if(this.adjustments == 'auto'){
  193.         var rc = this.resizeChild;
  194.         var hw = this.west, he = this.east, hn = this.north, hs = this.south;
  195.         if(rc && (hw || hn)){
  196.             rc.position('relative');
  197.             rc.setLeft(hw ? hw.el.getWidth() : 0);
  198.             rc.setTop(hn ? hn.el.getHeight() : 0);
  199.         }
  200.         this.adjustments = [
  201.             (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
  202.             (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1 
  203.         ];
  204.     }
  205.     
  206.     if(this.draggable){
  207.         this.dd = this.dynamic ? 
  208.             this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
  209.         this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
  210.     }
  211.     
  212.     this.addEvents(
  213.         /**
  214.          * @event beforeresize
  215.          * Fired before resize is allowed. Set {@link #enabled} to false to cancel resize.
  216.          * @param {Ext.Resizable} this
  217.          * @param {Ext.EventObject} e The mousedown event
  218.          */
  219.         'beforeresize',
  220.         /**
  221.          * @event resize
  222.          * Fired after a resize.
  223.          * @param {Ext.Resizable} this
  224.          * @param {Number} width The new width
  225.          * @param {Number} height The new height
  226.          * @param {Ext.EventObject} e The mouseup event
  227.          */
  228.         'resize'
  229.     );
  230.     
  231.     if(this.width !== null && this.height !== null){
  232.         this.resizeTo(this.width, this.height);
  233.     }else{
  234.         this.updateChildSize();
  235.     }
  236.     if(Ext.isIE){
  237.         this.el.dom.style.zoom = 1;
  238.     }
  239.     Ext.Resizable.superclass.constructor.call(this);
  240. };
  241. Ext.extend(Ext.Resizable, Ext.util.Observable, {
  242.     /**
  243.      * @cfg {Array/String} adjustments String 'auto' or an array [width, height] with values to be <b>added</b> to the
  244.      * resize operation's new size (defaults to <tt>[0, 0]</tt>)
  245.      */
  246.     adjustments : [0, 0],
  247.     /**
  248.      * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
  249.      */
  250.     animate : false,
  251.     /**
  252.      * @cfg {Mixed} constrainTo Constrain the resize to a particular element
  253.      */
  254.     /**
  255.      * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
  256.      */
  257.     disableTrackOver : false,
  258.     /**
  259.      * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
  260.      */
  261.     draggable: false,
  262.     /**
  263.      * @cfg {Number} duration Animation duration if animate = true (defaults to 0.35)
  264.      */
  265.     duration : 0.35,
  266.     /**
  267.      * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
  268.      */
  269.     dynamic : false,
  270.     /**
  271.      * @cfg {String} easing Animation easing if animate = true (defaults to <tt>'easingOutStrong'</tt>)
  272.      */
  273.     easing : 'easeOutStrong',
  274.     /**
  275.      * @cfg {Boolean} enabled False to disable resizing (defaults to true)
  276.      */
  277.     enabled : true,
  278.     /**
  279.      * @property enabled Writable. False if resizing is disabled.
  280.      * @type Boolean 
  281.      */
  282.     /**
  283.      * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined).
  284.      * Specify either <tt>'all'</tt> or any of <tt>'n s e w ne nw se sw'</tt>.
  285.      */
  286.     handles : false,
  287.     /**
  288.      * @cfg {Boolean} multiDirectional <b>Deprecated</b>.  Deprecated style of adding multi-direction resize handles.
  289.      */
  290.     multiDirectional : false,
  291.     /**
  292.      * @cfg {Number} height The height of the element in pixels (defaults to null)
  293.      */
  294.     height : null,
  295.     /**
  296.      * @cfg {Number} width The width of the element in pixels (defaults to null)
  297.      */
  298.     width : null,
  299.     /**
  300.      * @cfg {Number} heightIncrement The increment to snap the height resize in pixels
  301.      * (only applies if <code>{@link #dynamic}==true</code>). Defaults to <tt>0</tt>.
  302.      */
  303.     heightIncrement : 0,
  304.     /**
  305.      * @cfg {Number} widthIncrement The increment to snap the width resize in pixels
  306.      * (only applies if <code>{@link #dynamic}==true</code>). Defaults to <tt>0</tt>.
  307.      */
  308.     widthIncrement : 0,
  309.     /**
  310.      * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
  311.      */
  312.     minHeight : 5,
  313.     /**
  314.      * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
  315.      */
  316.     minWidth : 5,
  317.     /**
  318.      * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
  319.      */
  320.     maxHeight : 10000,
  321.     /**
  322.      * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
  323.      */
  324.     maxWidth : 10000,
  325.     /**
  326.      * @cfg {Number} minX The minimum x for the element (defaults to 0)
  327.      */
  328.     minX: 0,
  329.     /**
  330.      * @cfg {Number} minY The minimum x for the element (defaults to 0)
  331.      */
  332.     minY: 0,
  333.     /**
  334.      * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
  335.      * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
  336.      */
  337.     pinned : false,
  338.     /**
  339.      * @cfg {Boolean} preserveRatio True to preserve the original ratio between height
  340.      * and width during resize (defaults to false)
  341.      */
  342.     preserveRatio : false,
  343.     /**
  344.      * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false) 
  345.      */ 
  346.     resizeChild : false,
  347.     /**
  348.      * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
  349.      */
  350.     transparent: false,
  351.     /**
  352.      * @cfg {Ext.lib.Region} resizeRegion Constrain the resize to a particular region
  353.      */
  354.     /**
  355.      * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
  356.      * in favor of the handles config option (defaults to false)
  357.      */
  358.     
  359.     /**
  360.      * Perform a manual resize and fires the 'resize' event.
  361.      * @param {Number} width
  362.      * @param {Number} height
  363.      */
  364.     resizeTo : function(width, height){
  365.         this.el.setSize(width, height);
  366.         this.updateChildSize();
  367.         this.fireEvent('resize', this, width, height, null);
  368.     },
  369.     // private
  370.     startSizing : function(e, handle){
  371.         this.fireEvent('beforeresize', this, e);
  372.         if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
  373.             if(!this.overlay){
  374.                 this.overlay = this.el.createProxy({tag: 'div', cls: 'x-resizable-overlay', html: '&#160;'}, Ext.getBody());
  375.                 this.overlay.unselectable();
  376.                 this.overlay.enableDisplayMode('block');
  377.                 this.overlay.on({
  378.                     scope: this,
  379.                     mousemove: this.onMouseMove,
  380.                     mouseup: this.onMouseUp
  381.                 });
  382.             }
  383.             this.overlay.setStyle('cursor', handle.el.getStyle('cursor'));
  384.             this.resizing = true;
  385.             this.startBox = this.el.getBox();
  386.             this.startPoint = e.getXY();
  387.             this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
  388.                             (this.startBox.y + this.startBox.height) - this.startPoint[1]];
  389.             this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
  390.             this.overlay.show();
  391.             if(this.constrainTo) {
  392.                 var ct = Ext.get(this.constrainTo);
  393.                 this.resizeRegion = ct.getRegion().adjust(
  394.                     ct.getFrameWidth('t'),
  395.                     ct.getFrameWidth('l'),
  396.                     -ct.getFrameWidth('b'),
  397.                     -ct.getFrameWidth('r')
  398.                 );
  399.             }
  400.             this.proxy.setStyle('visibility', 'hidden'); // workaround display none
  401.             this.proxy.show();
  402.             this.proxy.setBox(this.startBox);
  403.             if(!this.dynamic){
  404.                 this.proxy.setStyle('visibility', 'visible');
  405.             }
  406.         }
  407.     },
  408.     // private
  409.     onMouseDown : function(handle, e){
  410.         if(this.enabled){
  411.             e.stopEvent();
  412.             this.activeHandle = handle;
  413.             this.startSizing(e, handle);
  414.         }          
  415.     },
  416.     // private
  417.     onMouseUp : function(e){
  418.         this.activeHandle = null;
  419.         var size = this.resizeElement();
  420.         this.resizing = false;
  421.         this.handleOut();
  422.         this.overlay.hide();
  423.         this.proxy.hide();
  424.         this.fireEvent('resize', this, size.width, size.height, e);
  425.     },
  426.     // private
  427.     updateChildSize : function(){
  428.         if(this.resizeChild){
  429.             var el = this.el;
  430.             var child = this.resizeChild;
  431.             var adj = this.adjustments;
  432.             if(el.dom.offsetWidth){
  433.                 var b = el.getSize(true);
  434.                 child.setSize(b.width+adj[0], b.height+adj[1]);
  435.             }
  436.             // Second call here for IE
  437.             // The first call enables instant resizing and
  438.             // the second call corrects scroll bars if they
  439.             // exist
  440.             if(Ext.isIE){
  441.                 setTimeout(function(){
  442.                     if(el.dom.offsetWidth){
  443.                         var b = el.getSize(true);
  444.                         child.setSize(b.width+adj[0], b.height+adj[1]);
  445.                     }
  446.                 }, 10);
  447.             }
  448.         }
  449.     },
  450.     // private
  451.     snap : function(value, inc, min){
  452.         if(!inc || !value){
  453.             return value;
  454.         }
  455.         var newValue = value;
  456.         var m = value % inc;
  457.         if(m > 0){
  458.             if(m > (inc/2)){
  459.                 newValue = value + (inc-m);
  460.             }else{
  461.                 newValue = value - m;
  462.             }
  463.         }
  464.         return Math.max(min, newValue);
  465.     },
  466.     /**
  467.      * <p>Performs resizing of the associated Element. This method is called internally by this
  468.      * class, and should not be called by user code.</p>
  469.      * <p>If a Resizable is being used to resize an Element which encapsulates a more complex UI
  470.      * component such as a Panel, this method may be overridden by specifying an implementation
  471.      * as a config option to provide appropriate behaviour at the end of the resize operation on
  472.      * mouseup, for example resizing the Panel, and relaying the Panel's content.</p>
  473.      * <p>The new area to be resized to is available by examining the state of the {@link #proxy}
  474.      * Element. Example:
  475. <pre><code>
  476. new Ext.Panel({
  477.     title: 'Resize me',
  478.     x: 100,
  479.     y: 100,
  480.     renderTo: Ext.getBody(),
  481.     floating: true,
  482.     frame: true,
  483.     width: 400,
  484.     height: 200,
  485.     listeners: {
  486.         render: function(p) {
  487.             new Ext.Resizable(p.getEl(), {
  488.                 handles: 'all',
  489.                 pinned: true,
  490.                 transparent: true,
  491.                 resizeElement: function() {
  492.                     var box = this.proxy.getBox();
  493.                     p.updateBox(box);
  494.                     if (p.layout) {
  495.                         p.doLayout();
  496.                     }
  497.                     return box;
  498.                 }
  499.            });
  500.        }
  501.     }
  502. }).show();
  503. </code></pre>
  504.      */
  505.     resizeElement : function(){
  506.         var box = this.proxy.getBox();
  507.         if(this.updateBox){
  508.             this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
  509.         }else{
  510.             this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
  511.         }
  512.         this.updateChildSize();
  513.         if(!this.dynamic){
  514.             this.proxy.hide();
  515.         }
  516.         return box;
  517.     },
  518.     // private
  519.     constrain : function(v, diff, m, mx){
  520.         if(v - diff < m){
  521.             diff = v - m;    
  522.         }else if(v - diff > mx){
  523.             diff = v - mx; 
  524.         }
  525.         return diff;                
  526.     },
  527.     // private
  528.     onMouseMove : function(e){
  529.         if(this.enabled && this.activeHandle){
  530.             try{// try catch so if something goes wrong the user doesn't get hung
  531.             if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
  532.                 return;
  533.             }
  534.             //var curXY = this.startPoint;
  535.             var curSize = this.curSize || this.startBox,
  536.                 x = this.startBox.x, y = this.startBox.y,
  537.                 ox = x, 
  538.                 oy = y,
  539.                 w = curSize.width, 
  540.                 h = curSize.height,
  541.                 ow = w, 
  542.                 oh = h,
  543.                 mw = this.minWidth, 
  544.                 mh = this.minHeight,
  545.                 mxw = this.maxWidth, 
  546.                 mxh = this.maxHeight,
  547.                 wi = this.widthIncrement,
  548.                 hi = this.heightIncrement,
  549.                 eventXY = e.getXY(),
  550.                 diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0])),
  551.                 diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1])),
  552.                 pos = this.activeHandle.position,
  553.                 tw,
  554.                 th;
  555.             
  556.             switch(pos){
  557.                 case 'east':
  558.                     w += diffX; 
  559.                     w = Math.min(Math.max(mw, w), mxw);
  560.                     break;
  561.                 case 'south':
  562.                     h += diffY;
  563.                     h = Math.min(Math.max(mh, h), mxh);
  564.                     break;
  565.                 case 'southeast':
  566.                     w += diffX; 
  567.                     h += diffY;
  568.                     w = Math.min(Math.max(mw, w), mxw);
  569.                     h = Math.min(Math.max(mh, h), mxh);
  570.                     break;
  571.                 case 'north':
  572.                     diffY = this.constrain(h, diffY, mh, mxh);
  573.                     y += diffY;
  574.                     h -= diffY;
  575.                     break;
  576.                 case 'west':
  577.                     diffX = this.constrain(w, diffX, mw, mxw);
  578.                     x += diffX;
  579.                     w -= diffX;
  580.                     break;
  581.                 case 'northeast':
  582.                     w += diffX; 
  583.                     w = Math.min(Math.max(mw, w), mxw);
  584.                     diffY = this.constrain(h, diffY, mh, mxh);
  585.                     y += diffY;
  586.                     h -= diffY;
  587.                     break;
  588.                 case 'northwest':
  589.                     diffX = this.constrain(w, diffX, mw, mxw);
  590.                     diffY = this.constrain(h, diffY, mh, mxh);
  591.                     y += diffY;
  592.                     h -= diffY;
  593.                     x += diffX;
  594.                     w -= diffX;
  595.                     break;
  596.                case 'southwest':
  597.                     diffX = this.constrain(w, diffX, mw, mxw);
  598.                     h += diffY;
  599.                     h = Math.min(Math.max(mh, h), mxh);
  600.                     x += diffX;
  601.                     w -= diffX;
  602.                     break;
  603.             }
  604.             
  605.             var sw = this.snap(w, wi, mw);
  606.             var sh = this.snap(h, hi, mh);
  607.             if(sw != w || sh != h){
  608.                 switch(pos){
  609.                     case 'northeast':
  610.                         y -= sh - h;
  611.                     break;
  612.                     case 'north':
  613.                         y -= sh - h;
  614.                         break;
  615.                     case 'southwest':
  616.                         x -= sw - w;
  617.                     break;
  618.                     case 'west':
  619.                         x -= sw - w;
  620.                         break;
  621.                     case 'northwest':
  622.                         x -= sw - w;
  623.                         y -= sh - h;
  624.                     break;
  625.                 }
  626.                 w = sw;
  627.                 h = sh;
  628.             }
  629.             
  630.             if(this.preserveRatio){
  631.                 switch(pos){
  632.                     case 'southeast':
  633.                     case 'east':
  634.                         h = oh * (w/ow);
  635.                         h = Math.min(Math.max(mh, h), mxh);
  636.                         w = ow * (h/oh);
  637.                        break;
  638.                     case 'south':
  639.                         w = ow * (h/oh);
  640.                         w = Math.min(Math.max(mw, w), mxw);
  641.                         h = oh * (w/ow);
  642.                         break;
  643.                     case 'northeast':
  644.                         w = ow * (h/oh);
  645.                         w = Math.min(Math.max(mw, w), mxw);
  646.                         h = oh * (w/ow);
  647.                     break;
  648.                     case 'north':
  649.                         tw = w;
  650.                         w = ow * (h/oh);
  651.                         w = Math.min(Math.max(mw, w), mxw);
  652.                         h = oh * (w/ow);
  653.                         x += (tw - w) / 2;
  654.                         break;
  655.                     case 'southwest':
  656.                         h = oh * (w/ow);
  657.                         h = Math.min(Math.max(mh, h), mxh);
  658.                         tw = w;
  659.                         w = ow * (h/oh);
  660.                         x += tw - w;
  661.                         break;
  662.                     case 'west':
  663.                         th = h;
  664.                         h = oh * (w/ow);
  665.                         h = Math.min(Math.max(mh, h), mxh);
  666.                         y += (th - h) / 2;
  667.                         tw = w;
  668.                         w = ow * (h/oh);
  669.                         x += tw - w;
  670.                        break;
  671.                     case 'northwest':
  672.                         tw = w;
  673.                         th = h;
  674.                         h = oh * (w/ow);
  675.                         h = Math.min(Math.max(mh, h), mxh);
  676.                         w = ow * (h/oh);
  677.                         y += th - h;
  678.                         x += tw - w;
  679.                         break;
  680.                         
  681.                 }
  682.             }
  683.             this.proxy.setBounds(x, y, w, h);
  684.             if(this.dynamic){
  685.                 this.resizeElement();
  686.             }
  687.             }catch(ex){}
  688.         }
  689.     },
  690.     // private
  691.     handleOver : function(){
  692.         if(this.enabled){
  693.             this.el.addClass('x-resizable-over');
  694.         }
  695.     },
  696.     // private
  697.     handleOut : function(){
  698.         if(!this.resizing){
  699.             this.el.removeClass('x-resizable-over');
  700.         }
  701.     },
  702.     
  703.     /**
  704.      * Returns the element this component is bound to.
  705.      * @return {Ext.Element}
  706.      */
  707.     getEl : function(){
  708.         return this.el;
  709.     },
  710.     
  711.     /**
  712.      * Returns the resizeChild element (or null).
  713.      * @return {Ext.Element}
  714.      */
  715.     getResizeChild : function(){
  716.         return this.resizeChild;
  717.     },
  718.     
  719.     /**
  720.      * Destroys this resizable. If the element was wrapped and 
  721.      * removeEl is not true then the element remains.
  722.      * @param {Boolean} removeEl (optional) true to remove the element from the DOM
  723.      */
  724.     destroy : function(removeEl){
  725.         Ext.destroy(this.dd, this.overlay, this.proxy);
  726.         this.overlay = null;
  727.         this.proxy = null;
  728.         
  729.         var ps = Ext.Resizable.positions;
  730.         for(var k in ps){
  731.             if(typeof ps[k] != 'function' && this[ps[k]]){
  732.                 this[ps[k]].destroy();
  733.             }
  734.         }
  735.         if(removeEl){
  736.             this.el.update('');
  737.             Ext.destroy(this.el);
  738.             this.el = null;
  739.         }
  740.         this.purgeListeners();
  741.     },
  742.     syncHandleHeight : function(){
  743.         var h = this.el.getHeight(true);
  744.         if(this.west){
  745.             this.west.el.setHeight(h);
  746.         }
  747.         if(this.east){
  748.             this.east.el.setHeight(h);
  749.         }
  750.     }
  751. });
  752. // private
  753. // hash to map config positions to true positions
  754. Ext.Resizable.positions = {
  755.     n: 'north', s: 'south', e: 'east', w: 'west', se: 'southeast', sw: 'southwest', nw: 'northwest', ne: 'northeast'
  756. };
  757. // private
  758. Ext.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
  759.     if(!this.tpl){
  760.         // only initialize the template if resizable is used
  761.         var tpl = Ext.DomHelper.createTemplate(
  762.             {tag: 'div', cls: 'x-resizable-handle x-resizable-handle-{0}'}
  763.         );
  764.         tpl.compile();
  765.         Ext.Resizable.Handle.prototype.tpl = tpl;
  766.     }
  767.     this.position = pos;
  768.     this.rz = rz;
  769.     this.el = this.tpl.append(rz.el.dom, [this.position], true);
  770.     this.el.unselectable();
  771.     if(transparent){
  772.         this.el.setOpacity(0);
  773.     }
  774.     this.el.on('mousedown', this.onMouseDown, this);
  775.     if(!disableTrackOver){
  776.         this.el.on({
  777.             scope: this,
  778.             mouseover: this.onMouseOver,
  779.             mouseout: this.onMouseOut
  780.         });
  781.     }
  782. };
  783. // private
  784. Ext.Resizable.Handle.prototype = {
  785.     // private
  786.     afterResize : function(rz){
  787.         // do nothing    
  788.     },
  789.     // private
  790.     onMouseDown : function(e){
  791.         this.rz.onMouseDown(this, e);
  792.     },
  793.     // private
  794.     onMouseOver : function(e){
  795.         this.rz.handleOver(this, e);
  796.     },
  797.     // private
  798.     onMouseOut : function(e){
  799.         this.rz.handleOut(this, e);
  800.     },
  801.     // private
  802.     destroy : function(){
  803.         Ext.destroy(this.el);
  804.         this.el = null;
  805.     }
  806. };
  807. /**  * @class Ext.Window  * @extends Ext.Panel  * <p>A specialized panel intended for use as an application window.  Windows are floated, {@link #resizable}, and  * {@link #draggable} by default.  Windows can be {@link #maximizable maximized} to fill the viewport,  * restored to their prior size, and can be {@link #minimize}d.</p>  * <p>Windows can also be linked to a {@link Ext.WindowGroup} or managed by the {@link Ext.WindowMgr} to provide   * grouping, activation, to front, to back and other application-specific behavior.</p>  * <p>By default, Windows will be rendered to document.body. To {@link #constrain} a Window to another element  * specify {@link Ext.Component#renderTo renderTo}.</p>  * <p><b>Note:</b> By default, the <code>{@link #closable close}</code> header tool <i>destroys</i> the Window resulting in  * destruction of any child Components. This makes the Window object, and all its descendants <b>unusable</b>. To enable  * re-use of a Window, use <b><code>{@link #closeAction closeAction: 'hide'}</code></b>.</p>  * @constructor  * @param {Object} config The config object  * @xtype window  */ Ext.Window = Ext.extend(Ext.Panel, {     /**      * @cfg {Number} x      * The X position of the left edge of the window on initial showing. Defaults to centering the Window within      * the width of the Window's container {@link Ext.Element Element) (The Element that the Window is rendered to).      */     /**      * @cfg {Number} y      * The Y position of the top edge of the window on initial showing. Defaults to centering the Window within      * the height of the Window's container {@link Ext.Element Element) (The Element that the Window is rendered to).      */     /**      * @cfg {Boolean} modal      * True to make the window modal and mask everything behind it when displayed, false to display it without      * restricting access to other UI elements (defaults to false).      */     /**      * @cfg {String/Element} animateTarget      * Id or element from which the window should animate while opening (defaults to null with no animation).      */     /**      * @cfg {String} resizeHandles      * A valid {@link Ext.Resizable} handles config string (defaults to 'all').  Only applies when resizable = true.      */     /**      * @cfg {Ext.WindowGroup} manager      * A reference to the WindowGroup that should manage this window (defaults to {@link Ext.WindowMgr}).      */     /**     * @cfg {String/Number/Button} defaultButton     * The id / index of a button or a button instance to focus when this window received the focus.     */     /**     * @cfg {Function} onEsc     * Allows override of the built-in processing for the escape key. Default action     * is to close the Window (performing whatever action is specified in {@link #closeAction}.     * To prevent the Window closing when the escape key is pressed, specify this as     * Ext.emptyFn (See {@link Ext#emptyFn}).     */     /**      * @cfg {Boolean} collapsed      * True to render the window collapsed, false to render it expanded (defaults to false). Note that if       * {@link #expandOnShow} is true (the default) it will override the <tt>collapsed</tt> config and the window       * will always be expanded when shown.      */     /**      * @cfg {Boolean} maximized      * True to initially display the window in a maximized state. (Defaults to false).      */          /**     * @cfg {String} baseCls     * The base CSS class to apply to this panel's element (defaults to 'x-window').     */     baseCls : 'x-window',     /**      * @cfg {Boolean} resizable      * True to allow user resizing at each edge and corner of the window, false to disable resizing (defaults to true).      */     resizable : true,     /**      * @cfg {Boolean} draggable      * True to allow the window to be dragged by the header bar, false to disable dragging (defaults to true).  Note      * that by default the window will be centered in the viewport, so if dragging is disabled the window may need      * to be positioned programmatically after render (e.g., myWindow.setPosition(100, 100);).      */     draggable : true,     /**      * @cfg {Boolean} closable      * <p>True to display the 'close' tool button and allow the user to close the window, false to      * hide the button and disallow closing the window (defaults to true).</p>      * <p>By default, when close is requested by either clicking the close button in the header      * or pressing ESC when the Window has focus, the {@link #close} method will be called. This      * will <i>{@link Ext.Component#destroy destroy}</i> the Window and its content meaning that      * it may not be reused.</p>      * <p>To make closing a Window <i>hide</i> the Window so that it may be reused, set      * {@link #closeAction} to 'hide'.      */     closable : true,     /**      * @cfg {String} closeAction      * <p>The action to take when the close header tool is clicked:      * <div class="mdetail-params"><ul>      * <li><b><code>'{@link #close}'</code></b> : <b>Default</b><div class="sub-desc">      * {@link #close remove} the window from the DOM and {@link Ext.Component#destroy destroy}      * it and all descendant Components. The window will <b>not</b> be available to be      * redisplayed via the {@link #show} method.      * </div></li>      * <li><b><code>'{@link #hide}'</code></b> : <div class="sub-desc">      * {@link #hide} the window by setting visibility to hidden and applying negative offsets.      * The window will be available to be redisplayed via the {@link #show} method.      * </div></li>      * </ul></div>      * <p><b>Note:</b> This setting does not affect the {@link #close} method      * which will always {@link Ext.Component#destroy destroy} the window. To      * programatically <i>hide</i> a window, call {@link #hide}.</p>      */     closeAction : 'close',     /**      * @cfg {Boolean} constrain      * True to constrain the window within its containing element, false to allow it to fall outside of its      * containing element. By default the window will be rendered to document.body.  To render and constrain the       * window within another element specify {@link #renderTo}.      * (defaults to false).  Optionally the header only can be constrained using {@link #constrainHeader}.      */     constrain : false,     /**      * @cfg {Boolean} constrainHeader      * True to constrain the window header within its containing element (allowing the window body to fall outside       * of its containing element) or false to allow the header to fall outside its containing element (defaults to       * false). Optionally the entire window can be constrained using {@link #constrain}.      */     constrainHeader : false,     /**      * @cfg {Boolean} plain      * True to render the window body with a transparent background so that it will blend into the framing      * elements, false to add a lighter background color to visually highlight the body element and separate it      * more distinctly from the surrounding frame (defaults to false).      */     plain : false,     /**      * @cfg {Boolean} minimizable      * True to display the 'minimize' tool button and allow the user to minimize the window, false to hide the button      * and disallow minimizing the window (defaults to false).  Note that this button provides no implementation --      * the behavior of minimizing a window is implementation-specific, so the minimize event must be handled and a      * custom minimize behavior implemented for this option to be useful.      */     minimizable : false,     /**      * @cfg {Boolean} maximizable      * True to display the 'maximize' tool button and allow the user to maximize the window, false to hide the button      * and disallow maximizing the window (defaults to false).  Note that when a window is maximized, the tool button      * will automatically change to a 'restore' button with the appropriate behavior already built-in that will      * restore the window to its previous size.      */     maximizable : false,     /**      * @cfg {Number} minHeight      * The minimum height in pixels allowed for this window (defaults to 100).  Only applies when resizable = true.      */     minHeight : 100,     /**      * @cfg {Number} minWidth      * The minimum width in pixels allowed for this window (defaults to 200).  Only applies when resizable = true.      */     minWidth : 200,     /**      * @cfg {Boolean} expandOnShow      * True to always expand the window when it is displayed, false to keep it in its current state (which may be      * {@link #collapsed}) when displayed (defaults to true).      */     expandOnShow : true,     // inherited docs, same default     collapsible : false,     /**      * @cfg {Boolean} initHidden      * True to hide the window until show() is explicitly called (defaults to true).      */     initHidden : true,     /**     * @cfg {Boolean} monitorResize @hide     * This is automatically managed based on the value of constrain and constrainToHeader     */     monitorResize : true,     // The following configs are set to provide the basic functionality of a window.     // Changing them would require additional code to handle correctly and should     // usually only be done in subclasses that can provide custom behavior.  Changing them     // may have unexpected or undesirable results.     /** @cfg {String} elements @hide */     elements : 'header,body',     /** @cfg {Boolean} frame @hide */     frame : true,     /** @cfg {Boolean} floating @hide */     floating : true,     // private     initComponent : function(){         Ext.Window.superclass.initComponent.call(this);         this.addEvents(             /**              * @event activate              * Fires after the window has been visually activated via {@link setActive}.              * @param {Ext.Window} this              */             /**              * @event deactivate              * Fires after the window has been visually deactivated via {@link setActive}.              * @param {Ext.Window} this              */             /**              * @event resize              * Fires after the window has been resized.              * @param {Ext.Window} this              * @param {Number} width The window's new width              * @param {Number} height The window's new height              */             'resize',             /**              * @event maximize              * Fires after the window has been maximized.              * @param {Ext.Window} this              */             'maximize',             /**              * @event minimize              * Fires after the window has been minimized.              * @param {Ext.Window} this              */             'minimize',             /**              * @event restore              * Fires after the window has been restored to its original size after being maximized.              * @param {Ext.Window} this              */             'restore'         );         if(this.initHidden === false){             this.show();         }else{             this.hidden = true;         }     },     // private     getState : function(){         return Ext.apply(Ext.Window.superclass.getState.call(this) || {}, this.getBox(true));     },     // private     onRender : function(ct, position){         Ext.Window.superclass.onRender.call(this, ct, position);         if(this.plain){             this.el.addClass('x-window-plain');         }         // this element allows the Window to be focused for keyboard events         this.focusEl = this.el.createChild({                     tag: 'a', href:'#', cls:'x-dlg-focus',                     tabIndex:'-1', html: '&#160;'});         this.focusEl.swallowEvent('click', true);         this.proxy = this.el.createProxy('x-window-proxy');         this.proxy.enableDisplayMode('block');         if(this.modal){             this.mask = this.container.createChild({cls:'ext-el-mask'}, this.el.dom);             this.mask.enableDisplayMode('block');             this.mask.hide();             this.mon(this.mask, 'click', this.focus, this);         }         this.initTools();     },     // private     initEvents : function(){         Ext.Window.superclass.initEvents.call(this);         if(this.animateTarget){             this.setAnimateTarget(this.animateTarget);         }         if(this.resizable){             this.resizer = new Ext.Resizable(this.el, {                 minWidth: this.minWidth,                 minHeight:this.minHeight,                 handles: this.resizeHandles || 'all',                 pinned: true,                 resizeElement : this.resizerAction             });             this.resizer.window = this;             this.mon(this.resizer, 'beforeresize', this.beforeResize, this);         }         if(this.draggable){             this.header.addClass('x-window-draggable');         }         this.mon(this.el, 'mousedown', this.toFront, this);         this.manager = this.manager || Ext.WindowMgr;         this.manager.register(this);         if(this.maximized){             this.maximized = false;             this.maximize();         }         if(this.closable){             var km = this.getKeyMap();             km.on(27, this.onEsc, this);             km.disable();         }     },     initDraggable : function(){         /**          * If this Window is configured {@link #draggable}, this property will contain          * an instance of {@link Ext.dd.DD} which handles dragging the Window's DOM Element.          * @type Ext.dd.DD          * @property dd          */         this.dd = new Ext.Window.DD(this);     },    // private     onEsc : function(){         this[this.closeAction]();     },     // private     beforeDestroy : function(){         if (this.rendered){             this.hide();           if(this.doAnchor){                 Ext.EventManager.removeResizeListener(this.doAnchor, this);               Ext.EventManager.un(window, 'scroll', this.doAnchor, this);             }             Ext.destroy(                 this.focusEl,                 this.resizer,                 this.dd,                 this.proxy,                 this.mask             );         }         Ext.Window.superclass.beforeDestroy.call(this);     },     // private     onDestroy : function(){         if(this.manager){             this.manager.unregister(this);         }         Ext.Window.superclass.onDestroy.call(this);     },     // private     initTools : function(){         if(this.minimizable){             this.addTool({                 id: 'minimize',                 handler: this.minimize.createDelegate(this, [])             });         }         if(this.maximizable){             this.addTool({                 id: 'maximize',                 handler: this.maximize.createDelegate(this, [])             });             this.addTool({                 id: 'restore',                 handler: this.restore.createDelegate(this, []),                 hidden:true             });             this.mon(this.header, 'dblclick', this.toggleMaximize, this);         }         if(this.closable){             this.addTool({                 id: 'close',                 handler: this[this.closeAction].createDelegate(this, [])             });         }     },     // private     resizerAction : function(){         var box = this.proxy.getBox();         this.proxy.hide();         this.window.handleResize(box);         return box;     },     // private     beforeResize : function(){         this.resizer.minHeight = Math.max(this.minHeight, this.getFrameHeight() + 40); // 40 is a magic minimum content size?         this.resizer.minWidth = Math.max(this.minWidth, this.getFrameWidth() + 40);         this.resizeBox = this.el.getBox();     },     // private     updateHandles : function(){         if(Ext.isIE && this.resizer){             this.resizer.syncHandleHeight();             this.el.repaint();         }     },     // private     handleResize : function(box){         var rz = this.resizeBox;         if(rz.x != box.x || rz.y != box.y){             this.updateBox(box);         }else{             this.setSize(box);         }         this.focus();         this.updateHandles();         this.saveState();         this.doLayout();         this.fireEvent('resize', this, box.width, box.height);     },     /**      * Focuses the window.  If a defaultButton is set, it will receive focus, otherwise the      * window itself will receive focus.      */     focus : function(){         var f = this.focusEl, db = this.defaultButton, t = typeof db;         if(t != 'undefined'){             if(t == 'number' && this.fbar){                 f = this.fbar.items.get(db);             }else if(t == 'string'){                 f = Ext.getCmp(db);             }else{                 f = db;             }         }         f = f || this.focusEl;         f.focus.defer(10, f);     },     /**      * Sets the target element from which the window should animate while opening.      * @param {String/Element} el The target element or id      */     setAnimateTarget : function(el){         el = Ext.get(el);         this.animateTarget = el;     },     // private     beforeShow : function(){         delete this.el.lastXY;         delete this.el.lastLT;         if(this.x === undefined || this.y === undefined){             var xy = this.el.getAlignToXY(this.container, 'c-c');             var pos = this.el.translatePoints(xy[0], xy[1]);             this.x = this.x === undefined? pos.left : this.x;             this.y = this.y === undefined? pos.top : this.y;         }         this.el.setLeftTop(this.x, this.y);         if(this.expandOnShow){             this.expand(false);         }         if(this.modal){             Ext.getBody().addClass('x-body-masked');             this.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));             this.mask.show();         }     },     /**      * Shows the window, rendering it first if necessary, or activates it and brings it to front if hidden.      * @param {String/Element} animateTarget (optional) The target element or id from which the window should      * animate while opening (defaults to null with no animation)      * @param {Function} callback (optional) A callback function to call after the window is displayed      * @param {Object} scope (optional) The scope in which to execute the callback      * @return {Ext.Window} this      */     show : function(animateTarget, cb, scope){         if(!this.rendered){             this.render(Ext.getBody());         }         if(this.hidden === false){             this.toFront();             return this;         }         if(this.fireEvent('beforeshow', this) === false){             return this;         }         if(cb){             this.on('show', cb, scope, {single:true});         }         this.hidden = false;         if(animateTarget !== undefined){             this.setAnimateTarget(animateTarget);         }         this.beforeShow();         if(this.animateTarget){             this.animShow();         }else{             this.afterShow();         }         return this;     },     // private     afterShow : function(isAnim){         this.proxy.hide();         this.el.setStyle('display', 'block');         this.el.show();         if(this.maximized){             this.fitContainer();         }         if(Ext.isMac && Ext.isGecko){ // work around stupid FF 2.0/Mac scroll bar bug             this.cascade(this.setAutoScroll);         }         if(this.monitorResize || this.modal || this.constrain || this.constrainHeader){             Ext.EventManager.onWindowResize(this.onWindowResize, this);         }         this.doConstrain();         this.doLayout();         if(this.keyMap){             this.keyMap.enable();         }         this.toFront();         this.updateHandles();         if(isAnim && (Ext.isIE || Ext.isWebKit)){             var sz = this.getSize();             this.onResize(sz.width, sz.height);         }         this.fireEvent('show', this);     },     // private     animShow : function(){         this.proxy.show();         this.proxy.setBox(this.animateTarget.getBox());         this.proxy.setOpacity(0);         var b = this.getBox(false);         b.callback = this.afterShow.createDelegate(this, [true], false);         b.scope = this;         b.duration = 0.25;         b.easing = 'easeNone';         b.opacity = 0.5;         b.block = true;         this.el.setStyle('display', 'none');         this.proxy.shift(b);     },     /**      * Hides the window, setting it to invisible and applying negative offsets.      * @param {String/Element} animateTarget (optional) The target element or id to which the window should      * animate while hiding (defaults to null with no animation)      * @param {Function} callback (optional) A callback function to call after the window is hidden      * @param {Object} scope (optional) The scope in which to execute the callback      * @return {Ext.Window} this      */     hide : function(animateTarget, cb, scope){         if(this.hidden || this.fireEvent('beforehide', this) === false){             return this;         }         if(cb){             this.on('hide', cb, scope, {single:true});         }         this.hidden = true;         if(animateTarget !== undefined){             this.setAnimateTarget(animateTarget);         }         if(this.modal){             this.mask.hide();             Ext.getBody().removeClass('x-body-masked');         }         if(this.animateTarget){             this.animHide();         }else{             this.el.hide();             this.afterHide();         }         return this;     },     // private     afterHide : function(){         this.proxy.hide();         if(this.monitorResize || this.modal || this.constrain || this.constrainHeader){             Ext.EventManager.removeResizeListener(this.onWindowResize, this);         }         if(this.keyMap){             this.keyMap.disable();         }         this.fireEvent('hide', this);     },     // private     animHide : function(){         this.proxy.setOpacity(0.5);         this.proxy.show();         var tb = this.getBox(false);         this.proxy.setBox(tb);         this.el.hide();         var b = this.animateTarget.getBox();         b.callback = this.afterHide;         b.scope = this;         b.duration = 0.25;         b.easing = 'easeNone';         b.block = true;         b.opacity = 0;         this.proxy.shift(b);     },     // private     onWindowResize : function(){         if(this.maximized){             this.fitContainer();         }         if(this.modal){             this.mask.setSize('100%', '100%');             var force = this.mask.dom.offsetHeight;             this.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));         }         this.doConstrain();     },     // private     doConstrain : function(){         if(this.constrain || this.constrainHeader){             var offsets;             if(this.constrain){                 offsets = {                     right:this.el.shadowOffset,                     left:this.el.shadowOffset,                     bottom:this.el.shadowOffset                 };             }else {                 var s = this.getSize();                 offsets = {                     right:-(s.width - 100),                     bottom:-(s.height - 25)                 };             }             var xy = this.el.getConstrainToXY(this.container, true, offsets);             if(xy){                 this.setPosition(xy[0], xy[1]);             }         }     },     // private - used for dragging     ghost : function(cls){         var ghost = this.createGhost(cls);         var box = this.getBox(true);         ghost.setLeftTop(box.x, box.y);         ghost.setWidth(box.width);         this.el.hide();         this.activeGhost = ghost;         return ghost;     },     // private     unghost : function(show, matchPosition){         if(!this.activeGhost) {             return;         }         if(show !== false){             this.el.show();             this.focus();             if(Ext.isMac && Ext.isGecko){ // work around stupid FF 2.0/Mac scroll bar bug                 this.cascade(this.setAutoScroll);             }         }         if(matchPosition !== false){             this.setPosition(this.activeGhost.getLeft(true), this.activeGhost.getTop(true));         }         this.activeGhost.hide();         this.activeGhost.remove();         delete this.activeGhost;     },     /**      * Placeholder method for minimizing the window.  By default, this method simply fires the {@link #minimize} event      * since the behavior of minimizing a window is application-specific.  To implement custom minimize behavior,      * either the minimize event can be handled or this method can be overridden.      * @return {Ext.Window} this      */     minimize : function(){         this.fireEvent('minimize', this);         return this;     },     /**      * <p>Closes the Window, removes it from the DOM, {@link Ext.Component#destroy destroy}s      * the Window object and all its descendant Components. The {@link Ext.Panel#beforeclose beforeclose}      * event is fired before the close happens and will cancel the close action if it returns false.<p>      * <p><b>Note:</b> This method is not affected by the {@link #closeAction} setting which      * only affects the action triggered when clicking the {@link #closable 'close' tool in the header}.      * To hide the Window without destroying it, call {@link #hide}.</p>      */     close : function(){         if(this.fireEvent('beforeclose', this) !== false){             this.hide(null, function(){                 this.fireEvent('close', this);                 this.destroy();             }, this);         }     },     /**      * Fits the window within its current container and automatically replaces      * the {@link #maximizable 'maximize' tool button} with the 'restore' tool button.      * Also see {@link #toggleMaximize}.      * @return {Ext.Window} this      */     maximize : function(){         if(!this.maximized){             this.expand(false);             this.restoreSize = this.getSize();             this.restorePos = this.getPosition(true);             if (this.maximizable){                 this.tools.maximize.hide();                 this.tools.restore.show();             }             this.maximized = true;             this.el.disableShadow();             if(this.dd){                 this.dd.lock();             }             if(this.collapsible){                 this.tools.toggle.hide();             }             this.el.addClass('x-window-maximized');             this.container.addClass('x-window-maximized-ct');             this.setPosition(0, 0);             this.fitContainer();             this.fireEvent('maximize', this);         }         return this;     },     /**      * Restores a {@link #maximizable maximized}  window back to its original      * size and position prior to being maximized and also replaces      * the 'restore' tool button with the 'maximize' tool button.      * Also see {@link #toggleMaximize}.      * @return {Ext.Window} this      */     restore : function(){         if(this.maximized){             this.el.removeClass('x-window-maximized');             this.tools.restore.hide();             this.tools.maximize.show();             this.setPosition(this.restorePos[0], this.restorePos[1]);             this.setSize(this.restoreSize.width, this.restoreSize.height);             delete this.restorePos;             delete this.restoreSize;             this.maximized = false;             this.el.enableShadow(true);             if(this.dd){                 this.dd.unlock();             }             if(this.collapsible){                 this.tools.toggle.show();             }             this.container.removeClass('x-window-maximized-ct');             this.doConstrain();             this.fireEvent('restore', this);         }         return this;     },     /**      * A shortcut method for toggling between {@link #maximize} and {@link #restore} based on the current maximized      * state of the window.      * @return {Ext.Window} this      */     toggleMaximize : function(){         return this[this.maximized ? 'restore' : 'maximize']();     },     // private     fitContainer : function(){         var vs = this.container.getViewSize();         this.setSize(vs.width, vs.height);     },     // private     // z-index is managed by the WindowManager and may be overwritten at any time     setZIndex : function(index){         if(this.modal){             this.mask.setStyle('z-index', index);         }         this.el.setZIndex(++index);         index += 5;         if(this.resizer){             this.resizer.proxy.setStyle('z-index', ++index);         }         this.lastZIndex = index;     },     /**      * Aligns the window to the specified element      * @param {Mixed} element The element to align to.      * @param {String} position The position to align to (see {@link Ext.Element#alignTo} for more details).      * @param {Array} offsets (optional) Offset the positioning by [x, y]      * @return {Ext.Window} this      */     alignTo : function(element, position, offsets){         var xy = this.el.getAlignToXY(element, position, offsets);         this.setPagePosition(xy[0], xy[1]);         return this;     },     /**      * Anchors this window to another element and realigns it when the window is resized or scrolled.      * @param {Mixed} element The element to align to.      * @param {String} position The position to align to (see {@link Ext.Element#alignTo} for more details)      * @param {Array} offsets (optional) Offset the positioning by [x, y]      * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter      * is a number, it is used as the buffer delay (defaults to 50ms).      * @return {Ext.Window} this      */     anchorTo : function(el, alignment, offsets, monitorScroll){       if(this.doAnchor){           Ext.EventManager.removeResizeListener(this.doAnchor, this);           Ext.EventManager.un(window, 'scroll', this.doAnchor, this);       }       this.doAnchor = function(){           this.alignTo(el, alignment, offsets);       };       Ext.EventManager.onWindowResize(this.doAnchor, this);              var tm = typeof monitorScroll;       if(tm != 'undefined'){           Ext.EventManager.on(window, 'scroll', this.doAnchor, this,               {buffer: tm == 'number' ? monitorScroll : 50});       }       this.doAnchor();       return this;     },     /**      * Brings this window to the front of any other visible windows      * @param {Boolean} e (optional) Specify <tt>false</tt> to prevent the window from being focused.      * @return {Ext.Window} this      */     toFront : function(e){         if(this.manager.bringToFront(this)){             if(!e || !e.getTarget().focus){                 this.focus();             }         }         return this;     },     /**      * Makes this the active window by showing its shadow, or deactivates it by hiding its shadow.  This method also      * fires the {@link #activate} or {@link #deactivate} event depending on which action occurred.      * @param {Boolean} active True to activate the window, false to deactivate it (defaults to false)      */     setActive : function(active){         if(active){             if(!this.maximized){                 this.el.enableShadow(true);             }             this.fireEvent('activate', this);         }else{             this.el.disableShadow();             this.fireEvent('deactivate', this);         }     },     /**      * Sends this window to the back of (lower z-index than) any other visible windows      * @return {Ext.Window} this      */     toBack : function(){         this.manager.sendToBack(this);         return this;     },     /**      * Centers this window in the viewport      * @return {Ext.Window} this      */     center : function(){         var xy = this.el.getAlignToXY(this.container, 'c-c');         this.setPagePosition(xy[0], xy[1]);         return this;     }     /**      * @cfg {Boolean} autoWidth @hide      **/ }); Ext.reg('window', Ext.Window); // private - custom Window DD implementation Ext.Window.DD = function(win){     this.win = win;     Ext.Window.DD.superclass.constructor.call(this, win.el.id, 'WindowDD-'+win.id);     this.setHandleElId(win.header.id);     this.scroll = false; }; Ext.extend(Ext.Window.DD, Ext.dd.DD, {     moveOnly:true,     headerOffsets:[100, 25],     startDrag : function(){         var w = this.win;         this.proxy = w.ghost();         if(w.constrain !== false){             var so = w.el.shadowOffset;             this.constrainTo(w.container, {right: so, left: so, bottom: so});         }else if(w.constrainHeader !== false){             var s = this.proxy.getSize();             this.constrainTo(w.container, {right: -(s.width-this.headerOffsets[0]), bottom: -(s.height-this.headerOffsets[1])});         }     },     b4Drag : Ext.emptyFn,     onDrag : function(e){         this.alignElWithMouse(this.proxy, e.getPageX(), e.getPageY());     },     endDrag : function(e){         this.win.unghost();         this.win.saveState();     } }); /**  * @class Ext.WindowGroup  * An object that represents a group of {@link Ext.Window} instances and provides z-order management  * and window activation behavior.  * @constructor  */ Ext.WindowGroup = function(){     var list = {};     var accessList = [];     var front = null;     // private     var sortWindows = function(d1, d2){         return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;     };     // private     var orderWindows = function(){         var a = accessList, len = a.length;         if(len > 0){             a.sort(sortWindows);             var seed = a[0].manager.zseed;             for(var i = 0; i < len; i++){                 var win = a[i];                 if(win && !win.hidden){                     win.setZIndex(seed + (i*10));                 }             }         }         activateLast();     };     // private     var setActiveWin = function(win){         if(win != front){             if(front){                 front.setActive(false);             }             front = win;             if(win){                 win.setActive(true);             }         }     };     // private     var activateLast = function(){         for(var i = accessList.length-1; i >=0; --i) {             if(!accessList[i].hidden){                 setActiveWin(accessList[i]);                 return;             }         }         // none to activate         setActiveWin(null);     };     return {         /**          * The starting z-index for windows (defaults to 9000)          * @type Number The z-index value          */         zseed : 9000,         // private         register : function(win){             list[win.id] = win;             accessList.push(win);             win.on('hide', activateLast);         },         // private         unregister : function(win){             delete list[win.id];             win.un('hide', activateLast);             accessList.remove(win);         },         /**          * Gets a registered window by id.          * @param {String/Object} id The id of the window or a {@link Ext.Window} instance          * @return {Ext.Window}          */         get : function(id){             return typeof id == "object" ? id : list[id];         },         /**          * Brings the specified window to the front of any other active windows.          * @param {String/Object} win The id of the window or a {@link Ext.Window} instance          * @return {Boolean} True if the dialog was brought to the front, else false          * if it was already in front          */         bringToFront : function(win){             win = this.get(win);             if(win != front){                 win._lastAccess = new Date().getTime();                 orderWindows();                 return true;             }             return false;         },         /**          * Sends the specified window to the back of other active windows.          * @param {String/Object} win The id of the window or a {@link Ext.Window} instance          * @return {Ext.Window} The window          */         sendToBack : function(win){             win = this.get(win);             win._lastAccess = -(new Date().getTime());             orderWindows();             return win;         },         /**          * Hides all windows in the group.          */         hideAll : function(){             for(var id in list){                 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){                     list[id].hide();                 }             }         },         /**          * Gets the currently-active window in the group.          * @return {Ext.Window} The active window          */         getActive : function(){             return front;         },         /**          * Returns zero or more windows in the group using the custom search function passed to this method.          * The function should accept a single {@link Ext.Window} reference as its only argument and should          * return true if the window matches the search criteria, otherwise it should return false.          * @param {Function} fn The search function          * @param {Object} scope (optional) The scope in which to execute the function (defaults to the window          * that gets passed to the function if not specified)          * @return {Array} An array of zero or more matching windows          */         getBy : function(fn, scope){             var r = [];             for(var i = accessList.length-1; i >=0; --i) {                 var win = accessList[i];                 if(fn.call(scope||win, win) !== false){                     r.push(win);                 }             }             return r;         },         /**          * Executes the specified function once for every window in the group, passing each          * window as the only parameter. Returning false from the function will stop the iteration.          * @param {Function} fn The function to execute for each item          * @param {Object} scope (optional) The scope in which to execute the function          */         each : function(fn, scope){             for(var id in list){                 if(list[id] && typeof list[id] != "function"){                     if(fn.call(scope || list[id], list[id]) === false){                         return;                     }                 }             }         }     }; }; /**  * @class Ext.WindowMgr  * @extends Ext.WindowGroup  * The default global window group that is available automatically.  To have more than one group of windows  * with separate z-order stacks, create additional instances of {@link Ext.WindowGroup} as needed.  * @singleton  */ Ext.WindowMgr = new Ext.WindowGroup();/**  * @class Ext.MessageBox  * <p>Utility class for generating different styles of message boxes.  The alias Ext.Msg can also be used.<p/>  * <p>Note that the MessageBox is asynchronous.  Unlike a regular JavaScript <code>alert</code> (which will halt  * browser execution), showing a MessageBox will not cause the code to stop.  For this reason, if you have code  * that should only run <em>after</em> some user feedback from the MessageBox, you must use a callback function  * (see the <code>function</code> parameter for {@link #show} for more details).</p>  * <p>Example usage:</p>  *<pre><code> // Basic alert: Ext.Msg.alert('Status', 'Changes saved successfully.'); // Prompt for user data and process the result using a callback: Ext.Msg.prompt('Name', 'Please enter your name:', function(btn, text){     if (btn == 'ok'){         // process text value and close...     } }); // Show a dialog using config options: Ext.Msg.show({    title:'Save Changes?',    msg: 'You are closing a tab that has unsaved changes. Would you like to save your changes?',    buttons: Ext.Msg.YESNOCANCEL,    fn: processResult,    animEl: 'elId',    icon: Ext.MessageBox.QUESTION }); </code></pre>  * @singleton  */ Ext.MessageBox = function(){     var dlg, opt, mask, waitTimer;     var bodyEl, msgEl, textboxEl, textareaEl, progressBar, pp, iconEl, spacerEl;     var buttons, activeTextEl, bwidth, iconCls = '';     // private     var handleButton = function(button){         if(dlg.isVisible()){             dlg.hide();             handleHide();             Ext.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value, opt], 1);         }     };     // private     var handleHide = function(){         if(opt && opt.cls){             dlg.el.removeClass(opt.cls);         }         progressBar.reset();     };     // private     var handleEsc = function(d, k, e){         if(opt && opt.closable !== false){             dlg.hide();             handleHide();         }         if(e){             e.stopEvent();         }     };     // private     var updateButtons = function(b){         var width = 0;         if(!b){             buttons["ok"].hide();             buttons["cancel"].hide();             buttons["yes"].hide();             buttons["no"].hide();             return width;         }         dlg.footer.dom.style.display = '';         for(var k in buttons){             if(typeof buttons[k] != "function"){                 if(b[k]){                     buttons[k].show();                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Ext.MessageBox.buttonText[k]);                     width += buttons[k].el.getWidth()+15;                 }else{                     buttons[k].hide();                 }             }         }         return width;     };     return {         /**          * Returns a reference to the underlying {@link Ext.Window} element          * @return {Ext.Window} The window          */         getDialog : function(titleText){            if(!dlg){                 dlg = new Ext.Window({                     autoCreate : true,                     title:titleText,                     resizable:false,                     constrain:true,                     constrainHeader:true,                     minimizable : false,                     maximizable : false,                     stateful: false,                     modal: true,                     shim:true,                     buttonAlign:"center",                     width:400,                     height:100,                     minHeight: 80,                     plain:true,                     footer:true,                     closable:true,                     close : function(){                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){                             handleButton("no");                         }else{                             handleButton("cancel");                         }                     }                 });                 buttons = {};                 var bt = this.buttonText;                 //TODO: refactor this block into a buttons config to pass into the Window constructor                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));                 buttons["ok"].hideMode = buttons["yes"].hideMode = buttons["no"].hideMode = buttons["cancel"].hideMode = 'offsets';                 dlg.render(document.body);                 dlg.getEl().addClass('x-window-dlg');                 mask = dlg.mask;                 bodyEl = dlg.body.createChild({                     html:'<div class="ext-mb-icon"></div><div class="ext-mb-content"><span class="ext-mb-text"></span><br /><div class="ext-mb-fix-cursor"><input type="text" class="ext-mb-input" /><textarea class="ext-mb-textarea"></textarea></div></div>'                 });                 iconEl = Ext.get(bodyEl.dom.firstChild);                 var contentEl = bodyEl.dom.childNodes[1];                 msgEl = Ext.get(contentEl.firstChild);                 textboxEl = Ext.get(contentEl.childNodes[2].firstChild);                 textboxEl.enableDisplayMode();                 textboxEl.addKeyListener([10,13], function(){                     if(dlg.isVisible() && opt && opt.buttons){                         if(opt.buttons.ok){                             handleButton("ok");                         }else if(opt.buttons.yes){                             handleButton("yes");                         }                     }                 });                 textareaEl = Ext.get(contentEl.childNodes[2].childNodes[1]);                 textareaEl.enableDisplayMode();                 progressBar = new Ext.ProgressBar({                     renderTo:bodyEl                 });                bodyEl.createChild({cls:'x-clear'});             }             return dlg;         },         /**          * Updates the message box body text          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to          * the XHTML-compliant non-breaking space character '&amp;#160;')          * @return {Ext.MessageBox} this          */         updateText : function(text){             if(!dlg.isVisible() && !opt.width){                 dlg.setSize(this.maxWidth, 100); // resize first so content is never clipped from previous shows             }             msgEl.update(text || '&#160;');             var iw = iconCls != '' ? (iconEl.getWidth() + iconEl.getMargins('lr')) : 0;             var mw = msgEl.getWidth() + msgEl.getMargins('lr');             var fw = dlg.getFrameWidth('lr');             var bw = dlg.body.getFrameWidth('lr');             if (Ext.isIE && iw > 0){                 //3 pixels get subtracted in the icon CSS for an IE margin issue,                 //so we have to add it back here for the overall width to be consistent                 iw += 3;             }             var w = Math.max(Math.min(opt.width || iw+mw+fw+bw, this.maxWidth),                         Math.max(opt.minWidth || this.minWidth, bwidth || 0));             if(opt.prompt === true){                 activeTextEl.setWidth(w-iw-fw-bw);             }             if(opt.progress === true || opt.wait === true){                 progressBar.setSize(w-iw-fw-bw);             }             if(Ext.isIE && w == bwidth){                 w += 4; //Add offset when the content width is smaller than the buttons.                 }             dlg.setSize(w, 'auto').center();             return this;         },         /**          * Updates a progress-style message box's text and progress bar. Only relevant on message boxes          * initiated via {@link Ext.MessageBox#progress} or {@link Ext.MessageBox#wait},          * or by calling {@link Ext.MessageBox#show} with progress: true.          * @param {Number} value Any number between 0 and 1 (e.g., .5, defaults to 0)          * @param {String} progressText The progress text to display inside the progress bar (defaults to '')          * @param {String} msg The message box's body text is replaced with the specified string (defaults to undefined          * so that any existing body text will not get overwritten by default unless a new value is passed in)          * @return {Ext.MessageBox} this          */         updateProgress : function(value, progressText, msg){             progressBar.updateProgress(value, progressText);             if(msg){                 this.updateText(msg);             }             return this;         },         /**          * Returns true if the message box is currently displayed          * @return {Boolean} True if the message box is visible, else false          */         isVisible : function(){             return dlg && dlg.isVisible();         },         /**          * Hides the message box if it is displayed          * @return {Ext.MessageBox} this          */         hide : function(){             var proxy = dlg ? dlg.activeGhost : null;             if(this.isVisible() || proxy){                 dlg.hide();                 handleHide();                 if (proxy){                     // unghost is a private function, but i saw no better solution                     // to fix the locking problem when dragging while it closes                     dlg.unghost(false, false);                 }              }             return this;         },         /**          * Displays a new message box, or reinitializes an existing message box, based on the config options          * passed in. All display functions (e.g. prompt, alert, etc.) on MessageBox call this function internally,          * although those calls are basic shortcuts and do not support all of the config options allowed here.          * @param {Object} config The following config options are supported: <ul>          * <li><b>animEl</b> : String/Element<div class="sub-desc">An id or Element from which the message box should animate as it          * opens and closes (defaults to undefined)</div></li>          * <li><b>buttons</b> : Object/Boolean<div class="sub-desc">A button config object (e.g., Ext.MessageBox.OKCANCEL or {ok:'Foo',          * cancel:'Bar'}), or false to not show any buttons (defaults to false)</div></li>          * <li><b>closable</b> : Boolean<div class="sub-desc">False to hide the top-right close button (defaults to true). Note that          * progress and wait dialogs will ignore this property and always hide the close button as they can only          * be closed programmatically.</div></li>          * <li><b>cls</b> : String<div class="sub-desc">A custom CSS class to apply to the message box's container element</div></li>          * <li><b>defaultTextHeight</b> : Number<div class="sub-desc">The default height in pixels of the message box's multiline textarea          * if displayed (defaults to 75)</div></li>          * <li><b>fn</b> : Function<div class="sub-desc">A callback function which is called when the dialog is dismissed either          * by clicking on the configured buttons, or on the dialog close button, or by pressing          * the return button to enter input.          * <p>Progress and wait dialogs will ignore this option since they do not respond to user          * actions and can only be closed programmatically, so any required function should be called          * by the same code after it closes the dialog. Parameters passed:<ul>          * <li><b>buttonId</b> : String<div class="sub-desc">The ID of the button pressed, one of:<div class="sub-desc"><ul>          * <li><tt>ok</tt></li>          * <li><tt>yes</tt></li>          * <li><tt>no</tt></li>          * <li><tt>cancel</tt></li>          * </ul></div></div></li>          * <li><b>text</b> : String<div class="sub-desc">Value of the input field if either <tt><a href="#show-option-prompt" ext:member="show-option-prompt" ext:cls="Ext.MessageBox">prompt</a></tt>          * or <tt><a href="#show-option-multiline" ext:member="show-option-multiline" ext:cls="Ext.MessageBox">multiline</a></tt> is true</div></li>          * <li><b>opt</b> : Object<div class="sub-desc">The config object passed to show.</div></li>          * </ul></p></div></li>          * <li><b>scope</b> : Object<div class="sub-desc">The scope of the callback function</div></li>          * <li><b>icon</b> : String<div class="sub-desc">A CSS class that provides a background image to be used as the body icon for the          * dialog (e.g. Ext.MessageBox.WARNING or 'custom-class') (defaults to '')</div></li>          * <li><b>iconCls</b> : String<div class="sub-desc">The standard {@link Ext.Window#iconCls} to          * add an optional header icon (defaults to '')</div></li>          * <li><b>maxWidth</b> : Number<div class="sub-desc">The maximum width in pixels of the message box (defaults to 600)</div></li>          * <li><b>minWidth</b> : Number<div class="sub-desc">The minimum width in pixels of the message box (defaults to 100)</div></li>          * <li><b>modal</b> : Boolean<div class="sub-desc">False to allow user interaction with the page while the message box is          * displayed (defaults to true)</div></li>          * <li><b>msg</b> : String<div class="sub-desc">A string that will replace the existing message box body text (defaults to the          * XHTML-compliant non-breaking space character '&amp;#160;')</div></li>          * <li><a id="show-option-multiline"></a><b>multiline</b> : Boolean<div class="sub-desc">          * True to prompt the user to enter multi-line text (defaults to false)</div></li>          * <li><b>progress</b> : Boolean<div class="sub-desc">True to display a progress bar (defaults to false)</div></li>          * <li><b>progressText</b> : String<div class="sub-desc">The text to display inside the progress bar if progress = true (defaults to '')</div></li>          * <li><a id="show-option-prompt"></a><b>prompt</b> : Boolean<div class="sub-desc">True to prompt the user to enter single-line text (defaults to false)</div></li>          * <li><b>proxyDrag</b> : Boolean<div class="sub-desc">True to display a lightweight proxy while dragging (defaults to false)</div></li>          * <li><b>title</b> : String<div class="sub-desc">The title text</div></li>          * <li><b>value</b> : String<div class="sub-desc">The string value to set into the active textbox element if displayed</div></li>          * <li><b>wait</b> : Boolean<div class="sub-desc">True to display a progress bar (defaults to false)</div></li>          * <li><b>waitConfig</b> : Object<div class="sub-desc">A {@link Ext.ProgressBar#waitConfig} object (applies only if wait = true)</div></li>          * <li><b>width</b> : Number<div class="sub-desc">The width of the dialog in pixels</div></li>          * </ul>          * Example usage:          * <pre><code> Ext.Msg.show({    title: 'Address',    msg: 'Please enter your address:',    width: 300,    buttons: Ext.MessageBox.OKCANCEL,    multiline: true,    fn: saveAddress,    animEl: 'addAddressBtn',    icon: Ext.MessageBox.INFO }); </code></pre>          * @return {Ext.MessageBox} this          */         show : function(options){             if(this.isVisible()){                 this.hide();             }             opt = options;             var d = this.getDialog(opt.title || "&#160;");             d.setTitle(opt.title || "&#160;");             var allowClose = (opt.closable !== false && opt.progress !== true && opt.wait !== true);             d.tools.close.setDisplayed(allowClose);             activeTextEl = textboxEl;             opt.prompt = opt.prompt || (opt.multiline ? true : false);             if(opt.prompt){                 if(opt.multiline){                     textboxEl.hide();                     textareaEl.show();                     textareaEl.setHeight(typeof opt.multiline == "number" ?                         opt.multiline : this.defaultTextHeight);                     activeTextEl = textareaEl;                 }else{                     textboxEl.show();                     textareaEl.hide();                 }             }else{                 textboxEl.hide();                 textareaEl.hide();             }             activeTextEl.dom.value = opt.value || "";             if(opt.prompt){                 d.focusEl = activeTextEl;             }else{                 var bs = opt.buttons;                 var db = null;                 if(bs && bs.ok){                     db = buttons["ok"];                 }else if(bs && bs.yes){                     db = buttons["yes"];                 }                 if (db){                     d.focusEl = db;                 }             }             if(opt.iconCls){               d.setIconClass(opt.iconCls);             }             this.setIcon(opt.icon);             if(opt.cls){                 d.el.addClass(opt.cls);             }             d.proxyDrag = opt.proxyDrag === true;             d.modal = opt.modal !== false;             d.mask = opt.modal !== false ? mask : false;                          d.on('show', function(){                 //workaround for window internally enabling keymap in afterShow                 d.keyMap.setDisabled(allowClose !== true);                 d.doLayout();                 this.setIcon(opt.icon);                 bwidth = updateButtons(opt.buttons);                 progressBar.setVisible(opt.progress === true || opt.wait === true);                 this.updateProgress(0, opt.progressText);                 this.updateText(opt.msg);                 if(opt.wait === true){                     progressBar.wait(opt.waitConfig);                 }             }, this, {single:true});             if(!d.isVisible()){                 // force it to the end of the z-index stack so it gets a cursor in FF                 document.body.appendChild(dlg.el.dom);                 d.setAnimateTarget(opt.animEl);                 d.show(opt.animEl);             }             return this;         },         /**          * Adds the specified icon to the dialog.  By default, the class 'ext-mb-icon' is applied for default          * styling, and the class passed in is expected to supply the background image url. Pass in empty string ('')          * to clear any existing icon.  The following built-in icon classes are supported, but you can also pass          * in a custom class name:          * <pre> Ext.MessageBox.INFO Ext.MessageBox.WARNING Ext.MessageBox.QUESTION Ext.MessageBox.ERROR          *</pre>          * @param {String} icon A CSS classname specifying the icon's background image url, or empty string to clear the icon          * @return {Ext.MessageBox} this          */         setIcon : function(icon){             if(icon && icon != ''){                 iconEl.removeClass('x-hidden');                 iconEl.replaceClass(iconCls, icon);                 bodyEl.addClass('x-dlg-icon');                 iconCls = icon;             }else{                 iconEl.replaceClass(iconCls, 'x-hidden');                 bodyEl.removeClass('x-dlg-icon');                 iconCls = '';             }             return this;         },         /**          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by          * the user.  You are responsible for updating the progress bar as needed via {@link Ext.MessageBox#updateProgress}          * and closing the message box when the process is complete.          * @param {String} title The title bar text          * @param {String} msg The message box body text          * @param {String} progressText (optional) The text to display inside the progress bar (defaults to '')          * @return {Ext.MessageBox} this          */         progress : function(title, msg, progressText){             this.show({                 title : title,                 msg : msg,                 buttons: false,                 progress:true,                 closable:false,                 minWidth: this.minProgressWidth,                 progressText: progressText             });             return this;         },         /**          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user          * interaction while waiting for a long-running process to complete that does not have defined intervals.          * You are responsible for closing the message box when the process is complete.          * @param {String} msg The message box body text          * @param {String} title (optional) The title bar text          * @param {Object} config (optional) A {@link Ext.ProgressBar#waitConfig} object          * @return {Ext.MessageBox} this          */         wait : function(msg, title, config){             this.show({                 title : title,                 msg : msg,                 buttons: false,                 closable:false,                 wait:true,                 modal:true,                 minWidth: this.minProgressWidth,                 waitConfig: config             });             return this;         },         /**          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript alert prompt).          * If a callback function is passed it will be called after the user clicks the button, and the          * id of the button that was clicked will be passed as the only parameter to the callback          * (could also be the top-right close button).          * @param {String} title The title bar text          * @param {String} msg The message box body text          * @param {Function} fn (optional) The callback function invoked after the message box is closed          * @param {Object} scope (optional) The scope of the callback function          * @return {Ext.MessageBox} this          */         alert : function(title, msg, fn, scope){             this.show({                 title : title,                 msg : msg,                 buttons: this.OK,                 fn: fn,                 scope : scope             });             return this;         },         /**          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's confirm).          * If a callback function is passed it will be called after the user clicks either button,          * and the id of the button that was clicked will be passed as the only parameter to the callback          * (could also be the top-right close button).          * @param {String} title The title bar text          * @param {String} msg The message box body text          * @param {Function} fn (optional) The callback function invoked after the message box is closed          * @param {Object} scope (optional) The scope of the callback function          * @return {Ext.MessageBox} this          */         confirm : function(title, msg, fn, scope){             this.show({                 title : title,                 msg : msg,                 buttons: this.YESNO,                 fn: fn,                 scope : scope,                 icon: this.QUESTION             });             return this;         },         /**          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to JavaScript's prompt).          * The prompt can be a single-line or multi-line textbox.  If a callback function is passed it will be called after the user          * clicks either button, and the id of the button that was clicked (could also be the top-right          * close button) and the text that was entered will be passed as the two parameters to the callback.          * @param {String} title The title bar text          * @param {String} msg The message box body text          * @param {Function} fn (optional) The callback function invoked after the message box is closed          * @param {Object} scope (optional) The scope of the callback function          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight          * property, or the height in pixels to create the textbox (defaults to false / single-line)          * @param {String} value (optional) Default value of the text input element (defaults to '')          * @return {Ext.MessageBox} this          */         prompt : function(title, msg, fn, scope, multiline, value){             this.show({                 title : title,                 msg : msg,                 buttons: this.OKCANCEL,                 fn: fn,                 minWidth:250,                 scope : scope,                 prompt:true,                 multiline: multiline,                 value: value             });             return this;         },         /**          * Button config that displays a single OK button          * @type Object          */         OK : {ok:true},         /**          * Button config that displays a single Cancel button          * @type Object          */         CANCEL : {cancel:true},         /**          * Button config that displays OK and Cancel buttons          * @type Object          */         OKCANCEL : {ok:true, cancel:true},         /**          * Button config that displays Yes and No buttons          * @type Object          */         YESNO : {yes:true, no:true},         /**          * Button config that displays Yes, No and Cancel buttons          * @type Object          */         YESNOCANCEL : {yes:true, no:true, cancel:true},         /**          * The CSS class that provides the INFO icon image          * @type String          */         INFO : 'ext-mb-info',         /**          * The CSS class that provides the WARNING icon image          * @type String          */         WARNING : 'ext-mb-warning',         /**          * The CSS class that provides the QUESTION icon image          * @type String          */         QUESTION : 'ext-mb-question',         /**          * The CSS class that provides the ERROR icon image          * @type String          */         ERROR : 'ext-mb-error',         /**          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)          * @type Number          */         defaultTextHeight : 75,         /**          * The maximum width in pixels of the message box (defaults to 600)          * @type Number          */         maxWidth : 600,         /**          * The minimum width in pixels of the message box (defaults to 110)          * @type Number          */         minWidth : 110,         /**          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful          * for setting a different minimum width than text-only dialogs may need (defaults to 250)          * @type Number          */         minProgressWidth : 250,         /**          * An object containing the default button text strings that can be overriden for localized language support.          * Supported properties are: ok, cancel, yes and no.  Generally you should include a locale-specific          * resource file for handling language support across the framework.          * Customize the default text like so: Ext.MessageBox.buttonText.yes = "oui"; //french          * @type Object          */         buttonText : {             ok : "OK",             cancel : "Cancel",             yes : "Yes",             no : "No"         }     }; }(); /**  * Shorthand for {@link Ext.MessageBox}  */ Ext.Msg = Ext.MessageBox;/**
  808.  * @class Ext.dd.PanelProxy
  809.  * A custom drag proxy implementation specific to {@link Ext.Panel}s. This class is primarily used internally
  810.  * for the Panel's drag drop implementation, and should never need to be created directly.
  811.  * @constructor
  812.  * @param panel The {@link Ext.Panel} to proxy for
  813.  * @param config Configuration options
  814.  */
  815. Ext.dd.PanelProxy = function(panel, config){
  816.     this.panel = panel;
  817.     this.id = this.panel.id +'-ddproxy';
  818.     Ext.apply(this, config);
  819. };
  820. Ext.dd.PanelProxy.prototype = {
  821.     /**
  822.      * @cfg {Boolean} insertProxy True to insert a placeholder proxy element while dragging the panel,
  823.      * false to drag with no proxy (defaults to true).
  824.      */
  825.     insertProxy : true,
  826.     // private overrides
  827.     setStatus : Ext.emptyFn,
  828.     reset : Ext.emptyFn,
  829.     update : Ext.emptyFn,
  830.     stop : Ext.emptyFn,
  831.     sync: Ext.emptyFn,
  832.     /**
  833.      * Gets the proxy's element
  834.      * @return {Element} The proxy's element
  835.      */
  836.     getEl : function(){
  837.         return this.ghost;
  838.     },
  839.     /**
  840.      * Gets the proxy's ghost element
  841.      * @return {Element} The proxy's ghost element
  842.      */
  843.     getGhost : function(){
  844.         return this.ghost;
  845.     },
  846.     /**
  847.      * Gets the proxy's element
  848.      * @return {Element} The proxy's element
  849.      */
  850.     getProxy : function(){
  851.         return this.proxy;
  852.     },
  853.     /**
  854.      * Hides the proxy
  855.      */
  856.     hide : function(){
  857.         if(this.ghost){
  858.             if(this.proxy){
  859.                 this.proxy.remove();
  860.                 delete this.proxy;
  861.             }
  862.             this.panel.el.dom.style.display = '';
  863.             this.ghost.remove();
  864.             delete this.ghost;
  865.         }
  866.     },
  867.     /**
  868.      * Shows the proxy
  869.      */
  870.     show : function(){
  871.         if(!this.ghost){
  872.             this.ghost = this.panel.createGhost(undefined, undefined, Ext.getBody());
  873.             this.ghost.setXY(this.panel.el.getXY())
  874.             if(this.insertProxy){
  875.                 this.proxy = this.panel.el.insertSibling({cls:'x-panel-dd-spacer'});
  876.                 this.proxy.setSize(this.panel.getSize());
  877.             }
  878.             this.panel.el.dom.style.display = 'none';
  879.         }
  880.     },
  881.     // private
  882.     repair : function(xy, callback, scope){
  883.         this.hide();
  884.         if(typeof callback == "function"){
  885.             callback.call(scope || this);
  886.         }
  887.     },
  888.     /**
  889.      * Moves the proxy to a different position in the DOM.  This is typically called while dragging the Panel
  890.      * to keep the proxy sync'd to the Panel's location.
  891.      * @param {HTMLElement} parentNode The proxy's parent DOM node
  892.      * @param {HTMLElement} before (optional) The sibling node before which the proxy should be inserted (defaults
  893.      * to the parent's last child if not specified)
  894.      */
  895.     moveProxy : function(parentNode, before){
  896.         if(this.proxy){
  897.             parentNode.insertBefore(this.proxy.dom, before);
  898.         }
  899.     }
  900. };
  901. // private - DD implementation for Panels
  902. Ext.Panel.DD = function(panel, cfg){
  903.     this.panel = panel;
  904.     this.dragData = {panel: panel};
  905.     this.proxy = new Ext.dd.PanelProxy(panel, cfg);
  906.     Ext.Panel.DD.superclass.constructor.call(this, panel.el, cfg);
  907.     var h = panel.header;
  908.     if(h){
  909.         this.setHandleElId(h.id);
  910.     }
  911.     (h ? h : this.panel.body).setStyle('cursor', 'move');
  912.     this.scroll = false;
  913. };
  914. Ext.extend(Ext.Panel.DD, Ext.dd.DragSource, {
  915.     showFrame: Ext.emptyFn,
  916.     startDrag: Ext.emptyFn,
  917.     b4StartDrag: function(x, y) {
  918.         this.proxy.show();
  919.     },
  920.     b4MouseDown: function(e) {
  921.         var x = e.getPageX();
  922.         var y = e.getPageY();
  923.         this.autoOffset(x, y);
  924.     },
  925.     onInitDrag : function(x, y){
  926.         this.onStartDrag(x, y);
  927.         return true;
  928.     },
  929.     createFrame : Ext.emptyFn,
  930.     getDragEl : function(e){
  931.         return this.proxy.ghost.dom;
  932.     },
  933.     endDrag : function(e){
  934.         this.proxy.hide();
  935.         this.panel.saveState();
  936.     },
  937.     autoOffset : function(x, y) {
  938.         x -= this.startPageX;
  939.         y -= this.startPageY;
  940.         this.setDelta(x, y);
  941.     }
  942. });/**  * @class Ext.state.Provider  * Abstract base class for state provider implementations. This class provides methods  * for encoding and decoding <b>typed</b> variables including dates and defines the  * Provider interface.  */ Ext.state.Provider = function(){     /**      * @event statechange      * Fires when a state change occurs.      * @param {Provider} this This state provider      * @param {String} key The state key which was changed      * @param {String} value The encoded value for the state      */     this.addEvents("statechange");     this.state = {};     Ext.state.Provider.superclass.constructor.call(this); }; Ext.extend(Ext.state.Provider, Ext.util.Observable, {     /**      * Returns the current value for a key      * @param {String} name The key name      * @param {Mixed} defaultValue A default value to return if the key's value is not found      * @return {Mixed} The state data      */     get : function(name, defaultValue){         return typeof this.state[name] == "undefined" ?             defaultValue : this.state[name];     },     /**      * Clears a value from the state      * @param {String} name The key name      */     clear : function(name){         delete this.state[name];         this.fireEvent("statechange", this, name, null);     },     /**      * Sets the value for a key      * @param {String} name The key name      * @param {Mixed} value The value to set      */     set : function(name, value){         this.state[name] = value;         this.fireEvent("statechange", this, name, value);     },     /**      * Decodes a string previously encoded with {@link #encodeValue}.      * @param {String} value The value to decode      * @return {Mixed} The decoded value      */     decodeValue : function(cookie){         var re = /^(a|n|d|b|s|o):(.*)$/;         var matches = re.exec(unescape(cookie));         if(!matches || !matches[1]) return; // non state cookie         var type = matches[1];         var v = matches[2];         switch(type){             case "n":                 return parseFloat(v);             case "d":                 return new Date(Date.parse(v));             case "b":                 return (v == "1");             case "a":                 var all = [];                 var values = v.split("^");                 for(var i = 0, len = values.length; i < len; i++){                     all.push(this.decodeValue(values[i]));                 }                 return all;            case "o":                 var all = {};                 var values = v.split("^");                 for(var i = 0, len = values.length; i < len; i++){                     var kv = values[i].split("=");                     all[kv[0]] = this.decodeValue(kv[1]);                 }                 return all;            default:                 return v;         }     },     /**      * Encodes a value including type information.  Decode with {@link #decodeValue}.      * @param {Mixed} value The value to encode      * @return {String} The encoded value      */     encodeValue : function(v){         var enc;         if(typeof v == "number"){             enc = "n:" + v;         }else if(typeof v == "boolean"){             enc = "b:" + (v ? "1" : "0");         }else if(Ext.isDate(v)){             enc = "d:" + v.toGMTString();         }else if(Ext.isArray(v)){             var flat = "";             for(var i = 0, len = v.length; i < len; i++){                 flat += this.encodeValue(v[i]);                 if(i != len-1) flat += "^";             }             enc = "a:" + flat;         }else if(typeof v == "object"){             var flat = "";             for(var key in v){                 if(typeof v[key] != "function" && v[key] !== undefined){                     flat += key + "=" + this.encodeValue(v[key]) + "^";                 }             }             enc = "o:" + flat.substring(0, flat.length-1);         }else{             enc = "s:" + v;         }         return escape(enc);     } }); /**
  943.  * @class Ext.state.Manager
  944.  * This is the global state manager. By default all components that are "state aware" check this class
  945.  * for state information if you don't pass them a custom state provider. In order for this class
  946.  * to be useful, it must be initialized with a provider when your application initializes. Example usage:
  947.  <pre><code>
  948. // in your initialization function
  949. init : function(){
  950.    Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
  951.    var win = new Window(...);
  952.    win.restoreState();
  953. }
  954.  </code></pre>
  955.  * @singleton
  956.  */
  957. Ext.state.Manager = function(){
  958.     var provider = new Ext.state.Provider();
  959.     return {
  960.         /**
  961.          * Configures the default state provider for your application
  962.          * @param {Provider} stateProvider The state provider to set
  963.          */
  964.         setProvider : function(stateProvider){
  965.             provider = stateProvider;
  966.         },
  967.         /**
  968.          * Returns the current value for a key
  969.          * @param {String} name The key name
  970.          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
  971.          * @return {Mixed} The state data
  972.          */
  973.         get : function(key, defaultValue){
  974.             return provider.get(key, defaultValue);
  975.         },
  976.         /**
  977.          * Sets the value for a key
  978.          * @param {String} name The key name
  979.          * @param {Mixed} value The state data
  980.          */
  981.          set : function(key, value){
  982.             provider.set(key, value);
  983.         },
  984.         /**
  985.          * Clears a value from the state
  986.          * @param {String} name The key name
  987.          */
  988.         clear : function(key){
  989.             provider.clear(key);
  990.         },
  991.         /**
  992.          * Gets the currently configured state provider
  993.          * @return {Provider} The state provider
  994.          */
  995.         getProvider : function(){
  996.             return provider;
  997.         }
  998.     };
  999. }();
  1000. /**
  1001.  * @class Ext.state.CookieProvider
  1002.  * @extends Ext.state.Provider
  1003.  * The default Provider implementation which saves state via cookies.
  1004.  * <br />Usage:
  1005.  <pre><code>
  1006.    var cp = new Ext.state.CookieProvider({
  1007.        path: "/cgi-bin/",
  1008.        expires: new Date(new Date().getTime()+(1000*60*60*24*30)), //30 days
  1009.        domain: "extjs.com"
  1010.    });
  1011.    Ext.state.Manager.setProvider(cp);
  1012.  </code></pre>
  1013.  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
  1014.  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
  1015.  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
  1016.  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'extjs.com' to include
  1017.  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
  1018.  * domain the page is running on including the 'www' like 'www.extjs.com')
  1019.  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
  1020.  * @constructor
  1021.  * Create a new CookieProvider
  1022.  * @param {Object} config The configuration object
  1023.  */
  1024. Ext.state.CookieProvider = function(config){
  1025.     Ext.state.CookieProvider.superclass.constructor.call(this);
  1026.     this.path = "/";
  1027.     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
  1028.     this.domain = null;
  1029.     this.secure = false;
  1030.     Ext.apply(this, config);
  1031.     this.state = this.readCookies();
  1032. };
  1033. Ext.extend(Ext.state.CookieProvider, Ext.state.Provider, {
  1034.     // private
  1035.     set : function(name, value){
  1036.         if(typeof value == "undefined" || value === null){
  1037.             this.clear(name);
  1038.             return;
  1039.         }
  1040.         this.setCookie(name, value);
  1041.         Ext.state.CookieProvider.superclass.set.call(this, name, value);
  1042.     },
  1043.     // private
  1044.     clear : function(name){
  1045.         this.clearCookie(name);
  1046.         Ext.state.CookieProvider.superclass.clear.call(this, name);
  1047.     },
  1048.     // private
  1049.     readCookies : function(){
  1050.         var cookies = {};
  1051.         var c = document.cookie + ";";
  1052.         var re = /s?(.*?)=(.*?);/g;
  1053.      var matches;
  1054.      while((matches = re.exec(c)) != null){
  1055.             var name = matches[1];
  1056.             var value = matches[2];
  1057.             if(name && name.substring(0,3) == "ys-"){
  1058.                 cookies[name.substr(3)] = this.decodeValue(value);
  1059.             }
  1060.         }
  1061.         return cookies;
  1062.     },
  1063.     // private
  1064.     setCookie : function(name, value){
  1065.         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
  1066.            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
  1067.            ((this.path == null) ? "" : ("; path=" + this.path)) +
  1068.            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
  1069.            ((this.secure == true) ? "; secure" : "");
  1070.     },
  1071.     // private
  1072.     clearCookie : function(name){
  1073.         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
  1074.            ((this.path == null) ? "" : ("; path=" + this.path)) +
  1075.            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
  1076.            ((this.secure == true) ? "; secure" : "");
  1077.     }
  1078. });/**  * @class Ext.DataView  * @extends Ext.BoxComponent  * A mechanism for displaying data using custom layout templates and formatting. DataView uses an {@link Ext.XTemplate}  * as its internal templating mechanism, and is bound to an {@link Ext.data.Store}  * so that as the data in the store changes the view is automatically updated to reflect the changes.  The view also  * provides built-in behavior for many common events that can occur for its contained items including click, doubleclick,  * mouseover, mouseout, etc. as well as a built-in selection model. <b>In order to use these features, an {@link #itemSelector}  * config must be provided for the DataView to determine what nodes it will be working with.</b>  *  * <p>The example below binds a DataView to a {@link Ext.data.Store} and renders it into an {@link Ext.Panel}.</p>  * <pre><code> var store = new Ext.data.JsonStore({     url: 'get-images.php',     root: 'images',     fields: [         'name', 'url',         {name:'size', type: 'float'},         {name:'lastmod', type:'date', dateFormat:'timestamp'}     ] }); store.load(); var tpl = new Ext.XTemplate(     '&lt;tpl for="."&gt;',         '&lt;div class="thumb-wrap" id="{name}"&gt;',         '&lt;div class="thumb"&gt;&lt;img src="{url}" title="{name}"&gt;&lt;/div&gt;',         '&lt;span class="x-editable"&gt;{shortName}&lt;/span&gt;&lt;/div&gt;',     '&lt;/tpl&gt;',     '&lt;div class="x-clear"&gt;&lt;/div&gt;' ); var panel = new Ext.Panel({     id:'images-view',     frame:true,     width:535,     autoHeight:true,     collapsible:true,     layout:'fit',     title:'Simple DataView',     items: new Ext.DataView({         store: store,         tpl: tpl,         autoHeight:true,         multiSelect: true,         overClass:'x-view-over',         itemSelector:'div.thumb-wrap',         emptyText: 'No images to display'     }) }); panel.render(document.body); </code></pre>  * @constructor  * Create a new DataView  * @param {Object} config The config object  * @xtype dataview  */ Ext.DataView = Ext.extend(Ext.BoxComponent, {     /**      * @cfg {String/Array} tpl      * The HTML fragment or an array of fragments that will make up the template used by this DataView.  This should      * be specified in the same format expected by the constructor of {@link Ext.XTemplate}.      */     /**      * @cfg {Ext.data.Store} store      * The {@link Ext.data.Store} to bind this DataView to.      */     /**      * @cfg {String} itemSelector      * <b>This is a required setting</b>. A simple CSS selector (e.g. <tt>div.some-class</tt> or       * <tt>span:first-child</tt>) that will be used to determine what nodes this DataView will be      * working with.      */     /**      * @cfg {Boolean} multiSelect      * True to allow selection of more than one item at a time, false to allow selection of only a single item      * at a time or no selection at all, depending on the value of {@link #singleSelect} (defaults to false).      */     /**      * @cfg {Boolean} singleSelect      * True to allow selection of exactly one item at a time, false to allow no selection at all (defaults to false).      * Note that if {@link #multiSelect} = true, this value will be ignored.      */     /**      * @cfg {Boolean} simpleSelect      * True to enable multiselection by clicking on multiple items without requiring the user to hold Shift or Ctrl,      * false to force the user to hold Ctrl or Shift to select more than on item (defaults to false).      */     /**      * @cfg {String} overClass      * A CSS class to apply to each item in the view on mouseover (defaults to undefined).      */     /**      * @cfg {String} loadingText      * A string to display during data load operations (defaults to undefined).  If specified, this text will be      * displayed in a loading div and the view's contents will be cleared while loading, otherwise the view's      * contents will continue to display normally until the new data is loaded and the contents are replaced.      */     /**      * @cfg {String} selectedClass      * A CSS class to apply to each selected item in the view (defaults to 'x-view-selected').      */     selectedClass : "x-view-selected",     /**      * @cfg {String} emptyText      * The text to display in the view when there is no data to display (defaults to '').      */     emptyText : "",     /**      * @cfg {Boolean} deferEmptyText True to defer emptyText being applied until the store's first load      */     deferEmptyText: true,     /**      * @cfg {Boolean} trackOver True to enable mouseenter and mouseleave events      */     trackOver: false,     //private     last: false,     // private     initComponent : function(){         Ext.DataView.superclass.initComponent.call(this);         if(Ext.isString(this.tpl) || Ext.isArray(this.tpl)){             this.tpl = new Ext.XTemplate(this.tpl);         }         this.addEvents(             /**              * @event beforeclick              * Fires before a click is processed. Returns false to cancel the default action.              * @param {Ext.DataView} this              * @param {Number} index The index of the target node              * @param {HTMLElement} node The target node              * @param {Ext.EventObject} e The raw event object              */             "beforeclick",             /**              * @event click              * Fires when a template node is clicked.              * @param {Ext.DataView} this              * @param {Number} index The index of the target node              * @param {HTMLElement} node The target node              * @param {Ext.EventObject} e The raw event object              */             "click",             /**              * @event mouseenter              * Fires when the mouse enters a template node. trackOver:true or an overCls must be set to enable this event.              * @param {Ext.DataView} this              * @param {Number} index The index of the target node              * @param {HTMLElement} node The target node              * @param {Ext.EventObject} e The raw event object              */             "mouseenter",             /**              * @event mouseleave              * Fires when the mouse leaves a template node. trackOver:true or an overCls must be set to enable this event.              * @param {Ext.DataView} this              * @param {Number} index The index of the target node              * @param {HTMLElement} node The target node              * @param {Ext.EventObject} e The raw event object              */             "mouseleave",             /**              * @event containerclick              * Fires when a click occurs and it is not on a template node.              * @param {Ext.DataView} this              * @param {Ext.EventObject} e The raw event object              */             "containerclick",             /**              * @event dblclick              * Fires when a template node is double clicked.              * @param {Ext.DataView} this              * @param {Number} index The index of the target node              * @param {HTMLElement} node The target node              * @param {Ext.EventObject} e The raw event object              */             "dblclick",             /**              * @event contextmenu              * Fires when a template node is right clicked.              * @param {Ext.DataView} this              * @param {Number} index The index of the target node              * @param {HTMLElement} node The target node              * @param {Ext.EventObject} e The raw event object              */             "contextmenu",             /**              * @event containercontextmenu              * Fires when a right click occurs that is not on a template node.              * @param {Ext.DataView} this              * @param {Ext.EventObject} e The raw event object              */             "containercontextmenu",             /**              * @event selectionchange              * Fires when the selected nodes change.              * @param {Ext.DataView} this              * @param {Array} selections Array of the selected nodes              */             "selectionchange",             /**              * @event beforeselect              * Fires before a selection is made. If any handlers return false, the selection is cancelled.              * @param {Ext.DataView} this              * @param {HTMLElement} node The node to be selected              * @param {Array} selections Array of currently selected nodes              */             "beforeselect"         );         this.store = Ext.StoreMgr.lookup(this.store);         this.all = new Ext.CompositeElementLite();         this.selected = new Ext.CompositeElementLite();     },     // private     afterRender : function(){         Ext.DataView.superclass.afterRender.call(this); this.mon(this.getTemplateTarget(), {             "click": this.onClick,             "dblclick": this.onDblClick,             "contextmenu": this.onContextMenu,             scope:this         });         if(this.overClass || this.trackOver){             this.mon(this.getTemplateTarget(), {                 "mouseover": this.onMouseOver,                 "mouseout": this.onMouseOut,                 scope:this             });         }         if(this.store){             this.bindStore(this.store, true);         }     },     /**      * Refreshes the view by reloading the data from the store and re-rendering the template.      */     refresh : function(){         this.clearSelections(false, true);         var el = this.getTemplateTarget();         el.update("");         var records = this.store.getRange();         if(records.length < 1){             if(!this.deferEmptyText || this.hasSkippedEmptyText){                 el.update(this.emptyText);             }             this.all.clear();         }else{             this.tpl.overwrite(el, this.collectData(records, 0));             this.all.fill(Ext.query(this.itemSelector, el.dom));             this.updateIndexes(0);         }         this.hasSkippedEmptyText = true;     },     getTemplateTarget: function(){         return this.el;     },     /**      * Function which can be overridden to provide custom formatting for each Record that is used by this      * DataView's {@link #tpl template} to render each node.      * @param {Array/Object} data The raw data object that was used to create the Record.      * @param {Number} recordIndex the index number of the Record being prepared for rendering.      * @param {Record} record The Record being prepared for rendering.      * @return {Array/Object} The formatted data in a format expected by the internal {@link #tpl template}'s overwrite() method.      * (either an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'}))      */     prepareData : function(data){         return data;     },     /**      * <p>Function which can be overridden which returns the data object passed to this      * DataView's {@link #tpl template} to render the whole DataView.</p>      * <p>This is usually an Array of data objects, each element of which is processed by an      * {@link Ext.XTemplate XTemplate} which uses <tt>'&lt;tpl for="."&gt;'</tt> to iterate over its supplied      * data object as an Array. However, <i>named</i> properties may be placed into the data object to      * provide non-repeating data such as headings, totals etc.</p>      * @param {Array} records An Array of {@link Ext.data.Record}s to be rendered into the DataView.      * @param {Number} startIndex the index number of the Record being prepared for rendering.      * @return {Array} An Array of data objects to be processed by a repeating XTemplate. May also      * contain <i>named</i> properties.      */     collectData : function(records, startIndex){         var r = [];         for(var i = 0, len = records.length; i < len; i++){             r[r.length] = this.prepareData(records[i].data, startIndex+i, records[i]);         }         return r;     },     // private     bufferRender : function(records){         var div = document.createElement('div');         this.tpl.overwrite(div, this.collectData(records));         return Ext.query(this.itemSelector, div);     },     // private     onUpdate : function(ds, record){         var index = this.store.indexOf(record);         var sel = this.isSelected(index);         var original = this.all.elements[index];         var node = this.bufferRender([record], index)[0];         this.all.replaceElement(index, node, true);         if(sel){             this.selected.replaceElement(original, node);             this.all.item(index).addClass(this.selectedClass);         }         this.updateIndexes(index, index);     },     // private     onAdd : function(ds, records, index){         if(this.all.getCount() === 0){             this.refresh();             return;         }         var nodes = this.bufferRender(records, index), n, a = this.all.elements;         if(index < this.all.getCount()){             n = this.all.item(index).insertSibling(nodes, 'before', true);             a.splice.apply(a, [index, 0].concat(nodes));         }else{             n = this.all.last().insertSibling(nodes, 'after', true);             a.push.apply(a, nodes);         }         this.updateIndexes(index);     },     // private     onRemove : function(ds, record, index){         this.deselect(index);         this.all.removeElement(index, true);         this.updateIndexes(index);         if (this.store.getCount() === 0){             this.refresh();         }     },     /**      * Refreshes an individual node's data from the store.      * @param {Number} index The item's data index in the store      */     refreshNode : function(index){         this.onUpdate(this.store, this.store.getAt(index));     },     // private     updateIndexes : function(startIndex, endIndex){         var ns = this.all.elements;         startIndex = startIndex || 0;         endIndex = endIndex || ((endIndex === 0) ? 0 : (ns.length - 1));         for(var i = startIndex; i <= endIndex; i++){             ns[i].viewIndex = i;         }     },          /**      * Returns the store associated with this DataView.      * @return {Ext.data.Store} The store      */     getStore : function(){         return this.store;     },     /**      * Changes the data store bound to this view and refreshes it.      * @param {Store} store The store to bind to this view      */     bindStore : function(store, initial){         if(!initial && this.store){             this.store.un("beforeload", this.onBeforeLoad, this);             this.store.un("datachanged", this.refresh, this);             this.store.un("add", this.onAdd, this);             this.store.un("remove", this.onRemove, this);             this.store.un("update", this.onUpdate, this);             this.store.un("clear", this.refresh, this);             if(store !== this.store && this.store.autoDestroy){                 this.store.destroy();             }         }         if(store){             store = Ext.StoreMgr.lookup(store);             store.on({                 scope: this,                 beforeload: this.onBeforeLoad,                 datachanged: this.refresh,                 add: this.onAdd,                 remove: this.onRemove,                 update: this.onUpdate,                 clear: this.refresh             });         }         this.store = store;         if(store){             this.refresh();         }     },     /**      * Returns the template node the passed child belongs to, or null if it doesn't belong to one.      * @param {HTMLElement} node      * @return {HTMLElement} The template node      */     findItemFromChild : function(node){         return Ext.fly(node).findParent(this.itemSelector, this.getTemplateTarget());     },     // private     onClick : function(e){         var item = e.getTarget(this.itemSelector, this.getTemplateTarget());         if(item){             var index = this.indexOf(item);             if(this.onItemClick(item, index, e) !== false){                 this.fireEvent("click", this, index, item, e);             }         }else{             if(this.fireEvent("containerclick", this, e) !== false){                 this.onContainerClick(e);             }         }     },     onContainerClick : function(e){         this.clearSelections();     },     // private     onContextMenu : function(e){         var item = e.getTarget(this.itemSelector, this.getTemplateTarget());         if(item){             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);         }else{             this.fireEvent("containercontextmenu", this, e);         }     },     // private     onDblClick : function(e){         var item = e.getTarget(this.itemSelector, this.getTemplateTarget());         if(item){             this.fireEvent("dblclick", this, this.indexOf(item), item, e);         }     },     // private     onMouseOver : function(e){         var item = e.getTarget(this.itemSelector, this.getTemplateTarget());         if(item && item !== this.lastItem){             this.lastItem = item;             Ext.fly(item).addClass(this.overClass);             this.fireEvent("mouseenter", this, this.indexOf(item), item, e);         }     },     // private     onMouseOut : function(e){         if(this.lastItem){             if(!e.within(this.lastItem, true, true)){                 Ext.fly(this.lastItem).removeClass(this.overClass);                 this.fireEvent("mouseleave", this, this.indexOf(this.lastItem), this.lastItem, e);                 delete this.lastItem;             }         }     },     // private     onItemClick : function(item, index, e){         if(this.fireEvent("beforeclick", this, index, item, e) === false){             return false;         }         if(this.multiSelect){             this.doMultiSelection(item, index, e);             e.preventDefault();         }else if(this.singleSelect){             this.doSingleSelection(item, index, e);             e.preventDefault();         }         return true;     },     // private     doSingleSelection : function(item, index, e){         if(e.ctrlKey && this.isSelected(index)){             this.deselect(index);         }else{             this.select(index, false);         }     },     // private     doMultiSelection : function(item, index, e){         if(e.shiftKey && this.last !== false){             var last = this.last;             this.selectRange(last, index, e.ctrlKey);             this.last = last; // reset the last         }else{             if((e.ctrlKey||this.simpleSelect) && this.isSelected(index)){                 this.deselect(index);             }else{                 this.select(index, e.ctrlKey || e.shiftKey || this.simpleSelect);             }         }     },     /**      * Gets the number of selected nodes.      * @return {Number} The node count      */     getSelectionCount : function(){         return this.selected.getCount();     },     /**      * Gets the currently selected nodes.      * @return {Array} An array of HTMLElements      */     getSelectedNodes : function(){         return this.selected.elements;     },     /**      * Gets the indexes of the selected nodes.      * @return {Array} An array of numeric indexes      */     getSelectedIndexes : function(){         var indexes = [], s = this.selected.elements;         for(var i = 0, len = s.length; i < len; i++){             indexes.push(s[i].viewIndex);         }         return indexes;     },     /**      * Gets an array of the selected records      * @return {Array} An array of {@link Ext.data.Record} objects      */     getSelectedRecords : function(){         var r = [], s = this.selected.elements;         for(var i = 0, len = s.length; i < len; i++){             r[r.length] = this.store.getAt(s[i].viewIndex);         }         return r;     },     /**      * Gets an array of the records from an array of nodes      * @param {Array} nodes The nodes to evaluate      * @return {Array} records The {@link Ext.data.Record} objects      */     getRecords : function(nodes){         var r = [], s = nodes;         for(var i = 0, len = s.length; i < len; i++){             r[r.length] = this.store.getAt(s[i].viewIndex);         }         return r;     },     /**      * Gets a record from a node      * @param {HTMLElement} node The node to evaluate      * @return {Record} record The {@link Ext.data.Record} object      */     getRecord : function(node){         return this.store.getAt(node.viewIndex);     },     /**      * Clears all selections.      * @param {Boolean} suppressEvent (optional) True to skip firing of the selectionchange event      */     clearSelections : function(suppressEvent, skipUpdate){         if((this.multiSelect || this.singleSelect) && this.selected.getCount() > 0){             if(!skipUpdate){                 this.selected.removeClass(this.selectedClass);             }             this.selected.clear();             this.last = false;             if(!suppressEvent){                 this.fireEvent("selectionchange", this, this.selected.elements);             }         }     },     /**      * Returns true if the passed node is selected, else false.      * @param {HTMLElement/Number} node The node or node index to check      * @return {Boolean} True if selected, else false      */     isSelected : function(node){         return this.selected.contains(this.getNode(node));     },     /**      * Deselects a node.      * @param {HTMLElement/Number} node The node to deselect      */     deselect : function(node){         if(this.isSelected(node)){             node = this.getNode(node);             this.selected.removeElement(node);             if(this.last == node.viewIndex){                 this.last = false;             }             Ext.fly(node).removeClass(this.selectedClass);             this.fireEvent("selectionchange", this, this.selected.elements);         }     },     /**      * Selects a set of nodes.      * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node,      * id of a template node or an array of any of those to select      * @param {Boolean} keepExisting (optional) true to keep existing selections      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent      */     select : function(nodeInfo, keepExisting, suppressEvent){         if(Ext.isArray(nodeInfo)){             if(!keepExisting){                 this.clearSelections(true);             }             for(var i = 0, len = nodeInfo.length; i < len; i++){                 this.select(nodeInfo[i], true, true);             }             if(!suppressEvent){                 this.fireEvent("selectionchange", this, this.selected.elements);             }         } else{             var node = this.getNode(nodeInfo);             if(!keepExisting){                 this.clearSelections(true);             }             if(node && !this.isSelected(node)){                 if(this.fireEvent("beforeselect", this, node, this.selected.elements) !== false){                     Ext.fly(node).addClass(this.selectedClass);                     this.selected.add(node);                     this.last = node.viewIndex;                     if(!suppressEvent){                         this.fireEvent("selectionchange", this, this.selected.elements);                     }                 }             }         }     },     /**      * Selects a range of nodes. All nodes between start and end are selected.      * @param {Number} start The index of the first node in the range      * @param {Number} end The index of the last node in the range      * @param {Boolean} keepExisting (optional) True to retain existing selections      */     selectRange : function(start, end, keepExisting){         if(!keepExisting){             this.clearSelections(true);         }         this.select(this.getNodes(start, end), true);     },     /**      * Gets a template node.      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node      * @return {HTMLElement} The node or null if it wasn't found      */     getNode : function(nodeInfo){         if(Ext.isString(nodeInfo)){             return document.getElementById(nodeInfo);         }else if(Ext.isNumber(nodeInfo)){             return this.all.elements[nodeInfo];         }         return nodeInfo;     },     /**      * Gets a range nodes.      * @param {Number} start (optional) The index of the first node in the range      * @param {Number} end (optional) The index of the last node in the range      * @return {Array} An array of nodes      */     getNodes : function(start, end){         var ns = this.all.elements;         start = start || 0;         end = !Ext.isDefined(end) ? Math.max(ns.length - 1, 0) : end;         var nodes = [], i;         if(start <= end){             for(i = start; i <= end && ns[i]; i++){                 nodes.push(ns[i]);             }         } else{             for(i = start; i >= end && ns[i]; i--){                 nodes.push(ns[i]);             }         }         return nodes;     },     /**      * Finds the index of the passed node.      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node      * @return {Number} The index of the node or -1      */     indexOf : function(node){         node = this.getNode(node);         if(Ext.isNumber(node.viewIndex)){             return node.viewIndex;         }         return this.all.indexOf(node);     },     // private     onBeforeLoad : function(){         if(this.loadingText){             this.clearSelections(false, true);             this.getTemplateTarget().update('<div class="loading-indicator">'+this.loadingText+'</div>');             this.all.clear();         }     },     onDestroy : function(){         Ext.DataView.superclass.onDestroy.call(this);         this.bindStore(null);     } }); /**  * Changes the data store bound to this view and refreshes it. (deprecated in favor of bindStore)  * @param {Store} store The store to bind to this view  */ Ext.DataView.prototype.setStore = Ext.DataView.prototype.bindStore; Ext.reg('dataview', Ext.DataView);/**
  1079.  * @class Ext.ListView
  1080.  * @extends Ext.DataView
  1081.  * <p>Ext.ListView is a fast and light-weight implentation of a
  1082.  * {@link Ext.grid.GridPanel Grid} like view with the following characteristics:</p>
  1083.  * <div class="mdetail-params"><ul>
  1084.  * <li>resizable columns</li>
  1085.  * <li>selectable</li>
  1086.  * <li>column widths are initially proportioned by percentage based on the container
  1087.  * width and number of columns</li>
  1088.  * <li>uses templates to render the data in any required format</li>
  1089.  * <li>no horizontal scrolling</li>
  1090.  * <li>no editing</li>
  1091.  * </ul></div>
  1092.  * <p>Example usage:</p>
  1093.  * <pre><code>
  1094. // consume JSON of this form:
  1095. {
  1096.    "images":[
  1097.       {
  1098.          "name":"dance_fever.jpg",
  1099.          "size":2067,
  1100.          "lastmod":1236974993000,
  1101.          "url":"images/thumbs/dance_fever.jpg"
  1102.       },
  1103.       {
  1104.          "name":"zack_sink.jpg",
  1105.          "size":2303,
  1106.          "lastmod":1236974993000,
  1107.          "url":"images/thumbs/zack_sink.jpg"
  1108.       }
  1109.    ]
  1110. var store = new Ext.data.JsonStore({
  1111.     url: 'get-images.php',
  1112.     root: 'images',
  1113.     fields: [
  1114.         'name', 'url',
  1115.         {name:'size', type: 'float'},
  1116.         {name:'lastmod', type:'date', dateFormat:'timestamp'}
  1117.     ]
  1118. });
  1119. store.load();
  1120. var listView = new Ext.ListView({
  1121.     store: store,
  1122.     multiSelect: true,
  1123.     emptyText: 'No images to display',
  1124.     reserveScrollOffset: true,
  1125.     columns: [{
  1126.         header: 'File',
  1127.         width: .5,
  1128.         dataIndex: 'name'
  1129.     },{
  1130.         header: 'Last Modified',
  1131.         width: .35, 
  1132.         dataIndex: 'lastmod',
  1133.         tpl: '{lastmod:date("m-d h:i a")}'
  1134.     },{
  1135.         header: 'Size',
  1136.         dataIndex: 'size',
  1137.         tpl: '{size:fileSize}', // format using Ext.util.Format.fileSize()
  1138.         align: 'right'
  1139.     }]
  1140. });
  1141. // put it in a Panel so it looks pretty
  1142. var panel = new Ext.Panel({
  1143.     id:'images-view',
  1144.     width:425,
  1145.     height:250,
  1146.     collapsible:true,
  1147.     layout:'fit',
  1148.     title:'Simple ListView <i>(0 items selected)</i>',
  1149.     items: listView
  1150. });
  1151. panel.render(document.body);
  1152. // little bit of feedback
  1153. listView.on('selectionchange', function(view, nodes){
  1154.     var l = nodes.length;
  1155.     var s = l != 1 ? 's' : '';
  1156.     panel.setTitle('Simple ListView <i>('+l+' item'+s+' selected)</i>');
  1157. });
  1158.  * </code></pre>
  1159.  * @constructor
  1160.  * @param {Object} config
  1161.  * @xtype listview
  1162.  */
  1163. Ext.ListView = Ext.extend(Ext.DataView, {
  1164.     /**
  1165.      * Set this property to <tt>true</tt> to disable the header click handler disabling sort
  1166.      * (defaults to <tt>false</tt>).
  1167.      * @type Boolean
  1168.      * @property disableHeaders
  1169.      */
  1170.     /**
  1171.      * @cfg {Boolean} hideHeaders
  1172.      * <tt>true</tt> to hide the {@link #internalTpl header row} (defaults to <tt>false</tt> so
  1173.      * the {@link #internalTpl header row} will be shown).
  1174.      */
  1175.     /**
  1176.      * @cfg {String} itemSelector
  1177.      * Defaults to <tt>'dl'</tt> to work with the preconfigured <b><tt>{@link Ext.DataView#tpl tpl}</tt></b>.
  1178.      * This setting specifies the CSS selector (e.g. <tt>div.some-class</tt> or <tt>span:first-child</tt>)
  1179.      * that will be used to determine what nodes the ListView will be working with.   
  1180.      */
  1181.     itemSelector: 'dl',
  1182.     /**
  1183.      * @cfg {String} selectedClass The CSS class applied to a selected row (defaults to
  1184.      * <tt>'x-list-selected'</tt>). An example overriding the default styling:
  1185.     <pre><code>
  1186.     .x-list-selected {background-color: yellow;}
  1187.     </code></pre>
  1188.      * @type String
  1189.      */
  1190.     selectedClass:'x-list-selected',
  1191.     /**
  1192.      * @cfg {String} overClass The CSS class applied when over a row (defaults to
  1193.      * <tt>'x-list-over'</tt>). An example overriding the default styling:
  1194.     <pre><code>
  1195.     .x-list-over {background-color: orange;}
  1196.     </code></pre>
  1197.      * @type String
  1198.      */
  1199.     overClass:'x-list-over',
  1200.     /**
  1201.      * @cfg {Boolean} reserveScrollOffset
  1202.      * By default will defer accounting for the configured <b><tt>{@link #scrollOffset}</tt></b>
  1203.      * for 10 milliseconds.  Specify <tt>true</tt> to account for the configured
  1204.      * <b><tt>{@link #scrollOffset}</tt></b> immediately.
  1205.      */
  1206.     /**
  1207.      * @cfg {Number} scrollOffset The amount of space to reserve for the scrollbar (defaults to
  1208.      * <tt>19</tt> pixels)
  1209.      */
  1210.     scrollOffset : 19,
  1211.     /**
  1212.      * @cfg {Boolean/Object} columnResize
  1213.      * Specify <tt>true</tt> or specify a configuration object for {@link Ext.ListView.ColumnResizer}
  1214.      * to enable the columns to be resizable (defaults to <tt>true</tt>).
  1215.      */
  1216.     columnResize: true,
  1217.     /**
  1218.      * @cfg {Array} columns An array of column configuration objects, for example:
  1219.      * <pre><code>
  1220. {
  1221.     align: 'right',
  1222.     dataIndex: 'size',
  1223.     header: 'Size',
  1224.     tpl: '{size:fileSize}',
  1225.     width: .35
  1226. }
  1227.      * </code></pre> 
  1228.      * Acceptable properties for each column configuration object are:
  1229.      * <div class="mdetail-params"><ul>
  1230.      * <li><b><tt>align</tt></b> : String<div class="sub-desc">Set the CSS text-align property
  1231.      * of the column. Defaults to <tt>'left'</tt>.</div></li>
  1232.      * <li><b><tt>dataIndex</tt></b> : String<div class="sub-desc">See {@link Ext.grid.Column}.
  1233.      * {@link Ext.grid.Column#dataIndex dataIndex} for details.</div></li>
  1234.      * <li><b><tt>header</tt></b> : String<div class="sub-desc">See {@link Ext.grid.Column}.
  1235.      * {@link Ext.grid.Column#header header} for details.</div></li>
  1236.      * <li><b><tt>tpl</tt></b> : String<div class="sub-desc">Specify a string to pass as the
  1237.      * configuration string for {@link Ext.XTemplate}.  By default an {@link Ext.XTemplate}
  1238.      * will be implicitly created using the <tt>dataIndex</tt>.</div></li>
  1239.      * <li><b><tt>width</tt></b> : Number<div class="sub-desc">Percentage of the container width
  1240.      * this column should be allocated.  Columns that have no width specified will be
  1241.      * allocated with an equal percentage to fill 100% of the container width.  To easily take
  1242.      * advantage of the full container width, leave the width of at least one column undefined.
  1243.      * Note that if you do not want to take up the full width of the container, the width of
  1244.      * every column needs to be explicitly defined.</div></li>
  1245.      * </ul></div>
  1246.      */
  1247.     /**
  1248.      * @cfg {Boolean/Object} columnSort
  1249.      * Specify <tt>true</tt> or specify a configuration object for {@link Ext.ListView.Sorter}
  1250.      * to enable the columns to be sortable (defaults to <tt>true</tt>).
  1251.      */
  1252.     columnSort: true,
  1253.     /**
  1254.      * @cfg {String/Array} internalTpl
  1255.      * The template to be used for the header row.  See {@link #tpl} for more details.
  1256.      */
  1257.     initComponent : function(){
  1258.         if(this.columnResize){
  1259.             this.colResizer = new Ext.ListView.ColumnResizer(this.colResizer);
  1260.             this.colResizer.init(this);
  1261.         }
  1262.         if(this.columnSort){
  1263.             this.colSorter = new Ext.ListView.Sorter(this.columnSort);
  1264.             this.colSorter.init(this);
  1265.         }
  1266.         if(!this.internalTpl){
  1267.             this.internalTpl = new Ext.XTemplate(
  1268.                 '<div class="x-list-header"><div class="x-list-header-inner">',
  1269.                     '<tpl for="columns">',
  1270.                     '<div style="width:{width}%;text-align:{align};"><em unselectable="on" id="',this.id, '-xlhd-{#}">',
  1271.                         '{header}',
  1272.                     '</em></div>',
  1273.                     '</tpl>',
  1274.                     '<div class="x-clear"></div>',
  1275.                 '</div></div>',
  1276.                 '<div class="x-list-body"><div class="x-list-body-inner">',
  1277.                 '</div></div>'
  1278.             );
  1279.         }
  1280.         if(!this.tpl){
  1281.             this.tpl = new Ext.XTemplate(
  1282.                 '<tpl for="rows">',
  1283.                     '<dl>',
  1284.                         '<tpl for="parent.columns">',
  1285.                         '<dt style="width:{width}%;text-align:{align};"><em unselectable="on">',
  1286.                             '{[values.tpl.apply(parent)]}',
  1287.                         '</em></dt>',
  1288.                         '</tpl>',
  1289.                         '<div class="x-clear"></div>',
  1290.                     '</dl>',
  1291.                 '</tpl>'
  1292.             );
  1293.         };
  1294.         var cs = this.columns, allocatedWidth = 0, colsWithWidth = 0, len = cs.length;
  1295.         for(var i = 0; i < len; i++){
  1296.             var c = cs[i];
  1297.             if(!c.tpl){
  1298.                 c.tpl = new Ext.XTemplate('{' + c.dataIndex + '}');
  1299.             }else if(Ext.isString(c.tpl)){
  1300.                 c.tpl = new Ext.XTemplate(c.tpl);
  1301.             }
  1302.             c.align = c.align || 'left';
  1303.             if(Ext.isNumber(c.width)){
  1304.                 c.width *= 100;
  1305.                 allocatedWidth += c.width;
  1306.                 colsWithWidth++;
  1307.             }
  1308.         }
  1309.         // auto calculate missing column widths
  1310.         if(colsWithWidth < len){
  1311.             var remaining = len - colsWithWidth;
  1312.             if(allocatedWidth < 100){
  1313.                 var perCol = ((100-allocatedWidth) / remaining);
  1314.                 for(var j = 0; j < len; j++){
  1315.                     var c = cs[j];
  1316.                     if(!Ext.isNumber(c.width)){
  1317.                         c.width = perCol;
  1318.                     }
  1319.                 }
  1320.             }
  1321.         }
  1322.         Ext.ListView.superclass.initComponent.call(this);
  1323.     },
  1324.     onRender : function(){
  1325.         Ext.ListView.superclass.onRender.apply(this, arguments);
  1326.         this.internalTpl.overwrite(this.el, {columns: this.columns});
  1327.         
  1328.         this.innerBody = Ext.get(this.el.dom.childNodes[1].firstChild);
  1329.         this.innerHd = Ext.get(this.el.dom.firstChild.firstChild);
  1330.         if(this.hideHeaders){
  1331.             this.el.dom.firstChild.style.display = 'none';
  1332.         }
  1333.     },
  1334.     getTemplateTarget : function(){
  1335.         return this.innerBody;
  1336.     },
  1337.     /**
  1338.      * <p>Function which can be overridden which returns the data object passed to this
  1339.      * view's {@link #tpl template} to render the whole ListView. The returned object 
  1340.      * shall contain the following properties:</p>
  1341.      * <div class="mdetail-params"><ul>
  1342.      * <li><b>columns</b> : String<div class="sub-desc">See <tt>{@link #columns}</tt></div></li>
  1343.      * <li><b>rows</b> : String<div class="sub-desc">See
  1344.      * <tt>{@link Ext.DataView}.{@link Ext.DataView#collectData collectData}</div></li>
  1345.      * </ul></div>
  1346.      * @param {Array} records An Array of {@link Ext.data.Record}s to be rendered into the DataView.
  1347.      * @param {Number} startIndex the index number of the Record being prepared for rendering.
  1348.      * @return {Object} A data object containing properties to be processed by a repeating
  1349.      * XTemplate as described above.
  1350.      */
  1351.     collectData : function(){
  1352.         var rs = Ext.ListView.superclass.collectData.apply(this, arguments);
  1353.         return {
  1354.             columns: this.columns,
  1355.             rows: rs
  1356.         }
  1357.     },
  1358.     verifyInternalSize : function(){
  1359.         if(this.lastSize){
  1360.             this.onResize(this.lastSize.width, this.lastSize.height);
  1361.         }
  1362.     },
  1363.     // private
  1364.     onResize : function(w, h){
  1365.         var bd = this.innerBody.dom;
  1366.         var hd = this.innerHd.dom
  1367.         if(!bd){
  1368.             return;
  1369.         }
  1370.         var bdp = bd.parentNode;
  1371.         if(Ext.isNumber(w)){
  1372.             var sw = w - this.scrollOffset;
  1373.             if(this.reserveScrollOffset || ((bdp.offsetWidth - bdp.clientWidth) > 10)){
  1374.                 bd.style.width = sw + 'px';
  1375.                 hd.style.width = sw + 'px';
  1376.             }else{
  1377.                 bd.style.width = w + 'px';
  1378.                 hd.style.width = w + 'px';
  1379.                 setTimeout(function(){
  1380.                     if((bdp.offsetWidth - bdp.clientWidth) > 10){
  1381.                         bd.style.width = sw + 'px';
  1382.                         hd.style.width = sw + 'px';
  1383.                     }
  1384.                 }, 10);
  1385.             }
  1386.         }
  1387.         if(Ext.isNumber(h == 'number')){
  1388.             bdp.style.height = (h - hd.parentNode.offsetHeight) + 'px';
  1389.         }
  1390.     },
  1391.     updateIndexes : function(){
  1392.         Ext.ListView.superclass.updateIndexes.apply(this, arguments);
  1393.         this.verifyInternalSize();
  1394.     },
  1395.     findHeaderIndex : function(hd){
  1396.         hd = hd.dom || hd;
  1397.         var pn = hd.parentNode, cs = pn.parentNode.childNodes;
  1398.         for(var i = 0, c; c = cs[i]; i++){
  1399.             if(c == pn){
  1400.                 return i;
  1401.             }
  1402.         }
  1403.         return -1;
  1404.     },
  1405.     setHdWidths : function(){
  1406.         var els = this.innerHd.dom.getElementsByTagName('div');
  1407.         for(var i = 0, cs = this.columns, len = cs.length; i < len; i++){
  1408.             els[i].style.width = cs[i].width + '%';
  1409.         }
  1410.     }
  1411. });
  1412. Ext.reg('listview', Ext.ListView);/**
  1413.  * @class Ext.ListView.ColumnResizer
  1414.  * @extends Ext.util.Observable
  1415.  * <p>Supporting Class for Ext.ListView.</p>
  1416.  * @constructor
  1417.  * @param {Object} config
  1418.  */
  1419. Ext.ListView.ColumnResizer = Ext.extend(Ext.util.Observable, {
  1420.     /**
  1421.      * @cfg {Number} minPct The minimum percentage to allot for any column (defaults to <tt>.05</tt>)
  1422.      */
  1423.     minPct: .05,
  1424.     constructor: function(config){
  1425.         Ext.apply(this, config);
  1426.         Ext.ListView.ColumnResizer.superclass.constructor.call(this);
  1427.     },
  1428.     init : function(listView){
  1429.         this.view = listView;
  1430.         listView.on('render', this.initEvents, this);
  1431.     },
  1432.     initEvents : function(view){
  1433.         view.mon(view.innerHd, 'mousemove', this.handleHdMove, this);
  1434.         this.tracker = new Ext.dd.DragTracker({
  1435.             onBeforeStart: this.onBeforeStart.createDelegate(this),
  1436.             onStart: this.onStart.createDelegate(this),
  1437.             onDrag: this.onDrag.createDelegate(this),
  1438.             onEnd: this.onEnd.createDelegate(this),
  1439.             tolerance: 3,
  1440.             autoStart: 300
  1441.         });
  1442.         this.tracker.initEl(view.innerHd);
  1443.         view.on('beforedestroy', this.tracker.destroy, this.tracker);
  1444.     },
  1445.     handleHdMove : function(e, t){
  1446.         var hw = 5;
  1447.         var x = e.getPageX();
  1448.         var hd = e.getTarget('em', 3, true);
  1449.         if(hd){
  1450.             var r = hd.getRegion();
  1451.             var ss = hd.dom.style;
  1452.             var pn = hd.dom.parentNode;
  1453.             if(x - r.left <= hw && pn != pn.parentNode.firstChild){
  1454.                 this.activeHd = Ext.get(pn.previousSibling.firstChild);
  1455. ss.cursor = Ext.isWebKit ? 'e-resize' : 'col-resize';
  1456.             } else if(r.right - x <= hw && pn != pn.parentNode.lastChild.previousSibling){
  1457.                 this.activeHd = hd;
  1458. ss.cursor = Ext.isWebKit ? 'w-resize' : 'col-resize';
  1459.             } else{
  1460.                 delete this.activeHd;
  1461.                 ss.cursor = '';
  1462.             }
  1463.         }
  1464.     },
  1465.     onBeforeStart : function(e){
  1466.         this.dragHd = this.activeHd;
  1467.         return !!this.dragHd;
  1468.     },
  1469.     onStart: function(e){
  1470.         this.view.disableHeaders = true;
  1471.         this.proxy = this.view.el.createChild({cls:'x-list-resizer'});
  1472.         this.proxy.setHeight(this.view.el.getHeight());
  1473.         var x = this.tracker.getXY()[0];
  1474.         var w = this.view.innerHd.getWidth();
  1475.         this.hdX = this.dragHd.getX();
  1476.         this.hdIndex = this.view.findHeaderIndex(this.dragHd);
  1477.         this.proxy.setX(this.hdX);
  1478.         this.proxy.setWidth(x-this.hdX);
  1479.         this.minWidth = w*this.minPct;
  1480.         this.maxWidth = w - (this.minWidth*(this.view.columns.length-1-this.hdIndex));
  1481.     },
  1482.     onDrag: function(e){
  1483.         var cursorX = this.tracker.getXY()[0];
  1484.         this.proxy.setWidth((cursorX-this.hdX).constrain(this.minWidth, this.maxWidth));
  1485.     },
  1486.     onEnd: function(e){
  1487.         var nw = this.proxy.getWidth();
  1488.         this.proxy.remove();
  1489.         var index = this.hdIndex;
  1490.         var vw = this.view, cs = vw.columns, len = cs.length;
  1491.         var w = this.view.innerHd.getWidth(), minPct = this.minPct * 100;
  1492.         var pct = Math.ceil((nw*100) / w);
  1493.         var diff = cs[index].width - pct;
  1494.         var each = Math.floor(diff / (len-1-index));
  1495.         var mod = diff - (each * (len-1-index));
  1496.         for(var i = index+1; i < len; i++){
  1497.             var cw = cs[i].width + each;
  1498.             var ncw = Math.max(minPct, cw);
  1499.             if(cw != ncw){
  1500.                 mod += cw - ncw;
  1501.             }
  1502.             cs[i].width = ncw;
  1503.         }
  1504.         cs[index].width = pct;
  1505.         cs[index+1].width += mod;
  1506.         delete this.dragHd;
  1507.         this.view.setHdWidths();
  1508.         this.view.refresh();
  1509.         setTimeout(function(){
  1510.             vw.disableHeaders = false;
  1511.         }, 100);
  1512.     }
  1513. });/**
  1514.  * @class Ext.ListView.Sorter
  1515.  * @extends Ext.util.Observable
  1516.  * <p>Supporting Class for Ext.ListView.</p>
  1517.  * @constructor
  1518.  * @param {Object} config
  1519.  */
  1520. Ext.ListView.Sorter = Ext.extend(Ext.util.Observable, {
  1521.     /**
  1522.      * @cfg {Array} sortClasses
  1523.      * The CSS classes applied to a header when it is sorted. (defaults to <tt>["sort-asc", "sort-desc"]</tt>)
  1524.      */
  1525.     sortClasses : ["sort-asc", "sort-desc"],
  1526.     constructor: function(config){
  1527.         Ext.apply(this, config);
  1528.         Ext.ListView.Sorter.superclass.constructor.call(this);
  1529.     },
  1530.     init : function(listView){
  1531.         this.view = listView;
  1532.         listView.on('render', this.initEvents, this);
  1533.     },
  1534.     initEvents : function(view){
  1535.         view.mon(view.innerHd, 'click', this.onHdClick, this);
  1536.         view.innerHd.setStyle('cursor', 'pointer');
  1537.         view.mon(view.store, 'datachanged', this.updateSortState, this);
  1538.         this.updateSortState.defer(10, this, [view.store]);
  1539.     },
  1540.     updateSortState : function(store){
  1541.         var state = store.getSortState();
  1542.         if(!state){
  1543.             return;
  1544.         }
  1545.         this.sortState = state;
  1546.         var cs = this.view.columns, sortColumn = -1;
  1547.         for(var i = 0, len = cs.length; i < len; i++){
  1548.             if(cs[i].dataIndex == state.field){
  1549.                 sortColumn = i;
  1550.                 break;
  1551.             }
  1552.         }
  1553.         if(sortColumn != -1){
  1554.             var sortDir = state.direction;