MediaWiki REL1_33
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 foreach ( $keys as $key ) {
141 if ( !is_array( $data ) || !array_key_exists( $key, $data ) ) {
142 continue 2;
143 }
144 $data = $data[$key];
145 }
146 $testValue = (string)$data;
147 break;
148 }
149
150 return $testValue;
151 }
152
161 protected function isHiddenRecurse( array $alldata, array $params ) {
162 $origParams = $params;
163 $op = array_shift( $params );
164
165 try {
166 switch ( $op ) {
167 case 'AND':
168 foreach ( $params as $i => $p ) {
169 if ( !is_array( $p ) ) {
170 throw new MWException(
171 "Expected array, found " . gettype( $p ) . " at index $i"
172 );
173 }
174 if ( !$this->isHiddenRecurse( $alldata, $p ) ) {
175 return false;
176 }
177 }
178 return true;
179
180 case 'OR':
181 foreach ( $params as $i => $p ) {
182 if ( !is_array( $p ) ) {
183 throw new MWException(
184 "Expected array, found " . gettype( $p ) . " at index $i"
185 );
186 }
187 if ( $this->isHiddenRecurse( $alldata, $p ) ) {
188 return true;
189 }
190 }
191 return false;
192
193 case 'NAND':
194 foreach ( $params as $i => $p ) {
195 if ( !is_array( $p ) ) {
196 throw new MWException(
197 "Expected array, found " . gettype( $p ) . " at index $i"
198 );
199 }
200 if ( !$this->isHiddenRecurse( $alldata, $p ) ) {
201 return true;
202 }
203 }
204 return false;
205
206 case 'NOR':
207 foreach ( $params as $i => $p ) {
208 if ( !is_array( $p ) ) {
209 throw new MWException(
210 "Expected array, found " . gettype( $p ) . " at index $i"
211 );
212 }
213 if ( $this->isHiddenRecurse( $alldata, $p ) ) {
214 return false;
215 }
216 }
217 return true;
218
219 case 'NOT':
220 if ( count( $params ) !== 1 ) {
221 throw new MWException( "NOT takes exactly one parameter" );
222 }
223 $p = $params[0];
224 if ( !is_array( $p ) ) {
225 throw new MWException(
226 "Expected array, found " . gettype( $p ) . " at index 0"
227 );
228 }
229 return !$this->isHiddenRecurse( $alldata, $p );
230
231 case '===':
232 case '!==':
233 if ( count( $params ) !== 2 ) {
234 throw new MWException( "$op takes exactly two parameters" );
235 }
236 list( $field, $value ) = $params;
237 if ( !is_string( $field ) || !is_string( $value ) ) {
238 throw new MWException( "Parameters for $op must be strings" );
239 }
240 $testValue = $this->getNearestFieldByName( $alldata, $field );
241 switch ( $op ) {
242 case '===':
243 return ( $value === $testValue );
244 case '!==':
245 return ( $value !== $testValue );
246 }
247
248 default:
249 throw new MWException( "Unknown operation" );
250 }
251 } catch ( Exception $ex ) {
252 throw new MWException(
253 "Invalid hide-if specification for $this->mName: " .
254 $ex->getMessage() . " in " . var_export( $origParams, true ),
255 0, $ex
256 );
257 }
258 }
259
268 public function isHidden( $alldata ) {
269 if ( !$this->mHideIf ) {
270 return false;
271 }
272
273 return $this->isHiddenRecurse( $alldata, $this->mHideIf );
274 }
275
286 public function cancelSubmit( $value, $alldata ) {
287 return false;
288 }
289
301 public function validate( $value, $alldata ) {
302 if ( $this->isHidden( $alldata ) ) {
303 return true;
304 }
305
306 if ( isset( $this->mParams['required'] )
307 && $this->mParams['required'] !== false
308 && $value === ''
309 ) {
310 return $this->msg( 'htmlform-required' );
311 }
312
313 if ( isset( $this->mValidationCallback ) ) {
314 return ( $this->mValidationCallback )( $value, $alldata, $this->mParent );
315 }
316
317 return true;
318 }
319
320 public function filter( $value, $alldata ) {
321 if ( isset( $this->mFilterCallback ) ) {
322 $value = ( $this->mFilterCallback )( $value, $alldata, $this->mParent );
323 }
324
325 return $value;
326 }
327
334 protected function needsLabel() {
335 return true;
336 }
337
347 public function setShowEmptyLabel( $show ) {
348 $this->mShowEmptyLabels = $show;
349 }
350
361 protected function isSubmitAttempt( WebRequest $request ) {
362 return $request->getCheck( 'wpEditToken' ) || $request->getCheck( 'wpFormIdentifier' );
363 }
364
372 public function loadDataFromRequest( $request ) {
373 if ( $request->getCheck( $this->mName ) ) {
374 return $request->getText( $this->mName );
375 } else {
376 return $this->getDefault();
377 }
378 }
379
388 public function __construct( $params ) {
389 $this->mParams = $params;
390
391 if ( isset( $params['parent'] ) && $params['parent'] instanceof HTMLForm ) {
392 $this->mParent = $params['parent'];
393 }
394
395 # Generate the label from a message, if possible
396 if ( isset( $params['label-message'] ) ) {
397 $this->mLabel = $this->getMessage( $params['label-message'] )->parse();
398 } elseif ( isset( $params['label'] ) ) {
399 if ( $params['label'] === '&#160;' || $params['label'] === "\u{00A0}" ) {
400 // Apparently some things set &nbsp directly and in an odd format
401 $this->mLabel = "\u{00A0}";
402 } else {
403 $this->mLabel = htmlspecialchars( $params['label'] );
404 }
405 } elseif ( isset( $params['label-raw'] ) ) {
406 $this->mLabel = $params['label-raw'];
407 }
408
409 $this->mName = "wp{$params['fieldname']}";
410 if ( isset( $params['name'] ) ) {
411 $this->mName = $params['name'];
412 }
413
414 if ( isset( $params['dir'] ) ) {
415 $this->mDir = $params['dir'];
416 }
417
418 $validName = urlencode( $this->mName );
419 $validName = str_replace( [ '%5B', '%5D' ], [ '[', ']' ], $validName );
420 if ( $this->mName != $validName && !isset( $params['nodata'] ) ) {
421 throw new MWException( "Invalid name '{$this->mName}' passed to " . __METHOD__ );
422 }
423
424 $this->mID = "mw-input-{$this->mName}";
425
426 if ( isset( $params['default'] ) ) {
427 $this->mDefault = $params['default'];
428 }
429
430 if ( isset( $params['id'] ) ) {
431 $id = $params['id'];
432 $validId = urlencode( $id );
433
434 if ( $id != $validId ) {
435 throw new MWException( "Invalid id '$id' passed to " . __METHOD__ );
436 }
437
438 $this->mID = $id;
439 }
440
441 if ( isset( $params['cssclass'] ) ) {
442 $this->mClass = $params['cssclass'];
443 }
444
445 if ( isset( $params['csshelpclass'] ) ) {
446 $this->mHelpClass = $params['csshelpclass'];
447 }
448
449 if ( isset( $params['validation-callback'] ) ) {
450 $this->mValidationCallback = $params['validation-callback'];
451 }
452
453 if ( isset( $params['filter-callback'] ) ) {
454 $this->mFilterCallback = $params['filter-callback'];
455 }
456
457 if ( isset( $params['hidelabel'] ) ) {
458 $this->mShowEmptyLabels = false;
459 }
460
461 if ( isset( $params['hide-if'] ) ) {
462 $this->mHideIf = $params['hide-if'];
463 }
464 }
465
474 public function getTableRow( $value ) {
475 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
476 $inputHtml = $this->getInputHTML( $value );
477 $fieldType = static::class;
478 $helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
479 $cellAttributes = [];
480 $rowAttributes = [];
481 $rowClasses = '';
482
483 if ( !empty( $this->mParams['vertical-label'] ) ) {
484 $cellAttributes['colspan'] = 2;
485 $verticalLabel = true;
486 } else {
487 $verticalLabel = false;
488 }
489
490 $label = $this->getLabelHtml( $cellAttributes );
491
492 $field = Html::rawElement(
493 'td',
494 [ 'class' => 'mw-input' ] + $cellAttributes,
495 $inputHtml . "\n$errors"
496 );
497
498 if ( $this->mHideIf ) {
499 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
500 $rowClasses .= ' mw-htmlform-hide-if';
501 }
502
503 if ( $verticalLabel ) {
504 $html = Html::rawElement( 'tr',
505 $rowAttributes + [ 'class' => "mw-htmlform-vertical-label $rowClasses" ], $label );
506 $html .= Html::rawElement( 'tr',
507 $rowAttributes + [
508 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
509 ],
510 $field );
511 } else {
512 $html =
513 Html::rawElement( 'tr',
514 $rowAttributes + [
515 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
516 ],
517 $label . $field );
518 }
519
520 return $html . $helptext;
521 }
522
532 public function getDiv( $value ) {
533 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
534 $inputHtml = $this->getInputHTML( $value );
535 $fieldType = static::class;
536 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
537 $cellAttributes = [];
538 $label = $this->getLabelHtml( $cellAttributes );
539
540 $outerDivClass = [
541 'mw-input',
542 'mw-htmlform-nolabel' => ( $label === '' )
543 ];
544
545 $horizontalLabel = $this->mParams['horizontal-label'] ?? false;
546
547 if ( $horizontalLabel ) {
548 $field = "\u{00A0}" . $inputHtml . "\n$errors";
549 } else {
550 $field = Html::rawElement(
551 'div',
552 [ 'class' => $outerDivClass ] + $cellAttributes,
553 $inputHtml . "\n$errors"
554 );
555 }
556 $divCssClasses = [ "mw-htmlform-field-$fieldType",
557 $this->mClass, $this->mVFormClass, $errorClass ];
558
559 $wrapperAttributes = [
560 'class' => $divCssClasses,
561 ];
562 if ( $this->mHideIf ) {
563 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
564 $wrapperAttributes['class'][] = ' mw-htmlform-hide-if';
565 }
566 $html = Html::rawElement( 'div', $wrapperAttributes, $label . $field );
567 $html .= $helptext;
568
569 return $html;
570 }
571
580 public function getOOUI( $value ) {
581 $inputField = $this->getInputOOUI( $value );
582
583 if ( !$inputField ) {
584 // This field doesn't have an OOUI implementation yet at all. Fall back to getDiv() to
585 // generate the whole field, label and errors and all, then wrap it in a Widget.
586 // It might look weird, but it'll work OK.
587 return $this->getFieldLayoutOOUI(
588 new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $this->getDiv( $value ) ) ] ),
589 [ 'align' => 'top' ]
590 );
591 }
592
593 $infusable = true;
594 if ( is_string( $inputField ) ) {
595 // We have an OOUI implementation, but it's not proper, and we got a load of HTML.
596 // Cheat a little and wrap it in a widget. It won't be infusable, though, since client-side
597 // JavaScript doesn't know how to rebuilt the contents.
598 $inputField = new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $inputField ) ] );
599 $infusable = false;
600 }
601
602 $fieldType = static::class;
603 $help = $this->getHelpText();
604 $errors = $this->getErrorsRaw( $value );
605 foreach ( $errors as &$error ) {
606 $error = new OOUI\HtmlSnippet( $error );
607 }
608
609 $config = [
610 'classes' => [ "mw-htmlform-field-$fieldType", $this->mClass ],
611 'align' => $this->getLabelAlignOOUI(),
612 'help' => ( $help !== null && $help !== '' ) ? new OOUI\HtmlSnippet( $help ) : null,
613 'errors' => $errors,
614 'infusable' => $infusable,
615 'helpInline' => $this->isHelpInline(),
616 ];
617
618 $preloadModules = false;
619
620 if ( $infusable && $this->shouldInfuseOOUI() ) {
621 $preloadModules = true;
622 $config['classes'][] = 'mw-htmlform-field-autoinfuse';
623 }
624
625 // the element could specify, that the label doesn't need to be added
626 $label = $this->getLabel();
627 if ( $label && $label !== "\u{00A0}" && $label !== '&#160;' ) {
628 $config['label'] = new OOUI\HtmlSnippet( $label );
629 }
630
631 if ( $this->mHideIf ) {
632 $preloadModules = true;
633 $config['hideIf'] = $this->mHideIf;
634 }
635
636 $config['modules'] = $this->getOOUIModules();
637
638 if ( $preloadModules ) {
639 $this->mParent->getOutput()->addModules( 'mediawiki.htmlform.ooui' );
640 $this->mParent->getOutput()->addModules( $this->getOOUIModules() );
641 }
642
643 return $this->getFieldLayoutOOUI( $inputField, $config );
644 }
645
650 protected function getLabelAlignOOUI() {
651 return 'top';
652 }
653
660 protected function getFieldLayoutOOUI( $inputField, $config ) {
661 if ( isset( $this->mClassWithButton ) ) {
662 $buttonWidget = $this->mClassWithButton->getInputOOUI( '' );
663 return new HTMLFormActionFieldLayout( $inputField, $buttonWidget, $config );
664 }
665 return new HTMLFormFieldLayout( $inputField, $config );
666 }
667
675 protected function shouldInfuseOOUI() {
676 // Always infuse fields with popup help text, since the interface for it is nicer with JS
677 return $this->getHelpText() !== null && !$this->isHelpInline();
678 }
679
686 protected function getOOUIModules() {
687 return [];
688 }
689
699 public function getRaw( $value ) {
700 list( $errors, ) = $this->getErrorsAndErrorClass( $value );
701 $inputHtml = $this->getInputHTML( $value );
702 $helptext = $this->getHelpTextHtmlRaw( $this->getHelpText() );
703 $cellAttributes = [];
704 $label = $this->getLabelHtml( $cellAttributes );
705
706 $html = "\n$errors";
707 $html .= $label;
708 $html .= $inputHtml;
709 $html .= $helptext;
710
711 return $html;
712 }
713
722 public function getVForm( $value ) {
723 // Ewwww
724 $this->mVFormClass = ' mw-ui-vform-field';
725 return $this->getDiv( $value );
726 }
727
734 public function getInline( $value ) {
735 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
736 $inputHtml = $this->getInputHTML( $value );
737 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
738 $cellAttributes = [];
739 $label = $this->getLabelHtml( $cellAttributes );
740
741 $html = "\n" . $errors .
742 $label . "\u{00A0}" .
743 $inputHtml .
744 $helptext;
745
746 return $html;
747 }
748
756 public function getHelpTextHtmlTable( $helptext ) {
757 if ( is_null( $helptext ) ) {
758 return '';
759 }
760
761 $rowAttributes = [];
762 if ( $this->mHideIf ) {
763 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
764 $rowAttributes['class'] = 'mw-htmlform-hide-if';
765 }
766
767 $tdClasses = [ 'htmlform-tip' ];
768 if ( $this->mHelpClass !== false ) {
769 $tdClasses[] = $this->mHelpClass;
770 }
771 $row = Html::rawElement( 'td', [ 'colspan' => 2, 'class' => $tdClasses ], $helptext );
772 $row = Html::rawElement( 'tr', $rowAttributes, $row );
773
774 return $row;
775 }
776
785 public function getHelpTextHtmlDiv( $helptext ) {
786 if ( is_null( $helptext ) ) {
787 return '';
788 }
789
790 $wrapperAttributes = [
791 'class' => 'htmlform-tip',
792 ];
793 if ( $this->mHelpClass !== false ) {
794 $wrapperAttributes['class'] .= " {$this->mHelpClass}";
795 }
796 if ( $this->mHideIf ) {
797 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
798 $wrapperAttributes['class'] .= ' mw-htmlform-hide-if';
799 }
800 $div = Html::rawElement( 'div', $wrapperAttributes, $helptext );
801
802 return $div;
803 }
804
812 public function getHelpTextHtmlRaw( $helptext ) {
813 return $this->getHelpTextHtmlDiv( $helptext );
814 }
815
821 public function getHelpText() {
822 $helptext = null;
823
824 if ( isset( $this->mParams['help-message'] ) ) {
825 $this->mParams['help-messages'] = [ $this->mParams['help-message'] ];
826 }
827
828 if ( isset( $this->mParams['help-messages'] ) ) {
829 foreach ( $this->mParams['help-messages'] as $msg ) {
830 $msg = $this->getMessage( $msg );
831
832 if ( $msg->exists() ) {
833 if ( is_null( $helptext ) ) {
834 $helptext = '';
835 } else {
836 $helptext .= $this->msg( 'word-separator' )->escaped(); // some space
837 }
838 $helptext .= $msg->parse(); // Append message
839 }
840 }
841 } elseif ( isset( $this->mParams['help'] ) ) {
842 $helptext = $this->mParams['help'];
843 }
844
845 return $helptext;
846 }
847
856 public function isHelpInline() {
857 return $this->mParams['help-inline'] ?? true;
858 }
859
872 public function getErrorsAndErrorClass( $value ) {
873 $errors = $this->validate( $value, $this->mParent->mFieldData );
874
875 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
876 $errors = '';
877 $errorClass = '';
878 } else {
879 $errors = self::formatErrors( $errors );
880 $errorClass = 'mw-htmlform-invalid-input';
881 }
882
883 return [ $errors, $errorClass ];
884 }
885
893 public function getErrorsRaw( $value ) {
894 $errors = $this->validate( $value, $this->mParent->mFieldData );
895
896 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
897 $errors = [];
898 }
899
900 if ( !is_array( $errors ) ) {
901 $errors = [ $errors ];
902 }
903 foreach ( $errors as &$error ) {
904 if ( $error instanceof Message ) {
905 $error = $error->parse();
906 }
907 }
908
909 return $errors;
910 }
911
915 public function getLabel() {
916 return $this->mLabel ?? '';
917 }
918
919 public function getLabelHtml( $cellAttributes = [] ) {
920 # Don't output a for= attribute for labels with no associated input.
921 # Kind of hacky here, possibly we don't want these to be <label>s at all.
922 $for = [];
923
924 if ( $this->needsLabel() ) {
925 $for['for'] = $this->mID;
926 }
927
928 $labelValue = trim( $this->getLabel() );
929 $hasLabel = false;
930 if ( $labelValue !== "\u{00A0}" && $labelValue !== '&#160;' && $labelValue !== '' ) {
931 $hasLabel = true;
932 }
933
934 $displayFormat = $this->mParent->getDisplayFormat();
935 $html = '';
936 $horizontalLabel = $this->mParams['horizontal-label'] ?? false;
937
938 if ( $displayFormat === 'table' ) {
939 $html =
940 Html::rawElement( 'td',
941 [ 'class' => 'mw-label' ] + $cellAttributes,
942 Html::rawElement( 'label', $for, $labelValue ) );
943 } elseif ( $hasLabel || $this->mShowEmptyLabels ) {
944 if ( $displayFormat === 'div' && !$horizontalLabel ) {
945 $html =
946 Html::rawElement( 'div',
947 [ 'class' => 'mw-label' ] + $cellAttributes,
948 Html::rawElement( 'label', $for, $labelValue ) );
949 } else {
950 $html = Html::rawElement( 'label', $for, $labelValue );
951 }
952 }
953
954 return $html;
955 }
956
957 public function getDefault() {
958 return $this->mDefault ?? null;
959 }
960
966 public function getTooltipAndAccessKey() {
967 if ( empty( $this->mParams['tooltip'] ) ) {
968 return [];
969 }
970
971 return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] );
972 }
973
979 public function getTooltipAndAccessKeyOOUI() {
980 if ( empty( $this->mParams['tooltip'] ) ) {
981 return [];
982 }
983
984 return [
985 'title' => Linker::titleAttrib( $this->mParams['tooltip'] ),
986 'accessKey' => Linker::accesskey( $this->mParams['tooltip'] ),
987 ];
988 }
989
996 public function getAttributes( array $list ) {
997 static $boolAttribs = [ 'disabled', 'required', 'autofocus', 'multiple', 'readonly' ];
998
999 $ret = [];
1000 foreach ( $list as $key ) {
1001 if ( in_array( $key, $boolAttribs ) ) {
1002 if ( !empty( $this->mParams[$key] ) ) {
1003 $ret[$key] = '';
1004 }
1005 } elseif ( isset( $this->mParams[$key] ) ) {
1006 $ret[$key] = $this->mParams[$key];
1007 }
1008 }
1009
1010 return $ret;
1011 }
1012
1020 private function lookupOptionsKeys( $options ) {
1021 $ret = [];
1022 foreach ( $options as $key => $value ) {
1023 $key = $this->msg( $key )->plain();
1024 $ret[$key] = is_array( $value )
1025 ? $this->lookupOptionsKeys( $value )
1026 : strval( $value );
1027 }
1028 return $ret;
1029 }
1030
1038 public static function forceToStringRecursive( $array ) {
1039 if ( is_array( $array ) ) {
1040 return array_map( [ __CLASS__, 'forceToStringRecursive' ], $array );
1041 } else {
1042 return strval( $array );
1043 }
1044 }
1045
1052 public function getOptions() {
1053 if ( $this->mOptions === false ) {
1054 if ( array_key_exists( 'options-messages', $this->mParams ) ) {
1055 $this->mOptions = $this->lookupOptionsKeys( $this->mParams['options-messages'] );
1056 } elseif ( array_key_exists( 'options', $this->mParams ) ) {
1057 $this->mOptionsLabelsNotFromMessage = true;
1058 $this->mOptions = self::forceToStringRecursive( $this->mParams['options'] );
1059 } elseif ( array_key_exists( 'options-message', $this->mParams ) ) {
1060 $message = $this->getMessage( $this->mParams['options-message'] )->inContentLanguage()->plain();
1061 $this->mOptions = Xml::listDropDownOptions( $message );
1062 } else {
1063 $this->mOptions = null;
1064 }
1065 }
1066
1067 return $this->mOptions;
1068 }
1069
1074 public function getOptionsOOUI() {
1075 $oldoptions = $this->getOptions();
1076
1077 if ( $oldoptions === null ) {
1078 return null;
1079 }
1080
1081 return Xml::listDropDownOptionsOoui( $oldoptions );
1082 }
1083
1091 public static function flattenOptions( $options ) {
1092 $flatOpts = [];
1093
1094 foreach ( $options as $value ) {
1095 if ( is_array( $value ) ) {
1096 $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) );
1097 } else {
1098 $flatOpts[] = $value;
1099 }
1100 }
1101
1102 return $flatOpts;
1103 }
1104
1118 protected static function formatErrors( $errors ) {
1119 // Note: If you change the logic in this method, change
1120 // htmlform.Checker.js to match.
1121
1122 if ( is_array( $errors ) && count( $errors ) === 1 ) {
1123 $errors = array_shift( $errors );
1124 }
1125
1126 if ( is_array( $errors ) ) {
1127 $lines = [];
1128 foreach ( $errors as $error ) {
1129 if ( $error instanceof Message ) {
1130 $lines[] = Html::rawElement( 'li', [], $error->parse() );
1131 } else {
1132 $lines[] = Html::rawElement( 'li', [], $error );
1133 }
1134 }
1135
1136 return Html::rawElement( 'ul', [ 'class' => 'error' ], implode( "\n", $lines ) );
1137 } else {
1138 if ( $errors instanceof Message ) {
1139 $errors = $errors->parse();
1140 }
1141
1142 return Html::rawElement( 'span', [ 'class' => 'error' ], $errors );
1143 }
1144 }
1145
1152 protected function getMessage( $value ) {
1153 $message = Message::newFromSpecifier( $value );
1154
1155 if ( $this->mParent ) {
1156 $message->setContext( $this->mParent );
1157 }
1158
1159 return $message;
1160 }
1161
1168 public function skipLoadData( $request ) {
1169 return !empty( $this->mParams['nodata'] );
1170 }
1171
1180 if ( $this->mHideIf ) {
1181 // This is probably more restrictive than it needs to be, but better safe than sorry
1182 return true;
1183 }
1184 return false;
1185 }
1186}
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
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:133
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:1965
static accesskey( $name)
Given the id of an interface element, constructs the appropriate accesskey attribute from the system ...
Definition Linker.php:2013
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Definition Linker.php:2130
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
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
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:2843
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:1999
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:2003
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:2011
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:271
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