X-Git-Url: https://scripts.mit.edu/gitweb/autoinstallsdev/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/resources/lib/oojs-ui/oojs-ui-windows.js diff --git a/resources/lib/oojs-ui/oojs-ui-windows.js b/resources/lib/oojs-ui/oojs-ui-windows.js new file mode 100644 index 00000000..2a0f02d6 --- /dev/null +++ b/resources/lib/oojs-ui/oojs-ui-windows.js @@ -0,0 +1,3571 @@ +/*! + * OOjs UI v0.23.0 + * https://www.mediawiki.org/wiki/OOjs_UI + * + * Copyright 2011â2017 OOjs UI Team and other contributors. + * Released under the MIT license + * http://oojs.mit-license.org + * + * Date: 2017-09-05T21:23:58Z + */ +( function ( OO ) { + +'use strict'; + +/** + * An ActionWidget is a {@link OO.ui.ButtonWidget button widget} that executes an action. + * Action widgets are used with OO.ui.ActionSet, which manages the behavior and availability + * of the actions. + * + * Both actions and action sets are primarily used with {@link OO.ui.Dialog Dialogs}. + * Please see the [OOjs UI documentation on MediaWiki] [1] for more information + * and examples. + * + * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs#Action_sets + * + * @class + * @extends OO.ui.ButtonWidget + * @mixins OO.ui.mixin.PendingElement + * + * @constructor + * @param {Object} [config] Configuration options + * @cfg {string} [action] Symbolic name of the action (e.g., âcontinueâ or âcancelâ). + * @cfg {string[]} [modes] Symbolic names of the modes (e.g., âeditâ or âreadâ) in which the action + * should be made available. See the action set's {@link OO.ui.ActionSet#setMode setMode} method + * for more information about setting modes. + * @cfg {boolean} [framed=false] Render the action button with a frame + */ +OO.ui.ActionWidget = function OoUiActionWidget( config ) { + // Configuration initialization + config = $.extend( { framed: false }, config ); + + // Parent constructor + OO.ui.ActionWidget.parent.call( this, config ); + + // Mixin constructors + OO.ui.mixin.PendingElement.call( this, config ); + + // Properties + this.action = config.action || ''; + this.modes = config.modes || []; + this.width = 0; + this.height = 0; + + // Initialization + this.$element.addClass( 'oo-ui-actionWidget' ); +}; + +/* Setup */ + +OO.inheritClass( OO.ui.ActionWidget, OO.ui.ButtonWidget ); +OO.mixinClass( OO.ui.ActionWidget, OO.ui.mixin.PendingElement ); + +/* Methods */ + +/** + * Check if the action is configured to be available in the specified `mode`. + * + * @param {string} mode Name of mode + * @return {boolean} The action is configured with the mode + */ +OO.ui.ActionWidget.prototype.hasMode = function ( mode ) { + return this.modes.indexOf( mode ) !== -1; +}; + +/** + * Get the symbolic name of the action (e.g., âcontinueâ or âcancelâ). + * + * @return {string} + */ +OO.ui.ActionWidget.prototype.getAction = function () { + return this.action; +}; + +/** + * Get the symbolic name of the mode or modes for which the action is configured to be available. + * + * The current mode is set with the action set's {@link OO.ui.ActionSet#setMode setMode} method. + * Only actions that are configured to be avaiable in the current mode will be visible. All other actions + * are hidden. + * + * @return {string[]} + */ +OO.ui.ActionWidget.prototype.getModes = function () { + return this.modes.slice(); +}; + +/* eslint-disable no-unused-vars */ +/** + * ActionSets manage the behavior of the {@link OO.ui.ActionWidget action widgets} that comprise them. + * Actions can be made available for specific contexts (modes) and circumstances + * (abilities). Action sets are primarily used with {@link OO.ui.Dialog Dialogs}. + * + * ActionSets contain two types of actions: + * + * - Special: Special actions are the first visible actions with special flags, such as 'safe' and 'primary', the default special flags. Additional special flags can be configured in subclasses with the static #specialFlags property. + * - Other: Other actions include all non-special visible actions. + * + * Please see the [OOjs UI documentation on MediaWiki][1] for more information. + * + * @example + * // Example: An action set used in a process dialog + * function MyProcessDialog( config ) { + * MyProcessDialog.parent.call( this, config ); + * } + * OO.inheritClass( MyProcessDialog, OO.ui.ProcessDialog ); + * MyProcessDialog.static.title = 'An action set in a process dialog'; + * MyProcessDialog.static.name = 'myProcessDialog'; + * // An action set that uses modes ('edit' and 'help' mode, in this example). + * MyProcessDialog.static.actions = [ + * { action: 'continue', modes: 'edit', label: 'Continue', flags: [ 'primary', 'constructive' ] }, + * { action: 'help', modes: 'edit', label: 'Help' }, + * { modes: 'edit', label: 'Cancel', flags: 'safe' }, + * { action: 'back', modes: 'help', label: 'Back', flags: 'safe' } + * ]; + * + * MyProcessDialog.prototype.initialize = function () { + * MyProcessDialog.parent.prototype.initialize.apply( this, arguments ); + * this.panel1 = new OO.ui.PanelLayout( { padded: true, expanded: false } ); + * this.panel1.$element.append( '
This dialog uses an action set (continue, help, cancel, back) configured with modes. This is edit mode. Click \'help\' to see help mode.
' ); + * this.panel2 = new OO.ui.PanelLayout( { padded: true, expanded: false } ); + * this.panel2.$element.append( 'This is help mode. Only the \'back\' action widget is configured to be visible here. Click \'back\' to return to \'edit\' mode.
' ); + * this.stackLayout = new OO.ui.StackLayout( { + * items: [ this.panel1, this.panel2 ] + * } ); + * this.$body.append( this.stackLayout.$element ); + * }; + * MyProcessDialog.prototype.getSetupProcess = function ( data ) { + * return MyProcessDialog.parent.prototype.getSetupProcess.call( this, data ) + * .next( function () { + * this.actions.setMode( 'edit' ); + * }, this ); + * }; + * MyProcessDialog.prototype.getActionProcess = function ( action ) { + * if ( action === 'help' ) { + * this.actions.setMode( 'help' ); + * this.stackLayout.setItem( this.panel2 ); + * } else if ( action === 'back' ) { + * this.actions.setMode( 'edit' ); + * this.stackLayout.setItem( this.panel1 ); + * } else if ( action === 'continue' ) { + * var dialog = this; + * return new OO.ui.Process( function () { + * dialog.close(); + * } ); + * } + * return MyProcessDialog.parent.prototype.getActionProcess.call( this, action ); + * }; + * MyProcessDialog.prototype.getBodyHeight = function () { + * return this.panel1.$element.outerHeight( true ); + * }; + * var windowManager = new OO.ui.WindowManager(); + * $( 'body' ).append( windowManager.$element ); + * var dialog = new MyProcessDialog( { + * size: 'medium' + * } ); + * windowManager.addWindows( [ dialog ] ); + * windowManager.openWindow( dialog ); + * + * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs#Action_sets + * + * @abstract + * @class + * @mixins OO.EventEmitter + * + * @constructor + * @param {Object} [config] Configuration options + */ +OO.ui.ActionSet = function OoUiActionSet( config ) { + // Configuration initialization + config = config || {}; + + // Mixin constructors + OO.EventEmitter.call( this ); + + // Properties + this.list = []; + this.categories = { + actions: 'getAction', + flags: 'getFlags', + modes: 'getModes' + }; + this.categorized = {}; + this.special = {}; + this.others = []; + this.organized = false; + this.changing = false; + this.changed = false; +}; +/* eslint-enable no-unused-vars */ + +/* Setup */ + +OO.mixinClass( OO.ui.ActionSet, OO.EventEmitter ); + +/* Static Properties */ + +/** + * Symbolic name of the flags used to identify special actions. Special actions are displayed in the + * header of a {@link OO.ui.ProcessDialog process dialog}. + * See the [OOjs UI documentation on MediaWiki][2] for more information and examples. + * + * [2]:https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs + * + * @abstract + * @static + * @inheritable + * @property {string} + */ +OO.ui.ActionSet.static.specialFlags = [ 'safe', 'primary' ]; + +/* Events */ + +/** + * @event click + * + * A 'click' event is emitted when an action is clicked. + * + * @param {OO.ui.ActionWidget} action Action that was clicked + */ + +/** + * @event add + * + * An 'add' event is emitted when actions are {@link #method-add added} to the action set. + * + * @param {OO.ui.ActionWidget[]} added Actions added + */ + +/** + * @event remove + * + * A 'remove' event is emitted when actions are {@link #method-remove removed} + * or {@link #clear cleared}. + * + * @param {OO.ui.ActionWidget[]} added Actions removed + */ + +/** + * @event change + * + * A 'change' event is emitted when actions are {@link #method-add added}, {@link #clear cleared}, + * or {@link #method-remove removed} from the action set or when the {@link #setMode mode} is changed. + * + */ + +/* Methods */ + +/** + * Handle action change events. + * + * @private + * @fires change + */ +OO.ui.ActionSet.prototype.onActionChange = function () { + this.organized = false; + if ( this.changing ) { + this.changed = true; + } else { + this.emit( 'change' ); + } +}; + +/** + * Check if an action is one of the special actions. + * + * @param {OO.ui.ActionWidget} action Action to check + * @return {boolean} Action is special + */ +OO.ui.ActionSet.prototype.isSpecial = function ( action ) { + var flag; + + for ( flag in this.special ) { + if ( action === this.special[ flag ] ) { + return true; + } + } + + return false; +}; + +/** + * Get action widgets based on the specified filter: âactionsâ, âflagsâ, âmodesâ, âvisibleâ, + * or âdisabledâ. + * + * @param {Object} [filters] Filters to use, omit to get all actions + * @param {string|string[]} [filters.actions] Actions that action widgets must have + * @param {string|string[]} [filters.flags] Flags that action widgets must have (e.g., 'safe') + * @param {string|string[]} [filters.modes] Modes that action widgets must have + * @param {boolean} [filters.visible] Action widgets must be visible + * @param {boolean} [filters.disabled] Action widgets must be disabled + * @return {OO.ui.ActionWidget[]} Action widgets matching all criteria + */ +OO.ui.ActionSet.prototype.get = function ( filters ) { + var i, len, list, category, actions, index, match, matches; + + if ( filters ) { + this.organize(); + + // Collect category candidates + matches = []; + for ( category in this.categorized ) { + list = filters[ category ]; + if ( list ) { + if ( !Array.isArray( list ) ) { + list = [ list ]; + } + for ( i = 0, len = list.length; i < len; i++ ) { + actions = this.categorized[ category ][ list[ i ] ]; + if ( Array.isArray( actions ) ) { + matches.push.apply( matches, actions ); + } + } + } + } + // Remove by boolean filters + for ( i = 0, len = matches.length; i < len; i++ ) { + match = matches[ i ]; + if ( + ( filters.visible !== undefined && match.isVisible() !== filters.visible ) || + ( filters.disabled !== undefined && match.isDisabled() !== filters.disabled ) + ) { + matches.splice( i, 1 ); + len--; + i--; + } + } + // Remove duplicates + for ( i = 0, len = matches.length; i < len; i++ ) { + match = matches[ i ]; + index = matches.lastIndexOf( match ); + while ( index !== i ) { + matches.splice( index, 1 ); + len--; + index = matches.lastIndexOf( match ); + } + } + return matches; + } + return this.list.slice(); +}; + +/** + * Get 'special' actions. + * + * Special actions are the first visible action widgets with special flags, such as 'safe' and 'primary'. + * Special flags can be configured in subclasses by changing the static #specialFlags property. + * + * @return {OO.ui.ActionWidget[]|null} 'Special' action widgets. + */ +OO.ui.ActionSet.prototype.getSpecial = function () { + this.organize(); + return $.extend( {}, this.special ); +}; + +/** + * Get 'other' actions. + * + * Other actions include all non-special visible action widgets. + * + * @return {OO.ui.ActionWidget[]} 'Other' action widgets + */ +OO.ui.ActionSet.prototype.getOthers = function () { + this.organize(); + return this.others.slice(); +}; + +/** + * Set the mode (e.g., âeditâ or âviewâ). Only {@link OO.ui.ActionWidget#modes actions} configured + * to be available in the specified mode will be made visible. All other actions will be hidden. + * + * @param {string} mode The mode. Only actions configured to be available in the specified + * mode will be made visible. + * @chainable + * @fires toggle + * @fires change + */ +OO.ui.ActionSet.prototype.setMode = function ( mode ) { + var i, len, action; + + this.changing = true; + for ( i = 0, len = this.list.length; i < len; i++ ) { + action = this.list[ i ]; + action.toggle( action.hasMode( mode ) ); + } + + this.organized = false; + this.changing = false; + this.emit( 'change' ); + + return this; +}; + +/** + * Set the abilities of the specified actions. + * + * Action widgets that are configured with the specified actions will be enabled + * or disabled based on the boolean values specified in the `actions` + * parameter. + * + * @param {Object.Popup contents.
Popup contents.
Popup contents.
' ), + * padded: true + * } + * } ); + * ... + * }; + * + * @property {jQuery} + */ + this.$overlay = $( 'A simple dialog window. Press \'Esc\' to close.
' ); + * this.$body.append( this.content.$element ); + * }; + * MyDialog.prototype.getBodyHeight = function () { + * return this.content.$element.outerHeight( true ); + * }; + * var myDialog = new MyDialog( { + * size: 'medium' + * } ); + * // Create and append a window manager, which opens and closes the window. + * var windowManager = new OO.ui.WindowManager(); + * $( 'body' ).append( windowManager.$element ); + * windowManager.addWindows( [ myDialog ] ); + * // Open the window! + * windowManager.openWindow( myDialog ); + * + * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Dialogs + * + * @abstract + * @class + * @extends OO.ui.Window + * @mixins OO.ui.mixin.PendingElement + * + * @constructor + * @param {Object} [config] Configuration options + */ +OO.ui.Dialog = function OoUiDialog( config ) { + // Parent constructor + OO.ui.Dialog.parent.call( this, config ); + + // Mixin constructors + OO.ui.mixin.PendingElement.call( this ); + + // Properties + this.actions = new OO.ui.ActionSet(); + this.attachedActions = []; + this.currentAction = null; + this.onDialogKeyDownHandler = this.onDialogKeyDown.bind( this ); + + // Events + this.actions.connect( this, { + click: 'onActionClick', + change: 'onActionsChange' + } ); + + // Initialization + this.$element + .addClass( 'oo-ui-dialog' ) + .attr( 'role', 'dialog' ); +}; + +/* Setup */ + +OO.inheritClass( OO.ui.Dialog, OO.ui.Window ); +OO.mixinClass( OO.ui.Dialog, OO.ui.mixin.PendingElement ); + +/* Static Properties */ + +/** + * Symbolic name of dialog. + * + * The dialog class must have a symbolic name in order to be registered with OO.Factory. + * Please see the [OOjs UI documentation on MediaWiki] [3] for more information. + * + * [3]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Window_managers + * + * @abstract + * @static + * @inheritable + * @property {string} + */ +OO.ui.Dialog.static.name = ''; + +/** + * The dialog title. + * + * The title can be specified as a plaintext string, a {@link OO.ui.mixin.LabelElement Label} node, or a function + * that will produce a Label node or string. The title can also be specified with data passed to the + * constructor (see #getSetupProcess). In this case, the static value will be overridden. + * + * @abstract + * @static + * @inheritable + * @property {jQuery|string|Function} + */ +OO.ui.Dialog.static.title = ''; + +/** + * An array of configured {@link OO.ui.ActionWidget action widgets}. + * + * Actions can also be specified with data passed to the constructor (see #getSetupProcess). In this case, the static + * value will be overridden. + * + * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs#Action_sets + * + * @static + * @inheritable + * @property {Object[]} + */ +OO.ui.Dialog.static.actions = []; + +/** + * Close the dialog when the 'Esc' key is pressed. + * + * @static + * @abstract + * @inheritable + * @property {boolean} + */ +OO.ui.Dialog.static.escapable = true; + +/* Methods */ + +/** + * Handle frame document key down events. + * + * @private + * @param {jQuery.Event} e Key down event + */ +OO.ui.Dialog.prototype.onDialogKeyDown = function ( e ) { + var actions; + if ( e.which === OO.ui.Keys.ESCAPE && this.constructor.static.escapable ) { + this.executeAction( '' ); + e.preventDefault(); + e.stopPropagation(); + } else if ( e.which === OO.ui.Keys.ENTER && ( e.ctrlKey || e.metaKey ) ) { + actions = this.actions.get( { flags: 'primary', visible: true, disabled: false } ); + if ( actions.length > 0 ) { + this.executeAction( actions[ 0 ].getAction() ); + e.preventDefault(); + e.stopPropagation(); + } + } +}; + +/** + * Handle action click events. + * + * @private + * @param {OO.ui.ActionWidget} action Action that was clicked + */ +OO.ui.Dialog.prototype.onActionClick = function ( action ) { + if ( !this.isPending() ) { + this.executeAction( action.getAction() ); + } +}; + +/** + * Handle actions change event. + * + * @private + */ +OO.ui.Dialog.prototype.onActionsChange = function () { + this.detachActions(); + if ( !this.isClosing() ) { + this.attachActions(); + } +}; + +/** + * Get the set of actions used by the dialog. + * + * @return {OO.ui.ActionSet} + */ +OO.ui.Dialog.prototype.getActions = function () { + return this.actions; +}; + +/** + * Get a process for taking action. + * + * When you override this method, you can create a new OO.ui.Process and return it, or add additional + * accept steps to the process the parent method provides using the {@link OO.ui.Process#first 'first'} + * and {@link OO.ui.Process#next 'next'} methods of OO.ui.Process. + * + * @param {string} [action] Symbolic name of action + * @return {OO.ui.Process} Action process + */ +OO.ui.Dialog.prototype.getActionProcess = function ( action ) { + return new OO.ui.Process() + .next( function () { + if ( !action ) { + // An empty action always closes the dialog without data, which should always be + // safe and make no changes + this.close(); + } + }, this ); +}; + +/** + * @inheritdoc + * + * @param {Object} [data] Dialog opening data + * @param {jQuery|string|Function|null} [data.title] Dialog title, omit to use + * the {@link #static-title static title} + * @param {Object[]} [data.actions] List of configuration options for each + * {@link OO.ui.ActionWidget action widget}, omit to use {@link #static-actions static actions}. + */ +OO.ui.Dialog.prototype.getSetupProcess = function ( data ) { + data = data || {}; + + // Parent method + return OO.ui.Dialog.parent.prototype.getSetupProcess.call( this, data ) + .next( function () { + var config = this.constructor.static, + actions = data.actions !== undefined ? data.actions : config.actions, + title = data.title !== undefined ? data.title : config.title; + + this.title.setLabel( title ).setTitle( title ); + this.actions.add( this.getActionWidgets( actions ) ); + + this.$element.on( 'keydown', this.onDialogKeyDownHandler ); + }, this ); +}; + +/** + * @inheritdoc + */ +OO.ui.Dialog.prototype.getTeardownProcess = function ( data ) { + // Parent method + return OO.ui.Dialog.parent.prototype.getTeardownProcess.call( this, data ) + .first( function () { + this.$element.off( 'keydown', this.onDialogKeyDownHandler ); + + this.actions.clear(); + this.currentAction = null; + }, this ); +}; + +/** + * @inheritdoc + */ +OO.ui.Dialog.prototype.initialize = function () { + // Parent method + OO.ui.Dialog.parent.prototype.initialize.call( this ); + + // Properties + this.title = new OO.ui.LabelWidget(); + + // Initialization + this.$content.addClass( 'oo-ui-dialog-content' ); + this.$element.attr( 'aria-labelledby', this.title.getElementId() ); + this.setPendingElement( this.$head ); +}; + +/** + * Get action widgets from a list of configs + * + * @param {Object[]} actions Action widget configs + * @return {OO.ui.ActionWidget[]} Action widgets + */ +OO.ui.Dialog.prototype.getActionWidgets = function ( actions ) { + var i, len, widgets = []; + for ( i = 0, len = actions.length; i < len; i++ ) { + widgets.push( + new OO.ui.ActionWidget( actions[ i ] ) + ); + } + return widgets; +}; + +/** + * Attach action actions. + * + * @protected + */ +OO.ui.Dialog.prototype.attachActions = function () { + // Remember the list of potentially attached actions + this.attachedActions = this.actions.get(); +}; + +/** + * Detach action actions. + * + * @protected + * @chainable + */ +OO.ui.Dialog.prototype.detachActions = function () { + var i, len; + + // Detach all actions that may have been previously attached + for ( i = 0, len = this.attachedActions.length; i < len; i++ ) { + this.attachedActions[ i ].$element.detach(); + } + this.attachedActions = []; +}; + +/** + * Execute an action. + * + * @param {string} action Symbolic name of action to execute + * @return {jQuery.Promise} Promise resolved when action completes, rejected if it fails + */ +OO.ui.Dialog.prototype.executeAction = function ( action ) { + this.pushPending(); + this.currentAction = action; + return this.getActionProcess( action ).execute() + .always( this.popPending.bind( this ) ); +}; + +/** + * 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.parent.call( this, config ); + + // Properties + this.verticalActionLayout = null; + + // Initialization + this.$element.addClass( 'oo-ui-messageDialog' ); +}; + +/* Setup */ + +OO.inheritClass( OO.ui.MessageDialog, OO.ui.Dialog ); + +/* Static Properties */ + +/** + * @static + * @inheritdoc + */ +OO.ui.MessageDialog.static.name = 'message'; + +/** + * @static + * @inheritdoc + */ +OO.ui.MessageDialog.static.size = 'small'; + +/** + * 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; + +/** + * @static + * @inheritdoc + */ +OO.ui.MessageDialog.static.actions = [ + // Note that OO.ui.alert() and OO.ui.confirm() rely on these. + { 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.parent.prototype.setManager.call( this, manager ); + + // Events + this.manager.connect( this, { + resize: 'onResize' + } ); + + return this; +}; + +/** + * 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.parent.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 {string} [data.size] Symbolic name of the dialog size, see OO.ui.Window + * @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.parent.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.size = data.size !== undefined ? data.size : this.constructor.static.size; + }, this ); +}; + +/** + * @inheritdoc + */ +OO.ui.MessageDialog.prototype.getReadyProcess = function ( data ) { + data = data || {}; + + // Parent method + return OO.ui.MessageDialog.parent.prototype.getReadyProcess.call( this, data ) + .next( function () { + // Focus the primary action button + var actions = this.actions.get(); + actions = actions.filter( function ( action ) { + return action.getFlags().indexOf( 'primary' ) > -1; + } ); + if ( actions.length > 0 ) { + actions[ 0 ].focus(); + } + }, 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.parent.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, + activeElement = document.activeElement; + + $scrollable[ 0 ].style.overflow = 'hidden'; + + OO.ui.Element.static.reconsiderScrollbars( $scrollable[ 0 ] ); + + // Check reconsiderScrollbars didn't destroy our focus, as we + // are doing this after the ready process. + if ( activeElement && activeElement !== document.activeElement && activeElement.focus ) { + activeElement.focus(); + } + + $scrollable[ 0 ].style.overflow = oldOverflow; + }, 300 ); + + return this; +}; + +/** + * @inheritdoc + */ +OO.ui.MessageDialog.prototype.initialize = function () { + // Parent method + OO.ui.MessageDialog.parent.prototype.initialize.call( this ); + + // Properties + this.$actions = $( 'This is a process dialog window. The header contains the title and two buttons: \'Cancel\' (a safe action) on the left and \'Done\' (a primary action) on the right.
' ); + * this.$body.append( this.content.$element ); + * }; + * MyProcessDialog.prototype.getActionProcess = function ( action ) { + * var dialog = this; + * if ( action ) { + * return new OO.ui.Process( function () { + * dialog.close( { action: action } ); + * } ); + * } + * return MyProcessDialog.parent.prototype.getActionProcess.call( this, action ); + * }; + * + * var windowManager = new OO.ui.WindowManager(); + * $( 'body' ).append( windowManager.$element ); + * + * var dialog = new MyProcessDialog(); + * windowManager.addWindows( [ dialog ] ); + * windowManager.openWindow( dialog ); + * + * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs + * + * @abstract + * @class + * @extends OO.ui.Dialog + * + * @constructor + * @param {Object} [config] Configuration options + */ +OO.ui.ProcessDialog = function OoUiProcessDialog( config ) { + // Parent constructor + OO.ui.ProcessDialog.parent.call( this, config ); + + // Properties + this.fitOnOpen = false; + + // Initialization + this.$element.addClass( 'oo-ui-processDialog' ); +}; + +/* Setup */ + +OO.inheritClass( OO.ui.ProcessDialog, OO.ui.Dialog ); + +/* Methods */ + +/** + * Handle dismiss button click events. + * + * Hides errors. + * + * @private + */ +OO.ui.ProcessDialog.prototype.onDismissErrorButtonClick = function () { + this.hideErrors(); +}; + +/** + * Handle retry button click events. + * + * Hides errors and then tries again. + * + * @private + */ +OO.ui.ProcessDialog.prototype.onRetryButtonClick = function () { + this.hideErrors(); + this.executeAction( this.currentAction ); +}; + +/** + * @inheritdoc + */ +OO.ui.ProcessDialog.prototype.initialize = function () { + // Parent method + OO.ui.ProcessDialog.parent.prototype.initialize.call( this ); + + // Properties + this.$navigation = $( '