From 573a065e0574a45a45c54f9731256be2ab8061fc Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 11 Dec 2024 18:04:25 +0100 Subject: [PATCH 1/6] wip --- .../static/umap/js/modules/rendering/popup.js | 4 +- .../umap/js/modules/rendering/template.js | 48 +++++++++++++++---- umap/static/umap/js/modules/schema.js | 1 + 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/umap/static/umap/js/modules/rendering/popup.js b/umap/static/umap/js/modules/rendering/popup.js index 3baf2793..0a74c638 100644 --- a/umap/static/umap/js/modules/rendering/popup.js +++ b/umap/static/umap/js/modules/rendering/popup.js @@ -27,9 +27,9 @@ const Popup = BasePopup.extend({ this.setContent(this.container) }, - format: function () { + format: async function () { const name = this.feature.getOption('popupTemplate') - this.content = loadTemplate(name, this.feature, this.container) + this.content = await loadTemplate(name, this.feature, this.container) const elements = this.container.querySelectorAll('img,iframe') for (const element of elements) { this.onElementLoaded(element) diff --git a/umap/static/umap/js/modules/rendering/template.js b/umap/static/umap/js/modules/rendering/template.js index 838ad66e..9e7487a8 100644 --- a/umap/static/umap/js/modules/rendering/template.js +++ b/umap/static/umap/js/modules/rendering/template.js @@ -2,8 +2,9 @@ import { DomUtil, DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js' import { translate, getLocale } from '../i18n.js' import * as Utils from '../utils.js' import * as Icon from './icon.js' +import { Request } from '../request.js' -export default function loadTemplate(name, feature, container) { +export default async function loadTemplate(name, feature, container) { let klass = PopupTemplate switch (name) { case 'GeoRSSLink': @@ -18,9 +19,12 @@ export default function loadTemplate(name, feature, container) { case 'OSM': klass = OSM break + case 'Wikipedia': + klass = Wikipedia + break } const content = new klass() - return content.render(feature, container) + return await content.render(feature, container) } class PopupTemplate { @@ -76,10 +80,10 @@ class PopupTemplate { } } - render(feature, container) { + async render(feature, container) { const title = this.renderTitle(feature) if (title) container.appendChild(title) - const body = this.renderBody(feature) + const body = await this.renderBody(feature) if (body) DomUtil.add('div', 'umap-popup-content', container, body) const footer = this.renderFooter(feature) if (footer) container.appendChild(footer) @@ -111,7 +115,7 @@ class Table extends TitleMixin(PopupTemplate) { ) } - renderBody(feature) { + async renderBody(feature) { const table = document.createElement('table') for (const key in feature.properties) { @@ -125,7 +129,7 @@ class Table extends TitleMixin(PopupTemplate) { } class GeoRSSImage extends TitleMixin(PopupTemplate) { - renderBody(feature) { + async renderBody(feature) { const body = DomUtil.create('a') body.href = feature.properties.link body.target = '_blank' @@ -142,7 +146,7 @@ class GeoRSSImage extends TitleMixin(PopupTemplate) { } class GeoRSSLink extends PopupTemplate { - renderBody(feature) { + async renderBody(feature) { if (feature.properties.link) { return Utils.loadTemplate( `

${feature.getDisplayName()}

` @@ -151,7 +155,7 @@ class GeoRSSLink extends PopupTemplate { } } -class OSM extends TitleMixin(PopupTemplate) { +class OSM extends PopupTemplate { renderTitle(feature) { const title = DomUtil.add('h3', 'popup-title') const color = feature.getPreviewColor() @@ -172,7 +176,7 @@ class OSM extends TitleMixin(PopupTemplate) { return props.name } - renderBody(feature) { + async renderBody(feature) { const props = feature.properties const body = document.createElement('div') const locale = getLocale() @@ -238,3 +242,29 @@ class OSM extends TitleMixin(PopupTemplate) { return body } } + +class Wikipedia extends PopupTemplate { + async renderBody(feature) { + const body = document.createElement('div') + const wikipedia = feature.properties.wikipedia + if (!wikipedia) return 'No data' + // Wikipedia value should be in form of "{locale}:{title}", according to https://wiki.openstreetmap.org/wiki/Key:wikipedia + const [locale, page] = wikipedia.split(':') + const url = `https://${locale}.wikipedia.org/w/api.php?action=query&format=json&origin=*&pithumbsize=280&prop=extracts|pageimages&titles=${page}` + const request = new Request() + const response = await request.get(url) + if (response?.ok) { + const data = await response.json() + const page = Object.values(data.query.pages)[0] + const title = page.title + const extract = page.extract + const thumbnail = page.thumbnail.source + body.appendChild( + Utils.loadTemplate( + `

${title}

${extract}
` + ) + ) + } + return body + } +} diff --git a/umap/static/umap/js/modules/schema.js b/umap/static/umap/js/modules/schema.js index 6ac145e4..54322c10 100644 --- a/umap/static/umap/js/modules/schema.js +++ b/umap/static/umap/js/modules/schema.js @@ -404,6 +404,7 @@ export const SCHEMA = { ['GeoRSSImage', translate('GeoRSS (title + image)')], ['GeoRSSLink', translate('GeoRSS (only link)')], ['OSM', translate('OpenStreetMap')], + ['Wikipedia', translate('Wikipedia')], ], default: 'Default', }, From 7670989798785ecb2bc1a563e61df96404cdecf3 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Thu, 12 Dec 2024 15:29:54 +0100 Subject: [PATCH 2/6] fixup: bigger images from wikipedia --- umap/static/umap/js/modules/rendering/template.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/umap/static/umap/js/modules/rendering/template.js b/umap/static/umap/js/modules/rendering/template.js index 9e7487a8..232080dc 100644 --- a/umap/static/umap/js/modules/rendering/template.js +++ b/umap/static/umap/js/modules/rendering/template.js @@ -250,7 +250,7 @@ class Wikipedia extends PopupTemplate { if (!wikipedia) return 'No data' // Wikipedia value should be in form of "{locale}:{title}", according to https://wiki.openstreetmap.org/wiki/Key:wikipedia const [locale, page] = wikipedia.split(':') - const url = `https://${locale}.wikipedia.org/w/api.php?action=query&format=json&origin=*&pithumbsize=280&prop=extracts|pageimages&titles=${page}` + const url = `https://${locale}.wikipedia.org/w/api.php?action=query&format=json&origin=*&pithumbsize=500&prop=extracts|pageimages&titles=${page}` const request = new Request() const response = await request.get(url) if (response?.ok) { From 8a929d2352eba551f3f0cc30cdf24716535f9396 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Thu, 12 Dec 2024 15:30:06 +0100 Subject: [PATCH 3/6] fixup: allow aynchronous popups --- .../static/umap/js/modules/rendering/popup.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/umap/static/umap/js/modules/rendering/popup.js b/umap/static/umap/js/modules/rendering/popup.js index 0a74c638..7c07a39e 100644 --- a/umap/static/umap/js/modules/rendering/popup.js +++ b/umap/static/umap/js/modules/rendering/popup.js @@ -21,23 +21,23 @@ export default function loadPopup(name) { const Popup = BasePopup.extend({ initialize: function (feature) { this.feature = feature - this.container = DomUtil.create('div', 'umap-popup') - this.format() - BasePopup.prototype.initialize.call(this, {}, feature) - this.setContent(this.container) + BasePopup.prototype.initialize.call(this, {}, feature.ui) + this.getContentFromTemplate() }, - format: async function () { + getContentFromTemplate: async function () { + const container = DomUtil.create('div', 'umap-popup') const name = this.feature.getOption('popupTemplate') - this.content = await loadTemplate(name, this.feature, this.container) - const elements = this.container.querySelectorAll('img,iframe') + this.content = await loadTemplate(name, this.feature, container) + const elements = container.querySelectorAll('img,iframe') for (const element of elements) { this.onElementLoaded(element) } - if (!elements.length && this.container.textContent.replace('\n', '') === '') { - this.container.innerHTML = '' - DomUtil.add('h3', '', this.container, this.feature.getDisplayName()) + if (!elements.length && container.textContent.replace('\n', '') === '') { + container.innerHTML = '' + DomUtil.add('h3', '', container, this.feature.getDisplayName()) } + this.setContent(container) }, onElementLoaded: function (el) { From b7173d46296343f7f9fe1467006f87aa028f3653 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Fri, 13 Dec 2024 15:28:07 +0100 Subject: [PATCH 4/6] fixup: allow to display asynchronous content in the panel too --- umap/static/umap/js/modules/data/features.js | 11 +++++++---- umap/static/umap/js/modules/rendering/popup.js | 3 +-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/umap/static/umap/js/modules/data/features.js b/umap/static/umap/js/modules/data/features.js index a9171a72..6b60f9dc 100644 --- a/umap/static/umap/js/modules/data/features.js +++ b/umap/static/umap/js/modules/data/features.js @@ -199,8 +199,9 @@ class Feature { this._umap.slideshow.current = this } this._umap.currentFeature = this - this.attachPopup() - this.ui.openPopup(latlng || this.center) + this.attachPopup().then(() => { + this.ui.openPopup(latlng || this.center) + }) } render(fields) { @@ -355,9 +356,11 @@ class Feature { return loadPopup(this.getOption('popupShape') || old) } - attachPopup() { + async attachPopup() { const Class = this.getPopupClass() - this.ui.bindPopup(new Class(this)) + const popup = new Class(this) + this.ui.bindPopup(popup) + return popup.loadContent() } async confirmDelete() { diff --git a/umap/static/umap/js/modules/rendering/popup.js b/umap/static/umap/js/modules/rendering/popup.js index 7c07a39e..0b87d01e 100644 --- a/umap/static/umap/js/modules/rendering/popup.js +++ b/umap/static/umap/js/modules/rendering/popup.js @@ -22,10 +22,9 @@ const Popup = BasePopup.extend({ initialize: function (feature) { this.feature = feature BasePopup.prototype.initialize.call(this, {}, feature.ui) - this.getContentFromTemplate() }, - getContentFromTemplate: async function () { + loadContent: async function () { const container = DomUtil.create('div', 'umap-popup') const name = this.feature.getOption('popupTemplate') this.content = await loadTemplate(name, this.feature, container) From 6e5540fe7937a3e75c74df65ece1e5e3af95e6d5 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Fri, 13 Dec 2024 15:28:36 +0100 Subject: [PATCH 5/6] fixup: cache wikipedia calls and be a bit more defensive --- .../umap/js/modules/rendering/template.js | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/umap/static/umap/js/modules/rendering/template.js b/umap/static/umap/js/modules/rendering/template.js index 232080dc..80f0be0b 100644 --- a/umap/static/umap/js/modules/rendering/template.js +++ b/umap/static/umap/js/modules/rendering/template.js @@ -243,11 +243,11 @@ class OSM extends PopupTemplate { } } +const _WIKIPEDIA_CACHE = {} + class Wikipedia extends PopupTemplate { - async renderBody(feature) { - const body = document.createElement('div') - const wikipedia = feature.properties.wikipedia - if (!wikipedia) return 'No data' + async callWikipedia(wikipedia) { + if (wikipedia && _WIKIPEDIA_CACHE[wikipedia]) return _WIKIPEDIA_CACHE[wikipedia] // Wikipedia value should be in form of "{locale}:{title}", according to https://wiki.openstreetmap.org/wiki/Key:wikipedia const [locale, page] = wikipedia.split(':') const url = `https://${locale}.wikipedia.org/w/api.php?action=query&format=json&origin=*&pithumbsize=500&prop=extracts|pageimages&titles=${page}` @@ -255,15 +255,29 @@ class Wikipedia extends PopupTemplate { const response = await request.get(url) if (response?.ok) { const data = await response.json() + _WIKIPEDIA_CACHE[wikipedia] = data + return data + } + } + + async renderBody(feature) { + const body = document.createElement('div') + const wikipedia = feature.properties.wikipedia + if (!wikipedia) return '' + const data = await this.callWikipedia(wikipedia) + if (data) { const page = Object.values(data.query.pages)[0] - const title = page.title - const extract = page.extract - const thumbnail = page.thumbnail.source - body.appendChild( - Utils.loadTemplate( - `

${title}

${extract}
` - ) + const title = page.title || feature.getDisplayName() + const extract = page.extract || '' + const thumbnail = page.thumbnail?.source + const [content, { image }] = Utils.loadTemplateWithRefs( + `

${title}

${extract}
` ) + if (thumbnail) { + image.src = thumbnail + image.hidden = false + } + body.appendChild(content) } return body } From 92df1d792a2e879b370dec2ee654420d0a564938 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Tue, 17 Dec 2024 18:49:49 +0100 Subject: [PATCH 6/6] fixup: escape Wikipedia HTML, just in case --- umap/static/umap/js/modules/rendering/template.js | 2 +- umap/static/umap/js/modules/utils.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/umap/static/umap/js/modules/rendering/template.js b/umap/static/umap/js/modules/rendering/template.js index 80f0be0b..39854c6e 100644 --- a/umap/static/umap/js/modules/rendering/template.js +++ b/umap/static/umap/js/modules/rendering/template.js @@ -271,7 +271,7 @@ class Wikipedia extends PopupTemplate { const extract = page.extract || '' const thumbnail = page.thumbnail?.source const [content, { image }] = Utils.loadTemplateWithRefs( - `

${title}

${extract}
` + `

${Utils.escapeHTML(title)}

${Utils.escapeHTML(extract)}
` ) if (thumbnail) { image.src = thumbnail diff --git a/umap/static/umap/js/modules/utils.js b/umap/static/umap/js/modules/utils.js index 19085ec3..2f70edf4 100644 --- a/umap/static/umap/js/modules/utils.js +++ b/umap/static/umap/js/modules/utils.js @@ -115,6 +115,8 @@ export function escapeHTML(s) { 'span', 'dt', 'dd', + 'b', + 'i', ], ADD_ATTR: [ 'target',