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