/**
* ButtonMenuSelectWidgets launch a menu of options created with OO.ui.MenuOptionWidget.
* The ButtonMenuSelectWidget takes care of opening and displaying the menu so that
* users can interact with it.
*
* @example
* // A ButtonMenuSelectWidget with a menu that contains three options.
* const buttonMenu = new OO.ui.ButtonMenuSelectWidget( {
* icon: 'menu',
* menu: {
* items: [
* new OO.ui.MenuOptionWidget( {
* data: 'a',
* label: 'First'
* } ),
* new OO.ui.MenuOptionWidget( {
* data: 'b',
* label: 'Second'
* } ),
* new OO.ui.MenuOptionWidget( {
* data: 'c',
* label: 'Third'
* } )
* ]
* }
* } );
*
* $( document.body ).append( buttonMenu.$element );
*
* // When using the `clearOnSelect` option, listen to the `choose` event
* // to avoid getting the null select event.
* buttonMenu.getMenu().on( 'choose', function ( menuOption ) {
* console.log( menuOption.getData() );
* } );
*
* @class
* @extends OO.ui.ButtonWidget
*
* @constructor
* @param {Object} [config] Configuration options
* @param {boolean} [config.clearOnSelect=true] Clear selection immediately after making it
* @param {Object} [config.menuClass=OO.ui.MenuSelectWidget] Class for the menu widget. This
* must be a subclass of {@link OO.ui.MenuSelectWidget menu select widget}.
* @param {Object} [config.menu] Configuration options to pass to
* {@link OO.ui.MenuSelectWidget menu select widget}.
* @param {jQuery|boolean} [config.$overlay] Render the menu into a separate layer. This configuration is
* useful in cases where the expanded menu is larger than its containing `<div>`. The specified
* overlay layer is usually on top of the containing `<div>` and has a larger area. By default,
* the menu uses relative positioning. Pass 'true' to use the default overlay.
* See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.
*/
OO.ui.ButtonMenuSelectWidget = function OoUiButtonMenuSelectWidget( config ) {
// Configuration initialization
config = config || {};
// Parent constructor
OO.ui.ButtonMenuSelectWidget.super.call( this, config );
this.$overlay = ( config.$overlay === true ?
OO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;
const MenuClass = config.menuClass || OO.ui.MenuSelectWidget;
// Properties
this.clearOnSelect = config.clearOnSelect !== false;
this.menu = new MenuClass( Object.assign( {
widget: this,
$floatableContainer: this.$element,
spacing: 4 // @spacing-25
}, config.menu ) );
// Events
this.connect( this, {
click: 'onButtonMenuClick'
} );
this.getMenu().connect( this, {
select: 'onMenuSelect',
toggle: 'onMenuToggle'
} );
// Initialization
this.$button
.attr( {
'aria-expanded': 'false',
'aria-haspopup': 'true',
'aria-owns': this.menu.getElementId()
} );
this.$element.addClass( 'oo-ui-buttonMenuSelectWidget' );
this.$overlay.append( this.menu.$element );
};
/* Setup */
OO.inheritClass( OO.ui.ButtonMenuSelectWidget, OO.ui.ButtonWidget );
/* Methods */
/**
* Get the menu.
*
* @return {OO.ui.MenuSelectWidget} Menu of widget
*/
OO.ui.ButtonMenuSelectWidget.prototype.getMenu = function () {
return this.menu;
};
/**
* Handle menu select events.
*
* @private
* @param {OO.ui.MenuOptionWidget} item Selected menu item
*/
OO.ui.ButtonMenuSelectWidget.prototype.onMenuSelect = function ( item ) {
if ( this.clearOnSelect && item ) {
// This will cause an additional 'select' event to fire, so
// users should probably listen to the 'choose' event.
this.getMenu().selectItem();
}
};
/**
* Handle menu toggle events.
*
* @private
* @param {boolean} isVisible Open state of the menu
*/
OO.ui.ButtonMenuSelectWidget.prototype.onMenuToggle = function ( isVisible ) {
this.$element.toggleClass( 'oo-ui-buttonElement-pressed', isVisible );
};
/**
* Handle mouse click events.
*
* @private
*/
OO.ui.ButtonMenuSelectWidget.prototype.onButtonMenuClick = function () {
this.menu.toggle();
};