diff --git a/umap/templates/umap/map_detail.html b/umap/templates/umap/map_detail.html
index 42000f4a..88eb5d4e 100644
--- a/umap/templates/umap/map_detail.html
+++ b/umap/templates/umap/map_detail.html
@@ -7,6 +7,11 @@
map_detail
{% endblock body_class %}
{% block extra_head %}
+ {% if preconnect_domains %}
+ {% for domain in preconnect_domains %}
+
+ {% endfor %}
+ {% endif %}
{% umap_css %}
{% umap_js locale=locale %}
{% if object.share_status != object.PUBLIC %}{% endif %}
diff --git a/umap/tests/base.py b/umap/tests/base.py
index 687793e6..62f948eb 100644
--- a/umap/tests/base.py
+++ b/umap/tests/base.py
@@ -81,7 +81,7 @@ class MapFactory(factory.django.DjangoModelFactory):
"attribution": "\xa9 OSM Contributors",
"maxZoom": 18,
"minZoom": 0,
- "url_template": "https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png",
+ "url_template": "https://a.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png",
},
"tilelayersControl": True,
"zoom": 7,
diff --git a/umap/tests/integration/test_export_map.py b/umap/tests/integration/test_export_map.py
index e1735e9b..69599dde 100644
--- a/umap/tests/integration/test_export_map.py
+++ b/umap/tests/integration/test_export_map.py
@@ -61,7 +61,7 @@ def test_umap_export(map, live_server, datalayer, page):
"attribution": "© OSM Contributors",
"maxZoom": 18,
"minZoom": 0,
- "url_template": "https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png",
+ "url_template": "https://a.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png",
},
"tilelayersControl": True,
"zoom": 7,
diff --git a/umap/tests/integration/test_map.py b/umap/tests/integration/test_map.py
index 3bcbb2f8..7f77ad5f 100644
--- a/umap/tests/integration/test_map.py
+++ b/umap/tests/integration/test_map.py
@@ -12,6 +12,35 @@ from ..base import DataLayerFactory
pytestmark = pytest.mark.django_db
+def test_preconnect_for_tilelayer(map, page, live_server, tilelayer):
+ page.goto(f"{live_server.url}{map.get_absolute_url()}")
+ meta = page.locator('link[rel="preconnect"]')
+ expect(meta).to_have_count(1)
+ expect(meta).to_have_attribute("href", "//a.tile.openstreetmap.fr")
+ # Add custom tilelayer
+ map.settings["properties"]["tilelayer"] = {
+ "name": "OSM Piano FR",
+ "maxZoom": 20,
+ "minZoom": 0,
+ "attribution": "test",
+ "url_template": "https://a.piano.tiles.quaidorsay.fr/fr{r}/{z}/{x}/{y}.png",
+ }
+ map.save()
+ page.goto(f"{live_server.url}{map.get_absolute_url()}")
+ expect(meta).to_have_attribute("href", "//a.piano.tiles.quaidorsay.fr")
+ # Add custom tilelayer with variable in domain, should create a preconnect
+ map.settings["properties"]["tilelayer"] = {
+ "name": "OSM Piano FR",
+ "maxZoom": 20,
+ "minZoom": 0,
+ "attribution": "test",
+ "url_template": "https://{s}.piano.tiles.quaidorsay.fr/fr{r}/{z}/{x}/{y}.png",
+ }
+ map.save()
+ page.goto(f"{live_server.url}{map.get_absolute_url()}")
+ expect(meta).to_have_count(0)
+
+
def test_default_view_latest_without_datalayer_should_use_default_center(
map, live_server, datalayer, page
):
diff --git a/umap/tests/test_map_views.py b/umap/tests/test_map_views.py
index 6ef798e2..f31350e3 100644
--- a/umap/tests/test_map_views.py
+++ b/umap/tests/test_map_views.py
@@ -19,7 +19,7 @@ def post_data():
return {
"name": "name",
"center": '{"type":"Point","coordinates":[13.447265624999998,48.94415123418794]}', # noqa
- "settings": '{"type":"Feature","geometry":{"type":"Point","coordinates":[5.0592041015625,52.05924589011585]},"properties":{"tilelayer":{"maxZoom":20,"url_template":"http://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png","minZoom":0,"attribution":"HOT and friends"},"licence":"","description":"","name":"test enrhûmé","tilelayersControl":true,"displayDataBrowserOnLoad":false,"displayPopupFooter":true,"displayCaptionOnLoad":false,"miniMap":true,"moreControl":true,"scaleControl":true,"zoomControl":true,"datalayersControl":true,"zoom":8}}', # noqa
+ "settings": '{"type":"Feature","geometry":{"type":"Point","coordinates":[5.0592041015625,52.05924589011585]},"properties":{"tilelayer":{"maxZoom":20,"url_template":"http://a.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png","minZoom":0,"attribution":"HOT and friends"},"licence":"","description":"","name":"test enrhûmé","tilelayersControl":true,"displayDataBrowserOnLoad":false,"displayPopupFooter":true,"displayCaptionOnLoad":false,"miniMap":true,"moreControl":true,"scaleControl":true,"zoomControl":true,"datalayersControl":true,"zoom":8}}', # noqa
}
@@ -624,7 +624,7 @@ def test_download(client, map, datalayer):
"attribution": "© OSM Contributors",
"maxZoom": 18,
"minZoom": 0,
- "url_template": "https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png",
+ "url_template": "https://a.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png",
},
"tilelayersControl": True,
"zoom": 7,
diff --git a/umap/views.py b/umap/views.py
index 4561fadf..b152afea 100644
--- a/umap/views.py
+++ b/umap/views.py
@@ -421,6 +421,21 @@ class MapDetailMixin:
model = Map
pk_url_kwarg = "map_id"
+ def set_preconnect(self, properties, context):
+ # Try to extract the tilelayer domain, in order to but a preconnect meta.
+ url_template = properties.get("tilelayer", {}).get("url_template")
+ # Not explicit tilelayer set, take the first of the list, which will be
+ # used by frontend too.
+ if not url_template:
+ tilelayers = properties.get("tilelayers")
+ if tilelayers:
+ url_template = tilelayers[0].get("url_template")
+ if url_template:
+ domain = urlparse(url_template).netloc
+ # Do not try to preconnect on domains with variables
+ if domain and "{" not in domain:
+ context["preconnect_domains"] = [f"//{domain}"]
+
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user = self.request.user
@@ -473,6 +488,7 @@ class MapDetailMixin:
map_settings["properties"].update(properties)
map_settings["properties"]["datalayers"] = self.get_datalayers()
context["map_settings"] = json.dumps(map_settings, indent=settings.DEBUG)
+ self.set_preconnect(map_settings["properties"], context)
return context
def get_datalayers(self):