mirror of
https://github.com/umap-project/umap.git
synced 2025-04-29 11:52:38 +02:00
Merge pull request #2034 from umap-project/popup-to-modules
chore: move popups to modules
This commit is contained in:
commit
9f5361f2c0
6 changed files with 329 additions and 349 deletions
|
@ -10,6 +10,7 @@ import { SCHEMA } from '../schema.js'
|
||||||
import { translate } from '../i18n.js'
|
import { translate } from '../i18n.js'
|
||||||
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
||||||
import { LeafletMarker, LeafletPolyline, LeafletPolygon } from '../rendering/ui.js'
|
import { LeafletMarker, LeafletPolyline, LeafletPolygon } from '../rendering/ui.js'
|
||||||
|
import loadPopup from '../rendering/popup.js'
|
||||||
|
|
||||||
class Feature {
|
class Feature {
|
||||||
constructor(datalayer, geojson = {}, id = null) {
|
constructor(datalayer, geojson = {}, id = null) {
|
||||||
|
@ -291,7 +292,7 @@ class Feature {
|
||||||
|
|
||||||
getPopupClass() {
|
getPopupClass() {
|
||||||
const old = this.getOption('popupTemplate') // Retrocompat.
|
const old = this.getOption('popupTemplate') // Retrocompat.
|
||||||
return U.Popup[this.getOption('popupShape') || old] || U.Popup
|
return loadPopup(this.getOption('popupShape') || old)
|
||||||
}
|
}
|
||||||
|
|
||||||
attachPopup() {
|
attachPopup() {
|
||||||
|
|
99
umap/static/umap/js/modules/rendering/popup.js
Normal file
99
umap/static/umap/js/modules/rendering/popup.js
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
import {
|
||||||
|
DomEvent,
|
||||||
|
DomUtil,
|
||||||
|
Path,
|
||||||
|
Popup as BasePopup,
|
||||||
|
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
import loadTemplate from './template.js'
|
||||||
|
import Browser from '../browser.js'
|
||||||
|
|
||||||
|
export default function loadPopup(name) {
|
||||||
|
switch (name) {
|
||||||
|
case 'Large':
|
||||||
|
return PopupLarge
|
||||||
|
case 'Panel':
|
||||||
|
return Panel
|
||||||
|
default:
|
||||||
|
return Popup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
|
||||||
|
format: function () {
|
||||||
|
const name = this.feature.getOption('popupTemplate')
|
||||||
|
this.content = loadTemplate(name, this.feature, this.container)
|
||||||
|
const elements = this.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())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onElementLoaded: function (el) {
|
||||||
|
DomEvent.on(el, 'load', () => {
|
||||||
|
this._updateLayout()
|
||||||
|
this._updatePosition()
|
||||||
|
this._adjustPan()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const PopupLarge = Popup.extend({
|
||||||
|
options: {
|
||||||
|
maxWidth: 500,
|
||||||
|
className: 'umap-popup-large',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const Panel = Popup.extend({
|
||||||
|
options: {
|
||||||
|
zoomAnimation: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
onAdd: function (map) {
|
||||||
|
map.panel.setDefaultMode('expanded')
|
||||||
|
map.panel.open({
|
||||||
|
content: this._content,
|
||||||
|
actions: [Browser.backButton(map)],
|
||||||
|
})
|
||||||
|
|
||||||
|
// fire events as in base class Popup.js:onAdd
|
||||||
|
map.fire('popupopen', { popup: this })
|
||||||
|
if (this._source) {
|
||||||
|
this._source.fire('popupopen', { popup: this }, true)
|
||||||
|
if (!(this._source instanceof Path)) {
|
||||||
|
this._source.on('preclick', DomEvent.stopPropagation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onRemove: function (map) {
|
||||||
|
map.panel.close()
|
||||||
|
|
||||||
|
// fire events as in base class Popup.js:onRemove
|
||||||
|
map.fire('popupclose', { popup: this })
|
||||||
|
if (this._source) {
|
||||||
|
this._source.fire('popupclose', { popup: this }, true)
|
||||||
|
if (!(this._source instanceof Path)) {
|
||||||
|
this._source.off('preclick', DomEvent.stopPropagation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
update: () => {},
|
||||||
|
_updateLayout: () => {},
|
||||||
|
_updatePosition: () => {},
|
||||||
|
_adjustPan: () => {},
|
||||||
|
_animateZoom: () => {},
|
||||||
|
})
|
214
umap/static/umap/js/modules/rendering/template.js
Normal file
214
umap/static/umap/js/modules/rendering/template.js
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
import { DomUtil, DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
|
import { translate, getLocale } from '../i18n.js'
|
||||||
|
import * as Utils from '../utils.js'
|
||||||
|
|
||||||
|
export default function loadTemplate(name, feature, container) {
|
||||||
|
let klass = PopupTemplate
|
||||||
|
switch (name) {
|
||||||
|
case 'GeoRSSLink':
|
||||||
|
klass = GeoRSSLink
|
||||||
|
break
|
||||||
|
case 'GeoRSSImage':
|
||||||
|
klass = GeoRSSImage
|
||||||
|
break
|
||||||
|
case 'Table':
|
||||||
|
klass = Table
|
||||||
|
break
|
||||||
|
case 'OSM':
|
||||||
|
klass = OSM
|
||||||
|
break
|
||||||
|
}
|
||||||
|
const content = new klass()
|
||||||
|
return content.render(feature, container)
|
||||||
|
}
|
||||||
|
|
||||||
|
class PopupTemplate {
|
||||||
|
renderTitle(feature, container) {}
|
||||||
|
|
||||||
|
renderBody(feature, container) {
|
||||||
|
const template = feature.getOption('popupContentTemplate')
|
||||||
|
const target = feature.getOption('outlinkTarget')
|
||||||
|
const properties = feature.extendedProperties()
|
||||||
|
// Resolve properties inside description
|
||||||
|
properties.description = Utils.greedyTemplate(
|
||||||
|
feature.properties.description || '',
|
||||||
|
properties
|
||||||
|
)
|
||||||
|
let content = Utils.greedyTemplate(template, properties)
|
||||||
|
content = Utils.toHTML(content, { target: target })
|
||||||
|
return Utils.loadTemplate(`<div class="umap-popup-container text">${content}</div>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderFooter(feature, container) {
|
||||||
|
if (feature.hasPopupFooter()) {
|
||||||
|
const template = `
|
||||||
|
<ul class="umap-popup-footer">
|
||||||
|
<li rel="prev" data-ref="previous"></li>
|
||||||
|
<li class="zoom" data-ref="zoom" title="${translate('Zoom to this feature')}"></li>
|
||||||
|
<li rel="next" data-ref="next"></li>
|
||||||
|
</ul>`
|
||||||
|
const [footer, { previous, zoom, next }] = Utils.loadTemplateWithRefs(template)
|
||||||
|
const nextFeature = feature.getNext()
|
||||||
|
const previousFeature = feature.getPrevious()
|
||||||
|
// Fixme: remove me when this is merged and released
|
||||||
|
// https://github.com/Leaflet/Leaflet/pull/9052
|
||||||
|
DomEvent.disableClickPropagation(footer)
|
||||||
|
if (nextFeature) {
|
||||||
|
next.title = translate('Go to «{feature}»', {
|
||||||
|
feature: nextFeature.properties.name || translate('next'),
|
||||||
|
})
|
||||||
|
DomEvent.on(next, 'click', () => {
|
||||||
|
nextFeature.zoomTo({ callback: nextFeature.view })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (previousFeature) {
|
||||||
|
previous.title = translate('Go to «{feature}»', {
|
||||||
|
feature: previousFeature.properties.name || translate('previous'),
|
||||||
|
})
|
||||||
|
DomEvent.on(previous, 'click', () => {
|
||||||
|
previousFeature.zoomTo({ callback: previousFeature.view })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
DomEvent.on(zoom, 'click', () => feature.zoomTo())
|
||||||
|
container.appendChild(footer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(feature, container) {
|
||||||
|
const title = this.renderTitle(feature, container)
|
||||||
|
if (title) container.appendChild(title)
|
||||||
|
const body = this.renderBody(feature, container)
|
||||||
|
if (body) DomUtil.add('div', 'umap-popup-content', container, body)
|
||||||
|
this.renderFooter(feature, container)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const TitleMixin = (Base) =>
|
||||||
|
class extends Base {
|
||||||
|
renderTitle(feature, container) {
|
||||||
|
const title = feature.getDisplayName()
|
||||||
|
if (title) {
|
||||||
|
return Utils.loadTemplate(`<h3 class="popup-title">${title}</h3>`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Table extends TitleMixin(PopupTemplate) {
|
||||||
|
getValue(feature, key) {
|
||||||
|
// TODO, manage links (url, mailto, wikipedia...)
|
||||||
|
const value = Utils.escapeHTML(feature.properties[key]).trim()
|
||||||
|
if (value.indexOf('http') === 0) {
|
||||||
|
return `<a href="${value}" target="_blank">${value}</a>`
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
makeRow(feature, key) {
|
||||||
|
return Utils.loadTemplate(
|
||||||
|
`<tr><th>${key}</th><td>${this.getValue(feature, key)}</td></tr>`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderBody(feature, container) {
|
||||||
|
const table = document.createElement('table')
|
||||||
|
|
||||||
|
for (const key in feature.properties) {
|
||||||
|
if (typeof feature.properties[key] === 'object' || key === 'name') continue
|
||||||
|
table.appendChild(this.makeRow(feature, key))
|
||||||
|
}
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GeoRSSImage extends TitleMixin(PopupTemplate) {
|
||||||
|
renderBody(feature, container) {
|
||||||
|
const body = DomUtil.create('a')
|
||||||
|
body.href = feature.properties.link
|
||||||
|
body.target = '_blank'
|
||||||
|
if (feature.properties.img) {
|
||||||
|
const img = DomUtil.create('img', '', body)
|
||||||
|
img.src = feature.properties.img
|
||||||
|
// Sadly, we are unable to override this from JS the clean way
|
||||||
|
// See https://github.com/Leaflet/Leaflet/commit/61d746818b99d362108545c151a27f09d60960ee#commitcomment-6061847
|
||||||
|
img.style.maxWidth = '500px'
|
||||||
|
img.style.maxHeight = '500px'
|
||||||
|
}
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GeoRSSLink extends TitleMixin(PopupTemplate) {
|
||||||
|
renderBody(feature, container) {
|
||||||
|
const title = this.renderTitle(feature, container)
|
||||||
|
return Utils.loadTemplate(
|
||||||
|
`<a href="${feature.properties.link}" target="_blank">${title}</a>`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OSM extends TitleMixin(PopupTemplate) {
|
||||||
|
getName(feature) {
|
||||||
|
const props = feature.properties
|
||||||
|
const locale = getLocale()
|
||||||
|
if (locale && props[`name:${locale}`]) return props[`name:${locale}`]
|
||||||
|
return props.name
|
||||||
|
}
|
||||||
|
|
||||||
|
renderBody(feature, container) {
|
||||||
|
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 = U.Icon.makeIconElement(iconUrl, title)
|
||||||
|
DomUtil.addClass(icon, 'icon')
|
||||||
|
U.Icon.setIconContrast(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)
|
||||||
|
const number = props['addr:housenumber']
|
||||||
|
if (number) {
|
||||||
|
// Poor way to deal with international forms of writting addresses
|
||||||
|
DomUtil.add('span', '', row, `${translate('No.')}: ${number}`)
|
||||||
|
DomUtil.add('span', '', row, `${translate('Street')}: ${street}`)
|
||||||
|
} else {
|
||||||
|
DomUtil.add('span', '', row, street)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (props.website) {
|
||||||
|
body.appendChild(
|
||||||
|
Utils.loadTemplate(`<div><a href="${props.website}">${props.website}</a></div>`)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const phone = props.phone || props['contact:phone']
|
||||||
|
if (phone) {
|
||||||
|
body.appendChild(
|
||||||
|
Utils.loadTemplate(`<div><a href="tel:${phone}">${phone}</a></div>`)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (props.mobile) {
|
||||||
|
body.appendChild(
|
||||||
|
Utils.loadTemplate(
|
||||||
|
`<div><a href="tel:${props.mobile}">${props.mobile}</a></div>`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const email = props.email || props['contact:email']
|
||||||
|
if (email) {
|
||||||
|
body.appendChild(
|
||||||
|
Utils.loadTemplate(`<div><a href="mailto:${email}">${email}</a></div>`)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const id = props['@id'] || props.id
|
||||||
|
if (id) {
|
||||||
|
body.appendChild(
|
||||||
|
Utils.loadTemplate(
|
||||||
|
`<div class="osm-link"><a href="https://www.openstreetmap.org/${id}">${translate('See on OpenStreetMap')}</a></div>`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
}
|
|
@ -392,13 +392,20 @@ export function loadTemplate(html) {
|
||||||
return template.content.firstElementChild
|
return template.content.firstElementChild
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function loadTemplateWithRefs(html) {
|
||||||
|
const element = loadTemplate(html)
|
||||||
|
const elements = {}
|
||||||
|
for (const node of element.querySelectorAll('[data-ref]')) {
|
||||||
|
elements[node.dataset.ref] = node
|
||||||
|
}
|
||||||
|
return [element, elements]
|
||||||
|
}
|
||||||
|
|
||||||
export class WithTemplate {
|
export class WithTemplate {
|
||||||
loadTemplate(html) {
|
loadTemplate(html) {
|
||||||
this.element = loadTemplate(html)
|
const [element, elements] = loadTemplateWithRefs(html)
|
||||||
this.elements = {}
|
this.element = element
|
||||||
for (const element of this.element.querySelectorAll('[data-ref]')) {
|
this.elements = elements
|
||||||
this.elements[element.dataset.ref] = element
|
|
||||||
}
|
|
||||||
return this.element
|
return this.element
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,341 +0,0 @@
|
||||||
/* Shapes */
|
|
||||||
|
|
||||||
U.Popup = L.Popup.extend({
|
|
||||||
options: {
|
|
||||||
parseTemplate: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function (feature) {
|
|
||||||
this.feature = feature
|
|
||||||
this.container = L.DomUtil.create('div', 'umap-popup')
|
|
||||||
this.format()
|
|
||||||
L.Popup.prototype.initialize.call(this, {}, feature)
|
|
||||||
this.setContent(this.container)
|
|
||||||
},
|
|
||||||
|
|
||||||
format: function () {
|
|
||||||
const mode = this.feature.getOption('popupTemplate') || 'Default'
|
|
||||||
const klass = U.PopupTemplate[mode] || U.PopupTemplate.Default
|
|
||||||
this.content = new klass(this.feature, this.container)
|
|
||||||
this.content.render()
|
|
||||||
const els = this.container.querySelectorAll('img,iframe')
|
|
||||||
for (let i = 0; i < els.length; i++) {
|
|
||||||
this.onElementLoaded(els[i])
|
|
||||||
}
|
|
||||||
if (!els.length && this.container.textContent.replace('\n', '') === '') {
|
|
||||||
this.container.innerHTML = ''
|
|
||||||
L.DomUtil.add('h3', '', this.container, this.feature.getDisplayName())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onElementLoaded: function (el) {
|
|
||||||
L.DomEvent.on(
|
|
||||||
el,
|
|
||||||
'load',
|
|
||||||
function () {
|
|
||||||
this._updateLayout()
|
|
||||||
this._updatePosition()
|
|
||||||
this._adjustPan()
|
|
||||||
},
|
|
||||||
this
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.Popup.Large = U.Popup.extend({
|
|
||||||
options: {
|
|
||||||
maxWidth: 500,
|
|
||||||
className: 'umap-popup-large',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.Popup.Panel = U.Popup.extend({
|
|
||||||
options: {
|
|
||||||
zoomAnimation: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
onAdd: function (map) {
|
|
||||||
map.panel.setDefaultMode('expanded')
|
|
||||||
map.panel.open({
|
|
||||||
content: this._content,
|
|
||||||
actions: [U.Browser.backButton(map)],
|
|
||||||
})
|
|
||||||
|
|
||||||
// fire events as in base class Popup.js:onAdd
|
|
||||||
map.fire('popupopen', { popup: this })
|
|
||||||
if (this._source) {
|
|
||||||
this._source.fire('popupopen', { popup: this }, true)
|
|
||||||
if (!(this._source instanceof L.Path)) {
|
|
||||||
this._source.on('preclick', L.DomEvent.stopPropagation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onRemove: function (map) {
|
|
||||||
map.panel.close()
|
|
||||||
|
|
||||||
// fire events as in base class Popup.js:onRemove
|
|
||||||
map.fire('popupclose', { popup: this })
|
|
||||||
if (this._source) {
|
|
||||||
this._source.fire('popupclose', { popup: this }, true)
|
|
||||||
if (!(this._source instanceof L.Path)) {
|
|
||||||
this._source.off('preclick', L.DomEvent.stopPropagation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
update: () => {},
|
|
||||||
_updateLayout: () => {},
|
|
||||||
_updatePosition: () => {},
|
|
||||||
_adjustPan: () => {},
|
|
||||||
_animateZoom: () => {},
|
|
||||||
})
|
|
||||||
U.Popup.SimplePanel = U.Popup.Panel // Retrocompat.
|
|
||||||
|
|
||||||
/* Content templates */
|
|
||||||
|
|
||||||
U.PopupTemplate = {}
|
|
||||||
|
|
||||||
U.PopupTemplate.Default = L.Class.extend({
|
|
||||||
initialize: function (feature, container) {
|
|
||||||
this.feature = feature
|
|
||||||
this.container = container
|
|
||||||
},
|
|
||||||
|
|
||||||
renderTitle: () => {},
|
|
||||||
|
|
||||||
renderBody: function () {
|
|
||||||
const template = this.feature.getOption('popupContentTemplate')
|
|
||||||
const target = this.feature.getOption('outlinkTarget')
|
|
||||||
const container = L.DomUtil.create('div', 'umap-popup-container text')
|
|
||||||
let content = ''
|
|
||||||
let properties
|
|
||||||
let center
|
|
||||||
properties = this.feature.extendedProperties()
|
|
||||||
// Resolve properties inside description
|
|
||||||
properties.description = U.Utils.greedyTemplate(
|
|
||||||
this.feature.properties.description || '',
|
|
||||||
properties
|
|
||||||
)
|
|
||||||
content = U.Utils.greedyTemplate(template, properties)
|
|
||||||
content = U.Utils.toHTML(content, { target: target })
|
|
||||||
container.innerHTML = content
|
|
||||||
return container
|
|
||||||
},
|
|
||||||
|
|
||||||
renderFooter: function () {
|
|
||||||
if (this.feature.hasPopupFooter()) {
|
|
||||||
const footer = L.DomUtil.create('ul', 'umap-popup-footer', this.container)
|
|
||||||
const previousLi = L.DomUtil.create('li', 'previous', footer)
|
|
||||||
const zoomLi = L.DomUtil.create('li', 'zoom', footer)
|
|
||||||
const nextLi = L.DomUtil.create('li', 'next', footer)
|
|
||||||
const next = this.feature.getNext()
|
|
||||||
const prev = this.feature.getPrevious()
|
|
||||||
// Fixme: remove me when this is merged and released
|
|
||||||
// https://github.com/Leaflet/Leaflet/pull/9052
|
|
||||||
L.DomEvent.disableClickPropagation(footer)
|
|
||||||
if (next)
|
|
||||||
nextLi.title = L._('Go to «{feature}»', {
|
|
||||||
feature: next.properties.name || L._('next'),
|
|
||||||
})
|
|
||||||
if (prev)
|
|
||||||
previousLi.title = L._('Go to «{feature}»', {
|
|
||||||
feature: prev.properties.name || L._('previous'),
|
|
||||||
})
|
|
||||||
zoomLi.title = L._('Zoom to this feature')
|
|
||||||
L.DomEvent.on(nextLi, 'click', () => {
|
|
||||||
if (next) next.zoomTo({ callback: next.view })
|
|
||||||
})
|
|
||||||
L.DomEvent.on(previousLi, 'click', () => {
|
|
||||||
if (prev) prev.zoomTo({ callback: prev.view })
|
|
||||||
})
|
|
||||||
L.DomEvent.on(
|
|
||||||
zoomLi,
|
|
||||||
'click',
|
|
||||||
function () {
|
|
||||||
this.zoomTo()
|
|
||||||
},
|
|
||||||
this.feature
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function () {
|
|
||||||
const title = this.renderTitle()
|
|
||||||
if (title) this.container.appendChild(title)
|
|
||||||
const body = this.renderBody()
|
|
||||||
if (body) L.DomUtil.add('div', 'umap-popup-content', this.container, body)
|
|
||||||
this.renderFooter()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.PopupTemplate.BaseWithTitle = U.PopupTemplate.Default.extend({
|
|
||||||
renderTitle: function () {
|
|
||||||
let title
|
|
||||||
if (this.feature.getDisplayName()) {
|
|
||||||
title = L.DomUtil.create('h3', 'popup-title')
|
|
||||||
title.textContent = this.feature.getDisplayName()
|
|
||||||
}
|
|
||||||
return title
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.PopupTemplate.Table = U.PopupTemplate.BaseWithTitle.extend({
|
|
||||||
formatRow: (key, value) => {
|
|
||||||
if (value.indexOf('http') === 0) {
|
|
||||||
value = `<a href="${value}" target="_blank">${value}</a>`
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
},
|
|
||||||
|
|
||||||
addRow: function (container, key, value) {
|
|
||||||
const tr = L.DomUtil.create('tr', '', container)
|
|
||||||
L.DomUtil.add('th', '', tr, key)
|
|
||||||
L.DomUtil.element({
|
|
||||||
tagName: 'td',
|
|
||||||
parent: tr,
|
|
||||||
innerHTML: this.formatRow(key, value),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
renderBody: function () {
|
|
||||||
const table = L.DomUtil.create('table')
|
|
||||||
|
|
||||||
for (const key in this.feature.properties) {
|
|
||||||
if (typeof this.feature.properties[key] === 'object' || key === 'name') continue
|
|
||||||
// TODO, manage links (url, mailto, wikipedia...)
|
|
||||||
this.addRow(table, key, U.Utils.escapeHTML(this.feature.properties[key]).trim())
|
|
||||||
}
|
|
||||||
return table
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.PopupTemplate.GeoRSSImage = U.PopupTemplate.BaseWithTitle.extend({
|
|
||||||
options: {
|
|
||||||
minWidth: 300,
|
|
||||||
maxWidth: 500,
|
|
||||||
className: 'umap-popup-large umap-georss-image',
|
|
||||||
},
|
|
||||||
|
|
||||||
renderBody: function () {
|
|
||||||
const container = L.DomUtil.create('a')
|
|
||||||
container.href = this.feature.properties.link
|
|
||||||
container.target = '_blank'
|
|
||||||
if (this.feature.properties.img) {
|
|
||||||
const img = L.DomUtil.create('img', '', container)
|
|
||||||
img.src = this.feature.properties.img
|
|
||||||
// Sadly, we are unable to override this from JS the clean way
|
|
||||||
// See https://github.com/Leaflet/Leaflet/commit/61d746818b99d362108545c151a27f09d60960ee#commitcomment-6061847
|
|
||||||
img.style.maxWidth = `${this.options.maxWidth}px`
|
|
||||||
img.style.maxHeight = `${this.options.maxWidth}px`
|
|
||||||
this.onElementLoaded(img)
|
|
||||||
}
|
|
||||||
return container
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.PopupTemplate.GeoRSSLink = U.PopupTemplate.Default.extend({
|
|
||||||
options: {
|
|
||||||
className: 'umap-georss-link',
|
|
||||||
},
|
|
||||||
|
|
||||||
renderBody: function () {
|
|
||||||
const title = this.renderTitle(this)
|
|
||||||
const a = L.DomUtil.add('a')
|
|
||||||
a.href = this.feature.properties.link
|
|
||||||
a.target = '_blank'
|
|
||||||
a.appendChild(title)
|
|
||||||
return a
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
U.PopupTemplate.OSM = U.PopupTemplate.Default.extend({
|
|
||||||
options: {
|
|
||||||
className: 'umap-openstreetmap',
|
|
||||||
},
|
|
||||||
|
|
||||||
getName: function () {
|
|
||||||
const props = this.feature.properties
|
|
||||||
const locale = L.getLocale()
|
|
||||||
if (locale && props[`name:${locale}`]) return props[`name:${locale}`]
|
|
||||||
return props.name
|
|
||||||
},
|
|
||||||
|
|
||||||
renderBody: function () {
|
|
||||||
const props = this.feature.properties
|
|
||||||
const container = L.DomUtil.add('div')
|
|
||||||
const title = L.DomUtil.add('h3', 'popup-title', container)
|
|
||||||
const color = this.feature.getPreviewColor()
|
|
||||||
title.style.backgroundColor = color
|
|
||||||
const iconUrl = this.feature.getDynamicOption('iconUrl')
|
|
||||||
const icon = U.Icon.makeIconElement(iconUrl, title)
|
|
||||||
L.DomUtil.addClass(icon, 'icon')
|
|
||||||
U.Icon.setIconContrast(icon, title, iconUrl, color)
|
|
||||||
if (L.DomUtil.contrastedColor(title, color)) title.style.color = 'white'
|
|
||||||
L.DomUtil.add('span', '', title, this.getName())
|
|
||||||
const street = props['addr:street']
|
|
||||||
if (street) {
|
|
||||||
const row = L.DomUtil.add('address', 'address', container)
|
|
||||||
const number = props['addr:housenumber']
|
|
||||||
if (number) {
|
|
||||||
// Poor way to deal with international forms of writting addresses
|
|
||||||
L.DomUtil.add('span', '', row, `${L._('No.')}: ${number}`)
|
|
||||||
L.DomUtil.add('span', '', row, `${L._('Street')}: ${street}`)
|
|
||||||
} else {
|
|
||||||
L.DomUtil.add('span', '', row, street)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (props.website) {
|
|
||||||
L.DomUtil.element({
|
|
||||||
tagName: 'a',
|
|
||||||
parent: container,
|
|
||||||
href: props.website,
|
|
||||||
textContent: props.website,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const phone = props.phone || props['contact:phone']
|
|
||||||
if (phone) {
|
|
||||||
L.DomUtil.add(
|
|
||||||
'div',
|
|
||||||
'',
|
|
||||||
container,
|
|
||||||
L.DomUtil.element({ tagName: 'a', href: `tel:${phone}`, textContent: phone })
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (props.mobile) {
|
|
||||||
L.DomUtil.add(
|
|
||||||
'div',
|
|
||||||
'',
|
|
||||||
container,
|
|
||||||
L.DomUtil.element({
|
|
||||||
tagName: 'a',
|
|
||||||
href: `tel:${props.mobile}`,
|
|
||||||
textContent: props.mobile,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
const email = props.email || props['contact:email']
|
|
||||||
if (email) {
|
|
||||||
L.DomUtil.add(
|
|
||||||
'div',
|
|
||||||
'',
|
|
||||||
container,
|
|
||||||
L.DomUtil.element('a', { href: `mailto:${email}`, textContent: email })
|
|
||||||
)
|
|
||||||
}
|
|
||||||
const id = props['@id'] || props.id
|
|
||||||
if (id) {
|
|
||||||
L.DomUtil.add(
|
|
||||||
'div',
|
|
||||||
'osm-link',
|
|
||||||
container,
|
|
||||||
L.DomUtil.element({
|
|
||||||
tagName: 'a',
|
|
||||||
href: `https://www.openstreetmap.org/${id}`,
|
|
||||||
textContent: L._('See on OpenStreetMap'),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return container
|
|
||||||
},
|
|
||||||
})
|
|
|
@ -1017,10 +1017,10 @@ a.umap-control-caption,
|
||||||
.umap-popup-footer li.zoom:before {
|
.umap-popup-footer li.zoom:before {
|
||||||
background-position: -5px -101px;
|
background-position: -5px -101px;
|
||||||
}
|
}
|
||||||
.umap-popup-footer li.previous:before {
|
.umap-popup-footer li[rel="prev"]:before {
|
||||||
background-position: -28px -77px;
|
background-position: -28px -77px;
|
||||||
}
|
}
|
||||||
.umap-popup-footer li.next:before {
|
.umap-popup-footer li[rel="next"]:before {
|
||||||
background-position: -5px -77px;
|
background-position: -5px -77px;
|
||||||
}
|
}
|
||||||
.umap-popup a:hover {
|
.umap-popup a:hover {
|
||||||
|
|
Loading…
Reference in a new issue