Chris@17: ' . t('About') . ''; Chris@17: $output .= '

' . 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 online documentation for the Media library module.', [':media' => 'https://www.drupal.org/docs/8/core/modules/media']) . '

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