From f6d65e533c62f6deb21342d4901ece24497b433e Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Thu, 4 Jun 2015 07:31:04 +0200 Subject: Update to MediaWiki 1.25.1 --- vendor/oojs/oojs-ui/src/dialogs/MessageDialog.js | 325 +++++++++++++++++++++++ vendor/oojs/oojs-ui/src/dialogs/ProcessDialog.js | 296 +++++++++++++++++++++ 2 files changed, 621 insertions(+) create mode 100644 vendor/oojs/oojs-ui/src/dialogs/MessageDialog.js create mode 100644 vendor/oojs/oojs-ui/src/dialogs/ProcessDialog.js (limited to 'vendor/oojs/oojs-ui/src/dialogs') diff --git a/vendor/oojs/oojs-ui/src/dialogs/MessageDialog.js b/vendor/oojs/oojs-ui/src/dialogs/MessageDialog.js new file mode 100644 index 00000000..4ec12615 --- /dev/null +++ b/vendor/oojs/oojs-ui/src/dialogs/MessageDialog.js @@ -0,0 +1,325 @@ +/** + * 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(); + } +}; diff --git a/vendor/oojs/oojs-ui/src/dialogs/ProcessDialog.js b/vendor/oojs/oojs-ui/src/dialogs/ProcessDialog.js new file mode 100644 index 00000000..d8f7c137 --- /dev/null +++ b/vendor/oojs/oojs-ui/src/dialogs/ProcessDialog.js @@ -0,0 +1,296 @@ +/** + * ProcessDialog windows encapsulate a {@link OO.ui.Process process} and all of the code necessary + * to complete it. If the process terminates with an error, a customizable {@link OO.ui.Error error + * interface} alerts users to the trouble, permitting the user to dismiss the error and try again when + * relevant. The ProcessDialog class is always extended and customized with the actions and content + * required for each process. + * + * The process dialog box consists of a header that visually represents the ‘working’ state of long + * processes with an animation. The header contains the dialog title as well as + * two {@link OO.ui.ActionWidget action widgets}: a ‘safe’ action on the left (e.g., ‘Cancel’) and + * a ‘primary’ action on the right (e.g., ‘Done’). + * + * Like other windows, the process dialog is managed by a {@link OO.ui.WindowManager window manager}. + * Please see the [OOjs UI documentation on MediaWiki][1] for more information and examples. + * + * @example + * // Example: Creating and opening a process dialog window. + * function MyProcessDialog( config ) { + * MyProcessDialog.super.call( this, config ); + * } + * OO.inheritClass( MyProcessDialog, OO.ui.ProcessDialog ); + * + * MyProcessDialog.static.title = 'Process dialog'; + * MyProcessDialog.static.actions = [ + * { action: 'save', label: 'Done', flags: 'primary' }, + * { label: 'Cancel', flags: 'safe' } + * ]; + * + * MyProcessDialog.prototype.initialize = function () { + * MyProcessDialog.super.prototype.initialize.apply( this, arguments ); + * this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } ); + * this.content.$element.append( '

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.super.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.super.call( this, config ); + + // 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.onActionResize = function ( action ) { + if ( this.actions.isSpecial( action ) ) { + this.fitLabel(); + } + return OO.ui.ProcessDialog.super.prototype.onActionResize.call( this, action ); +}; + +/** + * @inheritdoc + */ +OO.ui.ProcessDialog.prototype.initialize = function () { + // Parent method + OO.ui.ProcessDialog.super.prototype.initialize.call( this ); + + // Properties + this.$navigation = $( '
' ); + this.$location = $( '
' ); + this.$safeActions = $( '
' ); + this.$primaryActions = $( '
' ); + this.$otherActions = $( '
' ); + this.dismissButton = new OO.ui.ButtonWidget( { + label: OO.ui.msg( 'ooui-dialog-process-dismiss' ) + } ); + this.retryButton = new OO.ui.ButtonWidget(); + this.$errors = $( '
' ); + this.$errorsTitle = $( '
' ); + + // Events + this.dismissButton.connect( this, { click: 'onDismissErrorButtonClick' } ); + this.retryButton.connect( this, { click: 'onRetryButtonClick' } ); + + // Initialization + this.title.$element.addClass( 'oo-ui-processDialog-title' ); + this.$location + .append( this.title.$element ) + .addClass( 'oo-ui-processDialog-location' ); + this.$safeActions.addClass( 'oo-ui-processDialog-actions-safe' ); + this.$primaryActions.addClass( 'oo-ui-processDialog-actions-primary' ); + this.$otherActions.addClass( 'oo-ui-processDialog-actions-other' ); + this.$errorsTitle + .addClass( 'oo-ui-processDialog-errors-title' ) + .text( OO.ui.msg( 'ooui-dialog-process-error' ) ); + this.$errors + .addClass( 'oo-ui-processDialog-errors oo-ui-element-hidden' ) + .append( this.$errorsTitle, this.dismissButton.$element, this.retryButton.$element ); + this.$content + .addClass( 'oo-ui-processDialog-content' ) + .append( this.$errors ); + this.$navigation + .addClass( 'oo-ui-processDialog-navigation' ) + .append( this.$safeActions, this.$location, this.$primaryActions ); + this.$head.append( this.$navigation ); + this.$foot.append( this.$otherActions ); +}; + +/** + * @inheritdoc + */ +OO.ui.ProcessDialog.prototype.getActionWidgets = function ( actions ) { + var i, len, widgets = []; + for ( i = 0, len = actions.length; i < len; i++ ) { + widgets.push( + new OO.ui.ActionWidget( $.extend( { framed: true }, actions[ i ] ) ) + ); + } + return widgets; +}; + +/** + * @inheritdoc + */ +OO.ui.ProcessDialog.prototype.attachActions = function () { + var i, len, other, special, others; + + // Parent method + OO.ui.ProcessDialog.super.prototype.attachActions.call( this ); + + special = this.actions.getSpecial(); + others = this.actions.getOthers(); + if ( special.primary ) { + this.$primaryActions.append( special.primary.$element ); + } + for ( i = 0, len = others.length; i < len; i++ ) { + other = others[ i ]; + this.$otherActions.append( other.$element ); + } + if ( special.safe ) { + this.$safeActions.append( special.safe.$element ); + } + + this.fitLabel(); + this.$body.css( 'bottom', this.$foot.outerHeight( true ) ); +}; + +/** + * @inheritdoc + */ +OO.ui.ProcessDialog.prototype.executeAction = function ( action ) { + var process = this; + return OO.ui.ProcessDialog.super.prototype.executeAction.call( this, action ) + .fail( function ( errors ) { + process.showErrors( errors || [] ); + } ); +}; + +/** + * Fit label between actions. + * + * @private + * @chainable + */ +OO.ui.ProcessDialog.prototype.fitLabel = function () { + var width = Math.max( + this.$safeActions.is( ':visible' ) ? this.$safeActions.width() : 0, + this.$primaryActions.is( ':visible' ) ? this.$primaryActions.width() : 0 + ); + this.$location.css( { paddingLeft: width, paddingRight: width } ); + + return this; +}; + +/** + * Handle errors that occurred during accept or reject processes. + * + * @private + * @param {OO.ui.Error[]|OO.ui.Error} errors Errors to be handled + */ +OO.ui.ProcessDialog.prototype.showErrors = function ( errors ) { + var i, len, $item, actions, + items = [], + abilities = {}, + recoverable = true, + warning = false; + + if ( errors instanceof OO.ui.Error ) { + errors = [ errors ]; + } + + for ( i = 0, len = errors.length; i < len; i++ ) { + if ( !errors[ i ].isRecoverable() ) { + recoverable = false; + } + if ( errors[ i ].isWarning() ) { + warning = true; + } + $item = $( '
' ) + .addClass( 'oo-ui-processDialog-error' ) + .append( errors[ i ].getMessage() ); + items.push( $item[ 0 ] ); + } + this.$errorItems = $( items ); + if ( recoverable ) { + abilities[this.currentAction] = true; + // Copy the flags from the first matching action + actions = this.actions.get( { actions: this.currentAction } ); + if ( actions.length ) { + this.retryButton.clearFlags().setFlags( actions[0].getFlags() ); + } + } else { + abilities[this.currentAction] = false; + this.actions.setAbilities( abilities ); + } + if ( warning ) { + this.retryButton.setLabel( OO.ui.msg( 'ooui-dialog-process-continue' ) ); + } else { + this.retryButton.setLabel( OO.ui.msg( 'ooui-dialog-process-retry' ) ); + } + this.retryButton.toggle( recoverable ); + this.$errorsTitle.after( this.$errorItems ); + this.$errors.removeClass( 'oo-ui-element-hidden' ).scrollTop( 0 ); +}; + +/** + * Hide errors. + * + * @private + */ +OO.ui.ProcessDialog.prototype.hideErrors = function () { + this.$errors.addClass( 'oo-ui-element-hidden' ); + if ( this.$errorItems ) { + this.$errorItems.remove(); + this.$errorItems = null; + } +}; + +/** + * @inheritdoc + */ +OO.ui.ProcessDialog.prototype.getTeardownProcess = function ( data ) { + // Parent method + return OO.ui.ProcessDialog.super.prototype.getTeardownProcess.call( this, data ) + .first( function () { + // Make sure to hide errors + this.hideErrors(); + }, this ); +}; -- cgit v1.2.3-54-g00ecf