diff -u b/core/lib/Drupal/Core/Field/WidgetBase.php b/core/lib/Drupal/Core/Field/WidgetBase.php
--- b/core/lib/Drupal/Core/Field/WidgetBase.php
+++ b/core/lib/Drupal/Core/Field/WidgetBase.php
@@ -148,7 +148,7 @@
switch ($cardinality) {
case FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED:
$field_state = static::getWidgetState($parents, $field_name, $form_state);
- $max = $field_state['items_count'];
+ $max = $field_state['items_count'] - 1;
$is_multiple = TRUE;
break;
@@ -163,7 +163,7 @@
$elements = [];
- for ($delta = 0; $delta < $max; $delta++) {
+ for ($delta = 0; $delta <= $max; $delta++) {
// Add a new empty item if it doesn't exist yet at this delta.
if (!isset($items[$delta])) {
$items->appendItem();
@@ -208,68 +208,66 @@
}
}
- if ($elements) {
- $elements += [
- '#theme' => 'field_multiple_value_form',
- '#field_name' => $field_name,
- '#cardinality' => $cardinality,
- '#cardinality_multiple' => $this->fieldDefinition->getFieldStorageDefinition()->isMultiple(),
- '#required' => $this->fieldDefinition->isRequired(),
- '#title' => $title,
- '#description' => $description,
- '#max_delta' => $max,
- ];
+ $elements += [
+ '#theme' => 'field_multiple_value_form',
+ '#field_name' => $field_name,
+ '#cardinality' => $cardinality,
+ '#cardinality_multiple' => $this->fieldDefinition->getFieldStorageDefinition()->isMultiple(),
+ '#required' => $this->fieldDefinition->isRequired(),
+ '#title' => $title,
+ '#description' => $description,
+ '#max_delta' => $max,
+ ];
+
+ // Add 'add more' button, if not working with a programmed form.
+ if ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && !$form_state->isProgrammed()) {
+ $id_prefix = implode('-', array_merge($parents, [$field_name]));
+ $wrapper_id = Html::getUniqueId($id_prefix . '-add-more-wrapper');
+ $form['#wrapper_id'] = $wrapper_id;
+ $elements['#prefix'] = '
';
+ foreach ($elements as $element) {
+ $elements['#prefix'] = '
';
$elements['#suffix'] = '
';
+ $elements['add_more']['#ajax']['wrapper'] = $form['#wrapper_id'];
+ }
- foreach ($elements as $element) {
- $elements['#prefix'] = '
';
- $elements['#suffix'] = '
';
- $elements['add_more']['#ajax']['wrapper'] = $form['#wrapper_id'];
- }
-
- $elements['add_more'] = [
- '#type' => 'submit',
- '#name' => strtr($id_prefix, '-', '_') . '_add_more',
- '#value' => t('Add another item'),
- '#attributes' => ['class' => ['field-add-more-submit']],
- '#limit_validation_errors' => [array_merge($parents, [$field_name])],
- '#submit' => [[get_class($this), 'addMoreSubmit']],
- '#ajax' => [
- 'callback' => [get_class($this), 'addMoreAjax'],
- 'wrapper' => $wrapper_id,
- 'effect' => 'fade',
- ],
- ];
+ $elements['add_more'] = [
+ '#type' => 'submit',
+ '#name' => strtr($id_prefix, '-', '_') . '_add_more',
+ '#value' => t('Add another item'),
+ '#attributes' => ['class' => ['field-add-more-submit']],
+ '#limit_validation_errors' => [array_merge($parents, [$field_name])],
+ '#submit' => [[get_class($this), 'addMoreSubmit']],
+ '#ajax' => [
+ 'callback' => [get_class($this), 'addMoreAjax'],
+ 'wrapper' => $wrapper_id,
+ 'effect' => 'fade',
+ ],
+ ];
- for ($delta = 0; $delta < $max; $delta++) {
- $elements[$delta]['actions'] = [
- '#type' => 'actions',
- 'remove_button' => [
- '#delta' => $delta,
- '#name' => implode('_', array_merge($elements[$delta]['#field_parents'], [$field_name, $delta])) . '_remove_button',
- '#type' => 'submit',
- '#value' => t('Remove'),
- '#validate' => [],
- '#submit' => [[$this, 'ajaxSubmitRemove']],
- '#limit_validation_errors' => [],
- '#attributes' => [
- 'class' => ['remove-field-delta--' . $delta],
- ],
- '#ajax' => [
- 'callback' => [$this, 'removeAjaxContentRefresh'],
- 'effect' => 'fade',
- 'wrapper' => $form['#wrapper_id'],
- ],
+ for ($delta = 0; $delta <= $max; $delta++) {
+ $elements[$delta]['actions'] = [
+ '#type' => 'actions',
+ 'remove_button' => [
+ '#delta' => $delta,
+ '#name' => implode('_', array_merge($elements[$delta]['#field_parents'], [$field_name, $delta])) . '_remove_button',
+ '#type' => 'submit',
+ '#value' => t('Remove'),
+ '#validate' => [],
+ '#submit' => [[$this, 'ajaxSubmitRemove']],
+ '#limit_validation_errors' => [],
+ '#attributes' => [
+ 'class' => ['remove-field-delta--' . $delta],
],
- ];
- }
+ '#ajax' => [
+ 'callback' => [$this, 'removeAjaxContentRefresh'],
+ 'effect' => 'fade',
+ 'wrapper' => $form['#wrapper_id'],
+ ],
+ ],
+ ];
}
}
@@ -342,7 +340,7 @@
*
* This re-numbers form elements and removes an item.
*/
- public function ajaxSubmitRemove($form, FormStateInterface $form_state) {
+ public function ajaxSubmitRemove(&$form, FormStateInterface $form_state) {
$button = $form_state->getTriggeringElement();
$delta = $button['#delta'];
$array_parents = array_slice($button['#array_parents'], 0, -4);
@@ -352,30 +350,29 @@
$parents = $parent_element['#field_parents'];
$field_state = static::getWidgetState($parents, $field_name, $form_state);
for ($i = $delta; $i < $field_state['items_count']; $i++) {
- $old_element_widget = array_merge($array_parents, ['widget', $i + 1]);
- $old_element = array_merge($old_parents, [$i + 1]);
- $new_element = array_merge($old_parents, [$i]);
- $moving_element = NestedArray::getValue($form, $old_element_widget);
- $moving_element_value = NestedArray::getValue($form_state->getValues(), $old_element);
- $moving_element_input = NestedArray::getValue($form_state->getUserInput(), $old_element);
+ $old_element_widget_parents = array_merge($array_parents, ['widget', $i + 1]);
+ $old_element_parents = array_merge($old_parents, [$i + 1]);
+ $new_element_parents = array_merge($old_parents, [$i]);
+ $moving_element = NestedArray::getValue($form, $old_element_widget_parents);
+ $moving_element_input = NestedArray::getValue($form_state->getUserInput(), $old_element_parents);
// Tell the element where it's being moved to.
- $moving_element['#parents'] = $new_element;
+ $moving_element['#parents'] = $new_element_parents;
// Move the element around.
- $form_state->setValueForElement($moving_element, $moving_element_value);
$user_input = $form_state->getUserInput();
NestedArray::setValue($user_input, $moving_element['#parents'], $moving_element_input);
$user_input[$field_name] = array_filter($user_input[$field_name]);
$form_state->setUserInput($user_input);
}
+ unset($parent_element[$delta]);
+ NestedArray::setValue($form, $array_parents, $parent_element);
- $weight_multiplier = 1;
if ($field_state['items_count'] > 0) {
- $weight_multiplier = $field_state['items_count'] - 1;
+ $field_state['items_count']--;
}
$input = NestedArray::getValue($form_state->getUserInput(), $array_parents);
- $weight = -1 * $weight_multiplier;
+ $weight = -1 * $field_state['items_count'];
foreach ($input as $key => $item) {
if ($item) {
$input[$key]['_weight'] = $weight++;
@@ -384,9 +381,8 @@
$user_input = $form_state->getUserInput();
NestedArray::setValue($user_input, $array_parents, $input);
$form_state->setUserInput($user_input);
-
static::setWidgetState($parents, $field_name, $form_state, $field_state);
-
+ $form_state->setRebuild();
}
/**
@@ -397,7 +393,7 @@
*/
public function removeAjaxContentRefresh(array &$form, FormStateInterface $form_state) {
$button = $form_state->getTriggeringElement();
- return NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -3));
+ return NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -4));
}
/**