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