mirror of
https://github.com/umap-project/umap.git
synced 2025-04-28 19:42:36 +02:00
feat: experimental popup template for wikipedia (#2365)
When the data contain a `wikipedia` attribute, like used in OSM data (see https://wiki.openstreetmap.org/wiki/Key:wikipedia), this template will fetch the image and an extract for the given page.  fix #661
This commit is contained in:
commit
32acdc2070
5 changed files with 72 additions and 23 deletions
|
@ -199,8 +199,9 @@ class Feature {
|
||||||
this._umap.slideshow.current = this
|
this._umap.slideshow.current = this
|
||||||
}
|
}
|
||||||
this._umap.currentFeature = this
|
this._umap.currentFeature = this
|
||||||
this.attachPopup()
|
this.attachPopup().then(() => {
|
||||||
this.ui.openPopup(latlng || this.center)
|
this.ui.openPopup(latlng || this.center)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
render(fields) {
|
render(fields) {
|
||||||
|
@ -355,9 +356,11 @@ class Feature {
|
||||||
return loadPopup(this.getOption('popupShape') || old)
|
return loadPopup(this.getOption('popupShape') || old)
|
||||||
}
|
}
|
||||||
|
|
||||||
attachPopup() {
|
async attachPopup() {
|
||||||
const Class = this.getPopupClass()
|
const Class = this.getPopupClass()
|
||||||
this.ui.bindPopup(new Class(this))
|
const popup = new Class(this)
|
||||||
|
this.ui.bindPopup(popup)
|
||||||
|
return popup.loadContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
async confirmDelete() {
|
async confirmDelete() {
|
||||||
|
|
|
@ -21,23 +21,22 @@ export default function loadPopup(name) {
|
||||||
const Popup = BasePopup.extend({
|
const Popup = BasePopup.extend({
|
||||||
initialize: function (feature) {
|
initialize: function (feature) {
|
||||||
this.feature = feature
|
this.feature = feature
|
||||||
this.container = DomUtil.create('div', 'umap-popup')
|
BasePopup.prototype.initialize.call(this, {}, feature.ui)
|
||||||
this.format()
|
|
||||||
BasePopup.prototype.initialize.call(this, {}, feature)
|
|
||||||
this.setContent(this.container)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
format: function () {
|
loadContent: async function () {
|
||||||
|
const container = DomUtil.create('div', 'umap-popup')
|
||||||
const name = this.feature.getOption('popupTemplate')
|
const name = this.feature.getOption('popupTemplate')
|
||||||
this.content = loadTemplate(name, this.feature, this.container)
|
this.content = await loadTemplate(name, this.feature, container)
|
||||||
const elements = this.container.querySelectorAll('img,iframe')
|
const elements = container.querySelectorAll('img,iframe')
|
||||||
for (const element of elements) {
|
for (const element of elements) {
|
||||||
this.onElementLoaded(element)
|
this.onElementLoaded(element)
|
||||||
}
|
}
|
||||||
if (!elements.length && this.container.textContent.replace('\n', '') === '') {
|
if (!elements.length && container.textContent.replace('\n', '') === '') {
|
||||||
this.container.innerHTML = ''
|
container.innerHTML = ''
|
||||||
DomUtil.add('h3', '', this.container, this.feature.getDisplayName())
|
DomUtil.add('h3', '', container, this.feature.getDisplayName())
|
||||||
}
|
}
|
||||||
|
this.setContent(container)
|
||||||
},
|
},
|
||||||
|
|
||||||
onElementLoaded: function (el) {
|
onElementLoaded: function (el) {
|
||||||
|
|
|
@ -2,8 +2,9 @@ import { DomUtil, DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import { translate, getLocale } from '../i18n.js'
|
import { translate, getLocale } from '../i18n.js'
|
||||||
import * as Utils from '../utils.js'
|
import * as Utils from '../utils.js'
|
||||||
import * as Icon from './icon.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
|
let klass = PopupTemplate
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'GeoRSSLink':
|
case 'GeoRSSLink':
|
||||||
|
@ -18,9 +19,12 @@ export default function loadTemplate(name, feature, container) {
|
||||||
case 'OSM':
|
case 'OSM':
|
||||||
klass = OSM
|
klass = OSM
|
||||||
break
|
break
|
||||||
|
case 'Wikipedia':
|
||||||
|
klass = Wikipedia
|
||||||
|
break
|
||||||
}
|
}
|
||||||
const content = new klass()
|
const content = new klass()
|
||||||
return content.render(feature, container)
|
return await content.render(feature, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
class PopupTemplate {
|
class PopupTemplate {
|
||||||
|
@ -76,10 +80,10 @@ class PopupTemplate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render(feature, container) {
|
async render(feature, container) {
|
||||||
const title = this.renderTitle(feature)
|
const title = this.renderTitle(feature)
|
||||||
if (title) container.appendChild(title)
|
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)
|
if (body) DomUtil.add('div', 'umap-popup-content', container, body)
|
||||||
const footer = this.renderFooter(feature)
|
const footer = this.renderFooter(feature)
|
||||||
if (footer) container.appendChild(footer)
|
if (footer) container.appendChild(footer)
|
||||||
|
@ -111,7 +115,7 @@ class Table extends TitleMixin(PopupTemplate) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBody(feature) {
|
async renderBody(feature) {
|
||||||
const table = document.createElement('table')
|
const table = document.createElement('table')
|
||||||
|
|
||||||
for (const key in feature.properties) {
|
for (const key in feature.properties) {
|
||||||
|
@ -125,7 +129,7 @@ class Table extends TitleMixin(PopupTemplate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class GeoRSSImage extends TitleMixin(PopupTemplate) {
|
class GeoRSSImage extends TitleMixin(PopupTemplate) {
|
||||||
renderBody(feature) {
|
async renderBody(feature) {
|
||||||
const body = DomUtil.create('a')
|
const body = DomUtil.create('a')
|
||||||
body.href = feature.properties.link
|
body.href = feature.properties.link
|
||||||
body.target = '_blank'
|
body.target = '_blank'
|
||||||
|
@ -142,7 +146,7 @@ class GeoRSSImage extends TitleMixin(PopupTemplate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class GeoRSSLink extends PopupTemplate {
|
class GeoRSSLink extends PopupTemplate {
|
||||||
renderBody(feature) {
|
async renderBody(feature) {
|
||||||
if (feature.properties.link) {
|
if (feature.properties.link) {
|
||||||
return Utils.loadTemplate(
|
return Utils.loadTemplate(
|
||||||
`<a href="${feature.properties.link}" target="_blank"><h3>${feature.getDisplayName()}</h3></a>`
|
`<a href="${feature.properties.link}" target="_blank"><h3>${feature.getDisplayName()}</h3></a>`
|
||||||
|
@ -151,7 +155,7 @@ class GeoRSSLink extends PopupTemplate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OSM extends TitleMixin(PopupTemplate) {
|
class OSM extends PopupTemplate {
|
||||||
renderTitle(feature) {
|
renderTitle(feature) {
|
||||||
const title = DomUtil.add('h3', 'popup-title')
|
const title = DomUtil.add('h3', 'popup-title')
|
||||||
const color = feature.getPreviewColor()
|
const color = feature.getPreviewColor()
|
||||||
|
@ -172,7 +176,7 @@ class OSM extends TitleMixin(PopupTemplate) {
|
||||||
return props.name
|
return props.name
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBody(feature) {
|
async renderBody(feature) {
|
||||||
const props = feature.properties
|
const props = feature.properties
|
||||||
const body = document.createElement('div')
|
const body = document.createElement('div')
|
||||||
const locale = getLocale()
|
const locale = getLocale()
|
||||||
|
@ -238,3 +242,43 @@ class OSM extends TitleMixin(PopupTemplate) {
|
||||||
return body
|
return body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _WIKIPEDIA_CACHE = {}
|
||||||
|
|
||||||
|
class Wikipedia extends PopupTemplate {
|
||||||
|
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}`
|
||||||
|
const request = new Request()
|
||||||
|
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 || feature.getDisplayName()
|
||||||
|
const extract = page.extract || ''
|
||||||
|
const thumbnail = page.thumbnail?.source
|
||||||
|
const [content, { image }] = Utils.loadTemplateWithRefs(
|
||||||
|
`<div><h3>${Utils.escapeHTML(title)}</h3><img data-ref="image" hidden src="" />${Utils.escapeHTML(extract)}</div>`
|
||||||
|
)
|
||||||
|
if (thumbnail) {
|
||||||
|
image.src = thumbnail
|
||||||
|
image.hidden = false
|
||||||
|
}
|
||||||
|
body.appendChild(content)
|
||||||
|
}
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -404,6 +404,7 @@ export const SCHEMA = {
|
||||||
['GeoRSSImage', translate('GeoRSS (title + image)')],
|
['GeoRSSImage', translate('GeoRSS (title + image)')],
|
||||||
['GeoRSSLink', translate('GeoRSS (only link)')],
|
['GeoRSSLink', translate('GeoRSS (only link)')],
|
||||||
['OSM', translate('OpenStreetMap')],
|
['OSM', translate('OpenStreetMap')],
|
||||||
|
['Wikipedia', translate('Wikipedia')],
|
||||||
],
|
],
|
||||||
default: 'Default',
|
default: 'Default',
|
||||||
},
|
},
|
||||||
|
|
|
@ -115,6 +115,8 @@ export function escapeHTML(s) {
|
||||||
'span',
|
'span',
|
||||||
'dt',
|
'dt',
|
||||||
'dd',
|
'dd',
|
||||||
|
'b',
|
||||||
|
'i',
|
||||||
],
|
],
|
||||||
ADD_ATTR: [
|
ADD_ATTR: [
|
||||||
'target',
|
'target',
|
||||||
|
|
Loading…
Reference in a new issue