You are here

protected function MediaForm::mediaElement in GridStack 8.2

Returns Media Library form elements adapted from MediaLibraryWidget.

1 call to MediaForm::mediaElement()
Form::styleForm in src/Plugin/gridstack/stylizer/Form.php

File

src/Plugin/gridstack/stylizer/MediaForm.php, line 273

Class

MediaForm
Provides the media form for Layout Builder integration.

Namespace

Drupal\gridstack\Plugin\gridstack\stylizer

Code

protected function mediaElement(array &$element, $optionset, FormStateInterface $form_state, array $settings, array $extras = []) {
  if (empty($settings['field_name'])) {
    return;
  }
  $data = [];
  $media = NULL;
  $context = $settings['_scope'];
  $delta = $settings['_delta'];
  $main = [
    'layout_settings',
    'settings',
    'styles',
  ];
  $extra = [
    'layout_settings',
    'regions',
    $context,
    'styles',
  ];
  $parents = $context == GridStackDefault::ROOT ? $main : $extra;

  // Add a button that will load the Media library in a modal using AJAX.
  // Create an ID suffix from the parents to make sure each widget is unique.
  $remaining = 1;
  $field_name = $settings['field_name'];
  $id_suffix = $parents ? '-' . implode('-', $parents) : '';
  $field_widget_id = implode(':', array_filter([
    $field_name,
    $id_suffix,
  ]));
  $wrapper_id = $field_name . '-media-library-wrapper' . $id_suffix;
  $view_builder = $this->manager
    ->getEntityTypeManager()
    ->getViewBuilder('media');
  $cardinality = $this
    ->getFieldCardinality($field_name);

  // Create a new media library URL with the correct state parameters.
  $allowed_media_type_ids = [
    'image',
    'remote_video',
    'video',
  ];
  $selected_type_id = reset($allowed_media_type_ids);
  $limit_validation_errors = [
    array_merge($parents, [
      $field_name,
    ]),
  ];

  // This particular media library opener needs some extra metadata.
  $opener_parameters = [
    'field_widget_id' => $field_widget_id,
    'entity_type_id' => $extras['entity_type_id'],
    'bundle' => $extras['bundle'],
    'field_name' => $field_name,
  ];
  $state = MediaLibraryState::create('media_library.opener.field_widget', $allowed_media_type_ids, $selected_type_id, $remaining, $opener_parameters);
  $form_state
    ->set('media_library_state', $state);
  $add = $this
    ->t('Add media');
  $mid = $this
    ->saveMediaId($settings, $form_state);
  $target_bundles = isset($this
    ->getFieldSettings($field_name)['target_bundles']) ? $this
    ->getFieldSettings($field_name)['target_bundles'] : [];
  $element += [
    '#type' => 'details',
    '#open' => TRUE,
    '#tree' => TRUE,
    '#title' => $this
      ->t('Styles'),
    '#cardinality' => $cardinality,
    '#delta' => $delta,
    '#target_bundles' => $target_bundles,
    '#attributes' => [
      'id' => $wrapper_id,
      'class' => [
        'js-media-library-widget',
        'form-wrapper--styles',
      ],
    ],
    '#attached' => [
      'library' => [
        'media_library/widget',
      ],
    ],
    '#parents' => $parents,
  ];
  if ($optionset
    ->isFramework()) {
    $element['#description'] = $this
      ->t('Requires <code>Min height</code> at <code>Preset classes</code>, else collapsed.');
  }

  // Do not use the global current_selection.
  $new_settings = self::getUserInputValues($element, $form_state);
  if ($new_settings) {
    $new_mid = $new_settings['media_library_selection'];
    if ($new_mid && $new_mid != $mid) {
      $mid = $new_mid;
    }
  }

  // This hidden field and button are used to add new items to the widget.
  $element['media_library_selection'] = [
    '#type' => 'hidden',
    '#attributes' => [
      // This is used to pass the selection from the modal to the widget.
      'data-media-library-widget-value' => $field_widget_id,
    ],
  ];
  if (empty($mid)) {
    $element['#attributes']['class'][] = 'ig-gs-media-empty';
  }
  $element['selection'] = [
    '#type' => 'container',
    '#theme_wrappers' => [
      'container__media_library_widget_selection',
    ],
    '#attributes' => [
      'class' => [
        'js-media-library-selection',
      ],
    ],
    '#prefix' => '<div class="form-wrapper form-wrapper--media">',
    '#field_name' => $field_name,
  ];
  $element['selection'][$delta] = [
    '#theme' => 'media_library_item__widget',
    '#attributes' => [
      'class' => [
        'js-media-library-item',
        'form-wrapper--media__item',
      ],
      'tabindex' => '-1',
      'data-media-library-item-delta' => $delta,
    ],
  ];
  $element['selection'][$delta]['#field_name'] = $field_name;
  $element['selection'][$delta]['thumbnail'] = [];
  if ($mid) {
    $add = $this
      ->t('Replace media');
    $media = Media::load($mid);
    $data = $this
      ->getMediaData($media);

    // @todo Make the view mode configurable.
    $element['selection'][$delta]['rendered_entity'] = $view_builder
      ->view($media, 'media_library');
    $element['selection'][$delta]['remove_button'] = [
      '#type' => 'submit',
      '#name' => $field_name . '-' . $delta . '-media-library-remove-button' . $id_suffix,
      '#value' => $this
        ->t('Remove'),
      '#media_id' => $media
        ->id(),
      '#attributes' => [
        'aria-label' => $this
          ->t('Remove @label', [
          '@label' => $media
            ->label(),
        ]),
        'class' => [
          'form-submit--gs-remove',
        ],
        'title' => $this
          ->t('Remove'),
      ],
      '#ajax' => [
        'callback' => [
          static::class,
          'updateWidget',
        ],
        'wrapper' => $wrapper_id,
        'progress' => [
          'type' => 'throbber',
          'message' => $this
            ->t('Removing @label.', [
            '@label' => $media
              ->label(),
          ]),
        ],
      ],
      '#submit' => [
        [
          static::class,
          'removeItem',
        ],
      ],
      // Prevent errors in other widgets from preventing removal.
      '#limit_validation_errors' => $limit_validation_errors,
    ];
  }
  $element['selection'][$delta]['target_id'] = [
    '#type' => 'hidden',
    '#default_value' => $mid,
    '#attributes' => [
      'data-gs-media-storage' => TRUE,
    ],
  ];

  // This hidden value can be toggled visible for accessibility.
  $element['selection'][$delta]['weight'] = [
    '#type' => 'number',
    '#theme' => 'input__number__media_library_item_weight',
    '#title' => $this
      ->t('Weight'),
    '#default_value' => $delta,
    '#attributes' => [
      'class' => [
        'js-media-library-item-weight',
      ],
    ],
  ];
  $element['open_button'] = [
    '#type' => 'button',
    '#value' => $add,
    '#name' => $field_name . '-media-library-open-button' . $id_suffix,
    '#attributes' => [
      'class' => [
        'js-media-library-open-button',
        'form-submit--gs-add-replace',
      ],
      // The jQuery UI dialog automatically moves focus to the first :tabbable
      // element of the modal, so we need to disable refocus on the button.
      'data-disable-refocus' => 'true',
    ],
    '#media_library_state' => $state,
    '#ajax' => [
      'callback' => [
        MediaLibraryWidget::class,
        'openMediaLibrary',
      ],
      'progress' => [
        'type' => 'throbber',
        'message' => $this
          ->t('Opening media library.'),
      ],
    ],
    // Allow the media library to be opened even if there are form errors.
    '#limit_validation_errors' => [],
    '#attached' => [
      'library' => [
        'media_library/widget',
      ],
    ],
  ];

  // When a selection is made this hidden button is pressed to add new media
  // items based on the "media_library_selection" value.
  $element['media_library_update_widget'] = [
    '#type' => 'submit',
    '#value' => $this
      ->t('Update widget'),
    '#name' => $field_name . '-media-library-update' . $id_suffix,
    '#ajax' => [
      'callback' => [
        static::class,
        'updateWidget',
      ],
      'wrapper' => $wrapper_id,
      'progress' => [
        'type' => 'throbber',
        'message' => $this
          ->t('Adding selection.'),
      ],
    ],
    '#attributes' => [
      'data-media-library-widget-update' => $field_widget_id,
      'class' => [
        'js-hide',
        'visually-hidden',
      ],
    ],
    // @todo '#validate' => [[MediaLibraryWidget::class, 'validateItems']],
    '#submit' => [
      [
        static::class,
        'addItems',
      ],
    ],
    // We need to prevent the widget from being validated when no media items
    // are selected. When a media field is added in a subform, entity
    // validation is triggered in EntityFormDisplay::validateFormValues().
    // Since the media item is not added to the form yet, this triggers errors
    // for required media fields.
    '#limit_validation_errors' => empty($mid) ? [] : $limit_validation_errors,
  ];
  $element['metadata'] = [
    '#type' => 'hidden',
    '#default_value' => $data ? Json::encode($data) : '',
    '#suffix' => '</div>',
  ];
}