MediaWiki  1.27.2
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;
20  protected $mOptions = false;
21  protected $mOptionsLabelsNotFromMessage = false;
22  protected $mHideIf = null;
23 
28  protected $mShowEmptyLabels = true;
29 
33  public $mParent;
34 
45  abstract function getInputHTML( $value );
46 
54  function getInputOOUI( $value ) {
55  return false;
56  }
57 
63  public function canDisplayErrors() {
64  return true;
65  }
66 
77  function msg() {
78  $args = func_get_args();
79 
80  if ( $this->mParent ) {
81  $callback = [ $this->mParent, 'msg' ];
82  } else {
83  $callback = 'wfMessage';
84  }
85 
86  return call_user_func_array( $callback, $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  while ( $keys ) {
141  $key = array_shift( $keys );
142  if ( !is_array( $data ) || !array_key_exists( $key, $data ) ) {
143  continue 2;
144  }
145  $data = $data[$key];
146  }
147  $testValue = (string)$data;
148  break;
149  }
150 
151  return $testValue;
152  }
153 
162  protected function isHiddenRecurse( array $alldata, array $params ) {
163  $origParams = $params;
164  $op = array_shift( $params );
165 
166  try {
167  switch ( $op ) {
168  case 'AND':
169  foreach ( $params as $i => $p ) {
170  if ( !is_array( $p ) ) {
171  throw new MWException(
172  "Expected array, found " . gettype( $p ) . " at index $i"
173  );
174  }
175  if ( !$this->isHiddenRecurse( $alldata, $p ) ) {
176  return false;
177  }
178  }
179  return true;
180 
181  case 'OR':
182  foreach ( $params as $i => $p ) {
183  if ( !is_array( $p ) ) {
184  throw new MWException(
185  "Expected array, found " . gettype( $p ) . " at index $i"
186  );
187  }
188  if ( $this->isHiddenRecurse( $alldata, $p ) ) {
189  return true;
190  }
191  }
192  return false;
193 
194  case 'NAND':
195  foreach ( $params as $i => $p ) {
196  if ( !is_array( $p ) ) {
197  throw new MWException(
198  "Expected array, found " . gettype( $p ) . " at index $i"
199  );
200  }
201  if ( !$this->isHiddenRecurse( $alldata, $p ) ) {
202  return true;
203  }
204  }
205  return false;
206 
207  case 'NOR':
208  foreach ( $params as $i => $p ) {
209  if ( !is_array( $p ) ) {
210  throw new MWException(
211  "Expected array, found " . gettype( $p ) . " at index $i"
212  );
213  }
214  if ( $this->isHiddenRecurse( $alldata, $p ) ) {
215  return false;
216  }
217  }
218  return true;
219 
220  case 'NOT':
221  if ( count( $params ) !== 1 ) {
222  throw new MWException( "NOT takes exactly one parameter" );
223  }
224  $p = $params[0];
225  if ( !is_array( $p ) ) {
226  throw new MWException(
227  "Expected array, found " . gettype( $p ) . " at index 0"
228  );
229  }
230  return !$this->isHiddenRecurse( $alldata, $p );
231 
232  case '===':
233  case '!==':
234  if ( count( $params ) !== 2 ) {
235  throw new MWException( "$op takes exactly two parameters" );
236  }
237  list( $field, $value ) = $params;
238  if ( !is_string( $field ) || !is_string( $value ) ) {
239  throw new MWException( "Parameters for $op must be strings" );
240  }
241  $testValue = $this->getNearestFieldByName( $alldata, $field );
242  switch ( $op ) {
243  case '===':
244  return ( $value === $testValue );
245  case '!==':
246  return ( $value !== $testValue );
247  }
248 
249  default:
250  throw new MWException( "Unknown operation" );
251  }
252  } catch ( Exception $ex ) {
253  throw new MWException(
254  "Invalid hide-if specification for $this->mName: " .
255  $ex->getMessage() . " in " . var_export( $origParams, true ),
256  0, $ex
257  );
258  }
259  }
260 
269  function isHidden( $alldata ) {
270  if ( !$this->mHideIf ) {
271  return false;
272  }
273 
274  return $this->isHiddenRecurse( $alldata, $this->mHideIf );
275  }
276 
287  function cancelSubmit( $value, $alldata ) {
288  return false;
289  }
290 
302  function validate( $value, $alldata ) {
303  if ( $this->isHidden( $alldata ) ) {
304  return true;
305  }
306 
307  if ( isset( $this->mParams['required'] )
308  && $this->mParams['required'] !== false
309  && $value === ''
310  ) {
311  return $this->msg( 'htmlform-required' )->parse();
312  }
313 
314  if ( isset( $this->mValidationCallback ) ) {
315  return call_user_func( $this->mValidationCallback, $value, $alldata, $this->mParent );
316  }
317 
318  return true;
319  }
320 
321  function filter( $value, $alldata ) {
322  if ( isset( $this->mFilterCallback ) ) {
323  $value = call_user_func( $this->mFilterCallback, $value, $alldata, $this->mParent );
324  }
325 
326  return $value;
327  }
328 
335  protected function needsLabel() {
336  return true;
337  }
338 
348  public function setShowEmptyLabel( $show ) {
349  $this->mShowEmptyLabels = $show;
350  }
351 
360  if ( $request->getCheck( $this->mName ) ) {
361  return $request->getText( $this->mName );
362  } else {
363  return $this->getDefault();
364  }
365  }
366 
375  function __construct( $params ) {
376  $this->mParams = $params;
377 
378  if ( isset( $params['parent'] ) && $params['parent'] instanceof HTMLForm ) {
379  $this->mParent = $params['parent'];
380  }
381 
382  # Generate the label from a message, if possible
383  if ( isset( $params['label-message'] ) ) {
384  $this->mLabel = $this->getMessage( $params['label-message'] )->parse();
385  } elseif ( isset( $params['label'] ) ) {
386  if ( $params['label'] === '&#160;' ) {
387  // Apparently some things set &nbsp directly and in an odd format
388  $this->mLabel = '&#160;';
389  } else {
390  $this->mLabel = htmlspecialchars( $params['label'] );
391  }
392  } elseif ( isset( $params['label-raw'] ) ) {
393  $this->mLabel = $params['label-raw'];
394  }
395 
396  $this->mName = "wp{$params['fieldname']}";
397  if ( isset( $params['name'] ) ) {
398  $this->mName = $params['name'];
399  }
400 
401  if ( isset( $params['dir'] ) ) {
402  $this->mDir = $params['dir'];
403  }
404 
405  $validName = Sanitizer::escapeId( $this->mName );
406  $validName = str_replace( [ '.5B', '.5D' ], [ '[', ']' ], $validName );
407  if ( $this->mName != $validName && !isset( $params['nodata'] ) ) {
408  throw new MWException( "Invalid name '{$this->mName}' passed to " . __METHOD__ );
409  }
410 
411  $this->mID = "mw-input-{$this->mName}";
412 
413  if ( isset( $params['default'] ) ) {
414  $this->mDefault = $params['default'];
415  }
416 
417  if ( isset( $params['id'] ) ) {
418  $id = $params['id'];
419  $validId = Sanitizer::escapeId( $id );
420 
421  if ( $id != $validId ) {
422  throw new MWException( "Invalid id '$id' passed to " . __METHOD__ );
423  }
424 
425  $this->mID = $id;
426  }
427 
428  if ( isset( $params['cssclass'] ) ) {
429  $this->mClass = $params['cssclass'];
430  }
431 
432  if ( isset( $params['csshelpclass'] ) ) {
433  $this->mHelpClass = $params['csshelpclass'];
434  }
435 
436  if ( isset( $params['validation-callback'] ) ) {
437  $this->mValidationCallback = $params['validation-callback'];
438  }
439 
440  if ( isset( $params['filter-callback'] ) ) {
441  $this->mFilterCallback = $params['filter-callback'];
442  }
443 
444  if ( isset( $params['flatlist'] ) ) {
445  $this->mClass .= ' mw-htmlform-flatlist';
446  }
447 
448  if ( isset( $params['hidelabel'] ) ) {
449  $this->mShowEmptyLabels = false;
450  }
451 
452  if ( isset( $params['hide-if'] ) ) {
453  $this->mHideIf = $params['hide-if'];
454  }
455  }
456 
465  function getTableRow( $value ) {
466  list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
467  $inputHtml = $this->getInputHTML( $value );
468  $fieldType = get_class( $this );
469  $helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
470  $cellAttributes = [];
471  $rowAttributes = [];
472  $rowClasses = '';
473 
474  if ( !empty( $this->mParams['vertical-label'] ) ) {
475  $cellAttributes['colspan'] = 2;
476  $verticalLabel = true;
477  } else {
478  $verticalLabel = false;
479  }
480 
481  $label = $this->getLabelHtml( $cellAttributes );
482 
483  $field = Html::rawElement(
484  'td',
485  [ 'class' => 'mw-input' ] + $cellAttributes,
486  $inputHtml . "\n$errors"
487  );
488 
489  if ( $this->mHideIf ) {
490  $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
491  $rowClasses .= ' mw-htmlform-hide-if';
492  }
493 
494  if ( $verticalLabel ) {
495  $html = Html::rawElement( 'tr',
496  $rowAttributes + [ 'class' => "mw-htmlform-vertical-label $rowClasses" ], $label );
497  $html .= Html::rawElement( 'tr',
498  $rowAttributes + [
499  'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
500  ],
501  $field );
502  } else {
503  $html =
504  Html::rawElement( 'tr',
505  $rowAttributes + [
506  'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
507  ],
508  $label . $field );
509  }
510 
511  return $html . $helptext;
512  }
513 
523  public function getDiv( $value ) {
524  list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
525  $inputHtml = $this->getInputHTML( $value );
526  $fieldType = get_class( $this );
527  $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
528  $cellAttributes = [];
529  $label = $this->getLabelHtml( $cellAttributes );
530 
531  $outerDivClass = [
532  'mw-input',
533  'mw-htmlform-nolabel' => ( $label === '' )
534  ];
535 
536  $horizontalLabel = isset( $this->mParams['horizontal-label'] )
537  ? $this->mParams['horizontal-label'] : false;
538 
539  if ( $horizontalLabel ) {
540  $field = '&#160;' . $inputHtml . "\n$errors";
541  } else {
542  $field = Html::rawElement(
543  'div',
544  [ 'class' => $outerDivClass ] + $cellAttributes,
545  $inputHtml . "\n$errors"
546  );
547  }
548  $divCssClasses = [ "mw-htmlform-field-$fieldType",
549  $this->mClass, $this->mVFormClass, $errorClass ];
550 
551  $wrapperAttributes = [
552  'class' => $divCssClasses,
553  ];
554  if ( $this->mHideIf ) {
555  $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
556  $wrapperAttributes['class'][] = ' mw-htmlform-hide-if';
557  }
558  $html = Html::rawElement( 'div', $wrapperAttributes, $label . $field );
559  $html .= $helptext;
560 
561  return $html;
562  }
563 
572  public function getOOUI( $value ) {
573  $inputField = $this->getInputOOUI( $value );
574 
575  if ( !$inputField ) {
576  // This field doesn't have an OOUI implementation yet at all. Fall back to getDiv() to
577  // generate the whole field, label and errors and all, then wrap it in a Widget.
578  // It might look weird, but it'll work OK.
579  return $this->getFieldLayoutOOUI(
580  new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $this->getDiv( $value ) ) ] ),
581  [ 'infusable' => false, 'align' => 'top' ]
582  );
583  }
584 
585  $infusable = true;
586  if ( is_string( $inputField ) ) {
587  // We have an OOUI implementation, but it's not proper, and we got a load of HTML.
588  // Cheat a little and wrap it in a widget. It won't be infusable, though, since client-side
589  // JavaScript doesn't know how to rebuilt the contents.
590  $inputField = new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $inputField ) ] );
591  $infusable = false;
592  }
593 
594  $fieldType = get_class( $this );
595  $helpText = $this->getHelpText();
596  $errors = $this->getErrorsRaw( $value );
597  foreach ( $errors as &$error ) {
598  $error = new OOUI\HtmlSnippet( $error );
599  }
600 
601  $config = [
602  'classes' => [ "mw-htmlform-field-$fieldType", $this->mClass ],
603  'align' => $this->getLabelAlignOOUI(),
604  'help' => $helpText !== null ? new OOUI\HtmlSnippet( $helpText ) : null,
605  'errors' => $errors,
606  'infusable' => $infusable,
607  ];
608 
609  // the element could specify, that the label doesn't need to be added
610  $label = $this->getLabel();
611  if ( $label ) {
612  $config['label'] = new OOUI\HtmlSnippet( $label );
613  }
614 
615  return $this->getFieldLayoutOOUI( $inputField, $config );
616  }
617 
622  protected function getLabelAlignOOUI() {
623  return 'top';
624  }
625 
630  protected function getFieldLayoutOOUI( $inputField, $config ) {
631  if ( isset( $this->mClassWithButton ) ) {
632  $buttonWidget = $this->mClassWithButton->getInputOOUI( '' );
633  return new OOUI\ActionFieldLayout( $inputField, $buttonWidget, $config );
634  }
635  return new OOUI\FieldLayout( $inputField, $config );
636  }
637 
647  public function getRaw( $value ) {
648  list( $errors, ) = $this->getErrorsAndErrorClass( $value );
649  $inputHtml = $this->getInputHTML( $value );
650  $helptext = $this->getHelpTextHtmlRaw( $this->getHelpText() );
651  $cellAttributes = [];
652  $label = $this->getLabelHtml( $cellAttributes );
653 
654  $html = "\n$errors";
655  $html .= $label;
656  $html .= $inputHtml;
657  $html .= $helptext;
658 
659  return $html;
660  }
661 
670  public function getVForm( $value ) {
671  // Ewwww
672  $this->mVFormClass = ' mw-ui-vform-field';
673  return $this->getDiv( $value );
674  }
675 
682  public function getInline( $value ) {
683  list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
684  $inputHtml = $this->getInputHTML( $value );
685  $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
686  $cellAttributes = [];
687  $label = $this->getLabelHtml( $cellAttributes );
688 
689  $html = "\n" . $errors .
690  $label . '&#160;' .
691  $inputHtml .
692  $helptext;
693 
694  return $html;
695  }
696 
704  public function getHelpTextHtmlTable( $helptext ) {
705  if ( is_null( $helptext ) ) {
706  return '';
707  }
708 
709  $rowAttributes = [];
710  if ( $this->mHideIf ) {
711  $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
712  $rowAttributes['class'] = 'mw-htmlform-hide-if';
713  }
714 
715  $tdClasses = [ 'htmlform-tip' ];
716  if ( $this->mHelpClass !== false ) {
717  $tdClasses[] = $this->mHelpClass;
718  }
719  $row = Html::rawElement( 'td', [ 'colspan' => 2, 'class' => $tdClasses ], $helptext );
720  $row = Html::rawElement( 'tr', $rowAttributes, $row );
721 
722  return $row;
723  }
724 
733  public function getHelpTextHtmlDiv( $helptext ) {
734  if ( is_null( $helptext ) ) {
735  return '';
736  }
737 
738  $wrapperAttributes = [
739  'class' => 'htmlform-tip',
740  ];
741  if ( $this->mHelpClass !== false ) {
742  $wrapperAttributes['class'] .= " {$this->mHelpClass}";
743  }
744  if ( $this->mHideIf ) {
745  $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
746  $wrapperAttributes['class'] .= ' mw-htmlform-hide-if';
747  }
748  $div = Html::rawElement( 'div', $wrapperAttributes, $helptext );
749 
750  return $div;
751  }
752 
760  public function getHelpTextHtmlRaw( $helptext ) {
761  return $this->getHelpTextHtmlDiv( $helptext );
762  }
763 
769  public function getHelpText() {
770  $helptext = null;
771 
772  if ( isset( $this->mParams['help-message'] ) ) {
773  $this->mParams['help-messages'] = [ $this->mParams['help-message'] ];
774  }
775 
776  if ( isset( $this->mParams['help-messages'] ) ) {
777  foreach ( $this->mParams['help-messages'] as $msg ) {
778  $msg = $this->getMessage( $msg );
779 
780  if ( $msg->exists() ) {
781  if ( is_null( $helptext ) ) {
782  $helptext = '';
783  } else {
784  $helptext .= $this->msg( 'word-separator' )->escaped(); // some space
785  }
786  $helptext .= $msg->parse(); // Append message
787  }
788  }
789  } elseif ( isset( $this->mParams['help'] ) ) {
790  $helptext = $this->mParams['help'];
791  }
792 
793  return $helptext;
794  }
795 
803  public function getErrorsAndErrorClass( $value ) {
804  $errors = $this->validate( $value, $this->mParent->mFieldData );
805 
806  if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
807  $errors = '';
808  $errorClass = '';
809  } else {
810  $errors = self::formatErrors( $errors );
811  $errorClass = 'mw-htmlform-invalid-input';
812  }
813 
814  return [ $errors, $errorClass ];
815  }
816 
824  public function getErrorsRaw( $value ) {
825  $errors = $this->validate( $value, $this->mParent->mFieldData );
826 
827  if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
828  $errors = [];
829  }
830 
831  if ( !is_array( $errors ) ) {
832  $errors = [ $errors ];
833  }
834  foreach ( $errors as &$error ) {
835  if ( $error instanceof Message ) {
836  $error = $error->parse();
837  }
838  }
839 
840  return $errors;
841  }
842 
846  function getLabel() {
847  return is_null( $this->mLabel ) ? '' : $this->mLabel;
848  }
849 
850  function getLabelHtml( $cellAttributes = [] ) {
851  # Don't output a for= attribute for labels with no associated input.
852  # Kind of hacky here, possibly we don't want these to be <label>s at all.
853  $for = [];
854 
855  if ( $this->needsLabel() ) {
856  $for['for'] = $this->mID;
857  }
858 
859  $labelValue = trim( $this->getLabel() );
860  $hasLabel = false;
861  if ( $labelValue !== '&#160;' && $labelValue !== '' ) {
862  $hasLabel = true;
863  }
864 
865  $displayFormat = $this->mParent->getDisplayFormat();
866  $html = '';
867  $horizontalLabel = isset( $this->mParams['horizontal-label'] )
868  ? $this->mParams['horizontal-label'] : false;
869 
870  if ( $displayFormat === 'table' ) {
871  $html =
872  Html::rawElement( 'td',
873  [ 'class' => 'mw-label' ] + $cellAttributes,
874  Html::rawElement( 'label', $for, $labelValue ) );
875  } elseif ( $hasLabel || $this->mShowEmptyLabels ) {
876  if ( $displayFormat === 'div' && !$horizontalLabel ) {
877  $html =
878  Html::rawElement( 'div',
879  [ 'class' => 'mw-label' ] + $cellAttributes,
880  Html::rawElement( 'label', $for, $labelValue ) );
881  } else {
882  $html = Html::rawElement( 'label', $for, $labelValue );
883  }
884  }
885 
886  return $html;
887  }
888 
889  function getDefault() {
890  if ( isset( $this->mDefault ) ) {
891  return $this->mDefault;
892  } else {
893  return null;
894  }
895  }
896 
902  public function getTooltipAndAccessKey() {
903  if ( empty( $this->mParams['tooltip'] ) ) {
904  return [];
905  }
906 
907  return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] );
908  }
909 
916  public function getAttributes( array $list ) {
917  static $boolAttribs = [ 'disabled', 'required', 'autofocus', 'multiple', 'readonly' ];
918 
919  $ret = [];
920  foreach ( $list as $key ) {
921  if ( in_array( $key, $boolAttribs ) ) {
922  if ( !empty( $this->mParams[$key] ) ) {
923  $ret[$key] = '';
924  }
925  } elseif ( isset( $this->mParams[$key] ) ) {
926  $ret[$key] = $this->mParams[$key];
927  }
928  }
929 
930  return $ret;
931  }
932 
940  private function lookupOptionsKeys( $options ) {
941  $ret = [];
942  foreach ( $options as $key => $value ) {
943  $key = $this->msg( $key )->plain();
944  $ret[$key] = is_array( $value )
945  ? $this->lookupOptionsKeys( $value )
946  : strval( $value );
947  }
948  return $ret;
949  }
950 
958  static function forceToStringRecursive( $array ) {
959  if ( is_array( $array ) ) {
960  return array_map( [ __CLASS__, 'forceToStringRecursive' ], $array );
961  } else {
962  return strval( $array );
963  }
964  }
965 
972  public function getOptions() {
973  if ( $this->mOptions === false ) {
974  if ( array_key_exists( 'options-messages', $this->mParams ) ) {
975  $this->mOptions = $this->lookupOptionsKeys( $this->mParams['options-messages'] );
976  } elseif ( array_key_exists( 'options', $this->mParams ) ) {
977  $this->mOptionsLabelsNotFromMessage = true;
978  $this->mOptions = self::forceToStringRecursive( $this->mParams['options'] );
979  } elseif ( array_key_exists( 'options-message', $this->mParams ) ) {
981  $message = $this->getMessage( $this->mParams['options-message'] )->inContentLanguage()->plain();
982 
983  $optgroup = false;
984  $this->mOptions = [];
985  foreach ( explode( "\n", $message ) as $option ) {
986  $value = trim( $option );
987  if ( $value == '' ) {
988  continue;
989  } elseif ( substr( $value, 0, 1 ) == '*' && substr( $value, 1, 1 ) != '*' ) {
990  # A new group is starting...
991  $value = trim( substr( $value, 1 ) );
992  $optgroup = $value;
993  } elseif ( substr( $value, 0, 2 ) == '**' ) {
994  # groupmember
995  $opt = trim( substr( $value, 2 ) );
996  if ( $optgroup === false ) {
997  $this->mOptions[$opt] = $opt;
998  } else {
999  $this->mOptions[$optgroup][$opt] = $opt;
1000  }
1001  } else {
1002  # groupless reason list
1003  $optgroup = false;
1004  $this->mOptions[$option] = $option;
1005  }
1006  }
1007  } else {
1008  $this->mOptions = null;
1009  }
1010  }
1011 
1012  return $this->mOptions;
1013  }
1014 
1019  public function getOptionsOOUI() {
1020  $oldoptions = $this->getOptions();
1021 
1022  if ( $oldoptions === null ) {
1023  return null;
1024  }
1025 
1026  $options = [];
1027 
1028  foreach ( $oldoptions as $text => $data ) {
1029  $options[] = [
1030  'data' => (string)$data,
1031  'label' => (string)$text,
1032  ];
1033  }
1034 
1035  return $options;
1036  }
1037 
1045  public static function flattenOptions( $options ) {
1046  $flatOpts = [];
1047 
1048  foreach ( $options as $value ) {
1049  if ( is_array( $value ) ) {
1050  $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) );
1051  } else {
1052  $flatOpts[] = $value;
1053  }
1054  }
1055 
1056  return $flatOpts;
1057  }
1058 
1066  protected static function formatErrors( $errors ) {
1067  if ( is_array( $errors ) && count( $errors ) === 1 ) {
1068  $errors = array_shift( $errors );
1069  }
1070 
1071  if ( is_array( $errors ) ) {
1072  $lines = [];
1073  foreach ( $errors as $error ) {
1074  if ( $error instanceof Message ) {
1075  $lines[] = Html::rawElement( 'li', [], $error->parse() );
1076  } else {
1077  $lines[] = Html::rawElement( 'li', [], $error );
1078  }
1079  }
1080 
1081  return Html::rawElement( 'ul', [ 'class' => 'error' ], implode( "\n", $lines ) );
1082  } else {
1083  if ( $errors instanceof Message ) {
1084  $errors = $errors->parse();
1085  }
1086 
1087  return Html::rawElement( 'span', [ 'class' => 'error' ], $errors );
1088  }
1089  }
1090 
1097  protected function getMessage( $value ) {
1098  $message = Message::newFromSpecifier( $value );
1099 
1100  if ( $this->mParent ) {
1101  $message->setContext( $this->mParent );
1102  }
1103 
1104  return $message;
1105  }
1106 
1113  public function skipLoadData( $request ) {
1114  return !empty( $this->mParams['nodata'] );
1115  }
1116 }
getInline($value)
Get the complete field as an inline element.
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:1798
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
static formatErrors($errors)
Formats one or more errors as accepted by field validation-callback.
getRaw($value)
Get the complete raw fields for the input, including help text, labels, and whatever.
HTMLForm null $mParent
skipLoadData($request)
Skip this field when collecting data.
the array() calling protocol came about after MediaWiki 1.4rc1.
getOptions()
Fetch the array of options from the field's parameters.
loadDataFromRequest($request)
Get the value that this input has been set to from a posted form, or the input's default value if it ...
magic word the default is to use $key to get the and $key value or $key value text $key value html to format the value $key
Definition: hooks.txt:2321
lookupOptionsKeys($options)
Given an array of msg-key => value mappings, returns an array with keys being the message texts...
getMessage($value)
Turns a *-message parameter (which could be a MessageSpecifier, or a message name, or a name + parameters array) into a Message.
getLabelHtml($cellAttributes=[])
msg()
Get a translated interface message.
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:1798
isHidden($alldata)
Test whether this field is supposed to be hidden, based on the values of the other form fields...
getVForm($value)
Get the complete field for the input, including help text, labels, and whatever.
static rawElement($element, $attribs=[], $contents= '')
Returns an HTML element in a string.
Definition: Html.php:210
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:177
getTooltipAndAccessKey()
Returns the attributes required for the tooltip and accesskey.
$value
setShowEmptyLabel($show)
Tell the field whether to generate a separate label element if its label is blank.
getHelpText()
Determine the help text to display.
static tooltipAndAccesskeyAttribs($name, array $msgParams=[])
Returns the attributes for the tooltip and access key.
Definition: Linker.php:2335
static forceToStringRecursive($array)
Recursively forces values in an array to strings, because issues arise with integer 0 as a value...
getErrorsRaw($value)
Determine form errors to display, returning them in an array.
filter($value, $alldata)
getOOUI($value)
Get the OOUI version of the div.
if($line===false) $args
Definition: cdb.php:64
__construct($params)
Initialise the object.
validate($value, $alldata)
Override this function to add specific validation checks on the field input.
bool $mShowEmptyLabels
If true will generate an empty div element with no label.
magic word the default is to use $key to get the label
Definition: hooks.txt:2321
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
Definition: hooks.txt:1004
getNearestFieldByName($alldata, $name)
Fetch a field value from $alldata for the closest field matching a given name.
getTableRow($value)
Get the complete table row for the input, including help text, labels, and whatever.
static encode($value, $pretty=false, $escaping=0)
Returns the JSON representation of a value.
Definition: FormatJson.php:127
$params
getInputOOUI($value)
Same as getInputHTML, but returns an OOUI object.
getHelpTextHtmlTable($helptext)
Generate help text HTML in table format.
Object handling generic submission, CSRF protection, layout and other logic for UI forms...
Definition: HTMLForm.php:123
getDiv($value)
Get the complete div for the input, including help text, labels, and whatever.
getLabelAlignOOUI()
Get label alignment when generating field for OOUI.
getFieldLayoutOOUI($inputField, $config)
Get a FieldLayout (or subclass thereof) to wrap this field in when using OOUI output.
canDisplayErrors()
True if this field type is able to display errors; false if validation errors need to be displayed in...
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
getOptionsOOUI()
Get options and make them into arrays suitable for OOUI.
static escapeId($id, $options=[])
Given a value, escape it so that it can be used in an id attribute and return it. ...
Definition: Sanitizer.php:1132
needsLabel()
Should this field have a label, or is there no input element with the appropriate id for the label to...
getInputHTML($value)
This function must be implemented to return the HTML to generate the input object itself...
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
$lines
Definition: router.php:66
error also a ContextSource you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2418
The parent class to generate form fields.
cancelSubmit($value, $alldata)
Override this function if the control can somehow trigger a form submission that shouldn't actually s...
getHelpTextHtmlDiv($helptext)
Generate help text HTML in div format.
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:86
getErrorsAndErrorClass($value)
Determine form errors to display and their classes.
getHelpTextHtmlRaw($helptext)
Generate help text HTML formatted for raw output.
hasVisibleOutput()
If this field has a user-visible output or not.
static flattenOptions($options)
flatten an array of options to a single array, for instance, a set of "" inside "...
getAttributes(array $list)
Returns the given attributes from the parameters.
isHiddenRecurse(array $alldata, array $params)
Helper function for isHidden to handle recursive data structures.
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:310
static newFromSpecifier($value)
Transform a MessageSpecifier or a primitive value used interchangeably with specifiers (a message key...
Definition: Message.php:397