diff --git a/composer.json b/composer.json index 8b36846d19..af90c67708 100644 --- a/composer.json +++ b/composer.json @@ -177,7 +177,7 @@ "[10.2 regression] CKEditor 5 breaks when 'Source'/Source editing button is added and 'Manually editable HTML tags' are specified (3410100)": "https://www.drupal.org/files/issues/2024-01-23/drupal-revert-source-editing-validation-tightening-3410100-38.patch", "[Apache only] Wrong file header returned, when converting an image for example to webp (3310963)": "https://www.drupal.org/files/issues/2024-05-15/3310963-32.patch", "Hardcode a higher WebP conversion quality setting (3320689)": "https://gist.githubusercontent.com/joeparsons/d99b6c6eef240e8eaf768ba79e1c9f1b/raw/9b99325bd20907db0506969fc4f5823b46065c6b/3320689-10-3-x-hardcoded.patch", - "Provide option to display contextual links on embedded entities (3174252)": "https://git.drupalcode.org/project/drupal/-/merge_requests/5626.diff" + "Provide option to display contextual links on embedded entities (3174252)": "web/profiles/custom/az_quickstart/patches/composer/drupal/core/3174252-Provide-option-to-display-contextual-links-on-embedded-entities.diff" }, "drupal/draggableviews": { "Row weights not displaying on sort view (3252365)": "https://www.drupal.org/files/issues/2023-08-25/3252365-check-remove-select-all-class.patch", diff --git a/patches/composer/drupal/core/3174252-Provide-option-to-display-contextual-links-on-embedded-entities.diff b/patches/composer/drupal/core/3174252-Provide-option-to-display-contextual-links-on-embedded-entities.diff new file mode 100644 index 0000000000..e26f066929 --- /dev/null +++ b/patches/composer/drupal/core/3174252-Provide-option-to-display-contextual-links-on-embedded-entities.diff @@ -0,0 +1,223 @@ +diff --git a/core/modules/media/config/schema/media.schema.yml b/core/modules/media/config/schema/media.schema.yml +index 4311b11049c688520e4a1efd086f1ba3e398498c..bfa7b3929de54b0580bb5fae958341d1ed11f95f 100644 +--- a/core/modules/media/config/schema/media.schema.yml ++++ b/core/modules/media/config/schema/media.schema.yml +@@ -141,3 +141,6 @@ filter_settings.media_embed: + sequence: + type: string + label: 'Media type' ++ show_contextual_links: ++ type: boolean ++ label: 'Show contextual links for embedded media' +diff --git a/core/modules/media/media.post_update.php b/core/modules/media/media.post_update.php +index 7ab89500d231bfe7956e110d0d875e3df58315fe..6318f7e0be61d5b3182234c82f048241d0203a8c 100644 +--- a/core/modules/media/media.post_update.php ++++ b/core/modules/media/media.post_update.php +@@ -5,6 +5,8 @@ + * Post update functions for Media. + */ + ++use Drupal\Core\StringTranslation\TranslatableMarkup; ++ + /** + * Implements hook_removed_post_updates(). + */ +@@ -20,3 +22,52 @@ function media_removed_post_updates() { + 'media_post_update_remove_mappings_targeting_source_field' => '11.0.0', + ]; + } ++ ++/** ++ * Disable contextual links for media embeds in all text formats. ++ */ ++function media_post_update_add_show_contextual_links_as_false(&$sandbox = NULL): TranslatableMarkup { ++ // Initialize batch variables if this is the first run. ++ if (!isset($sandbox['total'])) { ++ // Load all filter_format configurations. ++ $config_names = \Drupal::service('config.storage')->listAll('filter.format.'); ++ $sandbox['config_names'] = $config_names; ++ $sandbox['total'] = count($sandbox['config_names']); ++ $sandbox['progress'] = 0; ++ ++ // In case there are no configurations to process. ++ if ($sandbox['total'] == 0) { ++ $sandbox['total'] = 1; ++ $sandbox['progress'] = 1; ++ } ++ } ++ ++ // Process configurations in chunks of 50. ++ $config_names = array_splice($sandbox['config_names'], 0, 50); ++ ++ foreach ($config_names as $config_name) { ++ $config = \Drupal::service('config.factory')->getEditable($config_name); ++ $filters = $config->get('filters'); ++ ++ if (isset($filters['media_embed'])) { ++ $media_embed_settings = $filters['media_embed']; ++ if (empty($media_embed_settings['settings']['show_contextual_links'])) { ++ $media_embed_settings['settings']['show_contextual_links'] = FALSE; ++ // Update the settings in the filters array. ++ $filters['media_embed'] = $media_embed_settings; ++ $config->set('filters', $filters); ++ $config->save(); ++ } ++ } ++ ++ $sandbox['progress']++; ++ } ++ ++ // Determine if the batch process is complete. ++ $sandbox['#finished'] = ($sandbox['progress'] / $sandbox['total']); ++ ++ return new TranslatableMarkup('Processed Filter Formats (@count/@total)', [ ++ '@count' => $sandbox['progress'], ++ '@total' => $sandbox['total'], ++ ]); ++} +diff --git a/core/modules/media/src/Plugin/Filter/MediaEmbed.php b/core/modules/media/src/Plugin/Filter/MediaEmbed.php +index 118422bf2c28d594569aa58a806ef722e4e0c4e4..71b7e1d65cc786786853181e1d6be45e57dae2b4 100644 +--- a/core/modules/media/src/Plugin/Filter/MediaEmbed.php ++++ b/core/modules/media/src/Plugin/Filter/MediaEmbed.php +@@ -39,6 +39,7 @@ + "default_view_mode" => "default", + "allowed_view_modes" => [], + "allowed_media_types" => [], ++ "show_contextual_links" => FALSE, + ], + )] + class MediaEmbed extends FilterBase implements ContainerFactoryPluginInterface, TrustedCallbackInterface { +@@ -182,6 +183,13 @@ public function settingsForm(array $form, FormStateInterface $form_state) { + '#element_validate' => [[static::class, 'validateOptions']], + ]; + ++ $form['show_contextual_links'] = [ ++ '#title' => $this->t("Show contextual links for embedded media"), ++ '#type' => 'checkbox', ++ '#default_value' => $this->settings['show_contextual_links'], ++ '#description' => $this->t('If selected, displays contextual links to edit/delete/etc. embedded media items.'), ++ ]; ++ + return $form; + } + +@@ -246,9 +254,11 @@ protected function renderMedia(MediaInterface $media, $view_mode, $langcode) { + // - caching an embedded media entity separately is unnecessary; the host + // entity is already render cached. + unset($build['#cache']['keys']); +- // - Contextual Links do not make sense for embedded entities; we only allow +- // the host entity to be contextually managed. +- $build['#pre_render'][] = static::class . '::disableContextualLinks'; ++ // - Contextual Links do not always make sense for embedded entities; users ++ // must opt in to exposing contextual links. ++ if (!$this->settings['show_contextual_links']) { ++ $build['#pre_render'][] = static::class . '::disableContextualLinks'; ++ } + // - default styling may break captioned media embeds; attach asset library + // to ensure captions behave as intended. Do not set this at the root + // level of the render array, otherwise it will be attached always, +diff --git a/core/modules/media/tests/src/Functional/MediaEmbedContextualLinksTest.php b/core/modules/media/tests/src/Functional/MediaEmbedContextualLinksTest.php +new file mode 100644 +index 0000000000000000000000000000000000000000..2b1a290ee9ff8f0bb60f7c541da3183b72ad73ce +--- /dev/null ++++ b/core/modules/media/tests/src/Functional/MediaEmbedContextualLinksTest.php +@@ -0,0 +1,81 @@ ++drupalLogin($this->drupalCreateUser([ ++ 'administer filters', ++ 'administer media', ++ 'access contextual links', ++ ])); ++ $this->drupalGet('admin/config/content/formats/add'); ++ $this->submitForm([ ++ 'name' => 'Media embed with contextual links', ++ 'format' => 'media_embed_with_contextual_link', ++ 'filters[media_embed][status]' => 1, ++ 'filters[media_embed][settings][show_contextual_links]' => 1, ++ ], 'Save configuration'); ++ $this->assertSession() ++ ->pageTextContains('Added text format Media embed with contextual links.'); ++ ++ // Create a media type. ++ $mediaType = $this->createMediaType('test'); ++ ++ // Create a media item. ++ $media = Media::create([ ++ 'bundle' => $mediaType->id(), ++ 'name' => 'Unnamed', ++ ]); ++ $media->save(); ++ ++ // Create a node type. ++ $node_type = NodeType::create([ ++ 'type' => $this->randomMachineName(), ++ 'name' => $this->randomString(), ++ ]); ++ $node_type->save(); ++ ++ // Add body field to node type. ++ node_add_body_field($node_type); ++ ++ $node = Node::create([ ++ 'type' => $node_type->id(), ++ 'title' => 'Test embed media to node body', ++ ]); ++ $node->body->value = ' '; ++ $node->body->format = 'media_embed_with_contextual_link'; ++ $node->save(); ++ ++ $this->drupalGet($node->toUrl()); ++ $this->assertSession()->elementExists('css', 'div[data-contextual-id*="media:media=' . $media->id() . ':"]'); ++ } ++ ++} +diff --git a/core/profiles/demo_umami/config/install/filter.format.basic_html.yml b/core/profiles/demo_umami/config/install/filter.format.basic_html.yml +index b57e2a67a7950fe32b2a422be14c9154f510ae97..a5a7ffb7e28ed5c2733cb433d35af1f80b2aa7c0 100644 +--- a/core/profiles/demo_umami/config/install/filter.format.basic_html.yml ++++ b/core/profiles/demo_umami/config/install/filter.format.basic_html.yml +@@ -71,3 +71,4 @@ filters: + image: image + remote_video: remote_video + video: video ++ show_contextual_links: false +diff --git a/core/profiles/demo_umami/config/install/filter.format.full_html.yml b/core/profiles/demo_umami/config/install/filter.format.full_html.yml +index 44a1d1ab590b2a92290db538287ff78138e01413..26977c062211d8253198eb552c482731584b5114 100644 +--- a/core/profiles/demo_umami/config/install/filter.format.full_html.yml ++++ b/core/profiles/demo_umami/config/install/filter.format.full_html.yml +@@ -64,3 +64,4 @@ filters: + image: image + remote_video: remote_video + video: video ++ show_contextual_links: false