MediaWiki  1.33.0
HTMLFormField.php
Go to the documentation of this file.
1 <?php
2 
7 abstract class HTMLFormField {
8  public $mParams;
9 
11  protected $mFilterCallback;
12  protected $mName;
13  protected $mDir;
14  protected $mLabel; # String label, as HTML. Set on construction.
15  protected $mID;
16  protected $mClass = '';
17  protected $mVFormClass = '';
18  protected $mHelpClass = false;
19  protected $mDefault;
23  protected $mOptions = false;
24  protected $mOptionsLabelsNotFromMessage = false;
25  protected $mHideIf = null;
26 
31  protected $mShowEmptyLabels = true;
32 
36  public $mParent;
37 
48  abstract public function getInputHTML( $value );
49 
57  public function getInputOOUI( $value ) {
58  return false;
59  }
60 
66  public function canDisplayErrors() {
67  return $this->hasVisibleOutput();
68  }
69 
80  public function msg() {
81  $args = func_get_args();
82 
83  if ( $this->mParent ) {
84  return $this->mParent->msg( ...$args );
85  }
86  return wfMessage( ...$args );
87  }
88 
95  public function hasVisibleOutput() {
96  return true;
97  }
98 
112  protected function getNearestFieldByName( $alldata, $name ) {
113  $tmp = $this->mName;
114  $thisKeys = [];
115  while ( preg_match( '/^(.+)\[([^\]]+)\]$/', $tmp, $m ) ) {
116  array_unshift( $thisKeys, $m[2] );
117  $tmp = $m[1];
118  }
119  if ( substr( $tmp, 0, 2 ) == 'wp' &&
120  !array_key_exists( $tmp, $alldata ) &&
121  array_key_exists( substr( $tmp, 2 ), $alldata )
122  ) {
123  // Adjust for name mangling.
124  $tmp = substr( $tmp, 2 );
125  }
126  array_unshift( $thisKeys, $tmp );
127 
128  $tmp = $name;
129  $nameKeys = [];
130  while ( preg_match( '/^(.+)\[([^\]]+)\]$/', $tmp, $m ) ) {
131  array_unshift( $nameKeys, $m[2] );
132  $tmp = $m[1];
133  }
134  array_unshift( $nameKeys, $tmp );
135 
136  $testValue = '';
137  for ( $i = count( $thisKeys ) - 1; $i >= 0; $i-- ) {
138  $keys = array_merge( array_slice( $thisKeys, 0, $i ), $nameKeys );
139  $data = $alldata;
140  foreach ( $keys as $key ) {
141  if ( !is_array( $data ) || !array_key_exists( $key, $data ) ) {
142  continue 2;
143  }
144  $data = $data[$key];
145  }
146  $testValue = (string)$data;
147  break;
148  }
149 
150  return $testValue;
151  }
152 
161  protected function isHiddenRecurse( array $alldata, array $params ) {
162  $origParams = $params;
163  $op = array_shift( $params );
164 
165  try {
166  switch ( $op ) {
167  case 'AND':
168  foreach ( $params as $i => $p ) {
169  if ( !is_array( $p ) ) {
170  throw new MWException(
171  "Expected array, found " . gettype( $p ) . " at index $i"
172  );
173  }
174  if ( !$this->isHiddenRecurse( $alldata, $p ) ) {
175  return false;
176  }
177  }
178  return true;
179 
180  case 'OR':
181  foreach ( $params as $i => $p ) {
182  if ( !is_array( $p ) ) {
183  throw new MWException(
184  "Expected array, found " . gettype( $p ) . " at index $i"
185  );
186  }
187  if ( $this->isHiddenRecurse( $alldata, $p ) ) {
188  return true;
189  }
190  }
191  return false;
192 
193  case 'NAND':
194  foreach ( $params as $i => $p ) {
195  if ( !is_array( $p ) ) {
196  throw new MWException(
197  "Expected array, found " . gettype( $p ) . " at index $i"
198  );
199  }
200  if ( !$this->isHiddenRecurse( $alldata, $p ) ) {
201  return true;
202  }
203  }
204  return false;
205 
206  case 'NOR':
207  foreach ( $params as $i => $p ) {
208  if ( !is_array( $p ) ) {
209  throw new MWException(
210  "Expected array, found " . gettype( $p ) . " at index $i"
211  );
212  }
213  if ( $this->isHiddenRecurse( $alldata, $p ) ) {
214  return false;
215  }
216  }
217  return true;
218 
219  case 'NOT':
220  if ( count( $params ) !== 1 ) {
221  throw new MWException( "NOT takes exactly one parameter" );
222  }
223  $p = $params[0];
224  if ( !is_array( $p ) ) {
225  throw new MWException(
226  "Expected array, found " . gettype( $p ) . " at index 0"
227  );
228  }
229  return !$this->isHiddenRecurse( $alldata, $p );
230 
231  case '===':
232  case '!==':
233  if ( count( $params ) !== 2 ) {
234  throw new MWException( "$op takes exactly two parameters" );
235  }
236  list( $field, $value ) = $params;
237  if ( !is_string( $field ) || !is_string( $value ) ) {
238  throw new MWException( "Parameters for $op must be strings" );
239  }
240  $testValue = $this->getNearestFieldByName( $alldata, $field );
241  switch ( $op ) {
242  case '===':
243  return ( $value === $testValue );
244  case '!==':
245  return ( $value !== $testValue );
246  }
247 
248  default:
249  throw new MWException( "Unknown operation" );
250  }
251  } catch ( Exception $ex ) {
252  throw new MWException(
253  "Invalid hide-if specification for $this->mName: " .
254  $ex->getMessage() . " in " . var_export( $origParams, true ),
255  0, $ex
256  );
257  }
258  }
259 
268  public function isHidden( $alldata ) {
269  if ( !$this->mHideIf ) {
270  return false;
271  }
272 
273  return $this->isHiddenRecurse( $alldata, $this->mHideIf );
274  }
275 
286  public function cancelSubmit( $value, $alldata ) {
287  return false;
288  }
289 
301  public function validate( $value, $alldata ) {
302  if ( $this->isHidden( $alldata ) ) {
303  return true;
304  }
305 
306  if ( isset( $this->mParams['required'] )
307  && $this->mParams['required'] !== false
308  && $value === ''
309  ) {
310  return $this->msg( 'htmlform-required' );
311  }
312 
313  if ( isset( $this->mValidationCallback ) ) {
314  return ( $this->mValidationCallback )( $value, $alldata, $this->mParent );
315  }
316 
317  return true;
318  }
319 
320  public function filter( $value, $alldata ) {
321  if ( isset( $this->mFilterCallback ) ) {
322  $value = ( $this->mFilterCallback )( $value, $alldata, $this->mParent );
323  }
324 
325  return $value;
326  }
327 
334  protected function needsLabel() {
335  return true;
336  }
337 
347  public function setShowEmptyLabel( $show ) {
348  $this->mShowEmptyLabels = $show;
349  }
350 
361  protected function isSubmitAttempt( WebRequest $request ) {
362  return $request->getCheck( 'wpEditToken' ) || $request->getCheck( 'wpFormIdentifier' );
363  }
364 
372  public function loadDataFromRequest( $request ) {
373  if ( $request->getCheck( $this->mName ) ) {
374  return $request->getText( $this->mName );
375  } else {
376  return $this->getDefault();
377  }
378  }
379 
388  public function __construct( $params ) {
389  $this->mParams = $params;
390 
391  if ( isset( $params['parent'] ) && $params['parent'] instanceof HTMLForm ) {
392  $this->mParent = $params['parent'];
393  }
394 
395  # Generate the label from a message, if possible
396  if ( isset( $params['label-message'] ) ) {
397  $this->mLabel = $this->getMessage( $params['label-message'] )->parse();
398  } elseif ( isset( $params['label'] ) ) {
399  if ( $params['label'] === '&#160;' || $params['label'] === "\u{00A0}" ) {
400  // Apparently some things set &nbsp directly and in an odd format
401  $this->mLabel = "\u{00A0}";
402  } else {
403  $this->mLabel = htmlspecialchars( $params['label'] );
404  }
405  } elseif ( isset( $params['label-raw'] ) ) {
406  $this->mLabel = $params['label-raw'];
407  }
408 
409  $this->mName = "wp{$params['fieldname']}";
410  if ( isset( $params['name'] ) ) {
411  $this->mName = $params['name'];
412  }
413 
414  if ( isset( $params['dir'] ) ) {
415  $this->mDir = $params['dir'];
416  }
417 
418  $validName = urlencode( $this->mName );
419  $validName = str_replace( [ '%5B', '%5D' ], [ '[', ']' ], $validName );
420  if ( $this->mName != $validName && !isset( $params['nodata'] ) ) {
421  throw new MWException( "Invalid name '{$this->mName}' passed to " . __METHOD__ );
422  }
423 
424  $this->mID = "mw-input-{$this->mName}";
425 
426  if ( isset( $params['default'] ) ) {
427  $this->mDefault = $params['default'];
428  }
429 
430  if ( isset( $params['id'] ) ) {
431  $id = $params['id'];
432  $validId = urlencode( $id );
433 
434  if ( $id != $validId ) {
435  throw new MWException( "Invalid id '$id' passed to " . __METHOD__ );
436  }
437 
438  $this->mID = $id;
439  }
440 
441  if ( isset( $params['cssclass'] ) ) {
442  $this->mClass = $params['cssclass'];
443  }
444 
445  if ( isset( $params['csshelpclass'] ) ) {
446  $this->mHelpClass = $params['csshelpclass'];
447  }
448 
449  if ( isset( $params['validation-callback'] ) ) {
450  $this->mValidationCallback = $params['validation-callback'];
451  }
452 
453  if ( isset( $params['filter-callback'] ) ) {
454  $this->mFilterCallback = $params['filter-callback'];
455  }
456 
457  if ( isset( $params['hidelabel'] ) ) {
458  $this->mShowEmptyLabels = false;
459  }
460 
461  if ( isset( $params['hide-if'] ) ) {
462  $this->mHideIf = $params['hide-if'];
463  }
464  }
465 
474  public function getTableRow( $value ) {
475  list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
476  $inputHtml = $this->getInputHTML( $value );
477  $fieldType = static::class;
478  $helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
479  $cellAttributes = [];
480  $rowAttributes = [];
481  $rowClasses = '';
482 
483  if ( !empty( $this->mParams['vertical-label'] ) ) {
484  $cellAttributes['colspan'] = 2;
485  $verticalLabel = true;
486  } else {
487  $verticalLabel = false;
488  }
489 
490  $label = $this->getLabelHtml( $cellAttributes );
491 
492  $field = Html::rawElement(
493  'td',
494  [ 'class' => 'mw-input' ] + $cellAttributes,
495  $inputHtml . "\n$errors"
496  );
497 
498  if ( $this->mHideIf ) {
499  $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
500  $rowClasses .= ' mw-htmlform-hide-if';
501  }
502 
503  if ( $verticalLabel ) {
504  $html = Html::rawElement( 'tr',
505  $rowAttributes + [ 'class' => "mw-htmlform-vertical-label $rowClasses" ], $label );
506  $html .= Html::rawElement( 'tr',
507  $rowAttributes + [
508  'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
509  ],
510  $field );
511  } else {
512  $html =
513  Html::rawElement( 'tr',
514  $rowAttributes + [
515  'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
516  ],
517  $label . $field );
518  }
519 
520  return $html . $helptext;
521  }
522 
532  public function getDiv( $value ) {
533  list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
534  $inputHtml = $this->getInputHTML( $value );
535  $fieldType = static::class;
536  $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
537  $cellAttributes = [];
538  $label = $this->getLabelHtml( $cellAttributes );
539 
540  $outerDivClass = [
541  'mw-input',
542  'mw-htmlform-nolabel' => ( $label === '' )
543  ];
544 
545  $horizontalLabel = $this->mParams['horizontal-label'] ?? false;
546 
547  if ( $horizontalLabel ) {
548  $field = "\u{00A0}" . $inputHtml . "\n$errors";
549  } else {
550  $field = Html::rawElement(
551  'div',
552  [ 'class' => $outerDivClass ] + $cellAttributes,
553  $inputHtml . "\n$errors"
554  );
555  }
556  $divCssClasses = [ "mw-htmlform-field-$fieldType",
557  $this->mClass, $this->mVFormClass, $errorClass ];
558 
559  $wrapperAttributes = [
560  'class' => $divCssClasses,
561  ];
562  if ( $this->mHideIf ) {
563  $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
564  $wrapperAttributes['class'][] = ' mw-htmlform-hide-if';
565  }
566  $html = Html::rawElement( 'div', $wrapperAttributes, $label . $field );
567  $html .= $helptext;
568 
569  return $html;
570  }
571 
580  public function getOOUI( $value ) {
581  $inputField = $this->getInputOOUI( $value );
582 
583  if ( !$inputField ) {
584  // This field doesn't have an OOUI implementation yet at all. Fall back to getDiv() to
585  // generate the whole field, label and errors and all, then wrap it in a Widget.
586  // It might look weird, but it'll work OK.
587  return $this->getFieldLayoutOOUI(
588  new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $this->getDiv( $value ) ) ] ),
589  [ 'align' => 'top' ]
590  );
591  }
592 
593  $infusable = true;
594  if ( is_string( $inputField ) ) {
595  // We have an OOUI implementation, but it's not proper, and we got a load of HTML.
596  // Cheat a little and wrap it in a widget. It won't be infusable, though, since client-side
597  // JavaScript doesn't know how to rebuilt the contents.
598  $inputField = new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $inputField ) ] );
599  $infusable = false;
600  }
601 
602  $fieldType = static::class;
603  $help = $this->getHelpText();
604  $errors = $this->getErrorsRaw( $value );
605  foreach ( $errors as &$error ) {
606  $error = new OOUI\HtmlSnippet( $error );
607  }
608 
609  $config = [
610  'classes' => [ "mw-htmlform-field-$fieldType", $this->mClass ],
611  'align' => $this->getLabelAlignOOUI(),
612  'help' => ( $help !== null && $help !== '' ) ? new OOUI\HtmlSnippet( $help ) : null,
613  'errors' => $errors,
614  'infusable' => $infusable,
615  'helpInline' => $this->isHelpInline(),
616  ];
617 
618  $preloadModules = false;
619 
620  if ( $infusable && $this->shouldInfuseOOUI() ) {
621  $preloadModules = true;
622  $config['classes'][] = 'mw-htmlform-field-autoinfuse';
623  }
624 
625  // the element could specify, that the label doesn't need to be added
626  $label = $this->getLabel();
627  if ( $label && $label !== "\u{00A0}" && $label !== '&#160;' ) {
628  $config['label'] = new OOUI\HtmlSnippet( $label );
629  }
630 
631  if ( $this->mHideIf ) {
632  $preloadModules = true;
633  $config['hideIf'] = $this->mHideIf;
634  }
635 
636  $config['modules'] = $this->getOOUIModules();
637 
638  if ( $preloadModules ) {
639  $this->mParent->getOutput()->addModules( 'mediawiki.htmlform.ooui' );
640  $this->mParent->getOutput()->addModules( $this->getOOUIModules() );
641  }
642 
643  return $this->getFieldLayoutOOUI( $inputField, $config );
644  }
645 
650  protected function getLabelAlignOOUI() {
651  return 'top';
652  }
653 
660  protected function getFieldLayoutOOUI( $inputField, $config ) {
661  if ( isset( $this->mClassWithButton ) ) {
662  $buttonWidget = $this->mClassWithButton->getInputOOUI( '' );
663  return new HTMLFormActionFieldLayout( $inputField, $buttonWidget, $config );
664  }
665  return new HTMLFormFieldLayout( $inputField, $config );
666  }
667 
675  protected function shouldInfuseOOUI() {
676  // Always infuse fields with popup help text, since the interface for it is nicer with JS
677  return $this->getHelpText() !== null && !$this->isHelpInline();
678  }
679 
686  protected function getOOUIModules() {
687  return [];
688  }
689 
699  public function getRaw( $value ) {
700  list( $errors, ) = $this->getErrorsAndErrorClass( $value );
701  $inputHtml = $this->getInputHTML( $value );
702  $helptext = $this->getHelpTextHtmlRaw( $this->getHelpText() );
703  $cellAttributes = [];
704  $label = $this->getLabelHtml( $cellAttributes );
705 
706  $html = "\n$errors";
707  $html .= $label;
708  $html .= $inputHtml;
709  $html .= $helptext;
710 
711  return $html;
712  }
713 
722  public function getVForm( $value ) {
723  // Ewwww
724  $this->mVFormClass = ' mw-ui-vform-field';
725  return $this->getDiv( $value );
726  }
727 
734  public function getInline( $value ) {
735  list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
736  $inputHtml = $this->getInputHTML( $value );
737  $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
738  $cellAttributes = [];
739  $label = $this->getLabelHtml( $cellAttributes );
740 
741  $html = "\n" . $errors .
742  $label . "\u{00A0}" .
743  $inputHtml .
744  $helptext;
745 
746  return $html;
747  }
748 
756  public function getHelpTextHtmlTable( $helptext ) {
757  if ( is_null( $helptext ) ) {
758  return '';
759  }
760 
761  $rowAttributes = [];
762  if ( $this->mHideIf ) {
763  $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
764  $rowAttributes['class'] = 'mw-htmlform-hide-if';
765  }
766 
767  $tdClasses = [ 'htmlform-tip' ];
768  if ( $this->mHelpClass !== false ) {
769  $tdClasses[] = $this->mHelpClass;
770  }
771  $row = Html::rawElement( 'td', [ 'colspan' => 2, 'class' => $tdClasses ], $helptext );
772  $row = Html::rawElement( 'tr', $rowAttributes, $row );
773 
774  return $row;
775  }
776 
785  public function getHelpTextHtmlDiv( $helptext ) {
786  if ( is_null( $helptext ) ) {
787  return '';
788  }
789 
790  $wrapperAttributes = [
791  'class' => 'htmlform-tip',
792  ];
793  if ( $this->mHelpClass !== false ) {
794  $wrapperAttributes['class'] .= " {$this->mHelpClass}";
795  }
796  if ( $this->mHideIf ) {
797  $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
798  $wrapperAttributes['class'] .= ' mw-htmlform-hide-if';
799  }
800  $div = Html::rawElement( 'div', $wrapperAttributes, $helptext );
801 
802  return $div;
803  }
804 
812  public function getHelpTextHtmlRaw( $helptext ) {
813  return $this->getHelpTextHtmlDiv( $helptext );
814  }
815 
821  public function getHelpText() {
822  $helptext = null;
823 
824  if ( isset( $this->mParams['help-message'] ) ) {
825  $this->mParams['help-messages'] = [ $this->mParams['help-message'] ];
826  }
827 
828  if ( isset( $this->mParams['help-messages'] ) ) {
829  foreach ( $this->mParams['help-messages'] as $msg ) {
830  $msg = $this->getMessage( $msg );
831 
832  if ( $msg->exists() ) {
833  if ( is_null( $helptext ) ) {
834  $helptext = '';
835  } else {
836  $helptext .= $this->msg( 'word-separator' )->escaped(); // some space
837  }
838  $helptext .= $msg->parse(); // Append message
839  }
840  }
841  } elseif ( isset( $this->mParams['help'] ) ) {
842  $helptext = $this->mParams['help'];
843  }
844 
845  return $helptext;
846  }
847 
856  public function isHelpInline() {
857  return $this->mParams['help-inline'] ?? true;
858  }
859 
872  public function getErrorsAndErrorClass( $value ) {
873  $errors = $this->validate( $value, $this->mParent->mFieldData );
874 
875  if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
876  $errors = '';
877  $errorClass = '';
878  } else {
879  $errors = self::formatErrors( $errors );
880  $errorClass = 'mw-htmlform-invalid-input';
881  }
882 
883  return [ $errors, $errorClass ];
884  }
885 
893  public function getErrorsRaw( $value ) {
894  $errors = $this->validate( $value, $this->mParent->mFieldData );
895 
896  if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
897  $errors = [];
898  }
899 
900  if ( !is_array( $errors ) ) {
901  $errors = [ $errors ];
902  }
903  foreach ( $errors as &$error ) {
904  if ( $error instanceof Message ) {
905  $error = $error->parse();
906  }
907  }
908 
909  return $errors;
910  }
911 
915  public function getLabel() {
916  return $this->mLabel ?? '';
917  }
918 
919  public function getLabelHtml( $cellAttributes = [] ) {
920  # Don't output a for= attribute for labels with no associated input.
921  # Kind of hacky here, possibly we don't want these to be <label>s at all.
922  $for = [];
923 
924  if ( $this->needsLabel() ) {
925  $for['for'] = $this->mID;
926  }
927 
928  $labelValue = trim( $this->getLabel() );
929  $hasLabel = false;
930  if ( $labelValue !== "\u{00A0}" && $labelValue !== '&#160;' && $labelValue !== '' ) {
931  $hasLabel = true;
932  }
933 
934  $displayFormat = $this->mParent->getDisplayFormat();
935  $html = '';
936  $horizontalLabel = $this->mParams['horizontal-label'] ?? false;
937 
938  if ( $displayFormat === 'table' ) {
939  $html =
940  Html::rawElement( 'td',
941  [ 'class' => 'mw-label' ] + $cellAttributes,
942  Html::rawElement( 'label', $for, $labelValue ) );
943  } elseif ( $hasLabel || $this->mShowEmptyLabels ) {
944  if ( $displayFormat === 'div' && !$horizontalLabel ) {
945  $html =
946  Html::rawElement( 'div',
947  [ 'class' => 'mw-label' ] + $cellAttributes,
948  Html::rawElement( 'label', $for, $labelValue ) );
949  } else {
950  $html = Html::rawElement( 'label', $for, $labelValue );
951  }
952  }
953 
954  return $html;
955  }
956 
957  public function getDefault() {
958  return $this->mDefault ?? null;
959  }
960 
966  public function getTooltipAndAccessKey() {
967  if ( empty( $this->mParams['tooltip'] ) ) {
968  return [];
969  }
970 
971  return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] );
972  }
973 
979  public function getTooltipAndAccessKeyOOUI() {
980  if ( empty( $this->mParams['tooltip'] ) ) {
981  return [];
982  }
983 
984  return [
985  'title' => Linker::titleAttrib( $this->mParams['tooltip'] ),
986  'accessKey' => Linker::accesskey( $this->mParams['tooltip'] ),
987  ];
988  }
989 
996  public function getAttributes( array $list ) {
997  static $boolAttribs = [ 'disabled', 'required', 'autofocus', 'multiple', 'readonly' ];
998 
999  $ret = [];
1000  foreach ( $list as $key ) {
1001  if ( in_array( $key, $boolAttribs ) ) {
1002  if ( !empty( $this->mParams[$key] ) ) {
1003  $ret[$key] = '';
1004  }
1005  } elseif ( isset( $this->mParams[$key] ) ) {
1006  $ret[$key] = $this->mParams[$key];
1007  }
1008  }
1009 
1010  return $ret;
1011  }
1012 
1020  private function lookupOptionsKeys( $options ) {
1021  $ret = [];
1022  foreach ( $options as $key => $value ) {
1023  $key = $this->msg( $key )->plain();
1024  $ret[$key] = is_array( $value )
1025  ? $this->lookupOptionsKeys( $value )
1026  : strval( $value );
1027  }
1028  return $ret;
1029  }
1030 
1038  public static function forceToStringRecursive( $array ) {
1039  if ( is_array( $array ) ) {
1040  return array_map( [ __CLASS__, 'forceToStringRecursive' ], $array );
1041  } else {
1042  return strval( $array );
1043  }
1044  }
1045 
1052  public function getOptions() {
1053  if ( $this->mOptions === false ) {
1054  if ( array_key_exists( 'options-messages', $this->mParams ) ) {
1055  $this->mOptions = $this->lookupOptionsKeys( $this->mParams['options-messages'] );
1056  } elseif ( array_key_exists( 'options', $this->mParams ) ) {
1057  $this->mOptionsLabelsNotFromMessage = true;
1058  $this->mOptions = self::forceToStringRecursive( $this->mParams['options'] );
1059  } elseif ( array_key_exists( 'options-message', $this->mParams ) ) {
1060  $message = $this->getMessage( $this->mParams['options-message'] )->inContentLanguage()->plain();
1061  $this->mOptions = Xml::listDropDownOptions( $message );
1062  } else {
1063  $this->mOptions = null;
1064  }
1065  }
1066 
1067  return $this->mOptions;
1068  }
1069 
1074  public function getOptionsOOUI() {
1075  $oldoptions = $this->getOptions();
1076 
1077  if ( $oldoptions === null ) {
1078  return null;
1079  }
1080 
1081  return Xml::listDropDownOptionsOoui( $oldoptions );
1082  }
1083 
1091  public static function flattenOptions( $options ) {
1092  $flatOpts = [];
1093 
1094  foreach ( $options as $value ) {
1095  if ( is_array( $value ) ) {
1096  $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) );
1097  } else {
1098  $flatOpts[] = $value;
1099  }
1100  }
1101 
1102  return $flatOpts;
1103  }
1104 
1118  protected static function formatErrors( $errors ) {
1119  // Note: If you change the logic in this method, change
1120  // htmlform.Checker.js to match.
1121 
1122  if ( is_array( $errors ) && count( $errors ) === 1 ) {
1123  $errors = array_shift( $errors );
1124  }
1125 
1126  if ( is_array( $errors ) ) {
1127  $lines = [];
1128  foreach ( $errors as $error ) {
1129  if ( $error instanceof Message ) {
1130  $lines[] = Html::rawElement( 'li', [], $error->parse() );
1131  } else {
1132  $lines[] = Html::rawElement( 'li', [], $error );
1133  }
1134  }
1135 
1136  return Html::rawElement( 'ul', [ 'class' => 'error' ], implode( "\n", $lines ) );
1137  } else {
1138  if ( $errors instanceof Message ) {
1139  $errors = $errors->parse();
1140  }
1141 
1142  return Html::rawElement( 'span', [ 'class' => 'error' ], $errors );
1143  }
1144  }
1145 
1152  protected function getMessage( $value ) {
1153  $message = Message::newFromSpecifier( $value );
1154 
1155  if ( $this->mParent ) {
1156  $message->setContext( $this->mParent );
1157  }
1158 
1159  return $message;
1160  }
1161 
1168  public function skipLoadData( $request ) {
1169  return !empty( $this->mParams['nodata'] );
1170  }
1171 
1179  public function needsJSForHtml5FormValidation() {
1180  if ( $this->mHideIf ) {
1181  // This is probably more restrictive than it needs to be, but better safe than sorry
1182  return true;
1183  }
1184  return false;
1185  }
1186 }
HTMLFormField\getOptions
getOptions()
Fetch the array of options from the field's parameters.
Definition: HTMLFormField.php:1052
HTMLFormField\__construct
__construct( $params)
Initialise the object.
Definition: HTMLFormField.php:388
HTMLFormField\$mHelpClass
$mHelpClass
Definition: HTMLFormField.php:18
HTMLFormField\getTooltipAndAccessKeyOOUI
getTooltipAndAccessKeyOOUI()
Returns the attributes required for the tooltip and accesskey, for OOUI widgets' config.
Definition: HTMLFormField.php:979
HTMLFormField\$mLabel
$mLabel
Definition: HTMLFormField.php:14
HTMLFormField\isHiddenRecurse
isHiddenRecurse(array $alldata, array $params)
Helper function for isHidden to handle recursive data structures.
Definition: HTMLFormField.php:161
Xml\listDropDownOptionsOoui
static listDropDownOptionsOoui( $options)
Convert options for a drop-down box into a format accepted by OOUI\DropdownInputWidget etc.
Definition: Xml.php:581
HTMLFormField\setShowEmptyLabel
setShowEmptyLabel( $show)
Tell the field whether to generate a separate label element if its label is blank.
Definition: HTMLFormField.php:347
captcha-old.count
count
Definition: captcha-old.py:249
HTMLFormField\getErrorsAndErrorClass
getErrorsAndErrorClass( $value)
Determine form errors to display and their classes.
Definition: HTMLFormField.php:872
HTMLFormField\validate
validate( $value, $alldata)
Override this function to add specific validation checks on the field input.
Definition: HTMLFormField.php:301
HTMLFormActionFieldLayout
Definition: HTMLFormElement.php:52
$params
$params
Definition: styleTest.css.php:44
HTMLFormField\formatErrors
static formatErrors( $errors)
Formats one or more errors as accepted by field validation-callback.
Definition: HTMLFormField.php:1118
HTMLFormField\hasVisibleOutput
hasVisibleOutput()
If this field has a user-visible output or not.
Definition: HTMLFormField.php:95
HTMLFormField\getMessage
getMessage( $value)
Turns a *-message parameter (which could be a MessageSpecifier, or a message name,...
Definition: HTMLFormField.php:1152
HTMLFormField\getNearestFieldByName
getNearestFieldByName( $alldata, $name)
Fetch a field value from $alldata for the closest field matching a given name.
Definition: HTMLFormField.php:112
HTMLFormField\$mClass
$mClass
Definition: HTMLFormField.php:16
HTMLFormField\shouldInfuseOOUI
shouldInfuseOOUI()
Whether the field should be automatically infused.
Definition: HTMLFormField.php:675
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
HTMLFormField\needsLabel
needsLabel()
Should this field have a label, or is there no input element with the appropriate id for the label to...
Definition: HTMLFormField.php:334
Linker\tooltipAndAccesskeyAttribs
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Definition: Linker.php:2130
HTMLFormField\$mDir
$mDir
Definition: HTMLFormField.php:13
HTMLFormField\skipLoadData
skipLoadData( $request)
Skip this field when collecting data.
Definition: HTMLFormField.php:1168
HTMLFormField\$mOptions
array bool null $mOptions
Definition: HTMLFormField.php:23
HTMLFormField\getTableRow
getTableRow( $value)
Get the complete table row for the input, including help text, labels, and whatever.
Definition: HTMLFormField.php:474
HTMLFormField\cancelSubmit
cancelSubmit( $value, $alldata)
Override this function if the control can somehow trigger a form submission that shouldn't actually s...
Definition: HTMLFormField.php:286
HTMLFormField\getLabelHtml
getLabelHtml( $cellAttributes=[])
Definition: HTMLFormField.php:919
HTMLFormField\canDisplayErrors
canDisplayErrors()
True if this field type is able to display errors; false if validation errors need to be displayed in...
Definition: HTMLFormField.php:66
HTMLFormField\getHelpTextHtmlTable
getHelpTextHtmlTable( $helptext)
Generate help text HTML in table format.
Definition: HTMLFormField.php:756
$data
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
Definition: generatePhpCharToUpperMappings.php:13
HTMLFormField\$mParent
HTMLForm null $mParent
Definition: HTMLFormField.php:36
FormatJson\encode
static encode( $value, $pretty=false, $escaping=0)
Returns the JSON representation of a value.
Definition: FormatJson.php:115
HTMLFormField\getHelpText
getHelpText()
Determine the help text to display.
Definition: HTMLFormField.php:821
$html
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition: hooks.txt:1985
MWException
MediaWiki exception.
Definition: MWException.php:26
HTMLFormField\$mName
$mName
Definition: HTMLFormField.php:12
HTMLFormField\isHelpInline
isHelpInline()
Determine if the help text should be displayed inline.
Definition: HTMLFormField.php:856
HTMLFormField\getLabelAlignOOUI
getLabelAlignOOUI()
Get label alignment when generating field for OOUI.
Definition: HTMLFormField.php:650
HTMLFormField
The parent class to generate form fields.
Definition: HTMLFormField.php:7
HTMLFormField\lookupOptionsKeys
lookupOptionsKeys( $options)
Given an array of msg-key => value mappings, returns an array with keys being the message texts.
Definition: HTMLFormField.php:1020
$lines
$lines
Definition: router.php:61
HTMLFormField\$mDefault
$mDefault
Definition: HTMLFormField.php:19
HTMLFormField\needsJSForHtml5FormValidation
needsJSForHtml5FormValidation()
Whether this field requires the user agent to have JavaScript enabled for the client-side HTML5 form ...
Definition: HTMLFormField.php:1179
array
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
string
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition: hooks.txt:175
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
HTMLFormField\filter
filter( $value, $alldata)
Definition: HTMLFormField.php:320
HTMLFormField\$mID
$mID
Definition: HTMLFormField.php:15
$request
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2636
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
HTMLFormField\getOOUI
getOOUI( $value)
Get the OOUI version of the div.
Definition: HTMLFormField.php:580
HTMLFormField\isHidden
isHidden( $alldata)
Test whether this field is supposed to be hidden, based on the values of the other form fields.
Definition: HTMLFormField.php:268
$value
$value
Definition: styleTest.css.php:49
HTMLFormField\$mValidationCallback
$mValidationCallback
Definition: HTMLFormField.php:10
HTMLFormField\getDefault
getDefault()
Definition: HTMLFormField.php:957
HTMLFormFieldLayout
Definition: HTMLFormElement.php:37
HTMLFormField\$mFilterCallback
$mFilterCallback
Definition: HTMLFormField.php:11
HTMLFormField\getFieldLayoutOOUI
getFieldLayoutOOUI( $inputField, $config)
Get a FieldLayout (or subclass thereof) to wrap this field in when using OOUI output.
Definition: HTMLFormField.php:660
HTMLFormField\msg
msg()
Get a translated interface message.
Definition: HTMLFormField.php:80
on
Using a hook running we can avoid having all this option specific stuff in our mainline code Using the function We ve cleaned up the code here by removing clumps of infrequently used code and moving them off somewhere else It s much easier for someone working with this code to see what s _really_ going on
Definition: hooks.txt:77
HTMLFormField\getLabel
getLabel()
Definition: HTMLFormField.php:915
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1985
HTMLFormField\$mParams
$mParams
Definition: HTMLFormField.php:8
HTMLFormField\getHelpTextHtmlRaw
getHelpTextHtmlRaw( $helptext)
Generate help text HTML formatted for raw output.
Definition: HTMLFormField.php:812
Linker\titleAttrib
static titleAttrib( $name, $options=null, array $msgParams=[])
Given the id of an interface element, constructs the appropriate title attribute from the system mess...
Definition: Linker.php:1965
WebRequest
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
Definition: WebRequest.php:41
HTMLFormField\getOOUIModules
getOOUIModules()
Get the list of extra ResourceLoader modules which must be loaded client-side before it's possible to...
Definition: HTMLFormField.php:686
HTMLFormField\getInputOOUI
getInputOOUI( $value)
Same as getInputHTML, but returns an OOUI object.
Definition: HTMLFormField.php:57
HTMLFormField\$mShowEmptyLabels
bool $mShowEmptyLabels
If true will generate an empty div element with no label.
Definition: HTMLFormField.php:31
$args
if( $line===false) $args
Definition: cdb.php:64
HTMLFormField\getDiv
getDiv( $value)
Get the complete div for the input, including help text, labels, and whatever.
Definition: HTMLFormField.php:532
HTMLFormField\getVForm
getVForm( $value)
Get the complete field for the input, including help text, labels, and whatever.
Definition: HTMLFormField.php:722
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1985
HTMLFormField\getInputHTML
getInputHTML( $value)
This function must be implemented to return the HTML to generate the input object itself.
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
HTMLFormField\$mOptionsLabelsNotFromMessage
$mOptionsLabelsNotFromMessage
Definition: HTMLFormField.php:24
HTMLFormField\getRaw
getRaw( $value)
Get the complete raw fields for the input, including help text, labels, and whatever.
Definition: HTMLFormField.php:699
$keys
$keys
Definition: testCompression.php:67
HTMLFormField\getErrorsRaw
getErrorsRaw( $value)
Determine form errors to display, returning them in an array.
Definition: HTMLFormField.php:893
HTMLFormField\forceToStringRecursive
static forceToStringRecursive( $array)
Recursively forces values in an array to strings, because issues arise with integer 0 as a value.
Definition: HTMLFormField.php:1038
HTMLFormField\isSubmitAttempt
isSubmitAttempt(WebRequest $request)
Can we assume that the request is an attempt to submit a HTMLForm, as opposed to an attempt to just v...
Definition: HTMLFormField.php:361
$help
$help
Definition: mcc.php:32
HTMLFormField\$mHideIf
$mHideIf
Definition: HTMLFormField.php:25
HTMLFormField\getTooltipAndAccessKey
getTooltipAndAccessKey()
Returns the attributes required for the tooltip and accesskey, for Html::element() etc.
Definition: HTMLFormField.php:966
HTMLFormField\flattenOptions
static flattenOptions( $options)
flatten an array of options to a single array, for instance, a set of "<options>" inside "<optgroups>...
Definition: HTMLFormField.php:1091
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
HTMLFormField\$mVFormClass
$mVFormClass
Definition: HTMLFormField.php:17
HTMLFormField\getHelpTextHtmlDiv
getHelpTextHtmlDiv( $helptext)
Generate help text HTML in div format.
Definition: HTMLFormField.php:785
wfMessage
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
Linker\accesskey
static accesskey( $name)
Given the id of an interface element, constructs the appropriate accesskey attribute from the system ...
Definition: Linker.php:2013
HTMLFormField\getInline
getInline( $value)
Get the complete field as an inline element.
Definition: HTMLFormField.php:734
HTMLFormField\getOptionsOOUI
getOptionsOOUI()
Get options and make them into arrays suitable for OOUI.
Definition: HTMLFormField.php:1074
Xml\listDropDownOptions
static listDropDownOptions( $list, $params=[])
Build options for a drop-down box from a textual list.
Definition: Xml.php:539
HTMLFormField\getAttributes
getAttributes(array $list)
Returns the given attributes from the parameters.
Definition: HTMLFormField.php:996
HTMLForm
Object handling generic submission, CSRF protection, layout and other logic for UI forms.
Definition: HTMLForm.php:133
HTMLFormField\loadDataFromRequest
loadDataFromRequest( $request)
Get the value that this input has been set to from a posted form, or the input's default value if it ...
Definition: HTMLFormField.php:372