MediaWiki REL1_35
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
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-field-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
1075 private function lookupOptionsKeys( $options ) {
1076 $ret = [];
1077 foreach ( $options as $key => $value ) {
1078 $key = $this->msg( $key )->plain();
1079 $ret[$key] = is_array( $value )
1080 ? $this->lookupOptionsKeys( $value )
1081 : strval( $value );
1082 }
1083 return $ret;
1084 }
1085
1093 public static function forceToStringRecursive( $array ) {
1094 if ( is_array( $array ) ) {
1095 return array_map( [ __CLASS__, 'forceToStringRecursive' ], $array );
1096 } else {
1097 return strval( $array );
1098 }
1099 }
1100
1107 public function getOptions() {
1108 if ( $this->mOptions === false ) {
1109 if ( array_key_exists( 'options-messages', $this->mParams ) ) {
1110 $this->mOptions = $this->lookupOptionsKeys( $this->mParams['options-messages'] );
1111 } elseif ( array_key_exists( 'options', $this->mParams ) ) {
1112 $this->mOptionsLabelsNotFromMessage = true;
1113 $this->mOptions = self::forceToStringRecursive( $this->mParams['options'] );
1114 } elseif ( array_key_exists( 'options-message', $this->mParams ) ) {
1115 $message = $this->getMessage( $this->mParams['options-message'] )->inContentLanguage()->plain();
1116 $this->mOptions = Xml::listDropDownOptions( $message );
1117 } else {
1118 $this->mOptions = null;
1119 }
1120 }
1121
1122 return $this->mOptions;
1123 }
1124
1130 public function getOptionsOOUI() {
1131 $oldoptions = $this->getOptions();
1132
1133 if ( $oldoptions === null ) {
1134 return null;
1135 }
1136
1137 return Xml::listDropDownOptionsOoui( $oldoptions );
1138 }
1139
1147 public static function flattenOptions( $options ) {
1148 $flatOpts = [];
1149
1150 foreach ( $options as $value ) {
1151 if ( is_array( $value ) ) {
1152 $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) );
1153 } else {
1154 $flatOpts[] = $value;
1155 }
1156 }
1157
1158 return $flatOpts;
1159 }
1160
1174 protected static function formatErrors( $errors ) {
1175 // Note: If you change the logic in this method, change
1176 // htmlform.Checker.js to match.
1177
1178 if ( is_array( $errors ) && count( $errors ) === 1 ) {
1179 $errors = array_shift( $errors );
1180 }
1181
1182 if ( is_array( $errors ) ) {
1183 $lines = [];
1184 foreach ( $errors as $error ) {
1185 if ( $error instanceof Message ) {
1186 $lines[] = Html::rawElement( 'li', [], $error->parse() );
1187 } else {
1188 $lines[] = Html::rawElement( 'li', [], $error );
1189 }
1190 }
1191
1192 $errors = Html::rawElement( 'ul', [], implode( "\n", $lines ) );
1193 } else {
1194 if ( $errors instanceof Message ) {
1195 $errors = $errors->parse();
1196 }
1197 }
1198
1199 return Html::rawElement( 'div', [ 'class' => 'errorbox' ], $errors );
1200 }
1201
1208 protected function getMessage( $value ) {
1209 $message = Message::newFromSpecifier( $value );
1210
1211 if ( $this->mParent ) {
1212 $message->setContext( $this->mParent );
1213 }
1214
1215 return $message;
1216 }
1217
1225 public function skipLoadData( $request ) {
1226 return !empty( $this->mParams['nodata'] );
1227 }
1228
1237 if ( $this->mHideIf ) {
1238 // This is probably more restrictive than it needs to be, but better safe than sorry
1239 return true;
1240 }
1241 return false;
1242 }
1243}
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)
Stable to override.
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...
getLabel()
Stable to override.
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.
lookupOptionsKeys( $options)
Given an array of msg-key => value mappings, returns an array with keys being the message texts.
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 Stable to override.
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.
getLabelHtml( $cellAttributes=[])
Stable to override.
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 Stable to override.
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.
getDefault()
Stable to override.
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:135
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:2120
static accesskey( $name)
Given the id of an interface element, constructs the appropriate accesskey attribute from the system ...
Definition Linker.php:2168
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Definition Linker.php:2304
MediaWiki exception.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:161
static newFromSpecifier( $value)
Transform a MessageSpecifier or a primitive value used interchangeably with specifiers (a message key...
Definition Message.php:452
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