MediaWiki REL1_30
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 = static::class;
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 = static::class;
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 = static::class;
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 ) {
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
657 protected function getLabelAlignOOUI() {
658 return 'top';
659 }
660
667 protected function getFieldLayoutOOUI( $inputField, $config ) {
668 if ( isset( $this->mClassWithButton ) ) {
669 $buttonWidget = $this->mClassWithButton->getInputOOUI( '' );
670 return new HTMLFormActionFieldLayout( $inputField, $buttonWidget, $config );
671 }
672 return new HTMLFormFieldLayout( $inputField, $config );
673 }
674
682 protected function shouldInfuseOOUI() {
683 // Always infuse fields with help text, since the interface for it is nicer with JS
684 return $this->getHelpText() !== null;
685 }
686
693 protected function getOOUIModules() {
694 return [];
695 }
696
706 public function getRaw( $value ) {
707 list( $errors, ) = $this->getErrorsAndErrorClass( $value );
708 $inputHtml = $this->getInputHTML( $value );
709 $helptext = $this->getHelpTextHtmlRaw( $this->getHelpText() );
710 $cellAttributes = [];
711 $label = $this->getLabelHtml( $cellAttributes );
712
713 $html = "\n$errors";
714 $html .= $label;
715 $html .= $inputHtml;
716 $html .= $helptext;
717
718 return $html;
719 }
720
729 public function getVForm( $value ) {
730 // Ewwww
731 $this->mVFormClass = ' mw-ui-vform-field';
732 return $this->getDiv( $value );
733 }
734
741 public function getInline( $value ) {
742 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
743 $inputHtml = $this->getInputHTML( $value );
744 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
745 $cellAttributes = [];
746 $label = $this->getLabelHtml( $cellAttributes );
747
748 $html = "\n" . $errors .
749 $label . '&#160;' .
750 $inputHtml .
751 $helptext;
752
753 return $html;
754 }
755
763 public function getHelpTextHtmlTable( $helptext ) {
764 if ( is_null( $helptext ) ) {
765 return '';
766 }
767
768 $rowAttributes = [];
769 if ( $this->mHideIf ) {
770 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
771 $rowAttributes['class'] = 'mw-htmlform-hide-if';
772 }
773
774 $tdClasses = [ 'htmlform-tip' ];
775 if ( $this->mHelpClass !== false ) {
776 $tdClasses[] = $this->mHelpClass;
777 }
778 $row = Html::rawElement( 'td', [ 'colspan' => 2, 'class' => $tdClasses ], $helptext );
779 $row = Html::rawElement( 'tr', $rowAttributes, $row );
780
781 return $row;
782 }
783
792 public function getHelpTextHtmlDiv( $helptext ) {
793 if ( is_null( $helptext ) ) {
794 return '';
795 }
796
797 $wrapperAttributes = [
798 'class' => 'htmlform-tip',
799 ];
800 if ( $this->mHelpClass !== false ) {
801 $wrapperAttributes['class'] .= " {$this->mHelpClass}";
802 }
803 if ( $this->mHideIf ) {
804 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
805 $wrapperAttributes['class'] .= ' mw-htmlform-hide-if';
806 }
807 $div = Html::rawElement( 'div', $wrapperAttributes, $helptext );
808
809 return $div;
810 }
811
819 public function getHelpTextHtmlRaw( $helptext ) {
820 return $this->getHelpTextHtmlDiv( $helptext );
821 }
822
828 public function getHelpText() {
829 $helptext = null;
830
831 if ( isset( $this->mParams['help-message'] ) ) {
832 $this->mParams['help-messages'] = [ $this->mParams['help-message'] ];
833 }
834
835 if ( isset( $this->mParams['help-messages'] ) ) {
836 foreach ( $this->mParams['help-messages'] as $msg ) {
837 $msg = $this->getMessage( $msg );
838
839 if ( $msg->exists() ) {
840 if ( is_null( $helptext ) ) {
841 $helptext = '';
842 } else {
843 $helptext .= $this->msg( 'word-separator' )->escaped(); // some space
844 }
845 $helptext .= $msg->parse(); // Append message
846 }
847 }
848 } elseif ( isset( $this->mParams['help'] ) ) {
849 $helptext = $this->mParams['help'];
850 }
851
852 return $helptext;
853 }
854
862 public function getErrorsAndErrorClass( $value ) {
863 $errors = $this->validate( $value, $this->mParent->mFieldData );
864
865 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
866 $errors = '';
867 $errorClass = '';
868 } else {
869 $errors = self::formatErrors( $errors );
870 $errorClass = 'mw-htmlform-invalid-input';
871 }
872
873 return [ $errors, $errorClass ];
874 }
875
883 public function getErrorsRaw( $value ) {
884 $errors = $this->validate( $value, $this->mParent->mFieldData );
885
886 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
887 $errors = [];
888 }
889
890 if ( !is_array( $errors ) ) {
891 $errors = [ $errors ];
892 }
893 foreach ( $errors as &$error ) {
894 if ( $error instanceof Message ) {
895 $error = $error->parse();
896 }
897 }
898
899 return $errors;
900 }
901
908 public function getNotices() {
909 $notices = [];
910
911 if ( isset( $this->mParams['notice-message'] ) ) {
912 $notices[] = $this->getMessage( $this->mParams['notice-message'] )->parse();
913 }
914
915 if ( isset( $this->mParams['notice-messages'] ) ) {
916 foreach ( $this->mParams['notice-messages'] as $msg ) {
917 $notices[] = $this->getMessage( $msg )->parse();
918 }
919 } elseif ( isset( $this->mParams['notice'] ) ) {
920 $notices[] = $this->mParams['notice'];
921 }
922
923 return $notices;
924 }
925
929 public function getLabel() {
930 return is_null( $this->mLabel ) ? '' : $this->mLabel;
931 }
932
933 public function getLabelHtml( $cellAttributes = [] ) {
934 # Don't output a for= attribute for labels with no associated input.
935 # Kind of hacky here, possibly we don't want these to be <label>s at all.
936 $for = [];
937
938 if ( $this->needsLabel() ) {
939 $for['for'] = $this->mID;
940 }
941
942 $labelValue = trim( $this->getLabel() );
943 $hasLabel = false;
944 if ( $labelValue !== '&#160;' && $labelValue !== '' ) {
945 $hasLabel = true;
946 }
947
948 $displayFormat = $this->mParent->getDisplayFormat();
949 $html = '';
950 $horizontalLabel = isset( $this->mParams['horizontal-label'] )
951 ? $this->mParams['horizontal-label'] : false;
952
953 if ( $displayFormat === 'table' ) {
954 $html =
955 Html::rawElement( 'td',
956 [ 'class' => 'mw-label' ] + $cellAttributes,
957 Html::rawElement( 'label', $for, $labelValue ) );
958 } elseif ( $hasLabel || $this->mShowEmptyLabels ) {
959 if ( $displayFormat === 'div' && !$horizontalLabel ) {
960 $html =
961 Html::rawElement( 'div',
962 [ 'class' => 'mw-label' ] + $cellAttributes,
963 Html::rawElement( 'label', $for, $labelValue ) );
964 } else {
965 $html = Html::rawElement( 'label', $for, $labelValue );
966 }
967 }
968
969 return $html;
970 }
971
972 public function getDefault() {
973 if ( isset( $this->mDefault ) ) {
974 return $this->mDefault;
975 } else {
976 return null;
977 }
978 }
979
985 public function getTooltipAndAccessKey() {
986 if ( empty( $this->mParams['tooltip'] ) ) {
987 return [];
988 }
989
990 return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] );
991 }
992
998 public function getTooltipAndAccessKeyOOUI() {
999 if ( empty( $this->mParams['tooltip'] ) ) {
1000 return [];
1001 }
1002
1003 return [
1004 'title' => Linker::titleAttrib( $this->mParams['tooltip'] ),
1005 'accessKey' => Linker::accesskey( $this->mParams['tooltip'] ),
1006 ];
1007 }
1008
1015 public function getAttributes( array $list ) {
1016 static $boolAttribs = [ 'disabled', 'required', 'autofocus', 'multiple', 'readonly' ];
1017
1018 $ret = [];
1019 foreach ( $list as $key ) {
1020 if ( in_array( $key, $boolAttribs ) ) {
1021 if ( !empty( $this->mParams[$key] ) ) {
1022 $ret[$key] = '';
1023 }
1024 } elseif ( isset( $this->mParams[$key] ) ) {
1025 $ret[$key] = $this->mParams[$key];
1026 }
1027 }
1028
1029 return $ret;
1030 }
1031
1039 private function lookupOptionsKeys( $options ) {
1040 $ret = [];
1041 foreach ( $options as $key => $value ) {
1042 $key = $this->msg( $key )->plain();
1043 $ret[$key] = is_array( $value )
1044 ? $this->lookupOptionsKeys( $value )
1045 : strval( $value );
1046 }
1047 return $ret;
1048 }
1049
1057 public static function forceToStringRecursive( $array ) {
1058 if ( is_array( $array ) ) {
1059 return array_map( [ __CLASS__, 'forceToStringRecursive' ], $array );
1060 } else {
1061 return strval( $array );
1062 }
1063 }
1064
1071 public function getOptions() {
1072 if ( $this->mOptions === false ) {
1073 if ( array_key_exists( 'options-messages', $this->mParams ) ) {
1074 $this->mOptions = $this->lookupOptionsKeys( $this->mParams['options-messages'] );
1075 } elseif ( array_key_exists( 'options', $this->mParams ) ) {
1076 $this->mOptionsLabelsNotFromMessage = true;
1077 $this->mOptions = self::forceToStringRecursive( $this->mParams['options'] );
1078 } elseif ( array_key_exists( 'options-message', $this->mParams ) ) {
1079 $message = $this->getMessage( $this->mParams['options-message'] )->inContentLanguage()->plain();
1080 $this->mOptions = Xml::listDropDownOptions( $message );
1081 } else {
1082 $this->mOptions = null;
1083 }
1084 }
1085
1086 return $this->mOptions;
1087 }
1088
1093 public function getOptionsOOUI() {
1094 $oldoptions = $this->getOptions();
1095
1096 if ( $oldoptions === null ) {
1097 return null;
1098 }
1099
1100 return Xml::listDropDownOptionsOoui( $oldoptions );
1101 }
1102
1110 public static function flattenOptions( $options ) {
1111 $flatOpts = [];
1112
1113 foreach ( $options as $value ) {
1114 if ( is_array( $value ) ) {
1115 $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) );
1116 } else {
1117 $flatOpts[] = $value;
1118 }
1119 }
1120
1121 return $flatOpts;
1122 }
1123
1131 protected static function formatErrors( $errors ) {
1132 // Note: If you change the logic in this method, change
1133 // htmlform.Checker.js to match.
1134
1135 if ( is_array( $errors ) && count( $errors ) === 1 ) {
1136 $errors = array_shift( $errors );
1137 }
1138
1139 if ( is_array( $errors ) ) {
1140 $lines = [];
1141 foreach ( $errors as $error ) {
1142 if ( $error instanceof Message ) {
1143 $lines[] = Html::rawElement( 'li', [], $error->parse() );
1144 } else {
1145 $lines[] = Html::rawElement( 'li', [], $error );
1146 }
1147 }
1148
1149 return Html::rawElement( 'ul', [ 'class' => 'error' ], implode( "\n", $lines ) );
1150 } else {
1151 if ( $errors instanceof Message ) {
1152 $errors = $errors->parse();
1153 }
1154
1155 return Html::rawElement( 'span', [ 'class' => 'error' ], $errors );
1156 }
1157 }
1158
1165 protected function getMessage( $value ) {
1166 $message = Message::newFromSpecifier( $value );
1167
1168 if ( $this->mParent ) {
1169 $message->setContext( $this->mParent );
1170 }
1171
1172 return $message;
1173 }
1174
1181 public function skipLoadData( $request ) {
1182 return !empty( $this->mParams['nodata'] );
1183 }
1184
1193 if ( $this->mHideIf ) {
1194 // This is probably more restrictive than it needs to be, but better safe than sorry
1195 return true;
1196 }
1197 return false;
1198 }
1199}
if( $line===false) $args
Definition cdb.php:63
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,...
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:128
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:1951
static accesskey( $name)
Given the id of an interface element, constructs the appropriate accesskey attribute from the system ...
Definition Linker.php:1994
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[])
Returns the attributes for the tooltip and access key.
Definition Linker.php:2111
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:2775
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:1971
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:1975
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:1983
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