acquia_dam-1.0.0-rc1/acquia_dam.module
acquia_dam.module
<?php /** * @file * Drupal Module: Acquia DAM. */ declare(strict_types=1); use Drupal\acquia_dam\Client\AcquiaDamClientFactory; use Drupal\acquia_dam\EmbedCodeFactory; use Drupal\acquia_dam\Entity\ComputedEmbedCodesField; use Drupal\acquia_dam\Entity\ImageAltTextField; use Drupal\acquia_dam\Entity\MediaExpiryDateField; use Drupal\acquia_dam\Entity\MediaSourceField; use Drupal\acquia_dam\Form\FocalPointMediaEditFormAlter; use Drupal\acquia_dam\Form\MediaEmbedFormAlter; use Drupal\acquia_dam\Form\MediaTypeFormAlter; use Drupal\acquia_dam\FormatAllowedHtmlModifier; use Drupal\acquia_dam\Plugin\Field\FieldType\AssetItem; use Drupal\acquia_dam\Plugin\media\Source\Asset; use Drupal\acquia_dam\Plugin\views\field\MediaLibrarySelectForm; use Drupal\acquia_dam\StreamWrapper\AcquiaDamStreamWrapper; use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Link; use Drupal\Core\Render\Element; use Drupal\Core\Render\Markup; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Template\Attribute; use Drupal\Core\Url; use Drupal\filter\FilterFormatInterface; use Drupal\media\Entity\Media; use Drupal\media\Entity\MediaType; use Drupal\media\MediaInterface; use Drupal\media\MediaTypeInterface; use Drupal\media_library\MediaLibraryState; use Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget; use Drupal\views\Form\ViewsForm; use Drupal\views\Plugin\views\cache\CachePluginBase; use Drupal\views\ViewExecutable; /** * Implements hook_theme(). */ function acquia_dam_theme($existing, $type, $theme, $path) { return [ 'acquia_dam_embed_select_form' => [ 'render element' => 'form', ], 'acquia_dam_iframe_responsive' => [ 'variables' => [ 'src' => NULL, ], ], 'acquia_dam_video_stream' => [ 'variables' => [ 'attributes' => NULL, 'source_attributes' => NULL, ], ], ]; } /** * Implements hook_entity_field_storage_info(). */ function acquia_dam_entity_field_storage_info(EntityTypeInterface $entity_type): array { $definitions = []; if ($entity_type->id() === 'media') { $definitions[MediaSourceField::SOURCE_FIELD_NAME] = MediaSourceField::getStorageDefinition($entity_type->id()); $definitions[MediaExpiryDateField::EXPIRY_DATE_FIELD_NAME] = MediaExpiryDateField::getStorageDefinition($entity_type->id()); $definitions[ComputedEmbedCodesField::FIELD_NAME] = ComputedEmbedCodesField::getStorageDefinition($entity_type->id()); $definitions[ImageAltTextField::IMAGE_ALT_TEXT_FIELD_NAME] = ImageAltTextField::getStorageDefinition($entity_type->id()); } return $definitions; } /** * Implements hook_entity_bundle_field_info(). */ function acquia_dam_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) { $definitions = []; if ($entity_type->id() === 'media') { $media_type_storage = Drupal::entityTypeManager()->getStorage('media_type'); $media_type = $media_type_storage->load($bundle); // @todo this check vs an `assert` is needed due to MediaLibrarySelectForm. // It can create media entity stubs with invalid bundles when the view // is not properly filtered. This should only happen when editing the // View and the MediaLibrarySelectForm is rendered and non-functional. if (!$media_type instanceof MediaTypeInterface) { return $definitions; } $source = $media_type->getSource(); if ($source instanceof Asset) { $definitions[MediaSourceField::SOURCE_FIELD_NAME] = MediaSourceField::getFieldDefinition( $entity_type->id(), $bundle, (string) $media_type->label() ); $definitions[MediaExpiryDateField::EXPIRY_DATE_FIELD_NAME] = MediaExpiryDateField::getFieldDefinition( $entity_type->id(), $bundle, (string) $media_type->label() ); $definitions[ComputedEmbedCodesField::FIELD_NAME] = ComputedEmbedCodesField::getFieldDefinition( $entity_type->id(), $bundle ); if ($source->getDerivativeId() === 'image') { $definitions[ImageAltTextField::IMAGE_ALT_TEXT_FIELD_NAME] = ImageAltTextField::getFieldDefinition( $entity_type->id(), $bundle, (string) $media_type->label() ); } } } return $definitions; } /** * Implements hook_form_FORM_ID_alter(). */ function acquia_dam_form_editor_media_dialog_alter(&$form, FormStateInterface $form_state) { $form_alter = \Drupal::classResolver() ->getInstanceFromDefinition(MediaEmbedFormAlter::class); assert($form_alter instanceof MediaEmbedFormAlter); $form_alter->formAlter($form, $form_state); } /** * Implements hook_form_BASE_FORM_ID_alter(). */ function acquia_dam_form_media_type_form_alter(&$form, FormStateInterface $form_state) { $form_alter = \Drupal::classResolver() ->getInstanceFromDefinition(MediaTypeFormAlter::class); assert($form_alter instanceof MediaTypeFormAlter); $form_alter->formAlter($form, $form_state); } /** * Implements hook_form_FORM_ID_alter(). */ function acquia_dam_form_media_acquiadam_config_alter(&$form, FormStateInterface $form_state) { $form['authentication'] = [ '#type' => 'fieldset', '#title' => t('Authentication details'), ]; $form['authentication']['redirect'] = [ "#markup" => "The site credentials to your Acquia DAM account are now under " . Link::createFromRoute(t('Acquia DAM'), 'acquia_dam.config')->toString(), ]; } /** * Implements hook_preprocess_HOOK(). */ function acquia_dam_preprocess_media(&$variables) { if ($variables['view_mode'] === 'media_library') { $variables['attributes']['class'][] = 'contextual-region'; } // We change how to render only if 'data-embed-code-id' attribute is set. // Otherwise, we let the view mode configuration handle rendering. if (isset($variables['attributes']['data-embed-code-id'])) { $media = $variables['media']; assert($media instanceof MediaInterface); $media_type = MediaType::load($media->bundle()); assert($media_type instanceof MediaTypeInterface); $source = $media_type->getSource(); if ($source instanceof Asset) { $embeds = $source->getMetadata($media, 'embeds'); if (empty($embeds)) { return; } $variables['content'][MediaSourceField::SOURCE_FIELD_NAME][0] = EmbedCodeFactory::renderAsset( $variables['attributes']['data-embed-code-id'], $media ); unset($variables['attributes']['data-embed-code-id']); } } } /** * Implements hook_theme_suggestions_HOOK(). * * Each theme in Drupal core provides a template for the view provided by Media * Library based on its identifier. We need to provide that theme hook * suggestion for our own view so that it is templated correctly. */ function acquia_dam_theme_suggestions_views_view_unformatted(array $variables) { $suggestions = []; if ($variables['view']->id() === 'acquia_dam_asset_library') { $suggestions[] = 'views_view_unformatted__media_library'; } return $suggestions; } /** * Implements hook_theme_suggestions_HOOK(). */ function acquia_dam_theme_suggestions_views_view(array $variables) { $suggestions = []; if ($variables['view']->id() === 'acquia_dam_asset_library') { $suggestions[] = 'views_view__media_library'; } return $suggestions; } /** * Implements hook_views_post_render(). * * Media Library comes with few preprocess that takes care of adding necessary * libraries into the page. Unfortunately it is only applicable for * media_library view, this will take extending to acquia_dam_assest_library as * well. */ function acquia_dam_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) { if ($view->id() === 'acquia_dam_asset_library') { $output['#attached']['library'][] = 'media_library/view'; if (strpos($view->current_display, 'widget') === 0) { try { $query = MediaLibraryState::fromRequest($view->getRequest())->all(); } catch (InvalidArgumentException $e) { // MediaLibraryState::fromRequest() will throw an exception if the view // is being previewed, since not all required query parameters will be // present. In a preview, however, this can be omitted since we're // merely previewing. // @todo Use the views API for checking for the preview mode when it // lands. https://www.drupal.org/project/drupal/issues/3060855 if (empty($view->preview) && empty($view->live_preview)) { throw $e; } } // 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_views_pre_render(). * * This will take care of necessary classes which is added by the media_library * to its view is extended to `acquia_dam_asset_library` as well. */ function acquia_dam_views_pre_render(ViewExecutable $view) { $add_classes = function (&$option, array $classes_to_add) { $classes = $option ? preg_split('/\s+/', trim($option)) : []; $classes = array_filter($classes); $classes = array_merge($classes, $classes_to_add); $option = implode(' ', array_unique($classes)); }; if ($view->id() === 'acquia_dam_asset_library') { if (isset($view->display_handler->options['defaults']['css_class']) && $view->display_handler->options['defaults']['css_class']) { $add_classes($view->displayHandlers->get('default')->options['css_class'], ['media-library-view']); } else { $add_classes($view->display_handler->options['css_class'], ['media-library-view']); } if (strpos($view->current_display, 'widget') === 0) { // Logic from claro.theme preprocess all of this will be remove once we // can make the view id configurable. if (array_key_exists('thumbnail', $view->field)) { $add_classes($view->field['thumbnail']->options['element_class'], ['media-library-item__content']); } if (array_key_exists('media_library_select_form', $view->field)) { $add_classes($view->field['media_library_select_form']->options['element_wrapper_class'], ['media-library-item__click-to-select-checkbox']); } if ($view->display_handler->options['defaults']['css_class']) { $add_classes($view->displayHandlers->get('default')->options['css_class'], ['media-library-view--widget']); } else { $add_classes($view->display_handler->options['css_class'], ['media-library-view--widget']); } if (array_key_exists('media_library_select_form', $view->field)) { $add_classes($view->field['media_library_select_form']->options['element_wrapper_class'], ['js-click-to-select-checkbox']); } $add_classes($view->display_handler->options['css_class'], ['js-media-library-view']); } $add_classes( $view->style_plugin->options['row_class'], ['js-media-library-item', 'js-click-to-select'] ); // NOTE: modified from core to bypass undefined offset in our View. if (!empty($view->display_handler->options['defaults']['css_class'])) { $add_classes($view->displayHandlers->get('default')->options['css_class'], ['js-media-library-view']); } else { $add_classes($view->display_handler->options['css_class'], ['js-media-library-view']); } } } /** * Implements hook_preprocess_views_view_fields(). * * This will take care of necessary classes which is added by the media_library * to its view is extended to `acquia_dam_asset_library` as well. */ function acquia_dam_preprocess_views_view_fields(&$variables) { // Add classes to media rendered entity field so it can be targeted for // JavaScript mouseover and click events. if ($variables['view']->id() === 'acquia_dam_asset_library' && isset($variables['fields']['rendered_entity'])) { if (isset($variables['fields']['rendered_entity']->wrapper_attributes)) { $variables['fields']['rendered_entity']->wrapper_attributes->addClass('js-click-to-select-trigger'); // @see function claro_preprocess_views_view_fields__media_library(array &$variables). $variables['fields']['rendered_entity']->wrapper_attributes->addClass('media-library-item__click-to-select-trigger'); } } } /** * 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 acquia_dam_form_views_form_acquia_dam_asset_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_ENTITY_TYPE_insert(). */ function acquia_dam_entity_view_display_insert(EntityViewDisplayInterface $display) { // Adjust our media type's media library view displays. // @see _media_library_configure_view_display(). if ($display->getTargetEntityTypeId() === 'media' && $display->getMode() === 'media_library') { $media_type = MediaType::load($display->getTargetBundle()); if ($media_type && $media_type->getSource() instanceof Asset) { $display->setComponent('thumbnail', [ 'type' => 'acquia_dam_thumbnail', 'label' => 'hidden', 'settings' => [ 'thumbnail_size' => '300px', ], ]); $display->save(); } } } /** * Implements hook_form_BASE_FORM_ID_alter(). */ function acquia_dam_form_media_form_alter(array &$form, FormStateInterface $form_state, $form_id) { /** @var \Drupal\acquia_dam\Plugin\media\Source\Asset $asset */ $asset = $form_state->getFormObject()->getEntity()->getSource(); $is_dam_asset = $asset instanceof Asset; if (!$is_dam_asset) { return; } // Disable add form save button for DAM assets. if (str_ends_with($form_id, '_add_form')) { \Drupal::messenger()->addWarning('DAM assets cannot be added from this form, only through the media library when creating content.'); $form['actions']['submit']['#disabled'] = TRUE; } $focal_point_installed = \Drupal::moduleHandler()->moduleExists('focal_point'); if ($focal_point_installed && str_ends_with($form_id, '_edit_form') && $asset->getDerivativeId() === 'image') { $form_alter = \Drupal::classResolver() ->getInstanceFromDefinition(FocalPointMediaEditFormAlter::class); assert($form_alter instanceof FocalPointMediaEditFormAlter); $form_alter->formAlter($form, $form_state); } } /** * Implements hook_form_alter(). */ function acquia_dam_form_alter(array &$form, FormStateInterface $form_state, $form_id) { // Add a process callback to ensure that the media library view's exposed // filters submit button is not moved to the modal dialog's button area. $form_object = $form_state->getFormObject(); // Add class to the Media Library views form. if ($form_object instanceof ViewsForm && strpos($form_object->getBaseFormId(), 'views_form_acquia_dam_asset_library_widget') === 0) { // The conditional below exists because the media-library-views-form class // is currently added by Classy, but Umami will eventually not use Classy as // a base theme. // @todo remove conditional, keep class addition in // https://drupal.org/node/3110137 // @see https://www.drupal.org/node/3109287 // @see classy_form_alter() if (!isset($form['#attributes']['class']) || !in_array('media-library-views-form', $form['#attributes']['class'])) { $form['#attributes']['class'][] = 'media-library-views-form'; } } if ($form_id === 'views_exposed_form' && strpos($form['#id'], 'views-exposed-form-acquia-dam-asset-library-widget') === 0) { $form['#after_build'][] = '_acquia_dam_views_form_media_library_after_build'; // Button or action #type won't work because that might trigger their own // request. Thereby breaking the view with empty conditions. // @see Drupal.views.ajaxView.prototype.attachExposedFormAjax. // @see https://www.drupal.org/project/drupal/issues/2804277. $form['clear'] = [ '#type' => 'markup', '#markup' => '<a href="#" class="button views-exposed-form__item views-exposed-form__item--actions acquia-dam-clear-filter">Clear Filter</a>', ]; } elseif ($form_id === 'user_form') { // Reverting the changes set in media_acquiadam_form_user_form_alter. if (\Drupal::moduleHandler()->moduleExists('media_acquiadam')) { unset($form['media_acquiadam']); if (in_array('media_acquiadam_unauthorize', $form['actions']['submit']['#submit'])) { $key = array_search('media_acquiadam_unauthorize', $form['actions']['submit']['#submit']); unset($form['actions']['submit']['#submit'][$key]); } } } } /** * Form #after_build callback for media_library view's exposed filters form. */ function _acquia_dam_views_form_media_library_after_build(array $form, FormStateInterface $form_state) { // Remove .form-actions from the view's exposed filter actions. This prevents // the "Apply" submit button from being moved into the dialog's // button area. // @see \Drupal\Core\Render\Element\Actions::processActions // @see Drupal.behaviors.dialog.prepareDialogButtons // @todo Remove this after // https://www.drupal.org/project/drupal/issues/3089751 is fixed. if (($key = array_search('form-actions', $form['actions']['#attributes']['class'])) !== FALSE) { unset($form['actions']['#attributes']['class'][$key]); } return $form; } /** * Implements hook_ENTITY_TYPE_presave(). * * Ensures `data-embed-code-id` is present for filter_html and drupal-media. * * We use hook_presave due to ConfigEntityBase::preSave crashing on re-save * during the hook_insert hook. */ function acquia_dam_filter_format_presave(FilterFormatInterface $filter_format) { \Drupal::classResolver() ->getInstanceFromDefinition(FormatAllowedHtmlModifier::class) ->process($filter_format); } /** * Implements hook_ENTITY_TYPE_insert(). * * Register integration link on Acquia DAM when media gets created. */ function acquia_dam_media_insert(MediaInterface $entity) { $source = $entity->getSource(); if (!str_starts_with($source->getPluginId(), 'acquia_dam_asset')) { return; } $asset_id = $entity->get('acquia_dam_asset_id')->first()->getValue(); if (empty($asset_id['asset_id'])) { return; } /** @var \Drupal\acquia_dam\IntegrationLinkRegister $register */ $register = \Drupal::service('acquia_dam.integration_link_register'); $register->addIntegrationLinksList($asset_id['asset_id'], $entity); } /** * Implements hook_cron(). * * Refresh acquia_dam versions. */ function acquia_dam_cron() { \Drupal::service('acquia_dam.cron')->run(); } /** * Implements hook_ENTITY_TYPE_delete(). * * Remove integration link from Acquia DAM when media gets deleted. */ function acquia_dam_media_delete(MediaInterface $entity) { /** @var \Drupal\acquia_dam\Plugin\media\Source\Asset $source */ $source = $entity->getSource(); if (!$source instanceof Asset) { return; } $source_field = $entity->get(MediaSourceField::SOURCE_FIELD_NAME); $source_field_item = $source_field->first(); assert($source_field_item instanceof AssetItem); Cache::invalidateTags(["acquia-dam-asset:{$source_field_item->asset_id}"]); $module_handler = \Drupal::service('module_handler'); if ($source->getDerivativeId() === 'image' && $module_handler->moduleExists('crop')) { /** @var \Drupal\acquia_dam\ImageStyleHelper $image_style_helper */ $image_style_helper = \Drupal::service('acquia_dam.image_style_support'); if ($crops = $image_style_helper->getCrops($entity)) { foreach ($crops as $crop) { $crop->delete(); } } } /** @var \Drupal\acquia_dam\IntegrationLinkRegister $register */ $register = \Drupal::service('acquia_dam.integration_link_register'); foreach ($register->getAllEntityUuuidsIntegratingAsset($source_field_item->asset_id) as $entity_uuid) { $register->addIntegrationToDeleteList($entity_uuid); } } /** * Implements hook_menu_links_discovered_alter(). */ function acquia_dam_menu_links_discovered_alter(array &$links) { if (isset($links['media_acquiadam.config'])) { $links['media_acquiadam.config']['title'] = new TranslatableMarkup('Acquia DAM Entity Browser'); $links['media_acquiadam.config']['description'] = new TranslatableMarkup('Configure Acquia DAM for the Entity Browser module.'); $links['media_acquiadam.config']['weight'] = 0; $links['acquia_dam.config']['weight'] = -1; } } /** * Implements hook_module_implements_alter(). */ function acquia_dam_module_implements_alter(&$implementations, $hook) { if ($hook == 'form_alter') { // Move acquia_dam_form_alter() to the end of the list. $group = $implementations['acquia_dam']; unset($implementations['acquia_dam']); $implementations['acquia_dam'] = $group; } } /** * Implements hook_preprocess_media_library_wrapper(). */ function acquia_dam_preprocess_media_library_wrapper(array &$variables) { $variables['attributes']['class'][] = 'acquia-dam-media-library'; } /** * Implements hook_library_info_alter(). */ function acquia_dam_library_info_alter(&$libraries, $extension) { if ($extension === 'acquia_dam') { $admin_theme = \Drupal::configFactory()->get('system.theme')->get('admin'); if ($admin_theme === 'acquia_claro') { $libraries['media_library.style']['css']['theme']['css/media-library-acquia-claro.css'] = []; } elseif ($admin_theme === 'gin') { $libraries['media_library.style']['css']['theme']['css/media-library-gin.css'] = []; } } } /** * Implements hook_views_plugins_field_alter(). */ function acquia_dam_views_plugins_field_alter(array &$plugins) { if (isset($plugins['media_library_select_form'])) { $plugins['media_library_select_form']['class'] = MediaLibrarySelectForm::class; } } /** * Implements hook_ENTITY_TYPE_presave(). */ function acquia_dam_media_presave(MediaInterface $media) { if ($media->isNew() && $media->getSource() instanceof Asset) { $source_field = $media->get(MediaSourceField::SOURCE_FIELD_NAME); if ($source_field->isEmpty()) { return; } $source_field_item = $source_field->first(); assert($source_field_item instanceof AssetItem); if (empty($source_field_item->version_id)) { $client_factory = \Drupal::service('acquia_dam.client.factory'); assert($client_factory instanceof AcquiaDamClientFactory); $client = $client_factory->getSiteClient(); $asset_versions = $client->getAssetVersionList($source_field_item->asset_id); $versions = $asset_versions['versions']; usort($versions, function ($a, $b) { return $a['dateLastEdited'] <=> $b['dateLastEdited']; }); $source_field_item->version_id = end($versions)['uuid']; } if (empty($source_field_item->external_id)) { $source = $media->getSource(); if ($source instanceof Asset) { $source_field_item->external_id = $source->getMetadata($media, "external_id"); } } } } /** * Implements hook_preprocess_links__media_library_menu(). * * This targets the menu of available media types in the media library's modal * dialog. * * @todo Do this in the relevant template once * https://www.drupal.org/project/drupal/issues/3088856 is resolved. */ function acquia_dam_preprocess_links__media_library_menu(array &$variables) { foreach ($variables['links'] as &$link) { // Add a class to the Media Library menu items. $link['attributes']->addClass('media-library-menu__item'); // This conditional exists because the media-library-menu__link class is // currently added by Classy, but Claro will eventually not use Classy as a // base theme. // @todo remove conditional, keep class addition in // https://drupal.org/node/3110137 // @see classy_preprocess_links__media_library_menu() if (!isset($link['link']['#options']['attributes']['class']) || !in_array('media-library-menu__link', $link['link']['#options']['attributes']['class'])) { $link['link']['#options']['attributes']['class'][] = 'media-library-menu__link'; } } } /** * Implements hook_filter_info_alter(). */ function acquia_dam_filter_info_alter(array &$info) { if (isset($info['media_embed'])) { $info['media_embed']['class'] = '\Drupal\acquia_dam\Plugin\Filter\DamMediaEmbed'; } } /** * Implements hook_editor_js_settings_alter(). */ function acquia_dam_editor_js_settings_alter(array &$settings) { // CKEditor always sorts plugins and does not have a mechanism for altering // dependencies. This makes it impossible for our `mediarevisions` plugin // to add its hooks before `drupalmedia` is loaded. if (isset($settings['editor']['formats']) && !is_array($settings['editor']['formats'])) { return; } foreach ($settings['editor']['formats'] as $editor => $setting) { if (!is_array($setting) || !isset($setting['editor'])) { continue; } if (!isset($setting['editorSettings']) || !is_array($setting['editorSettings'])) { continue; } $editor_settings = $setting['editorSettings']; // Make sure the media revisions plugin loads in correct order. if ($setting['editor'] === 'ckeditor') { if (!isset($editor_settings['extraPlugins']) || !is_string($editor_settings['extraPlugins'])) { continue; } $plugins = explode(',', $editor_settings['extraPlugins']); foreach (['acquia_dam_mediarevisions', 'acquia_dam_mediaexpiration'] as $plugin) { $acquia_dam_mediarevisions_index = array_search($plugin, $plugins, TRUE); if ($acquia_dam_mediarevisions_index === FALSE) { continue; } unset($plugins[$acquia_dam_mediarevisions_index]); array_unshift($plugins, $plugin); } $settings['editor']['formats'][$editor]['editorSettings']['extraPlugins'] = implode(',', $plugins); } // Remove asset media types from the viewMode dropdown. // @note the button isn't completely hidden // @see https://www.drupal.org/project/drupal/issues/3300568 elseif ($setting['editor'] === 'ckeditor5') { $media_types = MediaType::loadMultiple(); $asset_media_types = array_filter($media_types, static function (MediaTypeInterface $media_type) { return $media_type->getSource() instanceof Asset; }); if (!isset($editor_settings['config']['drupalElementStyles']['viewMode']) || !is_array($editor_settings['config']['drupalElementStyles']['viewMode'])) { continue; } $view_mode_items = $editor_settings['config']['drupalElementStyles']['viewMode']; foreach ($view_mode_items as $key => $view_mode_item) { $view_mode_items[$key]['modelAttributes']['drupalMediaType'] = array_values(array_diff( $view_mode_item['modelAttributes']['drupalMediaType'], array_keys($asset_media_types) )); } $settings['editor']['formats'][$editor]['editorSettings']['config']['drupalElementStyles']['viewMode'] = $view_mode_items; } } } /** * Implements hook_entity_operation(). */ function acquia_dam_entity_operation(EntityInterface $entity) { $operations = []; $entityTypeId = $entity->getEntityTypeId(); if ($entityTypeId !== 'media') { return $operations; } /** @var \Drupal\media\MediaInterface $entity */ $asset = $entity->getSource(); if (!$asset instanceof Asset) { return $operations; } if ($asset->getDerivativeId() === 'image') { $updateUrl = Url::fromRoute('acquia_dam.version_update', ['media' => $entity->id()]); $operations['version_update'] = [ 'title' => t('Check for update'), 'weight' => -1, 'url' => $updateUrl, ]; } $operations['metadata_sync'] = [ 'title' => t('Sync metadata'), 'url' => Url::fromRoute('acquia_dam.metadata_sync', ['media' => $entity->id()]), ]; return $operations; } /** * Implements hook_field_widget_single_element_form_alter(). */ function acquia_dam_field_widget_single_element_form_alter(array &$element, FormStateInterface $form_state, array $context) { if ($context['widget'] instanceof MediaLibraryWidget) { $selections = Element::children($element['selection']); $element['#attached']['library'][] = 'acquia_dam/acquia_dam.expired_assets'; $current_time = \Drupal::time()->getCurrentTime(); $svg = file_get_contents(\Drupal::service('extension.list.module')->getPath('acquia_dam') . '/images/alert-red.svg'); foreach ($selections as $selection) { /** @var \Drupal\media\Entity\Media $media*/ $media = $element['selection'][$selection]['rendered_entity']['#media']; $media = $media->isLatestRevision() ? $media : Media::load($media->id()); if (!$media->getSource() instanceof Asset) { continue; } $expiry_date = $media->get('acquia_dam_expiry_date')->getValue(); if (!$expiry_date) { continue; } if ((int) $expiry_date[0]['value'] < $current_time) { $expiry_build = [ '#type' => 'inline_template', '#template' => '<div class="acquia-dam-expired-asset-container"><div class="acquia-dam-expired-asset">{{ svg }}<div class="acquia-dam-asset-expired__popper">{{ description }}</div></div></div>', '#context' => [ 'description' => t("The media is expired and won't be seen by content viewers. Please remove existing media and add new media."), 'svg' => Markup::create($svg), ], ]; array_unshift($element['selection'][$selection], $expiry_build); } } } } /** * Implements hook_preprocess_responsive_image(). */ function acquia_dam_preprocess_responsive_image(&$variables) { $wrapper = \Drupal::service('stream_wrapper_manager')->getViaUri($variables['uri']); if ($wrapper instanceof AcquiaDamStreamWrapper) { // The `acquia-dam://` URI does not append an extension, since the format // may be optimized on the CDN (`web` format.) We need to remove the default // `type` attribute when uses `application/octet-stream` when an extension // is not part of the URI. foreach ($variables['sources'] as $source) { /** @var \Drupal\Core\Template\Attribute $source */ $source->removeAttribute('type'); } } } /** * Prepares variables for acquia_dam_video_stream templates. * * Default template: acquia-dam-video-stream.html.twig. * * @param array $variables * An associative array containing: * - attributes: An array of HTML attributes, intended to be added to the * video tag. * - source_attributes: An array of HTML attributes for to be added to the * source tag. */ function template_preprocess_acquia_dam_video_stream(array &$variables) { if (!isset($variables['source_attributes']) || empty($variables['source_attributes'])) { return; } $variables['source_attributes'] = new Attribute($variables['source_attributes']); }