class MediaDirectoriesLibraryWidget in Media Directories 3.x
Plugin implementation of the 'media_directories_library_widget' widget.
Plugin annotation
@FieldWidget(
id = "media_directories_library_widget",
label = @Translation("Media Directories library"),
description = @Translation("Allows you to select items from the media library."),
field_types = {
"entity_reference"
},
multiple_values = TRUE,
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\Core\Field\PluginSettingsBase implements DependentPluginInterface, PluginSettingsInterface
- class \Drupal\Core\Field\WidgetBase implements WidgetInterface, ContainerFactoryPluginInterface
- class \Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget implements TrustedCallbackInterface
- class \Drupal\media_directories_ui\Plugin\Field\FieldWidget\MediaDirectoriesLibraryWidget
- class \Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget implements TrustedCallbackInterface
- class \Drupal\Core\Field\WidgetBase implements WidgetInterface, ContainerFactoryPluginInterface
- class \Drupal\Core\Field\PluginSettingsBase implements DependentPluginInterface, PluginSettingsInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of MediaDirectoriesLibraryWidget
File
- modules/
media_directories_ui/ src/ Plugin/ Field/ FieldWidget/ MediaDirectoriesLibraryWidget.php, line 29
Namespace
Drupal\media_directories_ui\Plugin\Field\FieldWidgetView source
class MediaDirectoriesLibraryWidget extends MediaLibraryWidget {
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return [
'media_types' => [],
] + parent::defaultSettings();
}
/**
* Gets the enabled media type IDs sorted by weight.
*
* @return string[]
* The media type IDs sorted by weight.
*/
protected function getAllowedMediaTypeIdsSorted() {
// Get the media type IDs sorted by the user in the settings form.
$sorted_media_type_ids = $this
->getSetting('media_types');
// Get the configured media types from the field storage.
$handler_settings = $this
->getFieldSetting('handler_settings');
// The target bundles will be blank when saving field storage settings,
// when first adding a media reference field.
$allowed_media_type_ids = isset($handler_settings['target_bundles']) ? $handler_settings['target_bundles'] : NULL;
// When there are no allowed media types, return the empty array.
if ($allowed_media_type_ids === []) {
return $allowed_media_type_ids;
}
// When no target bundles are configured for the field, all are allowed.
if ($allowed_media_type_ids === NULL) {
$allowed_media_type_ids = $this->entityTypeManager
->getStorage('media_type')
->getQuery()
->execute();
}
// When the user did not sort the media types, return the media type IDs
// configured for the field.
if (empty($sorted_media_type_ids)) {
return $allowed_media_type_ids;
}
// Some of the media types may no longer exist, and new media types may have
// been added that we don't yet know about. We need to make sure new media
// types are added to the list and remove media types that are no longer
// configured for the field.
$new_media_type_ids = array_diff($allowed_media_type_ids, $sorted_media_type_ids);
// Add new media type IDs to the list.
$sorted_media_type_ids = array_merge($sorted_media_type_ids, array_values($new_media_type_ids));
// Remove media types that are no longer available.
$sorted_media_type_ids = array_intersect($sorted_media_type_ids, $allowed_media_type_ids);
// Make sure the keys are numeric.
return array_values($sorted_media_type_ids);
}
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
/** @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $items */
$referenced_entities = $items
->referencedEntities();
$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,
]),
];
$settings = $this
->getFieldSetting('handler_settings');
$element += [
'#type' => 'fieldset',
'#cardinality' => $this->fieldDefinition
->getFieldStorageDefinition()
->getCardinality(),
'#target_bundles' => isset($settings['target_bundles']) ? $settings['target_bundles'] : FALSE,
'#attributes' => [
'id' => $wrapper_id,
'class' => [
'media-library-widget',
],
],
'#attached' => [
'library' => [
'media_library/widget',
],
],
];
// When the list of allowed types in the field configuration is null,
// ::getAllowedMediaTypeIdsSorted() returns all existing media types. When
// the list of allowed types is an empty array, we show a message to users
// and ask them to configure the field if they have access.
$allowed_media_type_ids = $this
->getAllowedMediaTypeIdsSorted();
if (!$allowed_media_type_ids) {
$element['no_types_message'] = [
'#markup' => $this
->getNoMediaTypesAvailableMessage(),
];
return $element;
}
if (empty($referenced_entities)) {
$element['empty_selection'] = [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => $this
->t('No media items are selected.'),
'#attributes' => [
'class' => [
'media-library-widget-empty-text',
],
],
];
}
else {
$element['weight_toggle'] = [
'#type' => 'html_tag',
'#tag' => 'button',
'#value' => $this
->t('Show media item weights'),
'#attributes' => [
'class' => [
'link',
'media-library-widget__toggle-weight',
'js-media-library-widget-toggle-weight',
],
],
];
}
$element['selection'] = [
'#type' => 'container',
'#attributes' => [
'class' => [
'js-media-library-selection',
'media-library-selection',
],
],
];
foreach ($referenced_entities as $delta => $media_item) {
$element['selection'][$delta] = [
'#type' => 'container',
'#attributes' => [
'class' => [
'media-library-item',
'media-library-item--grid',
'js-media-library-item',
],
// Add the tabindex '-1' to allow the focus to be shifted to the next
// media item when an item is removed. We set focus to the container
// because we do not want to set focus to the remove button
// automatically.
// @see ::updateWidget()
'tabindex' => '-1',
// Add a data attribute containing the delta to allow us to easily
// shift the focus to a specific media item.
// @see ::updateWidget()
'data-media-library-item-delta' => $delta,
],
'preview' => [
'#type' => 'container',
'remove_button' => [
'#type' => 'submit',
'#name' => $field_name . '-' . $delta . '-media-library-remove-button' . $id_suffix,
'#value' => $this
->t('Remove'),
'#media_id' => $media_item
->id(),
'#attributes' => [
'class' => [
'media-library-item__remove',
],
'aria-label' => $this
->t('Remove @label', [
'@label' => $media_item
->label(),
]),
],
'#ajax' => [
'callback' => [
static::class,
'updateWidget',
],
'wrapper' => $wrapper_id,
'progress' => [
'type' => 'throbber',
'message' => $this
->t('Removing @label.', [
'@label' => $media_item
->label(),
]),
],
],
'#submit' => [
[
static::class,
'removeItem',
],
],
// Prevent errors in other widgets from preventing removal.
'#limit_validation_errors' => $limit_validation_errors,
],
// @todo Make the view mode configurable in https://www.drupal.org/project/drupal/issues/2971209
'rendered_entity' => $view_builder
->view($media_item, 'media_library'),
],
'target_id' => [
'#type' => 'hidden',
'#value' => $media_item
->id(),
],
// This hidden value can be toggled visible for accessibility.
'weight' => [
'#type' => 'number',
'#title' => $this
->t('Weight'),
'#default_value' => $delta,
'#attributes' => [
'class' => [
'js-media-library-item-weight',
'media-library-item__weight',
],
],
],
];
}
$cardinality_unlimited = $element['#cardinality'] === FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED;
$remaining = $element['#cardinality'] - count($referenced_entities);
// Inform the user of how many items are remaining.
if (!$cardinality_unlimited) {
if ($remaining) {
$cardinality_message = $this
->formatPlural($remaining, 'One media item remaining.', '@count media items remaining.');
}
else {
$cardinality_message = $this
->t('The maximum number of media items have been selected.');
}
// Add a line break between the field message and the cardinality message.
if (!empty($element['#description'])) {
$element['#description'] .= '<br />';
}
$element['#description'] .= $cardinality_message;
}
// 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;
// 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. The entity ID, entity type ID,
// bundle, field name are used for access checking.
$entity = $items
->getEntity();
$opener_parameters = [
'field_widget_id' => $field_widget_id,
'entity_type_id' => $entity
->getEntityTypeId(),
'bundle' => $entity
->bundle(),
'field_name' => $field_name,
];
// Only add the entity ID when we actually have one. The entity ID needs to
// be a string to ensure that the media library state generates its
// tamper-proof hash in a consistent way.
if (!$entity
->isNew()) {
$opener_parameters['entity_id'] = (string) $entity
->id();
}
$state = MediaDirectoriesLibraryState::create('media_library.opener.field_widget', $allowed_media_type_ids, $selected_type_id, $remaining, $opener_parameters, MEDIA_DIRECTORY_ROOT);
// Add a button that will load the Media library in a modal using AJAX.
$element['media_library_open_button'] = [
'#type' => 'submit',
'#value' => $this
->t('Add media'),
'#name' => $field_name . '-media-library-open-button' . $id_suffix,
'#attributes' => [
'class' => [
'media-library-open-button',
'js-media-library-open-button',
],
// 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' => [
static::class,
'openMediaLibrary',
],
'progress' => [
'type' => 'throbber',
'message' => $this
->t('Opening media library.'),
],
],
'#submit' => [],
// Allow the media library to be opened even if there are form errors.
'#limit_validation_errors' => [],
];
// When the user returns from the modal to the widget, we want to shift the
// focus back to the open button. If the user is not allowed to add more
// items, the button needs to be disabled. Since we can't shift the focus to
// disabled elements, the focus is set back to the open button via
// JavaScript by adding the 'data-disabled-focus' attribute.
// @see Drupal.behaviors.MediaLibraryWidgetDisableButton
if (!$cardinality_unlimited && $remaining === 0) {
$element['media_library_open_button']['#attributes']['data-disabled-focus'] = 'true';
$element['media_library_open_button']['#attributes']['class'][] = 'visually-hidden';
}
// 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,
],
];
// 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',
],
],
'#validate' => [
[
static::class,
'validateItems',
],
],
'#submit' => [
[
static::class,
'addItems',
],
],
// Prevent errors in other widgets from preventing updates.
'#limit_validation_errors' => $limit_validation_errors,
];
return $element;
}
/**
* AJAX callback to open the library modal.
*
* @param array $form
* The form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* An AJAX response to open the media library.
*/
public static function openMediaLibrary(array $form, FormStateInterface $form_state) {
$triggering_element = $form_state
->getTriggeringElement();
$library_ui = \Drupal::service('media_directories_ui.ui_builder')
->buildUi($triggering_element['#media_library_state']);
$dialog_options = MediaDirectoriesLibraryUiBuilder::dialogOptions();
return (new AjaxResponse())
->addCommand(new OpenModalDialogCommand($dialog_options['title'], $library_ui, $dialog_options));
}
/**
* Gets newly selected media items.
*
* @param array $element
* The wrapping element for this widget.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* @return \Drupal\media\MediaInterface[]
* An array of selected media items.
*/
protected static function getNewMediaItems(array $element, FormStateInterface $form_state) {
// Get the new media IDs passed to our hidden button.
$values = $form_state
->getValues();
$path = $element['#parents'];
$value = NestedArray::getValue($values, $path);
if (!empty($value['media_library_selection'])) {
$ids = explode(',', $value['media_library_selection']);
$ids = array_filter($ids, 'is_numeric');
if (!empty($ids)) {
/** @var \Drupal\media\MediaInterface[] $media */
return Media::loadMultiple($ids);
}
}
return [];
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
public | function | 2 | |
DependencySerializationTrait:: |
public | function | 2 | |
MediaDirectoriesLibraryWidget:: |
public static | function |
Defines the default settings for this plugin. Overrides MediaLibraryWidget:: |
|
MediaDirectoriesLibraryWidget:: |
public | function |
Returns the form for a single field widget. Overrides MediaLibraryWidget:: |
|
MediaDirectoriesLibraryWidget:: |
protected | function |
Gets the enabled media type IDs sorted by weight. Overrides MediaLibraryWidget:: |
|
MediaDirectoriesLibraryWidget:: |
protected static | function |
Gets newly selected media items. Overrides MediaLibraryWidget:: |
|
MediaDirectoriesLibraryWidget:: |
public static | function |
AJAX callback to open the library modal. Overrides MediaLibraryWidget:: |
|
MediaLibraryWidget:: |
protected | property | The current active user. | |
MediaLibraryWidget:: |
protected | property | Entity type manager service. | |
MediaLibraryWidget:: |
protected | property | The module handler. | |
MediaLibraryWidget:: |
public static | function | Updates the field state and flags the form for rebuild. | |
MediaLibraryWidget:: |
public static | function |
Creates an instance of the plugin. Overrides WidgetBase:: |
|
MediaLibraryWidget:: |
public | function |
Assigns a field-level validation error to the right widget sub-element. Overrides WidgetBase:: |
|
MediaLibraryWidget:: |
public | function |
Creates a form element for a field. Overrides WidgetBase:: |
|
MediaLibraryWidget:: |
protected static | function | Gets the field state for the widget. | |
MediaLibraryWidget:: |
protected | function | Gets the message to display when there are no allowed media types. | |
MediaLibraryWidget:: |
public static | function |
Returns if the widget can be used for the provided field. Overrides WidgetBase:: |
|
MediaLibraryWidget:: |
public | function |
Massages the form values into the format expected for field values. Overrides WidgetBase:: |
|
MediaLibraryWidget:: |
public | function | Prepares the widget's render element for rendering. | |
MediaLibraryWidget:: |
public static | function | Submit callback for remove buttons. | |
MediaLibraryWidget:: |
protected static | function | Sets the field state for the widget. | |
MediaLibraryWidget:: |
public static | function | Value callback to optimize the way the media type weights are stored. | |
MediaLibraryWidget:: |
public | function |
Returns a form to configure settings for the widget. Overrides WidgetBase:: |
|
MediaLibraryWidget:: |
public | function |
Returns a short summary for the current widget settings. Overrides WidgetBase:: |
|
MediaLibraryWidget:: |
public static | function |
Lists the trusted callbacks provided by the implementing class. Overrides TrustedCallbackInterface:: |
|
MediaLibraryWidget:: |
public static | function | AJAX callback to update the widget when the selection changes. | |
MediaLibraryWidget:: |
public static | function | Validates that newly selected items can be added to the widget. | |
MediaLibraryWidget:: |
public static | function | Validates whether the widget is required and contains values. | |
MediaLibraryWidget:: |
public | function |
Constructs a MediaLibraryWidget widget. Overrides WidgetBase:: |
|
MessengerTrait:: |
protected | property | The messenger. | 27 |
MessengerTrait:: |
public | function | Gets the messenger. | 27 |
MessengerTrait:: |
public | function | Sets the messenger. | |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
2 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
PluginSettingsBase:: |
protected | property | Whether default settings have been merged into the current $settings. | |
PluginSettingsBase:: |
protected | property | The plugin settings injected by third party modules. | |
PluginSettingsBase:: |
public | function |
Calculates dependencies for the configured plugin. Overrides DependentPluginInterface:: |
6 |
PluginSettingsBase:: |
public | function |
Returns the value of a setting, or its default value if absent. Overrides PluginSettingsInterface:: |
|
PluginSettingsBase:: |
public | function |
Returns the array of settings, including defaults for missing settings. Overrides PluginSettingsInterface:: |
|
PluginSettingsBase:: |
public | function |
Gets the list of third parties that store information. Overrides ThirdPartySettingsInterface:: |
|
PluginSettingsBase:: |
public | function |
Gets the value of a third-party setting. Overrides ThirdPartySettingsInterface:: |
|
PluginSettingsBase:: |
public | function |
Gets all third-party settings of a given module. Overrides ThirdPartySettingsInterface:: |
|
PluginSettingsBase:: |
protected | function | Merges default settings values into $settings. | |
PluginSettingsBase:: |
public | function |
Informs the plugin that some configuration it depends on will be deleted. Overrides PluginSettingsInterface:: |
3 |
PluginSettingsBase:: |
public | function |
Sets the value of a setting for the plugin. Overrides PluginSettingsInterface:: |
|
PluginSettingsBase:: |
public | function |
Sets the settings for the plugin. Overrides PluginSettingsInterface:: |
|
PluginSettingsBase:: |
public | function |
Sets the value of a third-party setting. Overrides ThirdPartySettingsInterface:: |
|
PluginSettingsBase:: |
public | function |
Unsets a third-party setting. Overrides ThirdPartySettingsInterface:: |
|
StringTranslationTrait:: |
protected | property | The string translation service. | 4 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
TrustedCallbackInterface:: |
constant | Untrusted callbacks throw exceptions. | ||
TrustedCallbackInterface:: |
constant | Untrusted callbacks trigger silenced E_USER_DEPRECATION errors. | ||
TrustedCallbackInterface:: |
constant | Untrusted callbacks trigger E_USER_WARNING errors. | ||
WidgetBase:: |
protected | property | The field definition. | |
WidgetBase:: |
protected | property |
The widget settings. Overrides PluginSettingsBase:: |
|
WidgetBase:: |
public static | function | Ajax callback for the "Add another item" button. | |
WidgetBase:: |
public static | function | Submission handler for the "Add another item" button. | |
WidgetBase:: |
public static | function | After-build handler for field elements in a form. | |
WidgetBase:: |
public | function |
Extracts field values from submitted form values. Overrides WidgetBaseInterface:: |
2 |
WidgetBase:: |
public | function |
Reports field-level validation errors against actual form elements. Overrides WidgetBaseInterface:: |
2 |
WidgetBase:: |
protected | function | Special handling to create form elements for multiple values. | 1 |
WidgetBase:: |
protected | function | Generates the form element for a single copy of the widget. | |
WidgetBase:: |
protected | function | Returns the value of a field setting. | |
WidgetBase:: |
protected | function | Returns the array of field settings. | |
WidgetBase:: |
protected | function | Returns the filtered field description. | |
WidgetBase:: |
public static | function |
Retrieves processing information about the widget from $form_state. Overrides WidgetBaseInterface:: |
|
WidgetBase:: |
protected static | function | Returns the location of processing information within $form_state. | |
WidgetBase:: |
protected | function | Returns whether the widget handles multiple values. | |
WidgetBase:: |
protected | function | Returns whether the widget used for default value form. | |
WidgetBase:: |
public static | function |
Stores processing information about the widget in $form_state. Overrides WidgetBaseInterface:: |