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
53 public function getInputHTML( $value ) {
54 $select = parent::getInputHTML( $value[1] );
55
56 $textAttribs = [
57 'size' => $this->getSize(),
58 ];
59
60 if ( isset( $this->mParams['maxlength-unit'] ) ) {
61 $textAttribs['data-mw-maxlength-unit'] = $this->mParams['maxlength-unit'];
62 }
63
64 $allowedParams = [
65 'required',
66 'autofocus',
67 'multiple',
68 'disabled',
69 'tabindex',
70 'maxlength', // gets dynamic with javascript, see mediawiki.htmlform.js
71 'maxlength-unit', // 'bytes' or 'codepoints', see mediawiki.htmlform.js
72 ];
73
74 $textAttribs += $this->getAttributes( $allowedParams );
75
76 $textbox = Html::input( $this->mName . '-other', $value[2], 'text', $textAttribs );
77
78 $wrapperAttribs = [
79 'id' => $this->mID,
80 'class' => self::FIELD_CLASS
81 ];
82 if ( $this->mClass !== '' ) {
83 $wrapperAttribs['class'] .= ' ' . $this->mClass;
84 }
85 return Html::rawElement(
86 'div',
87 $wrapperAttribs,
88 "$select<br />\n$textbox"
89 );
90 }
91
93 protected function getOOUIModules() {
94 return [ 'mediawiki.widgets.SelectWithInputWidget', 'mediawiki.widgets.visibleLengthLimit' ];
95 }
96
98 public function getInputOOUI( $value ) {
99 $this->mParent->getOutput()->addModuleStyles( 'mediawiki.widgets.SelectWithInputWidget.styles' );
100
101 # TextInput
102 $textAttribs = [
103 'name' => $this->mName . '-other',
104 'value' => $value[2],
105 ];
106
107 $allowedParams = [
108 'required',
109 'autofocus',
110 'multiple',
111 'disabled',
112 'tabindex',
113 'maxlength',
114 ];
115
116 $textAttribs += \OOUI\Element::configFromHtmlAttributes(
117 $this->getAttributes( $allowedParams )
118 );
119
120 # DropdownInput
121 $dropdownInputAttribs = [
122 'name' => $this->mName,
123 'options' => $this->getOptionsOOUI(),
124 'value' => $value[1],
125 ];
126
127 $allowedParams = [
128 'tabindex',
129 'disabled',
130 ];
131
132 $dropdownInputAttribs += \OOUI\Element::configFromHtmlAttributes(
133 $this->getAttributes( $allowedParams )
134 );
135
136 $disabled = false;
137 if ( isset( $this->mParams[ 'disabled' ] ) && $this->mParams[ 'disabled' ] ) {
138 $disabled = true;
139 }
140
141 $inputClasses = [ self::FIELD_CLASS ];
142 if ( $this->mClass !== '' ) {
143 $inputClasses = array_merge( $inputClasses, explode( ' ', $this->mClass ) );
144 }
145 return $this->getInputWidget( [
146 'id' => $this->mID,
147 'disabled' => $disabled,
148 'textinput' => $textAttribs,
149 'dropdowninput' => $dropdownInputAttribs,
150 'or' => false,
151 'required' => $this->mParams[ 'required' ] ?? false,
152 'classes' => $inputClasses,
153 'data' => [
154 'maxlengthUnit' => $this->mParams['maxlength-unit'] ?? 'bytes'
155 ],
156 ] );
157 }
158
164 public function getInputWidget( $params ) {
165 return new SelectWithInputWidget( $params );
166 }
167
169 public function getInputCodex( $value, $hasErrors ) {
170 $select = parent::getInputCodex( $value[1], $hasErrors );
171
172 // Set up attributes for the text input.
173 $textInputAttribs = [
174 'size' => $this->getSize(),
175 'name' => $this->mName . '-other'
176 ];
177
178 if ( isset( $this->mParams['maxlength-unit'] ) ) {
179 $textInputAttribs['data-mw-maxlength-unit'] = $this->mParams['maxlength-unit'];
180 }
181
182 $allowedParams = [
183 'required',
184 'autofocus',
185 'multiple',
186 'disabled',
187 'tabindex',
188 'maxlength', // gets dynamic with javascript, see mediawiki.htmlform.js
189 'maxlength-unit', // 'bytes' or 'codepoints', see mediawiki.htmlform.js
190 ];
191
192 $textInputAttribs += $this->getAttributes( $allowedParams );
193
194 // Get text input HTML.
196 $value[2],
197 $hasErrors,
198 'text',
199 $this->mName . '-other',
200 $textInputAttribs
201 );
202
203 // Set up the wrapper element and return the entire component.
204 $wrapperAttribs = [
205 'id' => $this->mID,
206 'class' => [ self::FIELD_CLASS ]
207 ];
208 if ( $this->mClass !== '' ) {
209 $wrapperAttribs['class'][] = $this->mClass;
210 }
211 return Html::rawElement(
212 'div',
213 $wrapperAttribs,
214 "$select<br />\n$textInput"
215 );
216 }
217
221 public function getDefault() {
222 $default = parent::getDefault();
223
224 // Default values of empty form
225 $final = '';
226 $list = 'other';
227 $text = '';
228
229 if ( $default !== null ) {
230 $final = $default;
231 // Assume the default is a text value, with the 'other' option selected.
232 // Then check if that assumption is correct, and update $list and $text if not.
233 $text = $final;
234 foreach ( $this->mFlatOptions as $option ) {
235 $match = $option . $this->msg( 'colon-separator' )->inContentLanguage()->text();
236 if ( str_starts_with( $final, $match ) ) {
237 $list = $option;
238 $text = substr( $final, strlen( $match ) );
239 break;
240 }
241 }
242 }
243
244 return [ $final, $list, $text ];
245 }
246
252 public function loadDataFromRequest( $request ) {
253 if ( $request->getCheck( $this->mName ) ) {
254 $list = $request->getText( $this->mName );
255 $text = $request->getText( $this->mName . '-other' );
256
257 // Should be built the same as in mediawiki.htmlform.js
258 if ( $list == 'other' ) {
259 $final = $text;
260 } elseif ( !in_array( $list, $this->mFlatOptions, true ) ) {
261 # User has spoofed the select form to give an option which wasn't
262 # in the original offer. Sulk...
263 $final = $text;
264 } elseif ( $text == '' ) {
265 $final = $list;
266 } else {
267 $final = $list . $this->msg( 'colon-separator' )->inContentLanguage()->text() . $text;
268 }
269 return [ $final, $list, $text ];
270 }
271 return $this->getDefault();
272 }
273
275 public function getSize() {
276 return $this->mParams['size'] ?? 45;
277 }
278
280 public function validate( $value, $alldata ) {
281 # HTMLSelectField forces $value to be one of the options in the select
282 # field, which is not useful here. But we do want the validation further up
283 # the chain
284 $p = parent::validate( $value[1], $alldata );
285
286 if ( $p !== true ) {
287 return $p;
288 }
289
290 if ( isset( $this->mParams['required'] )
291 && $this->mParams['required'] !== false
292 && $value[0] === ''
293 ) {
294 return $this->msg( 'htmlform-required' );
295 }
296
297 return true;
298 }
299}
300
302class_alias( HTMLSelectAndOtherField::class, 'HTMLSelectAndOtherField' );
Double field with a dropdown list constructed from a system message in the format.
getInputCodex( $value, $hasErrors)
Same as getInputHTML, but for Codex.This is called by CodexHTMLForm.If not overridden,...
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:43
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form,...