Upgrade to ExtJS 3.0.3 - Released 10/11/2009
[extjs.git] / pkgs / window-debug.js
1 /*!
2  * Ext JS Library 3.0.3
3  * Copyright(c) 2006-2009 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * @class Ext.Window
9  * @extends Ext.Panel
10  * <p>A specialized panel intended for use as an application window.  Windows are floated, {@link #resizable}, and
11  * {@link #draggable} by default.  Windows can be {@link #maximizable maximized} to fill the viewport,
12  * restored to their prior size, and can be {@link #minimize}d.</p>
13  * <p>Windows can also be linked to a {@link Ext.WindowGroup} or managed by the {@link Ext.WindowMgr} to provide
14  * grouping, activation, to front, to back and other application-specific behavior.</p>
15  * <p>By default, Windows will be rendered to document.body. To {@link #constrain} a Window to another element
16  * specify {@link Ext.Component#renderTo renderTo}.</p>
17  * <p><b>Note:</b> By default, the <code>{@link #closable close}</code> header tool <i>destroys</i> the Window resulting in
18  * destruction of any child Components. This makes the Window object, and all its descendants <b>unusable</b>. To enable
19  * re-use of a Window, use <b><code>{@link #closeAction closeAction: 'hide'}</code></b>.</p>
20  * @constructor
21  * @param {Object} config The config object
22  * @xtype window
23  */
24 Ext.Window = Ext.extend(Ext.Panel, {
25     /**
26      * @cfg {Number} x
27      * The X position of the left edge of the window on initial showing. Defaults to centering the Window within
28      * the width of the Window's container {@link Ext.Element Element) (The Element that the Window is rendered to).
29      */
30     /**
31      * @cfg {Number} y
32      * The Y position of the top edge of the window on initial showing. Defaults to centering the Window within
33      * the height of the Window's container {@link Ext.Element Element) (The Element that the Window is rendered to).
34      */
35     /**
36      * @cfg {Boolean} modal
37      * True to make the window modal and mask everything behind it when displayed, false to display it without
38      * restricting access to other UI elements (defaults to false).
39      */
40     /**
41      * @cfg {String/Element} animateTarget
42      * Id or element from which the window should animate while opening (defaults to null with no animation).
43      */
44     /**
45      * @cfg {String} resizeHandles
46      * A valid {@link Ext.Resizable} handles config string (defaults to 'all').  Only applies when resizable = true.
47      */
48     /**
49      * @cfg {Ext.WindowGroup} manager
50      * A reference to the WindowGroup that should manage this window (defaults to {@link Ext.WindowMgr}).
51      */
52     /**
53     * @cfg {String/Number/Button} defaultButton
54     * The id / index of a button or a button instance to focus when this window received the focus.
55     */
56     /**
57     * @cfg {Function} onEsc
58     * Allows override of the built-in processing for the escape key. Default action
59     * is to close the Window (performing whatever action is specified in {@link #closeAction}.
60     * To prevent the Window closing when the escape key is pressed, specify this as
61     * Ext.emptyFn (See {@link Ext#emptyFn}).
62     */
63     /**
64      * @cfg {Boolean} collapsed
65      * True to render the window collapsed, false to render it expanded (defaults to false). Note that if
66      * {@link #expandOnShow} is true (the default) it will override the <tt>collapsed</tt> config and the window
67      * will always be expanded when shown.
68      */
69     /**
70      * @cfg {Boolean} maximized
71      * True to initially display the window in a maximized state. (Defaults to false).
72      */
73
74     /**
75     * @cfg {String} baseCls
76     * The base CSS class to apply to this panel's element (defaults to 'x-window').
77     */
78     baseCls : 'x-window',
79     /**
80      * @cfg {Boolean} resizable
81      * True to allow user resizing at each edge and corner of the window, false to disable resizing (defaults to true).
82      */
83     resizable : true,
84     /**
85      * @cfg {Boolean} draggable
86      * True to allow the window to be dragged by the header bar, false to disable dragging (defaults to true).  Note
87      * that by default the window will be centered in the viewport, so if dragging is disabled the window may need
88      * to be positioned programmatically after render (e.g., myWindow.setPosition(100, 100);).
89      */
90     draggable : true,
91     /**
92      * @cfg {Boolean} closable
93      * <p>True to display the 'close' tool button and allow the user to close the window, false to
94      * hide the button and disallow closing the window (defaults to true).</p>
95      * <p>By default, when close is requested by either clicking the close button in the header
96      * or pressing ESC when the Window has focus, the {@link #close} method will be called. This
97      * will <i>{@link Ext.Component#destroy destroy}</i> the Window and its content meaning that
98      * it may not be reused.</p>
99      * <p>To make closing a Window <i>hide</i> the Window so that it may be reused, set
100      * {@link #closeAction} to 'hide'.
101      */
102     closable : true,
103     /**
104      * @cfg {String} closeAction
105      * <p>The action to take when the close header tool is clicked:
106      * <div class="mdetail-params"><ul>
107      * <li><b><code>'{@link #close}'</code></b> : <b>Default</b><div class="sub-desc">
108      * {@link #close remove} the window from the DOM and {@link Ext.Component#destroy destroy}
109      * it and all descendant Components. The window will <b>not</b> be available to be
110      * redisplayed via the {@link #show} method.
111      * </div></li>
112      * <li><b><code>'{@link #hide}'</code></b> : <div class="sub-desc">
113      * {@link #hide} the window by setting visibility to hidden and applying negative offsets.
114      * The window will be available to be redisplayed via the {@link #show} method.
115      * </div></li>
116      * </ul></div>
117      * <p><b>Note:</b> This setting does not affect the {@link #close} method
118      * which will always {@link Ext.Component#destroy destroy} the window. To
119      * programatically <i>hide</i> a window, call {@link #hide}.</p>
120      */
121     closeAction : 'close',
122     /**
123      * @cfg {Boolean} constrain
124      * True to constrain the window within its containing element, false to allow it to fall outside of its
125      * containing element. By default the window will be rendered to document.body.  To render and constrain the
126      * window within another element specify {@link #renderTo}.
127      * (defaults to false).  Optionally the header only can be constrained using {@link #constrainHeader}.
128      */
129     constrain : false,
130     /**
131      * @cfg {Boolean} constrainHeader
132      * True to constrain the window header within its containing element (allowing the window body to fall outside
133      * of its containing element) or false to allow the header to fall outside its containing element (defaults to
134      * false). Optionally the entire window can be constrained using {@link #constrain}.
135      */
136     constrainHeader : false,
137     /**
138      * @cfg {Boolean} plain
139      * True to render the window body with a transparent background so that it will blend into the framing
140      * elements, false to add a lighter background color to visually highlight the body element and separate it
141      * more distinctly from the surrounding frame (defaults to false).
142      */
143     plain : false,
144     /**
145      * @cfg {Boolean} minimizable
146      * True to display the 'minimize' tool button and allow the user to minimize the window, false to hide the button
147      * and disallow minimizing the window (defaults to false).  Note that this button provides no implementation --
148      * the behavior of minimizing a window is implementation-specific, so the minimize event must be handled and a
149      * custom minimize behavior implemented for this option to be useful.
150      */
151     minimizable : false,
152     /**
153      * @cfg {Boolean} maximizable
154      * True to display the 'maximize' tool button and allow the user to maximize the window, false to hide the button
155      * and disallow maximizing the window (defaults to false).  Note that when a window is maximized, the tool button
156      * will automatically change to a 'restore' button with the appropriate behavior already built-in that will
157      * restore the window to its previous size.
158      */
159     maximizable : false,
160     /**
161      * @cfg {Number} minHeight
162      * The minimum height in pixels allowed for this window (defaults to 100).  Only applies when resizable = true.
163      */
164     minHeight : 100,
165     /**
166      * @cfg {Number} minWidth
167      * The minimum width in pixels allowed for this window (defaults to 200).  Only applies when resizable = true.
168      */
169     minWidth : 200,
170     /**
171      * @cfg {Boolean} expandOnShow
172      * True to always expand the window when it is displayed, false to keep it in its current state (which may be
173      * {@link #collapsed}) when displayed (defaults to true).
174      */
175     expandOnShow : true,
176
177     // inherited docs, same default
178     collapsible : false,
179
180     /**
181      * @cfg {Boolean} initHidden
182      * True to hide the window until show() is explicitly called (defaults to true).
183      * @deprecated
184      */
185     initHidden : undefined,
186     
187     /**
188      * @cfg {Boolean} hidden
189      * Render this component hidden (default is <tt>true</tt>). If <tt>true</tt>, the
190      * {@link #hide} method will be called internally.
191      */
192     hidden : true,
193     
194     /**
195     * @cfg {Boolean} monitorResize @hide
196     * This is automatically managed based on the value of constrain and constrainToHeader
197     */
198     monitorResize : true,
199
200     // The following configs are set to provide the basic functionality of a window.
201     // Changing them would require additional code to handle correctly and should
202     // usually only be done in subclasses that can provide custom behavior.  Changing them
203     // may have unexpected or undesirable results.
204     /** @cfg {String} elements @hide */
205     elements : 'header,body',
206     /** @cfg {Boolean} frame @hide */
207     frame : true,
208     /** @cfg {Boolean} floating @hide */
209     floating : true,
210
211     // private
212     initComponent : function(){
213         this.initTools();
214         Ext.Window.superclass.initComponent.call(this);
215         this.addEvents(
216             /**
217              * @event activate
218              * Fires after the window has been visually activated via {@link #setActive}.
219              * @param {Ext.Window} this
220              */
221             /**
222              * @event deactivate
223              * Fires after the window has been visually deactivated via {@link #setActive}.
224              * @param {Ext.Window} this
225              */
226             /**
227              * @event resize
228              * Fires after the window has been resized.
229              * @param {Ext.Window} this
230              * @param {Number} width The window's new width
231              * @param {Number} height The window's new height
232              */
233             'resize',
234             /**
235              * @event maximize
236              * Fires after the window has been maximized.
237              * @param {Ext.Window} this
238              */
239             'maximize',
240             /**
241              * @event minimize
242              * Fires after the window has been minimized.
243              * @param {Ext.Window} this
244              */
245             'minimize',
246             /**
247              * @event restore
248              * Fires after the window has been restored to its original size after being maximized.
249              * @param {Ext.Window} this
250              */
251             'restore'
252         );
253         // for backwards compat, this should be removed at some point
254         if(Ext.isDefined(this.initHidden)){
255             this.hidden = this.initHidden;
256         }
257         if(this.hidden === false){
258             this.hidden = true;
259             this.show();
260         }
261     },
262
263     // private
264     getState : function(){
265         return Ext.apply(Ext.Window.superclass.getState.call(this) || {}, this.getBox(true));
266     },
267
268     // private
269     onRender : function(ct, position){
270         Ext.Window.superclass.onRender.call(this, ct, position);
271
272         if(this.plain){
273             this.el.addClass('x-window-plain');
274         }
275
276         // this element allows the Window to be focused for keyboard events
277         this.focusEl = this.el.createChild({
278                     tag: 'a', href:'#', cls:'x-dlg-focus',
279                     tabIndex:'-1', html: '&#160;'});
280         this.focusEl.swallowEvent('click', true);
281
282         this.proxy = this.el.createProxy('x-window-proxy');
283         this.proxy.enableDisplayMode('block');
284
285         if(this.modal){
286             this.mask = this.container.createChild({cls:'ext-el-mask'}, this.el.dom);
287             this.mask.enableDisplayMode('block');
288             this.mask.hide();
289             this.mon(this.mask, 'click', this.focus, this);
290         }
291         if(this.maximizable){
292             this.mon(this.header, 'dblclick', this.toggleMaximize, this);
293         }
294     },
295
296     // private
297     initEvents : function(){
298         Ext.Window.superclass.initEvents.call(this);
299         if(this.animateTarget){
300             this.setAnimateTarget(this.animateTarget);
301         }
302
303         if(this.resizable){
304             this.resizer = new Ext.Resizable(this.el, {
305                 minWidth: this.minWidth,
306                 minHeight:this.minHeight,
307                 handles: this.resizeHandles || 'all',
308                 pinned: true,
309                 resizeElement : this.resizerAction
310             });
311             this.resizer.window = this;
312             this.mon(this.resizer, 'beforeresize', this.beforeResize, this);
313         }
314
315         if(this.draggable){
316             this.header.addClass('x-window-draggable');
317         }
318         this.mon(this.el, 'mousedown', this.toFront, this);
319         this.manager = this.manager || Ext.WindowMgr;
320         this.manager.register(this);
321         if(this.maximized){
322             this.maximized = false;
323             this.maximize();
324         }
325         if(this.closable){
326             var km = this.getKeyMap();
327             km.on(27, this.onEsc, this);
328             km.disable();
329         }
330     },
331
332     initDraggable : function(){
333         /**
334          * If this Window is configured {@link #draggable}, this property will contain
335          * an instance of {@link Ext.dd.DD} which handles dragging the Window's DOM Element.
336          * @type Ext.dd.DD
337          * @property dd
338          */
339         this.dd = new Ext.Window.DD(this);
340     },
341
342    // private
343     onEsc : function(){
344         this[this.closeAction]();
345     },
346
347     // private
348     beforeDestroy : function(){
349         if (this.rendered){
350             this.hide();
351           if(this.doAnchor){
352                 Ext.EventManager.removeResizeListener(this.doAnchor, this);
353               Ext.EventManager.un(window, 'scroll', this.doAnchor, this);
354             }
355             Ext.destroy(
356                 this.focusEl,
357                 this.resizer,
358                 this.dd,
359                 this.proxy,
360                 this.mask
361             );
362         }
363         Ext.Window.superclass.beforeDestroy.call(this);
364     },
365
366     // private
367     onDestroy : function(){
368         if(this.manager){
369             this.manager.unregister(this);
370         }
371         Ext.Window.superclass.onDestroy.call(this);
372     },
373
374     // private
375     initTools : function(){
376         if(this.minimizable){
377             this.addTool({
378                 id: 'minimize',
379                 handler: this.minimize.createDelegate(this, [])
380             });
381         }
382         if(this.maximizable){
383             this.addTool({
384                 id: 'maximize',
385                 handler: this.maximize.createDelegate(this, [])
386             });
387             this.addTool({
388                 id: 'restore',
389                 handler: this.restore.createDelegate(this, []),
390                 hidden:true
391             });
392         }
393         if(this.closable){
394             this.addTool({
395                 id: 'close',
396                 handler: this[this.closeAction].createDelegate(this, [])
397             });
398         }
399     },
400
401     // private
402     resizerAction : function(){
403         var box = this.proxy.getBox();
404         this.proxy.hide();
405         this.window.handleResize(box);
406         return box;
407     },
408
409     // private
410     beforeResize : function(){
411         this.resizer.minHeight = Math.max(this.minHeight, this.getFrameHeight() + 40); // 40 is a magic minimum content size?
412         this.resizer.minWidth = Math.max(this.minWidth, this.getFrameWidth() + 40);
413         this.resizeBox = this.el.getBox();
414     },
415
416     // private
417     updateHandles : function(){
418         if(Ext.isIE && this.resizer){
419             this.resizer.syncHandleHeight();
420             this.el.repaint();
421         }
422     },
423
424     // private
425     handleResize : function(box){
426         var rz = this.resizeBox;
427         if(rz.x != box.x || rz.y != box.y){
428             this.updateBox(box);
429         }else{
430             this.setSize(box);
431         }
432         this.focus();
433         this.updateHandles();
434         this.saveState();
435         this.doLayout();
436     },
437
438     /**
439      * Focuses the window.  If a defaultButton is set, it will receive focus, otherwise the
440      * window itself will receive focus.
441      */
442     focus : function(){
443         var f = this.focusEl, db = this.defaultButton, t = typeof db;
444         if(Ext.isDefined(db)){
445             if(Ext.isNumber(db) && this.fbar){
446                 f = this.fbar.items.get(db);
447             }else if(Ext.isString(db)){
448                 f = Ext.getCmp(db);
449             }else{
450                 f = db;
451             }
452         }
453         f = f || this.focusEl;
454         f.focus.defer(10, f);
455     },
456
457     /**
458      * Sets the target element from which the window should animate while opening.
459      * @param {String/Element} el The target element or id
460      */
461     setAnimateTarget : function(el){
462         el = Ext.get(el);
463         this.animateTarget = el;
464     },
465
466     // private
467     beforeShow : function(){
468         delete this.el.lastXY;
469         delete this.el.lastLT;
470         if(this.x === undefined || this.y === undefined){
471             var xy = this.el.getAlignToXY(this.container, 'c-c');
472             var pos = this.el.translatePoints(xy[0], xy[1]);
473             this.x = this.x === undefined? pos.left : this.x;
474             this.y = this.y === undefined? pos.top : this.y;
475         }
476         this.el.setLeftTop(this.x, this.y);
477
478         if(this.expandOnShow){
479             this.expand(false);
480         }
481
482         if(this.modal){
483             Ext.getBody().addClass('x-body-masked');
484             this.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
485             this.mask.show();
486         }
487     },
488
489     /**
490      * Shows the window, rendering it first if necessary, or activates it and brings it to front if hidden.
491      * @param {String/Element} animateTarget (optional) The target element or id from which the window should
492      * animate while opening (defaults to null with no animation)
493      * @param {Function} callback (optional) A callback function to call after the window is displayed
494      * @param {Object} scope (optional) The scope in which to execute the callback
495      * @return {Ext.Window} this
496      */
497     show : function(animateTarget, cb, scope){
498         if(!this.rendered){
499             this.render(Ext.getBody());
500         }
501         if(this.hidden === false){
502             this.toFront();
503             return this;
504         }
505         if(this.fireEvent('beforeshow', this) === false){
506             return this;
507         }
508         if(cb){
509             this.on('show', cb, scope, {single:true});
510         }
511         this.hidden = false;
512         if(Ext.isDefined(animateTarget)){
513             this.setAnimateTarget(animateTarget);
514         }
515         this.beforeShow();
516         if(this.animateTarget){
517             this.animShow();
518         }else{
519             this.afterShow();
520         }
521         return this;
522     },
523
524     // private
525     afterShow : function(isAnim){
526         this.proxy.hide();
527         this.el.setStyle('display', 'block');
528         this.el.show();
529         if(this.maximized){
530             this.fitContainer();
531         }
532         if(Ext.isMac && Ext.isGecko){ // work around stupid FF 2.0/Mac scroll bar bug
533             this.cascade(this.setAutoScroll);
534         }
535
536         if(this.monitorResize || this.modal || this.constrain || this.constrainHeader){
537             Ext.EventManager.onWindowResize(this.onWindowResize, this);
538         }
539         this.doConstrain();
540         this.doLayout();
541         if(this.keyMap){
542             this.keyMap.enable();
543         }
544         this.toFront();
545         this.updateHandles();
546         if(isAnim && (Ext.isIE || Ext.isWebKit)){
547             var sz = this.getSize();
548             this.onResize(sz.width, sz.height);
549         }
550         this.fireEvent('show', this);
551     },
552
553     // private
554     animShow : function(){
555         this.proxy.show();
556         this.proxy.setBox(this.animateTarget.getBox());
557         this.proxy.setOpacity(0);
558         var b = this.getBox();
559         this.el.setStyle('display', 'none');
560         this.proxy.shift(Ext.apply(b, {
561             callback: this.afterShow.createDelegate(this, [true], false),
562             scope: this,
563             easing: 'easeNone',
564             duration: 0.25,
565             opacity: 0.5
566         }));
567     },
568
569     /**
570      * Hides the window, setting it to invisible and applying negative offsets.
571      * @param {String/Element} animateTarget (optional) The target element or id to which the window should
572      * animate while hiding (defaults to null with no animation)
573      * @param {Function} callback (optional) A callback function to call after the window is hidden
574      * @param {Object} scope (optional) The scope in which to execute the callback
575      * @return {Ext.Window} this
576      */
577     hide : function(animateTarget, cb, scope){
578         if(this.hidden || this.fireEvent('beforehide', this) === false){
579             return this;
580         }
581         if(cb){
582             this.on('hide', cb, scope, {single:true});
583         }
584         this.hidden = true;
585         if(animateTarget !== undefined){
586             this.setAnimateTarget(animateTarget);
587         }
588         if(this.modal){
589             this.mask.hide();
590             Ext.getBody().removeClass('x-body-masked');
591         }
592         if(this.animateTarget){
593             this.animHide();
594         }else{
595             this.el.hide();
596             this.afterHide();
597         }
598         return this;
599     },
600
601     // private
602     afterHide : function(){
603         this.proxy.hide();
604         if(this.monitorResize || this.modal || this.constrain || this.constrainHeader){
605             Ext.EventManager.removeResizeListener(this.onWindowResize, this);
606         }
607         if(this.keyMap){
608             this.keyMap.disable();
609         }
610         this.fireEvent('hide', this);
611     },
612
613     // private
614     animHide : function(){
615         this.proxy.setOpacity(0.5);
616         this.proxy.show();
617         var tb = this.getBox(false);
618         this.proxy.setBox(tb);
619         this.el.hide();
620         this.proxy.shift(Ext.apply(this.animateTarget.getBox(), {
621             callback: this.afterHide,
622             scope: this,
623             duration: 0.25,
624             easing: 'easeNone',
625             opacity: 0
626         }));
627     },
628
629     // private
630     onWindowResize : function(){
631         if(this.maximized){
632             this.fitContainer();
633         }
634         if(this.modal){
635             this.mask.setSize('100%', '100%');
636             var force = this.mask.dom.offsetHeight;
637             this.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
638         }
639         this.doConstrain();
640     },
641
642     // private
643     doConstrain : function(){
644         if(this.constrain || this.constrainHeader){
645             var offsets;
646             if(this.constrain){
647                 offsets = {
648                     right:this.el.shadowOffset,
649                     left:this.el.shadowOffset,
650                     bottom:this.el.shadowOffset
651                 };
652             }else {
653                 var s = this.getSize();
654                 offsets = {
655                     right:-(s.width - 100),
656                     bottom:-(s.height - 25)
657                 };
658             }
659
660             var xy = this.el.getConstrainToXY(this.container, true, offsets);
661             if(xy){
662                 this.setPosition(xy[0], xy[1]);
663             }
664         }
665     },
666
667     // private - used for dragging
668     ghost : function(cls){
669         var ghost = this.createGhost(cls);
670         var box = this.getBox(true);
671         ghost.setLeftTop(box.x, box.y);
672         ghost.setWidth(box.width);
673         this.el.hide();
674         this.activeGhost = ghost;
675         return ghost;
676     },
677
678     // private
679     unghost : function(show, matchPosition){
680         if(!this.activeGhost) {
681             return;
682         }
683         if(show !== false){
684             this.el.show();
685             this.focus();
686             if(Ext.isMac && Ext.isGecko){ // work around stupid FF 2.0/Mac scroll bar bug
687                 this.cascade(this.setAutoScroll);
688             }
689         }
690         if(matchPosition !== false){
691             this.setPosition(this.activeGhost.getLeft(true), this.activeGhost.getTop(true));
692         }
693         this.activeGhost.hide();
694         this.activeGhost.remove();
695         delete this.activeGhost;
696     },
697
698     /**
699      * Placeholder method for minimizing the window.  By default, this method simply fires the {@link #minimize} event
700      * since the behavior of minimizing a window is application-specific.  To implement custom minimize behavior,
701      * either the minimize event can be handled or this method can be overridden.
702      * @return {Ext.Window} this
703      */
704     minimize : function(){
705         this.fireEvent('minimize', this);
706         return this;
707     },
708
709     /**
710      * <p>Closes the Window, removes it from the DOM, {@link Ext.Component#destroy destroy}s
711      * the Window object and all its descendant Components. The {@link Ext.Panel#beforeclose beforeclose}
712      * event is fired before the close happens and will cancel the close action if it returns false.<p>
713      * <p><b>Note:</b> This method is not affected by the {@link #closeAction} setting which
714      * only affects the action triggered when clicking the {@link #closable 'close' tool in the header}.
715      * To hide the Window without destroying it, call {@link #hide}.</p>
716      */
717     close : function(){
718         if(this.fireEvent('beforeclose', this) !== false){
719             if(this.hidden){
720                 this.doClose();
721             }else{
722                 this.hide(null, this.doClose, this);
723             }
724         }
725     },
726     
727     // private
728     doClose : function(){
729         this.fireEvent('close', this);
730         this.destroy();
731     },
732
733     /**
734      * Fits the window within its current container and automatically replaces
735      * the {@link #maximizable 'maximize' tool button} with the 'restore' tool button.
736      * Also see {@link #toggleMaximize}.
737      * @return {Ext.Window} this
738      */
739     maximize : function(){
740         if(!this.maximized){
741             this.expand(false);
742             this.restoreSize = this.getSize();
743             this.restorePos = this.getPosition(true);
744             if (this.maximizable){
745                 this.tools.maximize.hide();
746                 this.tools.restore.show();
747             }
748             this.maximized = true;
749             this.el.disableShadow();
750
751             if(this.dd){
752                 this.dd.lock();
753             }
754             if(this.collapsible){
755                 this.tools.toggle.hide();
756             }
757             this.el.addClass('x-window-maximized');
758             this.container.addClass('x-window-maximized-ct');
759
760             this.setPosition(0, 0);
761             this.fitContainer();
762             this.fireEvent('maximize', this);
763         }
764         return this;
765     },
766
767     /**
768      * Restores a {@link #maximizable maximized}  window back to its original
769      * size and position prior to being maximized and also replaces
770      * the 'restore' tool button with the 'maximize' tool button.
771      * Also see {@link #toggleMaximize}.
772      * @return {Ext.Window} this
773      */
774     restore : function(){
775         if(this.maximized){
776             this.el.removeClass('x-window-maximized');
777             this.tools.restore.hide();
778             this.tools.maximize.show();
779             this.setPosition(this.restorePos[0], this.restorePos[1]);
780             this.setSize(this.restoreSize.width, this.restoreSize.height);
781             delete this.restorePos;
782             delete this.restoreSize;
783             this.maximized = false;
784             this.el.enableShadow(true);
785
786             if(this.dd){
787                 this.dd.unlock();
788             }
789             if(this.collapsible){
790                 this.tools.toggle.show();
791             }
792             this.container.removeClass('x-window-maximized-ct');
793
794             this.doConstrain();
795             this.fireEvent('restore', this);
796         }
797         return this;
798     },
799
800     /**
801      * A shortcut method for toggling between {@link #maximize} and {@link #restore} based on the current maximized
802      * state of the window.
803      * @return {Ext.Window} this
804      */
805     toggleMaximize : function(){
806         return this[this.maximized ? 'restore' : 'maximize']();
807     },
808
809     // private
810     fitContainer : function(){
811         var vs = this.container.getViewSize();
812         this.setSize(vs.width, vs.height);
813     },
814
815     // private
816     // z-index is managed by the WindowManager and may be overwritten at any time
817     setZIndex : function(index){
818         if(this.modal){
819             this.mask.setStyle('z-index', index);
820         }
821         this.el.setZIndex(++index);
822         index += 5;
823
824         if(this.resizer){
825             this.resizer.proxy.setStyle('z-index', ++index);
826         }
827
828         this.lastZIndex = index;
829     },
830
831     /**
832      * Aligns the window to the specified element
833      * @param {Mixed} element The element to align to.
834      * @param {String} position The position to align to (see {@link Ext.Element#alignTo} for more details).
835      * @param {Array} offsets (optional) Offset the positioning by [x, y]
836      * @return {Ext.Window} this
837      */
838     alignTo : function(element, position, offsets){
839         var xy = this.el.getAlignToXY(element, position, offsets);
840         this.setPagePosition(xy[0], xy[1]);
841         return this;
842     },
843
844     /**
845      * Anchors this window to another element and realigns it when the window is resized or scrolled.
846      * @param {Mixed} element The element to align to.
847      * @param {String} position The position to align to (see {@link Ext.Element#alignTo} for more details)
848      * @param {Array} offsets (optional) Offset the positioning by [x, y]
849      * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
850      * is a number, it is used as the buffer delay (defaults to 50ms).
851      * @return {Ext.Window} this
852      */
853     anchorTo : function(el, alignment, offsets, monitorScroll){
854       if(this.doAnchor){
855           Ext.EventManager.removeResizeListener(this.doAnchor, this);
856           Ext.EventManager.un(window, 'scroll', this.doAnchor, this);
857       }
858       this.doAnchor = function(){
859           this.alignTo(el, alignment, offsets);
860       };
861       Ext.EventManager.onWindowResize(this.doAnchor, this);
862
863       var tm = typeof monitorScroll;
864       if(tm != 'undefined'){
865           Ext.EventManager.on(window, 'scroll', this.doAnchor, this,
866               {buffer: tm == 'number' ? monitorScroll : 50});
867       }
868       this.doAnchor();
869       return this;
870     },
871
872     /**
873      * Brings this window to the front of any other visible windows
874      * @param {Boolean} e (optional) Specify <tt>false</tt> to prevent the window from being focused.
875      * @return {Ext.Window} this
876      */
877     toFront : function(e){
878         if(this.manager.bringToFront(this)){
879             if(!e || !e.getTarget().focus){
880                 this.focus();
881             }
882         }
883         return this;
884     },
885
886     /**
887      * Makes this the active window by showing its shadow, or deactivates it by hiding its shadow.  This method also
888      * fires the {@link #activate} or {@link #deactivate} event depending on which action occurred. This method is
889      * called internally by {@link Ext.WindowMgr}.
890      * @param {Boolean} active True to activate the window, false to deactivate it (defaults to false)
891      */
892     setActive : function(active){
893         if(active){
894             if(!this.maximized){
895                 this.el.enableShadow(true);
896             }
897             this.fireEvent('activate', this);
898         }else{
899             this.el.disableShadow();
900             this.fireEvent('deactivate', this);
901         }
902     },
903
904     /**
905      * Sends this window to the back of (lower z-index than) any other visible windows
906      * @return {Ext.Window} this
907      */
908     toBack : function(){
909         this.manager.sendToBack(this);
910         return this;
911     },
912
913     /**
914      * Centers this window in the viewport
915      * @return {Ext.Window} this
916      */
917     center : function(){
918         var xy = this.el.getAlignToXY(this.container, 'c-c');
919         this.setPagePosition(xy[0], xy[1]);
920         return this;
921     }
922
923     /**
924      * @cfg {Boolean} autoWidth @hide
925      **/
926 });
927 Ext.reg('window', Ext.Window);
928
929 // private - custom Window DD implementation
930 Ext.Window.DD = function(win){
931     this.win = win;
932     Ext.Window.DD.superclass.constructor.call(this, win.el.id, 'WindowDD-'+win.id);
933     this.setHandleElId(win.header.id);
934     this.scroll = false;
935 };
936
937 Ext.extend(Ext.Window.DD, Ext.dd.DD, {
938     moveOnly:true,
939     headerOffsets:[100, 25],
940     startDrag : function(){
941         var w = this.win;
942         this.proxy = w.ghost();
943         if(w.constrain !== false){
944             var so = w.el.shadowOffset;
945             this.constrainTo(w.container, {right: so, left: so, bottom: so});
946         }else if(w.constrainHeader !== false){
947             var s = this.proxy.getSize();
948             this.constrainTo(w.container, {right: -(s.width-this.headerOffsets[0]), bottom: -(s.height-this.headerOffsets[1])});
949         }
950     },
951     b4Drag : Ext.emptyFn,
952
953     onDrag : function(e){
954         this.alignElWithMouse(this.proxy, e.getPageX(), e.getPageY());
955     },
956
957     endDrag : function(e){
958         this.win.unghost();
959         this.win.saveState();
960     }
961 });
962 /**
963  * @class Ext.WindowGroup
964  * An object that represents a group of {@link Ext.Window} instances and provides z-order management
965  * and window activation behavior.
966  * @constructor
967  */
968 Ext.WindowGroup = function(){
969     var list = {};
970     var accessList = [];
971     var front = null;
972
973     // private
974     var sortWindows = function(d1, d2){
975         return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
976     };
977
978     // private
979     var orderWindows = function(){
980         var a = accessList, len = a.length;
981         if(len > 0){
982             a.sort(sortWindows);
983             var seed = a[0].manager.zseed;
984             for(var i = 0; i < len; i++){
985                 var win = a[i];
986                 if(win && !win.hidden){
987                     win.setZIndex(seed + (i*10));
988                 }
989             }
990         }
991         activateLast();
992     };
993
994     // private
995     var setActiveWin = function(win){
996         if(win != front){
997             if(front){
998                 front.setActive(false);
999             }
1000             front = win;
1001             if(win){
1002                 win.setActive(true);
1003             }
1004         }
1005     };
1006
1007     // private
1008     var activateLast = function(){
1009         for(var i = accessList.length-1; i >=0; --i) {
1010             if(!accessList[i].hidden){
1011                 setActiveWin(accessList[i]);
1012                 return;
1013             }
1014         }
1015         // none to activate
1016         setActiveWin(null);
1017     };
1018
1019     return {
1020         /**
1021          * The starting z-index for windows (defaults to 9000)
1022          * @type Number The z-index value
1023          */
1024         zseed : 9000,
1025
1026         // private
1027         register : function(win){
1028             list[win.id] = win;
1029             accessList.push(win);
1030             win.on('hide', activateLast);
1031         },
1032
1033         // private
1034         unregister : function(win){
1035             delete list[win.id];
1036             win.un('hide', activateLast);
1037             accessList.remove(win);
1038         },
1039
1040         /**
1041          * Gets a registered window by id.
1042          * @param {String/Object} id The id of the window or a {@link Ext.Window} instance
1043          * @return {Ext.Window}
1044          */
1045         get : function(id){
1046             return typeof id == "object" ? id : list[id];
1047         },
1048
1049         /**
1050          * Brings the specified window to the front of any other active windows.
1051          * @param {String/Object} win The id of the window or a {@link Ext.Window} instance
1052          * @return {Boolean} True if the dialog was brought to the front, else false
1053          * if it was already in front
1054          */
1055         bringToFront : function(win){
1056             win = this.get(win);
1057             if(win != front){
1058                 win._lastAccess = new Date().getTime();
1059                 orderWindows();
1060                 return true;
1061             }
1062             return false;
1063         },
1064
1065         /**
1066          * Sends the specified window to the back of other active windows.
1067          * @param {String/Object} win The id of the window or a {@link Ext.Window} instance
1068          * @return {Ext.Window} The window
1069          */
1070         sendToBack : function(win){
1071             win = this.get(win);
1072             win._lastAccess = -(new Date().getTime());
1073             orderWindows();
1074             return win;
1075         },
1076
1077         /**
1078          * Hides all windows in the group.
1079          */
1080         hideAll : function(){
1081             for(var id in list){
1082                 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
1083                     list[id].hide();
1084                 }
1085             }
1086         },
1087
1088         /**
1089          * Gets the currently-active window in the group.
1090          * @return {Ext.Window} The active window
1091          */
1092         getActive : function(){
1093             return front;
1094         },
1095
1096         /**
1097          * Returns zero or more windows in the group using the custom search function passed to this method.
1098          * The function should accept a single {@link Ext.Window} reference as its only argument and should
1099          * return true if the window matches the search criteria, otherwise it should return false.
1100          * @param {Function} fn The search function
1101          * @param {Object} scope (optional) The scope in which to execute the function (defaults to the window
1102          * that gets passed to the function if not specified)
1103          * @return {Array} An array of zero or more matching windows
1104          */
1105         getBy : function(fn, scope){
1106             var r = [];
1107             for(var i = accessList.length-1; i >=0; --i) {
1108                 var win = accessList[i];
1109                 if(fn.call(scope||win, win) !== false){
1110                     r.push(win);
1111                 }
1112             }
1113             return r;
1114         },
1115
1116         /**
1117          * Executes the specified function once for every window in the group, passing each
1118          * window as the only parameter. Returning false from the function will stop the iteration.
1119          * @param {Function} fn The function to execute for each item
1120          * @param {Object} scope (optional) The scope in which to execute the function
1121          */
1122         each : function(fn, scope){
1123             for(var id in list){
1124                 if(list[id] && typeof list[id] != "function"){
1125                     if(fn.call(scope || list[id], list[id]) === false){
1126                         return;
1127                     }
1128                 }
1129             }
1130         }
1131     };
1132 };
1133
1134
1135 /**
1136  * @class Ext.WindowMgr
1137  * @extends Ext.WindowGroup
1138  * The default global window group that is available automatically.  To have more than one group of windows
1139  * with separate z-order stacks, create additional instances of {@link Ext.WindowGroup} as needed.
1140  * @singleton
1141  */
1142 Ext.WindowMgr = new Ext.WindowGroup();/**\r
1143  * @class Ext.MessageBox\r
1144  * <p>Utility class for generating different styles of message boxes.  The alias Ext.Msg can also be used.<p/>\r
1145  * <p>Note that the MessageBox is asynchronous.  Unlike a regular JavaScript <code>alert</code> (which will halt\r
1146  * browser execution), showing a MessageBox will not cause the code to stop.  For this reason, if you have code\r
1147  * that should only run <em>after</em> some user feedback from the MessageBox, you must use a callback function\r
1148  * (see the <code>function</code> parameter for {@link #show} for more details).</p>\r
1149  * <p>Example usage:</p>\r
1150  *<pre><code>\r
1151 // Basic alert:\r
1152 Ext.Msg.alert('Status', 'Changes saved successfully.');\r
1153 \r
1154 // Prompt for user data and process the result using a callback:\r
1155 Ext.Msg.prompt('Name', 'Please enter your name:', function(btn, text){\r
1156     if (btn == 'ok'){\r
1157         // process text value and close...\r
1158     }\r
1159 });\r
1160 \r
1161 // Show a dialog using config options:\r
1162 Ext.Msg.show({\r
1163    title:'Save Changes?',\r
1164    msg: 'You are closing a tab that has unsaved changes. Would you like to save your changes?',\r
1165    buttons: Ext.Msg.YESNOCANCEL,\r
1166    fn: processResult,\r
1167    animEl: 'elId',\r
1168    icon: Ext.MessageBox.QUESTION\r
1169 });\r
1170 </code></pre>\r
1171  * @singleton\r
1172  */\r
1173 Ext.MessageBox = function(){\r
1174     var dlg, opt, mask, waitTimer,\r
1175         bodyEl, msgEl, textboxEl, textareaEl, progressBar, pp, iconEl, spacerEl,\r
1176         buttons, activeTextEl, bwidth, bufferIcon = '', iconCls = '';\r
1177 \r
1178     // private\r
1179     var handleButton = function(button){\r
1180         if(dlg.isVisible()){\r
1181             dlg.hide();\r
1182             handleHide();\r
1183             Ext.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value, opt], 1);\r
1184         }\r
1185     };\r
1186 \r
1187     // private\r
1188     var handleHide = function(){\r
1189         if(opt && opt.cls){\r
1190             dlg.el.removeClass(opt.cls);\r
1191         }\r
1192         progressBar.reset();\r
1193     };\r
1194 \r
1195     // private\r
1196     var handleEsc = function(d, k, e){\r
1197         if(opt && opt.closable !== false){\r
1198             dlg.hide();\r
1199             handleHide();\r
1200         }\r
1201         if(e){\r
1202             e.stopEvent();\r
1203         }\r
1204     };\r
1205 \r
1206     // private\r
1207     var updateButtons = function(b){\r
1208         var width = 0;\r
1209         if(!b){\r
1210             buttons["ok"].hide();\r
1211             buttons["cancel"].hide();\r
1212             buttons["yes"].hide();\r
1213             buttons["no"].hide();\r
1214             return width;\r
1215         }\r
1216         dlg.footer.dom.style.display = '';\r
1217         for(var k in buttons){\r
1218             if(!Ext.isFunction(buttons[k])){\r
1219                 if(b[k]){\r
1220                     buttons[k].show();\r
1221                     buttons[k].setText(Ext.isString(b[k]) ? b[k] : Ext.MessageBox.buttonText[k]);\r
1222                     width += buttons[k].el.getWidth()+15;\r
1223                 }else{\r
1224                     buttons[k].hide();\r
1225                 }\r
1226             }\r
1227         }\r
1228         return width;\r
1229     };\r
1230 \r
1231     return {\r
1232         /**\r
1233          * Returns a reference to the underlying {@link Ext.Window} element\r
1234          * @return {Ext.Window} The window\r
1235          */\r
1236         getDialog : function(titleText){\r
1237            if(!dlg){\r
1238                 dlg = new Ext.Window({\r
1239                     autoCreate : true,\r
1240                     title:titleText,\r
1241                     resizable:false,\r
1242                     constrain:true,\r
1243                     constrainHeader:true,\r
1244                     minimizable : false,\r
1245                     maximizable : false,\r
1246                     stateful: false,\r
1247                     modal: true,\r
1248                     shim:true,\r
1249                     buttonAlign:"center",\r
1250                     width:400,\r
1251                     height:100,\r
1252                     minHeight: 80,\r
1253                     plain:true,\r
1254                     footer:true,\r
1255                     closable:true,\r
1256                     close : function(){\r
1257                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){\r
1258                             handleButton("no");\r
1259                         }else{\r
1260                             handleButton("cancel");\r
1261                         }\r
1262                     }\r
1263                 });\r
1264                 buttons = {};\r
1265                 var bt = this.buttonText;\r
1266                 //TODO: refactor this block into a buttons config to pass into the Window constructor\r
1267                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));\r
1268                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));\r
1269                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));\r
1270                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));\r
1271                 buttons["ok"].hideMode = buttons["yes"].hideMode = buttons["no"].hideMode = buttons["cancel"].hideMode = 'offsets';\r
1272                 dlg.render(document.body);\r
1273                 dlg.getEl().addClass('x-window-dlg');\r
1274                 mask = dlg.mask;\r
1275                 bodyEl = dlg.body.createChild({\r
1276                     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>'\r
1277                 });\r
1278                 iconEl = Ext.get(bodyEl.dom.firstChild);\r
1279                 var contentEl = bodyEl.dom.childNodes[1];\r
1280                 msgEl = Ext.get(contentEl.firstChild);\r
1281                 textboxEl = Ext.get(contentEl.childNodes[2].firstChild);\r
1282                 textboxEl.enableDisplayMode();\r
1283                 textboxEl.addKeyListener([10,13], function(){\r
1284                     if(dlg.isVisible() && opt && opt.buttons){\r
1285                         if(opt.buttons.ok){\r
1286                             handleButton("ok");\r
1287                         }else if(opt.buttons.yes){\r
1288                             handleButton("yes");\r
1289                         }\r
1290                     }\r
1291                 });\r
1292                 textareaEl = Ext.get(contentEl.childNodes[2].childNodes[1]);\r
1293                 textareaEl.enableDisplayMode();\r
1294                 progressBar = new Ext.ProgressBar({\r
1295                     renderTo:bodyEl\r
1296                 });\r
1297                bodyEl.createChild({cls:'x-clear'});\r
1298             }\r
1299             return dlg;\r
1300         },\r
1301 \r
1302         /**\r
1303          * Updates the message box body text\r
1304          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to\r
1305          * the XHTML-compliant non-breaking space character '&amp;#160;')\r
1306          * @return {Ext.MessageBox} this\r
1307          */\r
1308         updateText : function(text){\r
1309             if(!dlg.isVisible() && !opt.width){\r
1310                 dlg.setSize(this.maxWidth, 100); // resize first so content is never clipped from previous shows\r
1311             }\r
1312             msgEl.update(text || '&#160;');\r
1313 \r
1314             var iw = iconCls != '' ? (iconEl.getWidth() + iconEl.getMargins('lr')) : 0;\r
1315             var mw = msgEl.getWidth() + msgEl.getMargins('lr');\r
1316             var fw = dlg.getFrameWidth('lr');\r
1317             var bw = dlg.body.getFrameWidth('lr');\r
1318             if (Ext.isIE && iw > 0){\r
1319                 //3 pixels get subtracted in the icon CSS for an IE margin issue,\r
1320                 //so we have to add it back here for the overall width to be consistent\r
1321                 iw += 3;\r
1322             }\r
1323             var w = Math.max(Math.min(opt.width || iw+mw+fw+bw, this.maxWidth),\r
1324                         Math.max(opt.minWidth || this.minWidth, bwidth || 0));\r
1325 \r
1326             if(opt.prompt === true){\r
1327                 activeTextEl.setWidth(w-iw-fw-bw);\r
1328             }\r
1329             if(opt.progress === true || opt.wait === true){\r
1330                 progressBar.setSize(w-iw-fw-bw);\r
1331             }\r
1332             if(Ext.isIE && w == bwidth){\r
1333                 w += 4; //Add offset when the content width is smaller than the buttons.    \r
1334             }\r
1335             dlg.setSize(w, 'auto').center();\r
1336             return this;\r
1337         },\r
1338 \r
1339         /**\r
1340          * Updates a progress-style message box's text and progress bar. Only relevant on message boxes\r
1341          * initiated via {@link Ext.MessageBox#progress} or {@link Ext.MessageBox#wait},\r
1342          * or by calling {@link Ext.MessageBox#show} with progress: true.\r
1343          * @param {Number} value Any number between 0 and 1 (e.g., .5, defaults to 0)\r
1344          * @param {String} progressText The progress text to display inside the progress bar (defaults to '')\r
1345          * @param {String} msg The message box's body text is replaced with the specified string (defaults to undefined\r
1346          * so that any existing body text will not get overwritten by default unless a new value is passed in)\r
1347          * @return {Ext.MessageBox} this\r
1348          */\r
1349         updateProgress : function(value, progressText, msg){\r
1350             progressBar.updateProgress(value, progressText);\r
1351             if(msg){\r
1352                 this.updateText(msg);\r
1353             }\r
1354             return this;\r
1355         },\r
1356 \r
1357         /**\r
1358          * Returns true if the message box is currently displayed\r
1359          * @return {Boolean} True if the message box is visible, else false\r
1360          */\r
1361         isVisible : function(){\r
1362             return dlg && dlg.isVisible();\r
1363         },\r
1364 \r
1365         /**\r
1366          * Hides the message box if it is displayed\r
1367          * @return {Ext.MessageBox} this\r
1368          */\r
1369         hide : function(){\r
1370             var proxy = dlg ? dlg.activeGhost : null;\r
1371             if(this.isVisible() || proxy){\r
1372                 dlg.hide();\r
1373                 handleHide();\r
1374                 if (proxy){\r
1375                     // unghost is a private function, but i saw no better solution\r
1376                     // to fix the locking problem when dragging while it closes\r
1377                     dlg.unghost(false, false);\r
1378                 } \r
1379             }\r
1380             return this;\r
1381         },\r
1382 \r
1383         /**\r
1384          * Displays a new message box, or reinitializes an existing message box, based on the config options\r
1385          * passed in. All display functions (e.g. prompt, alert, etc.) on MessageBox call this function internally,\r
1386          * although those calls are basic shortcuts and do not support all of the config options allowed here.\r
1387          * @param {Object} config The following config options are supported: <ul>\r
1388          * <li><b>animEl</b> : String/Element<div class="sub-desc">An id or Element from which the message box should animate as it\r
1389          * opens and closes (defaults to undefined)</div></li>\r
1390          * <li><b>buttons</b> : Object/Boolean<div class="sub-desc">A button config object (e.g., Ext.MessageBox.OKCANCEL or {ok:'Foo',\r
1391          * cancel:'Bar'}), or false to not show any buttons (defaults to false)</div></li>\r
1392          * <li><b>closable</b> : Boolean<div class="sub-desc">False to hide the top-right close button (defaults to true). Note that\r
1393          * progress and wait dialogs will ignore this property and always hide the close button as they can only\r
1394          * be closed programmatically.</div></li>\r
1395          * <li><b>cls</b> : String<div class="sub-desc">A custom CSS class to apply to the message box's container element</div></li>\r
1396          * <li><b>defaultTextHeight</b> : Number<div class="sub-desc">The default height in pixels of the message box's multiline textarea\r
1397          * if displayed (defaults to 75)</div></li>\r
1398          * <li><b>fn</b> : Function<div class="sub-desc">A callback function which is called when the dialog is dismissed either\r
1399          * by clicking on the configured buttons, or on the dialog close button, or by pressing\r
1400          * the return button to enter input.\r
1401          * <p>Progress and wait dialogs will ignore this option since they do not respond to user\r
1402          * actions and can only be closed programmatically, so any required function should be called\r
1403          * by the same code after it closes the dialog. Parameters passed:<ul>\r
1404          * <li><b>buttonId</b> : String<div class="sub-desc">The ID of the button pressed, one of:<div class="sub-desc"><ul>\r
1405          * <li><tt>ok</tt></li>\r
1406          * <li><tt>yes</tt></li>\r
1407          * <li><tt>no</tt></li>\r
1408          * <li><tt>cancel</tt></li>\r
1409          * </ul></div></div></li>\r
1410          * <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>\r
1411          * or <tt><a href="#show-option-multiline" ext:member="show-option-multiline" ext:cls="Ext.MessageBox">multiline</a></tt> is true</div></li>\r
1412          * <li><b>opt</b> : Object<div class="sub-desc">The config object passed to show.</div></li>\r
1413          * </ul></p></div></li>\r
1414          * <li><b>scope</b> : Object<div class="sub-desc">The scope of the callback function</div></li>\r
1415          * <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\r
1416          * dialog (e.g. Ext.MessageBox.WARNING or 'custom-class') (defaults to '')</div></li>\r
1417          * <li><b>iconCls</b> : String<div class="sub-desc">The standard {@link Ext.Window#iconCls} to\r
1418          * add an optional header icon (defaults to '')</div></li>\r
1419          * <li><b>maxWidth</b> : Number<div class="sub-desc">The maximum width in pixels of the message box (defaults to 600)</div></li>\r
1420          * <li><b>minWidth</b> : Number<div class="sub-desc">The minimum width in pixels of the message box (defaults to 100)</div></li>\r
1421          * <li><b>modal</b> : Boolean<div class="sub-desc">False to allow user interaction with the page while the message box is\r
1422          * displayed (defaults to true)</div></li>\r
1423          * <li><b>msg</b> : String<div class="sub-desc">A string that will replace the existing message box body text (defaults to the\r
1424          * XHTML-compliant non-breaking space character '&amp;#160;')</div></li>\r
1425          * <li><a id="show-option-multiline"></a><b>multiline</b> : Boolean<div class="sub-desc">\r
1426          * True to prompt the user to enter multi-line text (defaults to false)</div></li>\r
1427          * <li><b>progress</b> : Boolean<div class="sub-desc">True to display a progress bar (defaults to false)</div></li>\r
1428          * <li><b>progressText</b> : String<div class="sub-desc">The text to display inside the progress bar if progress = true (defaults to '')</div></li>\r
1429          * <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>\r
1430          * <li><b>proxyDrag</b> : Boolean<div class="sub-desc">True to display a lightweight proxy while dragging (defaults to false)</div></li>\r
1431          * <li><b>title</b> : String<div class="sub-desc">The title text</div></li>\r
1432          * <li><b>value</b> : String<div class="sub-desc">The string value to set into the active textbox element if displayed</div></li>\r
1433          * <li><b>wait</b> : Boolean<div class="sub-desc">True to display a progress bar (defaults to false)</div></li>\r
1434          * <li><b>waitConfig</b> : Object<div class="sub-desc">A {@link Ext.ProgressBar#waitConfig} object (applies only if wait = true)</div></li>\r
1435          * <li><b>width</b> : Number<div class="sub-desc">The width of the dialog in pixels</div></li>\r
1436          * </ul>\r
1437          * Example usage:\r
1438          * <pre><code>\r
1439 Ext.Msg.show({\r
1440    title: 'Address',\r
1441    msg: 'Please enter your address:',\r
1442    width: 300,\r
1443    buttons: Ext.MessageBox.OKCANCEL,\r
1444    multiline: true,\r
1445    fn: saveAddress,\r
1446    animEl: 'addAddressBtn',\r
1447    icon: Ext.MessageBox.INFO\r
1448 });\r
1449 </code></pre>\r
1450          * @return {Ext.MessageBox} this\r
1451          */\r
1452         show : function(options){\r
1453             if(this.isVisible()){\r
1454                 this.hide();\r
1455             }\r
1456             opt = options;\r
1457             var d = this.getDialog(opt.title || "&#160;");\r
1458 \r
1459             d.setTitle(opt.title || "&#160;");\r
1460             var allowClose = (opt.closable !== false && opt.progress !== true && opt.wait !== true);\r
1461             d.tools.close.setDisplayed(allowClose);\r
1462             activeTextEl = textboxEl;\r
1463             opt.prompt = opt.prompt || (opt.multiline ? true : false);\r
1464             if(opt.prompt){\r
1465                 if(opt.multiline){\r
1466                     textboxEl.hide();\r
1467                     textareaEl.show();\r
1468                     textareaEl.setHeight(Ext.isNumber(opt.multiline) ? opt.multiline : this.defaultTextHeight);\r
1469                     activeTextEl = textareaEl;\r
1470                 }else{\r
1471                     textboxEl.show();\r
1472                     textareaEl.hide();\r
1473                 }\r
1474             }else{\r
1475                 textboxEl.hide();\r
1476                 textareaEl.hide();\r
1477             }\r
1478             activeTextEl.dom.value = opt.value || "";\r
1479             if(opt.prompt){\r
1480                 d.focusEl = activeTextEl;\r
1481             }else{\r
1482                 var bs = opt.buttons;\r
1483                 var db = null;\r
1484                 if(bs && bs.ok){\r
1485                     db = buttons["ok"];\r
1486                 }else if(bs && bs.yes){\r
1487                     db = buttons["yes"];\r
1488                 }\r
1489                 if (db){\r
1490                     d.focusEl = db;\r
1491                 }\r
1492             }\r
1493             if(opt.iconCls){\r
1494               d.setIconClass(opt.iconCls);\r
1495             }\r
1496             this.setIcon(Ext.isDefined(opt.icon) ? opt.icon : bufferIcon);\r
1497             bwidth = updateButtons(opt.buttons);\r
1498             progressBar.setVisible(opt.progress === true || opt.wait === true);\r
1499             this.updateProgress(0, opt.progressText);\r
1500             this.updateText(opt.msg);\r
1501             if(opt.cls){\r
1502                 d.el.addClass(opt.cls);\r
1503             }\r
1504             d.proxyDrag = opt.proxyDrag === true;\r
1505             d.modal = opt.modal !== false;\r
1506             d.mask = opt.modal !== false ? mask : false;\r
1507             if(!d.isVisible()){\r
1508                 // force it to the end of the z-index stack so it gets a cursor in FF\r
1509                 document.body.appendChild(dlg.el.dom);\r
1510                 d.setAnimateTarget(opt.animEl);\r
1511                 d.show(opt.animEl);\r
1512             }\r
1513 \r
1514             //workaround for window internally enabling keymap in afterShow\r
1515             d.on('show', function(){\r
1516                 if(allowClose === true){\r
1517                     d.keyMap.enable();\r
1518                 }else{\r
1519                     d.keyMap.disable();\r
1520                 }\r
1521             }, this, {single:true});\r
1522 \r
1523             if(opt.wait === true){\r
1524                 progressBar.wait(opt.waitConfig);\r
1525             }\r
1526             return this;\r
1527         },\r
1528 \r
1529         /**\r
1530          * Adds the specified icon to the dialog.  By default, the class 'ext-mb-icon' is applied for default\r
1531          * styling, and the class passed in is expected to supply the background image url. Pass in empty string ('')\r
1532          * to clear any existing icon. This method must be called before the MessageBox is shown.\r
1533          * The following built-in icon classes are supported, but you can also pass in a custom class name:\r
1534          * <pre>\r
1535 Ext.MessageBox.INFO\r
1536 Ext.MessageBox.WARNING\r
1537 Ext.MessageBox.QUESTION\r
1538 Ext.MessageBox.ERROR\r
1539          *</pre>\r
1540          * @param {String} icon A CSS classname specifying the icon's background image url, or empty string to clear the icon\r
1541          * @return {Ext.MessageBox} this\r
1542          */\r
1543         setIcon : function(icon){\r
1544             if(!dlg){\r
1545                 bufferIcon = icon;\r
1546                 return;\r
1547             }\r
1548             bufferIcon = undefined;\r
1549             if(icon && icon != ''){\r
1550                 iconEl.removeClass('x-hidden');\r
1551                 iconEl.replaceClass(iconCls, icon);\r
1552                 bodyEl.addClass('x-dlg-icon');\r
1553                 iconCls = icon;\r
1554             }else{\r
1555                 iconEl.replaceClass(iconCls, 'x-hidden');\r
1556                 bodyEl.removeClass('x-dlg-icon');\r
1557                 iconCls = '';\r
1558             }\r
1559             return this;\r
1560         },\r
1561 \r
1562         /**\r
1563          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by\r
1564          * the user.  You are responsible for updating the progress bar as needed via {@link Ext.MessageBox#updateProgress}\r
1565          * and closing the message box when the process is complete.\r
1566          * @param {String} title The title bar text\r
1567          * @param {String} msg The message box body text\r
1568          * @param {String} progressText (optional) The text to display inside the progress bar (defaults to '')\r
1569          * @return {Ext.MessageBox} this\r
1570          */\r
1571         progress : function(title, msg, progressText){\r
1572             this.show({\r
1573                 title : title,\r
1574                 msg : msg,\r
1575                 buttons: false,\r
1576                 progress:true,\r
1577                 closable:false,\r
1578                 minWidth: this.minProgressWidth,\r
1579                 progressText: progressText\r
1580             });\r
1581             return this;\r
1582         },\r
1583 \r
1584         /**\r
1585          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user\r
1586          * interaction while waiting for a long-running process to complete that does not have defined intervals.\r
1587          * You are responsible for closing the message box when the process is complete.\r
1588          * @param {String} msg The message box body text\r
1589          * @param {String} title (optional) The title bar text\r
1590          * @param {Object} config (optional) A {@link Ext.ProgressBar#waitConfig} object\r
1591          * @return {Ext.MessageBox} this\r
1592          */\r
1593         wait : function(msg, title, config){\r
1594             this.show({\r
1595                 title : title,\r
1596                 msg : msg,\r
1597                 buttons: false,\r
1598                 closable:false,\r
1599                 wait:true,\r
1600                 modal:true,\r
1601                 minWidth: this.minProgressWidth,\r
1602                 waitConfig: config\r
1603             });\r
1604             return this;\r
1605         },\r
1606 \r
1607         /**\r
1608          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript alert prompt).\r
1609          * If a callback function is passed it will be called after the user clicks the button, and the\r
1610          * id of the button that was clicked will be passed as the only parameter to the callback\r
1611          * (could also be the top-right close button).\r
1612          * @param {String} title The title bar text\r
1613          * @param {String} msg The message box body text\r
1614          * @param {Function} fn (optional) The callback function invoked after the message box is closed\r
1615          * @param {Object} scope (optional) The scope of the callback function\r
1616          * @return {Ext.MessageBox} this\r
1617          */\r
1618         alert : function(title, msg, fn, scope){\r
1619             this.show({\r
1620                 title : title,\r
1621                 msg : msg,\r
1622                 buttons: this.OK,\r
1623                 fn: fn,\r
1624                 scope : scope\r
1625             });\r
1626             return this;\r
1627         },\r
1628 \r
1629         /**\r
1630          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's confirm).\r
1631          * If a callback function is passed it will be called after the user clicks either button,\r
1632          * and the id of the button that was clicked will be passed as the only parameter to the callback\r
1633          * (could also be the top-right close button).\r
1634          * @param {String} title The title bar text\r
1635          * @param {String} msg The message box body text\r
1636          * @param {Function} fn (optional) The callback function invoked after the message box is closed\r
1637          * @param {Object} scope (optional) The scope of the callback function\r
1638          * @return {Ext.MessageBox} this\r
1639          */\r
1640         confirm : function(title, msg, fn, scope){\r
1641             this.show({\r
1642                 title : title,\r
1643                 msg : msg,\r
1644                 buttons: this.YESNO,\r
1645                 fn: fn,\r
1646                 scope : scope,\r
1647                 icon: this.QUESTION\r
1648             });\r
1649             return this;\r
1650         },\r
1651 \r
1652         /**\r
1653          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to JavaScript's prompt).\r
1654          * The prompt can be a single-line or multi-line textbox.  If a callback function is passed it will be called after the user\r
1655          * clicks either button, and the id of the button that was clicked (could also be the top-right\r
1656          * close button) and the text that was entered will be passed as the two parameters to the callback.\r
1657          * @param {String} title The title bar text\r
1658          * @param {String} msg The message box body text\r
1659          * @param {Function} fn (optional) The callback function invoked after the message box is closed\r
1660          * @param {Object} scope (optional) The scope of the callback function\r
1661          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight\r
1662          * property, or the height in pixels to create the textbox (defaults to false / single-line)\r
1663          * @param {String} value (optional) Default value of the text input element (defaults to '')\r
1664          * @return {Ext.MessageBox} this\r
1665          */\r
1666         prompt : function(title, msg, fn, scope, multiline, value){\r
1667             this.show({\r
1668                 title : title,\r
1669                 msg : msg,\r
1670                 buttons: this.OKCANCEL,\r
1671                 fn: fn,\r
1672                 minWidth:250,\r
1673                 scope : scope,\r
1674                 prompt:true,\r
1675                 multiline: multiline,\r
1676                 value: value\r
1677             });\r
1678             return this;\r
1679         },\r
1680 \r
1681         /**\r
1682          * Button config that displays a single OK button\r
1683          * @type Object\r
1684          */\r
1685         OK : {ok:true},\r
1686         /**\r
1687          * Button config that displays a single Cancel button\r
1688          * @type Object\r
1689          */\r
1690         CANCEL : {cancel:true},\r
1691         /**\r
1692          * Button config that displays OK and Cancel buttons\r
1693          * @type Object\r
1694          */\r
1695         OKCANCEL : {ok:true, cancel:true},\r
1696         /**\r
1697          * Button config that displays Yes and No buttons\r
1698          * @type Object\r
1699          */\r
1700         YESNO : {yes:true, no:true},\r
1701         /**\r
1702          * Button config that displays Yes, No and Cancel buttons\r
1703          * @type Object\r
1704          */\r
1705         YESNOCANCEL : {yes:true, no:true, cancel:true},\r
1706         /**\r
1707          * The CSS class that provides the INFO icon image\r
1708          * @type String\r
1709          */\r
1710         INFO : 'ext-mb-info',\r
1711         /**\r
1712          * The CSS class that provides the WARNING icon image\r
1713          * @type String\r
1714          */\r
1715         WARNING : 'ext-mb-warning',\r
1716         /**\r
1717          * The CSS class that provides the QUESTION icon image\r
1718          * @type String\r
1719          */\r
1720         QUESTION : 'ext-mb-question',\r
1721         /**\r
1722          * The CSS class that provides the ERROR icon image\r
1723          * @type String\r
1724          */\r
1725         ERROR : 'ext-mb-error',\r
1726 \r
1727         /**\r
1728          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)\r
1729          * @type Number\r
1730          */\r
1731         defaultTextHeight : 75,\r
1732         /**\r
1733          * The maximum width in pixels of the message box (defaults to 600)\r
1734          * @type Number\r
1735          */\r
1736         maxWidth : 600,\r
1737         /**\r
1738          * The minimum width in pixels of the message box (defaults to 100)\r
1739          * @type Number\r
1740          */\r
1741         minWidth : 100,\r
1742         /**\r
1743          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful\r
1744          * for setting a different minimum width than text-only dialogs may need (defaults to 250)\r
1745          * @type Number\r
1746          */\r
1747         minProgressWidth : 250,\r
1748         /**\r
1749          * An object containing the default button text strings that can be overriden for localized language support.\r
1750          * Supported properties are: ok, cancel, yes and no.  Generally you should include a locale-specific\r
1751          * resource file for handling language support across the framework.\r
1752          * Customize the default text like so: Ext.MessageBox.buttonText.yes = "oui"; //french\r
1753          * @type Object\r
1754          */\r
1755         buttonText : {\r
1756             ok : "OK",\r
1757             cancel : "Cancel",\r
1758             yes : "Yes",\r
1759             no : "No"\r
1760         }\r
1761     };\r
1762 }();\r
1763 \r
1764 /**\r
1765  * Shorthand for {@link Ext.MessageBox}\r
1766  */\r
1767 Ext.Msg = Ext.MessageBox;/**\r
1768  * @class Ext.dd.PanelProxy\r
1769  * A custom drag proxy implementation specific to {@link Ext.Panel}s. This class is primarily used internally\r
1770  * for the Panel's drag drop implementation, and should never need to be created directly.\r
1771  * @constructor\r
1772  * @param panel The {@link Ext.Panel} to proxy for\r
1773  * @param config Configuration options\r
1774  */\r
1775 Ext.dd.PanelProxy = function(panel, config){\r
1776     this.panel = panel;\r
1777     this.id = this.panel.id +'-ddproxy';\r
1778     Ext.apply(this, config);\r
1779 };\r
1780 \r
1781 Ext.dd.PanelProxy.prototype = {\r
1782     /**\r
1783      * @cfg {Boolean} insertProxy True to insert a placeholder proxy element while dragging the panel,\r
1784      * false to drag with no proxy (defaults to true).\r
1785      */\r
1786     insertProxy : true,\r
1787 \r
1788     // private overrides\r
1789     setStatus : Ext.emptyFn,\r
1790     reset : Ext.emptyFn,\r
1791     update : Ext.emptyFn,\r
1792     stop : Ext.emptyFn,\r
1793     sync: Ext.emptyFn,\r
1794 \r
1795     /**\r
1796      * Gets the proxy's element\r
1797      * @return {Element} The proxy's element\r
1798      */\r
1799     getEl : function(){\r
1800         return this.ghost;\r
1801     },\r
1802 \r
1803     /**\r
1804      * Gets the proxy's ghost element\r
1805      * @return {Element} The proxy's ghost element\r
1806      */\r
1807     getGhost : function(){\r
1808         return this.ghost;\r
1809     },\r
1810 \r
1811     /**\r
1812      * Gets the proxy's element\r
1813      * @return {Element} The proxy's element\r
1814      */\r
1815     getProxy : function(){\r
1816         return this.proxy;\r
1817     },\r
1818 \r
1819     /**\r
1820      * Hides the proxy\r
1821      */\r
1822     hide : function(){\r
1823         if(this.ghost){\r
1824             if(this.proxy){\r
1825                 this.proxy.remove();\r
1826                 delete this.proxy;\r
1827             }\r
1828             this.panel.el.dom.style.display = '';\r
1829             this.ghost.remove();\r
1830             delete this.ghost;\r
1831         }\r
1832     },\r
1833 \r
1834     /**\r
1835      * Shows the proxy\r
1836      */\r
1837     show : function(){\r
1838         if(!this.ghost){\r
1839             this.ghost = this.panel.createGhost(undefined, undefined, Ext.getBody());\r
1840             this.ghost.setXY(this.panel.el.getXY())\r
1841             if(this.insertProxy){\r
1842                 this.proxy = this.panel.el.insertSibling({cls:'x-panel-dd-spacer'});\r
1843                 this.proxy.setSize(this.panel.getSize());\r
1844             }\r
1845             this.panel.el.dom.style.display = 'none';\r
1846         }\r
1847     },\r
1848 \r
1849     // private\r
1850     repair : function(xy, callback, scope){\r
1851         this.hide();\r
1852         if(typeof callback == "function"){\r
1853             callback.call(scope || this);\r
1854         }\r
1855     },\r
1856 \r
1857     /**\r
1858      * Moves the proxy to a different position in the DOM.  This is typically called while dragging the Panel\r
1859      * to keep the proxy sync'd to the Panel's location.\r
1860      * @param {HTMLElement} parentNode The proxy's parent DOM node\r
1861      * @param {HTMLElement} before (optional) The sibling node before which the proxy should be inserted (defaults\r
1862      * to the parent's last child if not specified)\r
1863      */\r
1864     moveProxy : function(parentNode, before){\r
1865         if(this.proxy){\r
1866             parentNode.insertBefore(this.proxy.dom, before);\r
1867         }\r
1868     }\r
1869 };\r
1870 \r
1871 // private - DD implementation for Panels\r
1872 Ext.Panel.DD = function(panel, cfg){\r
1873     this.panel = panel;\r
1874     this.dragData = {panel: panel};\r
1875     this.proxy = new Ext.dd.PanelProxy(panel, cfg);\r
1876     Ext.Panel.DD.superclass.constructor.call(this, panel.el, cfg);\r
1877     var h = panel.header;\r
1878     if(h){\r
1879         this.setHandleElId(h.id);\r
1880     }\r
1881     (h ? h : this.panel.body).setStyle('cursor', 'move');\r
1882     this.scroll = false;\r
1883 };\r
1884 \r
1885 Ext.extend(Ext.Panel.DD, Ext.dd.DragSource, {\r
1886     showFrame: Ext.emptyFn,\r
1887     startDrag: Ext.emptyFn,\r
1888     b4StartDrag: function(x, y) {\r
1889         this.proxy.show();\r
1890     },\r
1891     b4MouseDown: function(e) {\r
1892         var x = e.getPageX();\r
1893         var y = e.getPageY();\r
1894         this.autoOffset(x, y);\r
1895     },\r
1896     onInitDrag : function(x, y){\r
1897         this.onStartDrag(x, y);\r
1898         return true;\r
1899     },\r
1900     createFrame : Ext.emptyFn,\r
1901     getDragEl : function(e){\r
1902         return this.proxy.ghost.dom;\r
1903     },\r
1904     endDrag : function(e){\r
1905         this.proxy.hide();\r
1906         this.panel.saveState();\r
1907     },\r
1908 \r
1909     autoOffset : function(x, y) {\r
1910         x -= this.startPageX;\r
1911         y -= this.startPageY;\r
1912         this.setDelta(x, y);\r
1913     }\r
1914 });