diff --git a/a/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php b/b/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php index 960185f..8409969 100644 --- a/a/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php +++ b/b/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php @@ -6,6 +6,7 @@ namespace Drupal\leaflet_views\Plugin\views\style; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\NestedArray; +use Drupal\Component\Utility\Xss; use Drupal\Component\Render\MarkupInterface; use Drupal\Core\Entity\EntityDisplayRepositoryInterface; use Drupal\Core\Entity\EntityFieldManagerInterface; @@ -1202,6 +1203,35 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf return $langcode; } + /** + * Applies Views token replacement only when the text actually has tokens. + * + * PluginBase::viewsTokenReplace() always renders the text through the + * Twig "inline_template" pipeline once $tokens is non-empty, even when + * the text contains no '{{' placeholder at all. With hundreds/thousands + * of map features, most of the per-feature option strings (weight, path, + * className, popup/tooltip options, icon dimensions, ...) are static and + * never contain a token, so routing them through Twig on every single + * row is pure overhead. Skip straight to Xss::filterAdmin() in that case. + * + * @param string $text + * The text to token-replace. + * @param array $tokens + * The tokens available for replacement. + * + * @return string + * The token-replaced (or filtered) text. + */ + protected function fastViewsTokenReplace($text, array $tokens) { + if (!strlen((string) $text)) { + return ''; + } + if (!str_contains((string) $text, '{{')) { + return Xss::filterAdmin((string) $text); + } + return parent::viewsTokenReplace($text, $tokens); + } + /** * Get popup content for an entity. * @@ -1354,7 +1384,7 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf // Generate the weight feature property // (falls back to natural result ordering). $feature['weight'] = !empty($this->options['weight']) ? - intval(str_replace(["\n", "\r"], "", $this->viewsTokenReplace($this->options['weight'], $tokens))) : $id; + intval(str_replace(["\n", "\r"], "", $this->fastViewsTokenReplace($this->options['weight'], $tokens))) : $id; // Attach pop-ups if we have content. if (!empty($popup_content)) { @@ -1370,7 +1400,7 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf $feature['popup']['options'] = str_replace( ["\n", "\r"], "", - $this->viewsTokenReplace($this->options['leaflet_popup']['options'], $tokens) + $this->fastViewsTokenReplace($this->options['leaflet_popup']['options'], $tokens) ); } @@ -1383,20 +1413,20 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf $feature['path'] = htmlspecialchars_decode(str_replace([ "\n", "\r", - ], "", $this->viewsTokenReplace($this->options['path'], $tokens) + ], "", $this->fastViewsTokenReplace($this->options['path'], $tokens) )); } // Associate dynamic className property (token based) to icon. $feature['icon']['className'] = !empty($this->options['icon']['className']) ? - str_replace(["\n", "\r"], "", $this->viewsTokenReplace($this->options['icon']['className'], $tokens)) : ''; + str_replace(["\n", "\r"], "", $this->fastViewsTokenReplace($this->options['icon']['className'], $tokens)) : ''; // Add Feature additional Properties (if present). if (!empty($this->options['feature_properties']['values'])) { $feature['properties'] = htmlspecialchars_decode(str_replace( ["\n", "\r"], "", - $this->viewsTokenReplace($this->options['feature_properties']['values'], $tokens) + $this->fastViewsTokenReplace($this->options['feature_properties']['values'], $tokens) )); } @@ -1461,7 +1491,7 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf $feature['tooltip']['options'] = htmlspecialchars_decode(str_replace( ["\n", "\r"], "", - $this->viewsTokenReplace($this->options['leaflet_tooltip']['options'], $tokens) + $this->fastViewsTokenReplace($this->options['leaflet_tooltip']['options'], $tokens) )); } } @@ -1501,7 +1531,7 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf $feature['icon']['html'] = str_replace( ["\n", "\r"], "", - $this->viewsTokenReplace($this->options['icon']['html'], $tokens) + $this->fastViewsTokenReplace($this->options['icon']['html'], $tokens) ); $feature['icon']['html_class'] = $this->options['icon']['html_class']; break; @@ -1510,7 +1540,7 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf $feature['icon']['circle_marker_options'] = str_replace( ["\n", "\r"], "", - $this->viewsTokenReplace($this->options['icon']['circle_marker_options'], $tokens) + $this->fastViewsTokenReplace($this->options['icon']['circle_marker_options'], $tokens) ); break; @@ -1541,7 +1571,7 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf foreach ($dimensions as $dimension => $coords) { foreach ($coords as $coord) { if (!empty($this->options['icon'][$dimension][$coord])) { - $value = str_replace(["\n", "\r"], "", $this->viewsTokenReplace($this->options['icon'][$dimension][$coord], $tokens)); + $value = str_replace(["\n", "\r"], "", $this->fastViewsTokenReplace($this->options['icon'][$dimension][$coord], $tokens)); if (in_array($dimension, ['iconSize', 'shadowSize'])) { $feature['icon'][$dimension][$coord] = intval($value); } @@ -1567,7 +1597,7 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf $feature['icon']['iconUrl'] = str_replace( ["\n", "\r"], "", - $this->viewsTokenReplace($this->options['icon']['iconUrl'], $tokens) + $this->fastViewsTokenReplace($this->options['icon']['iconUrl'], $tokens) ); // Generate Absolute iconUrl if not external. @@ -1581,7 +1611,7 @@ class LeafletMap extends StylePluginBase implements ContainerFactoryPluginInterf $feature['icon']['shadowUrl'] = str_replace( ["\n", "\r"], "", - $this->viewsTokenReplace($this->options['icon']['shadowUrl'], $tokens) + $this->fastViewsTokenReplace($this->options['icon']['shadowUrl'], $tokens) ); // Generate Absolute shadowUrl if not external.