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'] = '
'; + $elements['#suffix'] = '
'; - // 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)); } /**