diff options
Diffstat (limited to 'vendor/oojs/oojs-ui/src/Dialog.js')
-rw-r--r-- | vendor/oojs/oojs-ui/src/Dialog.js | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/vendor/oojs/oojs-ui/src/Dialog.js b/vendor/oojs/oojs-ui/src/Dialog.js new file mode 100644 index 00000000..33226038 --- /dev/null +++ b/vendor/oojs/oojs-ui/src/Dialog.js @@ -0,0 +1,323 @@ +/** + * The Dialog class serves as the base class for the other types of dialogs. + * Unless extended to include controls, the rendered dialog box is a simple window + * that users can close by hitting the ‘Esc’ key. Dialog windows are used with OO.ui.WindowManager, + * which opens, closes, and controls the presentation of the window. See the + * [OOjs UI documentation on MediaWiki] [1] for more information. + * + * @example + * // A simple dialog window. + * function MyDialog( config ) { + * MyDialog.super.call( this, config ); + * } + * OO.inheritClass( MyDialog, OO.ui.Dialog ); + * MyDialog.prototype.initialize = function () { + * MyDialog.super.prototype.initialize.call( this ); + * this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } ); + * this.content.$element.append( '<p>A simple dialog window. Press \'Esc\' to close.</p>' ); + * 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.PendingElement + * + * @constructor + * @param {Object} [config] Configuration options + */ +OO.ui.Dialog = function OoUiDialog( config ) { + // Parent constructor + OO.ui.Dialog.super.call( this, config ); + + // Mixin constructors + OO.ui.PendingElement.call( this ); + + // Properties + this.actions = new OO.ui.ActionSet(); + this.attachedActions = []; + this.currentAction = null; + this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this ); + + // Events + this.actions.connect( this, { + click: 'onActionClick', + resize: 'onActionResize', + 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.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.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 overriden. + * + * @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 overriden. + * + * [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.onDocumentKeyDown = function ( e ) { + if ( e.which === OO.ui.Keys.ESCAPE ) { + this.close(); + e.preventDefault(); + e.stopPropagation(); + } +}; + +/** + * Handle action resized events. + * + * @private + * @param {OO.ui.ActionWidget} action Action that was resized + */ +OO.ui.Dialog.prototype.onActionResize = function () { + // Override in subclass +}; + +/** + * 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. + * + * @abstract + * @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.super.prototype.getSetupProcess.call( this, data ) + .next( function () { + var config = this.constructor.static, + actions = data.actions !== undefined ? data.actions : config.actions; + + this.title.setLabel( + data.title !== undefined ? data.title : this.constructor.static.title + ); + this.actions.add( this.getActionWidgets( actions ) ); + + if ( this.constructor.static.escapable ) { + this.$document.on( 'keydown', this.onDocumentKeyDownHandler ); + } + }, this ); +}; + +/** + * @inheritdoc + */ +OO.ui.Dialog.prototype.getTeardownProcess = function ( data ) { + // Parent method + return OO.ui.Dialog.super.prototype.getTeardownProcess.call( this, data ) + .first( function () { + if ( this.constructor.static.escapable ) { + this.$document.off( 'keydown', this.onDocumentKeyDownHandler ); + } + + this.actions.clear(); + this.currentAction = null; + }, this ); +}; + +/** + * @inheritdoc + */ +OO.ui.Dialog.prototype.initialize = function () { + // Parent method + OO.ui.Dialog.super.prototype.initialize.call( this ); + + // Properties + this.title = new OO.ui.LabelWidget(); + + // Initialization + this.$content.addClass( 'oo-ui-dialog-content' ); + 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 ) ); +}; |