17 protected $mLabel; # String label, as HTML. Set on construction.
87 public function msg( $key, ...$params ) {
88 if ( $this->mParent ) {
89 return $this->mParent->msg( $key, ...$params );
121 while ( preg_match(
'/^(.+)\[([^\]]+)\]$/', $tmp, $m ) ) {
122 array_unshift( $thisKeys, $m[2] );
125 if ( substr( $tmp, 0, 2 ) ==
'wp' &&
126 !array_key_exists( $tmp, $alldata ) &&
127 array_key_exists( substr( $tmp, 2 ), $alldata )
130 $tmp = substr( $tmp, 2 );
132 array_unshift( $thisKeys, $tmp );
136 while ( preg_match(
'/^(.+)\[([^\]]+)\]$/', $tmp, $m ) ) {
137 array_unshift( $nameKeys, $m[2] );
140 array_unshift( $nameKeys, $tmp );
143 for ( $i = count( $thisKeys ) - 1; $i >= 0; $i-- ) {
144 $keys = array_merge( array_slice( $thisKeys, 0, $i ), $nameKeys );
146 foreach (
$keys as $key ) {
147 if ( !is_array( $data ) || !array_key_exists( $key, $data ) ) {
152 $testValue = (string)$data;
168 $origParams = $params;
169 $op = array_shift( $params );
174 foreach ( $params as $i => $p ) {
175 if ( !is_array( $p ) ) {
177 "Expected array, found " . gettype( $p ) .
" at index $i"
187 foreach ( $params as $i => $p ) {
188 if ( !is_array( $p ) ) {
190 "Expected array, found " . gettype( $p ) .
" at index $i"
200 foreach ( $params as $i => $p ) {
201 if ( !is_array( $p ) ) {
203 "Expected array, found " . gettype( $p ) .
" at index $i"
213 foreach ( $params as $i => $p ) {
214 if ( !is_array( $p ) ) {
216 "Expected array, found " . gettype( $p ) .
" at index $i"
226 if ( count( $params ) !== 1 ) {
227 throw new MWException(
"NOT takes exactly one parameter" );
230 if ( !is_array( $p ) ) {
232 "Expected array, found " . gettype( $p ) .
" at index 0"
239 if ( count( $params ) !== 2 ) {
240 throw new MWException(
"$op takes exactly two parameters" );
242 list( $field, $value ) = $params;
243 if ( !is_string( $field ) || !is_string( $value ) ) {
244 throw new MWException(
"Parameters for $op must be strings" );
249 return ( $value === $testValue );
251 return ( $value !== $testValue );
257 }
catch ( Exception $ex ) {
259 "Invalid hide-if specification for $this->mName: " .
260 $ex->getMessage() .
" in " . var_export( $origParams,
true ),
275 if ( !$this->mHideIf ) {
310 if ( $this->
isHidden( $alldata ) ) {
314 if ( isset( $this->mParams[
'required'] )
315 && $this->mParams[
'required'] !==
false
318 return $this->
msg(
'htmlform-required' );
321 if ( isset( $this->mValidationCallback ) ) {
322 return ( $this->mValidationCallback )( $value, $alldata,
$this->mParent );
336 public function filter( $value, $alldata ) {
337 if ( isset( $this->mFilterCallback ) ) {
365 $this->mShowEmptyLabels = $show;
379 return $request->
getCheck(
'wpEditToken' ) || $request->
getCheck(
'wpFormIdentifier' );
391 if ( $request->getCheck( $this->mName ) ) {
392 return $request->getText( $this->mName );
408 $this->mParams = $params;
410 if ( isset( $params[
'parent'] ) && $params[
'parent'] instanceof
HTMLForm ) {
411 $this->mParent = $params[
'parent'];
414 # Generate the label from a message, if possible
415 if ( isset( $params[
'label-message'] ) ) {
416 $this->mLabel = $this->
getMessage( $params[
'label-message'] )->parse();
417 } elseif ( isset( $params[
'label'] ) ) {
418 if ( $params[
'label'] ===
' ' || $params[
'label'] ===
"\u{00A0}" ) {
420 $this->mLabel =
"\u{00A0}";
422 $this->mLabel = htmlspecialchars( $params[
'label'] );
424 } elseif ( isset( $params[
'label-raw'] ) ) {
425 $this->mLabel = $params[
'label-raw'];
428 $this->mName =
"wp{$params['fieldname']}";
429 if ( isset( $params[
'name'] ) ) {
430 $this->mName = $params[
'name'];
433 if ( isset( $params[
'dir'] ) ) {
434 $this->mDir = $params[
'dir'];
437 $validName = urlencode( $this->mName );
438 $validName = str_replace( [
'%5B',
'%5D' ], [
'[',
']' ], $validName );
439 if ( $this->mName != $validName && !isset( $params[
'nodata'] ) ) {
440 throw new MWException(
"Invalid name '{$this->mName}' passed to " . __METHOD__ );
443 $this->mID =
"mw-input-{$this->mName}";
445 if ( isset( $params[
'default'] ) ) {
446 $this->mDefault = $params[
'default'];
449 if ( isset( $params[
'id'] ) ) {
451 $validId = urlencode( $id );
453 if ( $id != $validId ) {
454 throw new MWException(
"Invalid id '$id' passed to " . __METHOD__ );
460 if ( isset( $params[
'cssclass'] ) ) {
461 $this->mClass = $params[
'cssclass'];
464 if ( isset( $params[
'csshelpclass'] ) ) {
465 $this->mHelpClass = $params[
'csshelpclass'];
468 if ( isset( $params[
'validation-callback'] ) ) {
469 $this->mValidationCallback = $params[
'validation-callback'];
472 if ( isset( $params[
'filter-callback'] ) ) {
473 $this->mFilterCallback = $params[
'filter-callback'];
476 if ( isset( $params[
'hidelabel'] ) ) {
477 $this->mShowEmptyLabels =
false;
480 if ( isset( $params[
'hide-if'] ) ) {
481 $this->mHideIf = $params[
'hide-if'];
497 $fieldType = static::class;
499 $cellAttributes = [];
503 if ( !empty( $this->mParams[
'vertical-label'] ) ) {
504 $cellAttributes[
'colspan'] = 2;
505 $verticalLabel =
true;
507 $verticalLabel =
false;
514 [
'class' =>
'mw-input' ] + $cellAttributes,
515 $inputHtml .
"\n$errors"
518 if ( $this->mHideIf ) {
520 $rowClasses .=
' mw-htmlform-hide-if';
523 if ( $verticalLabel ) {
525 $rowAttributes + [
'class' =>
"mw-htmlform-vertical-label $rowClasses" ], $label );
528 'class' =>
"mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
535 'class' =>
"mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses"
540 return $html . $helptext;
556 $fieldType = static::class;
558 $cellAttributes = [];
563 'mw-htmlform-nolabel' => ( $label ===
'' )
566 $horizontalLabel = $this->mParams[
'horizontal-label'] ??
false;
568 if ( $horizontalLabel ) {
569 $field =
"\u{00A0}" . $inputHtml .
"\n$errors";
574 [
'class' => $outerDivClass ] + $cellAttributes,
575 $inputHtml .
"\n$errors"
578 $divCssClasses = [
"mw-htmlform-field-$fieldType",
581 $wrapperAttributes = [
582 'class' => $divCssClasses,
584 if ( $this->mHideIf ) {
586 $wrapperAttributes[
'class'][] =
' mw-htmlform-hide-if';
606 if ( !$inputField ) {
611 new OOUI\Widget( [
'content' =>
new OOUI\HtmlSnippet( $this->
getDiv( $value ) ) ] ),
617 if ( is_string( $inputField ) ) {
621 $inputField =
new OOUI\Widget( [
'content' =>
new OOUI\HtmlSnippet( $inputField ) ] );
625 $fieldType = static::class;
628 foreach ( $errors as &$error ) {
629 $error =
new OOUI\HtmlSnippet( $error );
633 'classes' => [
"mw-htmlform-field-$fieldType",
$this->mClass ],
635 'help' => (
$help !==
null &&
$help !==
'' ) ?
new OOUI\HtmlSnippet(
$help ) :
null,
637 'infusable' => $infusable,
641 $preloadModules =
false;
644 $preloadModules =
true;
645 $config[
'classes'][] =
'mw-htmlform-field-autoinfuse';
650 if ( $label && $label !==
"\u{00A0}" && $label !==
' ' ) {
651 $config[
'label'] =
new OOUI\HtmlSnippet( $label );
654 if ( $this->mHideIf ) {
655 $preloadModules =
true;
661 if ( $preloadModules ) {
662 $this->mParent->getOutput()->addModules(
'mediawiki.htmlform.ooui' );
663 $this->mParent->getOutput()->addModules( $this->
getOOUIModules() );
686 if ( isset( $this->mClassWithButton ) ) {
687 $buttonWidget = $this->mClassWithButton->getInputOOUI(
'' );
731 $cellAttributes = [];
753 $this->mVFormClass =
' mw-ui-vform-field';
754 return $this->
getDiv( $value );
768 $cellAttributes = [];
771 $html =
"\n" . $errors .
772 $label .
"\u{00A0}" .
787 if ( $helptext ===
null ) {
792 if ( $this->mHideIf ) {
794 $rowAttributes[
'class'] =
'mw-htmlform-hide-if';
797 $tdClasses = [
'htmlform-tip' ];
798 if ( $this->mHelpClass !==
false ) {
801 $row =
Html::rawElement(
'td', [
'colspan' => 2,
'class' => $tdClasses ], $helptext );
816 if ( $helptext ===
null ) {
820 $wrapperAttributes = [
821 'class' =>
'htmlform-tip',
823 if ( $this->mHelpClass !==
false ) {
824 $wrapperAttributes[
'class'] .=
" {$this->mHelpClass}";
826 if ( $this->mHideIf ) {
828 $wrapperAttributes[
'class'] .=
' mw-htmlform-hide-if';
855 if ( isset( $this->mParams[
'help-message'] ) ) {
856 $this->mParams[
'help-messages'] = [ $this->mParams[
'help-message'] ];
859 if ( isset( $this->mParams[
'help-messages'] ) ) {
860 foreach ( $this->mParams[
'help-messages'] as $msg ) {
863 if ( $msg->exists() ) {
864 if ( $helptext ===
null ) {
867 $helptext .= $this->
msg(
'word-separator' )->escaped();
869 $helptext .= $msg->parse();
872 } elseif ( isset( $this->mParams[
'help'] ) ) {
873 $helptext = $this->mParams[
'help'];
888 return $this->mParams[
'help-inline'] ??
true;
904 $errors = $this->
validate( $value, $this->mParent->mFieldData );
906 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
911 $errorClass =
'mw-htmlform-invalid-input';
914 return [ $errors, $errorClass ];
925 $errors = $this->
validate( $value, $this->mParent->mFieldData );
927 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
931 if ( !is_array( $errors ) ) {
932 $errors = [ $errors ];
934 foreach ( $errors as &$error ) {
935 if ( $error instanceof
Message ) {
936 $error = $error->parse();
948 return $this->mLabel ??
'';
958 # Don't output a for= attribute for labels with no associated input.
959 # Kind of hacky here, possibly we don't want these to be <label>s at all.
966 $labelValue = trim( $this->
getLabel() );
968 if ( $labelValue !==
"\u{00A0}" && $labelValue !==
' ' && $labelValue !==
'' ) {
972 $displayFormat = $this->mParent->getDisplayFormat();
974 $horizontalLabel = $this->mParams[
'horizontal-label'] ??
false;
976 if ( $displayFormat ===
'table' ) {
979 [
'class' =>
'mw-label' ] + $cellAttributes,
981 } elseif ( $hasLabel || $this->mShowEmptyLabels ) {
982 if ( $displayFormat ===
'div' && !$horizontalLabel ) {
985 [
'class' =>
'mw-label' ] + $cellAttributes,
1000 return $this->mDefault ??
null;
1009 if ( empty( $this->mParams[
'tooltip'] ) ) {
1022 if ( empty( $this->mParams[
'tooltip'] ) ) {
1040 static $boolAttribs = [
'disabled',
'required',
'autofocus',
'multiple',
'readonly' ];
1043 foreach ( $list as $key ) {
1044 if ( in_array( $key, $boolAttribs ) ) {
1045 if ( !empty( $this->mParams[$key] ) ) {
1048 } elseif ( isset( $this->mParams[$key] ) ) {
1049 $ret[$key] = $this->mParams[$key];
1065 foreach ( $options as $key => $value ) {
1066 $key = $this->
msg( $key )->plain();
1067 $ret[$key] = is_array( $value )
1082 if ( is_array( $array ) ) {
1083 return array_map( [ __CLASS__,
'forceToStringRecursive' ], $array );
1085 return strval( $array );
1096 if ( $this->mOptions ===
false ) {
1097 if ( array_key_exists(
'options-messages', $this->mParams ) ) {
1098 $this->mOptions = $this->
lookupOptionsKeys( $this->mParams[
'options-messages'] );
1099 } elseif ( array_key_exists(
'options', $this->mParams ) ) {
1100 $this->mOptionsLabelsNotFromMessage =
true;
1102 } elseif ( array_key_exists(
'options-message', $this->mParams ) ) {
1103 $message = $this->
getMessage( $this->mParams[
'options-message'] )->inContentLanguage()->plain();
1106 $this->mOptions =
null;
1121 if ( $oldoptions ===
null ) {
1138 foreach ( $options as $value ) {
1139 if ( is_array( $value ) ) {
1140 $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) );
1142 $flatOpts[] = $value;
1163 if ( is_array( $errors ) && count( $errors ) === 1 ) {
1164 $errors = array_shift( $errors );
1167 if ( is_array( $errors ) ) {
1169 foreach ( $errors as $error ) {
1170 if ( $error instanceof
Message ) {
1179 if ( $errors instanceof
Message ) {
1180 $errors = $errors->parse();
1196 if ( $this->mParent ) {
1197 $message->setContext( $this->mParent );
1211 return !empty( $this->mParams[
'nodata'] );
1222 if ( $this->mHideIf ) {