// @define Ext.MessageBox, Ext.Msg
/**
* Utility class for generating different styles of message boxes. The singleton instance,
* Ext.MessageBox alias `Ext.Msg` can also be used.
*
* Note that a 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 #method-show}
* for more details).
*
* Basic alert
*
* @example
* Ext.Msg.alert('Status', 'Changes saved successfully.');
*
* Prompt for user data and process the result using a callback
*
* @example
* 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
*
* @example
* Ext.Msg.show({
* title:'Save Changes?',
* message: 'You are closing a tab that has unsaved changes. Do you want to save changes?',
* buttons: Ext.Msg.YESNOCANCEL,
* icon: Ext.Msg.QUESTION,
* fn: function(btn) {
* if (btn === 'yes') {
* console.log('Yes pressed');
* } else if (btn === 'no') {
* console.log('No pressed');
* } else {
* console.log('Cancel pressed');
* }
* }
* });
*
* Showing Ext.Msg while it's already shown will cause the visible instance to be
* overwritten with the newly passed config. While this may be the desired outcome, you
* can also create a new MessageBox that can exist alongside the Ext.Msg
* singleton instance.
*
* @example
* var myMsg = Ext.create('Ext.window.MessageBox', {
* // set closeAction to 'destroy' if this instance is not
* // intended to be reused by the application
* closeAction: 'destroy'
* }).show({
* title: 'Custom MessageBox Instance',
* message: 'I can exist along with Ext.Msg'
* });
*
* Ext.Msg.alert('Overlapping', 'Ext.Msg instance');
*
* ## Static Values
*
* The following values can be utilized by Ext.window.MessageBox and Ext.Msg:
*
* OK : {text: 'OK', itemId: 'ok'}
* YES : {text: 'Yes', itemId: 'yes'}
* NO : {text: 'No', itemId: 'no'}
* CANCEL: {text: 'Cancel', itemId: 'cancel'}
*
* INFO : Ext.baseCSSPrefix + 'msgbox-info'
* WARNING : Ext.baseCSSPrefix + 'msgbox-warning'
* QUESTION: Ext.baseCSSPrefix + 'msgbox-question'
* ERROR : Ext.baseCSSPrefix + 'msgbox-error'
*
* OKCANCEL: [
* {text: 'Cancel', itemId: 'cancel'},
* {text: 'OK', itemId: 'ok'}
* ]
*
* YESNOCANCEL: [
* {text: 'Cancel', itemId: 'cancel'},
* {text: 'No', itemId: 'no'},
* {text: 'Yes', itemId: 'yes'}
* ]
*
* YESNO: [
* {text: 'No', itemId: 'no'},
* {text: 'Yes', itemId: 'yes'}
* ]
*
*/
Ext.define('Ext.window.MessageBox', {
extend: 'Ext.window.Window',
requires: [
'Ext.toolbar.Toolbar',
'Ext.form.field.Text',
'Ext.form.field.TextArea',
'Ext.button.Button',
'Ext.layout.container.Anchor',
'Ext.layout.container.HBox',
'Ext.ProgressBar'
],
alias: 'widget.messagebox',
/**
* @property
* Button config that displays a single OK button
*/
OK: 1,
/**
* @property
* Button config that displays a single Yes button
*/
YES: 2,
/**
* @property
* Button config that displays a single No button
*/
NO: 4,
/**
* @property
* Button config that displays a single Cancel button
*/
CANCEL: 8,
/**
* @property
* Button config that displays OK and Cancel buttons
*/
OKCANCEL: 9,
/**
* @property
* Button config that displays Yes and No buttons
*/
YESNO: 6,
/**
* @property
* Button config that displays Yes, No and Cancel buttons
*/
YESNOCANCEL: 14,
/**
* @property
* The CSS class that provides the INFO icon image
*/
INFO: Ext.baseCSSPrefix + 'message-box-info',
/**
* @property
* The CSS class that provides the WARNING icon image
*/
WARNING: Ext.baseCSSPrefix + 'message-box-warning',
/**
* @property
* The CSS class that provides the QUESTION icon image
*/
QUESTION: Ext.baseCSSPrefix + 'message-box-question',
/**
* @property
* The CSS class that provides the ERROR icon image
*/
ERROR: Ext.baseCSSPrefix + 'message-box-error',
// hide it by offsets. Windows are hidden on render by default.
hideMode: 'offsets',
closeAction: 'hide',
resizable: false,
scrollable: true,
title: ' ',
defaultMinWidth: 250,
defaultMaxWidth: 600,
defaultMinHeight: 110,
defaultMaxHeight: 500,
// Forcibly set these to null on the prototype to override anything set higher in
// the hierarchy
minWidth: null,
maxWidth: null,
minHeight: null,
maxHeight: null,
constrain: true,
cls: [Ext.baseCSSPrefix + 'message-box', Ext.baseCSSPrefix + 'hidden-offsets'],
layout: {
type: 'vbox',
align: 'stretch'
},
// We want to shrinkWrap around all docked items
shrinkWrapDock: true,
/**
* @property
* The default height in pixels of the message box's multiline textarea if displayed.
*/
defaultTextHeight: 75,
/**
* @property
* 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.
*/
minProgressWidth: 250,
/**
* @property
* 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.
*/
minPromptWidth: 250,
/**
* @property
* 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.window.MessageBox.buttonText.yes = "oui"; //french
* @locale
*/
buttonText: {
ok: 'OK',
yes: 'Yes',
no: 'No',
cancel: 'Cancel'
},
buttonIds: [
'ok', 'yes', 'no', 'cancel'
],
baseIconCls: Ext.baseCSSPrefix + 'message-box-icon',
ariaRole: 'alertdialog',
makeButton: function(btnIdx) {
var btnId = this.buttonIds[btnIdx];
return new Ext.button.Button({
handler: this.btnCallback,
itemId: btnId,
scope: this,
text: this.buttonText[btnId],
minWidth: 75
});
},
btnCallback: function(btn, event) {
var me = this,
value, field;
// If this is caused by a keydown event (eg: SPACE on a Button), then the
// hide will throw focus back to the previously focused element which will
// then recieve an unexpected keyup event.
// So defer callback handling until the upcoming keyup event.
if (event && event.type === 'keydown' && !event.isSpecialKey()) {
event.getTarget(null, null, true).on({
keyup: function(e) {
me.btnCallback(btn, e);
},
single: true
});
return;
}
if (me.cfg.prompt || me.cfg.multiline) {
if (me.cfg.multiline) {
field = me.textArea;
}
else {
field = me.textField;
}
value = field.getValue();
field.reset();
}
// Component.onHide blurs the active element if the Component contains the active element
me.hide();
me.userCallback(btn.itemId, value, me.cfg);
},
hide: function() {
var me = this,
cls = me.cfg ? me.cfg.cls : '';
me.progressBar.reset();
if (cls) {
me.removeCls(cls);
}
me.callParent(arguments);
},
/**
* @private
*/
constructor: function(cfg) {
var me = this;
me.callParent(arguments);
// set the default min/max/Width/Height to the initially configured min/max/Width/Height
// so that it will be used as the default when reconfiguring.
me.minWidth = me.defaultMinWidth = (me.minWidth || me.defaultMinWidth);
me.maxWidth = me.defaultMaxWidth = (me.maxWidth || me.defaultMaxWidth);
me.minHeight = me.defaultMinHeight = (me.minHeight || me.defaultMinHeight);
me.maxHeight = me.defaultMaxHeight = (me.maxHeight || me.defaultMaxHeight);
},
initComponent: function(cfg) {
var me = this,
baseId = me.id,
i, button;
// A title or iconCls could have been passed in the config to the constructor.
me.title = me.title || ' ';
me.iconCls = me.iconCls || '';
me.topContainer = new Ext.container.Container({
layout: 'hbox',
padding: 10,
style: {
overflow: 'hidden'
},
items: [
me.iconComponent = new Ext.Component({
cls: me.baseIconCls
}),
me.promptContainer = new Ext.container.Container({
flex: 1,
layout: {
type: 'vbox',
align: 'stretch'
},
items: [
me.msg = new Ext.Component({
id: baseId + '-msg',
cls: me.baseCls + '-text'
}),
me.textField = new Ext.form.field.Text({
id: baseId + '-textfield',
enableKeyEvents: true,
ariaAttributes: {
'aria-labelledby': me.msg.id
},
listeners: {
keydown: me.onPromptKey,
scope: me
}
}),
me.textArea = new Ext.form.field.TextArea({
id: baseId + '-textarea',
height: 75,
ariaAttributes: {
'aria-labelledby': me.msg.id
}
})
]
})
]
});
me.progressBar = new Ext.ProgressBar({
id: baseId + '-progressbar',
margin: '0 10 10 10'
});
me.items = [me.topContainer, me.progressBar];
// Create the buttons based upon passed bitwise config
me.msgButtons = [];
for (i = 0; i < 4; i++) {
button = me.makeButton(i);
me.msgButtons[button.itemId] = button;
me.msgButtons.push(button);
}
me.bottomTb = new Ext.toolbar.Toolbar({
id: baseId + '-toolbar',
ui: 'footer',
dock: 'bottom',
focusableContainer: false,
ariaRole: null,
layout: {
pack: { left: 'start', right: 'end' }[me.buttonAlign] || 'center'
},
items: [
me.msgButtons[0],
me.msgButtons[1],
me.msgButtons[2],
me.msgButtons[3]
]
});
me.dockedItems = [me.bottomTb];
me.on('close', me.onClose, me);
me.callParent();
},
afterRender: function() {
var me = this;
me.callParent(arguments);
// These fields do not have a visible label, we're using message component instead.
// Input elements have aria-labelledby pointing to the message component's id;
// "for" attributes on the labelEl are redundant and get in the way.
me.textField.labelEl.dom.removeAttribute('for');
me.textArea.labelEl.dom.removeAttribute('for');
},
onClose: function() {
var btn = this.msgButtons[3];
if (btn) {
this.btnCallback(btn);
}
},
onPromptKey: function(textField, e) {
var me = this,
okButton = me.msgButtons.ok,
yesButton = me.msgButtons.yes;
if (e.keyCode === e.RETURN || e.keyCode === 10) {
if (okButton.isVisible() && !okButton.isDisabled()) {
okButton.handler.call(me, okButton);
}
else if (yesButton.isVisible() && !yesButton.isDisabled()) {
yesButton.handler.call(me, yesButton);
}
}
},
reconfigure: function(cfg) {
var me = this,
buttons = 0,
hideToolbar = true,
oldButtonText = me.buttonText,
resizer = me.resizer,
header = me.header,
headerCfg = header && !header.isHeader,
message = cfg && (cfg.message || cfg.msg),
buttonTips = cfg.buttonTips,
title, iconCls, resizeTracker, width, height, i, textArea,
textField, msg, progressBar, msgButtons, wait, tool;
// Restore default buttonText before reconfiguring.
me.updateButtonText();
me.cfg = cfg = cfg || {};
wait = cfg.wait;
if (cfg.width) {
width = cfg.width;
}
if (cfg.height) {
height = cfg.height;
}
me.minWidth = cfg.minWidth || me.defaultMinWidth;
me.maxWidth = cfg.maxWidth || me.defaultMaxWidth;
me.minHeight = cfg.minHeight || me.defaultMinHeight;
me.maxHeight = cfg.maxHeight || me.defaultMaxHeight;
if ('maskClickAction' in cfg) {
me.maskClickAction = cfg.maskClickAction;
}
else {
delete me.maskClickAction;
}
if (resizer) {
resizeTracker = resizer.resizeTracker;
resizer.minWidth = resizeTracker.minWidth = me.minWidth;
resizer.maxWidth = resizeTracker.maxWidth = me.maxWidth;
resizer.minHeight = resizeTracker.minHeight = me.minHeight;
resizer.maxHeight = resizeTracker.maxHeight = me.maxHeight;
}
// Previous default is rarely going to be valid
delete me.defaultFocus;
if (cfg.defaultFocus) {
me.defaultFocus = cfg.defaultFocus;
}
// clear any old animateTarget
me.animateTarget = cfg.animateTarget || undefined;
// Defaults to modal
me.modal = cfg.modal !== false;
// Show the title/icon if a title/iconCls config was passed in the config
// to either the constructor or the show() method. Note that anything
// passed in the config should win.
//
// Note that if there is no title/iconCls in the config, check the headerCfg
// and default to the instance properties. This works because there are default
// values defined in initComponent.
if (cfg.title != null) {
title = cfg.title;
}
else if (headerCfg && header.title != null) {
title = header.title;
}
else {
title = me.title;
}
if (cfg.iconCls != null) {
iconCls = cfg.iconCls;
}
else if (headerCfg && header.iconCls != null) {
iconCls = header.iconCls;
}
else {
iconCls = me.iconCls;
}
me.setTitle(title);
me.setIconCls(iconCls);
// Extract button configs
if (Ext.isObject(cfg.buttons)) {
me.buttonText = cfg.buttons;
buttons = 0;
}
else {
me.buttonText = cfg.buttonText || me.buttonText;
buttons = Ext.isNumber(cfg.buttons) ? cfg.buttons : 0;
}
Ext.each(me.buttonIds, function(buttonId) {
me.msgButtons[buttonId].setTooltip((buttonTips && buttonTips[buttonId]) || null);
});
// Apply custom-configured buttonText
// Infer additional buttons from the specified property names in the buttonText object
buttons = buttons | me.updateButtonText();
// Restore buttonText. Next run of reconfigure will restore to prototype's buttonText
me.buttonText = oldButtonText;
// During the on render, or size resetting layouts, and in subsequent hiding and showing,
// we need to suspend layouts, and flush at the end when the Window's children
// are at their final visibility.
Ext.suspendLayouts();
me.width = me.height = null;
if (width || height) {
if (width) {
me.setWidth(width);
}
if (height) {
me.setHeight(height);
}
}
if (!me.rendered) {
me.render(Ext.getBody());
}
// Hide or show the close tool
me.closable = cfg.closable !== false && !wait;
// We need to redefine `header` because me.setIconCls() could create a Header instance.
header = me.header;
if (header) {
tool = header.child('[type=close]');
if (tool) {
tool.setVisible(me.closable);
}
// Hide or show the header
if (!cfg.title && !me.closable && !cfg.iconCls) {
header.hide();
}
else {
header.show();
}
}
// Default to dynamic drag: drag the window, not a ghost
me.liveDrag = !cfg.proxyDrag;
// wrap the user callback
me.userCallback = Ext.Function.bindCallback(
cfg.callback || cfg.fn || Ext.emptyFn, cfg.scope || Ext.global
);
// Hide or show the icon Component
me.setIcon(cfg.icon);
// Hide or show the message area
msg = me.msg;
if (message) {
msg.setHtml(message);
msg.show();
// As per WAI-ARIA spec, the alertdialog element should point to message element
// via aria-describedby attribute.
me.ariaEl.dom.setAttribute('aria-describedby', msg.id);
}
else {
msg.hide();
me.ariaEl.dom.removeAttribute('aria-describedby');
}
// Hide or show the input field
textArea = me.textArea;
textField = me.textField;
if (cfg.prompt || cfg.multiline) {
me.multiline = cfg.multiline;
if (cfg.multiline) {
textArea.setValue(cfg.value);
textArea.setHeight(cfg.defaultTextHeight || me.defaultTextHeight);
textArea.show();
textField.hide();
me.defaultFocus = textArea;
}
else {
textField.setValue(cfg.value);
textArea.hide();
textField.show();
me.defaultFocus = textField;
}
// When either input field is displayed, it will reference the message component's
// element via aria-labelledby. In such cases we need to remove aria-describedby
// from the window ariaEl to avoid the message being announced twice.
me.ariaEl.dom.removeAttribute('aria-describedby');
}
else {
textArea.hide();
textField.hide();
}
// Hide or show the progress bar
progressBar = me.progressBar;
if (cfg.progress || wait) {
progressBar.show();
me.updateProgress(0, cfg.progressText);
me.defaultFocus = progressBar;
if (wait) {
progressBar.wait(wait === true ? cfg.waitConfig : wait);
}
}
else {
progressBar.hide();
}
// Hide or show buttons depending on flag value sent.
msgButtons = me.msgButtons;
for (i = 0; i < 4; i++) {
if (buttons & Math.pow(2, i)) {
// Default to focus on the first visible button if focus not already set
if (!me.defaultFocus) {
me.defaultFocus = msgButtons[i];
}
msgButtons[i].show();
hideToolbar = false;
}
else {
msgButtons[i].hide();
}
}
// Hide toolbar if no buttons to show
if (hideToolbar) {
me.bottomTb.hide();
}
else {
me.bottomTb.show();
}
Ext.resumeLayouts(true);
},
/**
* @private
* Set button text according to current buttonText property object
* @return {Number} The buttons bitwise flag based upon the button IDs specified
* in the buttonText property.
*/
updateButtonText: function() {
var me = this,
buttonText = me.buttonText,
buttons = 0,
btnId, btn;
for (btnId in buttonText) {
if (buttonText.hasOwnProperty(btnId)) {
btn = me.msgButtons[btnId];
if (btn) {
if (me.cfg && me.cfg.buttonText) {
buttons = buttons | Math.pow(2, Ext.Array.indexOf(me.buttonIds, btnId));
}
if (btn.text !== buttonText[btnId]) {
btn.setText(buttonText[btnId]);
}
}
}
}
return buttons;
},
/**
* Displays a new message box, or re-initializes 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.
*
* Example usage:
*
* Ext.Msg.show({
* title: 'Address',
* message: 'Please enter your address:',
* width: 300,
* buttons: Ext.Msg.OKCANCEL,
* multiline: true,
* fn: saveAddress,
* animateTarget: 'addAddressBtn',
* icon: Ext.window.MessageBox.INFO
* });
*
* @param {Object} cfg The following config options are supported:
*
* @param {String/Ext.dom.Element} [cfg.animateTarget]
* An id or Element from which the message box should animate as it opens and closes.
*
* @param {Number} [cfg.buttons=false]
* A bitwise button specifier consisting of the sum of any of the following constants:
*
* - Ext.MessageBox.OK
* - Ext.MessageBox.YES
* - Ext.MessageBox.NO
* - Ext.MessageBox.CANCEL
*
* Some common combinations have already been predefined:
*
* - Ext.MessageBox.OKCANCEL
* - Ext.MessageBox.YESNO
* - Ext.MessageBox.YESNOCANCEL
*
* Or false to not show any buttons.
*
* This may also be specified as an object hash containing custom button text in the same format
* as the {@link #buttonText} config. Button IDs present as property names will be made visible.
*
* @param {Boolean} [cfg.closable]
* False to hide the top-right close button (defaults to true). Note that progress and wait
* dialogs will ignore this property and always hide the close button as they can only be closed
* programmatically.
*
* @param {String} [cfg.cls]
* A custom CSS class to apply to the message box's container element
*
* @param {Number} [cfg.defaultTextHeight=75]
* The default height in pixels of the message box's multiline textarea if displayed.
*
* @param {Function} [cfg.fn]
* A callback function which is called when the dialog is dismissed either by clicking on the
* configured buttons, or on the dialog close button, or by pressing the return button
* to enter input.
*
* Progress and wait dialogs will ignore this option since they do not respond to user actions
* and can only be closed programmatically, so any required function should be called
* by the same code after it closes the dialog.
* Parameters passed:
*
* @param {String} cfg.fn.buttonId The ID of the button pressed, one of:
*
* - ok
* - yes
* - no
* - cancel
*
* @param {String} cfg.fn.text Value of the input field if either `prompt` or `multiline`
* is true
* @param {Object} cfg.fn.opt The config object passed to show.
*
* @param {Object} [cfg.buttonText]
* An object containing string properties which override the system-supplied button text values
* just for this invocation. The property names are:
*
* - ok
* - yes
* - no
* - cancel
*
* @param {Object} [cfg.buttonTips] An object keyed by the button ids containing
* {@link Ext.button.Button#tooltip tooltip} configurations for each button. eg:
*
* {
* ok: 'Commit the record',
* cancel: 'Discard the record'
* }
*
* @param {Object} [cfg.scope]
* The scope (`this` reference) in which the function will be executed.
*
* @param {String} [cfg.icon]
* A CSS class that provides a background image to be used as the body icon for the dialog.
* One can use a predefined icon class:
*
* - Ext.MessageBox.INFO
* - Ext.MessageBox.WARNING
* - Ext.MessageBox.QUESTION
* - Ext.MessageBox.ERROR
*
* or use just any `'custom-class'`. Defaults to empty string.
*
* @param {String} [cfg.iconCls]
* The standard {@link Ext.window.Window#iconCls} to add an optional header icon
* (defaults to '')
*
* @param {String} [cfg.defaultFocus]
* The button to focus when showing the dialog. If not specified, defaults to
* the first visible button.
*
* @param {Number} [cfg.maxWidth]
* The maximum width in pixels of the message box (defaults to 600)
*
* @param {Number} [cfg.minWidth]
* The minimum width in pixels of the message box (defaults to 100)
*
* @param {Boolean} [cfg.modal]
* False to allow user interaction with the page while the message box is displayed
* (defaults to true)
*
* @param {String} [cfg.message]
* A string that will replace the existing message box body text (defaults to the
* XHTML-compliant non-breaking space character ' ')
*
* @param {Boolean} [cfg.multiline]
* True to prompt the user to enter multi-line text (defaults to false)
*
* @param {Boolean} [cfg.progress]
* True to display a progress bar (defaults to false)
*
* @param {String} [cfg.progressText]
* The text to display inside the progress bar if progress = true (defaults to '')
*
* @param {Boolean} [cfg.prompt]
* True to prompt the user to enter single-line text (defaults to false)
*
* @param {Boolean} [cfg.proxyDrag]
* True to display a lightweight proxy while dragging (defaults to false)
*
* @param {String} cfg.title
* The title text
*
* @param {String} [cfg.value]
* The string value to set into the active textbox element if displayed
*
* @param {Object/Boolean} [cfg.wait=false]
* `true` to display a progress bar, or a configuration for {@link Ext.ProgressBar#wait}.
*
* @param {Object} [cfg.waitConfig]
* A {@link Ext.ProgressBar#wait} config object (applies only if wait = true)
*
* @param {Number} [cfg.width]
* The width of the dialog in pixels
*
* @param {String} [cfg.maskClickAction=focus]
* The method to call when the window's modal mask is clicked or tapped:
*
* - **`'{@link #method-focus}'`** :
*
* The default. Focus the window, which will then pass focus into its
* {@link #cfg-defaultFocus} delegate.
*
* - **`'{@link #method-hide}'`** :
*
* {@link #method-hide} the window by setting visibility to hidden and applying
* negative offsets.
* @since 6.2.0
*
* @return {Ext.window.MessageBox} this
*/
show: function(cfg) {
var me = this,
visibleFocusables;
cfg = cfg || {};
// If called during global layout suspension, make the call after layout resumption
if (Ext.Component.layoutSuspendCount) {
Ext.on({
resumelayouts: function() {
me.show(cfg);
},
single: true
});
return me;
}
me.reconfigure(cfg);
if (cfg.cls) {
me.addCls(cfg.cls);
}
// Do not steal focus from anything that may be focused if the MessageBox
// has no visible focusable items. For example, a "wait" message box should not get focus.
visibleFocusables =
me.query('textfield:not([hidden]),textarea:not([hidden]),button:not([hidden])');
me.preventFocusOnActivate = !visibleFocusables.length;
me.callParent();
// Focus the MessageBox if it is closable but has no focusable items
// so when the escape key is pressed the MessageBox will close.
if (me.closable && !me.defaultFocus) {
me.focus();
}
return me;
},
onShow: function() {
this.callParent(arguments);
this.center();
},
updateText: function(text) {
this.msg.setHtml(text);
},
/**
* Adds the specified icon to the dialog. By default, the class 'x-messagebox-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.
* 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:
*
* Ext.window.MessageBox.INFO
* Ext.window.MessageBox.WARNING
* Ext.window.MessageBox.QUESTION
* Ext.window.MessageBox.ERROR
*
* @param {String} icon A CSS classname specifying the icon's background image url,
* or empty string to clear the icon
* @param {Number} [width] The width of the icon. If not specified, the default is used
* @param {Number} [height] The height of the icon. If not specified, the default is used
* @return {Ext.window.MessageBox} this
*/
setIcon: function(icon, width, height) {
var me = this,
iconCmp = me.iconComponent,
cls = me.messageIconCls;
if (cls) {
iconCmp.removeCls(cls);
}
if (icon) {
iconCmp.show();
if (width || height) {
iconCmp.setSize(width || iconCmp.getWidth(), height || iconCmp.getHeight());
}
iconCmp.addCls(Ext.baseCSSPrefix + 'dlg-icon');
iconCmp.addCls(me.messageIconCls = icon);
}
else {
iconCmp.removeCls(Ext.baseCSSPrefix + 'dlg-icon');
iconCmp.hide();
}
return me;
},
/**
* Updates a progress-style message box's text and progress bar. Only relevant on message boxes
* initiated via {@link Ext.window.MessageBox#progress} or {@link Ext.window.MessageBox#wait},
* or by calling {@link Ext.window.MessageBox#method-show} with progress: true.
*
* @param {Number} [value=0] Any number between 0 and 1 (e.g., .5)
* @param {String} [progressText=''] The progress text to display inside the progress bar.
* @param {String} [message] 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.window.MessageBox} this
*/
updateProgress: function(value, progressText, message) {
this.progressBar.updateProgress(value, progressText);
if (message) {
this.updateText(message);
}
return this;
},
onEsc: function() {
if (this.closable !== false) {
this.callParent(arguments);
}
},
/**
* 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, which will always report
* as "cancel").
*
* @param {String} title The title bar text
* @param {String} message The message box body text
* @param {Function} [fn] The callback function invoked after the message box is closed.
* See {@link #method-show} method for details.
* @param {Object} [scope=window] The scope (`this` reference) in which the callback
* is executed.
* @return {Ext.window.MessageBox} this
*/
confirm: function(title, message, fn, scope) {
if (Ext.isString(title)) {
title = {
title: title,
icon: this.QUESTION,
message: message,
buttons: this.YESNO,
callback: fn,
scope: scope
};
}
return this.show(title);
},
/**
* 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,
* which will always report as "cancel") 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} message The message box body text
* @param {Function} [fn] The callback function invoked after the message box is closed.
* See {@link #method-show} method for details.
* @param {Object} [scope=window] The scope (`this` reference) in which the callback
* is executed.
* @param {Boolean/Number} [multiline=false] True to create a multiline textbox
* using the defaultTextHeight property, or the height in pixels to create the textbox.
* @param {String} [value=''] Default value of the text input element
* @return {Ext.window.MessageBox} this
*/
prompt: function(title, message, fn, scope, multiline, value) {
if (Ext.isString(title)) {
title = {
prompt: true,
title: title,
minWidth: this.minPromptWidth,
message: message,
buttons: this.OKCANCEL,
callback: fn,
scope: scope,
multiline: multiline,
value: value
};
}
return this.show(title);
},
/**
* 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} message The message box body text
* @param {String} [title] The title bar text
* @param {Object} [config] A {@link Ext.ProgressBar#wait} config object
* @return {Ext.window.MessageBox} this
*/
wait: function(message, title, config) {
if (Ext.isString(message)) {
message = {
title: title,
message: message,
closable: false,
wait: true,
modal: true,
minWidth: this.minProgressWidth,
waitConfig: config
};
}
return this.show(message);
},
/**
* 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, which will always
* report as "cancel").
*
* @param {String} title The title bar text
* @param {String} message The message box body text
* @param {Function} [fn] The callback function invoked after the message box is closed.
* See {@link #method-show} method for details.
* @param {Object} [scope=window] The scope (<code>this</code> reference) in which the callback
* is executed.
* @return {Ext.window.MessageBox} this
*/
alert: function(title, message, fn, scope) {
if (Ext.isString(title)) {
title = {
title: title,
message: message,
buttons: this.OK,
fn: fn,
scope: scope,
minWidth: this.minWidth
};
}
return this.show(title);
},
/**
* Displays a message box with a progress bar.
*
* You are responsible for updating the progress bar as needed via
* {@link Ext.window.MessageBox#updateProgress} and closing the message box when the process
* is complete.
*
* @param {String} title The title bar text
* @param {String} message The message box body text
* @param {String} [progressText=''] The text to display inside the progress bar
* @return {Ext.window.MessageBox} this
*/
progress: function(title, message, progressText) {
if (Ext.isString(title)) {
title = {
title: title,
message: message,
progress: true,
progressText: progressText
};
}
return this.show(title);
},
privates: {
syncHeaderConfigs: Ext.privateFn
}
}, function(MessageBox) {
/**
* @class Ext.MessageBox
* @alternateClassName Ext.Msg
* @extends Ext.window.MessageBox
* @singleton
* @inheritdoc Ext.window.MessageBox
*/
// We want to defer creating Ext.MessageBox and Ext.Msg instances
// until overrides have been applied.
Ext.onInternalReady(function() {
Ext.MessageBox = Ext.Msg = new MessageBox();
});
});