49 $this->uniqueId = static::class . ++self::$counter .
'x';
50 parent::__construct( $params );
52 if ( empty( $this->mParams[
'fields'] ) || !is_array( $this->mParams[
'fields'] ) ) {
53 throw new MWException(
'HTMLFormFieldCloner called without any fields' );
57 if ( isset( $this->mParams[
'fields'][
'delete'] ) ) {
58 $class =
'mw-htmlform-cloner-delete-button';
59 $info = $this->mParams[
'fields'][
'delete'] + [
60 'formnovalidate' =>
true,
63 unset( $info[
'name'], $info[
'class'] );
65 if ( !isset( $info[
'type'] ) || $info[
'type'] !==
'submit' ) {
67 'HTMLFormFieldCloner delete field, if specified, must be of type "submit"'
71 if ( !in_array( $class, explode(
' ', $info[
'cssclass'] ) ) ) {
72 $info[
'cssclass'] .=
" $class";
75 $this->mParams[
'fields'][
'delete'] = $info;
88 foreach ( $this->mParams[
'fields'] as $fieldname => $info ) {
89 $name =
"{$this->mName}[$key][$fieldname]";
90 if ( isset( $info[
'name'] ) ) {
91 $info[
'name'] =
"{$this->mName}[$key][{$info['name']}]";
93 $info[
'name'] = $name;
95 if ( isset( $info[
'id'] ) ) {
96 $info[
'id'] = Sanitizer::escapeIdForAttribute(
"{$this->mID}--$key--{$info['id']}" );
98 $info[
'id'] = Sanitizer::escapeIdForAttribute(
"{$this->mID}--$key--$fieldname" );
102 if ( $this->mHideIf ) {
103 if ( isset( $info[
'hide-if'] ) ) {
112 $fields[$fieldname] = $field;
127 foreach ( $values as $fieldname => $value ) {
128 $name =
"{$this->mName}[$key][$fieldname]";
129 $data[$name] = $value;
141 if ( !$request->getCheck(
'wpEditToken' ) && $request->getArray( $this->mName ) === null ) {
145 $values = $request->getArray( $this->mName );
146 if ( $values ===
null ) {
151 foreach ( $values as $key => $value ) {
152 if ( $key ===
'create' || isset( $value[
'delete'] ) ) {
164 foreach ( $fields as $fieldname => $field ) {
165 if ( $field->skipLoadData( $subrequest ) ) {
167 } elseif ( !empty( $field->mParams[
'disabled'] ) ) {
168 $row[$fieldname] = $field->getDefault();
170 $row[$fieldname] = $field->loadDataFromRequest( $subrequest );
176 if ( isset( $values[
'create'] ) ) {
180 foreach ( $fields as $fieldname => $field ) {
181 if ( !empty( $field->mParams[
'nodata'] ) ) {
184 $row[$fieldname] = $field->getDefault();
194 $ret = parent::getDefault();
198 if ( $ret ===
null ) {
201 foreach ( $fields as $fieldname => $field ) {
202 if ( !empty( $field->mParams[
'nodata'] ) ) {
205 $row[$fieldname] = $field->getDefault();
215 if ( isset( $values[
'nonjs'] ) ) {
219 foreach ( $values as $key => $value ) {
221 foreach ( $fields as $fieldname => $field ) {
222 if ( !array_key_exists( $fieldname, $value ) ) {
225 if ( $field->cancelSubmit( $value[$fieldname], $alldata ) ) {
231 return parent::cancelSubmit( $values, $alldata );
235 if ( isset( $this->mParams[
'required'] )
236 && $this->mParams[
'required'] !==
false
239 return $this->
msg(
'htmlform-cloner-required' );
242 if ( isset( $values[
'nonjs'] ) ) {
249 foreach ( $values as $key => $value ) {
251 foreach ( $fields as $fieldname => $field ) {
252 if ( !array_key_exists( $fieldname, $value ) ) {
255 if ( $field->isHidden( $alldata ) ) {
258 $ok = $field->validate( $value[$fieldname], $alldata );
259 if ( $ok !==
true ) {
265 return parent::validate( $values, $alldata );
276 $displayFormat = $this->mParams[
'format'] ?? $this->mParent->getDisplayFormat();
279 $getFieldHtmlMethod = $displayFormat ==
'table' ?
'getTableRow' : (
'get' . $displayFormat );
286 foreach ( $fields as $fieldname => $field ) {
287 $v = array_key_exists( $fieldname, $values )
288 ? $values[$fieldname]
289 : $field->getDefault();
293 list( $name, $value, $params ) = $field->getHiddenFieldData( $v );
294 $hidden .= Html::hidden( $name, $value, $params ) .
"\n";
296 $html .= $field->$getFieldHtmlMethod( $v );
298 $labelValue = trim( $field->getLabel() );
299 if ( $labelValue !==
"\u{00A0}" && $labelValue !==
' ' && $labelValue !==
'' ) {
305 if ( !isset( $fields[
'delete'] ) ) {
308 if ( $displayFormat ===
'table' ) {
309 $html .= $field->$getFieldHtmlMethod( $field->getDefault() );
311 $html .= $field->getInputHTML( $field->getDefault() );
315 if ( $displayFormat !==
'raw' ) {
317 'mw-htmlform-cloner-row',
321 $classes[] =
'mw-htmlform-nolabel';
325 'class' => implode(
' ', $classes ),
328 if ( $displayFormat ===
'table' ) {
329 $html = Html::rawElement(
'table',
331 Html::rawElement(
'tbody', [],
"\n$html\n" ) ) .
"\n";
333 $html = Html::rawElement(
'div', $attribs,
"\n$html\n" );
339 if ( !empty( $this->mParams[
'row-legend'] ) ) {
340 $legend = $this->
msg( $this->mParams[
'row-legend'] )->text();
352 $name =
"{$this->mName}[$key][delete]";
353 $label = $this->mParams[
'delete-button-message'] ??
'htmlform-cloner-delete';
356 'formnovalidate' =>
true,
358 'id' => Sanitizer::escapeIdForAttribute(
"{$this->mID}--$key--delete" ),
359 'cssclass' =>
'mw-htmlform-cloner-delete-button',
360 'default' => $this->
getMessage( $label )->text(),
366 $name =
"{$this->mName}[create]";
367 $label = $this->mParams[
'create-button-message'] ??
'htmlform-cloner-create';
370 'formnovalidate' =>
true,
372 'id' => Sanitizer::escapeIdForAttribute(
"{$this->mID}--create" ),
373 'cssclass' =>
'mw-htmlform-cloner-create-button',
374 'default' => $this->
getMessage( $label )->text(),
381 foreach ( (array)$values as $key => $value ) {
382 if ( $key ===
'nonjs' ) {
385 $html .= Html::rawElement(
'li', [
'class' =>
'mw-htmlform-cloner-li' ],
391 $html = Html::rawElement(
'ul', [
392 'id' =>
"mw-htmlform-cloner-list-{$this->mID}",
393 'class' =>
'mw-htmlform-cloner-ul',
394 'data-template' => $template,
395 'data-unique-id' => $this->uniqueId,
399 $html .= $field->getInputHTML( $field->getDefault() );
416 foreach ( $fields as $fieldname => $field ) {
417 $v = array_key_exists( $fieldname, $values )
418 ? $values[$fieldname]
419 : $field->getDefault();
423 list( $name, $value, $params ) = $field->getHiddenFieldData( $v );
424 $hidden .= Html::hidden( $name, $value, $params ) .
"\n";
426 $html .= $field->getOOUI( $v );
430 if ( !isset( $fields[
'delete'] ) ) {
432 $fieldHtml = $field->getInputOOUI( $field->getDefault() );
433 $fieldHtml->setInfusable(
true );
439 'mw-htmlform-cloner-row',
443 'class' => implode(
' ', $classes ),
446 $html = Html::rawElement(
'div', $attribs,
"\n$html\n" );
450 if ( !empty( $this->mParams[
'row-legend'] ) ) {
451 $legend = $this->
msg( $this->mParams[
'row-legend'] )->text();
461 foreach ( (array)$values as $key => $value ) {
462 if ( $key ===
'nonjs' ) {
465 $html .= Html::rawElement(
'li', [
'class' =>
'mw-htmlform-cloner-li' ],
471 $html = Html::rawElement(
'ul', [
472 'id' =>
"mw-htmlform-cloner-list-{$this->mID}",
473 'class' =>
'mw-htmlform-cloner-ul',
474 'data-template' => $template,
475 'data-unique-id' => $this->uniqueId,
479 $fieldHtml = $field->getInputOOUI( $field->getDefault() );
480 $fieldHtml->setInfusable(
true );