diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 498c490..3c5ea61 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1613,6 +1613,7 @@ function template_preprocess_field_multiple_value_form(&$variables) { 'class' => ['field-label'], ], t('Order', [], ['context' => 'Sort order']), + t('Remove', [], ['context' => 'Remove item']), ]; $rows = []; @@ -1634,19 +1635,23 @@ function template_preprocess_field_multiple_value_form(&$variables) { foreach ($items as $item) { $item['_weight']['#attributes']['class'] = [$order_class]; - // Remove weight form element from item render array so it can be rendered - // in a separate table column. + // Remove weight and remove form element from item render array so they + // can be rendered in a separate table columns. $delta_element = $item['_weight']; - unset($item['_weight']); + $remove_element = $item['_remove']; + unset($item['_weight'], $item['_remove']); $cells = [ ['data' => '', 'class' => ['field-multiple-drag']], ['data' => $item], ['data' => $delta_element, 'class' => ['delta-order']], + ['data' => $remove_element, 'class' => ['delta-remove']], ]; + $class = ['draggable']; + if (!empty($remove_element['#checked'])) $class[] = 'removed'; $rows[] = [ 'data' => $cells, - 'class' => ['draggable'], + 'class' => $class, ]; } diff --git a/core/lib/Drupal/Core/Field/WidgetBase.php b/core/lib/Drupal/Core/Field/WidgetBase.php index b1579f2..3bdab11 100644 --- a/core/lib/Drupal/Core/Field/WidgetBase.php +++ b/core/lib/Drupal/Core/Field/WidgetBase.php @@ -202,6 +202,22 @@ protected function formMultipleElements(FieldItemListInterface $items, array &$f '#default_value' => $items[$delta]->_weight ?: $delta, '#weight' => 100, ]; + + foreach (Element::children($element) as $key) { + $element[$key]['#states'] = [ + 'disabled' => [ + ':input[name="' . $field_name . '[' . $delta . '][_remove]"]' => ['checked' => TRUE], + ], + ]; + } + + $element['_remove'] = [ + '#title' => $this->t('Remove'), + '#title_display' => 'invisible', + '#type' => 'checkbox', + '#default_value' => $items[$delta]->_remove ?: FALSE, + '#weight' => 101, + ]; } $elements[$delta] = $element; @@ -353,6 +369,11 @@ public function extractFormValues(FieldItemListInterface $items, array $form, Fo // Remove the 'value' of the 'add more' button. unset($values['add_more']); + // Filter out removed items. + foreach ($values as $delta => $value) { + if (!empty($value['_remove'])) unset($values[$delta]); + } + // The original delta, before drag-and-drop reordering, is needed to // route errors to the correct form element. foreach ($values as $delta => &$value) { @@ -375,7 +396,7 @@ public function extractFormValues(FieldItemListInterface $items, array $form, Fo $field_state = static::getWidgetState($form['#parents'], $field_name, $form_state); foreach ($items as $delta => $item) { $field_state['original_deltas'][$delta] = isset($item->_original_delta) ? $item->_original_delta : $delta; - unset($item->_original_delta, $item->_weight); + unset($item->_original_delta, $item->_weight, $item->_remove); } static::setWidgetState($form['#parents'], $field_name, $form_state, $field_state); } diff --git a/core/misc/form.js b/core/misc/form.js index 7ca64fc..e1de89b 100644 --- a/core/misc/form.js +++ b/core/misc/form.js @@ -247,4 +247,44 @@ } }; + /** + * Initialize value remove checkboxes. + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches multipleRemove functionality. + */ + Drupal.behaviors.multipleRemove = { + attach: function (context, settings) { + $(context).find('table.field-multiple-table').each(Drupal.multipleRemove); + } + }; + + /** + * Callback used in {@link Drupal.behaviors.multipleRemove}. + */ + Drupal.multipleRemove = function () { + if ($(this).find('td.delta-remove input[type="checkbox"]').length === 0) { + return; + } + + // Keep track of the table, which checkbox is checked and alias the + // settings. + var table = this; + var checkboxes; + var $table = $(table); + + // For each of the checkboxes within the table that are not disabled. + checkboxes = $table.find('td.delta-remove input[type="checkbox"]:enabled').on('click', function (e) { + // Either add or remove the removed class based on the state of the + // check all checkbox. + + /** + * @this {HTMLElement} + */ + $(this).closest('tr').toggleClass('removed', this.checked); + }); + }; + })(jQuery, Drupal, Drupal.debounce);