MediaWiki REL1_32
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;
23 protected $mOptions = false;
25 protected $mHideIf = null;
26
31 protected $mShowEmptyLabels = true;
32
36 public $mParent;
37
48 abstract public function getInputHTML( $value );
49
57 public function getInputOOUI( $value ) {
58 return false;
59 }
60
66 public function canDisplayErrors() {
67 return $this->hasVisibleOutput();
68 }
69
80 public function msg() {
81 $args = func_get_args();
82
83 if ( $this->mParent ) {
84 return $this->mParent->msg( ...$args );
85 }
86 return wfMessage( ...$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 ( $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 = ( $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;' || $params['label'] === "\u{00A0}" ) {
401 // Apparently some things set &nbsp directly and in an odd format
402 $this->mLabel = "\u{00A0}";
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 if ( isset( $this->mParams['notice-message'] ) ) {
467 wfDeprecated( "'notice-message' parameter in HTMLForm", '1.32' );
468 }
469 if ( isset( $this->mParams['notice-messages'] ) ) {
470 wfDeprecated( "'notice-messages' parameter in HTMLForm", '1.32' );
471 }
472 if ( isset( $this->mParams['notice'] ) ) {
473 wfDeprecated( "'notice' parameter in HTMLForm", '1.32' );
474 }
475 }
476
485 public function getTableRow( $value ) {
486 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
487 $inputHtml = $this->getInputHTML( $value );
488 $fieldType = static::class;
489 $helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
490 $cellAttributes = [];
491 $rowAttributes = [];
492 $rowClasses = '';
493
494 if ( !empty( $this->mParams['vertical-label'] ) ) {
495 $cellAttributes['colspan'] = 2;
496 $verticalLabel = true;
497 } else {
498 $verticalLabel = false;
499 }
500
501 $label = $this->getLabelHtml( $cellAttributes );
502
503 $field = Html::rawElement(
504 'td',
505 [ 'class' => 'mw-input' ] + $cellAttributes,
506 $inputHtml . "\n$errors"
507 );
508
509 if ( $this->mHideIf ) {
510 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
511 $rowClasses .= ' mw-htmlform-hide-if';
512 }
513
514 if ( $verticalLabel ) {
515 $html = Html::rawElement( 'tr',
516 $rowAttributes + [ 'class' => "mw-htmlform-vertical-label $rowClasses" ], $label );
517 $html .= Html::rawElement( 'tr',
518 $rowAttributes + [
519 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
520 ],
521 $field );
522 } else {
523 $html =
524 Html::rawElement( 'tr',
525 $rowAttributes + [
526 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
527 ],
528 $label . $field );
529 }
530
531 return $html . $helptext;
532 }
533
543 public function getDiv( $value ) {
544 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
545 $inputHtml = $this->getInputHTML( $value );
546 $fieldType = static::class;
547 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
548 $cellAttributes = [];
549 $label = $this->getLabelHtml( $cellAttributes );
550
551 $outerDivClass = [
552 'mw-input',
553 'mw-htmlform-nolabel' => ( $label === '' )
554 ];
555
556 $horizontalLabel = $this->mParams['horizontal-label'] ?? false;
557
558 if ( $horizontalLabel ) {
559 $field = "\u{00A0}" . $inputHtml . "\n$errors";
560 } else {
561 $field = Html::rawElement(
562 'div',
563 [ 'class' => $outerDivClass ] + $cellAttributes,
564 $inputHtml . "\n$errors"
565 );
566 }
567 $divCssClasses = [ "mw-htmlform-field-$fieldType",
568 $this->mClass, $this->mVFormClass, $errorClass ];
569
570 $wrapperAttributes = [
571 'class' => $divCssClasses,
572 ];
573 if ( $this->mHideIf ) {
574 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
575 $wrapperAttributes['class'][] = ' mw-htmlform-hide-if';
576 }
577 $html = Html::rawElement( 'div', $wrapperAttributes, $label . $field );
578 $html .= $helptext;
579
580 return $html;
581 }
582
591 public function getOOUI( $value ) {
592 $inputField = $this->getInputOOUI( $value );
593
594 if ( !$inputField ) {
595 // This field doesn't have an OOUI implementation yet at all. Fall back to getDiv() to
596 // generate the whole field, label and errors and all, then wrap it in a Widget.
597 // It might look weird, but it'll work OK.
598 return $this->getFieldLayoutOOUI(
599 new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $this->getDiv( $value ) ) ] ),
600 [ 'infusable' => false, 'align' => 'top' ]
601 );
602 }
603
604 $infusable = true;
605 if ( is_string( $inputField ) ) {
606 // We have an OOUI implementation, but it's not proper, and we got a load of HTML.
607 // Cheat a little and wrap it in a widget. It won't be infusable, though, since client-side
608 // JavaScript doesn't know how to rebuilt the contents.
609 $inputField = new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $inputField ) ] );
610 $infusable = false;
611 }
612
613 $fieldType = static::class;
614 $help = $this->getHelpText();
615 $errors = $this->getErrorsRaw( $value );
616 foreach ( $errors as &$error ) {
617 $error = new OOUI\HtmlSnippet( $error );
618 }
619
620 $notices = $this->getNotices( 'skip deprecation' );
621 foreach ( $notices as &$notice ) {
622 $notice = new OOUI\HtmlSnippet( $notice );
623 }
624
625 $config = [
626 'classes' => [ "mw-htmlform-field-$fieldType", $this->mClass ],
627 'align' => $this->getLabelAlignOOUI(),
628 'help' => ( $help !== null && $help !== '' ) ? new OOUI\HtmlSnippet( $help ) : null,
629 'errors' => $errors,
630 'notices' => $notices,
631 'infusable' => $infusable,
632 'helpInline' => $this->isHelpInline(),
633 ];
634
635 $preloadModules = false;
636
637 if ( $infusable && $this->shouldInfuseOOUI() ) {
638 $preloadModules = true;
639 $config['classes'][] = 'mw-htmlform-field-autoinfuse';
640 }
641
642 // the element could specify, that the label doesn't need to be added
643 $label = $this->getLabel();
644 if ( $label && $label !== "\u{00A0}" && $label !== '&#160;' ) {
645 $config['label'] = new OOUI\HtmlSnippet( $label );
646 }
647
648 if ( $this->mHideIf ) {
649 $preloadModules = true;
650 $config['hideIf'] = $this->mHideIf;
651 }
652
653 $config['modules'] = $this->getOOUIModules();
654
655 if ( $preloadModules ) {
656 $this->mParent->getOutput()->addModules( 'mediawiki.htmlform.ooui' );
657 $this->mParent->getOutput()->addModules( $this->getOOUIModules() );
658 }
659
660 return $this->getFieldLayoutOOUI( $inputField, $config );
661 }
662
667 protected function getLabelAlignOOUI() {
668 return 'top';
669 }
670
677 protected function getFieldLayoutOOUI( $inputField, $config ) {
678 if ( isset( $this->mClassWithButton ) ) {
679 $buttonWidget = $this->mClassWithButton->getInputOOUI( '' );
680 return new HTMLFormActionFieldLayout( $inputField, $buttonWidget, $config );
681 }
682 return new HTMLFormFieldLayout( $inputField, $config );
683 }
684
692 protected function shouldInfuseOOUI() {
693 // Always infuse fields with popup help text, since the interface for it is nicer with JS
694 return $this->getHelpText() !== null && !$this->isHelpInline();
695 }
696
703 protected function getOOUIModules() {
704 return [];
705 }
706
716 public function getRaw( $value ) {
717 list( $errors, ) = $this->getErrorsAndErrorClass( $value );
718 $inputHtml = $this->getInputHTML( $value );
719 $helptext = $this->getHelpTextHtmlRaw( $this->getHelpText() );
720 $cellAttributes = [];
721 $label = $this->getLabelHtml( $cellAttributes );
722
723 $html = "\n$errors";
724 $html .= $label;
725 $html .= $inputHtml;
726 $html .= $helptext;
727
728 return $html;
729 }
730
739 public function getVForm( $value ) {
740 // Ewwww
741 $this->mVFormClass = ' mw-ui-vform-field';
742 return $this->getDiv( $value );
743 }
744
751 public function getInline( $value ) {
752 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
753 $inputHtml = $this->getInputHTML( $value );
754 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
755 $cellAttributes = [];
756 $label = $this->getLabelHtml( $cellAttributes );
757
758 $html = "\n" . $errors .
759 $label . "\u{00A0}" .
760 $inputHtml .
761 $helptext;
762
763 return $html;
764 }
765
773 public function getHelpTextHtmlTable( $helptext ) {
774 if ( is_null( $helptext ) ) {
775 return '';
776 }
777
778 $rowAttributes = [];
779 if ( $this->mHideIf ) {
780 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
781 $rowAttributes['class'] = 'mw-htmlform-hide-if';
782 }
783
784 $tdClasses = [ 'htmlform-tip' ];
785 if ( $this->mHelpClass !== false ) {
786 $tdClasses[] = $this->mHelpClass;
787 }
788 $row = Html::rawElement( 'td', [ 'colspan' => 2, 'class' => $tdClasses ], $helptext );
789 $row = Html::rawElement( 'tr', $rowAttributes, $row );
790
791 return $row;
792 }
793
802 public function getHelpTextHtmlDiv( $helptext ) {
803 if ( is_null( $helptext ) ) {
804 return '';
805 }
806
807 $wrapperAttributes = [
808 'class' => 'htmlform-tip',
809 ];
810 if ( $this->mHelpClass !== false ) {
811 $wrapperAttributes['class'] .= " {$this->mHelpClass}";
812 }
813 if ( $this->mHideIf ) {
814 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
815 $wrapperAttributes['class'] .= ' mw-htmlform-hide-if';
816 }
817 $div = Html::rawElement( 'div', $wrapperAttributes, $helptext );
818
819 return $div;
820 }
821
829 public function getHelpTextHtmlRaw( $helptext ) {
830 return $this->getHelpTextHtmlDiv( $helptext );
831 }
832
838 public function getHelpText() {
839 $helptext = null;
840
841 if ( isset( $this->mParams['help-message'] ) ) {
842 $this->mParams['help-messages'] = [ $this->mParams['help-message'] ];
843 }
844
845 if ( isset( $this->mParams['help-messages'] ) ) {
846 foreach ( $this->mParams['help-messages'] as $msg ) {
847 $msg = $this->getMessage( $msg );
848
849 if ( $msg->exists() ) {
850 if ( is_null( $helptext ) ) {
851 $helptext = '';
852 } else {
853 $helptext .= $this->msg( 'word-separator' )->escaped(); // some space
854 }
855 $helptext .= $msg->parse(); // Append message
856 }
857 }
858 } elseif ( isset( $this->mParams['help'] ) ) {
859 $helptext = $this->mParams['help'];
860 }
861
862 return $helptext;
863 }
864
873 public function isHelpInline() {
874 return $this->mParams['help-inline'] ?? true;
875 }
876
889 public function getErrorsAndErrorClass( $value ) {
890 $errors = $this->validate( $value, $this->mParent->mFieldData );
891
892 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
893 $errors = '';
894 $errorClass = '';
895 } else {
896 $errors = self::formatErrors( $errors );
897 $errorClass = 'mw-htmlform-invalid-input';
898 }
899
900 return [ $errors, $errorClass ];
901 }
902
910 public function getErrorsRaw( $value ) {
911 $errors = $this->validate( $value, $this->mParent->mFieldData );
912
913 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
914 $errors = [];
915 }
916
917 if ( !is_array( $errors ) ) {
918 $errors = [ $errors ];
919 }
920 foreach ( $errors as &$error ) {
921 if ( $error instanceof Message ) {
922 $error = $error->parse();
923 }
924 }
925
926 return $errors;
927 }
928
938 public function getNotices( $skipDeprecation = null ) {
939 if ( $skipDeprecation !== 'skip deprecation' ) {
940 wfDeprecated( __METHOD__, '1.32' );
941 }
942
943 $notices = [];
944
945 if ( isset( $this->mParams['notice-message'] ) ) {
946 $notices[] = $this->getMessage( $this->mParams['notice-message'] )->parse();
947 }
948
949 if ( isset( $this->mParams['notice-messages'] ) ) {
950 foreach ( $this->mParams['notice-messages'] as $msg ) {
951 $notices[] = $this->getMessage( $msg )->parse();
952 }
953 } elseif ( isset( $this->mParams['notice'] ) ) {
954 $notices[] = $this->mParams['notice'];
955 }
956
957 return $notices;
958 }
959
963 public function getLabel() {
964 return $this->mLabel ?? '';
965 }
966
967 public function getLabelHtml( $cellAttributes = [] ) {
968 # Don't output a for= attribute for labels with no associated input.
969 # Kind of hacky here, possibly we don't want these to be <label>s at all.
970 $for = [];
971
972 if ( $this->needsLabel() ) {
973 $for['for'] = $this->mID;
974 }
975
976 $labelValue = trim( $this->getLabel() );
977 $hasLabel = false;
978 if ( $labelValue !== "\u{00A0}" && $labelValue !== '&#160;' && $labelValue !== '' ) {
979 $hasLabel = true;
980 }
981
982 $displayFormat = $this->mParent->getDisplayFormat();
983 $html = '';
984 $horizontalLabel = $this->mParams['horizontal-label'] ?? false;
985
986 if ( $displayFormat === 'table' ) {
987 $html =
988 Html::rawElement( 'td',
989 [ 'class' => 'mw-label' ] + $cellAttributes,
990 Html::rawElement( 'label', $for, $labelValue ) );
991 } elseif ( $hasLabel || $this->mShowEmptyLabels ) {
992 if ( $displayFormat === 'div' && !$horizontalLabel ) {
993 $html =
994 Html::rawElement( 'div',
995 [ 'class' => 'mw-label' ] + $cellAttributes,
996 Html::rawElement( 'label', $for, $labelValue ) );
997 } else {
998 $html = Html::rawElement( 'label', $for, $labelValue );
999 }
1000 }
1001
1002 return $html;
1003 }
1004
1005 public function getDefault() {
1006 return $this->mDefault ?? null;
1007 }
1008
1014 public function getTooltipAndAccessKey() {
1015 if ( empty( $this->mParams['tooltip'] ) ) {
1016 return [];
1017 }
1018
1019 return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] );
1020 }
1021
1027 public function getTooltipAndAccessKeyOOUI() {
1028 if ( empty( $this->mParams['tooltip'] ) ) {
1029 return [];
1030 }
1031
1032 return [
1033 'title' => Linker::titleAttrib( $this->mParams['tooltip'] ),
1034 'accessKey' => Linker::accesskey( $this->mParams['tooltip'] ),
1035 ];
1036 }
1037
1044 public function getAttributes( array $list ) {
1045 static $boolAttribs = [ 'disabled', 'required', 'autofocus', 'multiple', 'readonly' ];
1046
1047 $ret = [];
1048 foreach ( $list as $key ) {
1049 if ( in_array( $key, $boolAttribs ) ) {
1050 if ( !empty( $this->mParams[$key] ) ) {
1051 $ret[$key] = '';
1052 }
1053 } elseif ( isset( $this->mParams[$key] ) ) {
1054 $ret[$key] = $this->mParams[$key];
1055 }
1056 }
1057
1058 return $ret;
1059 }
1060
1068 private function lookupOptionsKeys( $options ) {
1069 $ret = [];
1070 foreach ( $options as $key => $value ) {
1071 $key = $this->msg( $key )->plain();
1072 $ret[$key] = is_array( $value )
1073 ? $this->lookupOptionsKeys( $value )
1074 : strval( $value );
1075 }
1076 return $ret;
1077 }
1078
1086 public static function forceToStringRecursive( $array ) {
1087 if ( is_array( $array ) ) {
1088 return array_map( [ __CLASS__, 'forceToStringRecursive' ], $array );
1089 } else {
1090 return strval( $array );
1091 }
1092 }
1093
1100 public function getOptions() {
1101 if ( $this->mOptions === false ) {
1102 if ( array_key_exists( 'options-messages', $this->mParams ) ) {
1103 $this->mOptions = $this->lookupOptionsKeys( $this->mParams['options-messages'] );
1104 } elseif ( array_key_exists( 'options', $this->mParams ) ) {
1105 $this->mOptionsLabelsNotFromMessage = true;
1106 $this->mOptions = self::forceToStringRecursive( $this->mParams['options'] );
1107 } elseif ( array_key_exists( 'options-message', $this->mParams ) ) {
1108 $message = $this->getMessage( $this->mParams['options-message'] )->inContentLanguage()->plain();
1109 $this->mOptions = Xml::listDropDownOptions( $message );
1110 } else {
1111 $this->mOptions = null;
1112 }
1113 }
1114
1115 return $this->mOptions;
1116 }
1117
1122 public function getOptionsOOUI() {
1123 $oldoptions = $this->getOptions();
1124
1125 if ( $oldoptions === null ) {
1126 return null;
1127 }
1128
1129 return Xml::listDropDownOptionsOoui( $oldoptions );
1130 }
1131
1139 public static function flattenOptions( $options ) {
1140 $flatOpts = [];
1141
1142 foreach ( $options as $value ) {
1143 if ( is_array( $value ) ) {
1144 $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) );
1145 } else {
1146 $flatOpts[] = $value;
1147 }
1148 }
1149
1150 return $flatOpts;
1151 }
1152
1166 protected static function formatErrors( $errors ) {
1167 // Note: If you change the logic in this method, change
1168 // htmlform.Checker.js to match.
1169
1170 if ( is_array( $errors ) && count( $errors ) === 1 ) {
1171 $errors = array_shift( $errors );
1172 }
1173
1174 if ( is_array( $errors ) ) {
1175 $lines = [];
1176 foreach ( $errors as $error ) {
1177 if ( $error instanceof Message ) {
1178 $lines[] = Html::rawElement( 'li', [], $error->parse() );
1179 } else {
1180 $lines[] = Html::rawElement( 'li', [], $error );
1181 }
1182 }
1183
1184 return Html::rawElement( 'ul', [ 'class' => 'error' ], implode( "\n", $lines ) );
1185 } else {
1186 if ( $errors instanceof Message ) {
1187 $errors = $errors->parse();
1188 }
1189
1190 return Html::rawElement( 'span', [ 'class' => 'error' ], $errors );
1191 }
1192 }
1193
1200 protected function getMessage( $value ) {
1201 $message = Message::newFromSpecifier( $value );
1202
1203 if ( $this->mParent ) {
1204 $message->setContext( $this->mParent );
1205 }
1206
1207 return $message;
1208 }
1209
1216 public function skipLoadData( $request ) {
1217 return !empty( $this->mParams['nodata'] );
1218 }
1219
1228 if ( $this->mHideIf ) {
1229 // This is probably more restrictive than it needs to be, but better safe than sorry
1230 return true;
1231 }
1232 return false;
1233 }
1234}
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
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.
getHelpTextHtmlRaw( $helptext)
Generate help text HTML formatted for raw output.
isHelpInline()
Determine if the help text should be displayed inline.
getFieldLayoutOOUI( $inputField, $config)
Get a FieldLayout (or subclass thereof) to wrap this field in when using OOUI output.
isHidden( $alldata)
Test whether this field is supposed to be hidden, based on the values of the other form fields.
filter( $value, $alldata)
isHiddenRecurse(array $alldata, array $params)
Helper function for isHidden to handle recursive data structures.
bool $mShowEmptyLabels
If true will generate an empty div element with no label.
shouldInfuseOOUI()
Whether the field should be automatically infused.
__construct( $params)
Initialise the object.
getMessage( $value)
Turns a *-message parameter (which could be a MessageSpecifier, or a message name,...
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...
array bool null $mOptions
getNotices( $skipDeprecation=null)
Determine notices to display for the field.
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:136
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:1967
static accesskey( $name)
Given the id of an interface element, constructs the appropriate accesskey attribute from the system ...
Definition Linker.php:2015
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Definition Linker.php:2133
MediaWiki exception.
The Message class provides methods which fulfil two basic services:
Definition Message.php:160
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
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:2880
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:2050
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:2054
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt;div ...>$1&lt;/div>"). - flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException':Called before an exception(or PHP error) is logged. This is meant for integration with external error aggregation services
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:2062
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:302
Using a hook running we can avoid having all this option specific stuff in our mainline code Using the function 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
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
$lines
Definition router.php:61
$params