MediaWiki REL1_37
HTMLFormField.php
Go to the documentation of this file.
1<?php
2
9abstract class HTMLFormField {
11 public $mParams;
12
15 protected $mName;
16 protected $mDir;
17 protected $mLabel; # String label, as HTML. Set on construction.
18 protected $mID;
19 protected $mClass = '';
20 protected $mVFormClass = '';
21 protected $mHelpClass = false;
22 protected $mDefault;
26 protected $mOptions = false;
28 protected $mHideIf = null;
29
34 protected $mShowEmptyLabels = true;
35
39 public $mParent;
40
51 abstract public function getInputHTML( $value );
52
61 public function getInputOOUI( $value ) {
62 return false;
63 }
64
71 public function canDisplayErrors() {
72 return $this->hasVisibleOutput();
73 }
74
87 public function msg( $key, ...$params ) {
88 if ( $this->mParent ) {
89 return $this->mParent->msg( $key, ...$params );
90 }
91 return wfMessage( $key, ...$params );
92 }
93
101 public function hasVisibleOutput() {
102 return true;
103 }
104
118 protected function getNearestFieldByName( $alldata, $name ) {
119 $tmp = $this->mName;
120 $thisKeys = [];
121 while ( preg_match( '/^(.+)\[([^\]]+)\]$/', $tmp, $m ) ) {
122 array_unshift( $thisKeys, $m[2] );
123 $tmp = $m[1];
124 }
125 if ( substr( $tmp, 0, 2 ) == 'wp' &&
126 !array_key_exists( $tmp, $alldata ) &&
127 array_key_exists( substr( $tmp, 2 ), $alldata )
128 ) {
129 // Adjust for name mangling.
130 $tmp = substr( $tmp, 2 );
131 }
132 array_unshift( $thisKeys, $tmp );
133
134 $tmp = $name;
135 $nameKeys = [];
136 while ( preg_match( '/^(.+)\[([^\]]+)\]$/', $tmp, $m ) ) {
137 array_unshift( $nameKeys, $m[2] );
138 $tmp = $m[1];
139 }
140 array_unshift( $nameKeys, $tmp );
141
142 $testValue = '';
143 for ( $i = count( $thisKeys ) - 1; $i >= 0; $i-- ) {
144 $keys = array_merge( array_slice( $thisKeys, 0, $i ), $nameKeys );
145 $data = $alldata;
146 foreach ( $keys as $key ) {
147 if ( !is_array( $data ) || !array_key_exists( $key, $data ) ) {
148 continue 2;
149 }
150 $data = $data[$key];
151 }
152 $testValue = (string)$data;
153 break;
154 }
155
156 return $testValue;
157 }
158
167 protected function isHiddenRecurse( array $alldata, array $params ) {
168 $origParams = $params;
169 $op = array_shift( $params );
170
171 try {
172 switch ( $op ) {
173 case 'AND':
174 foreach ( $params as $i => $p ) {
175 if ( !is_array( $p ) ) {
176 throw new MWException(
177 "Expected array, found " . gettype( $p ) . " at index $i"
178 );
179 }
180 if ( !$this->isHiddenRecurse( $alldata, $p ) ) {
181 return false;
182 }
183 }
184 return true;
185
186 case 'OR':
187 foreach ( $params as $i => $p ) {
188 if ( !is_array( $p ) ) {
189 throw new MWException(
190 "Expected array, found " . gettype( $p ) . " at index $i"
191 );
192 }
193 if ( $this->isHiddenRecurse( $alldata, $p ) ) {
194 return true;
195 }
196 }
197 return false;
198
199 case 'NAND':
200 foreach ( $params as $i => $p ) {
201 if ( !is_array( $p ) ) {
202 throw new MWException(
203 "Expected array, found " . gettype( $p ) . " at index $i"
204 );
205 }
206 if ( !$this->isHiddenRecurse( $alldata, $p ) ) {
207 return true;
208 }
209 }
210 return false;
211
212 case 'NOR':
213 foreach ( $params as $i => $p ) {
214 if ( !is_array( $p ) ) {
215 throw new MWException(
216 "Expected array, found " . gettype( $p ) . " at index $i"
217 );
218 }
219 if ( $this->isHiddenRecurse( $alldata, $p ) ) {
220 return false;
221 }
222 }
223 return true;
224
225 case 'NOT':
226 if ( count( $params ) !== 1 ) {
227 throw new MWException( "NOT takes exactly one parameter" );
228 }
229 $p = $params[0];
230 if ( !is_array( $p ) ) {
231 throw new MWException(
232 "Expected array, found " . gettype( $p ) . " at index 0"
233 );
234 }
235 return !$this->isHiddenRecurse( $alldata, $p );
236
237 case '===':
238 case '!==':
239 if ( count( $params ) !== 2 ) {
240 throw new MWException( "$op takes exactly two parameters" );
241 }
242 list( $field, $value ) = $params;
243 if ( !is_string( $field ) || !is_string( $value ) ) {
244 throw new MWException( "Parameters for $op must be strings" );
245 }
246 $testValue = $this->getNearestFieldByName( $alldata, $field );
247 switch ( $op ) {
248 case '===':
249 return ( $value === $testValue );
250 case '!==':
251 return ( $value !== $testValue );
252 }
253 // fall-through, if $op is not added to both cases
254 default:
255 throw new MWException( "Unknown operation" );
256 }
257 } catch ( Exception $ex ) {
258 throw new MWException(
259 "Invalid hide-if specification for $this->mName: " .
260 $ex->getMessage() . " in " . var_export( $origParams, true ),
261 0, $ex
262 );
263 }
264 }
265
274 public function isHidden( $alldata ) {
275 if ( !$this->mHideIf ) {
276 return false;
277 }
278
279 return $this->isHiddenRecurse( $alldata, $this->mHideIf );
280 }
281
293 public function cancelSubmit( $value, $alldata ) {
294 return false;
295 }
296
309 public function validate( $value, $alldata ) {
310 if ( $this->isHidden( $alldata ) ) {
311 return true;
312 }
313
314 if ( isset( $this->mParams['required'] )
315 && $this->mParams['required'] !== false
316 && $value === ''
317 ) {
318 return $this->msg( 'htmlform-required' );
319 }
320
321 if ( isset( $this->mValidationCallback ) ) {
322 return ( $this->mValidationCallback )( $value, $alldata, $this->mParent );
323 }
324
325 return true;
326 }
327
336 public function filter( $value, $alldata ) {
337 if ( isset( $this->mFilterCallback ) ) {
338 $value = ( $this->mFilterCallback )( $value, $alldata, $this->mParent );
339 }
340
341 return $value;
342 }
343
351 protected function needsLabel() {
352 return true;
353 }
354
364 public function setShowEmptyLabel( $show ) {
365 $this->mShowEmptyLabels = $show;
366 }
367
378 protected function isSubmitAttempt( WebRequest $request ) {
379 return $request->getCheck( 'wpEditToken' ) || $request->getCheck( 'wpFormIdentifier' );
380 }
381
390 public function loadDataFromRequest( $request ) {
391 if ( $request->getCheck( $this->mName ) ) {
392 return $request->getText( $this->mName );
393 } else {
394 return $this->getDefault();
395 }
396 }
397
407 public function __construct( $params ) {
408 $this->mParams = $params;
409
410 if ( isset( $params['parent'] ) && $params['parent'] instanceof HTMLForm ) {
411 $this->mParent = $params['parent'];
412 }
413
414 # Generate the label from a message, if possible
415 if ( isset( $params['label-message'] ) ) {
416 $this->mLabel = $this->getMessage( $params['label-message'] )->parse();
417 } elseif ( isset( $params['label'] ) ) {
418 if ( $params['label'] === '&#160;' || $params['label'] === "\u{00A0}" ) {
419 // Apparently some things set &nbsp directly and in an odd format
420 $this->mLabel = "\u{00A0}";
421 } else {
422 $this->mLabel = htmlspecialchars( $params['label'] );
423 }
424 } elseif ( isset( $params['label-raw'] ) ) {
425 $this->mLabel = $params['label-raw'];
426 }
427
428 $this->mName = "wp{$params['fieldname']}";
429 if ( isset( $params['name'] ) ) {
430 $this->mName = $params['name'];
431 }
432
433 if ( isset( $params['dir'] ) ) {
434 $this->mDir = $params['dir'];
435 }
436
437 $validName = urlencode( $this->mName );
438 $validName = str_replace( [ '%5B', '%5D' ], [ '[', ']' ], $validName );
439 if ( $this->mName != $validName && !isset( $params['nodata'] ) ) {
440 throw new MWException( "Invalid name '{$this->mName}' passed to " . __METHOD__ );
441 }
442
443 $this->mID = "mw-input-{$this->mName}";
444
445 if ( isset( $params['default'] ) ) {
446 $this->mDefault = $params['default'];
447 }
448
449 if ( isset( $params['id'] ) ) {
450 $id = $params['id'];
451 $validId = urlencode( $id );
452
453 if ( $id != $validId ) {
454 throw new MWException( "Invalid id '$id' passed to " . __METHOD__ );
455 }
456
457 $this->mID = $id;
458 }
459
460 if ( isset( $params['cssclass'] ) ) {
461 $this->mClass = $params['cssclass'];
462 }
463
464 if ( isset( $params['csshelpclass'] ) ) {
465 $this->mHelpClass = $params['csshelpclass'];
466 }
467
468 if ( isset( $params['validation-callback'] ) ) {
469 $this->mValidationCallback = $params['validation-callback'];
470 }
471
472 if ( isset( $params['filter-callback'] ) ) {
473 $this->mFilterCallback = $params['filter-callback'];
474 }
475
476 if ( isset( $params['hidelabel'] ) ) {
477 $this->mShowEmptyLabels = false;
478 }
479
480 if ( isset( $params['hide-if'] ) ) {
481 $this->mHideIf = $params['hide-if'];
482 }
483 }
484
494 public function getTableRow( $value ) {
495 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
496 $inputHtml = $this->getInputHTML( $value );
497 $fieldType = $this->getClassName();
498 $helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
499 $cellAttributes = [];
500 $rowAttributes = [];
501 $rowClasses = '';
502
503 if ( !empty( $this->mParams['vertical-label'] ) ) {
504 $cellAttributes['colspan'] = 2;
505 $verticalLabel = true;
506 } else {
507 $verticalLabel = false;
508 }
509
510 $label = $this->getLabelHtml( $cellAttributes );
511
512 $field = Html::rawElement(
513 'td',
514 [ 'class' => 'mw-input' ] + $cellAttributes,
515 $inputHtml . "\n$errors"
516 );
517
518 if ( $this->mHideIf ) {
519 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
520 $rowClasses .= ' mw-htmlform-hide-if';
521 }
522
523 if ( $verticalLabel ) {
524 $html = Html::rawElement( 'tr',
525 $rowAttributes + [ 'class' => "mw-htmlform-vertical-label $rowClasses" ], $label );
526 $html .= Html::rawElement( 'tr',
527 $rowAttributes + [
528 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
529 ],
530 $field );
531 } else {
532 $html =
533 Html::rawElement( 'tr',
534 $rowAttributes + [
535 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
536 ],
537 $label . $field );
538 }
539
540 return $html . $helptext;
541 }
542
553 public function getDiv( $value ) {
554 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
555 $inputHtml = $this->getInputHTML( $value );
556 $fieldType = $this->getClassName();
557 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
558 $cellAttributes = [];
559 $label = $this->getLabelHtml( $cellAttributes );
560
561 $outerDivClass = [
562 'mw-input',
563 'mw-htmlform-nolabel' => ( $label === '' )
564 ];
565
566 $horizontalLabel = $this->mParams['horizontal-label'] ?? false;
567
568 if ( $horizontalLabel ) {
569 $field = "\u{00A0}" . $inputHtml . "\n$errors";
570 } else {
571 $field = Html::rawElement(
572 'div',
573 // @phan-suppress-next-line PhanUselessBinaryAddRight
574 [ 'class' => $outerDivClass ] + $cellAttributes,
575 $inputHtml . "\n$errors"
576 );
577 }
578 $divCssClasses = [ "mw-htmlform-field-$fieldType",
579 $this->mClass, $this->mVFormClass, $errorClass ];
580
581 $wrapperAttributes = [
582 'class' => $divCssClasses,
583 ];
584 if ( $this->mHideIf ) {
585 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
586 $wrapperAttributes['class'][] = ' mw-htmlform-hide-if';
587 }
588 $html = Html::rawElement( 'div', $wrapperAttributes, $label . $field );
589 $html .= $helptext;
590
591 return $html;
592 }
593
603 public function getOOUI( $value ) {
604 $inputField = $this->getInputOOUI( $value );
605
606 if ( !$inputField ) {
607 // This field doesn't have an OOUI implementation yet at all. Fall back to getDiv() to
608 // generate the whole field, label and errors and all, then wrap it in a Widget.
609 // It might look weird, but it'll work OK.
610 return $this->getFieldLayoutOOUI(
611 new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $this->getDiv( $value ) ) ] ),
612 [ 'align' => 'top' ]
613 );
614 }
615
616 $infusable = true;
617 if ( is_string( $inputField ) ) {
618 // We have an OOUI implementation, but it's not proper, and we got a load of HTML.
619 // Cheat a little and wrap it in a widget. It won't be infusable, though, since client-side
620 // JavaScript doesn't know how to rebuilt the contents.
621 $inputField = new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $inputField ) ] );
622 $infusable = false;
623 }
624
625 $fieldType = $this->getClassName();
626 $help = $this->getHelpText();
627 $errors = $this->getErrorsRaw( $value );
628 foreach ( $errors as &$error ) {
629 $error = new OOUI\HtmlSnippet( $error );
630 }
631
632 $config = [
633 'classes' => [ "mw-htmlform-field-$fieldType", $this->mClass ],
634 'align' => $this->getLabelAlignOOUI(),
635 'help' => ( $help !== null && $help !== '' ) ? new OOUI\HtmlSnippet( $help ) : null,
636 'errors' => $errors,
637 'infusable' => $infusable,
638 'helpInline' => $this->isHelpInline(),
639 ];
640
641 $preloadModules = false;
642
643 if ( $infusable && $this->shouldInfuseOOUI() ) {
644 $preloadModules = true;
645 $config['classes'][] = 'mw-htmlform-autoinfuse';
646 }
647
648 // the element could specify, that the label doesn't need to be added
649 $label = $this->getLabel();
650 if ( $label && $label !== "\u{00A0}" && $label !== '&#160;' ) {
651 $config['label'] = new OOUI\HtmlSnippet( $label );
652 }
653
654 if ( $this->mHideIf ) {
655 $preloadModules = true;
656 $config['hideIf'] = $this->mHideIf;
657 }
658
659 $config['modules'] = $this->getOOUIModules();
660
661 if ( $preloadModules ) {
662 $this->mParent->getOutput()->addModules( 'mediawiki.htmlform.ooui' );
663 $this->mParent->getOutput()->addModules( $this->getOOUIModules() );
664 }
665
666 return $this->getFieldLayoutOOUI( $inputField, $config );
667 }
668
676 protected function getClassName() {
677 $name = explode( '\\', static::class );
678 return end( $name );
679 }
680
686 protected function getLabelAlignOOUI() {
687 return 'top';
688 }
689
697 protected function getFieldLayoutOOUI( $inputField, $config ) {
698 if ( isset( $this->mClassWithButton ) ) {
699 $buttonWidget = $this->mClassWithButton->getInputOOUI( '' );
700 return new HTMLFormActionFieldLayout( $inputField, $buttonWidget, $config );
701 }
702 return new HTMLFormFieldLayout( $inputField, $config );
703 }
704
713 protected function shouldInfuseOOUI() {
714 // Always infuse fields with popup help text, since the interface for it is nicer with JS
715 return $this->getHelpText() !== null && !$this->isHelpInline();
716 }
717
725 protected function getOOUIModules() {
726 return [];
727 }
728
739 public function getRaw( $value ) {
740 list( $errors, ) = $this->getErrorsAndErrorClass( $value );
741 $inputHtml = $this->getInputHTML( $value );
742 $helptext = $this->getHelpTextHtmlRaw( $this->getHelpText() );
743 $cellAttributes = [];
744 $label = $this->getLabelHtml( $cellAttributes );
745
746 $html = "\n$errors";
747 $html .= $label;
748 $html .= $inputHtml;
749 $html .= $helptext;
750
751 return $html;
752 }
753
763 public function getVForm( $value ) {
764 // Ewwww
765 $this->mVFormClass = ' mw-ui-vform-field';
766 return $this->getDiv( $value );
767 }
768
776 public function getInline( $value ) {
777 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
778 $inputHtml = $this->getInputHTML( $value );
779 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
780 $cellAttributes = [];
781 $label = $this->getLabelHtml( $cellAttributes );
782
783 $html = "\n" . $errors .
784 $label . "\u{00A0}" .
785 $inputHtml .
786 $helptext;
787
788 return $html;
789 }
790
798 public function getHelpTextHtmlTable( $helptext ) {
799 if ( $helptext === null ) {
800 return '';
801 }
802
803 $rowAttributes = [];
804 if ( $this->mHideIf ) {
805 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
806 $rowAttributes['class'] = 'mw-htmlform-hide-if';
807 }
808
809 $tdClasses = [ 'htmlform-tip' ];
810 if ( $this->mHelpClass !== false ) {
811 $tdClasses[] = $this->mHelpClass;
812 }
813 $row = Html::rawElement( 'td', [ 'colspan' => 2, 'class' => $tdClasses ], $helptext );
814 $row = Html::rawElement( 'tr', $rowAttributes, $row );
815
816 return $row;
817 }
818
827 public function getHelpTextHtmlDiv( $helptext ) {
828 if ( $helptext === null ) {
829 return '';
830 }
831
832 $wrapperAttributes = [
833 'class' => 'htmlform-tip',
834 ];
835 if ( $this->mHelpClass !== false ) {
836 $wrapperAttributes['class'] .= " {$this->mHelpClass}";
837 }
838 if ( $this->mHideIf ) {
839 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
840 $wrapperAttributes['class'] .= ' mw-htmlform-hide-if';
841 }
842 $div = Html::rawElement( 'div', $wrapperAttributes, $helptext );
843
844 return $div;
845 }
846
854 public function getHelpTextHtmlRaw( $helptext ) {
855 return $this->getHelpTextHtmlDiv( $helptext );
856 }
857
864 public function getHelpText() {
865 $helptext = null;
866
867 if ( isset( $this->mParams['help-message'] ) ) {
868 $this->mParams['help-messages'] = [ $this->mParams['help-message'] ];
869 }
870
871 if ( isset( $this->mParams['help-messages'] ) ) {
872 foreach ( $this->mParams['help-messages'] as $msg ) {
873 $msg = $this->getMessage( $msg );
874
875 if ( $msg->exists() ) {
876 if ( $helptext === null ) {
877 $helptext = '';
878 } else {
879 $helptext .= $this->msg( 'word-separator' )->escaped(); // some space
880 }
881 $helptext .= $msg->parse(); // Append message
882 }
883 }
884 } elseif ( isset( $this->mParams['help'] ) ) {
885 $helptext = $this->mParams['help'];
886 }
887
888 return $helptext;
889 }
890
899 public function isHelpInline() {
900 return $this->mParams['help-inline'] ?? true;
901 }
902
915 public function getErrorsAndErrorClass( $value ) {
916 $errors = $this->validate( $value, $this->mParent->mFieldData );
917
918 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
919 $errors = '';
920 $errorClass = '';
921 } else {
922 $errors = self::formatErrors( $errors );
923 $errorClass = 'mw-htmlform-invalid-input';
924 }
925
926 return [ $errors, $errorClass ];
927 }
928
936 public function getErrorsRaw( $value ) {
937 $errors = $this->validate( $value, $this->mParent->mFieldData );
938
939 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
940 $errors = [];
941 }
942
943 if ( !is_array( $errors ) ) {
944 $errors = [ $errors ];
945 }
946 foreach ( $errors as &$error ) {
947 if ( $error instanceof Message ) {
948 $error = $error->parse();
949 }
950 }
951
952 return $errors;
953 }
954
959 public function getLabel() {
960 return $this->mLabel ?? '';
961 }
962
969 public function getLabelHtml( $cellAttributes = [] ) {
970 # Don't output a for= attribute for labels with no associated input.
971 # Kind of hacky here, possibly we don't want these to be <label>s at all.
972 $for = [];
973
974 if ( $this->needsLabel() ) {
975 $for['for'] = $this->mID;
976 }
977
978 $labelValue = trim( $this->getLabel() );
979 $hasLabel = false;
980 if ( $labelValue !== "\u{00A0}" && $labelValue !== '&#160;' && $labelValue !== '' ) {
981 $hasLabel = true;
982 }
983
984 $displayFormat = $this->mParent->getDisplayFormat();
985 $html = '';
986 $horizontalLabel = $this->mParams['horizontal-label'] ?? false;
987
988 if ( $displayFormat === 'table' ) {
989 $html =
990 Html::rawElement( 'td',
991 [ 'class' => 'mw-label' ] + $cellAttributes,
992 Html::rawElement( 'label', $for, $labelValue ) );
993 } elseif ( $hasLabel || $this->mShowEmptyLabels ) {
994 if ( $displayFormat === 'div' && !$horizontalLabel ) {
995 $html =
996 Html::rawElement( 'div',
997 [ 'class' => 'mw-label' ] + $cellAttributes,
998 Html::rawElement( 'label', $for, $labelValue ) );
999 } else {
1000 $html = Html::rawElement( 'label', $for, $labelValue );
1001 }
1002 }
1003
1004 return $html;
1005 }
1006
1011 public function getDefault() {
1012 return $this->mDefault ?? null;
1013 }
1014
1020 public function getTooltipAndAccessKey() {
1021 if ( empty( $this->mParams['tooltip'] ) ) {
1022 return [];
1023 }
1024
1025 return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] );
1026 }
1027
1033 public function getTooltipAndAccessKeyOOUI() {
1034 if ( empty( $this->mParams['tooltip'] ) ) {
1035 return [];
1036 }
1037
1038 return [
1039 'title' => Linker::titleAttrib( $this->mParams['tooltip'] ),
1040 'accessKey' => Linker::accesskey( $this->mParams['tooltip'] ),
1041 ];
1042 }
1043
1051 public function getAttributes( array $list ) {
1052 static $boolAttribs = [ 'disabled', 'required', 'autofocus', 'multiple', 'readonly' ];
1053
1054 $ret = [];
1055 foreach ( $list as $key ) {
1056 if ( in_array( $key, $boolAttribs ) ) {
1057 if ( !empty( $this->mParams[$key] ) ) {
1058 $ret[$key] = '';
1059 }
1060 } elseif ( isset( $this->mParams[$key] ) ) {
1061 $ret[$key] = $this->mParams[$key];
1062 }
1063 }
1064
1065 return $ret;
1066 }
1067
1077 private function lookupOptionsKeys( $options, $needsParse ) {
1078 $ret = [];
1079 foreach ( $options as $key => $value ) {
1080 $msg = $this->msg( $key );
1081 $key = $needsParse ? $msg->parse() : $msg->plain();
1082 $ret[$key] = is_array( $value )
1083 ? $this->lookupOptionsKeys( $value, $needsParse )
1084 : strval( $value );
1085 }
1086 return $ret;
1087 }
1088
1096 public static function forceToStringRecursive( $array ) {
1097 if ( is_array( $array ) ) {
1098 return array_map( [ __CLASS__, 'forceToStringRecursive' ], $array );
1099 } else {
1100 return strval( $array );
1101 }
1102 }
1103
1110 public function getOptions() {
1111 if ( $this->mOptions === false ) {
1112 if ( array_key_exists( 'options-messages', $this->mParams ) ) {
1113 $needsParse = $this->mParams['options-messages-parse'] ?? false;
1114 if ( $needsParse ) {
1115 $this->mOptionsLabelsNotFromMessage = true;
1116 }
1117 $this->mOptions = $this->lookupOptionsKeys( $this->mParams['options-messages'], $needsParse );
1118 } elseif ( array_key_exists( 'options', $this->mParams ) ) {
1119 $this->mOptionsLabelsNotFromMessage = true;
1120 $this->mOptions = self::forceToStringRecursive( $this->mParams['options'] );
1121 } elseif ( array_key_exists( 'options-message', $this->mParams ) ) {
1122 $message = $this->getMessage( $this->mParams['options-message'] )->inContentLanguage()->plain();
1123 $this->mOptions = Xml::listDropDownOptions( $message );
1124 } else {
1125 $this->mOptions = null;
1126 }
1127 }
1128
1129 return $this->mOptions;
1130 }
1131
1137 public function getOptionsOOUI() {
1138 $oldoptions = $this->getOptions();
1139
1140 if ( $oldoptions === null ) {
1141 return null;
1142 }
1143
1144 return Xml::listDropDownOptionsOoui( $oldoptions );
1145 }
1146
1154 public static function flattenOptions( $options ) {
1155 $flatOpts = [];
1156
1157 foreach ( $options as $value ) {
1158 if ( is_array( $value ) ) {
1159 $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) );
1160 } else {
1161 $flatOpts[] = $value;
1162 }
1163 }
1164
1165 return $flatOpts;
1166 }
1167
1181 protected static function formatErrors( $errors ) {
1182 if ( is_array( $errors ) && count( $errors ) === 1 ) {
1183 $errors = array_shift( $errors );
1184 }
1185
1186 if ( is_array( $errors ) ) {
1187 $lines = [];
1188 foreach ( $errors as $error ) {
1189 if ( $error instanceof Message ) {
1190 $lines[] = Html::rawElement( 'li', [], $error->parse() );
1191 } else {
1192 $lines[] = Html::rawElement( 'li', [], $error );
1193 }
1194 }
1195
1196 $errors = Html::rawElement( 'ul', [], implode( "\n", $lines ) );
1197 } else {
1198 if ( $errors instanceof Message ) {
1199 $errors = $errors->parse();
1200 }
1201 }
1202
1203 return Html::rawElement( 'div', [ 'class' => 'errorbox' ], $errors );
1204 }
1205
1212 protected function getMessage( $value ) {
1213 $message = Message::newFromSpecifier( $value );
1214
1215 if ( $this->mParent ) {
1216 $message->setContext( $this->mParent );
1217 }
1218
1219 return $message;
1220 }
1221
1229 public function skipLoadData( $request ) {
1230 return !empty( $this->mParams['nodata'] );
1231 }
1232
1241 if ( $this->mHideIf ) {
1242 // This is probably more restrictive than it needs to be, but better safe than sorry
1243 return true;
1244 }
1245 return false;
1246 }
1247}
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
The parent class to generate form fields.
getHelpTextHtmlDiv( $helptext)
Generate help text HTML in div format.
needsJSForHtml5FormValidation()
Whether this field requires the user agent to have JavaScript enabled for the client-side HTML5 form ...
HTMLForm null $mParent
getLabelAlignOOUI()
Get label alignment when generating field for OOUI.
getInputOOUI( $value)
Same as getInputHTML, but returns an OOUI object.
getHelpTextHtmlRaw( $helptext)
Generate help text HTML formatted for raw output.
isHelpInline()
Determine if the help text should be displayed inline.
getFieldLayoutOOUI( $inputField, $config)
Get a FieldLayout (or subclass thereof) to wrap this field in when using OOUI output.
isHidden( $alldata)
Test whether this field is supposed to be hidden, based on the values of the other form fields.
filter( $value, $alldata)
isHiddenRecurse(array $alldata, array $params)
Helper function for isHidden to handle recursive data structures.
bool $mShowEmptyLabels
If true will generate an empty div element with no label.
shouldInfuseOOUI()
Whether the field should be automatically infused.
__construct( $params)
Initialise the object.
getMessage( $value)
Turns a *-message parameter (which could be a MessageSpecifier, or a message name,...
getClassName()
Gets the non namespaced class name.
getOOUIModules()
Get the list of extra ResourceLoader modules which must be loaded client-side before it's possible to...
skipLoadData( $request)
Skip this field when collecting data.
getVForm( $value)
Get the complete field for the input, including help text, labels, and whatever.
getInputHTML( $value)
This function must be implemented to return the HTML to generate the input object itself.
getErrorsAndErrorClass( $value)
Determine form errors to display and their classes.
validate( $value, $alldata)
Override this function to add specific validation checks on the field input.
getOOUI( $value)
Get the OOUI version of the div.
canDisplayErrors()
True if this field type is able to display errors; false if validation errors need to be displayed in...
getHelpTextHtmlTable( $helptext)
Generate help text HTML in table format.
array array[] $mParams
static flattenOptions( $options)
flatten an array of options to a single array, for instance, a set of "<options>" inside "<optgroups>...
getRaw( $value)
Get the complete raw fields for the input, including help text, labels, and whatever.
getTooltipAndAccessKeyOOUI()
Returns the attributes required for the tooltip and accesskey, for OOUI widgets' config.
getErrorsRaw( $value)
Determine form errors to display, returning them in an array.
getHelpText()
Determine the help text to display.
getOptions()
Fetch the array of options from the field's parameters.
getTableRow( $value)
Get the complete table row for the input, including help text, labels, and whatever.
getInline( $value)
Get the complete field as an inline element.
isSubmitAttempt(WebRequest $request)
Can we assume that the request is an attempt to submit a HTMLForm, as opposed to an attempt to just v...
array bool null $mOptions
msg( $key,... $params)
Get a translated interface message.
lookupOptionsKeys( $options, $needsParse)
Given an array of msg-key => value mappings, returns an array with keys being the message texts.
getLabelHtml( $cellAttributes=[])
loadDataFromRequest( $request)
Get the value that this input has been set to from a posted form, or the input's default value if it ...
getAttributes(array $list)
Returns the given attributes from the parameters.
getNearestFieldByName( $alldata, $name)
Fetch a field value from $alldata for the closest field matching a given name.
setShowEmptyLabel( $show)
Tell the field whether to generate a separate label element if its label is blank.
needsLabel()
Should this field have a label, or is there no input element with the appropriate id for the label to...
getDiv( $value)
Get the complete div for the input, including help text, labels, and whatever.
cancelSubmit( $value, $alldata)
Override this function if the control can somehow trigger a form submission that shouldn't actually s...
getOptionsOOUI()
Get options and make them into arrays suitable for OOUI.
hasVisibleOutput()
If this field has a user-visible output or not.
getTooltipAndAccessKey()
Returns the attributes required for the tooltip and accesskey, for Html::element() etc.
static formatErrors( $errors)
Formats one or more errors as accepted by field validation-callback.
static forceToStringRecursive( $array)
Recursively forces values in an array to strings, because issues arise with integer 0 as a value.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:143
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:2276
static accesskey( $name)
Given the id of an interface element, constructs the appropriate accesskey attribute from the system ...
Definition Linker.php:2324
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Definition Linker.php:2455
MediaWiki exception.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:138
static newFromSpecifier( $value)
Transform a MessageSpecifier or a primitive value used interchangeably with specifiers (a message key...
Definition Message.php:414
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
getCheck( $name)
Return true if the named value is set in the input, whatever that value is (even "0").
$help
Definition mcc.php:32
if(!file_exists( $CREDITS)) $lines