/*!
- * OOjs UI v0.18.3
+ * OOjs UI v0.18.4
* 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-01-04T00:22:40Z
+ * Date: 2017-01-18T00:07:07Z
*/
( function ( OO ) {
/**
* @property {number}
+ * @private
*/
OO.ui.elementId = 0;
/**
* Generate a unique ID for element
*
- * @return {string} [id]
+ * @return {string} ID
*/
OO.ui.generateElementId = function () {
- OO.ui.elementId += 1;
- return 'oojsui-' + OO.ui.elementId;
+ OO.ui.elementId++;
+ return 'ooui-' + OO.ui.elementId;
};
/**
/**
* Get a localized message.
*
- * In environments that provide a localization system, this function should be overridden to
- * return the message translated in the user's language. The default implementation always returns
- * English messages.
- *
* After the message key, message parameters may optionally be passed. In the default implementation,
* any occurrences of $1 are replaced with the first parameter, $2 with the second parameter, etc.
* Alternative implementations of OO.ui.msg may use any substitution system they like, as long as
* they support unnamed, ordered message parameters.
*
+ * In environments that provide a localization system, this function should be overridden to
+ * return the message translated in the user's language. The default implementation always returns
+ * English messages. An example of doing this with [jQuery.i18n](https://github.com/wikimedia/jquery.i18n)
+ * follows.
+ *
+ * @example
+ * var i, iLen, button,
+ * messagePath = 'oojs-ui/dist/i18n/',
+ * languages = [ $.i18n().locale, 'ur', 'en' ],
+ * languageMap = {};
+ *
+ * for ( i = 0, iLen = languages.length; i < iLen; i++ ) {
+ * languageMap[ languages[ i ] ] = messagePath + languages[ i ].toLowerCase() + '.json';
+ * }
+ *
+ * $.i18n().load( languageMap ).done( function() {
+ * // Replace the built-in `msg` only once we've loaded the internationalization.
+ * // OOjs UI uses `OO.ui.deferMsg` for all initially-loaded messages. So long as
+ * // you put off creating any widgets until this promise is complete, no English
+ * // will be displayed.
+ * OO.ui.msg = $.i18n;
+ *
+ * // A button displaying "OK" in the default locale
+ * button = new OO.ui.ButtonWidget( {
+ * label: OO.ui.msg( 'ooui-dialog-message-accept' ),
+ * icon: 'check'
+ * } );
+ * $( 'body' ).append( button.$element );
+ *
+ * // A button displaying "OK" in Urdu
+ * $.i18n().locale = 'ur';
+ * button = new OO.ui.ButtonWidget( {
+ * label: OO.ui.msg( 'ooui-dialog-message-accept' ),
+ * icon: 'check'
+ * } );
+ * $( 'body' ).append( button.$element );
+ * } );
+ *
* @param {string} key Message key
* @param {...Mixed} [params] Message parameters
* @return {string} Translated message with parameters substituted
this.$element = config.$element ||
$( document.createElement( this.getTagName() ) );
this.elementGroup = null;
- this.debouncedUpdateThemeClassesHandler = OO.ui.debounce( this.debouncedUpdateThemeClasses );
// Initialization
if ( Array.isArray( config.classes ) ) {
};
/**
- * Gather the dynamic state (focus, value of form inputs, scroll position, etc.) of a HTML DOM node
+ * Gather the dynamic state (focus, value of form inputs, scroll position, etc.) of an HTML DOM node
* (and its children) that represent an Element of the same class and the given configuration,
* generated by the PHP implementation.
*
animations = {};
callback = typeof config.complete === 'function' && config.complete;
+ if ( callback ) {
+ OO.ui.warnDeprecation( 'Element#scrollIntoView: The `complete` callback config option is deprecated. Use the return promise instead.' );
+ }
container = this.getClosestScrollableContainer( el, config.direction );
$container = $( container );
elementDimensions = this.getDimensions( el );
* guaranteeing that theme updates do not occur within an element's constructor
*/
OO.ui.Element.prototype.updateThemeClasses = function () {
- this.debouncedUpdateThemeClassesHandler();
-};
-
-/**
- * @private
- * @localdoc This method is called directly from the QUnit tests instead of #updateThemeClasses, to
- * make them synchronous.
- */
-OO.ui.Element.prototype.debouncedUpdateThemeClasses = function () {
- OO.ui.theme.updateElementClasses( this );
+ OO.ui.theme.queueUpdateElementClasses( this );
};
/**
/* Static Properties */
/**
- * Whether this widget will behave reasonably when wrapped in a HTML `<label>`. If this is true,
+ * Whether this widget will behave reasonably when wrapped in an HTML `<label>`. If this is true,
* wrappers such as OO.ui.FieldLayout may use a `<label>` instead of implementing own label click
* handling.
*
*
* @constructor
*/
-OO.ui.Theme = function OoUiTheme() {};
+OO.ui.Theme = function OoUiTheme() {
+ this.elementClassesQueue = [];
+ this.debouncedUpdateQueuedElementClasses = OO.ui.debounce( this.updateQueuedElementClasses );
+};
/* Setup */
.addClass( classes.on.join( ' ' ) );
};
+/**
+ * @private
+ */
+OO.ui.Theme.prototype.updateQueuedElementClasses = function () {
+ var i;
+ for ( i = 0; i < this.elementClassesQueue.length; i++ ) {
+ this.updateElementClasses( this.elementClassesQueue[ i ] );
+ }
+ // Clear the queue
+ this.elementClassesQueue = [];
+};
+
+/**
+ * Queue #updateElementClasses to be called for this element.
+ *
+ * @localdoc QUnit tests override this method to directly call #queueUpdateElementClasses,
+ * to make them synchronous.
+ *
+ * @param {OO.ui.Element} element Element for which to update classes
+ */
+OO.ui.Theme.prototype.queueUpdateElementClasses = function ( element ) {
+ // Keep items in the queue unique. Use lastIndexOf to start checking from the end because that's
+ // the most common case (this method is often called repeatedly for the same element).
+ if ( this.elementClassesQueue.lastIndexOf( element ) !== -1 ) {
+ return;
+ }
+ this.elementClassesQueue.push( element );
+ this.debouncedUpdateQueuedElementClasses();
+};
+
/**
* Get the transition duration in milliseconds for dialogs opening/closing
*
* @deprecated since 0.16.0
*/
OO.ui.mixin.LabelElement.prototype.fitLabel = function () {
+ OO.ui.warnDeprecation( 'LabelElement#fitLabel: This is a deprecated no-op.' );
return this;
};
// Initial clip after visible
this.clip();
} else {
- this.$clippable.css( { width: '', height: '', overflowX: '', overflowY: '' } );
+ this.$clippable.css( {
+ width: '',
+ height: '',
+ maxWidth: '',
+ maxHeight: '',
+ overflowX: '',
+ overflowY: ''
+ } );
OO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );
this.$clippableScrollableContainer = null;
/**
* Set popup alignment
*
- * @param {string} align Alignment of the popup, `center`, `force-left`, `force-right`,
+ * @param {string} [align=center] Alignment of the popup, `center`, `force-left`, `force-right`,
* `backwards` or `forwards`.
*/
OO.ui.PopupWidget.prototype.setAlignment = function ( align ) {
- // Validate alignment and transform deprecated values
- if ( [ 'left', 'right', 'force-left', 'force-right', 'backwards', 'forwards', 'center' ].indexOf( align ) > -1 ) {
- this.align = { left: 'force-right', right: 'force-left' }[ align ] || align;
+ // Transform values deprecated since v0.11.0
+ if ( align === 'left' || align === 'right' ) {
+ OO.ui.warnDeprecation( 'PopupWidget#setAlignment parameter value `' + align + '` is deprecated. Use `force-right` or `force-left` instead.' );
+ align = { left: 'force-right', right: 'force-left' }[ align ];
+ }
+
+ // Validate alignment
+ if ( [ 'force-left', 'force-right', 'backwards', 'forwards', 'center' ].indexOf( align ) > -1 ) {
+ this.align = align;
} else {
this.align = 'center';
}
* OO.ui.MenuOptionWidget. The DropdownWidget takes care of opening and displaying the menu so that
* users can interact with it.
*
- * If you want to use this within a HTML form, such as a OO.ui.FormLayout, use
+ * If you want to use this within an HTML form, such as a OO.ui.FormLayout, use
* OO.ui.DropdownInputWidget instead.
*
* @example
* an interface for adding, removing and selecting options.
* Please see the [OOjs UI documentation on MediaWiki][1] for more information.
*
- * If you want to use this within a HTML form, such as a OO.ui.FormLayout, use
+ * If you want to use this within an HTML form, such as a OO.ui.FormLayout, use
* OO.ui.RadioSelectInputWidget instead.
*
* @example
* CheckboxMultiselectWidget provides an interface for adding, removing and selecting options.
* Please see the [OOjs UI documentation on MediaWiki][1] for more information.
*
- * If you want to use this within a HTML form, such as a OO.ui.FormLayout, use
+ * If you want to use this within an HTML form, such as a OO.ui.FormLayout, use
* OO.ui.CheckboxMultiselectInputWidget instead.
*
* @example
OO.inheritClass( OO.ui.FloatingMenuSelectWidget, OO.ui.MenuSelectWidget );
OO.mixinClass( OO.ui.FloatingMenuSelectWidget, OO.ui.mixin.FloatableElement );
-// For backwards compatibility
-OO.ui.TextInputMenuSelectWidget = OO.ui.FloatingMenuSelectWidget;
-
/* Methods */
/**
return this;
};
+/*
+ * The old name for the FloatingMenuSelectWidget widget, provided for backwards-compatibility.
+ *
+ * @class
+ * @extends OO.ui.FloatingMenuSelectWidget
+ *
+ * @constructor
+ * @deprecated since v0.12.5.
+ */
+OO.ui.TextInputMenuSelectWidget = function OoUiTextInputMenuSelectWidget() {
+ OO.ui.warnDeprecation( 'TextInputMenuSelectWidget is deprecated. Use the FloatingMenuSelectWidget instead.' );
+ // Parent constructor
+ OO.ui.TextInputMenuSelectWidget.parent.apply( this, arguments );
+};
+
+OO.inheritClass( OO.ui.TextInputMenuSelectWidget, OO.ui.FloatingMenuSelectWidget );
+
/**
* Progress bars visually display the status of an operation, such as a download,
* and can be either determinate or indeterminate:
* in {@link OO.ui.FieldLayout field layouts} that use the {@link OO.ui.FieldLayout#align inline}
* alignment. For more information, please see the [OOjs UI documentation on MediaWiki][1].
*
- * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
+ * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.
*
* @example
* // An example of selected, unselected, and disabled checkbox inputs
/**
* DropdownInputWidget is a {@link OO.ui.DropdownWidget DropdownWidget} intended to be used
- * within a HTML form, such as a OO.ui.FormLayout. The selected value is synchronized with the value
+ * within an HTML form, such as a OO.ui.FormLayout. The selected value is synchronized with the value
* of a hidden HTML `input` tag. Please see the [OOjs UI documentation on MediaWiki][1] for
* more information about input widgets.
*
* with {@link OO.ui.RadioOptionWidget radio options} instead of this class. For more information,
* please see the [OOjs UI documentation on MediaWiki][1].
*
- * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
+ * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.
*
* @example
* // An example of selected, unselected, and disabled radio inputs
/**
* RadioSelectInputWidget is a {@link OO.ui.RadioSelectWidget RadioSelectWidget} intended to be used
- * within a HTML form, such as a OO.ui.FormLayout. The selected value is synchronized with the value
+ * within an HTML form, such as a OO.ui.FormLayout. The selected value is synchronized with the value
* of a hidden HTML `input` tag. Please see the [OOjs UI documentation on MediaWiki][1] for
* more information about input widgets.
*
* which modifies incoming values rather than validating them.
* Please see the [OOjs UI documentation on MediaWiki] [1] for more information and examples.
*
- * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
+ * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.
*
* @example
* // Example of a text input widget
* - by choosing a value from the menu. The value of the chosen option will then appear in the text
* input field.
*
- * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
+ * This widget can be used inside an HTML form, such as a OO.ui.FormLayout.
*
* For more information about menus and options, please see the [OOjs UI documentation on MediaWiki][1].
*
this.notices = [];
this.$field = $( '<div>' );
this.$messages = $( '<ul>' );
+ this.$header = $( '<div>' );
this.$body = $( '<' + ( hasInputWidget ? 'label' : 'div' ) + '>' );
this.align = null;
if ( config.help ) {
this.$element
.addClass( 'oo-ui-fieldLayout' )
.toggleClass( 'oo-ui-fieldLayout-disabled', this.fieldWidget.isDisabled() )
- .append( this.$help, this.$body );
+ .append( this.$body );
this.$body.addClass( 'oo-ui-fieldLayout-body' );
+ this.$header.addClass( 'oo-ui-fieldLayout-header' );
this.$messages.addClass( 'oo-ui-fieldLayout-messages' );
this.$field
.addClass( 'oo-ui-fieldLayout-field' )
value = 'left';
}
// Reorder elements
- if ( value === 'inline' ) {
- this.$body.append( this.$field, this.$label );
+ if ( value === 'top' ) {
+ this.$header.append( this.$label, this.$help );
+ this.$body.append( this.$header, this.$field );
+ } else if ( value === 'inline' ) {
+ this.$header.append( this.$label, this.$help );
+ this.$body.append( this.$field, this.$header );
} else {
- this.$body.append( this.$label, this.$field );
+ this.$header.append( this.$label );
+ this.$body.append( this.$header, this.$help, this.$field );
}
// Set classes. The following classes can be used here:
// * oo-ui-fieldLayout-align-left
OO.ui.mixin.LabelElement.call( this, $.extend( {}, config, { $label: $( '<div>' ) } ) );
OO.ui.mixin.GroupElement.call( this, config );
+ // Properties
+ this.$header = $( '<div>' );
if ( config.help ) {
this.popupButtonWidget = new OO.ui.PopupButtonWidget( {
classes: [ 'oo-ui-fieldsetLayout-help' ],
}
// Initialization
+ this.$header
+ .addClass( 'oo-ui-fieldsetLayout-header' )
+ .append( this.$icon, this.$label, this.$help );
this.$group.addClass( 'oo-ui-fieldsetLayout-group' );
this.$element
.addClass( 'oo-ui-fieldsetLayout' )
- .prepend( this.$label, this.$help, this.$icon, this.$group );
+ .prepend( this.$header, this.$group );
if ( Array.isArray( config.items ) ) {
this.addItems( config.items );
}