/**
* OptionWidgets are special elements that can be selected and configured with data. The
* data is often unique for each option, but it does not have to be. OptionWidgets are used
* with OO.ui.SelectWidget to create a selection of mutually exclusive options. For more information
* and examples, please see the [OOUI documentation on MediaWiki][1].
*
* [1]: https://www.mediawiki.org/wiki/OOUI/Widgets/Selects_and_Options
*
* @class
* @extends OO.ui.Widget
* @mixes OO.ui.mixin.ItemWidget
* @mixes OO.ui.mixin.LabelElement
* @mixes OO.ui.mixin.FlaggedElement
* @mixes OO.ui.mixin.AccessKeyedElement
* @mixes OO.ui.mixin.TitledElement
*
* @constructor
* @param {Object} [config] Configuration options
* @param {boolean} [config.selected=false]
*/
OO.ui.OptionWidget = function OoUiOptionWidget( config ) {
// Configuration initialization
config = config || {};
// Parent constructor
OO.ui.OptionWidget.super.call( this, config );
// Mixin constructors
OO.ui.mixin.ItemWidget.call( this );
OO.ui.mixin.LabelElement.call( this, config );
OO.ui.mixin.FlaggedElement.call( this, config );
OO.ui.mixin.AccessKeyedElement.call( this, config );
OO.ui.mixin.TitledElement.call( this, config );
// Properties
this.highlighted = false;
this.pressed = false;
this.setSelected( !!config.selected );
// Initialization
this.$element
.data( 'oo-ui-optionWidget', this )
// Allow programmatic focussing (and by access key), but not tabbing
.attr( {
tabindex: '-1',
role: 'option'
} )
.addClass( 'oo-ui-optionWidget' )
.append( this.$label );
};
/* Setup */
OO.inheritClass( OO.ui.OptionWidget, OO.ui.Widget );
OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.ItemWidget );
OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.LabelElement );
OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.FlaggedElement );
OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.AccessKeyedElement );
OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.TitledElement );
/* Static Properties */
/**
* Whether this option can be selected. See #setSelected.
*
* @static
* @property {boolean}
*/
OO.ui.OptionWidget.static.selectable = true;
/**
* Whether this option can be highlighted. See #setHighlighted.
*
* @static
* @property {boolean}
*/
OO.ui.OptionWidget.static.highlightable = true;
/**
* Whether this option can be pressed. See #setPressed.
*
* @static
* @property {boolean}
*/
OO.ui.OptionWidget.static.pressable = true;
/**
* Whether this option will be scrolled into view when it is selected.
*
* @static
* @property {boolean}
*/
OO.ui.OptionWidget.static.scrollIntoViewOnSelect = false;
/* Methods */
/**
* Check if the option can be selected.
*
* @return {boolean} Item is selectable
*/
OO.ui.OptionWidget.prototype.isSelectable = function () {
return this.constructor.static.selectable && !this.disabled && this.isVisible();
};
/**
* Check if the option can be highlighted. A highlight indicates that the option
* may be selected when a user presses Enter key or clicks. Disabled items cannot
* be highlighted.
*
* @return {boolean} Item is highlightable
*/
OO.ui.OptionWidget.prototype.isHighlightable = function () {
return this.constructor.static.highlightable && !this.disabled && this.isVisible();
};
/**
* Check if the option can be pressed. The pressed state occurs when a user mouses
* down on an item, but has not yet let go of the mouse.
*
* @return {boolean} Item is pressable
*/
OO.ui.OptionWidget.prototype.isPressable = function () {
return this.constructor.static.pressable && !this.disabled && this.isVisible();
};
/**
* Check if the option is selected.
*
* @return {boolean} Item is selected
*/
OO.ui.OptionWidget.prototype.isSelected = function () {
return this.selected;
};
/**
* Check if the option is highlighted. A highlight indicates that the
* item may be selected when a user presses Enter key or clicks.
*
* @return {boolean} Item is highlighted
*/
OO.ui.OptionWidget.prototype.isHighlighted = function () {
return this.highlighted;
};
/**
* Check if the option is pressed. The pressed state occurs when a user mouses
* down on an item, but has not yet let go of the mouse. The item may appear
* selected, but it will not be selected until the user releases the mouse.
*
* @return {boolean} Item is pressed
*/
OO.ui.OptionWidget.prototype.isPressed = function () {
return this.pressed;
};
/**
* Set the option’s selected state. In general, all modifications to the selection
* should be handled by the SelectWidget’s
* {@link OO.ui.SelectWidget#selectItem selectItem( [item] )} method instead of this method.
*
* @param {boolean} [state=false] Select option
* @chainable
* @return {OO.ui.Widget} The widget, for chaining
*/
OO.ui.OptionWidget.prototype.setSelected = function ( state ) {
if ( this.constructor.static.selectable ) {
this.selected = !!state;
this.$element
.toggleClass( 'oo-ui-optionWidget-selected', state )
.attr( 'aria-selected', this.selected.toString() );
if ( state && this.constructor.static.scrollIntoViewOnSelect ) {
this.scrollElementIntoView();
}
this.updateThemeClasses();
}
return this;
};
/**
* Set the option’s highlighted state. In general, all programmatic
* modifications to the highlight should be handled by the
* SelectWidget’s {@link OO.ui.SelectWidget#highlightItem highlightItem( [item] )}
* method instead of this method.
*
* @param {boolean} [state=false] Highlight option
* @chainable
* @return {OO.ui.Widget} The widget, for chaining
*/
OO.ui.OptionWidget.prototype.setHighlighted = function ( state ) {
if ( this.constructor.static.highlightable ) {
this.highlighted = !!state;
this.$element.toggleClass( 'oo-ui-optionWidget-highlighted', state );
this.updateThemeClasses();
}
return this;
};
/**
* Set the option’s pressed state. In general, all
* programmatic modifications to the pressed state should be handled by the
* SelectWidget’s {@link OO.ui.SelectWidget#pressItem pressItem( [item] )}
* method instead of this method.
*
* @param {boolean} [state=false] Press option
* @chainable
* @return {OO.ui.Widget} The widget, for chaining
*/
OO.ui.OptionWidget.prototype.setPressed = function ( state ) {
if ( this.constructor.static.pressable ) {
this.pressed = !!state;
this.$element.toggleClass( 'oo-ui-optionWidget-pressed', state );
this.updateThemeClasses();
}
return this;
};
/**
* Get text to match search strings against.
*
* The default implementation returns the label text, but subclasses
* can override this to provide more complex behavior.
*
* @return {string|boolean} String to match search string against
*/
OO.ui.OptionWidget.prototype.getMatchText = function () {
const label = this.getLabel();
return typeof label === 'string' ? label : this.$label.text();
};