2 * MediaWiki Widgets - SelectWithInputWidget class.
4 * @copyright 2011-2017 MediaWiki Widgets Team and others; see AUTHORS.txt
5 * @license The MIT License (MIT); see LICENSE.txt
10 * @classdesc Select with input widget. Displays an OO.ui.TextInputWidget along with
11 * an OO.ui.DropdownInputWidget.
12 * TODO Explain the OTHER option
15 * mw.loader.using( 'mediawiki.widgets.SelectWithInputWidget', function () {
16 * let swi = new mw.widgets.SelectWithInputWidget( {
20 * { data: 'other', label: 'Other' },
21 * { data: 'a', label: 'First' },
22 * { data: 'b', label: 'Second' },
23 * { data: 'c', label: 'Third' }
30 * $( document.body ).append( swi.$element );
33 * @class mw.widgets.SelectWithInputWidget
34 * @extends OO.ui.Widget
37 * @description Create an instance of `mw.widgets.SelectWithInputWidget`.
38 * @param {Object} [config] Configuration options
39 * @param {Object} [config.dropdowninput] Config for the dropdown
40 * @param {Object} [config.textinput] Config for the text input
41 * @param {boolean} [config.or=false] Config for whether the widget is dropdown AND input
42 * or dropdown OR input
43 * @param {boolean} [config.required=false] Config for whether input is required
45 mw.widgets.SelectWithInputWidget = function MwWidgetsSelectWithInputWidget( config ) {
46 // Config initialization
47 config = Object.assign( { or: false, required: false }, config );
50 this.textinput = new OO.ui.TextInputWidget( config.textinput );
51 this.dropdowninput = new OO.ui.DropdownInputWidget( config.dropdowninput );
53 this.required = config.required;
56 this.dropdowninput.on( 'change', this.onChange.bind( this ) );
57 this.textinput.on( 'change', () => {
58 this.emit( 'change', this.getValue() );
62 mw.widgets.SelectWithInputWidget.super.call( this, config );
66 .addClass( 'mw-widget-selectWithInputWidget' )
68 this.dropdowninput.$element,
69 this.textinput.$element
75 OO.inheritClass( mw.widgets.SelectWithInputWidget, OO.ui.Widget );
82 mw.widgets.SelectWithInputWidget.static.reusePreInfuseDOM = function ( node, config ) {
83 config = mw.widgets.SelectWithInputWidget.super.static.reusePreInfuseDOM( node, config );
84 config.dropdowninput = OO.ui.DropdownInputWidget.static.reusePreInfuseDOM(
85 $( node ).find( '.oo-ui-dropdownInputWidget' ),
88 config.textinput = OO.ui.TextInputWidget.static.reusePreInfuseDOM(
89 $( node ).find( '.oo-ui-textInputWidget' ),
98 mw.widgets.SelectWithInputWidget.static.gatherPreInfuseState = function ( node, config ) {
99 const state = mw.widgets.SelectWithInputWidget.super.static.gatherPreInfuseState( node, config );
100 state.dropdowninput = OO.ui.DropdownInputWidget.static.gatherPreInfuseState(
101 $( node ).find( '.oo-ui-dropdownInputWidget' ),
104 state.textinput = OO.ui.TextInputWidget.static.gatherPreInfuseState(
105 $( node ).find( '.oo-ui-textInputWidget' ),
116 mw.widgets.SelectWithInputWidget.prototype.restorePreInfuseState = function ( state ) {
117 mw.widgets.SelectWithInputWidget.super.prototype.restorePreInfuseState.call( this, state );
118 this.dropdowninput.restorePreInfuseState( state.dropdowninput );
119 this.textinput.restorePreInfuseState( state.textinput );
125 mw.widgets.SelectWithInputWidget.prototype.setDisabled = function ( disabled ) {
126 const textinputIsHidden = this.or && this.dropdowninput.getValue() !== 'other';
127 mw.widgets.SelectWithInputWidget.super.prototype.setDisabled.call( this, disabled );
128 this.dropdowninput.setDisabled( disabled );
129 // It is impossible to submit a form with hidden fields failing validation, e.g. one that
130 // is required. However, validity is not checked for disabled fields, as these are not
131 // submitted with the form. So we should also disable fields when hiding them.
132 this.textinput.setDisabled( textinputIsHidden || disabled );
133 // If the widget is required, set the text field as required, but only if the widget is visible.
134 if ( this.required ) {
135 this.textinput.setRequired( !this.textinput.isDisabled() );
140 * Set the value from outside.
142 * @param {string|undefined} value
144 mw.widgets.SelectWithInputWidget.prototype.setValue = function ( value ) {
145 let selectable = false;
148 if ( value !== 'other' ) {
149 selectable = !!this.dropdowninput.dropdownWidget.getMenu().findItemFromData( value );
153 this.dropdowninput.setValue( value );
154 this.textinput.setValue( undefined );
156 this.dropdowninput.setValue( 'other' );
157 this.textinput.setValue( value );
160 this.emit( 'change', value );
165 * Get the value from outside.
169 mw.widgets.SelectWithInputWidget.prototype.getValue = function () {
171 if ( this.dropdowninput.getValue() !== 'other' ) {
172 return this.dropdowninput.getValue();
175 return this.textinput.getValue();
182 * Handle change events on the DropdownInput
184 * @param {string|undefined} value
187 mw.widgets.SelectWithInputWidget.prototype.onChange = function ( value ) {
189 value = value || this.dropdowninput.getValue();
190 this.textinput.$element.toggle( value === 'other' );
191 // It is impossible to submit a form with hidden fields failing validation, e.g. one that
192 // is required. However, validity is not checked for disabled fields, as these are not
193 // submitted with the form. So we should also disable fields when hiding them.
194 this.textinput.setDisabled( value !== 'other' || this.isDisabled() );
197 this.emit( 'change', this.getValue() );