Commit ca0ac736 authored by alexpott's avatar alexpott

Issue #3044649 by phenaproxima, seanB, Wim Leers, alexpott: Delegate media...

Issue #3044649 by phenaproxima, seanB, Wim Leers, alexpott: Delegate media library selection handling to the "thing" that opened the library
parent 09fdae11
......@@ -6,3 +6,9 @@ services:
class: Drupal\media_library\Routing\RouteSubscriber
tags:
- { name: event_subscriber }
media_library.opener_resolver:
class: Drupal\media_library\OpenerResolver
calls:
- [setContainer, ['@service_container']]
media_library.opener.field_widget:
class: Drupal\media_library\MediaLibraryFieldWidgetOpener
......@@ -16,7 +16,7 @@
use Drupal\media\MediaTypeInterface;
use Drupal\media_library\Ajax\UpdateSelectionCommand;
use Drupal\media_library\MediaLibraryUiBuilder;
use Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget;
use Drupal\media_library\OpenerResolverInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -57,6 +57,13 @@ abstract class AddFormBase extends FormBase {
*/
protected $viewBuilder;
/**
* The opener resolver.
*
* @var \Drupal\media_library\OpenerResolverInterface
*/
protected $openerResolver;
/**
* Constructs a AddFormBase object.
*
......@@ -64,11 +71,18 @@ abstract class AddFormBase extends FormBase {
* The entity type manager.
* @param \Drupal\media_library\MediaLibraryUiBuilder $library_ui_builder
* The media library UI builder.
* @param \Drupal\media_library\OpenerResolverInterface $opener_resolver
* The opener resolver.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, MediaLibraryUiBuilder $library_ui_builder) {
public function __construct(EntityTypeManagerInterface $entity_type_manager, MediaLibraryUiBuilder $library_ui_builder, OpenerResolverInterface $opener_resolver = NULL) {
$this->entityTypeManager = $entity_type_manager;
$this->libraryUiBuilder = $library_ui_builder;
$this->viewBuilder = $this->entityTypeManager->getViewBuilder('media');
if (!$opener_resolver) {
@trigger_error('The media_library.opener_resolver service must be passed to AddFormBase::__construct(), it is required before Drupal 9.0.0.', E_USER_DEPRECATED);
$opener_resolver = \Drupal::service('media_library.opener_resolver');
}
$this->openerResolver = $opener_resolver;
}
/**
......@@ -77,7 +91,8 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Med
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager'),
$container->get('media_library.ui_builder')
$container->get('media_library.ui_builder'),
$container->get('media_library.opener_resolver')
);
}
......@@ -247,7 +262,7 @@ protected function buildEntityFormElement(MediaInterface $media, array $form, Fo
// triggering element is not set correctly and the wrong media item is
// removed.
// @see ::removeButtonSubmit()
$parents = $form['#parents'];
$parents = isset($form['#parents']) ? $form['#parents'] : [];
$id_suffix = $parents ? '-' . implode('-', $parents) : '';
$element = [
......@@ -724,20 +739,18 @@ public function updateWidget(array &$form, FormStateInterface $form_state) {
return $form;
}
// Pass the selection to the field widget based on the current widget ID.
$opener_id = $this->getMediaLibraryState($form_state)->getOpenerId();
if ($field_id = MediaLibraryWidget::getOpenerFieldId($opener_id)) {
// The added media items get an ID when they are saved in ::submitForm().
// For that reason the added media items are keyed by delta in the form
// state and we have to do an array map to get each media ID.
$current_media_ids = array_map(function (MediaInterface $media) {
return $media->id();
}, $this->getCurrentMediaItems($form_state));
return (new AjaxResponse())
->addCommand(new InvokeCommand("[data-media-library-widget-value=\"$field_id\"]", 'val', [implode(',', $current_media_ids)]))
->addCommand(new InvokeCommand("[data-media-library-widget-update=\"$field_id\"]", 'trigger', ['mousedown']))
->addCommand(new CloseDialogCommand());
}
// The added media items get an ID when they are saved in ::submitForm().
// For that reason the added media items are keyed by delta in the form
// state and we have to do an array map to get each media ID.
$current_media_ids = array_map(function (MediaInterface $media) {
return $media->id();
}, $this->getCurrentMediaItems($form_state));
// Allow the opener service to respond to the selection.
$state = $this->getMediaLibraryState($form_state);
return $this->openerResolver->get($state)
->getSelectionResponse($state, $current_media_ids)
->addCommand(new CloseDialogCommand());
}
/**
......
......@@ -19,6 +19,7 @@
use Drupal\media\MediaInterface;
use Drupal\media\MediaTypeInterface;
use Drupal\media_library\MediaLibraryUiBuilder;
use Drupal\media_library\OpenerResolverInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -65,9 +66,11 @@ class FileUploadForm extends AddFormBase {
* The renderer service.
* @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system service.
* @param \Drupal\media_library\OpenerResolverInterface $opener_resolver
* The opener resolver.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, MediaLibraryUiBuilder $library_ui_builder, ElementInfoManagerInterface $element_info, RendererInterface $renderer, FileSystemInterface $file_system) {
parent::__construct($entity_type_manager, $library_ui_builder);
public function __construct(EntityTypeManagerInterface $entity_type_manager, MediaLibraryUiBuilder $library_ui_builder, ElementInfoManagerInterface $element_info, RendererInterface $renderer, FileSystemInterface $file_system, OpenerResolverInterface $opener_resolver = NULL) {
parent::__construct($entity_type_manager, $library_ui_builder, $opener_resolver);
$this->elementInfo = $element_info;
$this->renderer = $renderer;
$this->fileSystem = $file_system;
......@@ -82,7 +85,8 @@ public static function create(ContainerInterface $container) {
$container->get('media_library.ui_builder'),
$container->get('element_info'),
$container->get('renderer'),
$container->get('file_system')
$container->get('file_system'),
$container->get('media_library.opener_resolver')
);
}
......
......@@ -11,6 +11,7 @@
use Drupal\media\OEmbed\UrlResolverInterface;
use Drupal\media\Plugin\media\Source\OEmbedInterface;
use Drupal\media_library\MediaLibraryUiBuilder;
use Drupal\media_library\OpenerResolverInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -48,9 +49,11 @@ class OEmbedForm extends AddFormBase {
* The oEmbed URL resolver service.
* @param \Drupal\media\OEmbed\ResourceFetcherInterface $resource_fetcher
* The oEmbed resource fetcher service.
* @param \Drupal\media_library\OpenerResolverInterface $opener_resolver
* The opener resolver.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, MediaLibraryUiBuilder $library_ui_builder, UrlResolverInterface $url_resolver, ResourceFetcherInterface $resource_fetcher) {
parent::__construct($entity_type_manager, $library_ui_builder);
public function __construct(EntityTypeManagerInterface $entity_type_manager, MediaLibraryUiBuilder $library_ui_builder, UrlResolverInterface $url_resolver, ResourceFetcherInterface $resource_fetcher, OpenerResolverInterface $opener_resolver = NULL) {
parent::__construct($entity_type_manager, $library_ui_builder, $opener_resolver);
$this->urlResolver = $url_resolver;
$this->resourceFetcher = $resource_fetcher;
}
......@@ -63,7 +66,8 @@ public static function create(ContainerInterface $container) {
$container->get('entity_type.manager'),
$container->get('media_library.ui_builder'),
$container->get('media.oembed.url_resolver'),
$container->get('media.oembed.resource_fetcher')
$container->get('media.oembed.resource_fetcher'),
$container->get('media_library.opener_resolver')
);
}
......
<?php
namespace Drupal\media_library;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Session\AccountInterface;
/**
* The media library opener for field widgets.
*/
class MediaLibraryFieldWidgetOpener implements MediaLibraryOpenerInterface {
/**
* {@inheritdoc}
*/
public function checkAccess(MediaLibraryState $state, AccountInterface $account) {
throw new \Exception('Not yet implemented, see https://www.drupal.org/project/drupal/issues/3038254.');
}
/**
* {@inheritdoc}
*/
public function getSelectionResponse(MediaLibraryState $state, array $selected_ids) {
$response = new AjaxResponse();
$parameters = $state->getOpenerParameters();
if (empty($parameters['field_widget_id'])) {
throw new \InvalidArgumentException('field_widget_id parameter is missing.');
}
// Create a comma-separated list of media IDs, insert them in the hidden
// field of the widget, and trigger the field update via the hidden submit
// button.
$widget_id = $parameters['field_widget_id'];
$ids = implode(',', $selected_ids);
$response
->addCommand(new InvokeCommand("[data-media-library-widget-value=\"$widget_id\"]", 'val', [$ids]))
->addCommand(new InvokeCommand("[data-media-library-widget-update=\"$widget_id\"]", 'trigger', ['mousedown']));
return $response;
}
}
<?php
namespace Drupal\media_library;
use Drupal\Core\Session\AccountInterface;
/**
* Defines an interface for media library openers.
*
* Media library opener services allow modules to check access to the media
* library selection dialog and respond to selections. Example use cases that
* require different handling:
* - when used in an entity reference field widget;
* - when used in a text editor.
*
* Openers that require additional parameters or metadata should retrieve them
* from the MediaLibraryState object.
*
* @see \Drupal\media_library\MediaLibraryState
* @see \Drupal\media_library\MediaLibraryState::getOpenerParameters()
*/
interface MediaLibraryOpenerInterface {
/**
* Checks media library access.
*
* @param \Drupal\media_library\MediaLibraryState $state
* The media library.
* @param \Drupal\Core\Session\AccountInterface $account
* The user for which to check access.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*
* @see https://www.drupal.org/project/drupal/issues/3038254
*/
public function checkAccess(MediaLibraryState $state, AccountInterface $account);
/**
* Generates a response after selecting media items in the media library.
*
* @param \Drupal\media_library\MediaLibraryState $state
* The state the media library was in at the time of selection, allowing the
* response to be customized based on that state.
* @param int[] $selected_ids
* The IDs of the selected media items.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* The response to update the page after selecting media.
*/
public function getSelectionResponse(MediaLibraryState $state, array $selected_ids);
}
......@@ -12,14 +12,13 @@
* A value object for the media library state.
*
* When the media library is opened it needs several parameters to work
* properly. The parameters are retrieved from the MediaLibraryState value
* object. Since the parameters are passed via the URL, the value object is
* extended from ParameterBag. This also allows an opener to add extra
* parameters if needed. The following parameters are needed to open the media
* library:
* - media_library_opener_id: The opener ID is used to describe the "thing" that
* opened the media library. Most of the time this is going to be a form
* field.
* properly. These parameters are normally extracted from the current URL, then
* retrieved from and managed by the MediaLibraryState value object. The
* following parameters are required in order to open the media library:
* - media_library_opener_id: The ID of a container service which implements
* \Drupal\media_library\MediaLibraryOpenerInterface and is responsible for
* interacting with the media library on behalf of the "thing" (e.g., a field
* widget or text editor button) which opened it.
* - media_library_allowed_types: The media types available in the library can
* be restricted to a list of allowed types. This should be an array of media
* type IDs.
......@@ -31,6 +30,13 @@
* the number of remaining slots is a negative number, an unlimited amount of
* items can be selected.
*
* This object can also carry an optional opener-specific array of arbitrary
* values, under the media_library_opener_parameters key. These values are
* included in the hash generated by ::getHash(), so the end user cannot tamper
* with them either.
*
* @see \Drupal\media_library\MediaLibraryOpenerInterface
*
* @internal
* Media Library is an experimental module and its internal code may be
* subject to change in minor releases. External code should not instantiate
......@@ -42,9 +48,11 @@ class MediaLibraryState extends ParameterBag {
* {@inheritdoc}
*/
public function __construct(array $parameters = []) {
$this->validateParameters($parameters['media_library_opener_id'], $parameters['media_library_allowed_types'], $parameters['media_library_selected_type'], $parameters['media_library_remaining']);
$this->validateRequiredParameters($parameters['media_library_opener_id'], $parameters['media_library_allowed_types'], $parameters['media_library_selected_type'], $parameters['media_library_remaining']);
$parameters += [
'media_library_opener_parameters' => [],
];
parent::__construct($parameters);
// Add a hash to the state parameters.
$this->set('hash', $this->getHash());
}
......@@ -60,16 +68,19 @@ public function __construct(array $parameters = []) {
* @param int $remaining_slots
* The number of remaining items the user is allowed to select or add in the
* library.
* @param array $opener_parameters
* (optional) Any additional opener-specific parameter values.
*
* @return \Drupal\media_library\MediaLibraryState
* A state object.
*/
public static function create($opener_id, array $allowed_media_type_ids, $selected_type_id, $remaining_slots) {
public static function create($opener_id, array $allowed_media_type_ids, $selected_type_id, $remaining_slots, array $opener_parameters = []) {
$state = new static([
'media_library_opener_id' => $opener_id,
'media_library_allowed_types' => $allowed_media_type_ids,
'media_library_selected_type' => $selected_type_id,
'media_library_remaining' => $remaining_slots,
'media_library_opener_parameters' => $opener_parameters,
]);
return $state;
}
......@@ -95,7 +106,8 @@ public static function fromRequest(Request $request) {
$query->get('media_library_opener_id'),
$query->get('media_library_allowed_types', []),
$query->get('media_library_selected_type'),
$query->get('media_library_remaining')
$query->get('media_library_remaining'),
$query->get('media_library_opener_parameters', [])
);
// The request parameters need to contain a valid hash to prevent a
......@@ -112,10 +124,10 @@ public static function fromRequest(Request $request) {
}
/**
* Validate the required parameters for a new MediaLibraryState object.
* Validates the required parameters for a new MediaLibraryState object.
*
* @param string $opener_id
* The opener ID.
* The media library opener service ID.
* @param string[] $allowed_media_type_ids
* The allowed media type IDs.
* @param string $selected_type_id
......@@ -128,7 +140,7 @@ public static function fromRequest(Request $request) {
* If one of the passed arguments is missing or does not pass the
* validation.
*/
protected function validateParameters($opener_id, array $allowed_media_type_ids, $selected_type_id, $remaining_slots) {
protected function validateRequiredParameters($opener_id, array $allowed_media_type_ids, $selected_type_id, $remaining_slots) {
// The opener ID must be a non-empty string.
if (!is_string($opener_id) || empty(trim($opener_id))) {
throw new \InvalidArgumentException('The opener ID parameter is required and must be a string.');
......@@ -166,12 +178,14 @@ protected function validateParameters($opener_id, array $allowed_media_type_ids,
* The hashed parameters.
*/
public function getHash() {
// Create a hash from the required state parameters.
// Create a hash from the required state parameters and the serialized
// optional opener-specific parameters.
$hash = implode(':', [
$this->getOpenerId(),
implode(':', $this->getAllowedTypeIds()),
$this->getSelectedTypeId(),
$this->getAvailableSlots(),
serialize($this->getOpenerParameters()),
]);
return Crypt::hmacBase64($hash, \Drupal::service('private_key')->get() . Settings::getHashSalt());
......@@ -191,10 +205,10 @@ public function isValidHash($hash) {
}
/**
* Returns the ID of the opener of the media library.
* Returns the ID of the media library opener service.
*
* @return string
* The opener ID.
* The media library opener service ID.
*/
public function getOpenerId() {
return $this->get('media_library_opener_id');
......@@ -244,4 +258,14 @@ public function getAvailableSlots() {
return $this->getInt('media_library_remaining');
}
/**
* Returns all opener-specific parameter values.
*
* @return array
* An associative array of all opener-specific parameter values.
*/
public function getOpenerParameters() {
return $this->get('media_library_opener_parameters', []);
}
}
......@@ -224,7 +224,7 @@ protected function buildMediaTypeMenu(MediaLibraryState $state) {
$selected_type_id = $state->getSelectedTypeId();
foreach ($allowed_types as $allowed_type_id => $allowed_type) {
$link_state = MediaLibraryState::create($state->getOpenerId(), $state->getAllowedTypeIds(), $allowed_type_id, $state->getAvailableSlots());
$link_state = MediaLibraryState::create($state->getOpenerId(), $state->getAllowedTypeIds(), $allowed_type_id, $state->getAvailableSlots(), $state->getOpenerParameters());
// Add the 'media_library_content' parameter so the response will contain
// only the updated content for the tab.
// @see self::buildUi()
......
<?php
namespace Drupal\media_library;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
/**
* Defines a class to get media library openers from the container.
*
* This is intended to be a very thin interface-verifying wrapper around
* services which implement \Drupal\media_library\MediaLibraryOpenerInterface.
* It is not an API and should not be extended or used by code that does not
* interact with the Media Library module.
*/
class OpenerResolver implements OpenerResolverInterface {
use ContainerAwareTrait;
/**
* {@inheritdoc}
*/
public function get(MediaLibraryState $state) {
$service_id = $state->getOpenerId();
$service = $this->container->get($service_id);
if ($service instanceof MediaLibraryOpenerInterface) {
return $service;
}
throw new \RuntimeException("$service_id must be an instance of " . MediaLibraryOpenerInterface::class);
}
}
<?php
namespace Drupal\media_library;
/**
* Defines an interface to get a media library opener from the container.
*
* This is intended to be a very thin interface-verifying wrapper around
* services which implement \Drupal\media_library\MediaLibraryOpenerInterface.
* It is not an API and should not be extended or used by code that does not
* interact with the Media Library module.
*/
interface OpenerResolverInterface {
/**
* Gets a media library opener service from the container.
*
* @param \Drupal\media_library\MediaLibraryState $state
* A value object representing the state of the media library.
*
* @return \Drupal\media_library\MediaLibraryOpenerInterface
* The media library opener service.
*
* @throws \RuntimeException
* If the requested opener service does not implement
* \Drupal\media_library\MediaLibraryOpenerInterface.
*/
public function get(MediaLibraryState $state);
}
......@@ -67,13 +67,6 @@ class MediaLibraryWidget extends WidgetBase implements ContainerFactoryPluginInt
*/
protected $moduleHandler;
/**
* The prefix to use with a field ID for media library opener IDs.
*
* @var string
*/
protected static $openerIdPrefix = 'field:';
/**
* Constructs a MediaLibraryWidget widget.
*
......@@ -90,9 +83,9 @@ class MediaLibraryWidget extends WidgetBase implements ContainerFactoryPluginInt
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* Entity type manager service.
* @param \Drupal\Core\Session\AccountInterface $current_user
* (optional) The current active user.
* The current active user.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* (optional) The module handler.
* The module handler.
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, EntityTypeManagerInterface $entity_type_manager, AccountInterface $current_user = NULL, ModuleHandlerInterface $module_handler = NULL) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
......@@ -142,7 +135,7 @@ public static function defaultSettings() {
}
/**
* Get the enabled media type IDs sorted by weight.
* Gets the enabled media type IDs sorted by weight.
*
* @return string[]
* The media type IDs sorted by weight.
......@@ -309,7 +302,9 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
$view_builder = $this->entityTypeManager->getViewBuilder('media');
$field_name = $this->fieldDefinition->getName();
$parents = $form['#parents'];
// Create an ID suffix from the parents to make sure each widget is unique.
$id_suffix = $parents ? '-' . implode('-', $parents) : '';
$field_widget_id = implode(':', array_filter([$field_name, $id_suffix]));
$wrapper_id = $field_name . '-media-library-wrapper' . $id_suffix;
$limit_validation_errors = [array_merge($parents, [$field_name])];
......@@ -463,11 +458,13 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
// Create a new media library URL with the correct state parameters.
$selected_type_id = reset($allowed_media_type_ids);
$remaining = $cardinality_unlimited ? FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED : $remaining;
// The opener ID is used by the select form and the upload form to add the
// selected/uploaded media items to the widget.
$opener_id = static::$openerIdPrefix . $field_name . $id_suffix;
$state = MediaLibraryState::create($opener_id, $allowed_media_type_ids, $selected_type_id, $remaining);
// This particular media library opener needs some extra metadata for its
// \Drupal\media_library\MediaLibraryOpenerInterface::getSelectionResponse()
// to be able to target the element whose 'data-media-library-widget-value'
// attribute is the same as $field_widget_id.
$state = MediaLibraryState::create('media_library.opener.field_widget', $allowed_media_type_ids, $selected_type_id, $remaining, [
'field_widget_id' => $field_widget_id,
]);
// Add a button that will load the Media library in a modal using AJAX.
$element['media_library_open_button'] = [
......@@ -512,7 +509,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
'#type' => 'hidden',
'#attributes' => [
// This is used to pass the selection from the modal to the widget.
'data-media-library-widget-value' => $field_name . $id_suffix,
'data-media-library-widget-value' => $field_widget_id,
],
];
......@@ -531,7 +528,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
],
],
'#attributes' => [
'data-media-library-widget-update' => $field_name . $id_suffix,
'data-media-library-widget-update' => $field_widget_id,
'class' => ['js-hide'],
],
'#validate' => [[static::class, 'validateItems']],
......@@ -886,23 +883,4 @@ protected static function setFieldState(array $element, FormStateInterface $form
static::setWidgetState($element['#field_parents'], $element['#field_name'], $form_state, $field_state);
}
/**
* Get the field ID of the widget from an opener ID.
*
* @param string $opener_id
* The opener ID of the media library.
*
* @return string|null
* The field ID or NULL if the opener ID is not valid for the widget.
*
* @see \Drupal\media_library\MediaLibraryState
*/
public static function getOpenerFieldId($opener_id) {
// Media library widget opener IDs are always prefixed with 'field:' in .
if (preg_match('/^' . static::$openerIdPrefix . '([a-z0-9_-]+)$/', $opener_id, $matches)) {
return $matches[1];
}
return NULL;
}
}
......@@ -2,17 +2,15 @@
namespace Drupal\media_library\Plugin\views\field;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\CloseDialogCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\media_library\MediaLibraryState;
use Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\Render\ViewsRenderPipelineMarkup;
use Drupal\views\ResultRow;
use Symfony\Component\HttpFoundation\Request;
/**
* Defines a field that outputs a checkbox and form for selecting media.
......@@ -53,10 +51,6 @@ public function viewsForm(array &$form, FormStateInterface $form_state) {
'class' => ['media-library-views-form', 'js-media-library-views-form'],
];
// Add the view to the form state so the opener ID can be fetched from the
// view request object in ::updateWidget().
$form_state->set('view', $this->view);
// Render checkboxes for all rows.
$form[$this->options['id']]['#tree'] = TRUE;
foreach ($this->view->result as $row_index => $row) {
......@@ -120,27 +114,24 @@ public function viewsForm(array &$form, FormStateInterface $form_state) {
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* A command to send the selection to the current field widget.
*/
public static function updateWidget(array &$form, FormStateInterface $form_state) {
public static function updateWidget(array &$form, FormStateInterface $form_state, Request $request) {
$field_id = $form_state->getTriggeringElement()['#field_id'];
$selected = array_filter(explode(',', $form_state->getValue($field_id, [])));
$response = new AjaxResponse();
$response->addCommand(new CloseDialogCommand());
$selected_ids = $form_state->getValue($field_id);
$selected_ids = $selected_ids ? array_filter(explode(',', $selected_ids)) : [];
$ids = implode(',', $selected);
$opener_id = MediaLibraryState::fromRequest($form_state->get('view')->getRequest())->getOpenerId();
if ($field_id = MediaLibraryWidget::getOpenerFieldId($opener_id)) {
$response
->addCommand(new InvokeCommand("[data-media-library-widget-value=\"$field_id\"]", 'val', [$ids]))
->addCommand(new InvokeCommand("[data-media-library-widget-update=\"$field_id\"]", 'trigger', ['mousedown']));
}
// Allow the opener service to handle the selection.
$state = MediaLibraryState::fromRequest($request);
return $response;
return \Drupal::service('media_library.opener_resolver')
->get($state)
->getSelectionResponse($state, $selected_ids)
->addCommand(new CloseDialogCommand());
}
/**
......
......@@ -354,4 +354,14 @@ public function providerFromRequest() {
return $test_data;
}
/**
* @covers ::getOpenerParameters
*/
public function testOpenerParameters() {
$state = MediaLibraryState::create('test', ['file'], 'file', -1, [
'foo' => 'baz',
]);
$this->assertSame(['foo' => 'baz'], $state->getOpenerParameters());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment