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