/**
* SearchWidgets combine a {@link OO.ui.TextInputWidget text input field},
* where users can type a search query, and a menu of search results,
* which is displayed beneath the query field.
* Unlike {@link OO.ui.mixin.LookupElement lookup menus}, search result menus are always visible
* to the user. Users can choose an item from the menu or type a query into the text field to
* search for a matching result item.
* In general, search widgets are used inside a separate {@link OO.ui.Dialog dialog} window.
*
* Each time the query is changed, the search result menu is cleared and repopulated. Please see
* the [OOUI demos][1] for an example.
*
* [1]: https://doc.wikimedia.org/oojs-ui/master/demos/#SearchInputWidget-type-search
*
* @class
* @extends OO.ui.Widget
*
* @constructor
* @param {Object} [config] Configuration options
* @param {string|jQuery} [config.placeholder] Placeholder text for query input
* @param {string} [config.value] Initial query value
* @param {OO.ui.InputWidget} [config.input] {@link OO.ui.InputWidget Input widget} for search. Defaults
* to a {@link OO.ui.SearchInputWidget search input widget} if not provided.
*/
OO.ui.SearchWidget = function OoUiSearchWidget( config ) {
// Configuration initialization
config = config || {};
// Parent constructor
OO.ui.SearchWidget.super.call( this, config );
// Properties
this.query = config.input || new OO.ui.SearchInputWidget( {
placeholder: config.placeholder,
value: config.value
} );
this.results = new OO.ui.SelectWidget();
this.results.setFocusOwner( this.query.$input );
this.$query = $( '<div>' );
this.$results = $( '<div>' );
// Events
this.query.connect( this, {
change: 'onQueryChange',
enter: 'onQueryEnter'
} );
this.query.$input.on( 'keydown', this.onQueryKeydown.bind( this ) );
// Initialization
this.$query
.addClass( 'oo-ui-searchWidget-query' )
.append( this.query.$element );
this.$results
.addClass( 'oo-ui-searchWidget-results' )
.append( this.results.$element );
this.$element
.addClass( 'oo-ui-searchWidget' )
.append( this.$results, this.$query );
};
/* Setup */
OO.inheritClass( OO.ui.SearchWidget, OO.ui.Widget );
/* Methods */
/**
* Handle query key down events.
*
* @private
* @param {jQuery.Event} e Key down event
*/
OO.ui.SearchWidget.prototype.onQueryKeydown = function ( e ) {
const dir = e.which === OO.ui.Keys.DOWN ? 1 : ( e.which === OO.ui.Keys.UP ? -1 : 0 );
if ( dir ) {
const highlightedItem = this.results.findHighlightedItem() || this.results.findSelectedItem();
const nextItem = this.results.findRelativeSelectableItem( highlightedItem, dir );
// nextItem may be null if there are no results
this.results.highlightItem( nextItem );
if ( nextItem ) {
nextItem.scrollElementIntoView();
}
}
};
/**
* Handle select widget select events.
*
* Clears existing results. Subclasses should repopulate items according to new query.
*
* @private
* @param {string} value New value
*/
OO.ui.SearchWidget.prototype.onQueryChange = function () {
// Reset
this.results.clearItems();
};
/**
* Handle select widget enter key events.
*
* Chooses highlighted item.
*
* @private
* @param {string} value New value
*/
OO.ui.SearchWidget.prototype.onQueryEnter = function () {
const highlightedItem = this.results.findHighlightedItem();
if ( highlightedItem ) {
this.results.chooseItem( highlightedItem );
}
};
/**
* Get the query input.
*
* @return {OO.ui.TextInputWidget} Query input
*/
OO.ui.SearchWidget.prototype.getQuery = function () {
return this.query;
};
/**
* Get the search results menu.
*
* @return {OO.ui.SelectWidget} Menu of search results
*/
OO.ui.SearchWidget.prototype.getResults = function () {
return this.results;
};