MediaWiki master
HTMLSelectAndOtherField.php
Go to the documentation of this file.
1<?php
2
4
5use InvalidArgumentException;
9
23 private const FIELD_CLASS = 'mw-htmlform-select-and-other-field';
25 private $mFlatOptions;
26
31 public function __construct( $params ) {
32 if ( array_key_exists( 'other', $params ) ) {
33 // Do nothing
34 } elseif ( array_key_exists( 'other-message', $params ) ) {
35 $params['other'] = $this->getMessage( $params['other-message'] )->plain();
36 } else {
37 $params['other'] = $this->msg( 'htmlform-selectorother-other' )->plain();
38 }
39
40 parent::__construct( $params );
41
42 if ( $this->getOptions() === null ) {
43 throw new InvalidArgumentException( 'HTMLSelectAndOtherField called without any options' );
44 }
45 if ( !in_array( 'other', $this->mOptions, true ) ) {
46 // Have 'other' always as first element
47 $this->mOptions = [ $params['other'] => 'other' ] + $this->mOptions;
48 }
49 $this->mFlatOptions = self::flattenOptions( $this->getOptions() );
50 }
51
52 public function getInputHTML( $value ) {
53 $select = parent::getInputHTML( $value[1] );
54
55 $textAttribs = [
56 'size' => $this->getSize(),
57 ];
58
59 if ( isset( $this->mParams['maxlength-unit'] ) ) {
60 $textAttribs['data-mw-maxlength-unit'] = $this->mParams['maxlength-unit'];
61 }
62
63 $allowedParams = [
64 'required',
65 'autofocus',
66 'multiple',
67 'disabled',
68 'tabindex',
69 'maxlength', // gets dynamic with javascript, see mediawiki.htmlform.js
70 'maxlength-unit', // 'bytes' or 'codepoints', see mediawiki.htmlform.js
71 ];
72
73 $textAttribs += $this->getAttributes( $allowedParams );
74
75 $textbox = Html::input( $this->mName . '-other', $value[2], 'text', $textAttribs );
76
77 $wrapperAttribs = [
78 'id' => $this->mID,
79 'class' => self::FIELD_CLASS
80 ];
81 if ( $this->mClass !== '' ) {
82 $wrapperAttribs['class'] .= ' ' . $this->mClass;
83 }
84 return Html::rawElement(
85 'div',
86 $wrapperAttribs,
87 "$select<br />\n$textbox"
88 );
89 }
90
91 protected function getOOUIModules() {
92 return [ 'mediawiki.widgets.SelectWithInputWidget' ];
93 }
94
95 public function getInputOOUI( $value ) {
96 $this->mParent->getOutput()->addModuleStyles( 'mediawiki.widgets.SelectWithInputWidget.styles' );
97
98 # TextInput
99 $textAttribs = [
100 'name' => $this->mName . '-other',
101 'value' => $value[2],
102 ];
103
104 $allowedParams = [
105 'required',
106 'autofocus',
107 'multiple',
108 'disabled',
109 'tabindex',
110 'maxlength',
111 ];
112
113 $textAttribs += \OOUI\Element::configFromHtmlAttributes(
114 $this->getAttributes( $allowedParams )
115 );
116
117 # DropdownInput
118 $dropdownInputAttribs = [
119 'name' => $this->mName,
120 'options' => $this->getOptionsOOUI(),
121 'value' => $value[1],
122 ];
123
124 $allowedParams = [
125 'tabindex',
126 'disabled',
127 ];
128
129 $dropdownInputAttribs += \OOUI\Element::configFromHtmlAttributes(
130 $this->getAttributes( $allowedParams )
131 );
132
133 $disabled = false;
134 if ( isset( $this->mParams[ 'disabled' ] ) && $this->mParams[ 'disabled' ] ) {
135 $disabled = true;
136 }
137
138 $inputClasses = [ self::FIELD_CLASS ];
139 if ( $this->mClass !== '' ) {
140 $inputClasses = array_merge( $inputClasses, explode( ' ', $this->mClass ) );
141 }
142 return $this->getInputWidget( [
143 'id' => $this->mID,
144 'disabled' => $disabled,
145 'textinput' => $textAttribs,
146 'dropdowninput' => $dropdownInputAttribs,
147 'or' => false,
148 'required' => $this->mParams[ 'required' ] ?? false,
149 'classes' => $inputClasses,
150 'data' => [
151 'maxlengthUnit' => $this->mParams['maxlength-unit'] ?? 'bytes'
152 ],
153 ] );
154 }
155
161 public function getInputWidget( $params ) {
162 return new SelectWithInputWidget( $params );
163 }
164
165 public function getInputCodex( $value, $hasErrors ) {
166 $select = parent::getInputCodex( $value[1], $hasErrors );
167
168 // Set up attributes for the text input.
169 $textInputAttribs = [
170 'size' => $this->getSize(),
171 'name' => $this->mName . '-other'
172 ];
173
174 if ( isset( $this->mParams['maxlength-unit'] ) ) {
175 $textInputAttribs['data-mw-maxlength-unit'] = $this->mParams['maxlength-unit'];
176 }
177
178 $allowedParams = [
179 'required',
180 'autofocus',
181 'multiple',
182 'disabled',
183 'tabindex',
184 'maxlength', // gets dynamic with javascript, see mediawiki.htmlform.js
185 'maxlength-unit', // 'bytes' or 'codepoints', see mediawiki.htmlform.js
186 ];
187
188 $textInputAttribs += $this->getAttributes( $allowedParams );
189
190 // Get text input HTML.
192 $value[2],
193 $hasErrors,
194 'text',
195 $this->mName . '-other',
196 $textInputAttribs
197 );
198
199 // Set up the wrapper element and return the entire component.
200 $wrapperAttribs = [
201 'id' => $this->mID,
202 'class' => [ self::FIELD_CLASS ]
203 ];
204 if ( $this->mClass !== '' ) {
205 $wrapperAttribs['class'][] = $this->mClass;
206 }
207 return Html::rawElement(
208 'div',
209 $wrapperAttribs,
210 "$select<br />\n$textInput"
211 );
212 }
213
217 public function getDefault() {
218 $default = parent::getDefault();
219
220 // Default values of empty form
221 $final = '';
222 $list = 'other';
223 $text = '';
224
225 if ( $default !== null ) {
226 $final = $default;
227 // Assume the default is a text value, with the 'other' option selected.
228 // Then check if that assumption is correct, and update $list and $text if not.
229 $text = $final;
230 foreach ( $this->mFlatOptions as $option ) {
231 $match = $option . $this->msg( 'colon-separator' )->inContentLanguage()->text();
232 if ( str_starts_with( $final, $match ) ) {
233 $list = $option;
234 $text = substr( $final, strlen( $match ) );
235 break;
236 }
237 }
238 }
239
240 return [ $final, $list, $text ];
241 }
242
248 public function loadDataFromRequest( $request ) {
249 if ( $request->getCheck( $this->mName ) ) {
250 $list = $request->getText( $this->mName );
251 $text = $request->getText( $this->mName . '-other' );
252
253 // Should be built the same as in mediawiki.htmlform.js
254 if ( $list == 'other' ) {
255 $final = $text;
256 } elseif ( !in_array( $list, $this->mFlatOptions, true ) ) {
257 # User has spoofed the select form to give an option which wasn't
258 # in the original offer. Sulk...
259 $final = $text;
260 } elseif ( $text == '' ) {
261 $final = $list;
262 } else {
263 $final = $list . $this->msg( 'colon-separator' )->inContentLanguage()->text() . $text;
264 }
265 return [ $final, $list, $text ];
266 }
267 return $this->getDefault();
268 }
269
270 public function getSize() {
271 return $this->mParams['size'] ?? 45;
272 }
273
274 public function validate( $value, $alldata ) {
275 # HTMLSelectField forces $value to be one of the options in the select
276 # field, which is not useful here. But we do want the validation further up
277 # the chain
278 $p = parent::validate( $value[1], $alldata );
279
280 if ( $p !== true ) {
281 return $p;
282 }
283
284 if ( isset( $this->mParams['required'] )
285 && $this->mParams['required'] !== false
286 && $value[0] === ''
287 ) {
288 return $this->msg( 'htmlform-required' );
289 }
290
291 return true;
292 }
293}
294
296class_alias( HTMLSelectAndOtherField::class, 'HTMLSelectAndOtherField' );
array $params
The job parameters.
Double field with a dropdown list constructed from a system message in the format.
getInputCodex( $value, $hasErrors)
Same as getInputHTML, but for Codex.
getInputHTML( $value)
This function must be implemented to return the HTML to generate the input object itself....
validate( $value, $alldata)
Override this function to add specific validation checks on the field input.Don't forget to call pare...
getOOUIModules()
Get the list of extra ResourceLoader modules which must be loaded client-side before it's possible to...
getInputOOUI( $value)
Same as getInputHTML, but returns an OOUI object.Defaults to false, which getOOUI will interpret as "...
static buildCodexComponent( $value, $hasErrors, $type, $name, $inputAttribs)
Build the markup of the Codex component.
getMessage( $value)
Turns a *-message parameter (which could be a MessageSpecifier, or a message name,...
getOptionsOOUI()
Get options and make them into arrays suitable for OOUI.
static flattenOptions( $options)
flatten an array of options to a single array, for instance, a set of "<options>" inside "<optgroups>...
getOptions()
Fetch the array of options from the field's parameters.
getAttributes(array $list)
Returns the given attributes from the parameters.
msg( $key,... $params)
Get a translated interface message.
This class is a collection of static functions that serve two purposes:
Definition Html.php:56
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form,...