54 $this->uniqueId = $this->
getClassName() . ++self::$counter .
'x';
55 parent::__construct( $params );
57 if ( empty( $this->mParams[
'fields'] ) || !is_array( $this->mParams[
'fields'] ) ) {
58 throw new MWException(
'HTMLFormFieldCloner called without any fields' );
62 if ( isset( $this->mParams[
'fields'][
'delete'] ) ) {
63 $class =
'mw-htmlform-cloner-delete-button';
64 $info = $this->mParams[
'fields'][
'delete'] + [
65 'formnovalidate' =>
true,
68 unset( $info[
'name'], $info[
'class'] );
70 if ( !isset( $info[
'type'] ) || $info[
'type'] !==
'submit' ) {
72 'HTMLFormFieldCloner delete field, if specified, must be of type "submit"'
76 if ( !in_array( $class, explode(
' ', $info[
'cssclass'] ) ) ) {
77 $info[
'cssclass'] .=
" $class";
80 $this->mParams[
'fields'][
'delete'] = $info;
93 foreach ( $this->mParams[
'fields'] as $fieldname => $info ) {
94 $name =
"{$this->mName}[$key][$fieldname]";
95 if ( isset( $info[
'name'] ) ) {
96 $info[
'name'] =
"{$this->mName}[$key][{$info['name']}]";
98 $info[
'name'] = $name;
100 if ( isset( $info[
'id'] ) ) {
101 $info[
'id'] = Sanitizer::escapeIdForAttribute(
"{$this->mID}--$key--{$info['id']}" );
103 $info[
'id'] = Sanitizer::escapeIdForAttribute(
"{$this->mID}--$key--$fieldname" );
107 if ( $this->mHideIf ) {
108 if ( isset( $info[
'hide-if'] ) ) {
116 $field = HTMLForm::loadInputFromParameters( $name, $info, $this->mParent );
117 $fields[$fieldname] = $field;
132 foreach ( $values as $fieldname => $value ) {
133 $name =
"{$this->mName}[$key][$fieldname]";
134 $data[$name] = $value;
146 if ( !$request->getCheck(
'wpEditToken' ) && $request->getArray( $this->mName ) ===
null ) {
150 $values = $request->getArray( $this->mName );
151 if ( $values ===
null ) {
156 foreach ( $values as $key => $value ) {
157 if ( $key ===
'create' || isset( $value[
'delete'] ) ) {
169 foreach ( $fields as $fieldname => $field ) {
170 if ( $field->skipLoadData( $subrequest ) ) {
173 if ( !empty( $field->mParams[
'disabled'] ) ) {
174 $row[$fieldname] = $field->getDefault();
176 $row[$fieldname] = $field->loadDataFromRequest( $subrequest );
182 if ( isset( $values[
'create'] ) ) {
186 foreach ( $fields as $fieldname => $field ) {
187 if ( !empty( $field->mParams[
'nodata'] ) ) {
190 $row[$fieldname] = $field->getDefault();
199 $ret = parent::getDefault();
202 if ( $ret ===
null ) {
205 foreach ( $fields as $fieldname => $field ) {
206 if ( !empty( $field->mParams[
'nodata'] ) ) {
209 $row[$fieldname] = $field->getDefault();
222 if ( isset( $values[
'nonjs'] ) ) {
226 foreach ( $values as $key => $value ) {
228 foreach ( $fields as $fieldname => $field ) {
229 if ( !array_key_exists( $fieldname, $value ) ) {
232 if ( $field->cancelSubmit( $value[$fieldname], $alldata ) ) {
238 return parent::cancelSubmit( $values, $alldata );
246 if ( isset( $this->mParams[
'required'] )
247 && $this->mParams[
'required'] !==
false
250 return $this->
msg(
'htmlform-cloner-required' );
253 if ( isset( $values[
'nonjs'] ) ) {
260 foreach ( $values as $key => $value ) {
262 foreach ( $fields as $fieldname => $field ) {
263 if ( !array_key_exists( $fieldname, $value ) ) {
266 if ( $field->isHidden( $alldata ) ) {
269 $ok = $field->validate( $value[$fieldname], $alldata );
270 if ( $ok !==
true ) {
276 return parent::validate( $values, $alldata );
287 $displayFormat = $this->mParams[
'format'] ?? $this->mParent->getDisplayFormat();
290 $getFieldHtmlMethod = $displayFormat ==
'table' ?
'getTableRow' : (
'get' . $displayFormat );
297 foreach ( $fields as $fieldname => $field ) {
298 $v = array_key_exists( $fieldname, $values )
299 ? $values[$fieldname]
300 : $field->getDefault();
304 list( $name, $value, $params ) = $field->getHiddenFieldData( $v );
305 $hidden .= Html::hidden( $name, $value, $params ) .
"\n";
307 $html .= $field->$getFieldHtmlMethod( $v );
309 $labelValue = trim( $field->getLabel() );
310 if ( $labelValue !==
"\u{00A0}" && $labelValue !==
' ' && $labelValue !==
'' ) {
316 if ( !isset( $fields[
'delete'] ) ) {
319 if ( $displayFormat ===
'table' ) {
320 $html .= $field->$getFieldHtmlMethod( $field->getDefault() );
322 $html .= $field->getInputHTML( $field->getDefault() );
326 if ( $displayFormat !==
'raw' ) {
327 $classes = [
'mw-htmlform-cloner-row' ];
330 $classes[] =
'mw-htmlform-nolabel';
333 $attribs = [
'class' => $classes ];
335 if ( $displayFormat ===
'table' ) {
336 $html = Html::rawElement(
'table',
338 Html::rawElement(
'tbody', [],
"\n$html\n" ) ) .
"\n";
340 $html = Html::rawElement(
'div', $attribs,
"\n$html\n" );
346 if ( !empty( $this->mParams[
'row-legend'] ) ) {
347 $legend = $this->
msg( $this->mParams[
'row-legend'] )->text();
348 $html = Xml::fieldset( $legend, $html );
359 $name =
"{$this->mName}[$key][delete]";
360 $label = $this->mParams[
'delete-button-message'] ??
'htmlform-cloner-delete';
361 $field = HTMLForm::loadInputFromParameters( $name, [
363 'formnovalidate' =>
true,
365 'id' => Sanitizer::escapeIdForAttribute(
"{$this->mID}--$key--delete" ),
366 'cssclass' =>
'mw-htmlform-cloner-delete-button',
367 'default' => $this->
getMessage( $label )->text(),
368 'disabled' => $this->mParams[
'disabled'] ??
false,
374 $name =
"{$this->mName}[create]";
375 $label = $this->mParams[
'create-button-message'] ??
'htmlform-cloner-create';
376 return HTMLForm::loadInputFromParameters( $name, [
378 'formnovalidate' =>
true,
380 'id' => Sanitizer::escapeIdForAttribute(
"{$this->mID}--create" ),
381 'cssclass' =>
'mw-htmlform-cloner-create-button',
382 'default' => $this->getMessage( $label )->text(),
383 'disabled' => $this->mParams[
'disabled'] ??
false,
390 foreach ( (array)$values as $key => $value ) {
391 if ( $key ===
'nonjs' ) {
394 $html .= Html::rawElement(
'li', [
'class' =>
'mw-htmlform-cloner-li' ],
395 $this->getInputHTMLForKey( $key, $value )
399 $template = $this->getInputHTMLForKey( $this->uniqueId, [] );
401 $html = Html::rawElement(
'ul', [
402 'id' =>
"mw-htmlform-cloner-list-{$this->mID}",
403 'class' =>
'mw-htmlform-cloner-ul',
404 'data-template' => $template,
405 'data-unique-id' => $this->uniqueId,
408 $field = $this->getCreateButtonHtml();
409 $html .= $field->getInputHTML( $field->getDefault() );
425 $fields = $this->createFieldsForKey( $key );
426 foreach ( $fields as $fieldname => $field ) {
427 $v = array_key_exists( $fieldname, $values )
428 ? $values[$fieldname]
429 : $field->getDefault();
433 list( $name, $value, $params ) = $field->getHiddenFieldData( $v );
434 $hidden .= Html::hidden( $name, $value, $params ) .
"\n";
436 $html .= $field->getOOUI( $v );
440 if ( !isset( $fields[
'delete'] ) ) {
441 $field = $this->getDeleteButtonHtml( $key );
442 $fieldHtml = $field->getInputOOUI( $field->getDefault() );
443 $fieldHtml->setInfusable(
true );
448 $html = Html::rawElement(
'div', [
'class' =>
'mw-htmlform-cloner-row' ],
"\n$html\n" );
452 if ( !empty( $this->mParams[
'row-legend'] ) ) {
453 $legend = $this->msg( $this->mParams[
'row-legend'] )->text();
454 $html = Xml::fieldset( $legend, $html );
463 foreach ( (array)$values as $key => $value ) {
464 if ( $key ===
'nonjs' ) {
467 $html .= Html::rawElement(
'li', [
'class' =>
'mw-htmlform-cloner-li' ],
468 $this->getInputOOUIForKey( $key, $value )
472 $template = $this->getInputOOUIForKey( $this->uniqueId, [] );
474 $html = Html::rawElement(
'ul', [
475 'id' =>
"mw-htmlform-cloner-list-{$this->mID}",
476 'class' =>
'mw-htmlform-cloner-ul',
477 'data-template' => $template,
478 'data-unique-id' => $this->uniqueId,
481 $field = $this->getCreateButtonHtml();
482 $fieldHtml = $field->getInputOOUI( $field->getDefault() );
483 $fieldHtml->setInfusable(
true );
Similar to FauxRequest, but only fakes URL parameters and method (POST or GET) and use the base reque...