/** * @class Ext.MessageBox *

Utility class for generating different styles of message boxes. The alias Ext.Msg can also be used.

*

Note that the MessageBox is asynchronous. Unlike a regular JavaScript alert (which will halt * browser execution), showing a MessageBox will not cause the code to stop. For this reason, if you have code * that should only run after some user feedback from the MessageBox, you must use a callback function * (see the function parameter for {@link #show} for more details).

*

Example usage:

*

// Basic alert:
Ext.Msg.alert('Status', 'Changes saved successfully.');

// Prompt for user data and process the result using a callback:
Ext.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
    if (btn == 'ok'){
        // process text value and close...
    }
});

// Show a dialog using config options:
Ext.Msg.show({
   title:'Save Changes?',
   msg: 'You are closing a tab that has unsaved changes. Would you like to save your changes?',
   buttons: Ext.Msg.YESNOCANCEL,
   fn: processResult,
   animEl: 'elId',
   icon: Ext.MessageBox.QUESTION
});
* @singleton */ Ext.MessageBox = function(){ var dlg, opt, mask, waitTimer; var bodyEl, msgEl, textboxEl, textareaEl, progressBar, pp, iconEl, spacerEl; var buttons, activeTextEl, bwidth, iconCls = ''; // private var handleButton = function(button){ if(dlg.isVisible()){ dlg.hide(); handleHide(); Ext.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value, opt], 1); } }; // private var handleHide = function(){ if(opt && opt.cls){ dlg.el.removeClass(opt.cls); } progressBar.reset(); }; // private var handleEsc = function(d, k, e){ if(opt && opt.closable !== false){ dlg.hide(); handleHide(); } if(e){ e.stopEvent(); } }; // private var updateButtons = function(b){ var width = 0; if(!b){ buttons['ok'].hide(); buttons['cancel'].hide(); buttons['yes'].hide(); buttons['no'].hide(); return width; } dlg.footer.dom.style.display = ''; for(var k in buttons){ if(typeof buttons[k] != 'function'){ if(b[k]){ buttons[k].show(); buttons[k].setText(typeof b[k] == 'string' ? b[k] : Ext.MessageBox.buttonText[k]); width += buttons[k].el.getWidth()+15; }else{ buttons[k].hide(); } } } return width; }; return {
/** * Returns a reference to the underlying {@link Ext.Window} element * @return {Ext.Window} The window */ getDialog : function(titleText){ if(!dlg){ dlg = new Ext.Window({ autoCreate : true, title:titleText, resizable:false, constrain:true, constrainHeader:true, minimizable : false, maximizable : false, stateful: false, modal: true, shim:true, buttonAlign:'center', width:400, height:100, minHeight: 80, plain:true, footer:true, closable:true, close : function(){ if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){ handleButton('no'); }else{ handleButton('cancel'); } } }); buttons = {}; var bt = this.buttonText; //TODO: refactor this block into a buttons config to pass into the Window constructor buttons['ok'] = dlg.addButton(bt['ok'], handleButton.createCallback('ok')); buttons['yes'] = dlg.addButton(bt['yes'], handleButton.createCallback('yes')); buttons['no'] = dlg.addButton(bt['no'], handleButton.createCallback('no')); buttons['cancel'] = dlg.addButton(bt['cancel'], handleButton.createCallback('cancel')); buttons['ok'].hideMode = buttons['yes'].hideMode = buttons['no'].hideMode = buttons['cancel'].hideMode = 'offsets'; dlg.render(document.body); dlg.getEl().addClass('x-window-dlg'); mask = dlg.mask; bodyEl = dlg.body.createChild({ html:'

' }); iconEl = Ext.get(bodyEl.dom.firstChild); var contentEl = bodyEl.dom.childNodes[1]; msgEl = Ext.get(contentEl.firstChild); textboxEl = Ext.get(contentEl.childNodes[2].firstChild); textboxEl.enableDisplayMode(); textboxEl.addKeyListener([10,13], function(){ if(dlg.isVisible() && opt && opt.buttons){ if(opt.buttons.ok){ handleButton('ok'); }else if(opt.buttons.yes){ handleButton('yes'); } } }); textareaEl = Ext.get(contentEl.childNodes[2].childNodes[1]); textareaEl.enableDisplayMode(); progressBar = new Ext.ProgressBar({ renderTo:bodyEl }); bodyEl.createChild({cls:'x-clear'}); } return dlg; },
/** * Updates the message box body text * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to * the XHTML-compliant non-breaking space character ' ') * @return {Ext.MessageBox} this */ updateText : function(text){ if(!dlg.isVisible() && !opt.width){ dlg.setSize(this.maxWidth, 100); // resize first so content is never clipped from previous shows } msgEl.update(text || ' '); var iw = iconCls != '' ? (iconEl.getWidth() + iconEl.getMargins('lr')) : 0; var mw = msgEl.getWidth() + msgEl.getMargins('lr'); var fw = dlg.getFrameWidth('lr'); var bw = dlg.body.getFrameWidth('lr'); if (Ext.isIE && iw > 0){ //3 pixels get subtracted in the icon CSS for an IE margin issue, //so we have to add it back here for the overall width to be consistent iw += 3; } var w = Math.max(Math.min(opt.width || iw+mw+fw+bw, this.maxWidth), Math.max(opt.minWidth || this.minWidth, bwidth || 0)); if(opt.prompt === true){ activeTextEl.setWidth(w-iw-fw-bw); } if(opt.progress === true || opt.wait === true){ progressBar.setSize(w-iw-fw-bw); } if(Ext.isIE && w == bwidth){ w += 4; //Add offset when the content width is smaller than the buttons. } dlg.setSize(w, 'auto').center(); return this; },
/** * Updates a progress-style message box's text and progress bar. Only relevant on message boxes * initiated via {@link Ext.MessageBox#progress} or {@link Ext.MessageBox#wait}, * or by calling {@link Ext.MessageBox#show} with progress: true. * @param {Number} value Any number between 0 and 1 (e.g., .5, defaults to 0) * @param {String} progressText The progress text to display inside the progress bar (defaults to '') * @param {String} msg The message box's body text is replaced with the specified string (defaults to undefined * so that any existing body text will not get overwritten by default unless a new value is passed in) * @return {Ext.MessageBox} this */ updateProgress : function(value, progressText, msg){ progressBar.updateProgress(value, progressText); if(msg){ this.updateText(msg); } return this; },
/** * Returns true if the message box is currently displayed * @return {Boolean} True if the message box is visible, else false */ isVisible : function(){ return dlg && dlg.isVisible(); },
/** * Hides the message box if it is displayed * @return {Ext.MessageBox} this */ hide : function(){ var proxy = dlg ? dlg.activeGhost : null; if(this.isVisible() || proxy){ dlg.hide(); handleHide(); if (proxy){ // unghost is a private function, but i saw no better solution // to fix the locking problem when dragging while it closes dlg.unghost(false, false); } } return this; },
/** * Displays a new message box, or reinitializes an existing message box, based on the config options * passed in. All display functions (e.g. prompt, alert, etc.) on MessageBox call this function internally, * although those calls are basic shortcuts and do not support all of the config options allowed here. * @param {Object} config The following config options are supported: * Example usage: *

Ext.Msg.show({
   title: 'Address',
   msg: 'Please enter your address:',
   width: 300,
   buttons: Ext.MessageBox.OKCANCEL,
   multiline: true, // show a multiline textarea using the {@link #defaultTextHeight}
   fn: saveAddress,
   animEl: 'addAddressBtn',
   icon: Ext.MessageBox.INFO
});
* @return {Ext.MessageBox} this */ show : function(options){ if(this.isVisible()){ this.hide(); } opt = options; var d = this.getDialog(opt.title || ' '); d.setTitle(opt.title || ' '); var allowClose = (opt.closable !== false && opt.progress !== true && opt.wait !== true); d.tools.close.setDisplayed(allowClose); activeTextEl = textboxEl; opt.prompt = opt.prompt || (opt.multiline ? true : false); if(opt.prompt){ if(opt.multiline){ textboxEl.hide(); textareaEl.show(); textareaEl.setHeight(typeof opt.multiline == 'number' ? opt.multiline : this.defaultTextHeight); activeTextEl = textareaEl; }else{ textboxEl.show(); textareaEl.hide(); } }else{ textboxEl.hide(); textareaEl.hide(); } activeTextEl.dom.value = opt.value || ''; if(opt.prompt){ d.focusEl = activeTextEl; }else{ var bs = opt.buttons; var db = null; if(bs && bs.ok){ db = buttons['ok']; }else if(bs && bs.yes){ db = buttons['yes']; } if (db){ d.focusEl = db; } } if(opt.iconCls){ d.setIconClass(opt.iconCls); } this.setIcon(opt.icon); if(opt.cls){ d.el.addClass(opt.cls); } d.proxyDrag = opt.proxyDrag === true; d.modal = opt.modal !== false; d.mask = opt.modal !== false ? mask : false; d.on('show', function(){ //workaround for window internally enabling keymap in afterShow d.keyMap.setDisabled(allowClose !== true); d.doLayout(); this.setIcon(opt.icon); bwidth = updateButtons(opt.buttons); progressBar.setVisible(opt.progress === true || opt.wait === true); this.updateProgress(0, opt.progressText); this.updateText(opt.msg); if(opt.wait === true){ progressBar.wait(opt.waitConfig); } }, this, {single:true}); if(!d.isVisible()){ // force it to the end of the z-index stack so it gets a cursor in FF document.body.appendChild(dlg.el.dom); d.setAnimateTarget(opt.animEl); d.show(opt.animEl); } return this; },
/** * Adds the specified icon to the dialog. By default, the class 'ext-mb-icon' is applied for default * styling, and the class passed in is expected to supply the background image url. Pass in empty string ('') * to clear any existing icon. The following built-in icon classes are supported, but you can also pass * in a custom class name: *
Ext.MessageBox.INFO
Ext.MessageBox.WARNING
Ext.MessageBox.QUESTION
Ext.MessageBox.ERROR
         *
* @param {String} icon A CSS classname specifying the icon's background image url, or empty string to clear the icon * @return {Ext.MessageBox} this */ setIcon : function(icon){ if(icon && icon != ''){ iconEl.removeClass('x-hidden'); iconEl.replaceClass(iconCls, icon); bodyEl.addClass('x-dlg-icon'); iconCls = icon; }else{ iconEl.replaceClass(iconCls, 'x-hidden'); bodyEl.removeClass('x-dlg-icon'); iconCls = ''; } return this; },
/** * Displays a message box with a progress bar. This message box has no buttons and is not closeable by * the user. You are responsible for updating the progress bar as needed via {@link Ext.MessageBox#updateProgress} * and closing the message box when the process is complete. * @param {String} title The title bar text * @param {String} msg The message box body text * @param {String} progressText (optional) The text to display inside the progress bar (defaults to '') * @return {Ext.MessageBox} this */ progress : function(title, msg, progressText){ this.show({ title : title, msg : msg, buttons: false, progress:true, closable:false, minWidth: this.minProgressWidth, progressText: progressText }); return this; },
/** * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user * interaction while waiting for a long-running process to complete that does not have defined intervals. * You are responsible for closing the message box when the process is complete. * @param {String} msg The message box body text * @param {String} title (optional) The title bar text * @param {Object} config (optional) A {@link Ext.ProgressBar#waitConfig} object * @return {Ext.MessageBox} this */ wait : function(msg, title, config){ this.show({ title : title, msg : msg, buttons: false, closable:false, wait:true, modal:true, minWidth: this.minProgressWidth, waitConfig: config }); return this; },
/** * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript alert prompt). * If a callback function is passed it will be called after the user clicks the button, and the * id of the button that was clicked will be passed as the only parameter to the callback * (could also be the top-right close button). * @param {String} title The title bar text * @param {String} msg The message box body text * @param {Function} fn (optional) The callback function invoked after the message box is closed * @param {Object} scope (optional) The scope of the callback function * @return {Ext.MessageBox} this */ alert : function(title, msg, fn, scope){ this.show({ title : title, msg : msg, buttons: this.OK, fn: fn, scope : scope }); return this; },
/** * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's confirm). * If a callback function is passed it will be called after the user clicks either button, * and the id of the button that was clicked will be passed as the only parameter to the callback * (could also be the top-right close button). * @param {String} title The title bar text * @param {String} msg The message box body text * @param {Function} fn (optional) The callback function invoked after the message box is closed * @param {Object} scope (optional) The scope of the callback function * @return {Ext.MessageBox} this */ confirm : function(title, msg, fn, scope){ this.show({ title : title, msg : msg, buttons: this.YESNO, fn: fn, scope : scope, icon: this.QUESTION }); return this; },
/** * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to JavaScript's prompt). * The prompt can be a single-line or multi-line textbox. If a callback function is passed it will be called after the user * clicks either button, and the id of the button that was clicked (could also be the top-right * close button) and the text that was entered will be passed as the two parameters to the callback. * @param {String} title The title bar text * @param {String} msg The message box body text * @param {Function} fn (optional) The callback function invoked after the message box is closed * @param {Object} scope (optional) The scope of the callback function * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight * property, or the height in pixels to create the textbox (defaults to false / single-line) * @param {String} value (optional) Default value of the text input element (defaults to '') * @return {Ext.MessageBox} this */ prompt : function(title, msg, fn, scope, multiline, value){ this.show({ title : title, msg : msg, buttons: this.OKCANCEL, fn: fn, minWidth:250, scope : scope, prompt:true, multiline: multiline, value: value }); return this; },
/** * Button config that displays a single OK button * @type Object */ OK : {ok:true},
/** * Button config that displays a single Cancel button * @type Object */ CANCEL : {cancel:true},
/** * Button config that displays OK and Cancel buttons * @type Object */ OKCANCEL : {ok:true, cancel:true},
/** * Button config that displays Yes and No buttons * @type Object */ YESNO : {yes:true, no:true},
/** * Button config that displays Yes, No and Cancel buttons * @type Object */ YESNOCANCEL : {yes:true, no:true, cancel:true},
/** * The CSS class that provides the INFO icon image * @type String */ INFO : 'ext-mb-info',
/** * The CSS class that provides the WARNING icon image * @type String */ WARNING : 'ext-mb-warning',
/** * The CSS class that provides the QUESTION icon image * @type String */ QUESTION : 'ext-mb-question',
/** * The CSS class that provides the ERROR icon image * @type String */ ERROR : 'ext-mb-error',
/** * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75) * @type Number */ defaultTextHeight : 75,
/** * The maximum width in pixels of the message box (defaults to 600) * @type Number */ maxWidth : 600,
/** * The minimum width in pixels of the message box (defaults to 110) * @type Number */ minWidth : 110,
/** * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful * for setting a different minimum width than text-only dialogs may need (defaults to 250) * @type Number */ minProgressWidth : 250,
/** * An object containing the default button text strings that can be overriden for localized language support. * Supported properties are: ok, cancel, yes and no. Generally you should include a locale-specific * resource file for handling language support across the framework. * Customize the default text like so: Ext.MessageBox.buttonText.yes = 'oui'; //french * @type Object */ buttonText : { ok : 'OK', cancel : 'Cancel', yes : 'Yes', no : 'No' } }; }();
/** * Shorthand for {@link Ext.MessageBox} */ Ext.Msg = Ext.MessageBox;