MediaWiki REL1_31
HTMLFormField.php
Go to the documentation of this file.
1<?php
2
7abstract class HTMLFormField {
8 public $mParams;
9
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;
22 protected $mHideIf = null;
23
28 protected $mShowEmptyLabels = true;
29
33 public $mParent;
34
45 abstract public function getInputHTML( $value );
46
54 public function getInputOOUI( $value ) {
55 return false;
56 }
57
63 public function canDisplayErrors() {
64 return $this->hasVisibleOutput();
65 }
66
77 public 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 public function isHidden( $alldata ) {
270 if ( !$this->mHideIf ) {
271 return false;
272 }
273
274 return $this->isHiddenRecurse( $alldata, $this->mHideIf );
275 }
276
287 public function cancelSubmit( $value, $alldata ) {
288 return false;
289 }
290
302 public 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' );
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 public 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
362 protected function isSubmitAttempt( WebRequest $request ) {
363 return $request->getCheck( 'wpEditToken' ) || $request->getCheck( 'wpFormIdentifier' );
364 }
365
373 public function loadDataFromRequest( $request ) {
374 if ( $request->getCheck( $this->mName ) ) {
375 return $request->getText( $this->mName );
376 } else {
377 return $this->getDefault();
378 }
379 }
380
389 public function __construct( $params ) {
390 $this->mParams = $params;
391
392 if ( isset( $params['parent'] ) && $params['parent'] instanceof HTMLForm ) {
393 $this->mParent = $params['parent'];
394 }
395
396 # Generate the label from a message, if possible
397 if ( isset( $params['label-message'] ) ) {
398 $this->mLabel = $this->getMessage( $params['label-message'] )->parse();
399 } elseif ( isset( $params['label'] ) ) {
400 if ( $params['label'] === '&#160;' ) {
401 // Apparently some things set &nbsp directly and in an odd format
402 $this->mLabel = '&#160;';
403 } else {
404 $this->mLabel = htmlspecialchars( $params['label'] );
405 }
406 } elseif ( isset( $params['label-raw'] ) ) {
407 $this->mLabel = $params['label-raw'];
408 }
409
410 $this->mName = "wp{$params['fieldname']}";
411 if ( isset( $params['name'] ) ) {
412 $this->mName = $params['name'];
413 }
414
415 if ( isset( $params['dir'] ) ) {
416 $this->mDir = $params['dir'];
417 }
418
419 $validName = urlencode( $this->mName );
420 $validName = str_replace( [ '%5B', '%5D' ], [ '[', ']' ], $validName );
421 if ( $this->mName != $validName && !isset( $params['nodata'] ) ) {
422 throw new MWException( "Invalid name '{$this->mName}' passed to " . __METHOD__ );
423 }
424
425 $this->mID = "mw-input-{$this->mName}";
426
427 if ( isset( $params['default'] ) ) {
428 $this->mDefault = $params['default'];
429 }
430
431 if ( isset( $params['id'] ) ) {
432 $id = $params['id'];
433 $validId = urlencode( $id );
434
435 if ( $id != $validId ) {
436 throw new MWException( "Invalid id '$id' passed to " . __METHOD__ );
437 }
438
439 $this->mID = $id;
440 }
441
442 if ( isset( $params['cssclass'] ) ) {
443 $this->mClass = $params['cssclass'];
444 }
445
446 if ( isset( $params['csshelpclass'] ) ) {
447 $this->mHelpClass = $params['csshelpclass'];
448 }
449
450 if ( isset( $params['validation-callback'] ) ) {
451 $this->mValidationCallback = $params['validation-callback'];
452 }
453
454 if ( isset( $params['filter-callback'] ) ) {
455 $this->mFilterCallback = $params['filter-callback'];
456 }
457
458 if ( isset( $params['hidelabel'] ) ) {
459 $this->mShowEmptyLabels = false;
460 }
461
462 if ( isset( $params['hide-if'] ) ) {
463 $this->mHideIf = $params['hide-if'];
464 }
465 }
466
475 public function getTableRow( $value ) {
476 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
477 $inputHtml = $this->getInputHTML( $value );
478 $fieldType = $this->getClassName();
479 $helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
480 $cellAttributes = [];
481 $rowAttributes = [];
482 $rowClasses = '';
483
484 if ( !empty( $this->mParams['vertical-label'] ) ) {
485 $cellAttributes['colspan'] = 2;
486 $verticalLabel = true;
487 } else {
488 $verticalLabel = false;
489 }
490
491 $label = $this->getLabelHtml( $cellAttributes );
492
493 $field = Html::rawElement(
494 'td',
495 [ 'class' => 'mw-input' ] + $cellAttributes,
496 $inputHtml . "\n$errors"
497 );
498
499 if ( $this->mHideIf ) {
500 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
501 $rowClasses .= ' mw-htmlform-hide-if';
502 }
503
504 if ( $verticalLabel ) {
505 $html = Html::rawElement( 'tr',
506 $rowAttributes + [ 'class' => "mw-htmlform-vertical-label $rowClasses" ], $label );
507 $html .= Html::rawElement( 'tr',
508 $rowAttributes + [
509 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
510 ],
511 $field );
512 } else {
513 $html =
514 Html::rawElement( 'tr',
515 $rowAttributes + [
516 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
517 ],
518 $label . $field );
519 }
520
521 return $html . $helptext;
522 }
523
533 public function getDiv( $value ) {
534 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
535 $inputHtml = $this->getInputHTML( $value );
536 $fieldType = $this->getClassName();
537 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
538 $cellAttributes = [];
539 $label = $this->getLabelHtml( $cellAttributes );
540
541 $outerDivClass = [
542 'mw-input',
543 'mw-htmlform-nolabel' => ( $label === '' )
544 ];
545
546 $horizontalLabel = isset( $this->mParams['horizontal-label'] )
547 ? $this->mParams['horizontal-label'] : false;
548
549 if ( $horizontalLabel ) {
550 $field = '&#160;' . $inputHtml . "\n$errors";
551 } else {
552 $field = Html::rawElement(
553 'div',
554 [ 'class' => $outerDivClass ] + $cellAttributes,
555 $inputHtml . "\n$errors"
556 );
557 }
558 $divCssClasses = [ "mw-htmlform-field-$fieldType",
559 $this->mClass, $this->mVFormClass, $errorClass ];
560
561 $wrapperAttributes = [
562 'class' => $divCssClasses,
563 ];
564 if ( $this->mHideIf ) {
565 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
566 $wrapperAttributes['class'][] = ' mw-htmlform-hide-if';
567 }
568 $html = Html::rawElement( 'div', $wrapperAttributes, $label . $field );
569 $html .= $helptext;
570
571 return $html;
572 }
573
582 public function getOOUI( $value ) {
583 $inputField = $this->getInputOOUI( $value );
584
585 if ( !$inputField ) {
586 // This field doesn't have an OOUI implementation yet at all. Fall back to getDiv() to
587 // generate the whole field, label and errors and all, then wrap it in a Widget.
588 // It might look weird, but it'll work OK.
589 return $this->getFieldLayoutOOUI(
590 new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $this->getDiv( $value ) ) ] ),
591 [ 'infusable' => false, 'align' => 'top' ]
592 );
593 }
594
595 $infusable = true;
596 if ( is_string( $inputField ) ) {
597 // We have an OOUI implementation, but it's not proper, and we got a load of HTML.
598 // Cheat a little and wrap it in a widget. It won't be infusable, though, since client-side
599 // JavaScript doesn't know how to rebuilt the contents.
600 $inputField = new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $inputField ) ] );
601 $infusable = false;
602 }
603
604 $fieldType = $this->getClassName();
605 $help = $this->getHelpText();
606 $errors = $this->getErrorsRaw( $value );
607 foreach ( $errors as &$error ) {
608 $error = new OOUI\HtmlSnippet( $error );
609 }
610
611 $notices = $this->getNotices();
612 foreach ( $notices as &$notice ) {
613 $notice = new OOUI\HtmlSnippet( $notice );
614 }
615
616 $config = [
617 'classes' => [ "mw-htmlform-field-$fieldType", $this->mClass ],
618 'align' => $this->getLabelAlignOOUI(),
619 'help' => ( $help !== null && $help !== '' ) ? new OOUI\HtmlSnippet( $help ) : null,
620 'errors' => $errors,
621 'notices' => $notices,
622 'infusable' => $infusable,
623 ];
624
625 $preloadModules = false;
626
627 if ( $infusable && $this->shouldInfuseOOUI() ) {
628 $preloadModules = true;
629 $config['classes'][] = 'mw-htmlform-field-autoinfuse';
630 }
631
632 // the element could specify, that the label doesn't need to be added
633 $label = $this->getLabel();
634 if ( $label && $label !== '&#160;' ) {
635 $config['label'] = new OOUI\HtmlSnippet( $label );
636 }
637
638 if ( $this->mHideIf ) {
639 $preloadModules = true;
640 $config['hideIf'] = $this->mHideIf;
641 }
642
643 $config['modules'] = $this->getOOUIModules();
644
645 if ( $preloadModules ) {
646 $this->mParent->getOutput()->addModules( 'mediawiki.htmlform.ooui' );
647 $this->mParent->getOutput()->addModules( $this->getOOUIModules() );
648 }
649
650 return $this->getFieldLayoutOOUI( $inputField, $config );
651 }
652
660 protected function getClassName() {
661 $name = explode( '\\', static::class );
662 return end( $name );
663 }
664
669 protected function getLabelAlignOOUI() {
670 return 'top';
671 }
672
679 protected function getFieldLayoutOOUI( $inputField, $config ) {
680 if ( isset( $this->mClassWithButton ) ) {
681 $buttonWidget = $this->mClassWithButton->getInputOOUI( '' );
682 return new HTMLFormActionFieldLayout( $inputField, $buttonWidget, $config );
683 }
684 return new HTMLFormFieldLayout( $inputField, $config );
685 }
686
694 protected function shouldInfuseOOUI() {
695 // Always infuse fields with help text, since the interface for it is nicer with JS
696 return $this->getHelpText() !== null;
697 }
698
705 protected function getOOUIModules() {
706 return [];
707 }
708
718 public function getRaw( $value ) {
719 list( $errors, ) = $this->getErrorsAndErrorClass( $value );
720 $inputHtml = $this->getInputHTML( $value );
721 $helptext = $this->getHelpTextHtmlRaw( $this->getHelpText() );
722 $cellAttributes = [];
723 $label = $this->getLabelHtml( $cellAttributes );
724
725 $html = "\n$errors";
726 $html .= $label;
727 $html .= $inputHtml;
728 $html .= $helptext;
729
730 return $html;
731 }
732
741 public function getVForm( $value ) {
742 // Ewwww
743 $this->mVFormClass = ' mw-ui-vform-field';
744 return $this->getDiv( $value );
745 }
746
753 public function getInline( $value ) {
754 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
755 $inputHtml = $this->getInputHTML( $value );
756 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
757 $cellAttributes = [];
758 $label = $this->getLabelHtml( $cellAttributes );
759
760 $html = "\n" . $errors .
761 $label . '&#160;' .
762 $inputHtml .
763 $helptext;
764
765 return $html;
766 }
767
775 public function getHelpTextHtmlTable( $helptext ) {
776 if ( is_null( $helptext ) ) {
777 return '';
778 }
779
780 $rowAttributes = [];
781 if ( $this->mHideIf ) {
782 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
783 $rowAttributes['class'] = 'mw-htmlform-hide-if';
784 }
785
786 $tdClasses = [ 'htmlform-tip' ];
787 if ( $this->mHelpClass !== false ) {
788 $tdClasses[] = $this->mHelpClass;
789 }
790 $row = Html::rawElement( 'td', [ 'colspan' => 2, 'class' => $tdClasses ], $helptext );
791 $row = Html::rawElement( 'tr', $rowAttributes, $row );
792
793 return $row;
794 }
795
804 public function getHelpTextHtmlDiv( $helptext ) {
805 if ( is_null( $helptext ) ) {
806 return '';
807 }
808
809 $wrapperAttributes = [
810 'class' => 'htmlform-tip',
811 ];
812 if ( $this->mHelpClass !== false ) {
813 $wrapperAttributes['class'] .= " {$this->mHelpClass}";
814 }
815 if ( $this->mHideIf ) {
816 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
817 $wrapperAttributes['class'] .= ' mw-htmlform-hide-if';
818 }
819 $div = Html::rawElement( 'div', $wrapperAttributes, $helptext );
820
821 return $div;
822 }
823
831 public function getHelpTextHtmlRaw( $helptext ) {
832 return $this->getHelpTextHtmlDiv( $helptext );
833 }
834
840 public function getHelpText() {
841 $helptext = null;
842
843 if ( isset( $this->mParams['help-message'] ) ) {
844 $this->mParams['help-messages'] = [ $this->mParams['help-message'] ];
845 }
846
847 if ( isset( $this->mParams['help-messages'] ) ) {
848 foreach ( $this->mParams['help-messages'] as $msg ) {
849 $msg = $this->getMessage( $msg );
850
851 if ( $msg->exists() ) {
852 if ( is_null( $helptext ) ) {
853 $helptext = '';
854 } else {
855 $helptext .= $this->msg( 'word-separator' )->escaped(); // some space
856 }
857 $helptext .= $msg->parse(); // Append message
858 }
859 }
860 } elseif ( isset( $this->mParams['help'] ) ) {
861 $helptext = $this->mParams['help'];
862 }
863
864 return $helptext;
865 }
866
874 public function getErrorsAndErrorClass( $value ) {
875 $errors = $this->validate( $value, $this->mParent->mFieldData );
876
877 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
878 $errors = '';
879 $errorClass = '';
880 } else {
881 $errors = self::formatErrors( $errors );
882 $errorClass = 'mw-htmlform-invalid-input';
883 }
884
885 return [ $errors, $errorClass ];
886 }
887
895 public function getErrorsRaw( $value ) {
896 $errors = $this->validate( $value, $this->mParent->mFieldData );
897
898 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
899 $errors = [];
900 }
901
902 if ( !is_array( $errors ) ) {
903 $errors = [ $errors ];
904 }
905 foreach ( $errors as &$error ) {
906 if ( $error instanceof Message ) {
907 $error = $error->parse();
908 }
909 }
910
911 return $errors;
912 }
913
920 public function getNotices() {
921 $notices = [];
922
923 if ( isset( $this->mParams['notice-message'] ) ) {
924 $notices[] = $this->getMessage( $this->mParams['notice-message'] )->parse();
925 }
926
927 if ( isset( $this->mParams['notice-messages'] ) ) {
928 foreach ( $this->mParams['notice-messages'] as $msg ) {
929 $notices[] = $this->getMessage( $msg )->parse();
930 }
931 } elseif ( isset( $this->mParams['notice'] ) ) {
932 $notices[] = $this->mParams['notice'];
933 }
934
935 return $notices;
936 }
937
941 public function getLabel() {
942 return is_null( $this->mLabel ) ? '' : $this->mLabel;
943 }
944
945 public function getLabelHtml( $cellAttributes = [] ) {
946 # Don't output a for= attribute for labels with no associated input.
947 # Kind of hacky here, possibly we don't want these to be <label>s at all.
948 $for = [];
949
950 if ( $this->needsLabel() ) {
951 $for['for'] = $this->mID;
952 }
953
954 $labelValue = trim( $this->getLabel() );
955 $hasLabel = false;
956 if ( $labelValue !== '&#160;' && $labelValue !== '' ) {
957 $hasLabel = true;
958 }
959
960 $displayFormat = $this->mParent->getDisplayFormat();
961 $html = '';
962 $horizontalLabel = isset( $this->mParams['horizontal-label'] )
963 ? $this->mParams['horizontal-label'] : false;
964
965 if ( $displayFormat === 'table' ) {
966 $html =
967 Html::rawElement( 'td',
968 [ 'class' => 'mw-label' ] + $cellAttributes,
969 Html::rawElement( 'label', $for, $labelValue ) );
970 } elseif ( $hasLabel || $this->mShowEmptyLabels ) {
971 if ( $displayFormat === 'div' && !$horizontalLabel ) {
972 $html =
973 Html::rawElement( 'div',
974 [ 'class' => 'mw-label' ] + $cellAttributes,
975 Html::rawElement( 'label', $for, $labelValue ) );
976 } else {
977 $html = Html::rawElement( 'label', $for, $labelValue );
978 }
979 }
980
981 return $html;
982 }
983
984 public function getDefault() {
985 if ( isset( $this->mDefault ) ) {
986 return $this->mDefault;
987 } else {
988 return null;
989 }
990 }
991
997 public function getTooltipAndAccessKey() {
998 if ( empty( $this->mParams['tooltip'] ) ) {
999 return [];
1000 }
1001
1002 return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] );
1003 }
1004
1010 public function getTooltipAndAccessKeyOOUI() {
1011 if ( empty( $this->mParams['tooltip'] ) ) {
1012 return [];
1013 }
1014
1015 return [
1016 'title' => Linker::titleAttrib( $this->mParams['tooltip'] ),
1017 'accessKey' => Linker::accesskey( $this->mParams['tooltip'] ),
1018 ];
1019 }
1020
1027 public function getAttributes( array $list ) {
1028 static $boolAttribs = [ 'disabled', 'required', 'autofocus', 'multiple', 'readonly' ];
1029
1030 $ret = [];
1031 foreach ( $list as $key ) {
1032 if ( in_array( $key, $boolAttribs ) ) {
1033 if ( !empty( $this->mParams[$key] ) ) {
1034 $ret[$key] = '';
1035 }
1036 } elseif ( isset( $this->mParams[$key] ) ) {
1037 $ret[$key] = $this->mParams[$key];
1038 }
1039 }
1040
1041 return $ret;
1042 }
1043
1051 private function lookupOptionsKeys( $options ) {
1052 $ret = [];
1053 foreach ( $options as $key => $value ) {
1054 $key = $this->msg( $key )->plain();
1055 $ret[$key] = is_array( $value )
1056 ? $this->lookupOptionsKeys( $value )
1057 : strval( $value );
1058 }
1059 return $ret;
1060 }
1061
1069 public static function forceToStringRecursive( $array ) {
1070 if ( is_array( $array ) ) {
1071 return array_map( [ __CLASS__, 'forceToStringRecursive' ], $array );
1072 } else {
1073 return strval( $array );
1074 }
1075 }
1076
1083 public function getOptions() {
1084 if ( $this->mOptions === false ) {
1085 if ( array_key_exists( 'options-messages', $this->mParams ) ) {
1086 $this->mOptions = $this->lookupOptionsKeys( $this->mParams['options-messages'] );
1087 } elseif ( array_key_exists( 'options', $this->mParams ) ) {
1088 $this->mOptionsLabelsNotFromMessage = true;
1089 $this->mOptions = self::forceToStringRecursive( $this->mParams['options'] );
1090 } elseif ( array_key_exists( 'options-message', $this->mParams ) ) {
1091 $message = $this->getMessage( $this->mParams['options-message'] )->inContentLanguage()->plain();
1092 $this->mOptions = Xml::listDropDownOptions( $message );
1093 } else {
1094 $this->mOptions = null;
1095 }
1096 }
1097
1098 return $this->mOptions;
1099 }
1100
1105 public function getOptionsOOUI() {
1106 $oldoptions = $this->getOptions();
1107
1108 if ( $oldoptions === null ) {
1109 return null;
1110 }
1111
1112 return Xml::listDropDownOptionsOoui( $oldoptions );
1113 }
1114
1122 public static function flattenOptions( $options ) {
1123 $flatOpts = [];
1124
1125 foreach ( $options as $value ) {
1126 if ( is_array( $value ) ) {
1127 $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) );
1128 } else {
1129 $flatOpts[] = $value;
1130 }
1131 }
1132
1133 return $flatOpts;
1134 }
1135
1143 protected static function formatErrors( $errors ) {
1144 // Note: If you change the logic in this method, change
1145 // htmlform.Checker.js to match.
1146
1147 if ( is_array( $errors ) && count( $errors ) === 1 ) {
1148 $errors = array_shift( $errors );
1149 }
1150
1151 if ( is_array( $errors ) ) {
1152 $lines = [];
1153 foreach ( $errors as $error ) {
1154 if ( $error instanceof Message ) {
1155 $lines[] = Html::rawElement( 'li', [], $error->parse() );
1156 } else {
1157 $lines[] = Html::rawElement( 'li', [], $error );
1158 }
1159 }
1160
1161 return Html::rawElement( 'ul', [ 'class' => 'error' ], implode( "\n", $lines ) );
1162 } else {
1163 if ( $errors instanceof Message ) {
1164 $errors = $errors->parse();
1165 }
1166
1167 return Html::rawElement( 'span', [ 'class' => 'error' ], $errors );
1168 }
1169 }
1170
1177 protected function getMessage( $value ) {
1178 $message = Message::newFromSpecifier( $value );
1179
1180 if ( $this->mParent ) {
1181 $message->setContext( $this->mParent );
1182 }
1183
1184 return $message;
1185 }
1186
1193 public function skipLoadData( $request ) {
1194 return !empty( $this->mParams['nodata'] );
1195 }
1196
1205 if ( $this->mHideIf ) {
1206 // This is probably more restrictive than it needs to be, but better safe than sorry
1207 return true;
1208 }
1209 return false;
1210 }
1211}
if( $line===false) $args
Definition cdb.php:64
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.
getNotices()
Determine notices to display for the field.
getHelpTextHtmlRaw( $helptext)
Generate help text HTML formatted for raw output.
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.
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.
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...
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.
msg()
Get a translated interface message.
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.
Definition HTMLForm.php:130
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:1969
static accesskey( $name)
Given the id of an interface element, constructs the appropriate accesskey attribute from the system ...
Definition Linker.php:2017
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Definition Linker.php:2135
MediaWiki exception.
The Message class provides methods which fulfil two basic services:
Definition Message.php:159
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
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
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
the array() calling protocol came about after MediaWiki 1.4rc1.
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:2806
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:181
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:2001
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:2005
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:2013
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:302
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
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:37
$help
Definition mcc.php:32
$lines
Definition router.php:61
$params