331 lines
12 KiB
Plaintext
331 lines
12 KiB
Plaintext
<?php
|
|
|
|
/**
|
|
* @file
|
|
* Contains hook implementations for the media_library module.
|
|
*/
|
|
|
|
use Drupal\Component\Utility\UrlHelper;
|
|
use Drupal\Core\Access\AccessResult;
|
|
use Drupal\Core\Entity\EntityInterface;
|
|
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
|
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
|
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
|
use Drupal\Core\Form\FormStateInterface;
|
|
use Drupal\Core\Render\Element;
|
|
use Drupal\Core\Routing\RouteMatchInterface;
|
|
use Drupal\Core\Session\AccountInterface;
|
|
use Drupal\Core\Template\Attribute;
|
|
use Drupal\image\Entity\ImageStyle;
|
|
use Drupal\image\Plugin\Field\FieldType\ImageItem;
|
|
use Drupal\media\MediaTypeForm;
|
|
use Drupal\media\MediaTypeInterface;
|
|
use Drupal\media_library\Form\FileUploadForm;
|
|
use Drupal\media_library\Form\OEmbedForm;
|
|
use Drupal\media_library\MediaLibraryState;
|
|
use Drupal\views\Form\ViewsForm;
|
|
use Drupal\views\Plugin\views\cache\CachePluginBase;
|
|
use Drupal\views\ViewExecutable;
|
|
|
|
/**
|
|
* Implements hook_help().
|
|
*
|
|
* @todo Update in https://www.drupal.org/project/drupal/issues/2964789
|
|
*/
|
|
function media_library_help($route_name, RouteMatchInterface $route_match) {
|
|
switch ($route_name) {
|
|
case 'help.page.media_library':
|
|
$output = '<h3>' . t('About') . '</h3>';
|
|
$output .= '<p>' . t('The Media library module overrides the /admin/content/media view to provide a rich visual interface for performing administrative operations on media. For more information, see the <a href=":media">online documentation for the Media library module</a>.', [':media' => 'https://www.drupal.org/docs/8/core/modules/media']) . '</p>';
|
|
return $output;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_media_source_info_alter().
|
|
*/
|
|
function media_library_media_source_info_alter(array &$sources) {
|
|
$sources['audio_file']['forms']['media_library_add'] = FileUploadForm::class;
|
|
$sources['file']['forms']['media_library_add'] = FileUploadForm::class;
|
|
$sources['image']['forms']['media_library_add'] = FileUploadForm::class;
|
|
$sources['video_file']['forms']['media_library_add'] = FileUploadForm::class;
|
|
$sources['oembed:video']['forms']['media_library_add'] = OEmbedForm::class;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_theme().
|
|
*/
|
|
function media_library_theme() {
|
|
return [
|
|
'media__media_library' => [
|
|
'base hook' => 'media',
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Implements hook_views_post_render().
|
|
*/
|
|
function media_library_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
|
|
if ($view->id() === 'media_library') {
|
|
$output['#attached']['library'][] = 'media_library/view';
|
|
if (strpos($view->current_display, 'widget') === 0) {
|
|
$query = MediaLibraryState::fromRequest($view->getRequest())->all();
|
|
// If the current query contains any parameters we use to contextually
|
|
// filter the view, ensure they persist across AJAX rebuilds.
|
|
// The ajax_path is shared for all AJAX views on the page, but our query
|
|
// parameters are prefixed and should not interfere with any other views.
|
|
// @todo Rework or remove this in https://www.drupal.org/node/2983451
|
|
if (!empty($query)) {
|
|
$ajax_path = &$output['#attached']['drupalSettings']['views']['ajax_path'];
|
|
$parsed_url = UrlHelper::parse($ajax_path);
|
|
$query = array_merge($query, $parsed_url['query']);
|
|
$ajax_path = $parsed_url['path'] . '?' . UrlHelper::buildQuery($query);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_preprocess_media().
|
|
*/
|
|
function media_library_preprocess_media(&$variables) {
|
|
if ($variables['view_mode'] === 'media_library') {
|
|
/** @var \Drupal\media\MediaInterface $media */
|
|
$media = $variables['media'];
|
|
$variables['#cache']['contexts'][] = 'user.permissions';
|
|
$rel = $media->access('edit') ? 'edit-form' : 'canonical';
|
|
$variables['url'] = $media->toUrl($rel, [
|
|
'language' => $media->language(),
|
|
]);
|
|
$variables['preview_attributes'] = new Attribute();
|
|
$variables['preview_attributes']->addClass('media-library-item__preview', 'js-media-library-item-preview', 'js-click-to-select-trigger');
|
|
$variables['metadata_attributes'] = new Attribute();
|
|
$variables['metadata_attributes']->addClass('media-library-item__attributes');
|
|
$variables['status'] = $media->isPublished();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Alter the bulk form to add a more accessible label.
|
|
*
|
|
* @param array $form
|
|
* An associative array containing the structure of the form.
|
|
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
|
* The current state of the form.
|
|
*
|
|
* @todo Remove in https://www.drupal.org/node/2983454
|
|
*/
|
|
function media_library_form_views_form_media_library_page_alter(array &$form, FormStateInterface $form_state) {
|
|
if (isset($form['media_bulk_form']) && isset($form['output'])) {
|
|
/** @var \Drupal\views\ViewExecutable $view */
|
|
$view = $form['output'][0]['#view'];
|
|
foreach (Element::getVisibleChildren($form['media_bulk_form']) as $key) {
|
|
if (isset($view->result[$key])) {
|
|
$media = $view->field['media_bulk_form']->getEntity($view->result[$key]);
|
|
$form['media_bulk_form'][$key]['#title'] = t('Select @label', [
|
|
'@label' => $media->label(),
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_form_alter().
|
|
*/
|
|
function media_library_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
|
|
$form_object = $form_state->getFormObject();
|
|
if ($form_object instanceof ViewsForm && strpos($form_object->getBaseFormId(), 'views_form_media_library') === 0) {
|
|
$form['#attributes']['class'][] = 'media-library-views-form';
|
|
if (isset($form['header'])) {
|
|
$form['header']['#attributes']['class'][] = 'media-library-views-form__header';
|
|
$form['header']['media_bulk_form']['#attributes']['class'][] = 'media-library-views-form__bulk_form';
|
|
}
|
|
}
|
|
|
|
// Add after build to fix media library views exposed filter's submit button.
|
|
if ($form_id === 'views_exposed_form' && strpos($form['#id'], 'views-exposed-form-media-library-widget') === 0) {
|
|
$form['#after_build'][] = '_media_library_views_form_media_library_after_build';
|
|
}
|
|
|
|
// Configures media_library displays when a type is submitted.
|
|
if ($form_object instanceof MediaTypeForm) {
|
|
$form['actions']['submit']['#submit'][] = '_media_library_media_type_form_submit';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* After build callback for views form media library.
|
|
*/
|
|
function _media_library_views_form_media_library_after_build(array $form, FormStateInterface $form_state) {
|
|
// Remove .form-actions from media library views exposed filter actions
|
|
// and replace with .media-library-view--form-actions.
|
|
//
|
|
// This prevents the views exposed filter's 'Apply filter' submit button from
|
|
// being moved into the dialog's buttons.
|
|
// @see \Drupal\Core\Render\Element\Actions::processActions
|
|
// @see Drupal.behaviors.dialog.prepareDialogButtons
|
|
if (($key = array_search('form-actions', $form['actions']['#attributes']['class'])) !== FALSE) {
|
|
unset($form['actions']['#attributes']['class'][$key]);
|
|
}
|
|
$form['actions']['#attributes']['class'][] = 'media-library-view--form-actions';
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Submit callback for media type form.
|
|
*/
|
|
function _media_library_media_type_form_submit(array &$form, FormStateInterface $form_state) {
|
|
$form_object = $form_state->getFormObject();
|
|
if ($form_object->getOperation() === 'add') {
|
|
$type = $form_object->getEntity();
|
|
$form_display_created = _media_library_configure_form_display($type);
|
|
$view_display_created = _media_library_configure_view_display($type);
|
|
if ($form_display_created || $view_display_created) {
|
|
\Drupal::messenger()->addStatus(t('Media Library form and view displays have been created for the %type media type.', [
|
|
'%type' => $type->label(),
|
|
]));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_field_ui_preconfigured_options_alter().
|
|
*/
|
|
function media_library_field_ui_preconfigured_options_alter(array &$options, $field_type) {
|
|
// If the field is not an "entity_reference"-based field, bail out.
|
|
$class = \Drupal::service('plugin.manager.field.field_type')->getPluginClass($field_type);
|
|
if (!is_a($class, EntityReferenceItem::class, TRUE)) {
|
|
return;
|
|
}
|
|
|
|
// Set the default field widget for media to be the Media library.
|
|
if (!empty($options['media'])) {
|
|
$options['media']['entity_form_display']['type'] = 'media_library_widget';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_local_tasks_alter().
|
|
*
|
|
* Removes tasks for the Media library if the view display no longer exists.
|
|
*/
|
|
function media_library_local_tasks_alter(&$local_tasks) {
|
|
/** @var \Symfony\Component\Routing\RouteCollection $route_collection */
|
|
$route_collection = \Drupal::service('router')->getRouteCollection();
|
|
foreach (['media_library.grid', 'media_library.table'] as $key) {
|
|
if (isset($local_tasks[$key]) && !$route_collection->get($local_tasks[$key]['route_name'])) {
|
|
unset($local_tasks[$key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_ENTITY_TYPE_access().
|
|
*/
|
|
function media_library_image_style_access(EntityInterface $entity, $operation, AccountInterface $account) {
|
|
// Prevent the fallback 'media_library' image style from being deleted.
|
|
// @todo: Lock the image style instead of preventing delete access.
|
|
// https://www.drupal.org/project/drupal/issues/2247293
|
|
if ($operation === 'delete' && $entity->id() === 'media_library') {
|
|
return AccessResult::forbidden();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ensures that the given media type has a media_library form display.
|
|
*
|
|
* @param \Drupal\media\MediaTypeInterface $type
|
|
* The media type to configure.
|
|
*
|
|
* @return bool
|
|
* Whether a form display has been created or not.
|
|
*
|
|
* @throws \Drupal\Core\Entity\EntityStorageException
|
|
*/
|
|
function _media_library_configure_form_display(MediaTypeInterface $type) {
|
|
$display = EntityFormDisplay::load('media.' . $type->id() . '.media_library');
|
|
|
|
if ($display) {
|
|
return FALSE;
|
|
}
|
|
|
|
$values = [
|
|
'targetEntityType' => 'media',
|
|
'bundle' => $type->id(),
|
|
'mode' => 'media_library',
|
|
'status' => TRUE,
|
|
];
|
|
$display = EntityFormDisplay::create($values);
|
|
// Remove all default components.
|
|
foreach (array_keys($display->getComponents()) as $name) {
|
|
$display->removeComponent($name);
|
|
}
|
|
// Expose the name field when it is not mapped.
|
|
$field_map = $type->getFieldMap();
|
|
if (empty($field_map['name'])) {
|
|
$display->setComponent('name', [
|
|
'type' => 'string_textfield',
|
|
'settings' => [
|
|
'size' => 60,
|
|
],
|
|
]);
|
|
}
|
|
// If the source field is an image field, expose it so that users can set alt
|
|
// and title text.
|
|
$source_field = $type->getSource()->getSourceFieldDefinition($type);
|
|
if ($source_field->isDisplayConfigurable('form') && is_a($source_field->getItemDefinition()->getClass(), ImageItem::class, TRUE)) {
|
|
$type->getSource()->prepareFormDisplay($type, $display);
|
|
}
|
|
return (bool) $display->save();
|
|
}
|
|
|
|
/**
|
|
* Ensures that the given media type has a media_library view display.
|
|
*
|
|
* @param \Drupal\media\MediaTypeInterface $type
|
|
* The media type to configure.
|
|
*
|
|
* @return bool
|
|
* Whether a view display has been created or not.
|
|
*
|
|
* @throws \Drupal\Core\Entity\EntityStorageException
|
|
*/
|
|
function _media_library_configure_view_display(MediaTypeInterface $type) {
|
|
$display = EntityViewDisplay::load('media.' . $type->id() . '.media_library');
|
|
|
|
if ($display) {
|
|
return FALSE;
|
|
}
|
|
|
|
$values = [
|
|
'targetEntityType' => 'media',
|
|
'bundle' => $type->id(),
|
|
'mode' => 'media_library',
|
|
'status' => TRUE,
|
|
];
|
|
$display = EntityViewDisplay::create($values);
|
|
// Remove all default components.
|
|
foreach (array_keys($display->getComponents()) as $name) {
|
|
$display->removeComponent($name);
|
|
}
|
|
|
|
// @todo: Remove dependency on 'medium' and 'thumbnail' image styles from
|
|
// media and media library modules.
|
|
// https://www.drupal.org/project/drupal/issues/3030437
|
|
$image_style = ImageStyle::load('medium');
|
|
|
|
// Expose the thumbnail component. If the medium image style doesn't exist,
|
|
// use the fallback 'media_library' image style.
|
|
$display->setComponent('thumbnail', [
|
|
'type' => 'image',
|
|
'label' => 'hidden',
|
|
'settings' => [
|
|
'image_style' => $image_style ? $image_style->id() : 'media_library',
|
|
'image_link' => '',
|
|
],
|
|
]);
|
|
return (bool) $display->save();
|
|
}
|