Upgrade to ExtJS 3.2.1 - Released 04/27/2010
[extjs.git] / pkgs / window-debug.js
index b58ec94..ffc8a33 100644 (file)
@@ -1,6 +1,6 @@
 /*!
- * Ext JS Library 3.0.0
- * Copyright(c) 2006-2009 Ext JS, LLC
+ * Ext JS Library 3.2.1
+ * Copyright(c) 2006-2010 Ext JS, Inc.
  * licensing@extjs.com
  * http://www.extjs.com/license
  */
@@ -10,7 +10,7 @@
  * <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 
+ * <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>
@@ -50,8 +50,13 @@ Ext.Window = Ext.extend(Ext.Panel, {
      * 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 {String/Number/Component} defaultButton
+    * <p>Specifies a Component to receive focus when this Window is focussed.</p>
+    * <p>This may be one of:</p><div class="mdetail-params"><ul>
+    * <li>The index of a footer Button.</li>
+    * <li>The id of a Component.</li>
+    * <li>A Component.</li>
+    * </ul></div>
     */
     /**
     * @cfg {Function} onEsc
@@ -62,15 +67,15 @@ Ext.Window = Ext.extend(Ext.Panel, {
     */
     /**
      * @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 
+     * 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').
@@ -122,15 +127,15 @@ Ext.Window = Ext.extend(Ext.Panel, {
     /**
      * @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 
+     * 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 
+     * 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,
@@ -180,13 +185,16 @@ Ext.Window = Ext.extend(Ext.Panel, {
     /**
      * @cfg {Boolean} initHidden
      * True to hide the window until show() is explicitly called (defaults to true).
+     * @deprecated
      */
-    initHidden : true,
+    initHidden : undefined,
+
     /**
-    * @cfg {Boolean} monitorResize @hide
-    * This is automatically managed based on the value of constrain and constrainToHeader
-    */
-    monitorResize : true,
+     * @cfg {Boolean} hidden
+     * Render this component hidden (default is <tt>true</tt>). If <tt>true</tt>, the
+     * {@link #hide} method will be called internally.
+     */
+    hidden : 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
@@ -201,16 +209,17 @@ Ext.Window = Ext.extend(Ext.Panel, {
 
     // private
     initComponent : function(){
+        this.initTools();
         Ext.Window.superclass.initComponent.call(this);
         this.addEvents(
             /**
              * @event activate
-             * Fires after the window has been visually activated via {@link setActive}.
+             * 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}.
+             * Fires after the window has been visually deactivated via {@link #setActive}.
              * @param {Ext.Window} this
              */
             /**
@@ -240,10 +249,13 @@ Ext.Window = Ext.extend(Ext.Panel, {
              */
             'restore'
         );
-        if(this.initHidden === false){
-            this.show();
-        }else{
+        // for backwards compat, this should be removed at some point
+        if(Ext.isDefined(this.initHidden)){
+            this.hidden = this.initHidden;
+        }
+        if(this.hidden === false){
             this.hidden = true;
+            this.show();
         }
     },
 
@@ -275,7 +287,9 @@ Ext.Window = Ext.extend(Ext.Panel, {
             this.mask.hide();
             this.mon(this.mask, 'click', this.focus, this);
         }
-        this.initTools();
+        if(this.maximizable){
+            this.mon(this.header, 'dblclick', this.toggleMaximize, this);
+        }
     },
 
     // private
@@ -291,7 +305,8 @@ Ext.Window = Ext.extend(Ext.Panel, {
                 minHeight:this.minHeight,
                 handles: this.resizeHandles || 'all',
                 pinned: true,
-                resizeElement : this.resizerAction
+                resizeElement : this.resizerAction,
+                handleCls: 'x-window-handle'
             });
             this.resizer.window = this;
             this.mon(this.resizer, 'beforeresize', this.beforeResize, this);
@@ -316,8 +331,12 @@ Ext.Window = Ext.extend(Ext.Panel, {
 
     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.
+         * <p>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.</p>
+         * <p>This has implementations of <code>startDrag</code>, <code>onDrag</code> and <code>endDrag</code>
+         * which perform the dragging action. If extra logic is needed at these points, use
+         * {@link Function#createInterceptor createInterceptor} or {@link Function#createSequence createSequence} to
+         * augment the existing implementations.</p>
          * @type Ext.dd.DD
          * @property dd
          */
@@ -325,18 +344,16 @@ Ext.Window = Ext.extend(Ext.Panel, {
     },
 
    // private
-    onEsc : function(){
+    onEsc : function(k, e){
+        e.stopEvent();
         this[this.closeAction]();
     },
 
     // private
     beforeDestroy : function(){
-        if (this.rendered){
+        if(this.rendered){
             this.hide();
-          if(this.doAnchor){
-                Ext.EventManager.removeResizeListener(this.doAnchor, this);
-              Ext.EventManager.un(window, 'scroll', this.doAnchor, this);
-            }
+            this.clearAnchor();
             Ext.destroy(
                 this.focusEl,
                 this.resizer,
@@ -374,7 +391,6 @@ Ext.Window = Ext.extend(Ext.Panel, {
                 handler: this.restore.createDelegate(this, []),
                 hidden:true
             });
-            this.mon(this.header, 'dblclick', this.toggleMaximize, this);
         }
         if(this.closable){
             this.addTool({
@@ -414,12 +430,13 @@ Ext.Window = Ext.extend(Ext.Panel, {
             this.updateBox(box);
         }else{
             this.setSize(box);
+            if (Ext.isIE6 && Ext.isStrict) {
+                this.doLayout();
+            }
         }
         this.focus();
         this.updateHandles();
         this.saveState();
-        this.doLayout();
-        this.fireEvent('resize', this, box.width, box.height);
     },
 
     /**
@@ -427,15 +444,26 @@ Ext.Window = Ext.extend(Ext.Panel, {
      * 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){
+        var f = this.focusEl,
+            db = this.defaultButton,
+            t = typeof db,
+            el,
+            ct;
+        if(Ext.isDefined(db)){
+            if(Ext.isNumber(db) && this.fbar){
                 f = this.fbar.items.get(db);
-            }else if(t == 'string'){
+            }else if(Ext.isString(db)){
                 f = Ext.getCmp(db);
             }else{
                 f = db;
             }
+            el = f.getEl();
+            ct = Ext.getDom(this.container);
+            if (el && ct) {
+                if (!Ext.lib.Region.getRegion(ct).contains(Ext.lib.Region.getRegion(el.dom))){
+                    return;
+                }
+            }
         }
         f = f || this.focusEl;
         f.focus.defer(10, f);
@@ -478,7 +506,7 @@ Ext.Window = Ext.extend(Ext.Panel, {
      * @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
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this Window.
      * @return {Ext.Window} this
      */
     show : function(animateTarget, cb, scope){
@@ -496,7 +524,7 @@ Ext.Window = Ext.extend(Ext.Panel, {
             this.on('show', cb, scope, {single:true});
         }
         this.hidden = false;
-        if(animateTarget !== undefined){
+        if(Ext.isDefined(animateTarget)){
             this.setAnimateTarget(animateTarget);
         }
         this.beforeShow();
@@ -510,13 +538,16 @@ Ext.Window = Ext.extend(Ext.Panel, {
 
     // private
     afterShow : function(isAnim){
+        if (this.isDestroyed){
+            return false;
+        }
         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
+        if(Ext.isMac && Ext.isGecko2){ // work around stupid FF 2.0/Mac scroll bar bug
             this.cascade(this.setAutoScroll);
         }
 
@@ -534,6 +565,7 @@ Ext.Window = Ext.extend(Ext.Panel, {
             var sz = this.getSize();
             this.onResize(sz.width, sz.height);
         }
+        this.onShow();
         this.fireEvent('show', this);
     },
 
@@ -542,15 +574,15 @@ Ext.Window = Ext.extend(Ext.Panel, {
         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;
+        var b = this.getBox();
         this.el.setStyle('display', 'none');
-        this.proxy.shift(b);
+        this.proxy.shift(Ext.apply(b, {
+            callback: this.afterShow.createDelegate(this, [true], false),
+            scope: this,
+            easing: 'easeNone',
+            duration: 0.25,
+            opacity: 0.5
+        }));
     },
 
     /**
@@ -558,7 +590,7 @@ Ext.Window = Ext.extend(Ext.Panel, {
      * @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
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this Window.
      * @return {Ext.Window} this
      */
     hide : function(animateTarget, cb, scope){
@@ -594,6 +626,7 @@ Ext.Window = Ext.extend(Ext.Panel, {
         if(this.keyMap){
             this.keyMap.disable();
         }
+        this.onHide();
         this.fireEvent('hide', this);
     },
 
@@ -604,16 +637,27 @@ Ext.Window = Ext.extend(Ext.Panel, {
         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);
+        this.proxy.shift(Ext.apply(this.animateTarget.getBox(), {
+            callback: this.afterHide,
+            scope: this,
+            duration: 0.25,
+            easing: 'easeNone',
+            opacity: 0
+        }));
     },
 
+    /**
+     * Method that is called immediately before the <code>show</code> event is fired.
+     * Defaults to <code>Ext.emptyFn</code>.
+     */
+    onShow : Ext.emptyFn,
+
+    /**
+     * Method that is called immediately before the <code>hide</code> event is fired.
+     * Defaults to <code>Ext.emptyFn</code>.
+     */
+    onHide : Ext.emptyFn,
+
     // private
     onWindowResize : function(){
         if(this.maximized){
@@ -670,8 +714,8 @@ Ext.Window = Ext.extend(Ext.Panel, {
         }
         if(show !== false){
             this.el.show();
-            this.focus();
-            if(Ext.isMac && Ext.isGecko){ // work around stupid FF 2.0/Mac scroll bar bug
+            this.focus.defer(10, this);
+            if(Ext.isMac && Ext.isGecko2){ // work around stupid FF 2.0/Mac scroll bar bug
                 this.cascade(this.setAutoScroll);
             }
         }
@@ -704,13 +748,20 @@ Ext.Window = Ext.extend(Ext.Panel, {
      */
     close : function(){
         if(this.fireEvent('beforeclose', this) !== false){
-            this.hide(null, function(){
-                this.fireEvent('close', this);
-                this.destroy();
-            }, this);
+            if(this.hidden){
+                this.doClose();
+            }else{
+                this.hide(null, this.doClose, this);
+            }
         }
     },
 
+    // private
+    doClose : function(){
+        this.fireEvent('close', this);
+        this.destroy();
+    },
+
     /**
      * Fits the window within its current container and automatically replaces
      * the {@link #maximizable 'maximize' tool button} with the 'restore' tool button.
@@ -754,9 +805,14 @@ Ext.Window = Ext.extend(Ext.Panel, {
      */
     restore : function(){
         if(this.maximized){
+            var t = this.tools;
             this.el.removeClass('x-window-maximized');
-            this.tools.restore.hide();
-            this.tools.maximize.show();
+            if(t.restore){
+                t.restore.hide();
+            }
+            if(t.maximize){
+                t.maximize.show();
+            }
             this.setPosition(this.restorePos[0], this.restorePos[1]);
             this.setSize(this.restoreSize.width, this.restoreSize.height);
             delete this.restorePos;
@@ -767,8 +823,8 @@ Ext.Window = Ext.extend(Ext.Panel, {
             if(this.dd){
                 this.dd.unlock();
             }
-            if(this.collapsible){
-                this.tools.toggle.show();
+            if(this.collapsible && t.toggle){
+                t.toggle.show();
             }
             this.container.removeClass('x-window-maximized-ct');
 
@@ -789,7 +845,7 @@ Ext.Window = Ext.extend(Ext.Panel, {
 
     // private
     fitContainer : function(){
-        var vs = this.container.getViewSize();
+        var vs = this.container.getViewSize(false);
         this.setSize(vs.width, vs.height);
     },
 
@@ -812,7 +868,7 @@ Ext.Window = Ext.extend(Ext.Panel, {
     /**
      * 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 {String} position (optional, defaults to "tl-bl?") 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
      */
@@ -832,22 +888,44 @@ Ext.Window = Ext.extend(Ext.Panel, {
      * @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;
+        this.clearAnchor();
+        this.anchorTarget = {
+            el: el,
+            alignment: alignment,
+            offsets: 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});
+        }
+        return this.doAnchor();
+    },
+
+    /**
+     * Performs the anchor, using the saved anchorTarget property.
+     * @return {Ext.Window} this
+     * @private
+     */
+    doAnchor : function(){
+        var o = this.anchorTarget;
+        this.alignTo(o.el, o.alignment, o.offsets);
+        return this;
+    },
+
+    /**
+     * Removes any existing anchor from this window. See {@link #anchorTo}.
+     * @return {Ext.Window} this
+     */
+    clearAnchor : function(){
+        if(this.anchorTarget){
+            Ext.EventManager.removeResizeListener(this.doAnchor, this);
+            Ext.EventManager.un(window, 'scroll', this.doAnchor, this);
+            delete this.anchorTarget;
+        }
+        return this;
     },
 
     /**
@@ -866,7 +944,8 @@ Ext.Window = Ext.extend(Ext.Panel, {
 
     /**
      * 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.
+     * fires the {@link #activate} or {@link #deactivate} event depending on which action occurred. This method is
+     * called internally by {@link Ext.WindowMgr}.
      * @param {Boolean} active True to activate the window, false to deactivate it (defaults to false)
      */
     setActive : function(active){
@@ -941,7 +1020,7 @@ Ext.extend(Ext.Window.DD, Ext.dd.DD, {
 });
 /**
  * @class Ext.WindowGroup
- * An object that represents a group of {@link Ext.Window} instances and provides z-order management
+ * An object that manages a group of {@link Ext.Window} instances and provides z-order management
  * and window activation behavior.
  * @constructor
  */
@@ -998,20 +1077,42 @@ Ext.WindowGroup = function(){
 
     return {
         /**
-         * The starting z-index for windows (defaults to 9000)
+         * The starting z-index for windows in this WindowGroup (defaults to 9000)
          * @type Number The z-index value
          */
         zseed : 9000,
 
-        // private
+        /**
+         * <p>Registers a {@link Ext.Window Window} with this WindowManager. This should not
+         * need to be called under normal circumstances. Windows are automatically registered
+         * with a {@link Ext.Window#manager manager} at construction time.</p>
+         * <p>Where this may be useful is moving Windows between two WindowManagers. For example,
+         * to bring the Ext.MessageBox dialog under the same manager as the Desktop's
+         * WindowManager in the desktop sample app:</p><code><pre>
+var msgWin = Ext.MessageBox.getDialog();
+MyDesktop.getDesktop().getManager().register(msgWin);
+</pre></code>
+         * @param {Window} win The Window to register.
+         */
         register : function(win){
+            if(win.manager){
+                win.manager.unregister(win);
+            }
+            win.manager = this;
+
             list[win.id] = win;
             accessList.push(win);
             win.on('hide', activateLast);
         },
 
-        // private
+        /**
+         * <p>Unregisters a {@link Ext.Window Window} from this WindowManager. This should not
+         * need to be called. Windows are automatically unregistered upon destruction.
+         * See {@link #register}.</p>
+         * @param {Window} win The Window to unregister.
+         */
         unregister : function(win){
+            delete win.manager;
             delete list[win.id];
             win.un('hide', activateLast);
             accessList.remove(win);
@@ -1027,7 +1128,7 @@ Ext.WindowGroup = function(){
         },
 
         /**
-         * Brings the specified window to the front of any other active windows.
+         * Brings the specified window to the front of any other active windows in this WindowGroup.
          * @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
@@ -1043,7 +1144,7 @@ Ext.WindowGroup = function(){
         },
 
         /**
-         * Sends the specified window to the back of other active windows.
+         * Sends the specified window to the back of other active windows in this WindowGroup.
          * @param {String/Object} win The id of the window or a {@link Ext.Window} instance
          * @return {Ext.Window} The window
          */
@@ -1055,7 +1156,7 @@ Ext.WindowGroup = function(){
         },
 
         /**
-         * Hides all windows in the group.
+         * Hides all windows in this WindowGroup.
          */
         hideAll : function(){
             for(var id in list){
@@ -1066,7 +1167,7 @@ Ext.WindowGroup = function(){
         },
 
         /**
-         * Gets the currently-active window in the group.
+         * Gets the currently-active window in this WindowGroup.
          * @return {Ext.Window} The active window
          */
         getActive : function(){
@@ -1074,11 +1175,11 @@ Ext.WindowGroup = function(){
         },
 
         /**
-         * Returns zero or more windows in the group using the custom search function passed to this method.
+         * Returns zero or more windows in this WindowGroup 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
+         * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Window being tested.
          * that gets passed to the function if not specified)
          * @return {Array} An array of zero or more matching windows
          */
@@ -1094,10 +1195,10 @@ Ext.WindowGroup = function(){
         },
 
         /**
-         * Executes the specified function once for every window in the group, passing each
+         * Executes the specified function once for every window in this WindowGroup, 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
+         * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Window in the iteration.
          */
         each : function(fn, scope){
             for(var id in list){
@@ -1151,12 +1252,14 @@ Ext.Msg.show({
  * @singleton
  */
 Ext.MessageBox = function(){
-    var dlg, opt, mask, waitTimer;
-    var bodyEl, msgEl, textboxEl, textareaEl, progressBar, pp, iconEl, spacerEl;
-    var buttons, activeTextEl, bwidth, iconCls = '';
+    var dlg, opt, mask, waitTimer,
+        bodyEl, msgEl, textboxEl, textareaEl, progressBar, pp, iconEl, spacerEl,
+        buttons, activeTextEl, bwidth, bufferIcon = '', iconCls = '',
+        buttonNames = ['ok', 'yes', 'no', 'cancel'];
 
     // private
     var handleButton = function(button){
+        buttons[button].blur();
         if(dlg.isVisible()){
             dlg.hide();
             handleHide();
@@ -1169,7 +1272,7 @@ Ext.MessageBox = function(){
         if(opt && opt.cls){
             dlg.el.removeClass(opt.cls);
         }
-        progressBar.reset();
+        progressBar.reset();        
     };
 
     // private
@@ -1185,26 +1288,25 @@ Ext.MessageBox = function(){
 
     // private
     var updateButtons = function(b){
-        var width = 0;
+        var width = 0,
+            cfg;
         if(!b){
-            buttons["ok"].hide();
-            buttons["cancel"].hide();
-            buttons["yes"].hide();
-            buttons["no"].hide();
+            Ext.each(buttonNames, function(name){
+                buttons[name].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();
-                }
+        Ext.iterate(buttons, function(name, btn){
+            cfg = b[name];
+            if(cfg){
+                btn.show();
+                btn.setText(Ext.isString(cfg) ? cfg : Ext.MessageBox.buttonText[name]);
+                width += btn.getEl().getWidth() + 15;
+            }else{
+                btn.hide();
             }
-        }
+        });
         return width;
     };
 
@@ -1215,6 +1317,16 @@ Ext.MessageBox = function(){
          */
         getDialog : function(titleText){
            if(!dlg){
+                var btns = [];
+                
+                buttons = {};
+                Ext.each(buttonNames, function(name){
+                    btns.push(buttons[name] = new Ext.Button({
+                        text: this.buttonText[name],
+                        handler: handleButton.createCallback(name),
+                        hideMode: 'offsets'
+                    }));
+                }, this);
                 dlg = new Ext.Window({
                     autoCreate : true,
                     title:titleText,
@@ -1239,16 +1351,12 @@ Ext.MessageBox = function(){
                         }else{
                             handleButton("cancel");
                         }
-                    }
+                    },
+                    fbar: new Ext.Toolbar({
+                        items: btns,
+                        enableOverflow: false
+                    })
                 });
-                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;
@@ -1291,17 +1399,19 @@ Ext.MessageBox = function(){
             }
             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');
+            var iw = iconCls != '' ? (iconEl.getWidth() + iconEl.getMargins('lr')) : 0,
+                mw = msgEl.getWidth() + msgEl.getMargins('lr'),
+                fw = dlg.getFrameWidth('lr'),
+                bw = dlg.body.getFrameWidth('lr'),
+                w;
+                
             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));
+            w = Math.max(Math.min(opt.width || iw+mw+fw+bw, opt.maxWidth || this.maxWidth),
+                    Math.max(opt.minWidth || this.minWidth, bwidth || 0));
 
             if(opt.prompt === true){
                 activeTextEl.setWidth(w-iw-fw-bw);
@@ -1445,8 +1555,7 @@ Ext.Msg.show({
                 if(opt.multiline){
                     textboxEl.hide();
                     textareaEl.show();
-                    textareaEl.setHeight(typeof opt.multiline == "number" ?
-                        opt.multiline : this.defaultTextHeight);
+                    textareaEl.setHeight(Ext.isNumber(opt.multiline) ? opt.multiline : this.defaultTextHeight);
                     activeTextEl = textareaEl;
                 }else{
                     textboxEl.show();
@@ -1474,42 +1583,42 @@ Ext.Msg.show({
             if(opt.iconCls){
               d.setIconClass(opt.iconCls);
             }
-            this.setIcon(opt.icon);
+            this.setIcon(Ext.isDefined(opt.icon) ? opt.icon : bufferIcon);
+            bwidth = updateButtons(opt.buttons);
+            progressBar.setVisible(opt.progress === true || opt.wait === true);
+            this.updateProgress(0, opt.progressText);
+            this.updateText(opt.msg);
             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);
+                //workaround for window internally enabling keymap in afterShow
+                d.on('show', function(){
+                    if(allowClose === true){
+                        d.keyMap.enable();
+                    }else{
+                        d.keyMap.disable();
+                    }
+                }, this, {single:true});
                 d.show(opt.animEl);
             }
+            if(opt.wait === true){
+                progressBar.wait(opt.waitConfig);
+            }
             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:
+         * to clear any existing icon. This method must be called before the MessageBox is shown.
+         * 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
@@ -1520,6 +1629,11 @@ Ext.MessageBox.ERROR
          * @return {Ext.MessageBox} this
          */
         setIcon : function(icon){
+            if(!dlg){
+                bufferIcon = icon;
+                return;
+            }
+            bufferIcon = undefined;
             if(icon && icon != ''){
                 iconEl.removeClass('x-hidden');
                 iconEl.replaceClass(iconCls, icon);
@@ -1586,7 +1700,7 @@ Ext.MessageBox.ERROR
          * @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 {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to the browser wnidow.
          * @return {Ext.MessageBox} this
          */
         alert : function(title, msg, fn, scope){
@@ -1595,7 +1709,8 @@ Ext.MessageBox.ERROR
                 msg : msg,
                 buttons: this.OK,
                 fn: fn,
-                scope : scope
+                scope : scope,
+                minWidth: this.minWidth
             });
             return this;
         },
@@ -1608,7 +1723,7 @@ Ext.MessageBox.ERROR
          * @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 {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to the browser wnidow.
          * @return {Ext.MessageBox} this
          */
         confirm : function(title, msg, fn, scope){
@@ -1618,7 +1733,8 @@ Ext.MessageBox.ERROR
                 buttons: this.YESNO,
                 fn: fn,
                 scope : scope,
-                icon: this.QUESTION
+                icon: this.QUESTION,
+                minWidth: this.minWidth
             });
             return this;
         },
@@ -1631,7 +1747,7 @@ Ext.MessageBox.ERROR
          * @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 {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to the browser wnidow.
          * @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 '')
@@ -1643,7 +1759,7 @@ Ext.MessageBox.ERROR
                 msg : msg,
                 buttons: this.OKCANCEL,
                 fn: fn,
-                minWidth:250,
+                minWidth: this.minPromptWidth,
                 scope : scope,
                 prompt:true,
                 multiline: multiline,
@@ -1709,16 +1825,22 @@ Ext.MessageBox.ERROR
          */
         maxWidth : 600,
         /**
-         * The minimum width in pixels of the message box (defaults to 110)
+         * The minimum width in pixels of the message box (defaults to 100)
          * @type Number
          */
-        minWidth : 110,
+        minWidth : 100,
         /**
          * 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)
+         * for setting a different minimum width than text-only dialogs may need (defaults to 250).
          * @type Number
          */
         minProgressWidth : 250,
+        /**
+         * The minimum width in pixels of the message box if it is a prompt dialog.  This is useful
+         * for setting a different minimum width than text-only dialogs may need (defaults to 250).
+         * @type Number
+         */
+        minPromptWidth: 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
@@ -1738,151 +1860,151 @@ Ext.MessageBox.ERROR
 /**
  * Shorthand for {@link Ext.MessageBox}
  */
-Ext.Msg = Ext.MessageBox;/**\r
- * @class Ext.dd.PanelProxy\r
- * A custom drag proxy implementation specific to {@link Ext.Panel}s. This class is primarily used internally\r
- * for the Panel's drag drop implementation, and should never need to be created directly.\r
- * @constructor\r
- * @param panel The {@link Ext.Panel} to proxy for\r
- * @param config Configuration options\r
- */\r
-Ext.dd.PanelProxy = function(panel, config){\r
-    this.panel = panel;\r
-    this.id = this.panel.id +'-ddproxy';\r
-    Ext.apply(this, config);\r
-};\r
-\r
-Ext.dd.PanelProxy.prototype = {\r
-    /**\r
-     * @cfg {Boolean} insertProxy True to insert a placeholder proxy element while dragging the panel,\r
-     * false to drag with no proxy (defaults to true).\r
-     */\r
-    insertProxy : true,\r
-\r
-    // private overrides\r
-    setStatus : Ext.emptyFn,\r
-    reset : Ext.emptyFn,\r
-    update : Ext.emptyFn,\r
-    stop : Ext.emptyFn,\r
-    sync: Ext.emptyFn,\r
-\r
-    /**\r
-     * Gets the proxy's element\r
-     * @return {Element} The proxy's element\r
-     */\r
-    getEl : function(){\r
-        return this.ghost;\r
-    },\r
-\r
-    /**\r
-     * Gets the proxy's ghost element\r
-     * @return {Element} The proxy's ghost element\r
-     */\r
-    getGhost : function(){\r
-        return this.ghost;\r
-    },\r
-\r
-    /**\r
-     * Gets the proxy's element\r
-     * @return {Element} The proxy's element\r
-     */\r
-    getProxy : function(){\r
-        return this.proxy;\r
-    },\r
-\r
-    /**\r
-     * Hides the proxy\r
-     */\r
-    hide : function(){\r
-        if(this.ghost){\r
-            if(this.proxy){\r
-                this.proxy.remove();\r
-                delete this.proxy;\r
-            }\r
-            this.panel.el.dom.style.display = '';\r
-            this.ghost.remove();\r
-            delete this.ghost;\r
-        }\r
-    },\r
-\r
-    /**\r
-     * Shows the proxy\r
-     */\r
-    show : function(){\r
-        if(!this.ghost){\r
-            this.ghost = this.panel.createGhost(undefined, undefined, Ext.getBody());\r
-            this.ghost.setXY(this.panel.el.getXY())\r
-            if(this.insertProxy){\r
-                this.proxy = this.panel.el.insertSibling({cls:'x-panel-dd-spacer'});\r
-                this.proxy.setSize(this.panel.getSize());\r
-            }\r
-            this.panel.el.dom.style.display = 'none';\r
-        }\r
-    },\r
-\r
-    // private\r
-    repair : function(xy, callback, scope){\r
-        this.hide();\r
-        if(typeof callback == "function"){\r
-            callback.call(scope || this);\r
-        }\r
-    },\r
-\r
-    /**\r
-     * Moves the proxy to a different position in the DOM.  This is typically called while dragging the Panel\r
-     * to keep the proxy sync'd to the Panel's location.\r
-     * @param {HTMLElement} parentNode The proxy's parent DOM node\r
-     * @param {HTMLElement} before (optional) The sibling node before which the proxy should be inserted (defaults\r
-     * to the parent's last child if not specified)\r
-     */\r
-    moveProxy : function(parentNode, before){\r
-        if(this.proxy){\r
-            parentNode.insertBefore(this.proxy.dom, before);\r
-        }\r
-    }\r
-};\r
-\r
-// private - DD implementation for Panels\r
-Ext.Panel.DD = function(panel, cfg){\r
-    this.panel = panel;\r
-    this.dragData = {panel: panel};\r
-    this.proxy = new Ext.dd.PanelProxy(panel, cfg);\r
-    Ext.Panel.DD.superclass.constructor.call(this, panel.el, cfg);\r
-    var h = panel.header;\r
-    if(h){\r
-        this.setHandleElId(h.id);\r
-    }\r
-    (h ? h : this.panel.body).setStyle('cursor', 'move');\r
-    this.scroll = false;\r
-};\r
-\r
-Ext.extend(Ext.Panel.DD, Ext.dd.DragSource, {\r
-    showFrame: Ext.emptyFn,\r
-    startDrag: Ext.emptyFn,\r
-    b4StartDrag: function(x, y) {\r
-        this.proxy.show();\r
-    },\r
-    b4MouseDown: function(e) {\r
-        var x = e.getPageX();\r
-        var y = e.getPageY();\r
-        this.autoOffset(x, y);\r
-    },\r
-    onInitDrag : function(x, y){\r
-        this.onStartDrag(x, y);\r
-        return true;\r
-    },\r
-    createFrame : Ext.emptyFn,\r
-    getDragEl : function(e){\r
-        return this.proxy.ghost.dom;\r
-    },\r
-    endDrag : function(e){\r
-        this.proxy.hide();\r
-        this.panel.saveState();\r
-    },\r
-\r
-    autoOffset : function(x, y) {\r
-        x -= this.startPageX;\r
-        y -= this.startPageY;\r
-        this.setDelta(x, y);\r
-    }\r
+Ext.Msg = Ext.MessageBox;/**
+ * @class Ext.dd.PanelProxy
+ * A custom drag proxy implementation specific to {@link Ext.Panel}s. This class is primarily used internally
+ * for the Panel's drag drop implementation, and should never need to be created directly.
+ * @constructor
+ * @param panel The {@link Ext.Panel} to proxy for
+ * @param config Configuration options
+ */
+Ext.dd.PanelProxy = function(panel, config){
+    this.panel = panel;
+    this.id = this.panel.id +'-ddproxy';
+    Ext.apply(this, config);
+};
+
+Ext.dd.PanelProxy.prototype = {
+    /**
+     * @cfg {Boolean} insertProxy True to insert a placeholder proxy element while dragging the panel,
+     * false to drag with no proxy (defaults to true).
+     */
+    insertProxy : true,
+
+    // private overrides
+    setStatus : Ext.emptyFn,
+    reset : Ext.emptyFn,
+    update : Ext.emptyFn,
+    stop : Ext.emptyFn,
+    sync: Ext.emptyFn,
+
+    /**
+     * Gets the proxy's element
+     * @return {Element} The proxy's element
+     */
+    getEl : function(){
+        return this.ghost;
+    },
+
+    /**
+     * Gets the proxy's ghost element
+     * @return {Element} The proxy's ghost element
+     */
+    getGhost : function(){
+        return this.ghost;
+    },
+
+    /**
+     * Gets the proxy's element
+     * @return {Element} The proxy's element
+     */
+    getProxy : function(){
+        return this.proxy;
+    },
+
+    /**
+     * Hides the proxy
+     */
+    hide : function(){
+        if(this.ghost){
+            if(this.proxy){
+                this.proxy.remove();
+                delete this.proxy;
+            }
+            this.panel.el.dom.style.display = '';
+            this.ghost.remove();
+            delete this.ghost;
+        }
+    },
+
+    /**
+     * Shows the proxy
+     */
+    show : function(){
+        if(!this.ghost){
+            this.ghost = this.panel.createGhost(undefined, undefined, Ext.getBody());
+            this.ghost.setXY(this.panel.el.getXY());
+            if(this.insertProxy){
+                this.proxy = this.panel.el.insertSibling({cls:'x-panel-dd-spacer'});
+                this.proxy.setSize(this.panel.getSize());
+            }
+            this.panel.el.dom.style.display = 'none';
+        }
+    },
+
+    // private
+    repair : function(xy, callback, scope){
+        this.hide();
+        if(typeof callback == "function"){
+            callback.call(scope || this);
+        }
+    },
+
+    /**
+     * Moves the proxy to a different position in the DOM.  This is typically called while dragging the Panel
+     * to keep the proxy sync'd to the Panel's location.
+     * @param {HTMLElement} parentNode The proxy's parent DOM node
+     * @param {HTMLElement} before (optional) The sibling node before which the proxy should be inserted (defaults
+     * to the parent's last child if not specified)
+     */
+    moveProxy : function(parentNode, before){
+        if(this.proxy){
+            parentNode.insertBefore(this.proxy.dom, before);
+        }
+    }
+};
+
+// private - DD implementation for Panels
+Ext.Panel.DD = function(panel, cfg){
+    this.panel = panel;
+    this.dragData = {panel: panel};
+    this.proxy = new Ext.dd.PanelProxy(panel, cfg);
+    Ext.Panel.DD.superclass.constructor.call(this, panel.el, cfg);
+    var h = panel.header;
+    if(h){
+        this.setHandleElId(h.id);
+    }
+    (h ? h : this.panel.body).setStyle('cursor', 'move');
+    this.scroll = false;
+};
+
+Ext.extend(Ext.Panel.DD, Ext.dd.DragSource, {
+    showFrame: Ext.emptyFn,
+    startDrag: Ext.emptyFn,
+    b4StartDrag: function(x, y) {
+        this.proxy.show();
+    },
+    b4MouseDown: function(e) {
+        var x = e.getPageX();
+        var y = e.getPageY();
+        this.autoOffset(x, y);
+    },
+    onInitDrag : function(x, y){
+        this.onStartDrag(x, y);
+        return true;
+    },
+    createFrame : Ext.emptyFn,
+    getDragEl : function(e){
+        return this.proxy.ghost.dom;
+    },
+    endDrag : function(e){
+        this.proxy.hide();
+        this.panel.saveState();
+    },
+
+    autoOffset : function(x, y) {
+        x -= this.startPageX;
+        y -= this.startPageY;
+        this.setDelta(x, y);
+    }
 });
\ No newline at end of file