From 99ec3da19e4e5c9fa48023238956926a7251946c Mon Sep 17 00:00:00 2001
From: Axel Rutz <axel.rutz@machbarmacher.net>
Date: Sun, 21 Jul 2019 21:05:02 +0200
Subject: [PATCH] Issue #3068719: Attachments and Cacheability dropped for
 Leaflet (embeded|ajax) popups

---
 .../Controller/LeafletAjaxPopupController.php |  7 +++++-
 .../src/Plugin/views/style/LeafletMap.php     | 17 ++++++++++++--
 .../LeafletDefaultFormatter.php               | 23 ++++++++++++++-----
 3 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/modules/leaflet_views/src/Controller/LeafletAjaxPopupController.php b/modules/leaflet_views/src/Controller/LeafletAjaxPopupController.php
index 8a146ac..1898b5a 100644
--- a/modules/leaflet_views/src/Controller/LeafletAjaxPopupController.php
+++ b/modules/leaflet_views/src/Controller/LeafletAjaxPopupController.php
@@ -82,7 +82,12 @@ class LeafletAjaxPopupController extends ControllerBase {
     $entity_view_builder = $this->entityManager->getViewBuilder($entity->getEntityTypeId());
     $build = $entity_view_builder->view($entity, $view_mode, $langcode);
     $response = new HtmlResponse();
-    $response->setContent($this->renderer->renderRoot($build));
+    // Render this and set response content, so we get the HTML without page
+    // blocks. The response will also pick up cacheability metadata.
+    // @todo Care for attachments in https://www.drupal.org/project/leaflet/issues/3069250
+    // once we can rely on https://www.drupal.org/project/drupal/issues/1988968
+    $this->renderer->renderRoot($build);
+    $response->setContent($build);
     return $response;
   }
 
diff --git a/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php b/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php
index 163d947..5ca4ba2 100644
--- a/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php
+++ b/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php
@@ -4,6 +4,8 @@ namespace Drupal\leaflet_views\Plugin\views\style;
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\Render\BubbleableMetadata;
+use Drupal\Core\Render\RenderContext;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\Plugin\DataType\EntityAdapter;
 use Drupal\Core\Form\FormStateInterface;
@@ -665,6 +667,9 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf
 
     $data = [];
 
+    // Collect bubbleable metadata when doing early rendering.
+    $build_for_bubbleable_metadata = [];
+
     // Always render the map, otherwise ...
     $leaflet_map_style = !isset($this->options['leaflet_map']) ? $this->options['map'] : $this->options['leaflet_map'];
     $map = leaflet_map_get_info($leaflet_map_style);
@@ -754,7 +759,11 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf
               case '#rendered_entity':
                 $build = $this->entityManager->getViewBuilder($entity->getEntityTypeId())
                   ->view($entity, $this->options['view_mode'], $langcode);
-                $description = $this->renderer->renderPlain($build);
+                $render_context = new RenderContext();
+                $description = $this->renderer->executeInRenderContext($render_context, function () use (&$build) {
+                  return $this->renderer->render($build, TRUE);
+                });
+                $render_context->update($build_for_bubbleable_metadata);
                 break;
 
               case '#rendered_entity_ajax':
@@ -851,7 +860,11 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf
     // Allow other modules to add/alter the map js settings.
     $this->moduleHandler->alter('leaflet_map_view_style', $js_settings, $this);
 
-    return $this->leafletService->leafletRenderMap($js_settings['map'], $js_settings['features'], $this->options['height'] . 'px');
+    $build = $this->leafletService->leafletRenderMap($js_settings['map'], $js_settings['features'], $this->options['height'] . 'px');
+    BubbleableMetadata::createFromRenderArray($build)
+      ->merge(BubbleableMetadata::createFromRenderArray($build_for_bubbleable_metadata))
+      ->applyTo($build);
+    return $build;
   }
 
   /**
diff --git a/src/Plugin/Field/FieldFormatter/LeafletDefaultFormatter.php b/src/Plugin/Field/FieldFormatter/LeafletDefaultFormatter.php
index 031f127..4bd96e7 100644
--- a/src/Plugin/Field/FieldFormatter/LeafletDefaultFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/LeafletDefaultFormatter.php
@@ -3,6 +3,8 @@
 namespace Drupal\leaflet\Plugin\Field\FieldFormatter;
 
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Render\BubbleableMetadata;
+use Drupal\Core\Render\RenderContext;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
@@ -314,6 +316,7 @@ class LeafletDefaultFormatter extends FormatterBase implements ContainerFactoryP
       $this->fieldDefinition->getTargetEntityTypeId() => $items->getEntity(),
     ];
 
+    $results = [];
     $features = [];
     foreach ($items as $delta => $item) {
 
@@ -323,18 +326,27 @@ class LeafletDefaultFormatter extends FormatterBase implements ContainerFactoryP
 
       // Eventually set the popup content.
       if ($settings['popup']) {
-        // Construct the renderable array for popup title / text.
+        // Construct the renderable array for popup title / text. As we later
+        // convert that to plain text, losing attachments and cacheability, save
+        // them to $results.
         $build = [];
         if ($this->getSetting('popup_content')) {
-          $popup_content = $this->token->replace($this->getSetting('popup_content'), $token_context);
+          $bubbleable_metadata = new BubbleableMetadata();
+          $popup_content = $this->token->replace($this->getSetting('popup_content'), $token_context, $bubbleable_metadata);
           $build[] = [
             '#markup' => $popup_content,
           ];
+          $bubbleable_metadata->applyTo($results);
         }
 
-        // We need a string for using it inside the popup.
-        $build = $this->renderer->renderPlain($build);
-        $feature['popup'] = !empty($build) ? $build : $entity->label();;
+        // We need a string for using it inside the popup. Save attachments and
+        // cacheability to $results.
+        $render_context = new RenderContext();
+        $rendered = $this->renderer->executeInRenderContext($render_context, function () use (&$build) {
+          return $this->renderer->render($build, TRUE);
+        });
+        $feature['popup'] = !empty($rendered) ? $rendered : $entity->label();
+        $render_context->update($results);
       }
 
       // Add/merge eventual map icon definition from hook_leaflet_map_info.
@@ -368,7 +380,6 @@ class LeafletDefaultFormatter extends FormatterBase implements ContainerFactoryP
     // Allow other modules to add/alter the map js settings.
     $this->moduleHandler->alter('leaflet_default_map_formatter', $js_settings, $items);
 
-    $results = [];
     if (!empty($settings['multiple_map'])) {
       foreach ($js_settings['features'] as $k => $feature) {
         $map = $js_settings['map'];
-- 
2.17.1

