MediaWiki REL1_27
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 function getInputHTML( $value );
46
54 function getInputOOUI( $value ) {
55 return false;
56 }
57
63 public function canDisplayErrors() {
64 return true;
65 }
66
77 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 function isHidden( $alldata ) {
270 if ( !$this->mHideIf ) {
271 return false;
272 }
273
274 return $this->isHiddenRecurse( $alldata, $this->mHideIf );
275 }
276
287 function cancelSubmit( $value, $alldata ) {
288 return false;
289 }
290
302 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' )->parse();
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 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
360 if ( $request->getCheck( $this->mName ) ) {
361 return $request->getText( $this->mName );
362 } else {
363 return $this->getDefault();
364 }
365 }
366
375 function __construct( $params ) {
376 $this->mParams = $params;
377
378 if ( isset( $params['parent'] ) && $params['parent'] instanceof HTMLForm ) {
379 $this->mParent = $params['parent'];
380 }
381
382 # Generate the label from a message, if possible
383 if ( isset( $params['label-message'] ) ) {
384 $this->mLabel = $this->getMessage( $params['label-message'] )->parse();
385 } elseif ( isset( $params['label'] ) ) {
386 if ( $params['label'] === '&#160;' ) {
387 // Apparently some things set &nbsp directly and in an odd format
388 $this->mLabel = '&#160;';
389 } else {
390 $this->mLabel = htmlspecialchars( $params['label'] );
391 }
392 } elseif ( isset( $params['label-raw'] ) ) {
393 $this->mLabel = $params['label-raw'];
394 }
395
396 $this->mName = "wp{$params['fieldname']}";
397 if ( isset( $params['name'] ) ) {
398 $this->mName = $params['name'];
399 }
400
401 if ( isset( $params['dir'] ) ) {
402 $this->mDir = $params['dir'];
403 }
404
405 $validName = Sanitizer::escapeId( $this->mName );
406 $validName = str_replace( [ '.5B', '.5D' ], [ '[', ']' ], $validName );
407 if ( $this->mName != $validName && !isset( $params['nodata'] ) ) {
408 throw new MWException( "Invalid name '{$this->mName}' passed to " . __METHOD__ );
409 }
410
411 $this->mID = "mw-input-{$this->mName}";
412
413 if ( isset( $params['default'] ) ) {
414 $this->mDefault = $params['default'];
415 }
416
417 if ( isset( $params['id'] ) ) {
418 $id = $params['id'];
419 $validId = Sanitizer::escapeId( $id );
420
421 if ( $id != $validId ) {
422 throw new MWException( "Invalid id '$id' passed to " . __METHOD__ );
423 }
424
425 $this->mID = $id;
426 }
427
428 if ( isset( $params['cssclass'] ) ) {
429 $this->mClass = $params['cssclass'];
430 }
431
432 if ( isset( $params['csshelpclass'] ) ) {
433 $this->mHelpClass = $params['csshelpclass'];
434 }
435
436 if ( isset( $params['validation-callback'] ) ) {
437 $this->mValidationCallback = $params['validation-callback'];
438 }
439
440 if ( isset( $params['filter-callback'] ) ) {
441 $this->mFilterCallback = $params['filter-callback'];
442 }
443
444 if ( isset( $params['flatlist'] ) ) {
445 $this->mClass .= ' mw-htmlform-flatlist';
446 }
447
448 if ( isset( $params['hidelabel'] ) ) {
449 $this->mShowEmptyLabels = false;
450 }
451
452 if ( isset( $params['hide-if'] ) ) {
453 $this->mHideIf = $params['hide-if'];
454 }
455 }
456
465 function getTableRow( $value ) {
466 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
467 $inputHtml = $this->getInputHTML( $value );
468 $fieldType = get_class( $this );
469 $helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
470 $cellAttributes = [];
471 $rowAttributes = [];
472 $rowClasses = '';
473
474 if ( !empty( $this->mParams['vertical-label'] ) ) {
475 $cellAttributes['colspan'] = 2;
476 $verticalLabel = true;
477 } else {
478 $verticalLabel = false;
479 }
480
481 $label = $this->getLabelHtml( $cellAttributes );
482
483 $field = Html::rawElement(
484 'td',
485 [ 'class' => 'mw-input' ] + $cellAttributes,
486 $inputHtml . "\n$errors"
487 );
488
489 if ( $this->mHideIf ) {
490 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
491 $rowClasses .= ' mw-htmlform-hide-if';
492 }
493
494 if ( $verticalLabel ) {
495 $html = Html::rawElement( 'tr',
496 $rowAttributes + [ 'class' => "mw-htmlform-vertical-label $rowClasses" ], $label );
497 $html .= Html::rawElement( 'tr',
498 $rowAttributes + [
499 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
500 ],
501 $field );
502 } else {
503 $html =
504 Html::rawElement( 'tr',
505 $rowAttributes + [
506 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
507 ],
508 $label . $field );
509 }
510
511 return $html . $helptext;
512 }
513
523 public function getDiv( $value ) {
524 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
525 $inputHtml = $this->getInputHTML( $value );
526 $fieldType = get_class( $this );
527 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
528 $cellAttributes = [];
529 $label = $this->getLabelHtml( $cellAttributes );
530
531 $outerDivClass = [
532 'mw-input',
533 'mw-htmlform-nolabel' => ( $label === '' )
534 ];
535
536 $horizontalLabel = isset( $this->mParams['horizontal-label'] )
537 ? $this->mParams['horizontal-label'] : false;
538
539 if ( $horizontalLabel ) {
540 $field = '&#160;' . $inputHtml . "\n$errors";
541 } else {
542 $field = Html::rawElement(
543 'div',
544 [ 'class' => $outerDivClass ] + $cellAttributes,
545 $inputHtml . "\n$errors"
546 );
547 }
548 $divCssClasses = [ "mw-htmlform-field-$fieldType",
549 $this->mClass, $this->mVFormClass, $errorClass ];
550
551 $wrapperAttributes = [
552 'class' => $divCssClasses,
553 ];
554 if ( $this->mHideIf ) {
555 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
556 $wrapperAttributes['class'][] = ' mw-htmlform-hide-if';
557 }
558 $html = Html::rawElement( 'div', $wrapperAttributes, $label . $field );
559 $html .= $helptext;
560
561 return $html;
562 }
563
572 public function getOOUI( $value ) {
573 $inputField = $this->getInputOOUI( $value );
574
575 if ( !$inputField ) {
576 // This field doesn't have an OOUI implementation yet at all. Fall back to getDiv() to
577 // generate the whole field, label and errors and all, then wrap it in a Widget.
578 // It might look weird, but it'll work OK.
579 return $this->getFieldLayoutOOUI(
580 new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $this->getDiv( $value ) ) ] ),
581 [ 'infusable' => false, 'align' => 'top' ]
582 );
583 }
584
585 $infusable = true;
586 if ( is_string( $inputField ) ) {
587 // We have an OOUI implementation, but it's not proper, and we got a load of HTML.
588 // Cheat a little and wrap it in a widget. It won't be infusable, though, since client-side
589 // JavaScript doesn't know how to rebuilt the contents.
590 $inputField = new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $inputField ) ] );
591 $infusable = false;
592 }
593
594 $fieldType = get_class( $this );
595 $helpText = $this->getHelpText();
596 $errors = $this->getErrorsRaw( $value );
597 foreach ( $errors as &$error ) {
598 $error = new OOUI\HtmlSnippet( $error );
599 }
600
601 $config = [
602 'classes' => [ "mw-htmlform-field-$fieldType", $this->mClass ],
603 'align' => $this->getLabelAlignOOUI(),
604 'help' => $helpText !== null ? new OOUI\HtmlSnippet( $helpText ) : null,
605 'errors' => $errors,
606 'infusable' => $infusable,
607 ];
608
609 // the element could specify, that the label doesn't need to be added
610 $label = $this->getLabel();
611 if ( $label ) {
612 $config['label'] = new OOUI\HtmlSnippet( $label );
613 }
614
615 return $this->getFieldLayoutOOUI( $inputField, $config );
616 }
617
622 protected function getLabelAlignOOUI() {
623 return 'top';
624 }
625
630 protected function getFieldLayoutOOUI( $inputField, $config ) {
631 if ( isset( $this->mClassWithButton ) ) {
632 $buttonWidget = $this->mClassWithButton->getInputOOUI( '' );
633 return new OOUI\ActionFieldLayout( $inputField, $buttonWidget, $config );
634 }
635 return new OOUI\FieldLayout( $inputField, $config );
636 }
637
647 public function getRaw( $value ) {
648 list( $errors, ) = $this->getErrorsAndErrorClass( $value );
649 $inputHtml = $this->getInputHTML( $value );
650 $helptext = $this->getHelpTextHtmlRaw( $this->getHelpText() );
651 $cellAttributes = [];
652 $label = $this->getLabelHtml( $cellAttributes );
653
654 $html = "\n$errors";
655 $html .= $label;
656 $html .= $inputHtml;
657 $html .= $helptext;
658
659 return $html;
660 }
661
670 public function getVForm( $value ) {
671 // Ewwww
672 $this->mVFormClass = ' mw-ui-vform-field';
673 return $this->getDiv( $value );
674 }
675
682 public function getInline( $value ) {
683 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
684 $inputHtml = $this->getInputHTML( $value );
685 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
686 $cellAttributes = [];
687 $label = $this->getLabelHtml( $cellAttributes );
688
689 $html = "\n" . $errors .
690 $label . '&#160;' .
691 $inputHtml .
692 $helptext;
693
694 return $html;
695 }
696
704 public function getHelpTextHtmlTable( $helptext ) {
705 if ( is_null( $helptext ) ) {
706 return '';
707 }
708
709 $rowAttributes = [];
710 if ( $this->mHideIf ) {
711 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
712 $rowAttributes['class'] = 'mw-htmlform-hide-if';
713 }
714
715 $tdClasses = [ 'htmlform-tip' ];
716 if ( $this->mHelpClass !== false ) {
717 $tdClasses[] = $this->mHelpClass;
718 }
719 $row = Html::rawElement( 'td', [ 'colspan' => 2, 'class' => $tdClasses ], $helptext );
720 $row = Html::rawElement( 'tr', $rowAttributes, $row );
721
722 return $row;
723 }
724
733 public function getHelpTextHtmlDiv( $helptext ) {
734 if ( is_null( $helptext ) ) {
735 return '';
736 }
737
738 $wrapperAttributes = [
739 'class' => 'htmlform-tip',
740 ];
741 if ( $this->mHelpClass !== false ) {
742 $wrapperAttributes['class'] .= " {$this->mHelpClass}";
743 }
744 if ( $this->mHideIf ) {
745 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
746 $wrapperAttributes['class'] .= ' mw-htmlform-hide-if';
747 }
748 $div = Html::rawElement( 'div', $wrapperAttributes, $helptext );
749
750 return $div;
751 }
752
760 public function getHelpTextHtmlRaw( $helptext ) {
761 return $this->getHelpTextHtmlDiv( $helptext );
762 }
763
769 public function getHelpText() {
770 $helptext = null;
771
772 if ( isset( $this->mParams['help-message'] ) ) {
773 $this->mParams['help-messages'] = [ $this->mParams['help-message'] ];
774 }
775
776 if ( isset( $this->mParams['help-messages'] ) ) {
777 foreach ( $this->mParams['help-messages'] as $msg ) {
778 $msg = $this->getMessage( $msg );
779
780 if ( $msg->exists() ) {
781 if ( is_null( $helptext ) ) {
782 $helptext = '';
783 } else {
784 $helptext .= $this->msg( 'word-separator' )->escaped(); // some space
785 }
786 $helptext .= $msg->parse(); // Append message
787 }
788 }
789 } elseif ( isset( $this->mParams['help'] ) ) {
790 $helptext = $this->mParams['help'];
791 }
792
793 return $helptext;
794 }
795
803 public function getErrorsAndErrorClass( $value ) {
804 $errors = $this->validate( $value, $this->mParent->mFieldData );
805
806 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
807 $errors = '';
808 $errorClass = '';
809 } else {
810 $errors = self::formatErrors( $errors );
811 $errorClass = 'mw-htmlform-invalid-input';
812 }
813
814 return [ $errors, $errorClass ];
815 }
816
824 public function getErrorsRaw( $value ) {
825 $errors = $this->validate( $value, $this->mParent->mFieldData );
826
827 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
828 $errors = [];
829 }
830
831 if ( !is_array( $errors ) ) {
832 $errors = [ $errors ];
833 }
834 foreach ( $errors as &$error ) {
835 if ( $error instanceof Message ) {
836 $error = $error->parse();
837 }
838 }
839
840 return $errors;
841 }
842
846 function getLabel() {
847 return is_null( $this->mLabel ) ? '' : $this->mLabel;
848 }
849
850 function getLabelHtml( $cellAttributes = [] ) {
851 # Don't output a for= attribute for labels with no associated input.
852 # Kind of hacky here, possibly we don't want these to be <label>s at all.
853 $for = [];
854
855 if ( $this->needsLabel() ) {
856 $for['for'] = $this->mID;
857 }
858
859 $labelValue = trim( $this->getLabel() );
860 $hasLabel = false;
861 if ( $labelValue !== '&#160;' && $labelValue !== '' ) {
862 $hasLabel = true;
863 }
864
865 $displayFormat = $this->mParent->getDisplayFormat();
866 $html = '';
867 $horizontalLabel = isset( $this->mParams['horizontal-label'] )
868 ? $this->mParams['horizontal-label'] : false;
869
870 if ( $displayFormat === 'table' ) {
871 $html =
872 Html::rawElement( 'td',
873 [ 'class' => 'mw-label' ] + $cellAttributes,
874 Html::rawElement( 'label', $for, $labelValue ) );
875 } elseif ( $hasLabel || $this->mShowEmptyLabels ) {
876 if ( $displayFormat === 'div' && !$horizontalLabel ) {
877 $html =
878 Html::rawElement( 'div',
879 [ 'class' => 'mw-label' ] + $cellAttributes,
880 Html::rawElement( 'label', $for, $labelValue ) );
881 } else {
882 $html = Html::rawElement( 'label', $for, $labelValue );
883 }
884 }
885
886 return $html;
887 }
888
889 function getDefault() {
890 if ( isset( $this->mDefault ) ) {
891 return $this->mDefault;
892 } else {
893 return null;
894 }
895 }
896
902 public function getTooltipAndAccessKey() {
903 if ( empty( $this->mParams['tooltip'] ) ) {
904 return [];
905 }
906
907 return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] );
908 }
909
916 public function getAttributes( array $list ) {
917 static $boolAttribs = [ 'disabled', 'required', 'autofocus', 'multiple', 'readonly' ];
918
919 $ret = [];
920 foreach ( $list as $key ) {
921 if ( in_array( $key, $boolAttribs ) ) {
922 if ( !empty( $this->mParams[$key] ) ) {
923 $ret[$key] = '';
924 }
925 } elseif ( isset( $this->mParams[$key] ) ) {
926 $ret[$key] = $this->mParams[$key];
927 }
928 }
929
930 return $ret;
931 }
932
940 private function lookupOptionsKeys( $options ) {
941 $ret = [];
942 foreach ( $options as $key => $value ) {
943 $key = $this->msg( $key )->plain();
944 $ret[$key] = is_array( $value )
945 ? $this->lookupOptionsKeys( $value )
946 : strval( $value );
947 }
948 return $ret;
949 }
950
958 static function forceToStringRecursive( $array ) {
959 if ( is_array( $array ) ) {
960 return array_map( [ __CLASS__, 'forceToStringRecursive' ], $array );
961 } else {
962 return strval( $array );
963 }
964 }
965
972 public function getOptions() {
973 if ( $this->mOptions === false ) {
974 if ( array_key_exists( 'options-messages', $this->mParams ) ) {
975 $this->mOptions = $this->lookupOptionsKeys( $this->mParams['options-messages'] );
976 } elseif ( array_key_exists( 'options', $this->mParams ) ) {
977 $this->mOptionsLabelsNotFromMessage = true;
978 $this->mOptions = self::forceToStringRecursive( $this->mParams['options'] );
979 } elseif ( array_key_exists( 'options-message', $this->mParams ) ) {
981 $message = $this->getMessage( $this->mParams['options-message'] )->inContentLanguage()->plain();
982
983 $optgroup = false;
984 $this->mOptions = [];
985 foreach ( explode( "\n", $message ) as $option ) {
986 $value = trim( $option );
987 if ( $value == '' ) {
988 continue;
989 } elseif ( substr( $value, 0, 1 ) == '*' && substr( $value, 1, 1 ) != '*' ) {
990 # A new group is starting...
991 $value = trim( substr( $value, 1 ) );
992 $optgroup = $value;
993 } elseif ( substr( $value, 0, 2 ) == '**' ) {
994 # groupmember
995 $opt = trim( substr( $value, 2 ) );
996 if ( $optgroup === false ) {
997 $this->mOptions[$opt] = $opt;
998 } else {
999 $this->mOptions[$optgroup][$opt] = $opt;
1000 }
1001 } else {
1002 # groupless reason list
1003 $optgroup = false;
1004 $this->mOptions[$option] = $option;
1005 }
1006 }
1007 } else {
1008 $this->mOptions = null;
1009 }
1010 }
1011
1012 return $this->mOptions;
1013 }
1014
1019 public function getOptionsOOUI() {
1020 $oldoptions = $this->getOptions();
1021
1022 if ( $oldoptions === null ) {
1023 return null;
1024 }
1025
1026 $options = [];
1027
1028 foreach ( $oldoptions as $text => $data ) {
1029 $options[] = [
1030 'data' => (string)$data,
1031 'label' => (string)$text,
1032 ];
1033 }
1034
1035 return $options;
1036 }
1037
1045 public static function flattenOptions( $options ) {
1046 $flatOpts = [];
1047
1048 foreach ( $options as $value ) {
1049 if ( is_array( $value ) ) {
1050 $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) );
1051 } else {
1052 $flatOpts[] = $value;
1053 }
1054 }
1055
1056 return $flatOpts;
1057 }
1058
1066 protected static function formatErrors( $errors ) {
1067 if ( is_array( $errors ) && count( $errors ) === 1 ) {
1068 $errors = array_shift( $errors );
1069 }
1070
1071 if ( is_array( $errors ) ) {
1072 $lines = [];
1073 foreach ( $errors as $error ) {
1074 if ( $error instanceof Message ) {
1075 $lines[] = Html::rawElement( 'li', [], $error->parse() );
1076 } else {
1077 $lines[] = Html::rawElement( 'li', [], $error );
1078 }
1079 }
1080
1081 return Html::rawElement( 'ul', [ 'class' => 'error' ], implode( "\n", $lines ) );
1082 } else {
1083 if ( $errors instanceof Message ) {
1084 $errors = $errors->parse();
1085 }
1086
1087 return Html::rawElement( 'span', [ 'class' => 'error' ], $errors );
1088 }
1089 }
1090
1097 protected function getMessage( $value ) {
1098 $message = Message::newFromSpecifier( $value );
1099
1100 if ( $this->mParent ) {
1101 $message->setContext( $this->mParent );
1102 }
1103
1104 return $message;
1105 }
1106
1113 public function skipLoadData( $request ) {
1114 return !empty( $this->mParams['nodata'] );
1115 }
1116}
$i
Definition Parser.php:1694
if( $line===false) $args
Definition cdb.php:64
The parent class to generate form fields.
getHelpTextHtmlDiv( $helptext)
Generate help text HTML in div format.
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.
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.
__construct( $params)
Initialise the object.
getMessage( $value)
Turns a *-message parameter (which could be a MessageSpecifier, or a message name,...
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.
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.
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.
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:123
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition Html.php:210
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[])
Returns the attributes for the tooltip and access key.
Definition Linker.php:2337
MediaWiki exception.
The Message class provides methods which fulfil two basic services:
Definition Message.php:159
static escapeId( $id, $options=[])
Given a value, escape it so that it can be used in an id attribute and return it.
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.
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:183
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
Definition hooks.txt:1042
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:1810
error also a ContextSource you ll probably need to make sure the header is varied on $request
Definition hooks.txt:2530
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:1818
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:88
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:314
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
$lines
Definition router.php:66
$params