diff --git a/umap/static/umap/js/modules/rendering/template.js b/umap/static/umap/js/modules/rendering/template.js
index 33fbfb9d..f14b7eeb 100644
--- a/umap/static/umap/js/modules/rendering/template.js
+++ b/umap/static/umap/js/modules/rendering/template.js
@@ -152,6 +152,19 @@ class GeoRSSLink extends PopupTemplate {
}
class OSM extends TitleMixin(PopupTemplate) {
+ renderTitle(feature) {
+ const title = DomUtil.add('h3', 'popup-title')
+ const color = feature.getPreviewColor()
+ title.style.backgroundColor = color
+ const iconUrl = feature.getDynamicOption('iconUrl')
+ const icon = Icon.makeElement(iconUrl, title)
+ DomUtil.addClass(icon, 'icon')
+ Icon.setContrast(icon, title, iconUrl, color)
+ if (DomUtil.contrastedColor(title, color)) title.style.color = 'white'
+ DomUtil.add('span', '', title, this.getName(feature))
+ return title
+ }
+
getName(feature) {
const props = feature.properties
const locale = getLocale()
@@ -162,15 +175,6 @@ class OSM extends TitleMixin(PopupTemplate) {
renderBody(feature) {
const props = feature.properties
const body = document.createElement('div')
- const title = DomUtil.add('h3', 'popup-title', container)
- const color = feature.getPreviewColor()
- title.style.backgroundColor = color
- const iconUrl = feature.getDynamicOption('iconUrl')
- const icon = Icon.makeElement(iconUrl, title)
- DomUtil.addClass(icon, 'icon')
- Icon.setContrast(icon, title, iconUrl, color)
- if (DomUtil.contrastedColor(title, color)) title.style.color = 'white'
- DomUtil.add('span', '', title, this.getName(feature))
const street = props['addr:street']
if (street) {
const row = DomUtil.add('address', 'address', body)
@@ -207,6 +211,13 @@ class OSM extends TitleMixin(PopupTemplate) {
Utils.loadTemplate(`
`)
)
}
+ if (props.panoramax) {
+ body.appendChild(
+ Utils.loadTemplate(
+ ``
+ )
+ )
+ }
const id = props['@id'] || props.id
if (id) {
body.appendChild(
diff --git a/umap/static/umap/js/umap.core.js b/umap/static/umap/js/umap.core.js
index e7cf3cd5..0ddc7cba 100644
--- a/umap/static/umap/js/umap.core.js
+++ b/umap/static/umap/js/umap.core.js
@@ -170,22 +170,43 @@ L.DomUtil.contrastWCAG21 = (rgb) => {
const contrast = (whiteLum + 0.05) / (lum + 0.05)
return contrast > 3 ? 1 : 0
}
+L.DomUtil.colorNameToHex = (str) => {
+ const ctx = document.createElement('canvas').getContext('2d')
+ ctx.fillStyle = str
+ return ctx.fillStyle
+}
+L.DomUtil.hexToRGB = (hex) => {
+ return hex
+ .replace(
+ /^#?([a-f\d])([a-f\d])([a-f\d])$/i,
+ (m, r, g, b) => `#${r}${r}${g}${g}${b}${b}`
+ )
+ .substring(1)
+ .match(/.{2}/g)
+ .map((x) => Number.parseInt(x, 16))
+}
const _CACHE_CONSTRAST = {}
L.DomUtil.contrastedColor = (el, bgcolor) => {
// Return 0 for black and 1 for white
// bgcolor is a human color, it can be a any keyword (purpleā¦)
if (typeof _CACHE_CONSTRAST[bgcolor] !== 'undefined') return _CACHE_CONSTRAST[bgcolor]
- let out = 0
let rgb = window.getComputedStyle(el).getPropertyValue('background-color')
rgb = L.DomUtil.RGBRegex.exec(rgb)
- if (!rgb || rgb.length !== 4) return out
- rgb = [
- Number.parseInt(rgb[1], 10),
- Number.parseInt(rgb[2], 10),
- Number.parseInt(rgb[3], 10),
- ]
- out = L.DomUtil.contrastWCAG21(rgb)
+ if (rgb && rgb.length === 4) {
+ rgb = [
+ Number.parseInt(rgb[1], 10),
+ Number.parseInt(rgb[2], 10),
+ Number.parseInt(rgb[3], 10),
+ ]
+ } else {
+ // The element may not yet be added to the DOM, so let's try
+ // another way
+ const hex = L.DomUtil.colorNameToHex(bgcolor)
+ rgb = L.DomUtil.hexToRGB(hex)
+ }
+ if (!rgb) return 1
+ const out = L.DomUtil.contrastWCAG21(rgb)
if (bgcolor) _CACHE_CONSTRAST[bgcolor] = out
return out
}
diff --git a/umap/tests/integration/test_popup.py b/umap/tests/integration/test_popup.py
new file mode 100644
index 00000000..23d70aab
--- /dev/null
+++ b/umap/tests/integration/test_popup.py
@@ -0,0 +1,44 @@
+import pytest
+from playwright.sync_api import expect
+
+from ..base import DataLayerFactory
+
+pytestmark = pytest.mark.django_db
+
+OSM_DATA = {
+ "type": "FeatureCollection",
+ "features": [
+ {
+ "type": "Feature",
+ "geometry": {"type": "Point", "coordinates": [2.49, 48.79]},
+ "properties": {
+ "amenity": "restaurant",
+ "cuisine": "italian",
+ "name": "A Casa di Nonna",
+ "panoramax": "d811b398-d930-4cf8-95a2-0c29c34d9fca",
+ "phone": "+33 1 48 89 54 12",
+ "takeaway:covid19": "yes",
+ "wheelchair": "no",
+ "id": "node/1130849864",
+ },
+ "id": "AzMjk",
+ },
+ ],
+ "_umap_options": {
+ "popupTemplate": "OSM",
+ },
+}
+
+
+def test_openstreetmap_popup(live_server, map, page):
+ DataLayerFactory(map=map, data=OSM_DATA)
+ page.goto(f"{live_server.url}{map.get_absolute_url()}#18/48.79/2.49")
+ expect(page.locator(".umap-icon-active")).to_be_hidden()
+ page.locator(".leaflet-marker-icon").click()
+ expect(page.get_by_role("heading", name="A Casa di Nonna")).to_be_visible()
+ expect(page.get_by_text("+33 1 48 89 54 12")).to_be_visible()
+ img = page.locator(".umap-popup-content img")
+ expect(img).to_have_attribute(
+ "src",
+ "https://api.panoramax.xyz/api/pictures/d811b398-d930-4cf8-95a2-0c29c34d9fca/sd.jpg",
+ )