/*!
- * OOjs UI v0.17.10
+ * OOjs UI v0.18.3
* https://www.mediawiki.org/wiki/OOjs_UI
*
- * Copyright 2011–2016 OOjs UI Team and other contributors.
+ * Copyright 2011–2017 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2016-10-03T18:59:01Z
+ * Date: 2017-01-04T00:22:40Z
*/
( function ( OO ) {
* that must be resolved before proceeding, or a function to execute. See #createStep for more information. see #createStep for more information
* @param {Object} [context=null] Execution context of the function. The context is ignored if the step is
* a number or promise.
- * @return {Object} Step object, with `callback` and `context` properties
*/
OO.ui.Process = function ( step, context ) {
// Properties
this.preparingToClose = null;
this.currentWindow = null;
this.globalEvents = false;
+ this.$returnFocusTo = null;
this.$ariaHidden = null;
this.onWindowResizeTimeout = null;
this.onWindowResizeHandler = this.onWindowResize.bind( this );
/**
* Check if window is opening.
*
+ * @param {OO.ui.Window} win Window to check
* @return {boolean} Window is opening
*/
OO.ui.WindowManager.prototype.isOpening = function ( win ) {
/**
* Check if window is closing.
*
+ * @param {OO.ui.Window} win Window to check
* @return {boolean} Window is closing
*/
OO.ui.WindowManager.prototype.isClosing = function ( win ) {
/**
* Check if window is opened.
*
+ * @param {OO.ui.Window} win Window to check
* @return {boolean} Window is opened
*/
OO.ui.WindowManager.prototype.isOpened = function ( win ) {
*
* @param {OO.ui.Window|string} win Window object or symbolic name of window to open
* @param {Object} [data] Window opening data
+ * @param {jQuery|null} [data.$returnFocusTo] Element to which the window will return focus when closed.
+ * Defaults the current activeElement. If set to null, focus isn't changed on close.
* @return {jQuery.Promise} An `opening` promise resolved when the window is done opening.
* See {@link #event-opening 'opening' event} for more information about `opening` promises.
* @fires opening
OO.ui.WindowManager.prototype.openWindow = function ( win, data ) {
var manager = this,
opening = $.Deferred();
+ data = data || {};
// Argument handling
if ( typeof win === 'string' ) {
manager.toggleGlobalEvents( true );
manager.toggleAriaIsolation( true );
}
+ manager.$returnFocusTo = data.$returnFocusTo || $( document.activeElement );
manager.currentWindow = win;
manager.opening = opening;
manager.preparingToOpen = null;
manager.toggleGlobalEvents( false );
manager.toggleAriaIsolation( false );
}
+ if ( manager.$returnFocusTo && manager.$returnFocusTo.length ) {
+ manager.$returnFocusTo[ 0 ].focus();
+ }
manager.closing = null;
manager.currentWindow = null;
closing.resolve( data );
if ( typeof name !== 'string' ) {
throw new Error( 'Cannot add window' );
}
+ if ( !name ) {
+ OO.ui.warnDeprecation( 'OO.ui.WindowManager#addWindows: Windows must have a `name` static property defined.' );
+ }
list[ name ] = windows[ i ];
}
} else if ( OO.isPlainObject( windows ) ) {
*
* Fullscreen mode will be used if the dialog is too wide to fit in the screen.
*
+ * @param {OO.ui.Window} win Window to update, should be the current window
* @chainable
*/
OO.ui.WindowManager.prototype.updateWindowSize = function ( win ) {
OO.ui.Window.prototype.withoutSizeTransitions = function ( callback ) {
// Temporarily resize the frame so getBodyHeight() can use scrollHeight measurements.
// Disable transitions first, otherwise we'll get values from when the window was animating.
- var oldTransition,
- styleObj = this.$frame[ 0 ].style;
- oldTransition = styleObj.transition || styleObj.OTransition || styleObj.MsTransition ||
- styleObj.MozTransition || styleObj.WebkitTransition;
- styleObj.transition = styleObj.OTransition = styleObj.MsTransition =
- styleObj.MozTransition = styleObj.WebkitTransition = 'none';
+ // We need to build the transition CSS properties using these specific properties since
+ // Firefox doesn't return anything useful when asked just for 'transition'.
+ var oldTransition = this.$frame.css( 'transition-property' ) + ' ' +
+ this.$frame.css( 'transition-duration' ) + ' ' +
+ this.$frame.css( 'transition-timing-function' ) + ' ' +
+ this.$frame.css( 'transition-delay' );
+
+ this.$frame.css( 'transition', 'none' );
callback();
- // Force reflow to make sure the style changes done inside callback really are not transitioned
+
+ // Force reflow to make sure the style changes done inside callback
+ // really are not transitioned
this.$frame.height();
- styleObj.transition = styleObj.OTransition = styleObj.MsTransition =
- styleObj.MozTransition = styleObj.WebkitTransition = oldTransition;
+ this.$frame.css( 'transition', oldTransition );
};
/**
/**
* Get the 'hold' process.
*
- * The hold proccess is used to keep a window from being used in a particular context,
+ * The hold process is used to keep a window from being used in a particular context,
* based on the `data` argument. This method is called during the closing phase of the window’s
* lifecycle.
*
// 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;
+ 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 );
* @inheritdoc
*/
OO.ui.ProcessDialog.prototype.getActionWidgets = function ( actions ) {
- var i, len, widgets = [];
+ var i, len, config,
+ isMobile = OO.ui.isMobile(),
+ widgets = [];
+
for ( i = 0, len = actions.length; i < len; i++ ) {
+ config = $.extend( { framed: !OO.ui.isMobile() }, actions[ i ] );
+ if ( isMobile && ( config.flags === 'back' || config.flags.indexOf( 'back' ) !== -1 ) ) {
+ $.extend( config, {
+ icon: 'previous',
+ label: ''
+ } );
+ }
widgets.push(
- new OO.ui.ActionWidget( $.extend( { framed: true }, actions[ i ] ) )
+ new OO.ui.ActionWidget( config )
);
}
return widgets;
} );
};
+/**
+ * Display a quick modal prompt dialog, using a OO.ui.MessageDialog. While the dialog is open,
+ * the rest of the page will be dimmed out and the user won't be able to interact with it. The
+ * dialog has a text input widget and two action buttons, one to confirm an operation (labelled "OK")
+ * and one to cancel it (labelled "Cancel").
+ *
+ * A window manager is created automatically when this function is called for the first time.
+ *
+ * @example
+ * OO.ui.prompt( 'Choose a line to go to', { textInput: { placeholder: 'Line number' } } ).done( function ( result ) {
+ * if ( result !== null ) {
+ * console.log( 'User typed "' + result + '" then clicked "OK".' );
+ * } else {
+ * console.log( 'User clicked "Cancel" or closed the dialog.' );
+ * }
+ * } );
+ *
+ * @param {jQuery|string} text Message text to display
+ * @param {Object} [options] Additional options, see OO.ui.MessageDialog#getSetupProcess
+ * @cfg {Object} [textInput] Additional options for text input widget, see OO.ui.TextInputWidget
+ * @return {jQuery.Promise} Promise resolved when the user closes the dialog. If the user chose to
+ * confirm, the promise will resolve with the value of the text input widget; otherwise, it will
+ * resolve to `null`.
+ */
+OO.ui.prompt = function ( text, options ) {
+ var manager = OO.ui.getWindowManager(),
+ textInput = new OO.ui.TextInputWidget( ( options && options.textInput ) || {} ),
+ textField = new OO.ui.FieldLayout( textInput, {
+ align: 'top',
+ label: text
+ } );
+
+ // TODO: This is a little hacky, and could be done by extending MessageDialog instead.
+
+ return manager.openWindow( 'messageDialog', $.extend( {
+ message: textField.$element,
+ verbose: true
+ }, options ) ).then( function ( opened ) {
+ // After ready
+ textInput.on( 'enter', function () {
+ manager.getCurrentWindow().close( { action: 'accept' } );
+ } );
+ textInput.focus();
+ return opened.then( function ( closing ) {
+ return closing.then( function ( data ) {
+ return $.Deferred().resolve( data && data.action === 'accept' ? textInput.getValue() : null );
+ } );
+ } );
+ } );
+};
+
}( OO ) );