/*!
- * OOjs UI v0.22.5
+ * OOjs UI v0.23.2
* 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-08-22T21:37:37Z
+ * Date: 2017-09-26T20:18:42Z
*/
( function ( OO ) {
*/
OO.ui.Element.static.unsafeInfuse = function ( idOrNode, domPromise ) {
// look for a cached result of a previous infusion.
- var id, $elem, data, cls, parts, parent, obj, top, state, infusedChildren;
+ var id, $elem, error, data, cls, parts, parent, obj, top, state, infusedChildren;
if ( typeof idOrNode === 'string' ) {
id = idOrNode;
$elem = $( document.getElementById( id ) );
id = $elem.attr( 'id' );
}
if ( !$elem.length ) {
- throw new Error( 'Widget not found: ' + id );
+ if ( typeof idOrNode === 'string' ) {
+ error = 'Widget not found: ' + idOrNode;
+ } else if ( idOrNode && idOrNode.selector ) {
+ error = 'Widget not found: ' + idOrNode.selector;
+ } else {
+ error = 'Widget not found';
+ }
+ throw new Error( error );
}
if ( $elem[ 0 ].oouiInfused ) {
$elem = $elem[ 0 ].oouiInfused;
parts = data._.split( '.' );
cls = OO.getProp.apply( OO, [ window ].concat( parts ) );
if ( cls === undefined ) {
- // The PHP output might be old and not including the "OO.ui" prefix
- // TODO: Remove this back-compat after next major release
- cls = OO.getProp.apply( OO, [ OO.ui ].concat( parts ) );
- if ( cls === undefined ) {
- throw new Error( 'Unknown widget type: id: ' + id + ', class: ' + data._ );
- }
+ throw new Error( 'Unknown widget type: id: ' + id + ', class: ' + data._ );
}
// Verify that we're creating an OO.ui.Element instance
*
* @param {string} text Text
* @param {string} query Query to find
+ * @param {Function} [compare] Optional string comparator, e.g. Intl.Collator().compare
* @return {jQuery} Text with the first match of the query
* sub-string wrapped in highlighted span
*/
-OO.ui.mixin.LabelElement.static.highlightQuery = function ( text, query ) {
- var $result = $( '<span>' ),
+OO.ui.mixin.LabelElement.static.highlightQuery = function ( text, query, compare ) {
+ var i, offset, tLen, qLen,
+ $result = $( '<span>' );
+
+ if ( compare ) {
+ tLen = text.length;
+ qLen = query.length;
+ for ( i = 0; offset === undefined && i <= tLen - qLen; i++ ) {
+ if ( compare( query, text.slice( i, i + qLen ) ) === 0 ) {
+ offset = i;
+ }
+ }
+ } else {
offset = text.toLowerCase().indexOf( query.toLowerCase() );
+ }
if ( !query.length || offset === -1 ) {
return $result.text( text );
*
* @param {string} text Text label to set
* @param {string} query Substring of text to highlight
+ * @param {Function} [compare] Optional string comparator, e.g. Intl.Collator().compare
* @chainable
*/
-OO.ui.mixin.LabelElement.prototype.setHighlightedQuery = function ( text, query ) {
- return this.setLabel( this.constructor.static.highlightQuery( text, query ) );
+OO.ui.mixin.LabelElement.prototype.setHighlightedQuery = function ( text, query, compare ) {
+ return this.setLabel( this.constructor.static.highlightQuery( text, query, compare ) );
};
/**
*
* - **progressive**: Progressive styling is applied to convey that the widget will move the user forward in a process.
* - **destructive**: Destructive styling is applied to convey that the widget will remove something.
- * - **constructive**: Constructive styling is applied to convey that the widget will create something.
+ * - **constructive**: Constructive styling is deprecated since v0.23.2 and equivalent to progressive.
*
* The flags affect the appearance of the buttons:
*
* @example
* // FlaggedElement is mixed into ButtonWidget to provide styling flags
* var button1 = new OO.ui.ButtonWidget( {
- * label: 'Constructive',
- * flags: 'constructive'
+ * label: 'Progressive',
+ * flags: 'progressive'
* } );
* var button2 = new OO.ui.ButtonWidget( {
* label: 'Destructive',
* flags: 'destructive'
* } );
- * var button3 = new OO.ui.ButtonWidget( {
- * label: 'Progressive',
- * flags: 'progressive'
- * } );
- * $( 'body' ).append( button1.$element, button2.$element, button3.$element );
+ * $( 'body' ).append( button1.$element, button2.$element );
*
* {@link OO.ui.ActionWidget ActionWidgets}, which are a special kind of button that execute an action, use these flags: **primary** and **safe**.
* Please see the [OOjs UI documentation on MediaWiki] [1] for more information.
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {string|string[]} [flags] The name or names of the flags (e.g., 'constructive' or 'primary') to apply.
+ * @cfg {string|string[]} [flags] The name or names of the flags (e.g., 'progressive' or 'primary') to apply.
* Please see the [OOjs UI documentation on MediaWiki] [2] for more information about available flags.
* [2]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Flagged
* @cfg {jQuery} [$flagged] The flagged element. By default,
// This widget was focussed, e.g. by the user tabbing to it.
// The styles for focus state depend on one of the items being selected.
if ( !this.getSelectedItem() ) {
- item = this.getFirstSelectableItem();
+ item = this.findFirstSelectableItem();
}
} else {
// One of the options got focussed (and the event bubbled up here).
// They can't be tabbed to, but they can be activated using accesskeys.
- item = this.getTargetItem( event );
+ item = this.findTargetItem( event );
}
if ( item ) {
if ( !this.isDisabled() && e.which === OO.ui.MouseButtons.LEFT ) {
this.togglePressed( true );
- item = this.getTargetItem( e );
+ item = this.findTargetItem( e );
if ( item && item.isSelectable() ) {
this.pressItem( item );
this.selecting = item;
this.togglePressed( false );
if ( !this.selecting ) {
- item = this.getTargetItem( e );
+ item = this.findTargetItem( e );
if ( item && item.isSelectable() ) {
this.selecting = item;
}
var item;
if ( !this.isDisabled() && this.pressed ) {
- item = this.getTargetItem( e );
+ item = this.findTargetItem( e );
if ( item && item !== this.selecting && item.isSelectable() ) {
this.pressItem( item );
this.selecting = item;
return;
}
if ( !this.isDisabled() ) {
- item = this.getTargetItem( e );
+ item = this.findTargetItem( e );
this.highlightItem( item && item.isHighlightable() ? item : null );
}
return false;
OO.ui.SelectWidget.prototype.onKeyDown = function ( e ) {
var nextItem,
handled = false,
- currentItem = this.getHighlightedItem() || this.getSelectedItem();
+ currentItem = this.findHighlightedItem() || this.getSelectedItem();
if ( !this.isDisabled() && this.isVisible() ) {
switch ( e.keyCode ) {
case OO.ui.Keys.UP:
case OO.ui.Keys.LEFT:
this.clearKeyPressBuffer();
- nextItem = this.getRelativeSelectableItem( currentItem, -1 );
+ nextItem = this.findRelativeSelectableItem( currentItem, -1 );
handled = true;
break;
case OO.ui.Keys.DOWN:
case OO.ui.Keys.RIGHT:
this.clearKeyPressBuffer();
- nextItem = this.getRelativeSelectableItem( currentItem, 1 );
+ nextItem = this.findRelativeSelectableItem( currentItem, 1 );
handled = true;
break;
case OO.ui.Keys.ESCAPE:
}
this.keyPressBufferTimer = setTimeout( this.clearKeyPressBuffer.bind( this ), 1500 );
- item = this.getHighlightedItem() || this.getSelectedItem();
+ item = this.findHighlightedItem() || this.getSelectedItem();
if ( this.keyPressBuffer === c ) {
// Common (if weird) special case: typing "xxxx" will cycle through all
// the items beginning with "x".
if ( item ) {
- item = this.getRelativeSelectableItem( item, 1 );
+ item = this.findRelativeSelectableItem( item, 1 );
}
} else {
this.keyPressBuffer += c;
filter = this.getItemMatcher( this.keyPressBuffer, false );
if ( !item || !filter( item ) ) {
- item = this.getRelativeSelectableItem( item, 1, filter );
+ item = this.findRelativeSelectableItem( item, 1, filter );
}
if ( item ) {
if ( this.isVisible() && item.constructor.static.highlightable ) {
* @param {jQuery.Event} e
* @return {OO.ui.OptionWidget|null} Outline item widget, `null` if none was found
*/
-OO.ui.SelectWidget.prototype.getTargetItem = function ( e ) {
- return $( e.target ).closest( '.oo-ui-optionWidget' ).data( 'oo-ui-optionWidget' ) || null;
+OO.ui.SelectWidget.prototype.findTargetItem = function ( e ) {
+ var $option = $( e.target ).closest( '.oo-ui-optionWidget' );
+ if ( !$option.closest( '.oo-ui-selectWidget' ).is( this.$element ) ) {
+ return null;
+ }
+ return $option.data( 'oo-ui-optionWidget' ) || null;
};
/**
};
/**
- * Get highlighted item.
+ * Find highlighted item.
*
* @return {OO.ui.OptionWidget|null} Highlighted item, `null` if no item is highlighted
*/
-OO.ui.SelectWidget.prototype.getHighlightedItem = function () {
+OO.ui.SelectWidget.prototype.findHighlightedItem = function () {
var i, len;
for ( i = 0, len = this.items.length; i < len; i++ ) {
return null;
};
+/**
+ * Get highlighted item.
+ *
+ * @deprecated 0.23.1 Use {@link #findHighlightedItem} instead.
+ * @return {OO.ui.OptionWidget|null} Highlighted item, `null` if no item is highlighted
+ */
+OO.ui.SelectWidget.prototype.getHighlightedItem = function () {
+ OO.ui.warnDeprecation( 'SelectWidget#getHighlightedItem: Deprecated function. Use findHighlightedItem instead. See T76630.' );
+ return this.findHighlightedItem();
+};
+
/**
* Toggle pressed state.
*
};
/**
- * Get an option by its position relative to the specified item (or to the start of the option array,
+ * Find an option by its position relative to the specified item (or to the start of the option array,
* if item is `null`). The direction in which to search through the option array is specified with a
* number: -1 for reverse (the default) or 1 for forward. The method will return an option, or
* `null` if there are no options in the array.
* true. Function takes an OO.ui.OptionWidget and returns a boolean.
* @return {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the select
*/
-OO.ui.SelectWidget.prototype.getRelativeSelectableItem = function ( item, direction, filter ) {
+OO.ui.SelectWidget.prototype.findRelativeSelectableItem = function ( item, direction, filter ) {
var currentIndex, nextIndex, i,
increase = direction > 0 ? 1 : -1,
len = this.items.length;
return null;
};
+/**
+ * Get an option by its position relative to the specified item (or to the start of the option array,
+ * if item is `null`). The direction in which to search through the option array is specified with a
+ * number: -1 for reverse (the default) or 1 for forward. The method will return an option, or
+ * `null` if there are no options in the array.
+ *
+ * @deprecated 0.23.1 Use {@link #findRelativeSelectableItem} instead
+ * @param {OO.ui.OptionWidget|null} item Item to describe the start position, or `null` to start at the beginning of the array.
+ * @param {number} direction Direction to move in: -1 to move backward, 1 to move forward
+ * @param {Function} [filter] Only consider items for which this function returns
+ * true. Function takes an OO.ui.OptionWidget and returns a boolean.
+ * @return {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the select
+ */
+OO.ui.SelectWidget.prototype.getRelativeSelectableItem = function ( item, direction, filter ) {
+ OO.ui.warnDeprecation( 'SelectWidget#getRelativeSelectableItem: Deprecated function. Use findRelativeSelectableItem instead. See T76630.' );
+ return this.findRelativeSelectableItem( item, direction, filter );
+};
+
+/**
+ * Find the next selectable item or `null` if there are no selectable items.
+ * Disabled options and menu-section markers and breaks are not selectable.
+ *
+ * @return {OO.ui.OptionWidget|null} Item, `null` if there aren't any selectable items
+ */
+OO.ui.SelectWidget.prototype.findFirstSelectableItem = function () {
+ return this.findRelativeSelectableItem( null, 1 );
+};
+
/**
* Get the next selectable item or `null` if there are no selectable items.
* Disabled options and menu-section markers and breaks are not selectable.
*
+ * @deprecated 0.23.1 Use {@link OO.ui.SelectWidget#findFirstSelectableItem} instead.
* @return {OO.ui.OptionWidget|null} Item, `null` if there aren't any selectable items
*/
OO.ui.SelectWidget.prototype.getFirstSelectableItem = function () {
- return this.getRelativeSelectableItem( null, 1 );
+ OO.ui.warnDeprecation( 'SelectWidget#getFirstSelectableItem: Deprecated function. Use findFirstSelectableItem instead. See T76630.' );
+ return this.findFirstSelectableItem();
};
/**
* @inheritdoc
*/
OO.ui.MenuSelectWidget.prototype.onKeyDown = function ( e ) {
- var currentItem = this.getHighlightedItem() || this.getSelectedItem();
+ var currentItem = this.findHighlightedItem() || this.getSelectedItem();
if ( !this.isDisabled() && this.isVisible() ) {
switch ( e.keyCode ) {
this.focus();
};
-/**
- * FloatingMenuSelectWidget was a menu that would stick under a specified
- * container, even when it is inserted elsewhere in the document.
- * This functionality is now included in MenuSelectWidget, and FloatingMenuSelectWidget
- * is preserved for backwards-compatibility.
- *
- * @class
- * @extends OO.ui.MenuSelectWidget
- * @deprecated since v0.21.3, use MenuSelectWidget instead.
- *
- * @constructor
- * @param {OO.ui.Widget} [inputWidget] Widget to provide the menu for.
- * Deprecated, omit this parameter and specify `$container` instead.
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$container=inputWidget.$element] Element to render menu under
- */
-OO.ui.FloatingMenuSelectWidget = function OoUiFloatingMenuSelectWidget( inputWidget, config ) {
- OO.ui.warnDeprecation( 'FloatingMenuSelectWidget is deprecated. Use the MenuSelectWidget instead.' );
-
- // Allow 'inputWidget' parameter and config for backwards compatibility
- if ( OO.isPlainObject( inputWidget ) && config === undefined ) {
- config = inputWidget;
- inputWidget = config.inputWidget;
- }
-
- // Configuration initialization
- config = config || {};
-
- // Properties
- this.inputWidget = inputWidget; // For backwards compatibility
- this.$container = config.$floatableContainer || config.$container || this.inputWidget.$element;
-
- // Parent constructor
- OO.ui.FloatingMenuSelectWidget.parent.call( this, $.extend( {}, config, { $floatableContainer: this.$container } ) );
-
- // Initialization
- this.$element.addClass( 'oo-ui-floatingMenuSelectWidget' );
- // For backwards compatibility
- this.$element.addClass( 'oo-ui-textInputMenuSelectWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.FloatingMenuSelectWidget, OO.ui.MenuSelectWidget );
-
/**
* Progress bars visually display the status of an operation, such as a download,
* and can be either determinate or indeterminate:
value = this.cleanUpValue( value );
// Only allow setting values that are actually present in the dropdown
selected = this.dropdownWidget.getMenu().getItemFromData( value ) ||
- this.dropdownWidget.getMenu().getFirstSelectableItem();
+ this.dropdownWidget.getMenu().findFirstSelectableItem();
this.dropdownWidget.getMenu().selectItem( selected );
value = selected ? selected.getData() : '';
OO.ui.DropdownInputWidget.parent.prototype.setValue.call( this, value );
var match = this.menu.getItemFromData( value );
this.menu.selectItem( match );
- if ( this.menu.getHighlightedItem() ) {
+ if ( this.menu.findHighlightedItem() ) {
this.menu.highlightItem( match );
}
OO.ui.ComboBoxInputWidget.prototype.onMenuItemsChange = function () {
var match = this.menu.getItemFromData( this.getValue() );
this.menu.selectItem( match );
- if ( this.menu.getHighlightedItem() ) {
+ if ( this.menu.findHighlightedItem() ) {
this.menu.highlightItem( match );
}
this.$element.toggleClass( 'oo-ui-comboBoxInputWidget-empty', this.menu.isEmpty() );