You are here

public static function MediaLibraryWidget::updateWidget in Drupal 9

Same name and namespace in other branches
  1. 8 core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php \Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget::updateWidget()

AJAX callback to update the widget when the selection changes.

Parameters

array $form: The form array.

\Drupal\Core\Form\FormStateInterface $form_state: The form state.

Return value

\Drupal\Core\Ajax\AjaxResponse An AJAX response to update the selection.

File

core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php, line 664

Class

MediaLibraryWidget
Plugin implementation of the 'media_library_widget' widget.

Namespace

Drupal\media_library\Plugin\Field\FieldWidget

Code

public static function updateWidget(array $form, FormStateInterface $form_state) {
  $triggering_element = $form_state
    ->getTriggeringElement();
  $wrapper_id = $triggering_element['#ajax']['wrapper'];

  // This callback is either invoked from the remove button or the update
  // button, which have different nesting levels.
  $is_remove_button = end($triggering_element['#parents']) === 'remove_button';
  $length = $is_remove_button ? -3 : -1;
  if (count($triggering_element['#array_parents']) < abs($length)) {
    throw new \LogicException('The element that triggered the widget update was at an unexpected depth. Triggering element parents were: ' . implode(',', $triggering_element['#array_parents']));
  }
  $parents = array_slice($triggering_element['#array_parents'], 0, $length);
  $element = NestedArray::getValue($form, $parents);

  // Always clear the textfield selection to prevent duplicate additions.
  $element['media_library_selection']['#value'] = '';
  $field_state = static::getFieldState($element, $form_state);

  // Announce the updated content to screen readers.
  if ($is_remove_button) {
    $announcement = t('@label has been removed.', [
      '@label' => Media::load($field_state['removed_item_id'])
        ->label(),
    ]);
  }
  else {
    $new_items = count(static::getNewMediaItems($element, $form_state));
    $announcement = \Drupal::translation()
      ->formatPlural($new_items, 'Added one media item.', 'Added @count media items.');
  }
  $response = new AjaxResponse();
  $response
    ->addCommand(new ReplaceCommand("#{$wrapper_id}", $element));
  $response
    ->addCommand(new AnnounceCommand($announcement));

  // When the remove button is clicked, shift focus to the next remove button.
  // When the last item is deleted, we no longer have a selection and shift
  // the focus to the open button.
  $removed_last = $is_remove_button && !count($field_state['items']);
  if ($is_remove_button && !$removed_last) {

    // Find the next media item by weight. The weight of the removed item is
    // added to the field state when it is removed in ::removeItem(). If there
    // is no item with a bigger weight, we automatically shift the focus to
    // the previous media item.
    // @see ::removeItem()
    $removed_item_weight = $field_state['removed_item_weight'];
    $delta_to_focus = 0;
    foreach ($field_state['items'] as $delta => $item_fields) {
      $delta_to_focus = $delta;
      if ($item_fields['weight'] > $removed_item_weight) {

        // Stop directly when we find an item with a bigger weight. We also
        // have to subtract 1 from the delta in this case, since the delta's
        // are renumbered when rebuilding the form.
        $delta_to_focus--;
        break;
      }
    }
    $response
      ->addCommand(new InvokeCommand("#{$wrapper_id} [data-media-library-item-delta={$delta_to_focus}]", 'focus'));
  }
  elseif ($removed_last || !$is_remove_button && !isset($element['open_button']['#attributes']['data-disabled-focus'])) {
    $response
      ->addCommand(new InvokeCommand("#{$wrapper_id} .js-media-library-open-button", 'focus'));
  }
  return $response;
}