You are here

media_library_edit.module in Media Library Edit 8.2

Same filename and directory in other branches
  1. 8 media_library_edit.module

File

media_library_edit.module
View source
<?php

/**
 * @file
 * Contains media_library_edit.module.
 */
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\BeforeCommand;
use Drupal\Core\Ajax\CloseDialogCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\WidgetInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\media_library\MediaLibraryUiBuilder;

/**
 * Implements hook_help().
 */
function media_library_edit_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {

    // Main module help for the media_library_edit module.
    case 'help.page.media_library_edit':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Add an edit button to the Media Library widget when an item is selected.') . '</p>';
      return $output;
    default:
  }
}

/**
 * Implements hook_field_widget_settings_summary_alter().
 */
function media_library_edit_field_widget_settings_summary_alter(&$summary, $context) {
  $plugin_id = $context['widget']
    ->getPluginId();
  if ($plugin_id == 'media_library_widget') {
    $settings = $context['widget']
      ->getThirdPartySettings('media_library_edit');
    if (isset($settings['show_edit']) && $settings['show_edit']) {
      $summary[] = t('Show edit button');
    }
  }
}

/**
 * Implements hook_field_widget_third_party_settings_form().
 */
function media_library_edit_field_widget_third_party_settings_form(WidgetInterface $plugin, FieldDefinitionInterface $field_definition, $form_mode, $form, FormStateInterface $form_state) {
  $element = [];
  $plugin_id = $plugin
    ->getPluginId();
  if ($plugin_id == 'media_library_widget') {
    $settings = $plugin
      ->getThirdPartySettings('media_library_edit');
    $element['show_edit'] = [
      '#type' => 'checkbox',
      '#title' => t('Show edit button'),
      '#default_value' => isset($settings['show_edit']) ? $settings['show_edit'] : '',
    ];
  }
  return $element;
}

/**
 * Implements hook_field_widget_form_alter().
 */
function media_library_edit_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
  $plugin_id = $context['widget']
    ->getPluginId();
  if ($plugin_id == 'media_library_widget') {
    $settings = $context['widget']
      ->getThirdPartySettings('media_library_edit');
    if (isset($settings['show_edit']) && $settings['show_edit']) {
      if (isset($context['items'])) {

        // Gets the first referenced entity.
        // Doesn't matter which one, we just need the media edit template.
        if ($media = $context['items']->entity) {
          if ($media
            ->access('update') && ($edit_template = $media
            ->getEntityType()
            ->getLinkTemplate('edit-form'))) {
            $element['#attributes']['class'][] = 'js-media-library-edit-' . Html::cleanCssIdentifier($context['items']
              ->getFieldDefinition()
              ->getName()) . '-wrapper';
            foreach (Element::children($element['selection']) as $key) {
              $entity = $context['items']
                ->getEntity();
              if (!$entity || !$entity
                ->id()) {

                // Bail out if parent entity is not yet saved.
                return;
              }
              $edit_url_query_params = [
                'media_library_edit' => 'ajax',
                'media_library_edit_field_name' => $context['items']
                  ->getFieldDefinition()
                  ->getName(),
                'media_library_edit_entity_type' => $entity
                  ->getEntityTypeId(),
                'media_library_edit_entity_id' => $entity
                  ->id(),
              ];
              $edit_url = Url::fromUserInput(str_replace('{media}', $element['selection'][$key]['target_id']['#value'], $edit_template) . '?' . UrlHelper::buildQuery($edit_url_query_params));
              $dialog_options = MediaLibraryUiBuilder::dialogOptions();
              $element['selection'][$key]['media_edit'] = [
                '#type' => 'link',
                '#title' => t('Edit media item'),
                '#url' => $edit_url,
                '#attributes' => [
                  'class' => [
                    'js-media-library-edit-link',
                    'media-library-edit__link',
                    'use-ajax',
                  ],
                  'target' => '_blank',
                  'data-dialog-options' => json_encode([
                    'height' => $dialog_options['height'],
                    'width' => $dialog_options['width'],
                    'classes' => [
                      'ui-dialog-content' => 'media-library-edit__modal',
                    ],
                  ]),
                  'data-dialog-type' => 'dialog',
                ],
                '#attached' => [
                  'library' => [
                    'media_library_edit/admin',
                    'core/drupal.dialog.ajax',
                  ],
                ],
              ];
            }
          }
        }
      }
    }
  }
}

/**
 * Implements hook_form_alter().
 */
function media_library_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if (\Drupal::request()->query
    ->get('media_library_edit') === 'ajax') {

    // Remove delete.
    $form['actions']['delete']['#access'] = FALSE;

    // Modify the save action to make sure the dialog closes.
    unset($form['actions']['submit']['#submit']);
    $form['actions']['submit']['#ajax'] = [
      'callback' => '_media_library_edit_media_edit_save',
      'event' => 'click',
      'disable-refocus' => TRUE,
    ];
  }
}

/**
 * Callback for ajax media form above.
 */
function _media_library_edit_media_edit_save(array &$form, FormStateInterface $form_state) {
  $response = new AjaxResponse();
  $media_form = $form_state
    ->getFormObject();
  if (!$form_state
    ->hasAnyErrors()) {

    // Run the (inherited) media save callbacks.
    $media_form
      ->submitForm($form, $form_state);
    $media = $media_form
      ->getEntity();
    if ($media
      ->save()) {

      // Close the dialog.
      $response
        ->addCommand(new CloseDialogCommand('.media-library-edit__modal'));

      // Figure out the media item field name and the form structure from the request.
      $field_name = \Drupal::request()->query
        ->get('media_library_edit_field_name');
      $entity_type = \Drupal::request()->query
        ->get('media_library_edit_entity_type');
      $entity_id = \Drupal::request()->query
        ->get('media_library_edit_entity_id');
      $entity = \Drupal::entityTypeManager()
        ->getStorage($entity_type)
        ->load($entity_id);

      // Get an array of target_ids from field. This way we can target which index
      // should be updated.
      $referenced_media_ids = array_column($entity->{$field_name}
        ->getValue(), 'target_id');
      if ($entity) {

        // Update the value of the media field's reference to the media entity.
        // This new value will be saved to the parent entity when the entity is saved in the UI.
        // Get key of media entity we're changing.
        $key = array_search($media
          ->id(), $referenced_media_ids);

        // Update only that entity. Resetting value of the entire field will cause other
        // items referenced to disappear from the form display.
        $entity->{$field_name}[$key] = $media
          ->id();
        $form = \Drupal::service('entity.form_builder')
          ->getForm($entity);

        // Re-render the widget markup.
        $widget = $form[$field_name]['widget'];
        $markup = \Drupal::service('renderer')
          ->renderRoot($widget);

        // Replace the widget container on the form.
        $widget_class = '.js-media-library-edit-' . Html::cleanCssIdentifier($field_name) . '-wrapper';
        $response
          ->addCommand(new ReplaceCommand($widget_class, $markup));
      }
    }
  }
  else {
    $message = [
      '#type' => 'status_messages',
    ];
    $response
      ->addCommand(new BeforeCommand('form', $message));
  }
  return $response;
}