Upgrade to ExtJS 3.2.2 - Released 06/02/2010
[extjs.git] / src / widgets / MessageBox.js
index 3f2f0c9..97fc826 100644 (file)
@@ -1,6 +1,6 @@
 /*!
- * Ext JS Library 3.0.0
- * Copyright(c) 2006-2009 Ext JS, LLC
+ * Ext JS Library 3.2.2
+ * Copyright(c) 2006-2010 Ext JS, Inc.
  * licensing@extjs.com
  * http://www.extjs.com/license
  */
@@ -36,12 +36,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();
@@ -54,7 +56,7 @@ Ext.MessageBox = function(){
         if(opt && opt.cls){
             dlg.el.removeClass(opt.cls);
         }
-        progressBar.reset();
+        progressBar.reset();        
     };
 
     // private
@@ -70,26 +72,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;
     };
 
@@ -100,6 +101,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,
@@ -124,16 +135,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;
@@ -176,17 +183,19 @@ Ext.MessageBox = function(){
             }
             msgEl.update(text || ' ');
 
-            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);
@@ -330,8 +339,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();
@@ -356,45 +364,45 @@ Ext.Msg.show({
                     d.focusEl = db;
                 }
             }
-            if(opt.iconCls){
+            if(Ext.isDefined(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
@@ -405,6 +413,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);
@@ -471,7 +484,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){
@@ -480,7 +493,8 @@ Ext.MessageBox.ERROR
                 msg : msg,
                 buttons: this.OK,
                 fn: fn,
-                scope : scope
+                scope : scope,
+                minWidth: this.minWidth
             });
             return this;
         },
@@ -493,7 +507,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){
@@ -503,7 +517,8 @@ Ext.MessageBox.ERROR
                 buttons: this.YESNO,
                 fn: fn,
                 scope : scope,
-                icon: this.QUESTION
+                icon: this.QUESTION,
+                minWidth: this.minWidth
             });
             return this;
         },
@@ -516,7 +531,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 '')
@@ -528,7 +543,7 @@ Ext.MessageBox.ERROR
                 msg : msg,
                 buttons: this.OKCANCEL,
                 fn: fn,
-                minWidth:250,
+                minWidth: this.minPromptWidth,
                 scope : scope,
                 prompt:true,
                 multiline: multiline,
@@ -594,16 +609,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