Merge "mediawiki.Uri: Add another test for arrayParams"
[lhc/web/wiklou.git] / resources / src / mediawiki.widgets / mw.widgets.SelectWithInputWidget.js
1 /*!
2 * MediaWiki Widgets - SelectWithInputWidget class.
3 *
4 * @copyright 2011-2017 MediaWiki Widgets Team and others; see AUTHORS.txt
5 * @license The MIT License (MIT); see LICENSE.txt
6 */
7 ( function () {
8
9 /**
10 * Select with input widget. Displays an OO.ui.TextInputWidget along with
11 * an OO.ui.DropdownInputWidget.
12 * TODO Explain the OTHER option
13 *
14 * mw.loader.using( 'mediawiki.widgets.SelectWithInputWidget', function () {
15 * var swi = new mw.widgets.SelectWithInputWidget( {
16 * or: true,
17 * dropdowninput: {
18 * options: [
19 * { data: 'other', label: 'Other' },
20 * { data: 'a', label: 'First' },
21 * { data: 'b', label: 'Second' },
22 * { data: 'c', label: 'Third' }
23 * ]
24 * },
25 * textinput: {
26 * }
27 * } );
28 *
29 * $( 'body' ).append( swi.$element );
30 * } );
31 *
32 * @class mw.widgets.SelectWithInputWidget
33 * @extends OO.ui.Widget
34 *
35 * @constructor
36 * @param {Object} [config] Configuration options
37 * @cfg {Object} [dropdowninput] Config for the dropdown
38 * @cfg {Object} [textinput] Config for the text input
39 * @cfg {boolean} [or=false] Config for whether the widget is dropdown AND input
40 * or dropdown OR input
41 * @cfg {boolean} [required=false] Config for whether input is required
42 */
43 mw.widgets.SelectWithInputWidget = function MwWidgetsSelectWithInputWidget( config ) {
44 // Config initialization
45 config = $.extend( { or: false, required: false }, config );
46
47 // Properties
48 this.textinput = new OO.ui.TextInputWidget( config.textinput );
49 this.dropdowninput = new OO.ui.DropdownInputWidget( config.dropdowninput );
50 this.or = config.or;
51 this.required = config.required;
52
53 // Events
54 this.dropdowninput.on( 'change', this.onChange.bind( this ) );
55 this.textinput.on( 'change', function () {
56 this.emit( 'change', this.getValue() );
57 }.bind( this ) );
58
59 // Parent constructor
60 mw.widgets.SelectWithInputWidget.parent.call( this, config );
61
62 // Initialization
63 this.$element
64 .addClass( 'mw-widget-selectWithInputWidget' )
65 .append(
66 this.dropdowninput.$element,
67 this.textinput.$element
68 );
69 this.onChange();
70 };
71
72 /* Setup */
73 OO.inheritClass( mw.widgets.SelectWithInputWidget, OO.ui.Widget );
74
75 /* Static Methods */
76
77 /**
78 * @inheritdoc
79 */
80 mw.widgets.SelectWithInputWidget.static.reusePreInfuseDOM = function ( node, config ) {
81 config = mw.widgets.SelectWithInputWidget.parent.static.reusePreInfuseDOM( node, config );
82 config.dropdowninput = OO.ui.DropdownInputWidget.static.reusePreInfuseDOM(
83 $( node ).find( '.oo-ui-dropdownInputWidget' ),
84 config.dropdowninput
85 );
86 config.textinput = OO.ui.TextInputWidget.static.reusePreInfuseDOM(
87 $( node ).find( '.oo-ui-textInputWidget' ),
88 config.textinput
89 );
90 return config;
91 };
92
93 /**
94 * @inheritdoc
95 */
96 mw.widgets.SelectWithInputWidget.static.gatherPreInfuseState = function ( node, config ) {
97 var state = mw.widgets.SelectWithInputWidget.parent.static.gatherPreInfuseState( node, config );
98 state.dropdowninput = OO.ui.DropdownInputWidget.static.gatherPreInfuseState(
99 $( node ).find( '.oo-ui-dropdownInputWidget' ),
100 config.dropdowninput
101 );
102 state.textinput = OO.ui.TextInputWidget.static.gatherPreInfuseState(
103 $( node ).find( '.oo-ui-textInputWidget' ),
104 config.textinput
105 );
106 return state;
107 };
108
109 /* Methods */
110
111 /**
112 * @inheritdoc
113 */
114 mw.widgets.SelectWithInputWidget.prototype.restorePreInfuseState = function ( state ) {
115 mw.widgets.SelectWithInputWidget.parent.prototype.restorePreInfuseState.call( this, state );
116 this.dropdowninput.restorePreInfuseState( state.dropdowninput );
117 this.textinput.restorePreInfuseState( state.textinput );
118 };
119
120 /**
121 * @inheritdoc
122 */
123 mw.widgets.SelectWithInputWidget.prototype.setDisabled = function ( disabled ) {
124 var textinputIsHidden = this.or && this.dropdowninput.getValue() !== 'other';
125 mw.widgets.SelectWithInputWidget.parent.prototype.setDisabled.call( this, disabled );
126 this.dropdowninput.setDisabled( disabled );
127 // It is impossible to submit a form with hidden fields failing validation, e.g. one that
128 // is required. However, validity is not checked for disabled fields, as these are not
129 // submitted with the form. So we should also disable fields when hiding them.
130 this.textinput.setDisabled( textinputIsHidden || disabled );
131 // If the widget is required, set the text field as required, but only if the widget is visible.
132 if ( this.required ) {
133 this.textinput.setRequired( !this.textinput.isDisabled() );
134 }
135 };
136
137 /**
138 * Set the value from outside.
139 *
140 * @param {string|undefined} value
141 */
142 mw.widgets.SelectWithInputWidget.prototype.setValue = function ( value ) {
143 var selectable = false;
144
145 if ( this.or ) {
146 if ( value !== 'other' ) {
147 selectable = !!this.dropdowninput.dropdownWidget.getMenu().findItemFromData( value );
148 }
149
150 if ( selectable ) {
151 this.dropdowninput.setValue( value );
152 this.textinput.setValue( undefined );
153 } else {
154 this.dropdowninput.setValue( 'other' );
155 this.textinput.setValue( value );
156 }
157
158 this.emit( 'change', value );
159 }
160 };
161
162 /**
163 * Get the value from outside.
164 *
165 * @return {string}
166 */
167 mw.widgets.SelectWithInputWidget.prototype.getValue = function () {
168 if ( this.or ) {
169 if ( this.dropdowninput.getValue() !== 'other' ) {
170 return this.dropdowninput.getValue();
171 }
172
173 return this.textinput.getValue();
174 } else {
175 return '';
176 }
177 };
178
179 /**
180 * Handle change events on the DropdownInput
181 *
182 * @param {string|undefined} value
183 * @private
184 */
185 mw.widgets.SelectWithInputWidget.prototype.onChange = function ( value ) {
186 if ( this.or ) {
187 value = value || this.dropdowninput.getValue();
188 this.textinput.$element.toggle( value === 'other' );
189 // It is impossible to submit a form with hidden fields failing validation, e.g. one that
190 // is required. However, validity is not checked for disabled fields, as these are not
191 // submitted with the form. So we should also disable fields when hiding them.
192 this.textinput.setDisabled( value !== 'other' || this.isDisabled() );
193 }
194
195 this.emit( 'change', this.getValue() );
196 };
197
198 }() );