X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;ds=sidebyside;f=resources%2Flib%2Fooui%2Foojs-ui-core.js;h=2bb08e0a50dd6c247bbfb924448cd49ef8a70f8e;hb=a38af7ba26579bb3004f673e44d39710887763aa;hp=3ca6632b7907fc95c4b8553e6c084ac9d81745c5;hpb=a34f57387da5a71e7d1fba1939ac600a767b64dc;p=lhc%2Fweb%2Fwiklou.git
diff --git a/resources/lib/ooui/oojs-ui-core.js b/resources/lib/ooui/oojs-ui-core.js
index 3ca6632b79..2bb08e0a50 100644
--- a/resources/lib/ooui/oojs-ui-core.js
+++ b/resources/lib/ooui/oojs-ui-core.js
@@ -1,12 +1,12 @@
/*!
- * OOUI v0.31.0
+ * OOUI v0.31.3
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011â2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-03-20T23:07:02Z
+ * Date: 2019-04-04T19:10:48Z
*/
( function ( OO ) {
@@ -295,7 +295,7 @@ OO.ui.throttle = function ( func, wait ) {
previous = 0,
run = function () {
timeout = null;
- previous = OO.ui.now();
+ previous = Date.now();
func.apply( context, args );
};
return function () {
@@ -304,7 +304,7 @@ OO.ui.throttle = function ( func, wait ) {
// period. If it's less, run the function immediately. If it's more,
// set a timeout for the remaining time -- but don't replace an
// existing timeout, since that'd indefinitely prolong the wait.
- var remaining = wait - ( OO.ui.now() - previous );
+ var remaining = wait - ( Date.now() - previous );
context = this;
args = arguments;
if ( remaining <= 0 ) {
@@ -323,10 +323,12 @@ OO.ui.throttle = function ( func, wait ) {
/**
* A (possibly faster) way to get the current timestamp as an integer.
*
+ * @deprecated Since 0.31.1; use `Date.now()` instead.
* @return {number} Current timestamp, in milliseconds since the Unix epoch
*/
-OO.ui.now = Date.now || function () {
- return new Date().getTime();
+OO.ui.now = function () {
+ OO.ui.warnDeprecation( 'OO.ui.now() is deprecated, use Date.now() instead' );
+ return Date.now();
};
/**
@@ -345,124 +347,74 @@ OO.ui.infuse = function ( idOrNode, config ) {
return OO.ui.Element.static.infuse( idOrNode, config );
};
-( function () {
- /**
- * Message store for the default implementation of OO.ui.msg.
- *
- * Environments that provide a localization system should not use this, but should override
- * OO.ui.msg altogether.
- *
- * @private
- */
- var messages = {
- // Tool tip for a button that moves items in a list down one place
- 'ooui-outline-control-move-down': 'Move item down',
- // Tool tip for a button that moves items in a list up one place
- 'ooui-outline-control-move-up': 'Move item up',
- // Tool tip for a button that removes items from a list
- 'ooui-outline-control-remove': 'Remove item',
- // Label for the toolbar group that contains a list of all other available tools
- 'ooui-toolbar-more': 'More',
- // Label for the fake tool that expands the full list of tools in a toolbar group
- 'ooui-toolgroup-expand': 'More',
- // Label for the fake tool that collapses the full list of tools in a toolbar group
- 'ooui-toolgroup-collapse': 'Fewer',
- // Default label for the tooltip for the button that removes a tag item
- 'ooui-item-remove': 'Remove',
- // Default label for the accept button of a confirmation dialog
- 'ooui-dialog-message-accept': 'OK',
- // Default label for the reject button of a confirmation dialog
- 'ooui-dialog-message-reject': 'Cancel',
- // Title for process dialog error description
- 'ooui-dialog-process-error': 'Something went wrong',
- // Label for process dialog dismiss error button, visible when describing errors
- 'ooui-dialog-process-dismiss': 'Dismiss',
- // Label for process dialog retry action button, visible when describing only recoverable
- // errors
- 'ooui-dialog-process-retry': 'Try again',
- // Label for process dialog retry action button, visible when describing only warnings
- 'ooui-dialog-process-continue': 'Continue',
- // Label for button in combobox input that triggers its dropdown
- 'ooui-combobox-button-label': 'Dropdown for combobox',
- // Label for the file selection widget's select file button
- 'ooui-selectfile-button-select': 'Select a file',
- // Label for the file selection widget if file selection is not supported
- 'ooui-selectfile-not-supported': 'File selection is not supported',
- // Label for the file selection widget when no file is currently selected
- 'ooui-selectfile-placeholder': 'No file is selected',
- // Label for the file selection widget's drop target
- 'ooui-selectfile-dragdrop-placeholder': 'Drop file here',
- // Label for the help icon attached to a form field
- 'ooui-field-help': 'Help'
- };
-
- /**
- * Get a localized message.
- *
- * 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.
- * // OOUI 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'
- * } );
- * $( document.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'
- * } );
- * $( document.body ).append( button.$element );
- * } );
- *
- * @param {string} key Message key
- * @param {...Mixed} [params] Message parameters
- * @return {string} Translated message with parameters substituted
- */
- OO.ui.msg = function ( key ) {
- var message = messages[ key ],
- params = Array.prototype.slice.call( arguments, 1 );
- if ( typeof message === 'string' ) {
- // Perform $1 substitution
- message = message.replace( /\$(\d+)/g, function ( unused, n ) {
- var i = parseInt( n, 10 );
- return params[ i - 1 ] !== undefined ? params[ i - 1 ] : '$' + n;
- } );
- } else {
- // Return placeholder if message not found
- message = '[' + key + ']';
- }
- return message;
- };
-}() );
+/**
+ * Get a localized message.
+ *
+ * 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.
+ * // OOUI 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'
+ * } );
+ * $( document.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'
+ * } );
+ * $( document.body ).append( button.$element );
+ * } );
+ *
+ * @param {string} key Message key
+ * @param {...Mixed} [params] Message parameters
+ * @return {string} Translated message with parameters substituted
+ */
+OO.ui.msg = function ( key ) {
+ // `OO.ui.msg.messages` is defined in code generated during the build process
+ var messages = OO.ui.msg.messages,
+ message = messages[ key ],
+ params = Array.prototype.slice.call( arguments, 1 );
+ if ( typeof message === 'string' ) {
+ // Perform $1 substitution
+ message = message.replace( /\$(\d+)/g, function ( unused, n ) {
+ var i = parseInt( n, 10 );
+ return params[ i - 1 ] !== undefined ? params[ i - 1 ] : '$' + n;
+ } );
+ } else {
+ // Return placeholder if message not found
+ message = '[' + key + ']';
+ }
+ return message;
+};
/**
* Package a message and arguments for deferred resolution.
@@ -581,6 +533,36 @@ OO.ui.getDefaultOverlay = function () {
return OO.ui.$defaultOverlay;
};
+/**
+ * Message store for the default implementation of OO.ui.msg.
+ *
+ * Environments that provide a localization system should not use this, but should override
+ * OO.ui.msg altogether.
+ *
+ * @private
+ */
+OO.ui.msg.messages = {
+ "ooui-outline-control-move-down": "Move item down",
+ "ooui-outline-control-move-up": "Move item up",
+ "ooui-outline-control-remove": "Remove item",
+ "ooui-toolbar-more": "More",
+ "ooui-toolgroup-expand": "More",
+ "ooui-toolgroup-collapse": "Fewer",
+ "ooui-item-remove": "Remove",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Cancel",
+ "ooui-dialog-process-error": "Something went wrong",
+ "ooui-dialog-process-dismiss": "Dismiss",
+ "ooui-dialog-process-retry": "Try again",
+ "ooui-dialog-process-continue": "Continue",
+ "ooui-combobox-button-label": "Dropdown for combobox",
+ "ooui-selectfile-button-select": "Select a file",
+ "ooui-selectfile-not-supported": "File selection is not supported",
+ "ooui-selectfile-placeholder": "No file is selected",
+ "ooui-selectfile-dragdrop-placeholder": "Drop file here",
+ "ooui-field-help": "Help"
+};
+
/*!
* Mixin namespace.
*/
@@ -2118,7 +2100,7 @@ OO.ui.mixin.TabIndexedElement.prototype.getInputId = function () {
OO.ui.mixin.TabIndexedElement.prototype.isLabelableNode = function ( $node ) {
var
labelableTags = [ 'button', 'meter', 'output', 'progress', 'select', 'textarea' ],
- tagName = $node.prop( 'tagName' ).toLowerCase();
+ tagName = ( $node.prop( 'tagName' ) || '' ).toLowerCase();
if ( tagName === 'input' && $node.attr( 'type' ) !== 'hidden' ) {
return true;
@@ -3456,6 +3438,9 @@ OO.initClass( OO.ui.mixin.TitledElement );
* The title text, a function that returns text, or `null` for no title. The value of the static
* property is overridden if the #title config option is used.
*
+ * If the element has a default title (e.g. ``), `null` will allow that title to be
+ * shown. Use empty string to suppress it.
+ *
* @static
* @inheritable
* @property {string|Function|null}
@@ -3480,9 +3465,7 @@ OO.ui.mixin.TitledElement.prototype.setTitledElement = function ( $titled ) {
}
this.$titled = $titled;
- if ( this.title ) {
- this.updateTitle();
- }
+ this.updateTitle();
};
/**
@@ -3495,7 +3478,7 @@ OO.ui.mixin.TitledElement.prototype.setTitledElement = function ( $titled ) {
*/
OO.ui.mixin.TitledElement.prototype.setTitle = function ( title ) {
title = typeof title === 'function' ? OO.ui.resolveMsg( title ) : title;
- title = ( typeof title === 'string' && title.length ) ? title : null;
+ title = typeof title === 'string' ? title : null;
if ( this.title !== title ) {
this.title = title;
@@ -6420,6 +6403,7 @@ OO.ui.OptionWidget.prototype.getMatchText = function () {
* Options are created with {@link OO.ui.OptionWidget OptionWidget} classes. See
* the [OOUI documentation on MediaWiki] [2] for examples.
* [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options
+ * @cfg {boolean} [multiselect] Allow for multiple selections
*/
OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
// Configuration initialization
@@ -6436,6 +6420,7 @@ OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
// Properties
this.pressed = false;
this.selecting = null;
+ this.multiselect = !!config.multiselect;
this.onDocumentMouseUpHandler = this.onDocumentMouseUp.bind( this );
this.onDocumentMouseMoveHandler = this.onDocumentMouseMove.bind( this );
this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );
@@ -6496,13 +6481,16 @@ OO.mixinClass( OO.ui.SelectWidget, OO.ui.mixin.GroupWidget );
* A `select` event is emitted when the selection is modified programmatically with the #selectItem
* method.
*
- * @param {OO.ui.OptionWidget|null} item Selected item
+ * @param {OO.ui.OptionWidget[]|OO.ui.OptionWidget|null} items Currently selected items
*/
/**
* @event choose
+ *
* A `choose` event is emitted when an item is chosen with the #chooseItem method.
+ *
* @param {OO.ui.OptionWidget} item Chosen item
+ * @param {boolean} selected Item is selected
*/
/**
@@ -6699,12 +6687,13 @@ OO.ui.SelectWidget.prototype.onMouseLeave = function () {
OO.ui.SelectWidget.prototype.onDocumentKeyDown = function ( e ) {
var nextItem,
handled = false,
- currentItem = this.findHighlightedItem() || this.findSelectedItem();
+ currentItem = this.findHighlightedItem(),
+ firstItem = this.getItems()[ 0 ];
if ( !this.isDisabled() && this.isVisible() ) {
switch ( e.keyCode ) {
case OO.ui.Keys.ENTER:
- if ( currentItem && currentItem.constructor.static.highlightable ) {
+ if ( currentItem ) {
// Was only highlighted, now let's select it. No-op if already selected.
this.chooseItem( currentItem );
handled = true;
@@ -6713,18 +6702,18 @@ OO.ui.SelectWidget.prototype.onDocumentKeyDown = function ( e ) {
case OO.ui.Keys.UP:
case OO.ui.Keys.LEFT:
this.clearKeyPressBuffer();
- nextItem = this.findRelativeSelectableItem( currentItem, -1 );
+ nextItem = currentItem ? this.findRelativeSelectableItem( currentItem, -1 ) : firstItem;
handled = true;
break;
case OO.ui.Keys.DOWN:
case OO.ui.Keys.RIGHT:
this.clearKeyPressBuffer();
- nextItem = this.findRelativeSelectableItem( currentItem, 1 );
+ nextItem = currentItem ? this.findRelativeSelectableItem( currentItem, 1 ) : firstItem;
handled = true;
break;
case OO.ui.Keys.ESCAPE:
case OO.ui.Keys.TAB:
- if ( currentItem && currentItem.constructor.static.highlightable ) {
+ if ( currentItem ) {
currentItem.setHighlighted( false );
}
this.unbindDocumentKeyDownListener();
@@ -6944,20 +6933,36 @@ OO.ui.SelectWidget.prototype.findTargetItem = function ( e ) {
return $option.data( 'oo-ui-optionWidget' ) || null;
};
+/**
+ * Find all selected items, if there are any. If the widget allows for multiselect
+ * it will return an array of selected options. If the widget doesn't allow for
+ * multiselect, it will return the selected option or null if no item is selected.
+ *
+ * @return {OO.ui.OptionWidget[]|OO.ui.OptionWidget|null} If the widget is multiselect
+ * then return an array of selected items (or empty array),
+ * if the widget is not multiselect, return a single selected item, or `null`
+ * if no item is selected
+ */
+OO.ui.SelectWidget.prototype.findSelectedItems = function () {
+ var selected = this.items.filter( function ( item ) {
+ return item.isSelected();
+ } );
+
+ return this.multiselect ?
+ selected :
+ selected[ 0 ] || null;
+};
+
/**
* Find selected item.
*
- * @return {OO.ui.OptionWidget|null} Selected item, `null` if no item is selected
+ * @return {OO.ui.OptionWidget[]|OO.ui.OptionWidget|null} If the widget is multiselect
+ * then return an array of selected items (or empty array),
+ * if the widget is not multiselect, return a single selected item, or `null`
+ * if no item is selected
*/
OO.ui.SelectWidget.prototype.findSelectedItem = function () {
- var i, len;
-
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- if ( this.items[ i ].isSelected() ) {
- return this.items[ i ];
- }
- }
- return null;
+ return this.findSelectedItems();
};
/**
@@ -7104,6 +7109,30 @@ OO.ui.SelectWidget.prototype.selectItemByData = function ( data ) {
return this.selectItem( itemFromData );
};
+/**
+ * Programmatically unselect an option by its reference. If the widget
+ * allows for multiple selections, there may be other items still selected;
+ * otherwise, no items will be selected.
+ * If no item is given, all selected items will be unselected.
+ *
+ * @param {OO.ui.OptionWidget} [item] Item to unselect
+ * @fires select
+ * @chainable
+ * @return {OO.ui.Widget} The widget, for chaining
+ */
+OO.ui.SelectWidget.prototype.unselectItem = function ( item ) {
+ if ( item ) {
+ item.setSelected( false );
+ } else {
+ this.items.forEach( function ( item ) {
+ item.setSelected( false );
+ } );
+ }
+
+ this.emit( 'select', this.findSelectedItems() );
+ return this;
+};
+
/**
* Programmatically select an option by its reference. If the `item` parameter is omitted,
* all options will be deselected.
@@ -7117,14 +7146,20 @@ OO.ui.SelectWidget.prototype.selectItem = function ( item ) {
var i, len, selected,
changed = false;
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- selected = this.items[ i ] === item;
- if ( this.items[ i ].isSelected() !== selected ) {
- this.items[ i ].setSelected( selected );
- changed = true;
+ if ( this.multiselect && item ) {
+ // Select the item directly
+ item.setSelected( true );
+ } else {
+ for ( i = 0, len = this.items.length; i < len; i++ ) {
+ selected = this.items[ i ] === item;
+ if ( this.items[ i ].isSelected() !== selected ) {
+ this.items[ i ].setSelected( selected );
+ changed = true;
+ }
}
}
if ( changed ) {
+ // TODO: When should a non-highlightable element be selected?
if ( item && !item.constructor.static.highlightable ) {
if ( item ) {
this.$focusOwner.attr( 'aria-activedescendant', item.getElementId() );
@@ -7132,7 +7167,7 @@ OO.ui.SelectWidget.prototype.selectItem = function ( item ) {
this.$focusOwner.removeAttr( 'aria-activedescendant' );
}
}
- this.emit( 'select', item );
+ this.emit( 'select', this.findSelectedItems() );
}
return this;
@@ -7185,8 +7220,13 @@ OO.ui.SelectWidget.prototype.pressItem = function ( item ) {
*/
OO.ui.SelectWidget.prototype.chooseItem = function ( item ) {
if ( item ) {
- this.selectItem( item );
- this.emit( 'choose', item );
+ if ( this.multiselect && item.isSelected() ) {
+ this.unselectItem( item );
+ } else {
+ this.selectItem( item );
+ }
+
+ this.emit( 'choose', item, item.isSelected() );
}
return this;
@@ -7655,7 +7695,7 @@ OO.ui.MenuSelectWidget.prototype.onDocumentKeyDown = function ( e ) {
break;
case OO.ui.Keys.ESCAPE:
case OO.ui.Keys.TAB:
- if ( currentItem ) {
+ if ( currentItem && !this.multiselect ) {
currentItem.setHighlighted( false );
}
this.toggle( false );
@@ -7712,10 +7752,6 @@ OO.ui.MenuSelectWidget.prototype.updateItemVisibility = function () {
section.toggle( showAll || !sectionEmpty );
}
- if ( anyVisible && this.items.length && !exactMatch ) {
- this.scrollItemIntoView( this.items[ 0 ] );
- }
-
if ( !anyVisible ) {
this.highlightItem( null );
}
@@ -7872,7 +7908,7 @@ OO.ui.MenuSelectWidget.prototype.clearItems = function () {
* @inheritdoc
*/
OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
- var change, originalHeight, flippedHeight;
+ var change, originalHeight, flippedHeight, selectedItem;
visible = ( visible === undefined ? !this.visible : !!visible ) && !!this.items.length;
change = visible !== this.isVisible();
@@ -7937,9 +7973,13 @@ OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
this.$focusOwner.attr( 'aria-expanded', 'true' );
- if ( this.findSelectedItem() ) {
- this.$focusOwner.attr( 'aria-activedescendant', this.findSelectedItem().getElementId() );
- this.findSelectedItem().scrollElementIntoView( { duration: 0 } );
+ selectedItem = this.findSelectedItem();
+ if ( !this.multiselect && selectedItem ) {
+ // TODO: Verify if this is even needed; This is already done on highlight changes
+ // in SelectWidget#highlightItem, so we should just need to highlight the item we need to
+ // highlight here and not bother with attr or checking selections.
+ this.$focusOwner.attr( 'aria-activedescendant', selectedItem.getElementId() );
+ selectedItem.scrollElementIntoView( { duration: 0 } );
}
// Auto-hide
@@ -7962,6 +8002,13 @@ OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
return this;
};
+/**
+ * Scroll to the top of the menu
+ */
+OO.ui.MenuSelectWidget.prototype.scrollToTop = function () {
+ this.$element.scrollTop( 0 );
+};
+
/**
* DropdownWidgets are not menus themselves, rather they contain a menu of options created with
* OO.ui.MenuOptionWidget. The DropdownWidget takes care of opening and displaying the menu so that
@@ -9401,6 +9448,7 @@ OO.ui.ButtonInputWidget.prototype.getInputId = function () {
* @param {Object} [config] Configuration options
* @cfg {boolean} [selected=false] Select the checkbox initially. By default, the checkbox is
* not selected.
+ * @cfg {boolean} [indeterminate=false] Whether the checkbox is in the indeterminate state.
*/
OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
// Configuration initialization
@@ -9421,12 +9469,24 @@ OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
// Required for pretty styling in WikimediaUI theme
.append( this.checkIcon.$element );
this.setSelected( config.selected !== undefined ? config.selected : false );
+ this.setIndeterminate( config.indeterminate !== undefined ? config.indeterminate : false );
};
/* Setup */
OO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget );
+/* Events */
+
+/**
+ * @event change
+ *
+ * A change event is emitted when the state of the input changes.
+ *
+ * @param {boolean} selected
+ * @param {boolean} indeterminate
+ */
+
/* Static Properties */
/**
@@ -9465,6 +9525,7 @@ OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
// Allow the stack to clear so the value will be updated
setTimeout( function () {
widget.setSelected( widget.$input.prop( 'checked' ) );
+ widget.setIndeterminate( widget.$input.prop( 'indeterminate' ) );
} );
}
};
@@ -9472,16 +9533,20 @@ OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
/**
* Set selection state of this checkbox.
*
- * @param {boolean} state `true` for selected
+ * @param {boolean} state Selected state
+ * @param {boolean} internal Used for internal calls to suppress events
* @chainable
- * @return {OO.ui.Widget} The widget, for chaining
+ * @return {OO.ui.CheckboxInputWidget} The widget, for chaining
*/
-OO.ui.CheckboxInputWidget.prototype.setSelected = function ( state ) {
+OO.ui.CheckboxInputWidget.prototype.setSelected = function ( state, internal ) {
state = !!state;
if ( this.selected !== state ) {
this.selected = state;
this.$input.prop( 'checked', this.selected );
- this.emit( 'change', this.selected );
+ if ( !internal ) {
+ this.setIndeterminate( false, true );
+ this.emit( 'change', this.selected, this.indeterminate );
+ }
}
// The first time that the selection state is set (probably while constructing the widget),
// remember it in defaultSelected. This property can be later used to check whether
@@ -9508,6 +9573,42 @@ OO.ui.CheckboxInputWidget.prototype.isSelected = function () {
return this.selected;
};
+/**
+ * Set indeterminate state of this checkbox.
+ *
+ * @param {boolean} state Indeterminate state
+ * @param {boolean} internal Used for internal calls to suppress events
+ * @chainable
+ * @return {OO.ui.CheckboxInputWidget} The widget, for chaining
+ */
+OO.ui.CheckboxInputWidget.prototype.setIndeterminate = function ( state, internal ) {
+ state = !!state;
+ if ( this.indeterminate !== state ) {
+ this.indeterminate = state;
+ this.$input.prop( 'indeterminate', this.indeterminate );
+ if ( !internal ) {
+ this.setSelected( false, true );
+ this.emit( 'change', this.selected, this.indeterminate );
+ }
+ }
+ return this;
+};
+
+/**
+ * Check if this checkbox is selected.
+ *
+ * @return {boolean} Checkbox is selected
+ */
+OO.ui.CheckboxInputWidget.prototype.isIndeterminate = function () {
+ // Resynchronize our internal data with DOM data. Other scripts executing on the page can modify
+ // it, and we won't know unless they're kind enough to trigger a 'change' event.
+ var indeterminate = this.$input.prop( 'indeterminate' );
+ if ( this.indeterminate !== indeterminate ) {
+ this.setIndeterminate( indeterminate );
+ }
+ return this.indeterminate;
+};
+
/**
* @inheritdoc
*/
@@ -10397,7 +10498,7 @@ OO.ui.CheckboxMultiselectInputWidget.prototype.focus = function () {
* // A TextInputWidget.
* var textInput = new OO.ui.TextInputWidget( {
* value: 'Text input'
- * } )
+ * } );
* $( document.body ).append( textInput.$element );
*
* [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs
@@ -11117,6 +11218,7 @@ OO.ui.SearchInputWidget = function OoUiSearchInputWidget( config ) {
this.connect( this, {
change: 'onChange'
} );
+ this.$indicator.on( 'click', this.onIndicatorClick.bind( this ) );
// Initialization
this.updateSearchIndicator();
@@ -11140,9 +11242,12 @@ OO.ui.SearchInputWidget.prototype.getSaneType = function () {
};
/**
- * @inheritdoc
+ * Handle click events on the indicator
+ *
+ * @param {jQuery.Event} e Click event
+ * @return {boolean}
*/
-OO.ui.SearchInputWidget.prototype.onIndicatorMouseDown = function ( e ) {
+OO.ui.SearchInputWidget.prototype.onIndicatorClick = function ( e ) {
if ( e.which === OO.ui.MouseButtons.LEFT ) {
// Clear the text field
this.setValue( '' );
@@ -11205,8 +11310,8 @@ OO.ui.SearchInputWidget.prototype.setReadOnly = function ( state ) {
* // A MultilineTextInputWidget.
* var multilineTextInput = new OO.ui.MultilineTextInputWidget( {
* value: 'Text input on multiple lines'
- * } )
- * $( 'body' ).append( multilineTextInput.$element );
+ * } );
+ * $( document.body ).append( multilineTextInput.$element );
*
* [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs#MultilineTextInputWidget
*
@@ -12360,21 +12465,21 @@ OO.ui.FieldsetLayout.static.tagName = 'fieldset';
* [2]: https://www.mediawiki.org/wiki/OOUI/Widgets/Inputs
*
* @example
- * // Example of a form layout that wraps a fieldset layout
+ * // Example of a form layout that wraps a fieldset layout.
* var input1 = new OO.ui.TextInputWidget( {
- * placeholder: 'Username'
- * } );
- * var input2 = new OO.ui.TextInputWidget( {
- * placeholder: 'Password',
- * type: 'password'
- * } );
- * var submit = new OO.ui.ButtonInputWidget( {
- * label: 'Submit'
- * } );
+ * placeholder: 'Username'
+ * } ),
+ * input2 = new OO.ui.TextInputWidget( {
+ * placeholder: 'Password',
+ * type: 'password'
+ * } ),
+ * submit = new OO.ui.ButtonInputWidget( {
+ * label: 'Submit'
+ * } ),
+ * fieldset = new OO.ui.FieldsetLayout( {
+ * label: 'A form layout'
+ * } );
*
- * var fieldset = new OO.ui.FieldsetLayout( {
- * label: 'A form layout'
- * } );
* fieldset.addItems( [
* new OO.ui.FieldLayout( input1, {
* label: 'Username',
@@ -12565,7 +12670,7 @@ OO.ui.PanelLayout.prototype.focus = function () {
* Note that inline elements, such as OO.ui.ButtonWidgets, do not need this wrapper.
*
* @example
- * // HorizontalLayout with a text input and a label
+ * // HorizontalLayout with a text input and a label.
* var layout = new OO.ui.HorizontalLayout( {
* items: [
* new OO.ui.LabelWidget( { label: 'Label' } ),
@@ -12978,6 +13083,269 @@ OO.ui.NumberInputWidget.prototype.setDisabled = function ( disabled ) {
return this;
};
+/**
+ * SelectFileInputWidgets allow for selecting files, using . These
+ * widgets can be configured with {@link OO.ui.mixin.IconElement icons}, {@link
+ * OO.ui.mixin.IndicatorElement indicators} and {@link OO.ui.mixin.TitledElement titles}.
+ * Please see the [OOUI documentation on MediaWiki] [1] for more information and examples.
+ *
+ * SelectFileInputWidgets must be used in HTML forms, as getValue only returns the filename.
+ *
+ * @example
+ * // A file select input widget.
+ * var selectFile = new OO.ui.SelectFileInputWidget();
+ * $( document.body ).append( selectFile.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOUI/Widgets
+ *
+ * @class
+ * @extends OO.ui.InputWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string[]|null} [accept=null] MIME types to accept. null accepts all types.
+ * @cfg {boolean} [multiple=false] Allow multiple files to be selected.
+ * @cfg {string} [placeholder] Text to display when no file is selected.
+ * @cfg {Object} [button] Config to pass to select file button.
+ * @cfg {string} [icon] Icon to show next to file info
+ */
+OO.ui.SelectFileInputWidget = function OoUiSelectFileInputWidget( config ) {
+ var widget = this;
+
+ config = config || {};
+
+ // Construct buttons before parent method is called (calling setDisabled)
+ this.selectButton = new OO.ui.ButtonWidget( $.extend( {
+ $element: $( '