/** * MessageDialogs display a confirmation or alert message. By default, the rendered dialog box * consists of a header that contains the dialog title, a body with the message, and a footer that * contains any {@link OO.ui.ActionWidget action widgets}. The MessageDialog class is the only type * of {@link OO.ui.Dialog dialog} that is usually instantiated directly. * * There are two basic types of message dialogs, confirmation and alert: * * - **confirmation**: the dialog title describes what a progressive action will do and the message provides * more details about the consequences. * - **alert**: the dialog title describes which event occurred and the message provides more information * about why the event occurred. * * The MessageDialog class specifies two actions: ‘accept’, the primary * action (e.g., ‘ok’) and ‘reject,’ the safe action (e.g., ‘cancel’). Both will close the window, * passing along the selected action. * * For more information and examples, please see the [OOjs UI documentation on MediaWiki][1]. * * @example * // Example: Creating and opening a message dialog window. * var messageDialog = new OO.ui.MessageDialog(); * * // Create and append a window manager. * var windowManager = new OO.ui.WindowManager(); * $( 'body' ).append( windowManager.$element ); * windowManager.addWindows( [ messageDialog ] ); * // Open the window. * windowManager.openWindow( messageDialog, { * title: 'Basic message dialog', * message: 'This is the message' * } ); * * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Message_Dialogs * * @class * @extends OO.ui.Dialog * * @constructor * @param {Object} [config] Configuration options */ OO.ui.MessageDialog = function OoUiMessageDialog( config ) { // Parent constructor OO.ui.MessageDialog.super.call( this, config ); // Properties this.verticalActionLayout = null; // Initialization this.$element.addClass( 'oo-ui-messageDialog' ); }; /* Inheritance */ OO.inheritClass( OO.ui.MessageDialog, OO.ui.Dialog ); /* Static Properties */ OO.ui.MessageDialog.static.name = 'message'; OO.ui.MessageDialog.static.size = 'small'; OO.ui.MessageDialog.static.verbose = false; /** * Dialog title. * * The title of a confirmation dialog describes what a progressive action will do. The * title of an alert dialog describes which event occurred. * * @static * @inheritable * @property {jQuery|string|Function|null} */ OO.ui.MessageDialog.static.title = null; /** * The message displayed in the dialog body. * * A confirmation message describes the consequences of a progressive action. An alert * message describes why an event occurred. * * @static * @inheritable * @property {jQuery|string|Function|null} */ OO.ui.MessageDialog.static.message = null; OO.ui.MessageDialog.static.actions = [ { action: 'accept', label: OO.ui.deferMsg( 'ooui-dialog-message-accept' ), flags: 'primary' }, { action: 'reject', label: OO.ui.deferMsg( 'ooui-dialog-message-reject' ), flags: 'safe' } ]; /* Methods */ /** * @inheritdoc */ OO.ui.MessageDialog.prototype.setManager = function ( manager ) { OO.ui.MessageDialog.super.prototype.setManager.call( this, manager ); // Events this.manager.connect( this, { resize: 'onResize' } ); return this; }; /** * @inheritdoc */ OO.ui.MessageDialog.prototype.onActionResize = function ( action ) { this.fitActions(); return OO.ui.MessageDialog.super.prototype.onActionResize.call( this, action ); }; /** * Handle window resized events. * * @private */ OO.ui.MessageDialog.prototype.onResize = function () { var dialog = this; dialog.fitActions(); // Wait for CSS transition to finish and do it again :( setTimeout( function () { dialog.fitActions(); }, 300 ); }; /** * Toggle action layout between vertical and horizontal. * * * @private * @param {boolean} [value] Layout actions vertically, omit to toggle * @chainable */ OO.ui.MessageDialog.prototype.toggleVerticalActionLayout = function ( value ) { value = value === undefined ? !this.verticalActionLayout : !!value; if ( value !== this.verticalActionLayout ) { this.verticalActionLayout = value; this.$actions .toggleClass( 'oo-ui-messageDialog-actions-vertical', value ) .toggleClass( 'oo-ui-messageDialog-actions-horizontal', !value ); } return this; }; /** * @inheritdoc */ OO.ui.MessageDialog.prototype.getActionProcess = function ( action ) { if ( action ) { return new OO.ui.Process( function () { this.close( { action: action } ); }, this ); } return OO.ui.MessageDialog.super.prototype.getActionProcess.call( this, action ); }; /** * @inheritdoc * * @param {Object} [data] Dialog opening data * @param {jQuery|string|Function|null} [data.title] Description of the action being confirmed * @param {jQuery|string|Function|null} [data.message] Description of the action's consequence * @param {boolean} [data.verbose] Message is verbose and should be styled as a long message * @param {Object[]} [data.actions] List of OO.ui.ActionOptionWidget configuration options for each * action item */ OO.ui.MessageDialog.prototype.getSetupProcess = function ( data ) { data = data || {}; // Parent method return OO.ui.MessageDialog.super.prototype.getSetupProcess.call( this, data ) .next( function () { this.title.setLabel( data.title !== undefined ? data.title : this.constructor.static.title ); this.message.setLabel( data.message !== undefined ? data.message : this.constructor.static.message ); this.message.$element.toggleClass( 'oo-ui-messageDialog-message-verbose', data.verbose !== undefined ? data.verbose : this.constructor.static.verbose ); }, this ); }; /** * @inheritdoc */ OO.ui.MessageDialog.prototype.getBodyHeight = function () { var bodyHeight, oldOverflow, $scrollable = this.container.$element; oldOverflow = $scrollable[ 0 ].style.overflow; $scrollable[ 0 ].style.overflow = 'hidden'; OO.ui.Element.static.reconsiderScrollbars( $scrollable[ 0 ] ); bodyHeight = this.text.$element.outerHeight( true ); $scrollable[ 0 ].style.overflow = oldOverflow; return bodyHeight; }; /** * @inheritdoc */ OO.ui.MessageDialog.prototype.setDimensions = function ( dim ) { var $scrollable = this.container.$element; OO.ui.MessageDialog.super.prototype.setDimensions.call( this, dim ); // Twiddle the overflow property, otherwise an unnecessary scrollbar will be produced. // Need to do it after transition completes (250ms), add 50ms just in case. setTimeout( function () { var oldOverflow = $scrollable[ 0 ].style.overflow; $scrollable[ 0 ].style.overflow = 'hidden'; OO.ui.Element.static.reconsiderScrollbars( $scrollable[ 0 ] ); $scrollable[ 0 ].style.overflow = oldOverflow; }, 300 ); return this; }; /** * @inheritdoc */ OO.ui.MessageDialog.prototype.initialize = function () { // Parent method OO.ui.MessageDialog.super.prototype.initialize.call( this ); // Properties this.$actions = $( '
' ); this.container = new OO.ui.PanelLayout( { scrollable: true, classes: [ 'oo-ui-messageDialog-container' ] } ); this.text = new OO.ui.PanelLayout( { padded: true, expanded: false, classes: [ 'oo-ui-messageDialog-text' ] } ); this.message = new OO.ui.LabelWidget( { classes: [ 'oo-ui-messageDialog-message' ] } ); // Initialization this.title.$element.addClass( 'oo-ui-messageDialog-title' ); this.$content.addClass( 'oo-ui-messageDialog-content' ); this.container.$element.append( this.text.$element ); this.text.$element.append( this.title.$element, this.message.$element ); this.$body.append( this.container.$element ); this.$actions.addClass( 'oo-ui-messageDialog-actions' ); this.$foot.append( this.$actions ); }; /** * @inheritdoc */ OO.ui.MessageDialog.prototype.attachActions = function () { var i, len, other, special, others; // Parent method OO.ui.MessageDialog.super.prototype.attachActions.call( this ); special = this.actions.getSpecial(); others = this.actions.getOthers(); if ( special.safe ) { this.$actions.append( special.safe.$element ); special.safe.toggleFramed( false ); } if ( others.length ) { for ( i = 0, len = others.length; i < len; i++ ) { other = others[ i ]; this.$actions.append( other.$element ); other.toggleFramed( false ); } } if ( special.primary ) { this.$actions.append( special.primary.$element ); special.primary.toggleFramed( false ); } if ( !this.isOpening() ) { // If the dialog is currently opening, this will be called automatically soon. // This also calls #fitActions. this.updateSize(); } }; /** * Fit action actions into columns or rows. * * Columns will be used if all labels can fit without overflow, otherwise rows will be used. * * @private */ OO.ui.MessageDialog.prototype.fitActions = function () { var i, len, action, previous = this.verticalActionLayout, actions = this.actions.get(); // Detect clipping this.toggleVerticalActionLayout( false ); for ( i = 0, len = actions.length; i < len; i++ ) { action = actions[ i ]; if ( action.$element.innerWidth() < action.$label.outerWidth( true ) ) { this.toggleVerticalActionLayout( true ); break; } } // Move the body out of the way of the foot this.$body.css( 'bottom', this.$foot.outerHeight( true ) ); if ( this.verticalActionLayout !== previous ) { // We changed the layout, window height might need to be updated. this.updateSize(); } };