mirror of
https://github.com/umap-project/umap.git
synced 2025-05-05 14:01:50 +02:00
chore: apply Biome unsafe changes
This commit is contained in:
parent
ef33a26f11
commit
ec645fb6e6
32 changed files with 1431 additions and 714 deletions
|
@ -71,7 +71,9 @@ export class BaseAutocomplete {
|
||||||
onKeyDown(e) {
|
onKeyDown(e) {
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case 'Tab':
|
case 'Tab':
|
||||||
if (this.current !== null) this.setChoice()
|
if (this.current !== null) {
|
||||||
|
this.setChoice()
|
||||||
|
}
|
||||||
DomEvent.stop(e)
|
DomEvent.stop(e)
|
||||||
break
|
break
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
|
@ -195,8 +197,11 @@ export class BaseAutocomplete {
|
||||||
|
|
||||||
highlight() {
|
highlight() {
|
||||||
this.results.forEach((result, index) => {
|
this.results.forEach((result, index) => {
|
||||||
if (index === this.current) DomUtil.addClass(result.el, 'on')
|
if (index === this.current) {
|
||||||
else DomUtil.removeClass(result.el, 'on')
|
DomUtil.addClass(result.el, 'on')
|
||||||
|
} else {
|
||||||
|
DomUtil.removeClass(result.el, 'on')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,8 +254,10 @@ export class BaseAjax extends BaseAutocomplete {
|
||||||
this.clear()
|
this.clear()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (val === this.cache) return
|
if (val === this.cache) {
|
||||||
else this.cache = val
|
return
|
||||||
|
}
|
||||||
|
this.cache = val
|
||||||
val = val.toLowerCase()
|
val = val.toLowerCase()
|
||||||
const url = Util.template(this.url, { q: encodeURIComponent(val) })
|
const url = Util.template(this.url, { q: encodeURIComponent(val) })
|
||||||
this.handleResults(await this._search(url))
|
this.handleResults(await this._search(url))
|
||||||
|
@ -258,7 +265,7 @@ export class BaseAjax extends BaseAutocomplete {
|
||||||
|
|
||||||
async _search(url) {
|
async _search(url) {
|
||||||
const response = await this.request.get(url)
|
const response = await this.request.get(url)
|
||||||
if (response && response.ok) {
|
if (response?.ok) {
|
||||||
return await response.json()
|
return await response.json()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,12 @@ export default class Browser {
|
||||||
}
|
}
|
||||||
|
|
||||||
addFeature(feature, parent) {
|
addFeature(feature, parent) {
|
||||||
if (feature.isFiltered()) return
|
if (feature.isFiltered()) {
|
||||||
if (this.options.inBbox && !feature.isOnScreen(this.bounds)) return
|
return
|
||||||
|
}
|
||||||
|
if (this.options.inBbox && !feature.isOnScreen(this.bounds)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const row = DomUtil.create('li', `${feature.getClassName()} feature`)
|
const row = DomUtil.create('li', `${feature.getClassName()} feature`)
|
||||||
const zoom_to = DomUtil.createButtonIcon(
|
const zoom_to = DomUtil.createButtonIcon(
|
||||||
row,
|
row,
|
||||||
|
@ -62,9 +66,11 @@ export default class Browser {
|
||||||
|
|
||||||
addDataLayer(datalayer, parent) {
|
addDataLayer(datalayer, parent) {
|
||||||
let className = `datalayer ${datalayer.getHidableClass()}`
|
let className = `datalayer ${datalayer.getHidableClass()}`
|
||||||
if (this.mode !== 'layers') className += ' show-list'
|
if (this.mode !== 'layers') {
|
||||||
const container = DomUtil.create('div', className, parent),
|
className += ' show-list'
|
||||||
headline = DomUtil.create('h5', '', container)
|
}
|
||||||
|
const container = DomUtil.create('div', className, parent)
|
||||||
|
const headline = DomUtil.create('h5', '', container)
|
||||||
container.id = this.datalayerId(datalayer)
|
container.id = this.datalayerId(datalayer)
|
||||||
const ul = DomUtil.create('ul', '', container)
|
const ul = DomUtil.create('ul', '', container)
|
||||||
this.updateDatalayer(datalayer)
|
this.updateDatalayer(datalayer)
|
||||||
|
@ -75,7 +81,9 @@ export default class Browser {
|
||||||
this.bounds = this.map.getBounds()
|
this.bounds = this.map.getBounds()
|
||||||
const parent = DomUtil.get(this.datalayerId(datalayer))
|
const parent = DomUtil.get(this.datalayerId(datalayer))
|
||||||
// Panel is not open
|
// Panel is not open
|
||||||
if (!parent) return
|
if (!parent) {
|
||||||
|
return
|
||||||
|
}
|
||||||
parent.classList.toggle('off', !datalayer.isVisible())
|
parent.classList.toggle('off', !datalayer.isVisible())
|
||||||
const container = parent.querySelector('ul')
|
const container = parent.querySelector('ul')
|
||||||
const headline = parent.querySelector('h5')
|
const headline = parent.querySelector('h5')
|
||||||
|
@ -90,9 +98,9 @@ export default class Browser {
|
||||||
container.innerHTML = ''
|
container.innerHTML = ''
|
||||||
datalayer.eachFeature((feature) => this.addFeature(feature, container))
|
datalayer.eachFeature((feature) => this.addFeature(feature, container))
|
||||||
|
|
||||||
const total = datalayer.count(),
|
const total = datalayer.count()
|
||||||
current = container.querySelectorAll('li').length,
|
const current = container.querySelectorAll('li').length
|
||||||
count = total == current ? total : `${current}/${total}`
|
const count = total === current ? total : `${current}/${total}`
|
||||||
const counter = DomUtil.create('span', 'datalayer-counter', headline)
|
const counter = DomUtil.create('span', 'datalayer-counter', headline)
|
||||||
counter.textContent = `(${count})`
|
counter.textContent = `(${count})`
|
||||||
counter.title = translate(`Features in this layer: ${count}`)
|
counter.title = translate(`Features in this layer: ${count}`)
|
||||||
|
@ -112,7 +120,9 @@ export default class Browser {
|
||||||
}
|
}
|
||||||
|
|
||||||
redraw() {
|
redraw() {
|
||||||
if (this.isOpen()) this.open()
|
if (this.isOpen()) {
|
||||||
|
this.open()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isOpen() {
|
isOpen() {
|
||||||
|
@ -124,16 +134,22 @@ export default class Browser {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMoveEnd() {
|
onMoveEnd() {
|
||||||
if (!this.isOpen()) return
|
if (!this.isOpen()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const isListDynamic = this.options.inBbox
|
const isListDynamic = this.options.inBbox
|
||||||
this.map.eachBrowsableDataLayer((datalayer) => {
|
this.map.eachBrowsableDataLayer((datalayer) => {
|
||||||
if (!isListDynamic && !datalayer.hasDynamicData()) return
|
if (!isListDynamic && !datalayer.hasDynamicData()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.updateDatalayer(datalayer)
|
this.updateDatalayer(datalayer)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
if (!this.isOpen()) return
|
if (!this.isOpen()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.dataContainer.innerHTML = ''
|
this.dataContainer.innerHTML = ''
|
||||||
this.map.eachBrowsableDataLayer((datalayer) => {
|
this.map.eachBrowsableDataLayer((datalayer) => {
|
||||||
this.addDataLayer(datalayer, this.dataContainer)
|
this.addDataLayer(datalayer, this.dataContainer)
|
||||||
|
@ -142,7 +158,9 @@ export default class Browser {
|
||||||
|
|
||||||
open(mode) {
|
open(mode) {
|
||||||
// Force only if mode is known, otherwise keep current mode.
|
// Force only if mode is known, otherwise keep current mode.
|
||||||
if (mode) this.mode = mode
|
if (mode) {
|
||||||
|
this.mode = mode
|
||||||
|
}
|
||||||
const container = DomUtil.create('div')
|
const container = DomUtil.create('div')
|
||||||
// HOTFIX. Remove when this is released:
|
// HOTFIX. Remove when this is released:
|
||||||
// https://github.com/Leaflet/Leaflet/pull/9052
|
// https://github.com/Leaflet/Leaflet/pull/9052
|
||||||
|
@ -185,7 +203,9 @@ export default class Browser {
|
||||||
}
|
}
|
||||||
const reset = DomUtil.createButton('flat', formContainer, '', () => {
|
const reset = DomUtil.createButton('flat', formContainer, '', () => {
|
||||||
builder.form.reset()
|
builder.form.reset()
|
||||||
if (filtersBuilder) filtersBuilder.form.reset()
|
if (filtersBuilder) {
|
||||||
|
filtersBuilder.form.reset()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
DomUtil.createIcon(reset, 'icon-restore')
|
DomUtil.createIcon(reset, 'icon-restore')
|
||||||
DomUtil.element({
|
DomUtil.element({
|
||||||
|
|
|
@ -12,7 +12,9 @@ export default class Caption {
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh() {
|
refresh() {
|
||||||
if (!this.isOpen()) return
|
if (!this.isOpen()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.open()
|
this.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,10 +41,12 @@ export default class Caption {
|
||||||
}
|
}
|
||||||
|
|
||||||
addDataLayer(datalayer, container) {
|
addDataLayer(datalayer, container) {
|
||||||
if (!datalayer.options.inCaption) return
|
if (!datalayer.options.inCaption) {
|
||||||
const p = DomUtil.create('p', 'datalayer-legend', container),
|
return
|
||||||
legend = DomUtil.create('span', '', p),
|
}
|
||||||
headline = DomUtil.create('strong', '', p)
|
const p = DomUtil.create('p', 'datalayer-legend', container)
|
||||||
|
const legend = DomUtil.create('span', '', p)
|
||||||
|
const headline = DomUtil.create('strong', '', p)
|
||||||
datalayer.onceLoaded(() => {
|
datalayer.onceLoaded(() => {
|
||||||
datalayer.renderLegend(legend)
|
datalayer.renderLegend(legend)
|
||||||
if (datalayer.options.description) {
|
if (datalayer.options.description) {
|
||||||
|
|
|
@ -6,7 +6,6 @@ console.log(DOMPurifyInitializer)
|
||||||
export default function getPurify() {
|
export default function getPurify() {
|
||||||
if (typeof window === 'undefined') {
|
if (typeof window === 'undefined') {
|
||||||
return DOMPurifyInitializer(new JSDOM('').window)
|
return DOMPurifyInitializer(new JSDOM('').window)
|
||||||
} else {
|
|
||||||
return DOMPurifyInitializer(window)
|
|
||||||
}
|
}
|
||||||
|
return DOMPurifyInitializer(window)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default class Facets {
|
||||||
let selected
|
let selected
|
||||||
|
|
||||||
names.forEach((name) => {
|
names.forEach((name) => {
|
||||||
const type = defined[name]['type']
|
const type = defined[name].type
|
||||||
properties[name] = { type: type }
|
properties[name] = { type: type }
|
||||||
selected = this.selected[name] || {}
|
selected = this.selected[name] || {}
|
||||||
selected.type = type
|
selected.type = type
|
||||||
|
@ -28,18 +28,24 @@ export default class Facets {
|
||||||
datalayer.eachFeature((feature) => {
|
datalayer.eachFeature((feature) => {
|
||||||
names.forEach((name) => {
|
names.forEach((name) => {
|
||||||
let value = feature.properties[name]
|
let value = feature.properties[name]
|
||||||
const type = defined[name]['type']
|
const type = defined[name].type
|
||||||
const parser = this.getParser(type)
|
const parser = this.getParser(type)
|
||||||
value = parser(value)
|
value = parser(value)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'date':
|
case 'date':
|
||||||
case 'datetime':
|
case 'datetime':
|
||||||
case 'number':
|
case 'number':
|
||||||
if (!isNaN(value)) {
|
if (!Number.isNaN(value)) {
|
||||||
if (isNaN(properties[name].min) || properties[name].min > value) {
|
if (
|
||||||
|
Number.isNaN(properties[name].min) ||
|
||||||
|
properties[name].min > value
|
||||||
|
) {
|
||||||
properties[name].min = value
|
properties[name].min = value
|
||||||
}
|
}
|
||||||
if (isNaN(properties[name].max) || properties[name].max < value) {
|
if (
|
||||||
|
Number.isNaN(properties[name].max) ||
|
||||||
|
properties[name].max < value
|
||||||
|
) {
|
||||||
properties[name].max = value
|
properties[name].max = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +64,7 @@ export default class Facets {
|
||||||
|
|
||||||
isActive() {
|
isActive() {
|
||||||
for (const { type, min, max, choices } of Object.values(this.selected)) {
|
for (const { type, min, max, choices } of Object.values(this.selected)) {
|
||||||
if (min !== undefined || max != undefined || choices?.length) {
|
if (min !== undefined || max !== undefined || choices?.length) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +79,7 @@ export default class Facets {
|
||||||
const fields = names.map((name) => {
|
const fields = names.map((name) => {
|
||||||
const criteria = facetProperties[name]
|
const criteria = facetProperties[name]
|
||||||
let handler = 'FacetSearchChoices'
|
let handler = 'FacetSearchChoices'
|
||||||
switch (criteria['type']) {
|
switch (criteria.type) {
|
||||||
case 'number':
|
case 'number':
|
||||||
handler = 'FacetSearchNumber'
|
handler = 'FacetSearchNumber'
|
||||||
break
|
break
|
||||||
|
@ -84,7 +90,7 @@ export default class Facets {
|
||||||
handler = 'FacetSearchDateTime'
|
handler = 'FacetSearchDateTime'
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
const label = defined[name]['label']
|
const label = defined[name].label
|
||||||
return [
|
return [
|
||||||
`selected.${name}`,
|
`selected.${name}`,
|
||||||
{
|
{
|
||||||
|
|
|
@ -191,7 +191,7 @@ export default class Help {
|
||||||
const container = DomUtil.add('div')
|
const container = DomUtil.add('div')
|
||||||
DomUtil.createTitle(container, translate('Help'))
|
DomUtil.createTitle(container, translate('Help'))
|
||||||
// Special dynamic case. Do we still think this dialog is usefull ?
|
// Special dynamic case. Do we still think this dialog is usefull ?
|
||||||
if (entries == 'edit') {
|
if (entries === 'edit') {
|
||||||
DomUtil.element({
|
DomUtil.element({
|
||||||
tagName: 'div',
|
tagName: 'div',
|
||||||
className: 'umap-help-entry',
|
className: 'umap-help-entry',
|
||||||
|
|
|
@ -179,15 +179,17 @@ export default class Importer {
|
||||||
this.format === 'umap' || !this.url
|
this.format === 'umap' || !this.url
|
||||||
)
|
)
|
||||||
this.qs('[name=layer-name]').toggleAttribute('hidden', Boolean(this.layerId))
|
this.qs('[name=layer-name]').toggleAttribute('hidden', Boolean(this.layerId))
|
||||||
this.qs('#clear').toggleAttribute('hidden', !Boolean(this.layerId))
|
this.qs('#clear').toggleAttribute('hidden', !this.layerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
onFileChange(e) {
|
onFileChange(e) {
|
||||||
let type = '',
|
let type = ''
|
||||||
newType
|
let newType
|
||||||
for (const file of e.target.files) {
|
for (const file of e.target.files) {
|
||||||
newType = U.Utils.detectFileType(file)
|
newType = U.Utils.detectFileType(file)
|
||||||
if (!type && newType) type = newType
|
if (!type && newType) {
|
||||||
|
type = newType
|
||||||
|
}
|
||||||
if (type && newType !== type) {
|
if (type && newType !== type) {
|
||||||
type = ''
|
type = ''
|
||||||
break
|
break
|
||||||
|
@ -223,7 +225,9 @@ export default class Importer {
|
||||||
}
|
}
|
||||||
|
|
||||||
open() {
|
open() {
|
||||||
if (!this.container) this.build()
|
if (!this.container) {
|
||||||
|
this.build()
|
||||||
|
}
|
||||||
const onLoad = this.map.editPanel.open({ content: this.container })
|
const onLoad = this.map.editPanel.open({ content: this.container })
|
||||||
onLoad.then(() => this.onLoad())
|
onLoad.then(() => this.onLoad())
|
||||||
}
|
}
|
||||||
|
@ -294,7 +298,9 @@ export default class Importer {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const layer = this.layer
|
const layer = this.layer
|
||||||
if (this.clear) layer.empty()
|
if (this.clear) {
|
||||||
|
layer.empty()
|
||||||
|
}
|
||||||
if (this.files.length) {
|
if (this.files.length) {
|
||||||
for (const file of this.files) {
|
for (const file of this.files) {
|
||||||
this.map.processFileToImport(file, layer, this.format)
|
this.map.processFileToImport(file, layer, this.format)
|
||||||
|
|
|
@ -52,7 +52,7 @@ export class Importer {
|
||||||
container.innerHTML = TEMPLATE
|
container.innerHTML = TEMPLATE
|
||||||
const response = await importer.map.request.get(`${this.baseUrl}/themes`)
|
const response = await importer.map.request.get(`${this.baseUrl}/themes`)
|
||||||
const select = container.querySelector('select')
|
const select = container.querySelector('select')
|
||||||
if (response && response.ok) {
|
if (response?.ok) {
|
||||||
const { themes } = await response.json()
|
const { themes } = await response.json()
|
||||||
themes.sort((a, b) => Utils.naturalSort(a['name:fr'], b['name:fr']))
|
themes.sort((a, b) => Utils.naturalSort(a['name:fr'], b['name:fr']))
|
||||||
for (const theme of themes) {
|
for (const theme of themes) {
|
||||||
|
|
|
@ -65,12 +65,18 @@ export class Importer {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const outMode = container.querySelector('[name=out-mode]').value
|
const outMode = container.querySelector('[name=out-mode]').value
|
||||||
if (!tags.startsWith('[')) tags = `[${tags}]`
|
if (!tags.startsWith('[')) {
|
||||||
|
tags = `[${tags}]`
|
||||||
|
}
|
||||||
let area = '{south},{west},{north},{east}'
|
let area = '{south},{west},{north},{east}'
|
||||||
if (boundary) area = `area:${boundary}`
|
if (boundary) {
|
||||||
|
area = `area:${boundary}`
|
||||||
|
}
|
||||||
const query = `[out:json];nwr${tags}(${area});out ${outMode};`
|
const query = `[out:json];nwr${tags}(${area});out ${outMode};`
|
||||||
importer.url = `${this.baseUrl}?data=${query}`
|
importer.url = `${this.baseUrl}?data=${query}`
|
||||||
if (boundary) importer.layerName = boundaryName
|
if (boundary) {
|
||||||
|
importer.layerName = boundaryName
|
||||||
|
}
|
||||||
importer.format = 'osm'
|
importer.format = 'osm'
|
||||||
importer.dialog.close()
|
importer.dialog.close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,9 @@ export default class Orderable {
|
||||||
this.src = null
|
this.src = null
|
||||||
this.dst = null
|
this.dst = null
|
||||||
this.els = this.parent.querySelectorAll(selector)
|
this.els = this.parent.querySelectorAll(selector)
|
||||||
for (let i = 0; i < this.els.length; i++) this.makeDraggable(this.els[i])
|
for (let i = 0; i < this.els.length; i++) {
|
||||||
|
this.makeDraggable(this.els[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
makeDraggable(node) {
|
makeDraggable(node) {
|
||||||
|
@ -26,7 +28,9 @@ export default class Orderable {
|
||||||
|
|
||||||
findTarget(node) {
|
findTarget(node) {
|
||||||
while (node) {
|
while (node) {
|
||||||
if (this.nodeIndex(node) !== -1) return node
|
if (this.nodeIndex(node) !== -1) {
|
||||||
|
return node
|
||||||
|
}
|
||||||
node = node.parentNode
|
node = node.parentNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +52,9 @@ export default class Orderable {
|
||||||
|
|
||||||
onDragOver(e) {
|
onDragOver(e) {
|
||||||
DomEvent.stop(e)
|
DomEvent.stop(e)
|
||||||
if (e.preventDefault) e.preventDefault() // Necessary. Allows us to drop.
|
if (e.preventDefault) {
|
||||||
|
e.preventDefault() // Necessary. Allows us to drop.
|
||||||
|
}
|
||||||
e.dataTransfer.dropEffect = 'move'
|
e.dataTransfer.dropEffect = 'move'
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -57,12 +63,17 @@ export default class Orderable {
|
||||||
DomEvent.stop(e)
|
DomEvent.stop(e)
|
||||||
// e.target is the current hover target.
|
// e.target is the current hover target.
|
||||||
const dst = this.findTarget(e.target)
|
const dst = this.findTarget(e.target)
|
||||||
if (!dst || dst === this.src) return
|
if (!dst || dst === this.src) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.dst = dst
|
this.dst = dst
|
||||||
const targetIndex = this.nodeIndex(this.dst),
|
const targetIndex = this.nodeIndex(this.dst)
|
||||||
srcIndex = this.nodeIndex(this.src)
|
const srcIndex = this.nodeIndex(this.src)
|
||||||
if (targetIndex > srcIndex) this.parent.insertBefore(this.dst, this.src)
|
if (targetIndex > srcIndex) {
|
||||||
else this.parent.insertBefore(this.src, this.dst)
|
this.parent.insertBefore(this.dst, this.src)
|
||||||
|
} else {
|
||||||
|
this.parent.insertBefore(this.src, this.dst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDragLeave(e) {
|
onDragLeave(e) {
|
||||||
|
@ -71,8 +82,12 @@ export default class Orderable {
|
||||||
|
|
||||||
onDrop(e) {
|
onDrop(e) {
|
||||||
// e.target is current target element.
|
// e.target is current target element.
|
||||||
if (e.stopPropagation) e.stopPropagation() // Stops the browser from redirecting.
|
if (e.stopPropagation) {
|
||||||
if (!this.dst) return
|
e.stopPropagation() // Stops the browser from redirecting.
|
||||||
|
}
|
||||||
|
if (!this.dst) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.onCommit(this.src, this.dst, this.initialIndex, this.nodeIndex(this.src))
|
this.onCommit(this.src, this.dst, this.initialIndex, this.nodeIndex(this.src))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,9 @@ export class Request extends BaseRequest {
|
||||||
)
|
)
|
||||||
return response
|
return response
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof NOKError) return this._onNOK(error)
|
if (error instanceof NOKError) {
|
||||||
|
return this._onNOK(error)
|
||||||
|
}
|
||||||
return this._onError(error)
|
return this._onError(error)
|
||||||
} finally {
|
} finally {
|
||||||
this.fire('dataload', { id: id })
|
this.fire('dataload', { id: id })
|
||||||
|
@ -122,7 +124,9 @@ export class ServerRequest extends Request {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _as_json(response) {
|
async _as_json(response) {
|
||||||
if (Array.isArray(response)) return response
|
if (Array.isArray(response)) {
|
||||||
|
return response
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
if (data.info) {
|
if (data.info) {
|
||||||
|
|
|
@ -18,7 +18,9 @@ class Rule {
|
||||||
|
|
||||||
set isDirty(status) {
|
set isDirty(status) {
|
||||||
this._isDirty = status
|
this._isDirty = status
|
||||||
if (status) this.map.isDirty = status
|
if (status) {
|
||||||
|
this.map.isDirty = status
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(map, condition = '', options = {}) {
|
constructor(map, condition = '', options = {}) {
|
||||||
|
@ -49,7 +51,7 @@ class Rule {
|
||||||
}
|
}
|
||||||
|
|
||||||
not_equal(other) {
|
not_equal(other) {
|
||||||
return this.expected != other
|
return this.expected !== other
|
||||||
}
|
}
|
||||||
|
|
||||||
gt(other) {
|
gt(other) {
|
||||||
|
@ -71,16 +73,23 @@ class Rule {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vars.length != 2) return
|
if (vars.length !== 2) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.key = vars[0]
|
this.key = vars[0]
|
||||||
this.expected = vars[1]
|
this.expected = vars[1]
|
||||||
if (!isNaN(this.expected)) this.cast = Number.parseFloat
|
if (!Number.isNaN(this.expected)) {
|
||||||
else if (['true', 'false'].includes(this.expected)) this.cast = (v) => !!v
|
this.cast = Number.parseFloat
|
||||||
|
} else if (['true', 'false'].includes(this.expected)) {
|
||||||
|
this.cast = (v) => !!v
|
||||||
|
}
|
||||||
this.expected = this.cast(this.expected)
|
this.expected = this.cast(this.expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
match(props) {
|
match(props) {
|
||||||
if (!this.operator || !this.active) return false
|
if (!this.operator || !this.active) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return this.operator(this.cast(props[this.key]))
|
return this.operator(this.cast(props[this.key]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +153,9 @@ class Rule {
|
||||||
remove,
|
remove,
|
||||||
'click',
|
'click',
|
||||||
function () {
|
function () {
|
||||||
if (!confirm(translate('Are you sure you want to delete this rule?'))) return
|
if (!confirm(translate('Are you sure you want to delete this rule?'))) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this._delete()
|
this._delete()
|
||||||
this.map.editPanel.close()
|
this.map.editPanel.close()
|
||||||
},
|
},
|
||||||
|
@ -161,7 +172,7 @@ class Rule {
|
||||||
}
|
}
|
||||||
|
|
||||||
_delete() {
|
_delete() {
|
||||||
this.map.rules.rules = this.map.rules.rules.filter((rule) => rule != this)
|
this.map.rules.rules = this.map.rules.rules.filter((rule) => rule !== this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,16 +184,20 @@ export default class Rules {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadRules() {
|
loadRules() {
|
||||||
if (!this.map.options.rules?.length) return
|
if (!this.map.options.rules?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
for (const { condition, options } of this.map.options.rules) {
|
for (const { condition, options } of this.map.options.rules) {
|
||||||
if (!condition) continue
|
if (!condition) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
this.rules.push(new Rule(this.map, condition, options))
|
this.rules.push(new Rule(this.map, condition, options))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onReorder(src, dst, initialIndex, finalIndex) {
|
onReorder(src, dst, initialIndex, finalIndex) {
|
||||||
const moved = this.rules.find((rule) => stamp(rule) == src.dataset.id)
|
const moved = this.rules.find((rule) => stamp(rule) === src.dataset.id)
|
||||||
const reference = this.rules.find((rule) => stamp(rule) == dst.dataset.id)
|
const reference = this.rules.find((rule) => stamp(rule) === dst.dataset.id)
|
||||||
const movedIdx = this.rules.indexOf(moved)
|
const movedIdx = this.rules.indexOf(moved)
|
||||||
let referenceIdx = this.rules.indexOf(reference)
|
let referenceIdx = this.rules.indexOf(reference)
|
||||||
const minIndex = Math.min(movedIdx, referenceIdx)
|
const minIndex = Math.min(movedIdx, referenceIdx)
|
||||||
|
@ -190,9 +205,13 @@ export default class Rules {
|
||||||
moved._delete() // Remove from array
|
moved._delete() // Remove from array
|
||||||
referenceIdx = this.rules.indexOf(reference)
|
referenceIdx = this.rules.indexOf(reference)
|
||||||
let newIdx
|
let newIdx
|
||||||
if (finalIndex === 0) newIdx = 0
|
if (finalIndex === 0) {
|
||||||
else if (finalIndex > initialIndex) newIdx = referenceIdx
|
newIdx = 0
|
||||||
else newIdx = referenceIdx + 1
|
} else if (finalIndex > initialIndex) {
|
||||||
|
newIdx = referenceIdx
|
||||||
|
} else {
|
||||||
|
newIdx = referenceIdx + 1
|
||||||
|
}
|
||||||
this.rules.splice(newIdx, 0, moved)
|
this.rules.splice(newIdx, 0, moved)
|
||||||
moved.isDirty = true
|
moved.isDirty = true
|
||||||
this.map.render(['rules'])
|
this.map.render(['rules'])
|
||||||
|
@ -231,7 +250,9 @@ export default class Rules {
|
||||||
getOption(option, feature) {
|
getOption(option, feature) {
|
||||||
for (const rule of this.rules) {
|
for (const rule of this.rules) {
|
||||||
if (rule.match(feature.properties)) {
|
if (rule.match(feature.properties)) {
|
||||||
if (Utils.usableOption(rule.options, option)) return rule.options[option]
|
if (Utils.usableOption(rule.options, option)) {
|
||||||
|
return rule.options[option]
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,9 @@ export class SyncEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
if (this.transport) this.transport.close()
|
if (this.transport) {
|
||||||
|
this.transport.close()
|
||||||
|
}
|
||||||
this.transport = undefined
|
this.transport = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +38,7 @@ export class SyncEngine {
|
||||||
|
|
||||||
// This method is called by the transport layer on new messages
|
// This method is called by the transport layer on new messages
|
||||||
receive({ kind, ...payload }) {
|
receive({ kind, ...payload }) {
|
||||||
if (kind == 'operation') {
|
if (kind === 'operation') {
|
||||||
const updater = this._getUpdater(payload.subject, payload.metadata)
|
const updater = this._getUpdater(payload.subject, payload.metadata)
|
||||||
updater.applyMessage(payload)
|
updater.applyMessage(payload)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -15,11 +15,15 @@ class BaseUpdater {
|
||||||
// Reduce the current list of attributes,
|
// Reduce the current list of attributes,
|
||||||
// to find the object to set the property onto
|
// to find the object to set the property onto
|
||||||
const objectToSet = parts.reduce((currentObj, part) => {
|
const objectToSet = parts.reduce((currentObj, part) => {
|
||||||
if (currentObj !== undefined && part in currentObj) return currentObj[part]
|
if (currentObj !== undefined && part in currentObj) {
|
||||||
|
return currentObj[part]
|
||||||
|
}
|
||||||
}, obj)
|
}, obj)
|
||||||
|
|
||||||
// In case the given path doesn't exist, stop here
|
// In case the given path doesn't exist, stop here
|
||||||
if (objectToSet === undefined) return
|
if (objectToSet === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Set the value (or delete it)
|
// Set the value (or delete it)
|
||||||
if (typeof value === 'undefined') {
|
if (typeof value === 'undefined') {
|
||||||
|
@ -30,7 +34,9 @@ class BaseUpdater {
|
||||||
}
|
}
|
||||||
|
|
||||||
getDataLayerFromID(layerId) {
|
getDataLayerFromID(layerId) {
|
||||||
if (layerId) return this.map.getDataLayerByUmapId(layerId)
|
if (layerId) {
|
||||||
|
return this.map.getDataLayerByUmapId(layerId)
|
||||||
|
}
|
||||||
return this.map.defaultEditDataLayer()
|
return this.map.defaultEditDataLayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,9 +95,10 @@ export class FeatureUpdater extends BaseUpdater {
|
||||||
console.error(`Unable to find feature with id = ${metadata.id}.`)
|
console.error(`Unable to find feature with id = ${metadata.id}.`)
|
||||||
}
|
}
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'geometry':
|
case 'geometry': {
|
||||||
const datalayer = this.getDataLayerFromID(metadata.layerId)
|
const datalayer = this.getDataLayerFromID(metadata.layerId)
|
||||||
datalayer.geoJSONToLeaflet({ geometry: value, id: metadata.id, feature })
|
datalayer.geoJSONToLeaflet({ geometry: value, id: metadata.id, feature })
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
this.updateObjectValue(feature, key, value)
|
this.updateObjectValue(feature, key, value)
|
||||||
feature.datalayer.indexProperties(feature)
|
feature.datalayer.indexProperties(feature)
|
||||||
|
@ -104,6 +111,8 @@ export class FeatureUpdater extends BaseUpdater {
|
||||||
// XXX Distinguish between properties getting deleted
|
// XXX Distinguish between properties getting deleted
|
||||||
// and the wole feature getting deleted
|
// and the wole feature getting deleted
|
||||||
const feature = this.getFeatureFromMetadata(metadata)
|
const feature = this.getFeatureFromMetadata(metadata)
|
||||||
if (feature) feature.del(false)
|
if (feature) {
|
||||||
|
feature.del(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,14 @@ export default class Dialog {
|
||||||
open({ className, content, modal } = {}) {
|
open({ className, content, modal } = {}) {
|
||||||
this.container.innerHTML = ''
|
this.container.innerHTML = ''
|
||||||
const currentZIndex = this.currentZIndex()
|
const currentZIndex = this.currentZIndex()
|
||||||
if (currentZIndex) this.container.style.zIndex = currentZIndex + 1
|
if (currentZIndex) {
|
||||||
if (modal) this.container.showModal()
|
this.container.style.zIndex = currentZIndex + 1
|
||||||
else this.container.show()
|
}
|
||||||
|
if (modal) {
|
||||||
|
this.container.showModal()
|
||||||
|
} else {
|
||||||
|
this.container.show()
|
||||||
|
}
|
||||||
if (className) {
|
if (className) {
|
||||||
// Reset
|
// Reset
|
||||||
this.container.className = this.className
|
this.container.className = this.className
|
||||||
|
|
|
@ -17,7 +17,9 @@ export class Panel {
|
||||||
}
|
}
|
||||||
|
|
||||||
setDefaultMode(mode) {
|
setDefaultMode(mode) {
|
||||||
if (!this.mode) this.mode = mode
|
if (!this.mode) {
|
||||||
|
this.mode = mode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isOpen() {
|
isOpen() {
|
||||||
|
@ -46,7 +48,9 @@ export class Panel {
|
||||||
const element = DomUtil.element({ tagName: 'li', parent: actionsContainer })
|
const element = DomUtil.element({ tagName: 'li', parent: actionsContainer })
|
||||||
element.appendChild(action)
|
element.appendChild(action)
|
||||||
}
|
}
|
||||||
if (className) DomUtil.addClass(body, className)
|
if (className) {
|
||||||
|
DomUtil.addClass(body, className)
|
||||||
|
}
|
||||||
const promise = new Promise((resolve, reject) => {
|
const promise = new Promise((resolve, reject) => {
|
||||||
DomUtil.addClass(this.container, 'on')
|
DomUtil.addClass(this.container, 'on')
|
||||||
resolve()
|
resolve()
|
||||||
|
|
|
@ -44,8 +44,8 @@ export default class Tooltip {
|
||||||
const left =
|
const left =
|
||||||
this.parent.offsetLeft +
|
this.parent.offsetLeft +
|
||||||
this.parent.clientWidth / 2 -
|
this.parent.clientWidth / 2 -
|
||||||
this.container.clientWidth / 2,
|
this.container.clientWidth / 2
|
||||||
top = this.parent.offsetTop + 75
|
const top = this.parent.offsetTop + 75
|
||||||
this.setPosition({ top: top, left: left })
|
this.setPosition({ top: top, left: left })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,9 @@ export default class Tooltip {
|
||||||
// Clear timetout even if a new tooltip has been added
|
// Clear timetout even if a new tooltip has been added
|
||||||
// in the meantime. Eg. after a mouseout from the anchor.
|
// in the meantime. Eg. after a mouseout from the anchor.
|
||||||
window.clearTimeout(id)
|
window.clearTimeout(id)
|
||||||
if (id && id !== this.TOOLTIP_ID) return
|
if (id && id !== this.TOOLTIP_ID) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.container.className = ''
|
this.container.className = ''
|
||||||
this.container.innerHTML = ''
|
this.container.innerHTML = ''
|
||||||
this.setPosition({})
|
this.setPosition({})
|
||||||
|
@ -92,14 +94,26 @@ export default class Tooltip {
|
||||||
}
|
}
|
||||||
|
|
||||||
setPosition(coords) {
|
setPosition(coords) {
|
||||||
if (coords.left) this.container.style.left = `${coords.left}px`
|
if (coords.left) {
|
||||||
else this.container.style.left = 'initial'
|
this.container.style.left = `${coords.left}px`
|
||||||
if (coords.right) this.container.style.right = `${coords.right}px`
|
} else {
|
||||||
else this.container.style.right = 'initial'
|
this.container.style.left = 'initial'
|
||||||
if (coords.top) this.container.style.top = `${coords.top}px`
|
}
|
||||||
else this.container.style.top = 'initial'
|
if (coords.right) {
|
||||||
if (coords.bottom) this.container.style.bottom = `${coords.bottom}px`
|
this.container.style.right = `${coords.right}px`
|
||||||
else this.container.style.bottom = 'initial'
|
} else {
|
||||||
|
this.container.style.right = 'initial'
|
||||||
|
}
|
||||||
|
if (coords.top) {
|
||||||
|
this.container.style.top = `${coords.top}px`
|
||||||
|
} else {
|
||||||
|
this.container.style.top = 'initial'
|
||||||
|
}
|
||||||
|
if (coords.bottom) {
|
||||||
|
this.container.style.bottom = `${coords.bottom}px`
|
||||||
|
} else {
|
||||||
|
this.container.style.bottom = 'initial'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getDocHeight() {
|
getDocHeight() {
|
||||||
|
|
|
@ -6,24 +6,29 @@ export default class URLs {
|
||||||
}
|
}
|
||||||
|
|
||||||
get(urlName, params) {
|
get(urlName, params) {
|
||||||
if (typeof this[urlName] === 'function') return this[urlName](params)
|
if (typeof this[urlName] === 'function') {
|
||||||
|
return this[urlName](params)
|
||||||
|
}
|
||||||
|
|
||||||
if (this.urls.hasOwnProperty(urlName)) {
|
if (this.urls.hasOwnProperty(urlName)) {
|
||||||
return template(this.urls[urlName], params)
|
return template(this.urls[urlName], params)
|
||||||
} else {
|
|
||||||
throw `Unable to find a URL for route ${urlName}`
|
|
||||||
}
|
}
|
||||||
|
throw `Unable to find a URL for route ${urlName}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update if map_id is passed, create otherwise.
|
// Update if map_id is passed, create otherwise.
|
||||||
map_save({ map_id, ...options }) {
|
map_save({ map_id, ...options }) {
|
||||||
if (map_id) return this.get('map_update', { map_id, ...options })
|
if (map_id) {
|
||||||
|
return this.get('map_update', { map_id, ...options })
|
||||||
|
}
|
||||||
return this.get('map_create')
|
return this.get('map_create')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the layer if pk is passed, create otherwise.
|
// Update the layer if pk is passed, create otherwise.
|
||||||
datalayer_save({ map_id, pk }, ...options) {
|
datalayer_save({ map_id, pk }, ...options) {
|
||||||
if (pk) return this.get('datalayer_update', { map_id, pk }, ...options)
|
if (pk) {
|
||||||
|
return this.get('datalayer_update', { map_id, pk }, ...options)
|
||||||
|
}
|
||||||
return this.get('datalayer_create', { map_id, pk }, ...options)
|
return this.get('datalayer_create', { map_id, pk }, ...options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,9 @@ export function generateId() {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function checkId(string) {
|
export function checkId(string) {
|
||||||
if (typeof string !== 'string') return false
|
if (typeof string !== 'string') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return /^[A-Za-z0-9]{5}$/.test(string)
|
return /^[A-Za-z0-9]{5}$/.test(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,9 +65,8 @@ export function getImpactsFromSchema(fields, schema) {
|
||||||
export default function getPurify() {
|
export default function getPurify() {
|
||||||
if (typeof window === 'undefined') {
|
if (typeof window === 'undefined') {
|
||||||
return DOMPurifyInitializer(new global.JSDOM('').window)
|
return DOMPurifyInitializer(new global.JSDOM('').window)
|
||||||
} else {
|
|
||||||
return DOMPurifyInitializer(window)
|
|
||||||
}
|
}
|
||||||
|
return DOMPurifyInitializer(window)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function escapeHTML(s) {
|
export function escapeHTML(s) {
|
||||||
|
@ -113,8 +114,10 @@ export function escapeHTML(s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toHTML(r, options) {
|
export function toHTML(r, options) {
|
||||||
if (!r) return ''
|
if (!r) {
|
||||||
const target = (options && options.target) || 'blank'
|
return ''
|
||||||
|
}
|
||||||
|
const target = options?.target || 'blank'
|
||||||
|
|
||||||
// unordered lists
|
// unordered lists
|
||||||
r = r.replace(/^\*\* (.*)/gm, '<ul><ul><li>$1</li></ul></ul>')
|
r = r.replace(/^\*\* (.*)/gm, '<ul><ul><li>$1</li></ul></ul>')
|
||||||
|
@ -194,13 +197,21 @@ export function detectFileType(f) {
|
||||||
if (f.type === 'application/vnd.google-earth.kml+xml' || ext('.kml')) {
|
if (f.type === 'application/vnd.google-earth.kml+xml' || ext('.kml')) {
|
||||||
return 'kml'
|
return 'kml'
|
||||||
}
|
}
|
||||||
if (ext('.gpx')) return 'gpx'
|
if (ext('.gpx')) {
|
||||||
if (ext('.geojson') || ext('.json')) return 'geojson'
|
return 'gpx'
|
||||||
|
}
|
||||||
|
if (ext('.geojson') || ext('.json')) {
|
||||||
|
return 'geojson'
|
||||||
|
}
|
||||||
if (f.type === 'text/csv' || ext('.csv') || ext('.tsv') || ext('.dsv')) {
|
if (f.type === 'text/csv' || ext('.csv') || ext('.tsv') || ext('.dsv')) {
|
||||||
return 'csv'
|
return 'csv'
|
||||||
}
|
}
|
||||||
if (ext('.xml') || ext('.osm')) return 'osm'
|
if (ext('.xml') || ext('.osm')) {
|
||||||
if (ext('.umap')) return 'umap'
|
return 'osm'
|
||||||
|
}
|
||||||
|
if (ext('.umap')) {
|
||||||
|
return 'umap'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function usableOption(options, option) {
|
export function usableOption(options, option) {
|
||||||
|
@ -225,12 +236,16 @@ export function greedyTemplate(str, data, ignore) {
|
||||||
let value = data
|
let value = data
|
||||||
for (let i = 0; i < path.length; i++) {
|
for (let i = 0; i < path.length; i++) {
|
||||||
value = value[path[i]]
|
value = value[path[i]]
|
||||||
if (value === undefined) break
|
if (value === undefined) {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof str !== 'string') return ''
|
if (typeof str !== 'string') {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
return str.replace(
|
return str.replace(
|
||||||
/\{ *([^\{\}/\-]+)(?:\|("[^"]*"))? *\}/g,
|
/\{ *([^\{\}/\-]+)(?:\|("[^"]*"))? *\}/g,
|
||||||
|
@ -243,14 +258,21 @@ export function greedyTemplate(str, data, ignore) {
|
||||||
}
|
}
|
||||||
for (let i = 0; i < vars.length; i++) {
|
for (let i = 0; i < vars.length; i++) {
|
||||||
path = vars[i]
|
path = vars[i]
|
||||||
if (path.startsWith('"') && path.endsWith('"'))
|
if (path.startsWith('"') && path.endsWith('"')) {
|
||||||
value = path.substring(1, path.length - 1) // static default value.
|
value = path.substring(1, path.length - 1) // static default value.
|
||||||
else value = getValue(data, path.split('.'))
|
} else {
|
||||||
if (value !== undefined) break
|
value = getValue(data, path.split('.'))
|
||||||
|
}
|
||||||
|
if (value !== undefined) {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
if (ignore) value = str
|
if (ignore) {
|
||||||
else value = ''
|
value = str
|
||||||
|
} else {
|
||||||
|
value = ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
@ -271,8 +293,8 @@ export function sortFeatures(features, sortKey, lang) {
|
||||||
const sortKeys = (sortKey || 'name').split(',')
|
const sortKeys = (sortKey || 'name').split(',')
|
||||||
|
|
||||||
const sort = (a, b, i) => {
|
const sort = (a, b, i) => {
|
||||||
let sortKey = sortKeys[i],
|
let sortKey = sortKeys[i]
|
||||||
reverse = 1
|
let reverse = 1
|
||||||
if (sortKey[0] === '-') {
|
if (sortKey[0] === '-') {
|
||||||
reverse = -1
|
reverse = -1
|
||||||
sortKey = sortKey.substring(1)
|
sortKey = sortKey.substring(1)
|
||||||
|
@ -280,10 +302,16 @@ export function sortFeatures(features, sortKey, lang) {
|
||||||
let score
|
let score
|
||||||
const valA = a.properties[sortKey] || ''
|
const valA = a.properties[sortKey] || ''
|
||||||
const valB = b.properties[sortKey] || ''
|
const valB = b.properties[sortKey] || ''
|
||||||
if (!valA) score = -1
|
if (!valA) {
|
||||||
else if (!valB) score = 1
|
score = -1
|
||||||
else score = naturalSort(valA, valB, lang)
|
} else if (!valB) {
|
||||||
if (score === 0 && sortKeys[i + 1]) return sort(a, b, i + 1)
|
score = 1
|
||||||
|
} else {
|
||||||
|
score = naturalSort(valA, valB, lang)
|
||||||
|
}
|
||||||
|
if (score === 0 && sortKeys[i + 1]) {
|
||||||
|
return sort(a, b, i + 1)
|
||||||
|
}
|
||||||
return score * reverse
|
return score * reverse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +326,9 @@ export function sortFeatures(features, sortKey, lang) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flattenCoordinates(coords) {
|
export function flattenCoordinates(coords) {
|
||||||
while (coords[0] && typeof coords[0][0] !== 'number') coords = coords[0]
|
while (coords[0] && typeof coords[0][0] !== 'number') {
|
||||||
|
coords = coords[0]
|
||||||
|
}
|
||||||
return coords
|
return coords
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,19 +345,19 @@ export function getBaseUrl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasVar(value) {
|
export function hasVar(value) {
|
||||||
return typeof value === 'string' && value.indexOf('{') != -1
|
return typeof value === 'string' && value.indexOf('{') !== -1
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPath(value) {
|
export function isPath(value) {
|
||||||
return value && value.length && value.startsWith('/')
|
return value?.length && value.startsWith('/')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isRemoteUrl(value) {
|
export function isRemoteUrl(value) {
|
||||||
return value && value.length && value.startsWith('http')
|
return value?.length && value.startsWith('http')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isDataImage(value) {
|
export function isDataImage(value) {
|
||||||
return value && value.length && value.startsWith('data:image')
|
return value?.length && value.startsWith('data:image')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -349,15 +379,16 @@ export function normalize(s) {
|
||||||
|
|
||||||
// Vendorized from leaflet.utils
|
// Vendorized from leaflet.utils
|
||||||
// https://github.com/Leaflet/Leaflet/blob/108c6717b70f57c63645498f9bd66b6677758786/src/core/Util.js#L132-L151
|
// https://github.com/Leaflet/Leaflet/blob/108c6717b70f57c63645498f9bd66b6677758786/src/core/Util.js#L132-L151
|
||||||
var templateRe = /\{ *([\w_ -]+) *\}/g
|
const templateRe = /\{ *([\w_ -]+) *\}/g
|
||||||
|
|
||||||
export function template(str, data) {
|
export function template(str, data) {
|
||||||
return str.replace(templateRe, (str, key) => {
|
return str.replace(templateRe, (str, key) => {
|
||||||
var value = data[key]
|
let value = data[key]
|
||||||
|
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
throw new Error('No value provided for variable ' + str)
|
throw new Error(`No value provided for variable ${str}`)
|
||||||
} else if (typeof value === 'function') {
|
}
|
||||||
|
if (typeof value === 'function') {
|
||||||
value = value(data)
|
value = value(data)
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
|
@ -371,9 +402,16 @@ export function parseNaiveDate(value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toggleBadge(element, value) {
|
export function toggleBadge(element, value) {
|
||||||
if (!element.nodeType) element = document.querySelector(element)
|
if (!element.nodeType) {
|
||||||
if (!element) return
|
element = document.querySelector(element)
|
||||||
|
}
|
||||||
|
if (!element) {
|
||||||
|
return
|
||||||
|
}
|
||||||
// True means simple badge, without content
|
// True means simple badge, without content
|
||||||
if (value) element.dataset.badge = value === true ? ' ' : value
|
if (value) {
|
||||||
else delete element.dataset.badge
|
element.dataset.badge = value === true ? ' ' : value
|
||||||
|
} else {
|
||||||
|
delete element.dataset.badge
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,9 @@ U.BaseAction = L.ToolbarAction.extend({
|
||||||
tooltip: this.options.tooltip,
|
tooltip: this.options.tooltip,
|
||||||
}
|
}
|
||||||
L.ToolbarAction.prototype.initialize.call(this)
|
L.ToolbarAction.prototype.initialize.call(this)
|
||||||
if (this.options.helpMenu && !this.map.helpMenuActions[this.options.className])
|
if (this.options.helpMenu && !this.map.helpMenuActions[this.options.className]) {
|
||||||
this.map.helpMenuActions[this.options.className] = this
|
this.map.helpMenuActions[this.options.className] = this
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -213,8 +214,9 @@ U.DeleteFeatureAction = U.BaseFeatureAction.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
postInit: function () {
|
postInit: function () {
|
||||||
if (!this.feature.isMulti())
|
if (!this.feature.isMulti()) {
|
||||||
this.options.toolbarIcon.className = 'umap-delete-one-of-one'
|
this.options.toolbarIcon.className = 'umap-delete-one-of-one'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onClick: function (e) {
|
onClick: function (e) {
|
||||||
|
@ -434,11 +436,14 @@ U.MoreControls = L.Control.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
toggle: function () {
|
toggle: function () {
|
||||||
const pos = this.getPosition(),
|
const pos = this.getPosition()
|
||||||
corner = this._map._controlCorners[pos],
|
const corner = this._map._controlCorners[pos]
|
||||||
className = 'umap-more-controls'
|
const className = 'umap-more-controls'
|
||||||
if (L.DomUtil.hasClass(corner, className)) L.DomUtil.removeClass(corner, className)
|
if (L.DomUtil.hasClass(corner, className)) {
|
||||||
else L.DomUtil.addClass(corner, className)
|
L.DomUtil.removeClass(corner, className)
|
||||||
|
} else {
|
||||||
|
L.DomUtil.addClass(corner, className)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -456,8 +461,8 @@ U.PermanentCreditsControl = L.Control.extend({
|
||||||
const paragraphContainer = L.DomUtil.create(
|
const paragraphContainer = L.DomUtil.create(
|
||||||
'div',
|
'div',
|
||||||
'umap-permanent-credits-container'
|
'umap-permanent-credits-container'
|
||||||
),
|
)
|
||||||
creditsParagraph = L.DomUtil.create('p', '', paragraphContainer)
|
const creditsParagraph = L.DomUtil.create('p', '', paragraphContainer)
|
||||||
|
|
||||||
this.paragraphContainer = paragraphContainer
|
this.paragraphContainer = paragraphContainer
|
||||||
this.setCredits()
|
this.setCredits()
|
||||||
|
@ -564,7 +569,9 @@ L.Control.Embed = L.Control.Button.extend({
|
||||||
|
|
||||||
U.DataLayer.include({
|
U.DataLayer.include({
|
||||||
renderLegend: function (container) {
|
renderLegend: function (container) {
|
||||||
if (this.layer.renderLegend) return this.layer.renderLegend(container)
|
if (this.layer.renderLegend) {
|
||||||
|
return this.layer.renderLegend(container)
|
||||||
|
}
|
||||||
const color = L.DomUtil.create('span', 'datalayer-color', container)
|
const color = L.DomUtil.create('span', 'datalayer-color', container)
|
||||||
color.style.backgroundColor = this.getColor()
|
color.style.backgroundColor = this.getColor()
|
||||||
},
|
},
|
||||||
|
@ -604,8 +611,12 @@ U.DataLayer.include({
|
||||||
remove,
|
remove,
|
||||||
'click',
|
'click',
|
||||||
function () {
|
function () {
|
||||||
if (!this.isVisible()) return
|
if (!this.isVisible()) {
|
||||||
if (!confirm(L._('Are you sure you want to delete this layer?'))) return
|
return
|
||||||
|
}
|
||||||
|
if (!confirm(L._('Are you sure you want to delete this layer?'))) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this._delete()
|
this._delete()
|
||||||
},
|
},
|
||||||
this
|
this
|
||||||
|
@ -660,7 +671,9 @@ U.DataLayer.addInitHook(function () {
|
||||||
this.on('hide', this.propagateHide)
|
this.on('hide', this.propagateHide)
|
||||||
this.on('show', this.propagateShow)
|
this.on('show', this.propagateShow)
|
||||||
this.on('erase', this.propagateDelete)
|
this.on('erase', this.propagateDelete)
|
||||||
if (this.isVisible()) this.propagateShow()
|
if (this.isVisible()) {
|
||||||
|
this.propagateShow()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const ControlsMixin = {
|
const ControlsMixin = {
|
||||||
|
@ -745,7 +758,7 @@ const ControlsMixin = {
|
||||||
L.DomUtil.createLink(
|
L.DomUtil.createLink(
|
||||||
'umap-user',
|
'umap-user',
|
||||||
rightContainer,
|
rightContainer,
|
||||||
L._(`My Dashboard ({username})`, {
|
L._('My Dashboard ({username})', {
|
||||||
username: this.options.user.name,
|
username: this.options.user.name,
|
||||||
}),
|
}),
|
||||||
this.options.user.url
|
this.options.user.url
|
||||||
|
@ -818,7 +831,9 @@ const ControlsMixin = {
|
||||||
},
|
},
|
||||||
|
|
||||||
editDatalayers: function () {
|
editDatalayers: function () {
|
||||||
if (!this.editEnabled) return
|
if (!this.editEnabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const container = L.DomUtil.create('div')
|
const container = L.DomUtil.create('div')
|
||||||
L.DomUtil.createTitle(container, L._('Manage layers'), 'icon-layers')
|
L.DomUtil.createTitle(container, L._('Manage layers'), 'icon-layers')
|
||||||
const ul = L.DomUtil.create('ul', '', container)
|
const ul = L.DomUtil.create('ul', '', container)
|
||||||
|
@ -832,16 +847,21 @@ const ControlsMixin = {
|
||||||
row.dataset.id = L.stamp(datalayer)
|
row.dataset.id = L.stamp(datalayer)
|
||||||
})
|
})
|
||||||
const onReorder = (src, dst, initialIndex, finalIndex) => {
|
const onReorder = (src, dst, initialIndex, finalIndex) => {
|
||||||
const layer = this.datalayers[src.dataset.id],
|
const layer = this.datalayers[src.dataset.id]
|
||||||
other = this.datalayers[dst.dataset.id],
|
const other = this.datalayers[dst.dataset.id]
|
||||||
minIndex = Math.min(layer.getRank(), other.getRank()),
|
const minIndex = Math.min(layer.getRank(), other.getRank())
|
||||||
maxIndex = Math.max(layer.getRank(), other.getRank())
|
const maxIndex = Math.max(layer.getRank(), other.getRank())
|
||||||
if (finalIndex === 0) layer.bringToTop()
|
if (finalIndex === 0) {
|
||||||
else if (finalIndex > initialIndex) layer.insertBefore(other)
|
layer.bringToTop()
|
||||||
else layer.insertAfter(other)
|
} else if (finalIndex > initialIndex) {
|
||||||
|
layer.insertBefore(other)
|
||||||
|
} else {
|
||||||
|
layer.insertAfter(other)
|
||||||
|
}
|
||||||
this.eachDataLayerReverse((datalayer) => {
|
this.eachDataLayerReverse((datalayer) => {
|
||||||
if (datalayer.getRank() >= minIndex && datalayer.getRank() <= maxIndex)
|
if (datalayer.getRank() >= minIndex && datalayer.getRank() <= maxIndex) {
|
||||||
datalayer.isDirty = true
|
datalayer.isDirty = true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
this.indexDatalayers()
|
this.indexDatalayers()
|
||||||
}
|
}
|
||||||
|
@ -897,7 +917,9 @@ U.TileLayerControl = L.Control.IconLayers.extend({
|
||||||
}
|
}
|
||||||
const maxShown = 10
|
const maxShown = 10
|
||||||
L.Control.IconLayers.prototype.setLayers.call(this, layers.slice(0, maxShown))
|
L.Control.IconLayers.prototype.setLayers.call(this, layers.slice(0, maxShown))
|
||||||
if (this.map.selected_tilelayer) this.setActiveLayer(this.map.selected_tilelayer)
|
if (this.map.selected_tilelayer) {
|
||||||
|
this.setActiveLayer(this.map.selected_tilelayer)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -941,17 +963,18 @@ U.TileLayerChooser = L.Control.extend({
|
||||||
if (
|
if (
|
||||||
window.location.protocol === 'https:' &&
|
window.location.protocol === 'https:' &&
|
||||||
tilelayer.options.url_template.indexOf('http:') === 0
|
tilelayer.options.url_template.indexOf('http:') === 0
|
||||||
)
|
) {
|
||||||
return
|
return
|
||||||
|
}
|
||||||
this.addTileLayerElement(tilelayer, options)
|
this.addTileLayerElement(tilelayer, options)
|
||||||
}, this)
|
}, this)
|
||||||
},
|
},
|
||||||
|
|
||||||
addTileLayerElement: function (tilelayer, options) {
|
addTileLayerElement: function (tilelayer, options) {
|
||||||
const selectedClass = this.map.hasLayer(tilelayer) ? 'selected' : '',
|
const selectedClass = this.map.hasLayer(tilelayer) ? 'selected' : ''
|
||||||
el = L.DomUtil.create('li', selectedClass, this._tilelayers_container),
|
const el = L.DomUtil.create('li', selectedClass, this._tilelayers_container)
|
||||||
img = L.DomUtil.create('img', '', el),
|
const img = L.DomUtil.create('img', '', el)
|
||||||
name = L.DomUtil.create('div', '', el)
|
const name = L.DomUtil.create('div', '', el)
|
||||||
img.src = U.Utils.template(tilelayer.options.url_template, this.map.demoTileInfos)
|
img.src = U.Utils.template(tilelayer.options.url_template, this.map.demoTileInfos)
|
||||||
img.loading = 'lazy'
|
img.loading = 'lazy'
|
||||||
name.textContent = tilelayer.options.name
|
name.textContent = tilelayer.options.name
|
||||||
|
@ -961,7 +984,9 @@ U.TileLayerChooser = L.Control.extend({
|
||||||
function () {
|
function () {
|
||||||
this.map.selectTileLayer(tilelayer)
|
this.map.selectTileLayer(tilelayer)
|
||||||
this.map._controls.tilelayers.setLayers()
|
this.map._controls.tilelayers.setLayers()
|
||||||
if (options && options.callback) options.callback(tilelayer)
|
if (options?.callback) {
|
||||||
|
options.callback(tilelayer)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
|
@ -975,15 +1000,17 @@ U.AttributionControl = L.Control.Attribution.extend({
|
||||||
|
|
||||||
_update: function () {
|
_update: function () {
|
||||||
// Layer is no more on the map
|
// Layer is no more on the map
|
||||||
if (!this._map) return
|
if (!this._map) {
|
||||||
|
return
|
||||||
|
}
|
||||||
L.Control.Attribution.prototype._update.call(this)
|
L.Control.Attribution.prototype._update.call(this)
|
||||||
// Use our own container, so we can hide/show on small screens
|
// Use our own container, so we can hide/show on small screens
|
||||||
const credits = this._container.innerHTML
|
const credits = this._container.innerHTML
|
||||||
this._container.innerHTML = ''
|
this._container.innerHTML = ''
|
||||||
const container = L.DomUtil.create('div', 'attribution-container', this._container)
|
const container = L.DomUtil.create('div', 'attribution-container', this._container)
|
||||||
container.innerHTML = credits
|
container.innerHTML = credits
|
||||||
const shortCredit = this._map.getOption('shortCredit'),
|
const shortCredit = this._map.getOption('shortCredit')
|
||||||
captionMenus = this._map.getOption('captionMenus')
|
const captionMenus = this._map.getOption('captionMenus')
|
||||||
if (shortCredit) {
|
if (shortCredit) {
|
||||||
L.DomUtil.element({
|
L.DomUtil.element({
|
||||||
tagName: 'span',
|
tagName: 'span',
|
||||||
|
@ -1045,7 +1072,9 @@ U.Locate = L.Control.Locate.extend({
|
||||||
// This occurs because we do create the control and call its activate
|
// This occurs because we do create the control and call its activate
|
||||||
// method before adding the control button itself to the map, in the
|
// method before adding the control button itself to the map, in the
|
||||||
// case where the map defaultView is set to "location"
|
// case where the map defaultView is set to "location"
|
||||||
if (!this._container || !this._container.parentNode) return
|
if (!this._container || !this._container.parentNode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
return L.Control.Locate.prototype.remove.call(this)
|
return L.Control.Locate.prototype.remove.call(this)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1056,7 +1085,9 @@ U.Search = L.PhotonSearch.extend({
|
||||||
this.options.location_bias_scale = 0.5
|
this.options.location_bias_scale = 0.5
|
||||||
L.PhotonSearch.prototype.initialize.call(this, map, input, options)
|
L.PhotonSearch.prototype.initialize.call(this, map, input, options)
|
||||||
this.options.url = map.options.urls.search
|
this.options.url = map.options.urls.search
|
||||||
if (map.options.maxBounds) this.options.bbox = map.options.maxBounds.toBBoxString()
|
if (map.options.maxBounds) {
|
||||||
|
this.options.bbox = map.options.maxBounds.toBBoxString()
|
||||||
|
}
|
||||||
this.reverse = new L.PhotonReverse({
|
this.reverse = new L.PhotonReverse({
|
||||||
handleResults: (geojson) => {
|
handleResults: (geojson) => {
|
||||||
this.handleResultsWithReverse(geojson)
|
this.handleResultsWithReverse(geojson)
|
||||||
|
@ -1091,7 +1122,9 @@ U.Search = L.PhotonSearch.extend({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Only numbers, abort.
|
// Only numbers, abort.
|
||||||
if (/^[\d .,]*$/.test(this.input.value)) return
|
if (/^[\d .,]*$/.test(this.input.value)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
// Do normal search
|
// Do normal search
|
||||||
this.options.includePosition = this.map.getZoom() > 10
|
this.options.includePosition = this.map.getZoom() > 10
|
||||||
L.PhotonSearch.prototype.search.call(this)
|
L.PhotonSearch.prototype.search.call(this)
|
||||||
|
@ -1171,7 +1204,9 @@ U.SearchControl = L.Control.extend({
|
||||||
limit: 10,
|
limit: 10,
|
||||||
noResultLabel: L._('No results'),
|
noResultLabel: L._('No results'),
|
||||||
}
|
}
|
||||||
if (this.map.options.photonUrl) options.url = this.map.options.photonUrl
|
if (this.map.options.photonUrl) {
|
||||||
|
options.url = this.map.options.photonUrl
|
||||||
|
}
|
||||||
const container = L.DomUtil.create('div', '')
|
const container = L.DomUtil.create('div', '')
|
||||||
|
|
||||||
L.DomUtil.createTitle(container, L._('Search location'), 'icon-search')
|
L.DomUtil.createTitle(container, L._('Search location'), 'icon-search')
|
||||||
|
@ -1251,16 +1286,23 @@ U.Editable = L.Editable.extend({
|
||||||
// Leaflet.Editable will delete the drawn shape if invalid
|
// Leaflet.Editable will delete the drawn shape if invalid
|
||||||
// (eg. line has only one drawn point)
|
// (eg. line has only one drawn point)
|
||||||
// So let's check if the layer has no more shape
|
// So let's check if the layer has no more shape
|
||||||
if (!e.layer.hasGeom()) e.layer.del()
|
if (!e.layer.hasGeom()) {
|
||||||
else e.layer.edit()
|
e.layer.del()
|
||||||
|
} else {
|
||||||
|
e.layer.edit()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
// Layer for items added by users
|
// Layer for items added by users
|
||||||
this.on('editable:drawing:cancel', (e) => {
|
this.on('editable:drawing:cancel', (e) => {
|
||||||
if (e.layer instanceof U.Marker) e.layer.del()
|
if (e.layer instanceof U.Marker) {
|
||||||
|
e.layer.del()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
this.on('editable:drawing:commit', function (e) {
|
this.on('editable:drawing:commit', function (e) {
|
||||||
e.layer.isDirty = true
|
e.layer.isDirty = true
|
||||||
if (this.map.editedFeature !== e.layer) e.layer.edit(e)
|
if (this.map.editedFeature !== e.layer) {
|
||||||
|
e.layer.edit(e)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
this.on('editable:editing', (e) => {
|
this.on('editable:editing', (e) => {
|
||||||
const layer = e.layer
|
const layer = e.layer
|
||||||
|
@ -1272,11 +1314,14 @@ U.Editable = L.Editable.extend({
|
||||||
})
|
})
|
||||||
this.on('editable:vertex:ctrlclick', (e) => {
|
this.on('editable:vertex:ctrlclick', (e) => {
|
||||||
const index = e.vertex.getIndex()
|
const index = e.vertex.getIndex()
|
||||||
if (index === 0 || (index === e.vertex.getLastIndex() && e.vertex.continue))
|
if (index === 0 || (index === e.vertex.getLastIndex() && e.vertex.continue)) {
|
||||||
e.vertex.continue()
|
e.vertex.continue()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
this.on('editable:vertex:altclick', (e) => {
|
this.on('editable:vertex:altclick', (e) => {
|
||||||
if (e.vertex.editor.vertexCanBeDeleted(e.vertex)) e.vertex.delete()
|
if (e.vertex.editor.vertexCanBeDeleted(e.vertex)) {
|
||||||
|
e.vertex.delete()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
this.on('editable:vertex:rawclick', this.onVertexRawClick)
|
this.on('editable:vertex:rawclick', this.onVertexRawClick)
|
||||||
},
|
},
|
||||||
|
@ -1310,7 +1355,7 @@ U.Editable = L.Editable.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
drawingTooltip: function (e) {
|
drawingTooltip: function (e) {
|
||||||
if (e.layer instanceof L.Marker && e.type == 'editable:drawing:start') {
|
if (e.layer instanceof L.Marker && e.type === 'editable:drawing:start') {
|
||||||
this.map.tooltip.open({ content: L._('Click to add a marker') })
|
this.map.tooltip.open({ content: L._('Click to add a marker') })
|
||||||
}
|
}
|
||||||
if (!(e.layer instanceof L.Polyline)) {
|
if (!(e.layer instanceof L.Polyline)) {
|
||||||
|
|
|
@ -27,11 +27,13 @@ L.Util.copyToClipboard = (textToCopy) => {
|
||||||
|
|
||||||
L.Util.queryString = (name, fallback) => {
|
L.Util.queryString = (name, fallback) => {
|
||||||
const decode = (s) => decodeURIComponent(s.replace(/\+/g, ' '))
|
const decode = (s) => decodeURIComponent(s.replace(/\+/g, ' '))
|
||||||
const qs = window.location.search.slice(1).split('&'),
|
const qs = window.location.search.slice(1).split('&')
|
||||||
qa = {}
|
const qa = {}
|
||||||
for (const i in qs) {
|
for (const i in qs) {
|
||||||
const key = qs[i].split('=')
|
const key = qs[i].split('=')
|
||||||
if (!key) continue
|
if (!key) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
qa[decode(key[0])] = key[1] ? decode(key[1]) : 1
|
qa[decode(key[0])] = key[1] ? decode(key[1]) : 1
|
||||||
}
|
}
|
||||||
return qa[name] || fallback
|
return qa[name] || fallback
|
||||||
|
@ -44,25 +46,35 @@ L.Util.booleanFromQueryString = (name) => {
|
||||||
|
|
||||||
L.Util.setFromQueryString = (options, name) => {
|
L.Util.setFromQueryString = (options, name) => {
|
||||||
const value = L.Util.queryString(name)
|
const value = L.Util.queryString(name)
|
||||||
if (typeof value !== 'undefined') options[name] = value
|
if (typeof value !== 'undefined') {
|
||||||
|
options[name] = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
L.Util.setBooleanFromQueryString = (options, name) => {
|
L.Util.setBooleanFromQueryString = (options, name) => {
|
||||||
const value = L.Util.queryString(name)
|
const value = L.Util.queryString(name)
|
||||||
if (typeof value !== 'undefined') options[name] = value == '1' || value == 'true'
|
if (typeof value !== 'undefined') {
|
||||||
|
options[name] = value === '1' || value === 'true'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
L.Util.setNumberFromQueryString = (options, name) => {
|
L.Util.setNumberFromQueryString = (options, name) => {
|
||||||
const value = +L.Util.queryString(name)
|
const value = +L.Util.queryString(name)
|
||||||
if (!isNaN(value)) options[name] = value
|
if (!Number.isNaN(value)) {
|
||||||
|
options[name] = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
L.Util.setNullableBooleanFromQueryString = (options, name) => {
|
L.Util.setNullableBooleanFromQueryString = (options, name) => {
|
||||||
let value = L.Util.queryString(name)
|
let value = L.Util.queryString(name)
|
||||||
if (typeof value !== 'undefined') {
|
if (typeof value !== 'undefined') {
|
||||||
if (value === 'null') value = null
|
if (value === 'null') {
|
||||||
else if (value === '0' || value === 'false') value = false
|
value = null
|
||||||
else value = true
|
} else if (value === '0' || value === 'false') {
|
||||||
|
value = false
|
||||||
|
} else {
|
||||||
|
value = true
|
||||||
|
}
|
||||||
options[name] = value
|
options[name] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,13 +95,17 @@ L.DomUtil.createFieldset = (container, legend, options) => {
|
||||||
options = options || {}
|
options = options || {}
|
||||||
const details = L.DomUtil.create('details', options.className || '', container)
|
const details = L.DomUtil.create('details', options.className || '', container)
|
||||||
const summary = L.DomUtil.add('summary', '', details)
|
const summary = L.DomUtil.add('summary', '', details)
|
||||||
if (options.icon) L.DomUtil.createIcon(summary, options.icon)
|
if (options.icon) {
|
||||||
|
L.DomUtil.createIcon(summary, options.icon)
|
||||||
|
}
|
||||||
L.DomUtil.add('span', '', summary, legend)
|
L.DomUtil.add('span', '', summary, legend)
|
||||||
const fieldset = L.DomUtil.add('fieldset', '', details)
|
const fieldset = L.DomUtil.add('fieldset', '', details)
|
||||||
details.open = options.on === true
|
details.open = options.on === true
|
||||||
if (options.callback) {
|
if (options.callback) {
|
||||||
L.DomEvent.on(details, 'toggle', () => {
|
L.DomEvent.on(details, 'toggle', () => {
|
||||||
if (details.open) options.callback.call(options.context || this)
|
if (details.open) {
|
||||||
|
options.callback.call(options.context || this)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return fieldset
|
return fieldset
|
||||||
|
@ -139,7 +155,9 @@ L.DomUtil.createButtonIcon = (parent, className, title, size = 16) => {
|
||||||
|
|
||||||
L.DomUtil.createTitle = (parent, text, className, tag = 'h3') => {
|
L.DomUtil.createTitle = (parent, text, className, tag = 'h3') => {
|
||||||
const title = L.DomUtil.create(tag, '', parent)
|
const title = L.DomUtil.create(tag, '', parent)
|
||||||
if (className) L.DomUtil.createIcon(title, className)
|
if (className) {
|
||||||
|
L.DomUtil.createIcon(title, className)
|
||||||
|
}
|
||||||
L.DomUtil.add('span', '', title, text)
|
L.DomUtil.add('span', '', title, text)
|
||||||
return title
|
return title
|
||||||
}
|
}
|
||||||
|
@ -192,8 +210,10 @@ L.DomUtil.after = (target, el) => {
|
||||||
// convert colour in range 0-255 to the modifier used within luminance calculation
|
// convert colour in range 0-255 to the modifier used within luminance calculation
|
||||||
L.DomUtil.colourMod = (colour) => {
|
L.DomUtil.colourMod = (colour) => {
|
||||||
const sRGB = colour / 255
|
const sRGB = colour / 255
|
||||||
let mod = Math.pow((sRGB + 0.055) / 1.055, 2.4)
|
let mod = ((sRGB + 0.055) / 1.055) ** 2.4
|
||||||
if (sRGB < 0.03928) mod = sRGB / 12.92
|
if (sRGB < 0.03928) {
|
||||||
|
mod = sRGB / 12.92
|
||||||
|
}
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
L.DomUtil.RGBRegex = /rgb *\( *([0-9]{1,3}) *, *([0-9]{1,3}) *, *([0-9]{1,3}) *\)/
|
L.DomUtil.RGBRegex = /rgb *\( *([0-9]{1,3}) *, *([0-9]{1,3}) *, *([0-9]{1,3}) *\)/
|
||||||
|
@ -217,18 +237,24 @@ const _CACHE_CONSTRAST = {}
|
||||||
L.DomUtil.contrastedColor = (el, bgcolor) => {
|
L.DomUtil.contrastedColor = (el, bgcolor) => {
|
||||||
// Return 0 for black and 1 for white
|
// Return 0 for black and 1 for white
|
||||||
// bgcolor is a human color, it can be a any keyword (purple…)
|
// bgcolor is a human color, it can be a any keyword (purple…)
|
||||||
if (typeof _CACHE_CONSTRAST[bgcolor] !== 'undefined') return _CACHE_CONSTRAST[bgcolor]
|
if (typeof _CACHE_CONSTRAST[bgcolor] !== 'undefined') {
|
||||||
|
return _CACHE_CONSTRAST[bgcolor]
|
||||||
|
}
|
||||||
let out = 0
|
let out = 0
|
||||||
let rgb = window.getComputedStyle(el).getPropertyValue('background-color')
|
let rgb = window.getComputedStyle(el).getPropertyValue('background-color')
|
||||||
rgb = L.DomUtil.RGBRegex.exec(rgb)
|
rgb = L.DomUtil.RGBRegex.exec(rgb)
|
||||||
if (!rgb || rgb.length !== 4) return out
|
if (!rgb || rgb.length !== 4) {
|
||||||
|
return out
|
||||||
|
}
|
||||||
rgb = [
|
rgb = [
|
||||||
Number.parseInt(rgb[1], 10),
|
Number.parseInt(rgb[1], 10),
|
||||||
Number.parseInt(rgb[2], 10),
|
Number.parseInt(rgb[2], 10),
|
||||||
Number.parseInt(rgb[3], 10),
|
Number.parseInt(rgb[3], 10),
|
||||||
]
|
]
|
||||||
out = L.DomUtil.contrastWCAG21(rgb)
|
out = L.DomUtil.contrastWCAG21(rgb)
|
||||||
if (bgcolor) _CACHE_CONSTRAST[bgcolor] = out
|
if (bgcolor) {
|
||||||
|
_CACHE_CONSTRAST[bgcolor] = out
|
||||||
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
L.DomEvent.once = (el, types, fn, context) => {
|
L.DomEvent.once = (el, types, fn, context) => {
|
||||||
|
@ -251,9 +277,9 @@ L.DomEvent.once = (el, types, fn, context) => {
|
||||||
|
|
||||||
L.LatLng.prototype.isValid = function () {
|
L.LatLng.prototype.isValid = function () {
|
||||||
return (
|
return (
|
||||||
isFinite(this.lat) &&
|
Number.isFinite(this.lat) &&
|
||||||
Math.abs(this.lat) <= 90 &&
|
Math.abs(this.lat) <= 90 &&
|
||||||
isFinite(this.lng) &&
|
Number.isFinite(this.lng) &&
|
||||||
Math.abs(this.lng) <= 180
|
Math.abs(this.lng) <= 180
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,9 @@ U.DataLayerPermissions = L.Class.extend({
|
||||||
get: () => isDirty,
|
get: () => isDirty,
|
||||||
set: (status) => {
|
set: (status) => {
|
||||||
isDirty = status
|
isDirty = status
|
||||||
if (status) this.datalayer.isDirty = status
|
if (status) {
|
||||||
|
this.datalayer.isDirty = status
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -34,11 +36,11 @@ U.DataLayerPermissions = L.Class.extend({
|
||||||
selectOptions: this.datalayer.map.options.datalayer_edit_statuses,
|
selectOptions: this.datalayer.map.options.datalayer_edit_statuses,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
]
|
||||||
builder = new U.FormBuilder(this, fields, {
|
const builder = new U.FormBuilder(this, fields, {
|
||||||
className: 'umap-form datalayer-permissions',
|
className: 'umap-form datalayer-permissions',
|
||||||
}),
|
})
|
||||||
form = builder.build()
|
const form = builder.build()
|
||||||
container.appendChild(form)
|
container.appendChild(form)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -49,7 +51,9 @@ U.DataLayerPermissions = L.Class.extend({
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
save: async function () {
|
save: async function () {
|
||||||
if (!this.isDirty) return this.datalayer.map.continueSaving()
|
if (!this.isDirty) {
|
||||||
|
return this.datalayer.map.continueSaving()
|
||||||
|
}
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('edit_status', this.options.edit_status)
|
formData.append('edit_status', this.options.edit_status)
|
||||||
const [data, response, error] = await this.datalayer.map.server.post(
|
const [data, response, error] = await this.datalayer.map.server.post(
|
||||||
|
|
|
@ -15,7 +15,9 @@ U.FeatureMixin = {
|
||||||
onCommit: function () {
|
onCommit: function () {
|
||||||
// When the layer is a remote layer, we don't want to sync the creation of the
|
// When the layer is a remote layer, we don't want to sync the creation of the
|
||||||
// points via the websocket, as the other peers will get them themselves.
|
// points via the websocket, as the other peers will get them themselves.
|
||||||
if (this.datalayer.isRemoteLayer()) return
|
if (this.datalayer.isRemoteLayer()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.sync.upsert(this.toGeoJSON())
|
this.sync.upsert(this.toGeoJSON())
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -82,7 +84,7 @@ U.FeatureMixin = {
|
||||||
preInit: () => {},
|
preInit: () => {},
|
||||||
|
|
||||||
isReadOnly: function () {
|
isReadOnly: function () {
|
||||||
return this.datalayer && this.datalayer.isDataReadOnly()
|
return this.datalayer?.isDataReadOnly()
|
||||||
},
|
},
|
||||||
|
|
||||||
getSlug: function () {
|
getSlug: function () {
|
||||||
|
@ -91,10 +93,11 @@ U.FeatureMixin = {
|
||||||
|
|
||||||
getPermalink: function () {
|
getPermalink: function () {
|
||||||
const slug = this.getSlug()
|
const slug = this.getSlug()
|
||||||
if (slug)
|
if (slug) {
|
||||||
return `${U.Utils.getBaseUrl()}?${U.Utils.buildQueryString({ feature: slug })}${
|
return `${U.Utils.getBaseUrl()}?${U.Utils.buildQueryString({ feature: slug })}${
|
||||||
window.location.hash
|
window.location.hash
|
||||||
}`
|
}`
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
view: function (e) {
|
view: function (e) {
|
||||||
|
@ -139,7 +142,9 @@ U.FeatureMixin = {
|
||||||
},
|
},
|
||||||
|
|
||||||
edit: function (e) {
|
edit: function (e) {
|
||||||
if (!this.map.editEnabled || this.isReadOnly()) return
|
if (!this.map.editEnabled || this.isReadOnly()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const container = L.DomUtil.create('div', 'umap-feature-container')
|
const container = L.DomUtil.create('div', 'umap-feature-container')
|
||||||
L.DomUtil.createTitle(
|
L.DomUtil.createTitle(
|
||||||
container,
|
container,
|
||||||
|
@ -182,7 +187,9 @@ U.FeatureMixin = {
|
||||||
builder.helpers['properties.name'].input.focus()
|
builder.helpers['properties.name'].input.focus()
|
||||||
})
|
})
|
||||||
this.map.editedFeature = this
|
this.map.editedFeature = this
|
||||||
if (!this.isOnScreen()) this.zoomTo(e)
|
if (!this.isOnScreen()) {
|
||||||
|
this.zoomTo(e)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getAdvancedEditActions: function (container) {
|
getAdvancedEditActions: function (container) {
|
||||||
|
@ -192,7 +199,9 @@ U.FeatureMixin = {
|
||||||
L._('Delete'),
|
L._('Delete'),
|
||||||
function (e) {
|
function (e) {
|
||||||
L.DomEvent.stop(e)
|
L.DomEvent.stop(e)
|
||||||
if (this.confirmDelete()) this.map.editPanel.close()
|
if (this.confirmDelete()) {
|
||||||
|
this.map.editPanel.close()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
|
@ -238,19 +247,25 @@ U.FeatureMixin = {
|
||||||
endEdit: () => {},
|
endEdit: () => {},
|
||||||
|
|
||||||
getDisplayName: function (fallback) {
|
getDisplayName: function (fallback) {
|
||||||
if (fallback === undefined) fallback = this.datalayer.options.name
|
if (fallback === undefined) {
|
||||||
|
fallback = this.datalayer.options.name
|
||||||
|
}
|
||||||
const key = this.getOption('labelKey') || 'name'
|
const key = this.getOption('labelKey') || 'name'
|
||||||
// Variables mode.
|
// Variables mode.
|
||||||
if (U.Utils.hasVar(key))
|
if (U.Utils.hasVar(key)) {
|
||||||
return U.Utils.greedyTemplate(key, this.extendedProperties())
|
return U.Utils.greedyTemplate(key, this.extendedProperties())
|
||||||
|
}
|
||||||
// Simple mode.
|
// Simple mode.
|
||||||
return this.properties[key] || this.properties.title || fallback
|
return this.properties[key] || this.properties.title || fallback
|
||||||
},
|
},
|
||||||
|
|
||||||
hasPopupFooter: function () {
|
hasPopupFooter: function () {
|
||||||
if (L.Browser.ielt9) return false
|
if (L.Browser.ielt9) {
|
||||||
if (this.datalayer.isRemoteLayer() && this.datalayer.options.remoteData.dynamic)
|
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
|
if (this.datalayer.isRemoteLayer() && this.datalayer.options.remoteData.dynamic) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return this.map.getOption('displayPopupFooter')
|
return this.map.getOption('displayPopupFooter')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -278,7 +293,9 @@ U.FeatureMixin = {
|
||||||
this.datalayer.removeLayer(this)
|
this.datalayer.removeLayer(this)
|
||||||
this.disconnectFromDataLayer(this.datalayer)
|
this.disconnectFromDataLayer(this.datalayer)
|
||||||
|
|
||||||
if (sync !== false) this.syncDelete()
|
if (sync !== false) {
|
||||||
|
this.syncDelete()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -312,7 +329,7 @@ U.FeatureMixin = {
|
||||||
// Retrocompat
|
// Retrocompat
|
||||||
if (this.properties._umap_options.clickable === false) {
|
if (this.properties._umap_options.clickable === false) {
|
||||||
this.properties._umap_options.interactive = false
|
this.properties._umap_options.interactive = false
|
||||||
delete this.properties._umap_options.clickable
|
this.properties._umap_options.clickable = undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -345,14 +362,20 @@ U.FeatureMixin = {
|
||||||
// There is a variable inside.
|
// There is a variable inside.
|
||||||
if (U.Utils.hasVar(value)) {
|
if (U.Utils.hasVar(value)) {
|
||||||
value = U.Utils.greedyTemplate(value, this.properties, true)
|
value = U.Utils.greedyTemplate(value, this.properties, true)
|
||||||
if (U.Utils.hasVar(value)) value = this.map.getDefaultOption(option)
|
if (U.Utils.hasVar(value)) {
|
||||||
|
value = this.map.getDefaultOption(option)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
},
|
},
|
||||||
|
|
||||||
zoomTo: function ({ easing, latlng, callback } = {}) {
|
zoomTo: function ({ easing, latlng, callback } = {}) {
|
||||||
if (easing === undefined) easing = this.map.getOption('easing')
|
if (easing === undefined) {
|
||||||
if (callback) this.map.once('moveend', callback.call(this))
|
easing = this.map.getOption('easing')
|
||||||
|
}
|
||||||
|
if (callback) {
|
||||||
|
this.map.once('moveend', callback.call(this))
|
||||||
|
}
|
||||||
if (easing) {
|
if (easing) {
|
||||||
this.map.flyTo(this.getCenter(), this.getBestZoom())
|
this.map.flyTo(this.getCenter(), this.getBestZoom())
|
||||||
} else {
|
} else {
|
||||||
|
@ -377,7 +400,7 @@ U.FeatureMixin = {
|
||||||
const properties = L.extend({}, this.properties)
|
const properties = L.extend({}, this.properties)
|
||||||
properties._umap_options = L.extend({}, properties._umap_options)
|
properties._umap_options = L.extend({}, properties._umap_options)
|
||||||
if (Object.keys && Object.keys(properties._umap_options).length === 0) {
|
if (Object.keys && Object.keys(properties._umap_options).length === 0) {
|
||||||
delete properties._umap_options // It can make a difference on big data sets
|
properties._umap_options // It can make a difference on big data sets = undefined // It can make a difference on big data sets
|
||||||
}
|
}
|
||||||
return properties
|
return properties
|
||||||
},
|
},
|
||||||
|
@ -396,7 +419,7 @@ U.FeatureMixin = {
|
||||||
const geojson = this.parentClass.prototype.toGeoJSON.call(this)
|
const geojson = this.parentClass.prototype.toGeoJSON.call(this)
|
||||||
geojson.properties = this.cloneProperties()
|
geojson.properties = this.cloneProperties()
|
||||||
geojson.id = this.id
|
geojson.id = this.id
|
||||||
delete geojson.properties._storage_options
|
geojson.properties._storage_options = undefined
|
||||||
return geojson
|
return geojson
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -406,7 +429,9 @@ U.FeatureMixin = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_onClick: function (e) {
|
_onClick: function (e) {
|
||||||
if (this.map.measureTools && this.map.measureTools.enabled()) return
|
if (this.map.measureTools?.enabled()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this._popupHandlersAdded = true // Prevent leaflet from managing event
|
this._popupHandlersAdded = true // Prevent leaflet from managing event
|
||||||
if (!this.map.editEnabled) {
|
if (!this.map.editEnabled) {
|
||||||
this.view(e)
|
this.view(e)
|
||||||
|
@ -415,8 +440,11 @@ U.FeatureMixin = {
|
||||||
if (e.originalEvent.ctrlKey || e.originalEvent.metaKey) {
|
if (e.originalEvent.ctrlKey || e.originalEvent.metaKey) {
|
||||||
this.datalayer.edit(e)
|
this.datalayer.edit(e)
|
||||||
} else {
|
} else {
|
||||||
if (this._toggleEditing) this._toggleEditing(e)
|
if (this._toggleEditing) {
|
||||||
else this.edit(e)
|
this._toggleEditing(e)
|
||||||
|
} else {
|
||||||
|
this.edit(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
new L.Toolbar.Popup(e.latlng, {
|
new L.Toolbar.Popup(e.latlng, {
|
||||||
|
@ -451,13 +479,14 @@ U.FeatureMixin = {
|
||||||
getContextMenuItems: function (e) {
|
getContextMenuItems: function (e) {
|
||||||
const permalink = this.getPermalink()
|
const permalink = this.getPermalink()
|
||||||
let items = []
|
let items = []
|
||||||
if (permalink)
|
if (permalink) {
|
||||||
items.push({
|
items.push({
|
||||||
text: L._('Permalink'),
|
text: L._('Permalink'),
|
||||||
callback: () => {
|
callback: () => {
|
||||||
window.open(permalink)
|
window.open(permalink)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
}
|
||||||
if (this.map.editEnabled && !this.isReadOnly()) {
|
if (this.map.editEnabled && !this.isReadOnly()) {
|
||||||
items = items.concat(this.getContextMenuEditItems(e))
|
items = items.concat(this.getContextMenuEditItems(e))
|
||||||
}
|
}
|
||||||
|
@ -468,7 +497,7 @@ U.FeatureMixin = {
|
||||||
let items = ['-']
|
let items = ['-']
|
||||||
if (this.map.editedFeature !== this) {
|
if (this.map.editedFeature !== this) {
|
||||||
items.push({
|
items.push({
|
||||||
text: L._('Edit this feature') + ' (⇧+Click)',
|
text: `${L._('Edit this feature')} (⇧+Click)`,
|
||||||
callback: this.edit,
|
callback: this.edit,
|
||||||
context: this,
|
context: this,
|
||||||
iconCls: 'umap-edit',
|
iconCls: 'umap-edit',
|
||||||
|
@ -505,7 +534,9 @@ U.FeatureMixin = {
|
||||||
},
|
},
|
||||||
|
|
||||||
resetTooltip: function () {
|
resetTooltip: function () {
|
||||||
if (!this.hasGeom()) return
|
if (!this.hasGeom()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const displayName = this.getDisplayName(null)
|
const displayName = this.getDisplayName(null)
|
||||||
let showLabel = this.getOption('showLabel')
|
let showLabel = this.getOption('showLabel')
|
||||||
const oldLabelHover = this.getOption('labelHover')
|
const oldLabelHover = this.getOption('labelHover')
|
||||||
|
@ -515,18 +546,25 @@ U.FeatureMixin = {
|
||||||
interactive: this.getOption('labelInteractive'),
|
interactive: this.getOption('labelInteractive'),
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldLabelHover && showLabel) showLabel = null // Retrocompat.
|
if (oldLabelHover && showLabel) {
|
||||||
|
showLabel = null // Retrocompat.
|
||||||
|
}
|
||||||
options.permanent = showLabel === true
|
options.permanent = showLabel === true
|
||||||
this.unbindTooltip()
|
this.unbindTooltip()
|
||||||
if ((showLabel === true || showLabel === null) && displayName)
|
if ((showLabel === true || showLabel === null) && displayName) {
|
||||||
this.bindTooltip(U.Utils.escapeHTML(displayName), options)
|
this.bindTooltip(U.Utils.escapeHTML(displayName), options)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
isFiltered: function () {
|
isFiltered: function () {
|
||||||
const filterKeys = this.datalayer.getFilterKeys()
|
const filterKeys = this.datalayer.getFilterKeys()
|
||||||
const filter = this.map.browser.options.filter
|
const filter = this.map.browser.options.filter
|
||||||
if (filter && !this.matchFilter(filter, filterKeys)) return true
|
if (filter && !this.matchFilter(filter, filterKeys)) {
|
||||||
if (!this.matchFacets()) return true
|
return true
|
||||||
|
}
|
||||||
|
if (!this.matchFacets()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -537,8 +575,10 @@ U.FeatureMixin = {
|
||||||
}
|
}
|
||||||
keys = keys.split(',')
|
keys = keys.split(',')
|
||||||
for (let i = 0, value; i < keys.length; i++) {
|
for (let i = 0, value; i < keys.length; i++) {
|
||||||
value = (this.properties[keys[i]] || '') + ''
|
value = `${this.properties[keys[i]] || ''}`
|
||||||
if (value.toLowerCase().indexOf(filter) !== -1) return true
|
if (value.toLowerCase().indexOf(filter) !== -1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
|
@ -553,12 +593,18 @@ U.FeatureMixin = {
|
||||||
case 'date':
|
case 'date':
|
||||||
case 'datetime':
|
case 'datetime':
|
||||||
case 'number':
|
case 'number':
|
||||||
if (!isNaN(min) && !isNaN(value) && min > value) return false
|
if (!Number.isNaN(min) && !Number.isNaN(value) && min > value) {
|
||||||
if (!isNaN(max) && !isNaN(value) && max < value) return false
|
return false
|
||||||
|
}
|
||||||
|
if (!Number.isNaN(max) && !Number.isNaN(value) && max < value) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
value = value || L._('<empty value>')
|
value = value || L._('<empty value>')
|
||||||
if (choices?.length && !choices.includes(value)) return false
|
if (choices?.length && !choices.includes(value)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,8 +624,8 @@ U.FeatureMixin = {
|
||||||
|
|
||||||
clone: function () {
|
clone: function () {
|
||||||
const geoJSON = this.toGeoJSON()
|
const geoJSON = this.toGeoJSON()
|
||||||
delete geoJSON.id
|
geoJSON.id = undefined
|
||||||
delete geoJSON.properties.id
|
geoJSON.properties.id = undefined
|
||||||
const layer = this.datalayer.geojsonToFeatures(geoJSON)
|
const layer = this.datalayer.geojsonToFeatures(geoJSON)
|
||||||
layer.isDirty = true
|
layer.isDirty = true
|
||||||
layer.edit()
|
layer.edit()
|
||||||
|
@ -590,8 +636,12 @@ U.FeatureMixin = {
|
||||||
// Include context properties
|
// Include context properties
|
||||||
properties = this.map.getGeoContext()
|
properties = this.map.getGeoContext()
|
||||||
const locale = L.getLocale()
|
const locale = L.getLocale()
|
||||||
if (locale) properties.locale = locale
|
if (locale) {
|
||||||
if (L.lang) properties.lang = L.lang
|
properties.locale = locale
|
||||||
|
}
|
||||||
|
if (L.lang) {
|
||||||
|
properties.lang = L.lang
|
||||||
|
}
|
||||||
properties.rank = this.getRank() + 1
|
properties.rank = this.getRank() + 1
|
||||||
if (this._map && this.hasGeom()) {
|
if (this._map && this.hasGeom()) {
|
||||||
center = this.getCenter()
|
center = this.getCenter()
|
||||||
|
@ -638,7 +688,9 @@ U.Marker = L.Marker.extend({
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
this.on('editable:drawing:commit', this.onCommit)
|
this.on('editable:drawing:commit', this.onCommit)
|
||||||
if (!this.isReadOnly()) this.on('mouseover', this._enableDragging)
|
if (!this.isReadOnly()) {
|
||||||
|
this.on('mouseover', this._enableDragging)
|
||||||
|
}
|
||||||
this.on('mouseout', this._onMouseOut)
|
this.on('mouseout', this._onMouseOut)
|
||||||
this._popupHandlersAdded = true // prevent Leaflet from binding event on bindPopup
|
this._popupHandlersAdded = true // prevent Leaflet from binding event on bindPopup
|
||||||
this.on('popupopen', this.highlight)
|
this.on('popupopen', this.highlight)
|
||||||
|
@ -650,11 +702,7 @@ U.Marker = L.Marker.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
_onMouseOut: function () {
|
_onMouseOut: function () {
|
||||||
if (
|
if (this.dragging?._draggable && !this.dragging._draggable._moving) {
|
||||||
this.dragging &&
|
|
||||||
this.dragging._draggable &&
|
|
||||||
!this.dragging._draggable._moving
|
|
||||||
) {
|
|
||||||
// Do not disable if the mouse went out while dragging
|
// Do not disable if the mouse went out while dragging
|
||||||
this._disableDragging()
|
this._disableDragging()
|
||||||
}
|
}
|
||||||
|
@ -663,7 +711,9 @@ U.Marker = L.Marker.extend({
|
||||||
_enableDragging: function () {
|
_enableDragging: function () {
|
||||||
// TODO: start dragging after 1 second on mouse down
|
// TODO: start dragging after 1 second on mouse down
|
||||||
if (this.map.editEnabled) {
|
if (this.map.editEnabled) {
|
||||||
if (!this.editEnabled()) this.enableEdit()
|
if (!this.editEnabled()) {
|
||||||
|
this.enableEdit()
|
||||||
|
}
|
||||||
// Enabling dragging on the marker override the Draggable._OnDown
|
// Enabling dragging on the marker override the Draggable._OnDown
|
||||||
// event, which, as it stopPropagation, refrain the call of
|
// event, which, as it stopPropagation, refrain the call of
|
||||||
// _onDown with map-pane element, which is responsible to
|
// _onDown with map-pane element, which is responsible to
|
||||||
|
@ -675,14 +725,16 @@ U.Marker = L.Marker.extend({
|
||||||
|
|
||||||
_disableDragging: function () {
|
_disableDragging: function () {
|
||||||
if (this.map.editEnabled) {
|
if (this.map.editEnabled) {
|
||||||
if (this.editor && this.editor.drawing) return // when creating a new marker, the mouse can trigger the mouseover/mouseout event
|
if (this.editor?.drawing) {
|
||||||
|
return // when creating a new marker, the mouse can trigger the mouseover/mouseout event
|
||||||
|
}
|
||||||
// do not listen to them
|
// do not listen to them
|
||||||
this.disableEdit()
|
this.disableEdit()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_redraw: function () {
|
_redraw: function () {
|
||||||
if (this.datalayer && this.datalayer.isVisible()) {
|
if (this.datalayer?.isVisible()) {
|
||||||
this._initIcon()
|
this._initIcon()
|
||||||
this.update()
|
this.update()
|
||||||
}
|
}
|
||||||
|
@ -697,8 +749,8 @@ U.Marker = L.Marker.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
_getTooltipAnchor: function () {
|
_getTooltipAnchor: function () {
|
||||||
const anchor = this.options.icon.options.tooltipAnchor.clone(),
|
const anchor = this.options.icon.options.tooltipAnchor.clone()
|
||||||
direction = this.getOption('labelDirection')
|
const direction = this.getOption('labelDirection')
|
||||||
if (direction === 'left') {
|
if (direction === 'left') {
|
||||||
anchor.x *= -1
|
anchor.x *= -1
|
||||||
} else if (direction === 'bottom') {
|
} else if (direction === 'bottom') {
|
||||||
|
@ -716,7 +768,9 @@ U.Marker = L.Marker.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
_getIconUrl: function (name) {
|
_getIconUrl: function (name) {
|
||||||
if (typeof name === 'undefined') name = 'icon'
|
if (typeof name === 'undefined') {
|
||||||
|
name = 'icon'
|
||||||
|
}
|
||||||
return this.getOption(`${name}Url`)
|
return this.getOption(`${name}Url`)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -797,7 +851,9 @@ U.PathMixin = {
|
||||||
|
|
||||||
edit: function (e) {
|
edit: function (e) {
|
||||||
if (this.map.editEnabled) {
|
if (this.map.editEnabled) {
|
||||||
if (!this.editEnabled()) this.enableEdit()
|
if (!this.editEnabled()) {
|
||||||
|
this.enableEdit()
|
||||||
|
}
|
||||||
U.FeatureMixin.edit.call(this, e)
|
U.FeatureMixin.edit.call(this, e)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -847,13 +903,16 @@ U.PathMixin = {
|
||||||
option = this.styleOptions[idx]
|
option = this.styleOptions[idx]
|
||||||
options[option] = this.getDynamicOption(option)
|
options[option] = this.getDynamicOption(option)
|
||||||
}
|
}
|
||||||
if (options.interactive) this.options.pointerEvents = 'visiblePainted'
|
if (options.interactive) {
|
||||||
else this.options.pointerEvents = 'stroke'
|
this.options.pointerEvents = 'visiblePainted'
|
||||||
|
} else {
|
||||||
|
this.options.pointerEvents = 'stroke'
|
||||||
|
}
|
||||||
this.parentClass.prototype.setStyle.call(this, options)
|
this.parentClass.prototype.setStyle.call(this, options)
|
||||||
},
|
},
|
||||||
|
|
||||||
_redraw: function () {
|
_redraw: function () {
|
||||||
if (this.datalayer && this.datalayer.isVisible()) {
|
if (this.datalayer?.isVisible()) {
|
||||||
this.setStyle()
|
this.setStyle()
|
||||||
this.resetTooltip()
|
this.resetTooltip()
|
||||||
}
|
}
|
||||||
|
@ -867,14 +926,18 @@ U.PathMixin = {
|
||||||
// this.map.on('showmeasure', this.showMeasureTooltip, this);
|
// this.map.on('showmeasure', this.showMeasureTooltip, this);
|
||||||
// this.map.on('hidemeasure', this.removeTooltip, this);
|
// this.map.on('hidemeasure', this.removeTooltip, this);
|
||||||
this.parentClass.prototype.onAdd.call(this, map)
|
this.parentClass.prototype.onAdd.call(this, map)
|
||||||
if (this.editing && this.editing.enabled()) this.editing.addHooks()
|
if (this.editing?.enabled()) {
|
||||||
|
this.editing.addHooks()
|
||||||
|
}
|
||||||
this.resetTooltip()
|
this.resetTooltip()
|
||||||
},
|
},
|
||||||
|
|
||||||
onRemove: function (map) {
|
onRemove: function (map) {
|
||||||
// this.map.off('showmeasure', this.showMeasureTooltip, this);
|
// this.map.off('showmeasure', this.showMeasureTooltip, this);
|
||||||
// this.map.off('hidemeasure', this.removeTooltip, this);
|
// this.map.off('hidemeasure', this.removeTooltip, this);
|
||||||
if (this.editing && this.editing.enabled()) this.editing.removeHooks()
|
if (this.editing?.enabled()) {
|
||||||
|
this.editing.removeHooks()
|
||||||
|
}
|
||||||
U.FeatureMixin.onRemove.call(this, map)
|
U.FeatureMixin.onRemove.call(this, map)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -896,7 +959,7 @@ U.PathMixin = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_onMouseOver: function () {
|
_onMouseOver: function () {
|
||||||
if (this.map.measureTools && this.map.measureTools.enabled()) {
|
if (this.map.measureTools?.enabled()) {
|
||||||
this.map.tooltip.open({ content: this.getMeasure(), anchor: this })
|
this.map.tooltip.open({ content: this.getMeasure(), anchor: this })
|
||||||
} else if (this.map.editEnabled && !this.map.editedFeature) {
|
} else if (this.map.editEnabled && !this.map.editedFeature) {
|
||||||
this.map.tooltip.open({ content: L._('Click to edit'), anchor: this })
|
this.map.tooltip.open({ content: L._('Click to edit'), anchor: this })
|
||||||
|
@ -914,22 +977,32 @@ U.PathMixin = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDrag: function () {
|
_onDrag: function () {
|
||||||
if (this._tooltip) this._tooltip.setLatLng(this.getCenter())
|
if (this._tooltip) {
|
||||||
|
this._tooltip.setLatLng(this.getCenter())
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
transferShape: function (at, to) {
|
transferShape: function (at, to) {
|
||||||
const shape = this.enableEdit().deleteShapeAt(at)
|
const shape = this.enableEdit().deleteShapeAt(at)
|
||||||
this.disableEdit()
|
this.disableEdit()
|
||||||
if (!shape) return
|
if (!shape) {
|
||||||
|
return
|
||||||
|
}
|
||||||
to.enableEdit().appendShape(shape)
|
to.enableEdit().appendShape(shape)
|
||||||
if (!this._latlngs.length || !this._latlngs[0].length) this.del()
|
if (!this._latlngs.length || !this._latlngs[0].length) {
|
||||||
|
this.del()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
isolateShape: function (at) {
|
isolateShape: function (at) {
|
||||||
if (!this.isMulti()) return
|
if (!this.isMulti()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const shape = this.enableEdit().deleteShapeAt(at)
|
const shape = this.enableEdit().deleteShapeAt(at)
|
||||||
this.disableEdit()
|
this.disableEdit()
|
||||||
if (!shape) return
|
if (!shape) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const properties = this.cloneProperties()
|
const properties = this.cloneProperties()
|
||||||
const other = new (this instanceof U.Polyline ? U.Polyline : U.Polygon)(
|
const other = new (this instanceof U.Polyline ? U.Polyline : U.Polygon)(
|
||||||
this.map,
|
this.map,
|
||||||
|
@ -1033,7 +1106,9 @@ U.PathMixin = {
|
||||||
} else {
|
} else {
|
||||||
this.map.fitBounds(this.getBounds(), this.getBestZoom() || this.map.getZoom())
|
this.map.fitBounds(this.getBounds(), this.getBestZoom() || this.map.getZoom())
|
||||||
}
|
}
|
||||||
if (e.callback) e.callback.call(this)
|
if (e.callback) {
|
||||||
|
e.callback.call(this)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1103,7 +1178,7 @@ U.Polyline = L.Polyline.extend({
|
||||||
U.Utils.flattenCoordinates(geojson.geometry.coordinates),
|
U.Utils.flattenCoordinates(geojson.geometry.coordinates),
|
||||||
]
|
]
|
||||||
|
|
||||||
delete geojson.id // delete the copied id, a new one will be generated.
|
geojson.id // delete the copied id, a new one will be generated. = undefined // delete the copied id, a new one will be generated.
|
||||||
|
|
||||||
const polygon = this.datalayer.geojsonToFeatures(geojson)
|
const polygon = this.datalayer.geojsonToFeatures(geojson)
|
||||||
polygon.edit()
|
polygon.edit()
|
||||||
|
@ -1142,11 +1217,11 @@ U.Polyline = L.Polyline.extend({
|
||||||
from.reverse()
|
from.reverse()
|
||||||
toMerge = [from, to]
|
toMerge = [from, to]
|
||||||
}
|
}
|
||||||
const a = toMerge[0],
|
const a = toMerge[0]
|
||||||
b = toMerge[1],
|
const b = toMerge[1]
|
||||||
p1 = this.map.latLngToContainerPoint(a[a.length - 1]),
|
const p1 = this.map.latLngToContainerPoint(a[a.length - 1])
|
||||||
p2 = this.map.latLngToContainerPoint(b[0]),
|
const p2 = this.map.latLngToContainerPoint(b[0])
|
||||||
tolerance = 5 // px on screen
|
const tolerance = 5 // px on screen
|
||||||
if (Math.abs(p1.x - p2.x) <= tolerance && Math.abs(p1.y - p2.y) <= tolerance) {
|
if (Math.abs(p1.x - p2.x) <= tolerance && Math.abs(p1.y - p2.y) <= tolerance) {
|
||||||
a.pop()
|
a.pop()
|
||||||
}
|
}
|
||||||
|
@ -1154,14 +1229,20 @@ U.Polyline = L.Polyline.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
mergeShapes: function () {
|
mergeShapes: function () {
|
||||||
if (!this.isMulti()) return
|
if (!this.isMulti()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const latlngs = this.getLatLngs()
|
const latlngs = this.getLatLngs()
|
||||||
if (!latlngs.length) return
|
if (!latlngs.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
while (latlngs.length > 1) {
|
while (latlngs.length > 1) {
|
||||||
latlngs.splice(0, 2, this._mergeShapes(latlngs[1], latlngs[0]))
|
latlngs.splice(0, 2, this._mergeShapes(latlngs[1], latlngs[0]))
|
||||||
}
|
}
|
||||||
this.setLatLngs(latlngs[0])
|
this.setLatLngs(latlngs[0])
|
||||||
if (!this.editEnabled()) this.edit()
|
if (!this.editEnabled()) {
|
||||||
|
this.edit()
|
||||||
|
}
|
||||||
this.editor.reset()
|
this.editor.reset()
|
||||||
this.isDirty = true
|
this.isDirty = true
|
||||||
},
|
},
|
||||||
|
@ -1171,11 +1252,13 @@ U.Polyline = L.Polyline.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
getVertexActions: function (e) {
|
getVertexActions: function (e) {
|
||||||
const actions = U.FeatureMixin.getVertexActions.call(this, e),
|
const actions = U.FeatureMixin.getVertexActions.call(this, e)
|
||||||
index = e.vertex.getIndex()
|
const index = e.vertex.getIndex()
|
||||||
if (index === 0 || index === e.vertex.getLastIndex())
|
if (index === 0 || index === e.vertex.getLastIndex()) {
|
||||||
actions.push(U.ContinueLineAction)
|
actions.push(U.ContinueLineAction)
|
||||||
else actions.push(U.SplitLineAction)
|
} else {
|
||||||
|
actions.push(U.SplitLineAction)
|
||||||
|
}
|
||||||
return actions
|
return actions
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1214,8 +1297,8 @@ U.Polygon = L.Polygon.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
getContextMenuEditItems: function (e) {
|
getContextMenuEditItems: function (e) {
|
||||||
const items = U.PathMixin.getContextMenuEditItems.call(this, e),
|
const items = U.PathMixin.getContextMenuEditItems.call(this, e)
|
||||||
shape = this.shapeAt(e.latlng)
|
const shape = this.shapeAt(e.latlng)
|
||||||
// No multi and no holes.
|
// No multi and no holes.
|
||||||
if (shape && !this.isMulti() && (L.LineUtil.isFlat(shape) || shape.length === 1)) {
|
if (shape && !this.isMulti() && (L.LineUtil.isFlat(shape) || shape.length === 1)) {
|
||||||
items.push({
|
items.push({
|
||||||
|
@ -1238,8 +1321,8 @@ U.Polygon = L.Polygon.extend({
|
||||||
|
|
||||||
toPolyline: function () {
|
toPolyline: function () {
|
||||||
const geojson = this.toGeoJSON()
|
const geojson = this.toGeoJSON()
|
||||||
delete geojson.id
|
geojson.id = undefined
|
||||||
delete geojson.properties.id
|
geojson.properties.id = undefined
|
||||||
geojson.geometry.type = 'LineString'
|
geojson.geometry.type = 'LineString'
|
||||||
geojson.geometry.coordinates = U.Utils.flattenCoordinates(
|
geojson.geometry.coordinates = U.Utils.flattenCoordinates(
|
||||||
geojson.geometry.coordinates
|
geojson.geometry.coordinates
|
||||||
|
|
|
@ -60,9 +60,11 @@ L.FormBuilder.Element.include({
|
||||||
},
|
},
|
||||||
|
|
||||||
get: function (own) {
|
get: function (own) {
|
||||||
if (!this.options.inheritable || own) return this.builder.getter(this.field)
|
if (!this.options.inheritable || own) {
|
||||||
const path = this.field.split('.'),
|
return this.builder.getter(this.field)
|
||||||
key = path[path.length - 1]
|
}
|
||||||
|
const path = this.field.split('.')
|
||||||
|
const key = path[path.length - 1]
|
||||||
return this.obj.getOption(key)
|
return this.obj.getOption(key)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -70,9 +72,9 @@ L.FormBuilder.Element.include({
|
||||||
if (this.options.label) {
|
if (this.options.label) {
|
||||||
this.label = L.DomUtil.create('label', '', this.getLabelParent())
|
this.label = L.DomUtil.create('label', '', this.getLabelParent())
|
||||||
this.label.textContent = this.label.title = this.options.label
|
this.label.textContent = this.label.title = this.options.label
|
||||||
if (this.options.helpEntries)
|
if (this.options.helpEntries) {
|
||||||
this.builder.map.help.button(this.label, this.options.helpEntries)
|
this.builder.map.help.button(this.label, this.options.helpEntries)
|
||||||
else if (this.options.helpTooltip) {
|
} else if (this.options.helpTooltip) {
|
||||||
const info = L.DomUtil.create('i', 'info', this.label)
|
const info = L.DomUtil.create('i', 'info', this.label)
|
||||||
L.DomEvent.on(
|
L.DomEvent.on(
|
||||||
info,
|
info,
|
||||||
|
@ -97,7 +99,9 @@ L.FormBuilder.Select.include({
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefault: function () {
|
getDefault: function () {
|
||||||
if (this.options.inheritable) return undefined
|
if (this.options.inheritable) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
return this.getOptions()[0][0]
|
return this.getOptions()[0][0]
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -309,8 +313,11 @@ L.FormBuilder.ColorPicker = L.FormBuilder.Input.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
spreadColor: function () {
|
spreadColor: function () {
|
||||||
if (this.input.value) this.input.style.backgroundColor = this.input.value
|
if (this.input.value) {
|
||||||
else this.input.style.backgroundColor = 'inherit'
|
this.input.style.backgroundColor = this.input.value
|
||||||
|
} else {
|
||||||
|
this.input.style.backgroundColor = 'inherit'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addColor: function (colorName) {
|
addColor: function (colorName) {
|
||||||
|
@ -476,13 +483,20 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
||||||
const [{ pictogram_list }, response, error] = await this.builder.map.server.get(
|
const [{ pictogram_list }, response, error] = await this.builder.map.server.get(
|
||||||
this.builder.map.options.urls.pictogram_list_json
|
this.builder.map.options.urls.pictogram_list_json
|
||||||
)
|
)
|
||||||
if (!error) this.pictogram_list = pictogram_list
|
if (!error) {
|
||||||
|
this.pictogram_list = pictogram_list
|
||||||
|
}
|
||||||
this.buildTabs()
|
this.buildTabs()
|
||||||
const value = this.value()
|
const value = this.value()
|
||||||
if (U.Icon.RECENT.length) this.showRecentTab()
|
if (U.Icon.RECENT.length) {
|
||||||
else if (!value || U.Utils.isPath(value)) this.showSymbolsTab()
|
this.showRecentTab()
|
||||||
else if (U.Utils.isRemoteUrl(value) || U.Utils.isDataImage(value)) this.showURLTab()
|
} else if (!value || U.Utils.isPath(value)) {
|
||||||
else this.showCharsTab()
|
this.showSymbolsTab()
|
||||||
|
} else if (U.Utils.isRemoteUrl(value) || U.Utils.isDataImage(value)) {
|
||||||
|
this.showURLTab()
|
||||||
|
} else {
|
||||||
|
this.showCharsTab()
|
||||||
|
}
|
||||||
const closeButton = L.DomUtil.createButton(
|
const closeButton = L.DomUtil.createButton(
|
||||||
'button action-button',
|
'button action-button',
|
||||||
this.footer,
|
this.footer,
|
||||||
|
@ -491,8 +505,11 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
||||||
this.body.innerHTML = ''
|
this.body.innerHTML = ''
|
||||||
this.tabs.innerHTML = ''
|
this.tabs.innerHTML = ''
|
||||||
this.footer.innerHTML = ''
|
this.footer.innerHTML = ''
|
||||||
if (this.isDefault()) this.undefine(e)
|
if (this.isDefault()) {
|
||||||
else this.updatePreview()
|
this.undefine(e)
|
||||||
|
} else {
|
||||||
|
this.updatePreview()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
|
@ -514,13 +531,8 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const symbol = L.DomUtil.add(
|
const symbol = L.DomUtil.add('button', 'flat tab-symbols', this.tabs, L._('Symbol'))
|
||||||
'button',
|
const char = L.DomUtil.add(
|
||||||
'flat tab-symbols',
|
|
||||||
this.tabs,
|
|
||||||
L._('Symbol')
|
|
||||||
),
|
|
||||||
char = L.DomUtil.add(
|
|
||||||
'button',
|
'button',
|
||||||
'flat tab-chars',
|
'flat tab-chars',
|
||||||
this.tabs,
|
this.tabs,
|
||||||
|
@ -554,7 +566,9 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
||||||
|
|
||||||
updatePreview: function () {
|
updatePreview: function () {
|
||||||
this.buttons.innerHTML = ''
|
this.buttons.innerHTML = ''
|
||||||
if (this.isDefault()) return
|
if (this.isDefault()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!U.Utils.hasVar(this.value())) {
|
if (!U.Utils.hasVar(this.value())) {
|
||||||
// Do not try to render URL with variables
|
// Do not try to render URL with variables
|
||||||
const box = L.DomUtil.create('div', 'umap-pictogram-choice', this.buttons)
|
const box = L.DomUtil.create('div', 'umap-pictogram-choice', this.buttons)
|
||||||
|
@ -571,15 +585,17 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
addIconPreview: function (pictogram, parent) {
|
addIconPreview: function (pictogram, parent) {
|
||||||
const baseClass = 'umap-pictogram-choice',
|
const baseClass = 'umap-pictogram-choice'
|
||||||
value = pictogram.src,
|
const value = pictogram.src
|
||||||
search = U.Utils.normalize(this.searchInput.value),
|
const search = U.Utils.normalize(this.searchInput.value)
|
||||||
title = pictogram.attribution
|
const title = pictogram.attribution
|
||||||
? `${pictogram.name} — © ${pictogram.attribution}`
|
? `${pictogram.name} — © ${pictogram.attribution}`
|
||||||
: pictogram.name || pictogram.src
|
: pictogram.name || pictogram.src
|
||||||
if (search && U.Utils.normalize(title).indexOf(search) === -1) return
|
if (search && U.Utils.normalize(title).indexOf(search) === -1) {
|
||||||
const className = value === this.value() ? `${baseClass} selected` : baseClass,
|
return
|
||||||
container = L.DomUtil.create('div', className, parent)
|
}
|
||||||
|
const className = value === this.value() ? `${baseClass} selected` : baseClass
|
||||||
|
const container = L.DomUtil.create('div', className, parent)
|
||||||
U.Icon.makeIconElement(value, container)
|
U.Icon.makeIconElement(value, container)
|
||||||
container.title = title
|
container.title = title
|
||||||
L.DomEvent.on(
|
L.DomEvent.on(
|
||||||
|
@ -606,13 +622,17 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
||||||
|
|
||||||
addCategory: function (items, name) {
|
addCategory: function (items, name) {
|
||||||
const parent = L.DomUtil.create('div', 'umap-pictogram-category')
|
const parent = L.DomUtil.create('div', 'umap-pictogram-category')
|
||||||
if (name) L.DomUtil.add('h6', '', parent, name)
|
if (name) {
|
||||||
|
L.DomUtil.add('h6', '', parent, name)
|
||||||
|
}
|
||||||
const grid = L.DomUtil.create('div', 'umap-pictogram-grid', parent)
|
const grid = L.DomUtil.create('div', 'umap-pictogram-grid', parent)
|
||||||
let status = false
|
let status = false
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
status = this.addIconPreview(item, grid) || status
|
status = this.addIconPreview(item, grid) || status
|
||||||
}
|
}
|
||||||
if (status) this.grid.appendChild(parent)
|
if (status) {
|
||||||
|
this.grid.appendChild(parent)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
buildSymbolsList: function () {
|
buildSymbolsList: function () {
|
||||||
|
@ -653,7 +673,9 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
showRecentTab: function () {
|
showRecentTab: function () {
|
||||||
if (!U.Icon.RECENT.length) return
|
if (!U.Icon.RECENT.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.openTab('recent')
|
this.openTab('recent')
|
||||||
this.addGrid(this.buildRecentList)
|
this.addGrid(this.buildRecentList)
|
||||||
this.buildRecentList()
|
this.buildRecentList()
|
||||||
|
@ -687,11 +709,15 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
||||||
buildInput: function (parent, value) {
|
buildInput: function (parent, value) {
|
||||||
const input = L.DomUtil.create('input', 'blur', parent)
|
const input = L.DomUtil.create('input', 'blur', parent)
|
||||||
const button = L.DomUtil.create('span', 'button blur-button', parent)
|
const button = L.DomUtil.create('span', 'button blur-button', parent)
|
||||||
if (value) input.value = value
|
if (value) {
|
||||||
|
input.value = value
|
||||||
|
}
|
||||||
L.DomEvent.on(input, 'blur', () => {
|
L.DomEvent.on(input, 'blur', () => {
|
||||||
// Do not clear this.input when focus-blur
|
// Do not clear this.input when focus-blur
|
||||||
// empty input
|
// empty input
|
||||||
if (input.value === value) return
|
if (input.value === value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.input.value = input.value
|
this.input.value = input.value
|
||||||
this.sync()
|
this.sync()
|
||||||
})
|
})
|
||||||
|
@ -701,7 +727,9 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
||||||
unselectAll: (container) => {
|
unselectAll: (container) => {
|
||||||
const els = container.querySelectorAll('div.selected')
|
const els = container.querySelectorAll('div.selected')
|
||||||
for (const el in els) {
|
for (const el in els) {
|
||||||
if (els.hasOwnProperty(el)) L.DomUtil.removeClass(els[el], 'selected')
|
if (els.hasOwnProperty(el)) {
|
||||||
|
L.DomUtil.removeClass(els[el], 'selected')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -713,15 +741,19 @@ L.FormBuilder.Url = L.FormBuilder.Input.extend({
|
||||||
L.FormBuilder.Switch = L.FormBuilder.CheckBox.extend({
|
L.FormBuilder.Switch = L.FormBuilder.CheckBox.extend({
|
||||||
getParentNode: function () {
|
getParentNode: function () {
|
||||||
L.FormBuilder.CheckBox.prototype.getParentNode.call(this)
|
L.FormBuilder.CheckBox.prototype.getParentNode.call(this)
|
||||||
if (this.options.inheritable) return this.quickContainer
|
if (this.options.inheritable) {
|
||||||
|
return this.quickContainer
|
||||||
|
}
|
||||||
return this.extendedContainer
|
return this.extendedContainer
|
||||||
},
|
},
|
||||||
|
|
||||||
build: function () {
|
build: function () {
|
||||||
L.FormBuilder.CheckBox.prototype.build.apply(this)
|
L.FormBuilder.CheckBox.prototype.build.apply(this)
|
||||||
if (this.options.inheritable)
|
if (this.options.inheritable) {
|
||||||
this.label = L.DomUtil.create('label', '', this.input.parentNode)
|
this.label = L.DomUtil.create('label', '', this.input.parentNode)
|
||||||
else this.input.parentNode.appendChild(this.label)
|
} else {
|
||||||
|
this.input.parentNode.appendChild(this.label)
|
||||||
|
}
|
||||||
L.DomUtil.addClass(this.input.parentNode, 'with-switch')
|
L.DomUtil.addClass(this.input.parentNode, 'with-switch')
|
||||||
const id = `${this.builder.options.id || Date.now()}.${this.name}`
|
const id = `${this.builder.options.id || Date.now()}.${this.name}`
|
||||||
this.label.setAttribute('for', id)
|
this.label.setAttribute('for', id)
|
||||||
|
@ -743,9 +775,9 @@ L.FormBuilder.FacetSearchChoices = L.FormBuilder.FacetSearchBase.extend({
|
||||||
this.container = L.DomUtil.create('fieldset', 'umap-facet', this.parentNode)
|
this.container = L.DomUtil.create('fieldset', 'umap-facet', this.parentNode)
|
||||||
this.container.appendChild(this.label)
|
this.container.appendChild(this.label)
|
||||||
this.ul = L.DomUtil.create('ul', '', this.container)
|
this.ul = L.DomUtil.create('ul', '', this.container)
|
||||||
this.type = this.options.criteria['type']
|
this.type = this.options.criteria.type
|
||||||
|
|
||||||
const choices = this.options.criteria['choices']
|
const choices = this.options.criteria.choices
|
||||||
choices.sort()
|
choices.sort()
|
||||||
choices.forEach((value) => this.buildLi(value))
|
choices.forEach((value) => this.buildLi(value))
|
||||||
},
|
},
|
||||||
|
@ -758,7 +790,7 @@ L.FormBuilder.FacetSearchChoices = L.FormBuilder.FacetSearchBase.extend({
|
||||||
|
|
||||||
input.type = this.type
|
input.type = this.type
|
||||||
input.name = `${this.type}_${this.name}`
|
input.name = `${this.type}_${this.name}`
|
||||||
input.checked = this.get()['choices'].includes(value)
|
input.checked = this.get().choices.includes(value)
|
||||||
input.dataset.value = value
|
input.dataset.value = value
|
||||||
|
|
||||||
L.DomEvent.on(input, 'change', (e) => this.sync())
|
L.DomEvent.on(input, 'change', (e) => this.sync())
|
||||||
|
@ -845,13 +877,13 @@ L.FormBuilder.MinMaxBase = L.FormBuilder.FacetSearchBase.extend({
|
||||||
isMinModified: function () {
|
isMinModified: function () {
|
||||||
const default_ = this.minInput.getAttribute('value')
|
const default_ = this.minInput.getAttribute('value')
|
||||||
const current = this.minInput.value
|
const current = this.minInput.value
|
||||||
return current != default_
|
return current !== default_
|
||||||
},
|
},
|
||||||
|
|
||||||
isMaxModified: function () {
|
isMaxModified: function () {
|
||||||
const default_ = this.maxInput.getAttribute('value')
|
const default_ = this.maxInput.getAttribute('value')
|
||||||
const current = this.maxInput.value
|
const current = this.maxInput.value
|
||||||
return current != default_
|
return current !== default_
|
||||||
},
|
},
|
||||||
|
|
||||||
toJS: function () {
|
toJS: function () {
|
||||||
|
@ -879,7 +911,9 @@ L.FormBuilder.FacetSearchDate = L.FormBuilder.MinMaxBase.extend({
|
||||||
|
|
||||||
prepareForHTML: function (value) {
|
prepareForHTML: function (value) {
|
||||||
// Value must be in local time
|
// Value must be in local time
|
||||||
if (isNaN(value)) return
|
if (Number.isNaN(value)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
return this.toLocaleDateTime(value).toISOString().substr(0, 10)
|
return this.toLocaleDateTime(value).toISOString().substr(0, 10)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -891,7 +925,9 @@ L.FormBuilder.FacetSearchDateTime = L.FormBuilder.FacetSearchDate.extend({
|
||||||
|
|
||||||
prepareForHTML: function (value) {
|
prepareForHTML: function (value) {
|
||||||
// Value must be in local time
|
// Value must be in local time
|
||||||
if (isNaN(value)) return
|
if (Number.isNaN(value)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
return this.toLocaleDateTime(value).toISOString().slice(0, -1)
|
return this.toLocaleDateTime(value).toISOString().slice(0, -1)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -902,7 +938,9 @@ L.FormBuilder.MultiChoice = L.FormBuilder.Element.extend({
|
||||||
|
|
||||||
clear: function () {
|
clear: function () {
|
||||||
const checked = this.container.querySelector('input[type="radio"]:checked')
|
const checked = this.container.querySelector('input[type="radio"]:checked')
|
||||||
if (checked) checked.checked = false
|
if (checked) {
|
||||||
|
checked.checked = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
fetch: function () {
|
fetch: function () {
|
||||||
|
@ -920,7 +958,9 @@ L.FormBuilder.MultiChoice = L.FormBuilder.Element.extend({
|
||||||
|
|
||||||
value: function () {
|
value: function () {
|
||||||
const checked = this.container.querySelector('input[type="radio"]:checked')
|
const checked = this.container.querySelector('input[type="radio"]:checked')
|
||||||
if (checked) return checked.value
|
if (checked) {
|
||||||
|
return checked.value
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getChoices: function () {
|
getChoices: function () {
|
||||||
|
@ -992,8 +1032,9 @@ L.FormBuilder.DataLayersControl = L.FormBuilder.TernaryChoices.extend({
|
||||||
|
|
||||||
toJS: function () {
|
toJS: function () {
|
||||||
let value = this.value()
|
let value = this.value()
|
||||||
if (value !== 'expanded')
|
if (value !== 'expanded') {
|
||||||
value = L.FormBuilder.TernaryChoices.prototype.toJS.call(this)
|
value = L.FormBuilder.TernaryChoices.prototype.toJS.call(this)
|
||||||
|
}
|
||||||
return value
|
return value
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1037,10 +1078,11 @@ L.FormBuilder.ManageOwner = L.FormBuilder.Element.extend({
|
||||||
}
|
}
|
||||||
this.autocomplete = new U.AjaxAutocomplete(this.parentNode, options)
|
this.autocomplete = new U.AjaxAutocomplete(this.parentNode, options)
|
||||||
const owner = this.toHTML()
|
const owner = this.toHTML()
|
||||||
if (owner)
|
if (owner) {
|
||||||
this.autocomplete.displaySelected({
|
this.autocomplete.displaySelected({
|
||||||
item: { value: owner.id, label: owner.name },
|
item: { value: owner.id, label: owner.name },
|
||||||
})
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
value: function () {
|
value: function () {
|
||||||
|
@ -1066,11 +1108,13 @@ L.FormBuilder.ManageEditors = L.FormBuilder.Element.extend({
|
||||||
}
|
}
|
||||||
this.autocomplete = new U.AjaxAutocompleteMultiple(this.parentNode, options)
|
this.autocomplete = new U.AjaxAutocompleteMultiple(this.parentNode, options)
|
||||||
this._values = this.toHTML()
|
this._values = this.toHTML()
|
||||||
if (this._values)
|
if (this._values) {
|
||||||
for (let i = 0; i < this._values.length; i++)
|
for (let i = 0; i < this._values.length; i++) {
|
||||||
this.autocomplete.displaySelected({
|
this.autocomplete.displaySelected({
|
||||||
item: { value: this._values[i].id, label: this._values[i].name },
|
item: { value: this._values[i].id, label: this._values[i].name },
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
value: function () {
|
value: function () {
|
||||||
|
@ -1103,13 +1147,19 @@ U.FormBuilder = L.FormBuilder.extend({
|
||||||
computeDefaultOptions: function () {
|
computeDefaultOptions: function () {
|
||||||
for (const [key, schema] of Object.entries(U.SCHEMA)) {
|
for (const [key, schema] of Object.entries(U.SCHEMA)) {
|
||||||
if (schema.type === Boolean) {
|
if (schema.type === Boolean) {
|
||||||
if (schema.nullable) schema.handler = 'NullableChoices'
|
if (schema.nullable) {
|
||||||
else schema.handler = 'Switch'
|
schema.handler = 'NullableChoices'
|
||||||
|
} else {
|
||||||
|
schema.handler = 'Switch'
|
||||||
|
}
|
||||||
} else if (schema.type === 'Text') {
|
} else if (schema.type === 'Text') {
|
||||||
schema.handler = 'Textarea'
|
schema.handler = 'Textarea'
|
||||||
} else if (schema.type === Number) {
|
} else if (schema.type === Number) {
|
||||||
if (schema.step) schema.handler = 'Range'
|
if (schema.step) {
|
||||||
else schema.handler = 'IntInput'
|
schema.handler = 'Range'
|
||||||
|
} else {
|
||||||
|
schema.handler = 'IntInput'
|
||||||
|
}
|
||||||
} else if (schema.choices) {
|
} else if (schema.choices) {
|
||||||
const text_length = schema.choices.reduce(
|
const text_length = schema.choices.reduce(
|
||||||
(acc, [value, label]) => acc + label.length,
|
(acc, [value, label]) => acc + label.length,
|
||||||
|
@ -1138,7 +1188,7 @@ U.FormBuilder = L.FormBuilder.extend({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FormBuilder use this key for the input type itself
|
// FormBuilder use this key for the input type itself
|
||||||
delete schema.type
|
schema.type = undefined
|
||||||
this.defaultOptions[key] = schema
|
this.defaultOptions[key] = schema
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,14 +12,18 @@ U.Icon = L.DivIcon.extend({
|
||||||
options = L.Util.extend({}, default_options, options)
|
options = L.Util.extend({}, default_options, options)
|
||||||
L.Icon.prototype.initialize.call(this, options)
|
L.Icon.prototype.initialize.call(this, options)
|
||||||
this.feature = this.options.feature
|
this.feature = this.options.feature
|
||||||
if (this.feature && this.feature.isReadOnly()) {
|
if (this.feature?.isReadOnly()) {
|
||||||
this.options.className += ' readonly'
|
this.options.className += ' readonly'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_setRecent: (url) => {
|
_setRecent: (url) => {
|
||||||
if (U.Utils.hasVar(url)) return
|
if (U.Utils.hasVar(url)) {
|
||||||
if (url === U.SCHEMA.iconUrl.default) return
|
return
|
||||||
|
}
|
||||||
|
if (url === U.SCHEMA.iconUrl.default) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (U.Icon.RECENT.indexOf(url) === -1) {
|
if (U.Icon.RECENT.indexOf(url) === -1) {
|
||||||
U.Icon.RECENT.push(url)
|
U.Icon.RECENT.push(url)
|
||||||
}
|
}
|
||||||
|
@ -27,7 +31,7 @@ U.Icon = L.DivIcon.extend({
|
||||||
|
|
||||||
_getIconUrl: function (name) {
|
_getIconUrl: function (name) {
|
||||||
let url
|
let url
|
||||||
if (this.feature && this.feature._getIconUrl(name)) {
|
if (this.feature?._getIconUrl(name)) {
|
||||||
url = this.feature._getIconUrl(name)
|
url = this.feature._getIconUrl(name)
|
||||||
this._setRecent(url)
|
this._setRecent(url)
|
||||||
} else {
|
} else {
|
||||||
|
@ -38,14 +42,20 @@ U.Icon = L.DivIcon.extend({
|
||||||
|
|
||||||
_getColor: function () {
|
_getColor: function () {
|
||||||
let color
|
let color
|
||||||
if (this.feature) color = this.feature.getDynamicOption('color')
|
if (this.feature) {
|
||||||
else if (this.options.color) color = this.options.color
|
color = this.feature.getDynamicOption('color')
|
||||||
else color = this.map.getDefaultOption('color')
|
} else if (this.options.color) {
|
||||||
|
color = this.options.color
|
||||||
|
} else {
|
||||||
|
color = this.map.getDefaultOption('color')
|
||||||
|
}
|
||||||
return color
|
return color
|
||||||
},
|
},
|
||||||
|
|
||||||
_getOpacity: function () {
|
_getOpacity: function () {
|
||||||
if (this.feature) return this.feature.getOption('iconOpacity')
|
if (this.feature) {
|
||||||
|
return this.feature.getOption('iconOpacity')
|
||||||
|
}
|
||||||
return this.map.getDefaultOption('iconOpacity')
|
return this.map.getDefaultOption('iconOpacity')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -70,8 +80,8 @@ U.Icon.Default = U.Icon.extend({
|
||||||
|
|
||||||
_setIconStyles: function (img, name) {
|
_setIconStyles: function (img, name) {
|
||||||
U.Icon.prototype._setIconStyles.call(this, img, name)
|
U.Icon.prototype._setIconStyles.call(this, img, name)
|
||||||
const color = this._getColor(),
|
const color = this._getColor()
|
||||||
opacity = this._getOpacity()
|
const opacity = this._getOpacity()
|
||||||
this.elements.container.style.backgroundColor = color
|
this.elements.container.style.backgroundColor = color
|
||||||
this.elements.arrow.style.borderTopColor = color
|
this.elements.arrow.style.borderTopColor = color
|
||||||
this.elements.container.style.opacity = opacity
|
this.elements.container.style.opacity = opacity
|
||||||
|
@ -185,10 +195,10 @@ U.Icon.Cluster = L.DivIcon.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
createIcon: function () {
|
createIcon: function () {
|
||||||
const container = L.DomUtil.create('div', 'leaflet-marker-icon marker-cluster'),
|
const container = L.DomUtil.create('div', 'leaflet-marker-icon marker-cluster')
|
||||||
div = L.DomUtil.create('div', '', container),
|
const div = L.DomUtil.create('div', '', container)
|
||||||
span = L.DomUtil.create('span', '', div),
|
const span = L.DomUtil.create('span', '', div)
|
||||||
backgroundColor = this.datalayer.getColor()
|
const backgroundColor = this.datalayer.getColor()
|
||||||
span.textContent = this.cluster.getChildCount()
|
span.textContent = this.cluster.getChildCount()
|
||||||
div.style.backgroundColor = backgroundColor
|
div.style.backgroundColor = backgroundColor
|
||||||
return container
|
return container
|
||||||
|
@ -197,7 +207,7 @@ U.Icon.Cluster = L.DivIcon.extend({
|
||||||
computeTextColor: function (el) {
|
computeTextColor: function (el) {
|
||||||
let color
|
let color
|
||||||
const backgroundColor = this.datalayer.getColor()
|
const backgroundColor = this.datalayer.getColor()
|
||||||
if (this.datalayer.options.cluster && this.datalayer.options.cluster.textColor) {
|
if (this.datalayer.options.cluster?.textColor) {
|
||||||
color = this.datalayer.options.cluster.textColor
|
color = this.datalayer.options.cluster.textColor
|
||||||
}
|
}
|
||||||
return color || L.DomUtil.TextColorFromBackgroundColor(el, backgroundColor)
|
return color || L.DomUtil.TextColorFromBackgroundColor(el, backgroundColor)
|
||||||
|
@ -229,7 +239,9 @@ U.Icon.setIconContrast = (icon, parent, src, bgcolor) => {
|
||||||
* bgcolor: the background color, used for caching and in case we cannot guess the
|
* bgcolor: the background color, used for caching and in case we cannot guess the
|
||||||
* parent background color
|
* parent background color
|
||||||
*/
|
*/
|
||||||
if (!icon) return
|
if (!icon) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (L.DomUtil.contrastedColor(parent, bgcolor)) {
|
if (L.DomUtil.contrastedColor(parent, bgcolor)) {
|
||||||
// Decide whether to switch svg to white or not, but do it
|
// Decide whether to switch svg to white or not, but do it
|
||||||
|
|
|
@ -34,11 +34,15 @@ U.Map = L.Map.extend({
|
||||||
this.sync = this.sync_engine.proxy(this)
|
this.sync = this.sync_engine.proxy(this)
|
||||||
// Locale name (pt_PT, en_US…)
|
// Locale name (pt_PT, en_US…)
|
||||||
// To be used for Django localization
|
// To be used for Django localization
|
||||||
if (geojson.properties.locale) L.setLocale(geojson.properties.locale)
|
if (geojson.properties.locale) {
|
||||||
|
L.setLocale(geojson.properties.locale)
|
||||||
|
}
|
||||||
|
|
||||||
// Language code (pt-pt, en-us…)
|
// Language code (pt-pt, en-us…)
|
||||||
// To be used in javascript APIs
|
// To be used in javascript APIs
|
||||||
if (geojson.properties.lang) L.lang = geojson.properties.lang
|
if (geojson.properties.lang) {
|
||||||
|
L.lang = geojson.properties.lang
|
||||||
|
}
|
||||||
|
|
||||||
this.setOptionsFromQueryString(geojson.properties)
|
this.setOptionsFromQueryString(geojson.properties)
|
||||||
// Prevent default creation of controls
|
// Prevent default creation of controls
|
||||||
|
@ -49,10 +53,14 @@ U.Map = L.Map.extend({
|
||||||
|
|
||||||
L.Map.prototype.initialize.call(this, el, geojson.properties)
|
L.Map.prototype.initialize.call(this, el, geojson.properties)
|
||||||
|
|
||||||
if (geojson.properties.schema) this.overrideSchema(geojson.properties.schema)
|
if (geojson.properties.schema) {
|
||||||
|
this.overrideSchema(geojson.properties.schema)
|
||||||
|
}
|
||||||
|
|
||||||
// After calling parent initialize, as we are doing initCenter our-selves
|
// After calling parent initialize, as we are doing initCenter our-selves
|
||||||
if (geojson.geometry) this.options.center = this.latLng(geojson.geometry)
|
if (geojson.geometry) {
|
||||||
|
this.options.center = this.latLng(geojson.geometry)
|
||||||
|
}
|
||||||
this.urls = new U.URLs(this.options.urls)
|
this.urls = new U.URLs(this.options.urls)
|
||||||
|
|
||||||
this.panel = new U.Panel(this)
|
this.panel = new U.Panel(this)
|
||||||
|
@ -99,16 +107,12 @@ U.Map = L.Map.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrocompat
|
// Retrocompat
|
||||||
if (
|
if (this.options.slideshow?.delay && this.options.slideshow.active === undefined) {
|
||||||
this.options.slideshow &&
|
|
||||||
this.options.slideshow.delay &&
|
|
||||||
this.options.slideshow.active === undefined
|
|
||||||
) {
|
|
||||||
this.options.slideshow.active = true
|
this.options.slideshow.active = true
|
||||||
}
|
}
|
||||||
if (this.options.advancedFilterKey) {
|
if (this.options.advancedFilterKey) {
|
||||||
this.options.facetKey = this.options.advancedFilterKey
|
this.options.facetKey = this.options.advancedFilterKey
|
||||||
delete this.options.advancedFilterKey
|
this.options.advancedFilterKey = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global storage for retrieving datalayers and features
|
// Global storage for retrieving datalayers and features
|
||||||
|
@ -134,14 +138,14 @@ U.Map = L.Map.extend({
|
||||||
if (!this.options.onLoadPanel) {
|
if (!this.options.onLoadPanel) {
|
||||||
this.options.onLoadPanel = 'caption'
|
this.options.onLoadPanel = 'caption'
|
||||||
}
|
}
|
||||||
delete this.options.displayCaptionOnLoad
|
this.options.displayCaptionOnLoad = undefined
|
||||||
}
|
}
|
||||||
if (this.options.displayDataBrowserOnLoad) {
|
if (this.options.displayDataBrowserOnLoad) {
|
||||||
// Retrocompat
|
// Retrocompat
|
||||||
if (!this.options.onLoadPanel) {
|
if (!this.options.onLoadPanel) {
|
||||||
this.options.onLoadPanel = 'databrowser'
|
this.options.onLoadPanel = 'databrowser'
|
||||||
}
|
}
|
||||||
delete this.options.displayDataBrowserOnLoad
|
this.options.displayDataBrowserOnLoad = undefined
|
||||||
}
|
}
|
||||||
if (this.options.datalayersControl === 'expanded') {
|
if (this.options.datalayersControl === 'expanded') {
|
||||||
this.options.onLoadPanel = 'datalayers'
|
this.options.onLoadPanel = 'datalayers'
|
||||||
|
@ -165,7 +169,9 @@ U.Map = L.Map.extend({
|
||||||
this.on(
|
this.on(
|
||||||
'baselayerchange',
|
'baselayerchange',
|
||||||
function (e) {
|
function (e) {
|
||||||
if (this._controls.miniMap) this._controls.miniMap.onMainMapBaseLayerChange(e)
|
if (this._controls.miniMap) {
|
||||||
|
this._controls.miniMap.onMainMapBaseLayerChange(e)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
|
@ -211,8 +217,10 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
initSyncEngine: async function () {
|
initSyncEngine: async function () {
|
||||||
if (this.options.websocketEnabled == false) return
|
if (this.options.websocketEnabled === false) {
|
||||||
if (this.options.syncEnabled != true) {
|
return
|
||||||
|
}
|
||||||
|
if (this.options.syncEnabled !== true) {
|
||||||
this.sync.stop()
|
this.sync.stop()
|
||||||
} else {
|
} else {
|
||||||
const ws_token_uri = this.urls.get('map_websocket_auth_token', {
|
const ws_token_uri = this.urls.get('map_websocket_auth_token', {
|
||||||
|
@ -278,8 +286,11 @@ U.Map = L.Map.extend({
|
||||||
for (const [key, schema] of Object.entries(U.SCHEMA)) {
|
for (const [key, schema] of Object.entries(U.SCHEMA)) {
|
||||||
switch (schema.type) {
|
switch (schema.type) {
|
||||||
case Boolean:
|
case Boolean:
|
||||||
if (schema.nullable) L.Util.setNullableBooleanFromQueryString(options, key)
|
if (schema.nullable) {
|
||||||
else L.Util.setBooleanFromQueryString(options, key)
|
L.Util.setNullableBooleanFromQueryString(options, key)
|
||||||
|
} else {
|
||||||
|
L.Util.setBooleanFromQueryString(options, key)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case Number:
|
case Number:
|
||||||
L.Util.setNumberFromQueryString(options, key)
|
L.Util.setNumberFromQueryString(options, key)
|
||||||
|
@ -297,7 +308,9 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
setViewFromQueryString: function () {
|
setViewFromQueryString: function () {
|
||||||
if (this.options.noControl) return
|
if (this.options.noControl) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.initCaptionBar()
|
this.initCaptionBar()
|
||||||
if (L.Util.queryString('share')) {
|
if (L.Util.queryString('share')) {
|
||||||
this.share.open()
|
this.share.open()
|
||||||
|
@ -317,9 +330,13 @@ U.Map = L.Map.extend({
|
||||||
// Comes after default panels, so if it opens in a panel it will
|
// Comes after default panels, so if it opens in a panel it will
|
||||||
// take precedence.
|
// take precedence.
|
||||||
const slug = L.Util.queryString('feature')
|
const slug = L.Util.queryString('feature')
|
||||||
if (slug && this.features_index[slug]) this.features_index[slug].view()
|
if (slug && this.features_index[slug]) {
|
||||||
|
this.features_index[slug].view()
|
||||||
|
}
|
||||||
if (L.Util.queryString('edit')) {
|
if (L.Util.queryString('edit')) {
|
||||||
if (this.hasEditMode()) this.enableEdit()
|
if (this.hasEditMode()) {
|
||||||
|
this.enableEdit()
|
||||||
|
}
|
||||||
// Sometimes users share the ?edit link by mistake, let's remove
|
// Sometimes users share the ?edit link by mistake, let's remove
|
||||||
// this search parameter from URL to prevent this
|
// this search parameter from URL to prevent this
|
||||||
const url = new URL(window.location)
|
const url = new URL(window.location)
|
||||||
|
@ -388,7 +405,9 @@ U.Map = L.Map.extend({
|
||||||
this._controls.search = new U.SearchControl()
|
this._controls.search = new U.SearchControl()
|
||||||
this._controls.embed = new L.Control.Embed(this)
|
this._controls.embed = new L.Control.Embed(this)
|
||||||
this._controls.tilelayersChooser = new U.TileLayerChooser(this)
|
this._controls.tilelayersChooser = new U.TileLayerChooser(this)
|
||||||
if (this.options.user) this._controls.star = new U.StarControl(this)
|
if (this.options.user) {
|
||||||
|
this._controls.star = new U.StarControl(this)
|
||||||
|
}
|
||||||
this._controls.editinosm = new L.Control.EditInOSM({
|
this._controls.editinosm = new L.Control.EditInOSM({
|
||||||
position: 'topleft',
|
position: 'topleft',
|
||||||
widgetOptions: {
|
widgetOptions: {
|
||||||
|
@ -401,8 +420,11 @@ U.Map = L.Map.extend({
|
||||||
this._controls.more = new U.MoreControls()
|
this._controls.more = new U.MoreControls()
|
||||||
this._controls.scale = L.control.scale()
|
this._controls.scale = L.control.scale()
|
||||||
this._controls.permanentCredit = new U.PermanentCreditsControl(this)
|
this._controls.permanentCredit = new U.PermanentCreditsControl(this)
|
||||||
if (this.options.scrollWheelZoom) this.scrollWheelZoom.enable()
|
if (this.options.scrollWheelZoom) {
|
||||||
else this.scrollWheelZoom.disable()
|
this.scrollWheelZoom.enable()
|
||||||
|
} else {
|
||||||
|
this.scrollWheelZoom.disable()
|
||||||
|
}
|
||||||
this.browser = new U.Browser(this)
|
this.browser = new U.Browser(this)
|
||||||
this.facets = new U.Facets(this)
|
this.facets = new U.Facets(this)
|
||||||
this.caption = new U.Caption(this)
|
this.caption = new U.Caption(this)
|
||||||
|
@ -414,16 +436,16 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
renderControls: function () {
|
renderControls: function () {
|
||||||
const hasSlideshow = Boolean(
|
const hasSlideshow = Boolean(this.options.slideshow?.active)
|
||||||
this.options.slideshow && this.options.slideshow.active
|
|
||||||
)
|
|
||||||
const barEnabled = this.options.captionBar || hasSlideshow
|
const barEnabled = this.options.captionBar || hasSlideshow
|
||||||
document.body.classList.toggle('umap-caption-bar-enabled', barEnabled)
|
document.body.classList.toggle('umap-caption-bar-enabled', barEnabled)
|
||||||
document.body.classList.toggle('umap-slideshow-enabled', hasSlideshow)
|
document.body.classList.toggle('umap-slideshow-enabled', hasSlideshow)
|
||||||
for (const control of Object.values(this._controls)) {
|
for (const control of Object.values(this._controls)) {
|
||||||
this.removeControl(control)
|
this.removeControl(control)
|
||||||
}
|
}
|
||||||
if (this.options.noControl) return
|
if (this.options.noControl) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this._controls.attribution = new U.AttributionControl().addTo(this)
|
this._controls.attribution = new U.AttributionControl().addTo(this)
|
||||||
if (this.options.miniMap) {
|
if (this.options.miniMap) {
|
||||||
|
@ -444,21 +466,35 @@ U.Map = L.Map.extend({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let name, status, control
|
let name
|
||||||
|
let status
|
||||||
|
let control
|
||||||
for (let i = 0; i < this.HIDDABLE_CONTROLS.length; i++) {
|
for (let i = 0; i < this.HIDDABLE_CONTROLS.length; i++) {
|
||||||
name = this.HIDDABLE_CONTROLS[i]
|
name = this.HIDDABLE_CONTROLS[i]
|
||||||
status = this.getOption(`${name}Control`)
|
status = this.getOption(`${name}Control`)
|
||||||
if (status === false) continue
|
if (status === false) {
|
||||||
control = this._controls[name]
|
continue
|
||||||
if (!control) continue
|
}
|
||||||
control.addTo(this)
|
control = this._controls[name]
|
||||||
if (status === undefined || status === null)
|
if (!control) {
|
||||||
L.DomUtil.addClass(control._container, 'display-on-more')
|
continue
|
||||||
else L.DomUtil.removeClass(control._container, 'display-on-more')
|
}
|
||||||
|
control.addTo(this)
|
||||||
|
if (status === undefined || status === null) {
|
||||||
|
L.DomUtil.addClass(control._container, 'display-on-more')
|
||||||
|
} else {
|
||||||
|
L.DomUtil.removeClass(control._container, 'display-on-more')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.getOption('permanentCredit')) {
|
||||||
|
this._controls.permanentCredit.addTo(this)
|
||||||
|
}
|
||||||
|
if (this.getOption('moreControl')) {
|
||||||
|
this._controls.more.addTo(this)
|
||||||
|
}
|
||||||
|
if (this.getOption('scaleControl')) {
|
||||||
|
this._controls.scale.addTo(this)
|
||||||
}
|
}
|
||||||
if (this.getOption('permanentCredit')) this._controls.permanentCredit.addTo(this)
|
|
||||||
if (this.getOption('moreControl')) this._controls.more.addTo(this)
|
|
||||||
if (this.getOption('scaleControl')) this._controls.scale.addTo(this)
|
|
||||||
this._controls.tilelayers.setLayers()
|
this._controls.tilelayers.setLayers()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -474,7 +510,9 @@ U.Map = L.Map.extend({
|
||||||
this.datalayersLoaded = true
|
this.datalayersLoaded = true
|
||||||
this.fire('datalayersloaded')
|
this.fire('datalayersloaded')
|
||||||
for (const datalayer of Object.values(this.datalayers)) {
|
for (const datalayer of Object.values(this.datalayers)) {
|
||||||
if (datalayer.showAtLoad()) await datalayer.show()
|
if (datalayer.showAtLoad()) {
|
||||||
|
await datalayer.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.dataloaded = true
|
this.dataloaded = true
|
||||||
this.fire('dataloaded')
|
this.fire('dataloaded')
|
||||||
|
@ -486,14 +524,18 @@ U.Map = L.Map.extend({
|
||||||
this.datalayers_index = []
|
this.datalayers_index = []
|
||||||
for (let i = 0; i < panes.children.length; i++) {
|
for (let i = 0; i < panes.children.length; i++) {
|
||||||
pane = panes.children[i]
|
pane = panes.children[i]
|
||||||
if (!pane.dataset || !pane.dataset.id) continue
|
if (!pane.dataset || !pane.dataset.id) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
this.datalayers_index.push(this.datalayers[pane.dataset.id])
|
this.datalayers_index.push(this.datalayers[pane.dataset.id])
|
||||||
}
|
}
|
||||||
this.onDataLayersChanged()
|
this.onDataLayersChanged()
|
||||||
},
|
},
|
||||||
|
|
||||||
onDataLayersChanged: function () {
|
onDataLayersChanged: function () {
|
||||||
if (this.browser) this.browser.update()
|
if (this.browser) {
|
||||||
|
this.browser.update()
|
||||||
|
}
|
||||||
this.caption.refresh()
|
this.caption.refresh()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -557,7 +599,9 @@ U.Map = L.Map.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
// From now on, only ctrl/meta shortcut
|
// From now on, only ctrl/meta shortcut
|
||||||
if (!(e.ctrlKey || e.metaKey) || e.shiftKey) return
|
if (!(e.ctrlKey || e.metaKey) || e.shiftKey) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (e.key === 'f') {
|
if (e.key === 'f') {
|
||||||
L.DomEvent.stop(e)
|
L.DomEvent.stop(e)
|
||||||
|
@ -565,7 +609,9 @@ U.Map = L.Map.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Edit mode only shortcuts */
|
/* Edit mode only shortcuts */
|
||||||
if (!this.hasEditMode()) return
|
if (!this.hasEditMode()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Edit mode Off
|
// Edit mode Off
|
||||||
if (!this.editEnabled) {
|
if (!this.editEnabled) {
|
||||||
|
@ -582,13 +628,19 @@ U.Map = L.Map.extend({
|
||||||
let used = true
|
let used = true
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case 'e':
|
case 'e':
|
||||||
if (!this.isDirty) this.disableEdit()
|
if (!this.isDirty) {
|
||||||
|
this.disableEdit()
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 's':
|
case 's':
|
||||||
if (this.isDirty) this.save()
|
if (this.isDirty) {
|
||||||
|
this.save()
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 'z':
|
case 'z':
|
||||||
if (this.isDirty) this.askForReset()
|
if (this.isDirty) {
|
||||||
|
this.askForReset()
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 'm':
|
case 'm':
|
||||||
this.editTools.startMarker()
|
this.editTools.startMarker()
|
||||||
|
@ -611,7 +663,9 @@ U.Map = L.Map.extend({
|
||||||
default:
|
default:
|
||||||
used = false
|
used = false
|
||||||
}
|
}
|
||||||
if (used) L.DomEvent.stop(e)
|
if (used) {
|
||||||
|
L.DomEvent.stop(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
L.DomEvent.addListener(document, 'keydown', globalShortcuts, this)
|
L.DomEvent.addListener(document, 'keydown', globalShortcuts, this)
|
||||||
},
|
},
|
||||||
|
@ -629,17 +683,15 @@ U.Map = L.Map.extend({
|
||||||
this.options.tilelayer.attribution = props.attribution
|
this.options.tilelayer.attribution = props.attribution
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (this.options.tilelayer?.url_template && this.options.tilelayer.attribution) {
|
||||||
this.options.tilelayer &&
|
|
||||||
this.options.tilelayer.url_template &&
|
|
||||||
this.options.tilelayer.attribution
|
|
||||||
) {
|
|
||||||
this.customTilelayer = this.createTileLayer(this.options.tilelayer)
|
this.customTilelayer = this.createTileLayer(this.options.tilelayer)
|
||||||
this.selectTileLayer(this.customTilelayer)
|
this.selectTileLayer(this.customTilelayer)
|
||||||
} else {
|
} else {
|
||||||
this.selectTileLayer(this.tilelayers[0])
|
this.selectTileLayer(this.tilelayers[0])
|
||||||
}
|
}
|
||||||
if (this._controls) this._controls.tilelayers.setLayers()
|
if (this._controls) {
|
||||||
|
this._controls.tilelayers.setLayers()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
createTileLayer: (tilelayer) => new L.TileLayer(tilelayer.url_template, tilelayer),
|
createTileLayer: (tilelayer) => new L.TileLayer(tilelayer.url_template, tilelayer),
|
||||||
|
@ -656,13 +708,13 @@ U.Map = L.Map.extend({
|
||||||
}
|
}
|
||||||
this.selected_tilelayer = tilelayer
|
this.selected_tilelayer = tilelayer
|
||||||
if (
|
if (
|
||||||
!isNaN(this.selected_tilelayer.options.minZoom) &&
|
!Number.isNaN(this.selected_tilelayer.options.minZoom) &&
|
||||||
this.getZoom() < this.selected_tilelayer.options.minZoom
|
this.getZoom() < this.selected_tilelayer.options.minZoom
|
||||||
) {
|
) {
|
||||||
this.setZoom(this.selected_tilelayer.options.minZoom)
|
this.setZoom(this.selected_tilelayer.options.minZoom)
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
!isNaN(this.selected_tilelayer.options.maxZoom) &&
|
!Number.isNaN(this.selected_tilelayer.options.maxZoom) &&
|
||||||
this.getZoom() > this.selected_tilelayer.options.maxZoom
|
this.getZoom() > this.selected_tilelayer.options.maxZoom
|
||||||
) {
|
) {
|
||||||
this.setZoom(this.selected_tilelayer.options.maxZoom)
|
this.setZoom(this.selected_tilelayer.options.maxZoom)
|
||||||
|
@ -683,21 +735,31 @@ U.Map = L.Map.extend({
|
||||||
// Prevent adding a duplicate background,
|
// Prevent adding a duplicate background,
|
||||||
// while adding selected/custom on top of the list
|
// while adding selected/custom on top of the list
|
||||||
const url = layer.options.url_template
|
const url = layer.options.url_template
|
||||||
if (urls.indexOf(url) !== -1) return
|
if (urls.indexOf(url) !== -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
callback.call(context, layer)
|
callback.call(context, layer)
|
||||||
urls.push(url)
|
urls.push(url)
|
||||||
}
|
}
|
||||||
if (this.selected_tilelayer) callOne(this.selected_tilelayer)
|
if (this.selected_tilelayer) {
|
||||||
if (this.customTilelayer) callOne(this.customTilelayer)
|
callOne(this.selected_tilelayer)
|
||||||
|
}
|
||||||
|
if (this.customTilelayer) {
|
||||||
|
callOne(this.customTilelayer)
|
||||||
|
}
|
||||||
this.tilelayers.forEach(callOne)
|
this.tilelayers.forEach(callOne)
|
||||||
},
|
},
|
||||||
|
|
||||||
setOverlay: function () {
|
setOverlay: function () {
|
||||||
if (!this.options.overlay || !this.options.overlay.url_template) return
|
if (!this.options.overlay || !this.options.overlay.url_template) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const overlay = this.createTileLayer(this.options.overlay)
|
const overlay = this.createTileLayer(this.options.overlay)
|
||||||
try {
|
try {
|
||||||
this.addLayer(overlay)
|
this.addLayer(overlay)
|
||||||
if (this.overlay) this.removeLayer(this.overlay)
|
if (this.overlay) {
|
||||||
|
this.removeLayer(this.overlay)
|
||||||
|
}
|
||||||
this.overlay = overlay
|
this.overlay = overlay
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.removeLayer(overlay)
|
this.removeLayer(overlay)
|
||||||
|
@ -713,19 +775,25 @@ U.Map = L.Map.extend({
|
||||||
|
|
||||||
hasData: function () {
|
hasData: function () {
|
||||||
for (const datalayer of this.datalayers_index) {
|
for (const datalayer of this.datalayers_index) {
|
||||||
if (datalayer.hasData()) return true
|
if (datalayer.hasData()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
fitDataBounds: function () {
|
fitDataBounds: function () {
|
||||||
const bounds = this.getLayersBounds()
|
const bounds = this.getLayersBounds()
|
||||||
if (!this.hasData() || !bounds.isValid()) return false
|
if (!this.hasData() || !bounds.isValid()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
this.fitBounds(bounds)
|
this.fitBounds(bounds)
|
||||||
},
|
},
|
||||||
|
|
||||||
initCenter: function () {
|
initCenter: function () {
|
||||||
this._setDefaultCenter()
|
this._setDefaultCenter()
|
||||||
if (this.options.hash) this.addHash()
|
if (this.options.hash) {
|
||||||
|
this.addHash()
|
||||||
|
}
|
||||||
if (this.options.hash && this._hash.parseHash(location.hash)) {
|
if (this.options.hash && this._hash.parseHash(location.hash)) {
|
||||||
// FIXME An invalid hash will cause the load to fail
|
// FIXME An invalid hash will cause the load to fail
|
||||||
this._hash.update()
|
this._hash.update()
|
||||||
|
@ -735,7 +803,9 @@ U.Map = L.Map.extend({
|
||||||
this.onceDataLoaded(this.fitDataBounds)
|
this.onceDataLoaded(this.fitDataBounds)
|
||||||
} else if (this.options.defaultView === 'latest') {
|
} else if (this.options.defaultView === 'latest') {
|
||||||
this.onceDataLoaded(() => {
|
this.onceDataLoaded(() => {
|
||||||
if (!this.hasData()) return
|
if (!this.hasData()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const datalayer = this.firstVisibleDatalayer()
|
const datalayer = this.firstVisibleDatalayer()
|
||||||
let feature
|
let feature
|
||||||
if (datalayer) {
|
if (datalayer) {
|
||||||
|
@ -759,11 +829,16 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
handleLimitBounds: function () {
|
handleLimitBounds: function () {
|
||||||
const south = Number.parseFloat(this.options.limitBounds.south),
|
const south = Number.parseFloat(this.options.limitBounds.south)
|
||||||
west = Number.parseFloat(this.options.limitBounds.west),
|
const west = Number.parseFloat(this.options.limitBounds.west)
|
||||||
north = Number.parseFloat(this.options.limitBounds.north),
|
const north = Number.parseFloat(this.options.limitBounds.north)
|
||||||
east = Number.parseFloat(this.options.limitBounds.east)
|
const east = Number.parseFloat(this.options.limitBounds.east)
|
||||||
if (!isNaN(south) && !isNaN(west) && !isNaN(north) && !isNaN(east)) {
|
if (
|
||||||
|
!Number.isNaN(south) &&
|
||||||
|
!Number.isNaN(west) &&
|
||||||
|
!Number.isNaN(north) &&
|
||||||
|
!Number.isNaN(east)
|
||||||
|
) {
|
||||||
const bounds = L.latLngBounds([
|
const bounds = L.latLngBounds([
|
||||||
[south, west],
|
[south, west],
|
||||||
[north, east],
|
[north, east],
|
||||||
|
@ -793,7 +868,7 @@ U.Map = L.Map.extend({
|
||||||
return L.Map.prototype.setMaxBounds.call(this, bounds)
|
return L.Map.prototype.setMaxBounds.call(this, bounds)
|
||||||
},
|
},
|
||||||
|
|
||||||
createDataLayer: function (options = {}, sync) {
|
createDataLayer: function (options, sync) {
|
||||||
options.name = options.name || `${L._('Layer')} ${this.datalayers_index.length + 1}`
|
options.name = options.name || `${L._('Layer')} ${this.datalayers_index.length + 1}`
|
||||||
const datalayer = new U.DataLayer(this, options, sync)
|
const datalayer = new U.DataLayer(this, options, sync)
|
||||||
|
|
||||||
|
@ -808,14 +883,18 @@ U.Map = L.Map.extend({
|
||||||
datalayer.edit()
|
datalayer.edit()
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultOption: (option) => U.SCHEMA[option] && U.SCHEMA[option].default,
|
getDefaultOption: (option) => U.SCHEMA[option]?.default,
|
||||||
|
|
||||||
getOption: function (option, feature) {
|
getOption: function (option, feature) {
|
||||||
if (feature) {
|
if (feature) {
|
||||||
const value = this.rules.getOption(option, feature)
|
const value = this.rules.getOption(option, feature)
|
||||||
if (value !== undefined) return value
|
if (value !== undefined) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (U.Utils.usableOption(this.options, option)) {
|
||||||
|
return this.options[option]
|
||||||
}
|
}
|
||||||
if (U.Utils.usableOption(this.options, option)) return this.options[option]
|
|
||||||
return this.getDefaultOption(option)
|
return this.getDefaultOption(option)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -836,11 +915,12 @@ U.Map = L.Map.extend({
|
||||||
this.options.tilelayer = tilelayer.toJSON()
|
this.options.tilelayer = tilelayer.toJSON()
|
||||||
this.isDirty = true
|
this.isDirty = true
|
||||||
}
|
}
|
||||||
if (this._controls.tilelayersChooser)
|
if (this._controls.tilelayersChooser) {
|
||||||
this._controls.tilelayersChooser.openSwitcher({
|
this._controls.tilelayersChooser.openSwitcher({
|
||||||
callback: callback,
|
callback: callback,
|
||||||
className: 'dark',
|
className: 'dark',
|
||||||
})
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
toGeoJSON: function () {
|
toGeoJSON: function () {
|
||||||
|
@ -859,7 +939,9 @@ U.Map = L.Map.extend({
|
||||||
|
|
||||||
eachFeature: function (callback, context) {
|
eachFeature: function (callback, context) {
|
||||||
this.eachDataLayer((datalayer) => {
|
this.eachDataLayer((datalayer) => {
|
||||||
if (datalayer.isVisible()) datalayer.eachFeature(callback, context)
|
if (datalayer.isVisible()) {
|
||||||
|
datalayer.eachFeature(callback, context)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -876,14 +958,16 @@ U.Map = L.Map.extend({
|
||||||
if (type === 'umap') {
|
if (type === 'umap') {
|
||||||
this.importFromFile(file, 'umap')
|
this.importFromFile(file, 'umap')
|
||||||
} else {
|
} else {
|
||||||
if (!layer) layer = this.createDataLayer({ name: file.name })
|
if (!layer) {
|
||||||
|
layer = this.createDataLayer({ name: file.name })
|
||||||
|
}
|
||||||
layer.importFromFile(file, type)
|
layer.importFromFile(file, type)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
importFromUrl: async function (uri) {
|
importFromUrl: async function (uri) {
|
||||||
const response = await this.request.get(uri)
|
const response = await this.request.get(uri)
|
||||||
if (response && response.ok) {
|
if (response?.ok) {
|
||||||
this.importRaw(await response.text())
|
this.importRaw(await response.text())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -896,15 +980,19 @@ U.Map = L.Map.extend({
|
||||||
for (const option of Object.keys(U.SCHEMA)) {
|
for (const option of Object.keys(U.SCHEMA)) {
|
||||||
if (typeof importedData.properties[option] !== 'undefined') {
|
if (typeof importedData.properties[option] !== 'undefined') {
|
||||||
this.options[option] = importedData.properties[option]
|
this.options[option] = importedData.properties[option]
|
||||||
if (option === 'sortKey') mustReindex = true
|
if (option === 'sortKey') {
|
||||||
|
mustReindex = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (importedData.geometry) this.options.center = this.latLng(importedData.geometry)
|
if (importedData.geometry) {
|
||||||
|
this.options.center = this.latLng(importedData.geometry)
|
||||||
|
}
|
||||||
importedData.layers.forEach((geojson) => {
|
importedData.layers.forEach((geojson) => {
|
||||||
if (!geojson._umap_options && geojson._storage) {
|
if (!geojson._umap_options && geojson._storage) {
|
||||||
geojson._umap_options = geojson._storage
|
geojson._umap_options = geojson._storage
|
||||||
delete geojson._storage
|
geojson._storage = undefined
|
||||||
}
|
}
|
||||||
delete geojson._umap_options?.id // Never trust an id at this stage
|
delete geojson._umap_options?.id // Never trust an id at this stage
|
||||||
const dataLayer = this.createDataLayer(geojson._umap_options)
|
const dataLayer = this.createDataLayer(geojson._umap_options)
|
||||||
|
@ -915,7 +1003,9 @@ U.Map = L.Map.extend({
|
||||||
this.renderControls()
|
this.renderControls()
|
||||||
this.handleLimitBounds()
|
this.handleLimitBounds()
|
||||||
this.eachDataLayer((datalayer) => {
|
this.eachDataLayer((datalayer) => {
|
||||||
if (mustReindex) datalayer.reindex()
|
if (mustReindex) {
|
||||||
|
datalayer.reindex()
|
||||||
|
}
|
||||||
datalayer.redraw()
|
datalayer.redraw()
|
||||||
})
|
})
|
||||||
this.fire('postsync')
|
this.fire('postsync')
|
||||||
|
@ -952,7 +1042,9 @@ U.Map = L.Map.extend({
|
||||||
|
|
||||||
eachDataLayerReverse: function (method, context, filter) {
|
eachDataLayerReverse: function (method, context, filter) {
|
||||||
for (let i = this.datalayers_index.length - 1; i >= 0; i--) {
|
for (let i = this.datalayers_index.length - 1; i >= 0; i--) {
|
||||||
if (filter && !filter.call(context, this.datalayers_index[i])) continue
|
if (filter && !filter.call(context, this.datalayers_index[i])) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
method.call(context, this.datalayers_index[i])
|
method.call(context, this.datalayers_index[i])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -967,9 +1059,10 @@ U.Map = L.Map.extend({
|
||||||
|
|
||||||
findDataLayer: function (method, context) {
|
findDataLayer: function (method, context) {
|
||||||
for (let i = this.datalayers_index.length - 1; i >= 0; i--) {
|
for (let i = this.datalayers_index.length - 1; i >= 0; i--) {
|
||||||
if (method.call(context, this.datalayers_index[i]))
|
if (method.call(context, this.datalayers_index[i])) {
|
||||||
return this.datalayers_index[i]
|
return this.datalayers_index[i]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
backup: function () {
|
backup: function () {
|
||||||
|
@ -978,11 +1071,15 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
reset: function () {
|
reset: function () {
|
||||||
if (this.editTools) this.editTools.stopDrawing()
|
if (this.editTools) {
|
||||||
|
this.editTools.stopDrawing()
|
||||||
|
}
|
||||||
this.resetOptions()
|
this.resetOptions()
|
||||||
this.datalayers_index = [].concat(this._datalayers_index_bk)
|
this.datalayers_index = [].concat(this._datalayers_index_bk)
|
||||||
this.dirty_datalayers.slice().forEach((datalayer) => {
|
this.dirty_datalayers.slice().forEach((datalayer) => {
|
||||||
if (datalayer.isDeleted) datalayer.connectToMap()
|
if (datalayer.isDeleted) {
|
||||||
|
datalayer.connectToMap()
|
||||||
|
}
|
||||||
datalayer.reset()
|
datalayer.reset()
|
||||||
})
|
})
|
||||||
this.ensurePanesOrder()
|
this.ensurePanesOrder()
|
||||||
|
@ -1011,8 +1108,11 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
continueSaving: function () {
|
continueSaving: function () {
|
||||||
if (this.dirty_datalayers.length) this.dirty_datalayers[0].save()
|
if (this.dirty_datalayers.length) {
|
||||||
else this.fire('saved')
|
this.dirty_datalayers[0].save()
|
||||||
|
} else {
|
||||||
|
this.fire('saved')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
exportOptions: function () {
|
exportOptions: function () {
|
||||||
|
@ -1085,8 +1185,12 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
save: function () {
|
save: function () {
|
||||||
if (!this.isDirty) return
|
if (!this.isDirty) {
|
||||||
if (this._default_extent) this._setCenterAndZoom()
|
return
|
||||||
|
}
|
||||||
|
if (this._default_extent) {
|
||||||
|
this._setCenterAndZoom()
|
||||||
|
}
|
||||||
this.backup()
|
this.backup()
|
||||||
this.once('saved', () => {
|
this.once('saved', () => {
|
||||||
this.isDirty = false
|
this.isDirty = false
|
||||||
|
@ -1126,7 +1230,9 @@ U.Map = L.Map.extend({
|
||||||
|
|
||||||
firstVisibleDatalayer: function () {
|
firstVisibleDatalayer: function () {
|
||||||
return this.findDataLayer((datalayer) => {
|
return this.findDataLayer((datalayer) => {
|
||||||
if (datalayer.isVisible()) return true
|
if (datalayer.isVisible()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1134,7 +1240,8 @@ U.Map = L.Map.extend({
|
||||||
// (edit and viewing)
|
// (edit and viewing)
|
||||||
// cf https://github.com/umap-project/umap/issues/585
|
// cf https://github.com/umap-project/umap/issues/585
|
||||||
defaultEditDataLayer: function () {
|
defaultEditDataLayer: function () {
|
||||||
let datalayer, fallback
|
let datalayer
|
||||||
|
let fallback
|
||||||
datalayer = this.lastUsedDataLayer
|
datalayer = this.lastUsedDataLayer
|
||||||
if (
|
if (
|
||||||
datalayer &&
|
datalayer &&
|
||||||
|
@ -1147,10 +1254,14 @@ U.Map = L.Map.extend({
|
||||||
datalayer = this.findDataLayer((datalayer) => {
|
datalayer = this.findDataLayer((datalayer) => {
|
||||||
if (!datalayer.isDataReadOnly() && datalayer.isBrowsable()) {
|
if (!datalayer.isDataReadOnly() && datalayer.isBrowsable()) {
|
||||||
fallback = datalayer
|
fallback = datalayer
|
||||||
if (datalayer.isVisible()) return true
|
if (datalayer.isVisible()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (datalayer) return datalayer
|
if (datalayer) {
|
||||||
|
return datalayer
|
||||||
|
}
|
||||||
if (fallback) {
|
if (fallback) {
|
||||||
// No datalayer visible, let's force one
|
// No datalayer visible, let's force one
|
||||||
fallback.show()
|
fallback.show()
|
||||||
|
@ -1160,7 +1271,7 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
getDataLayerByUmapId: function (umap_id) {
|
getDataLayerByUmapId: function (umap_id) {
|
||||||
return this.findDataLayer((d) => d.umap_id == umap_id)
|
return this.findDataLayer((d) => d.umap_id === umap_id)
|
||||||
},
|
},
|
||||||
|
|
||||||
_editControls: function (container) {
|
_editControls: function (container) {
|
||||||
|
@ -1340,7 +1451,6 @@ U.Map = L.Map.extend({
|
||||||
'options.overlay.url_template',
|
'options.overlay.url_template',
|
||||||
{
|
{
|
||||||
handler: 'BlurInput',
|
handler: 'BlurInput',
|
||||||
helpText: `${L._('Supported scheme')}: http://{s}.domain.com/{z}/{x}/{y}.png`,
|
|
||||||
placeholder: 'url',
|
placeholder: 'url',
|
||||||
helpText: L._('Background overlay url'),
|
helpText: L._('Background overlay url'),
|
||||||
type: 'url',
|
type: 'url',
|
||||||
|
@ -1522,8 +1632,12 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
editCaption: function () {
|
editCaption: function () {
|
||||||
if (!this.editEnabled) return
|
if (!this.editEnabled) {
|
||||||
if (this.options.editMode !== 'advanced') return
|
return
|
||||||
|
}
|
||||||
|
if (this.options.editMode !== 'advanced') {
|
||||||
|
return
|
||||||
|
}
|
||||||
const container = L.DomUtil.create('div', 'umap-edit-container')
|
const container = L.DomUtil.create('div', 'umap-edit-container')
|
||||||
const metadataFields = ['options.name', 'options.description']
|
const metadataFields = ['options.name', 'options.description']
|
||||||
|
|
||||||
|
@ -1548,8 +1662,12 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
edit: function () {
|
edit: function () {
|
||||||
if (!this.editEnabled) return
|
if (!this.editEnabled) {
|
||||||
if (this.options.editMode !== 'advanced') return
|
return
|
||||||
|
}
|
||||||
|
if (this.options.editMode !== 'advanced') {
|
||||||
|
return
|
||||||
|
}
|
||||||
const container = L.DomUtil.create('div')
|
const container = L.DomUtil.create('div')
|
||||||
L.DomUtil.createTitle(container, L._('Map advanced properties'), 'icon-settings')
|
L.DomUtil.createTitle(container, L._('Map advanced properties'), 'icon-settings')
|
||||||
this._editControls(container)
|
this._editControls(container)
|
||||||
|
@ -1578,7 +1696,9 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
disableEdit: function () {
|
disableEdit: function () {
|
||||||
if (this.isDirty) return
|
if (this.isDirty) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.drop.disable()
|
this.drop.disable()
|
||||||
L.DomUtil.removeClass(document.body, 'umap-edit-enabled')
|
L.DomUtil.removeClass(document.body, 'umap-edit-enabled')
|
||||||
this.editedFeature = null
|
this.editedFeature = null
|
||||||
|
@ -1602,8 +1722,8 @@ U.Map = L.Map.extend({
|
||||||
'div',
|
'div',
|
||||||
'umap-caption-bar',
|
'umap-caption-bar',
|
||||||
this._controlContainer
|
this._controlContainer
|
||||||
),
|
)
|
||||||
name = L.DomUtil.create('h3', '', container)
|
const name = L.DomUtil.create('h3', '', container)
|
||||||
L.DomEvent.disableClickPropagation(container)
|
L.DomEvent.disableClickPropagation(container)
|
||||||
this.permissions.addOwnerLink('span', container)
|
this.permissions.addOwnerLink('span', container)
|
||||||
if (this.getOption('captionMenus')) {
|
if (this.getOption('captionMenus')) {
|
||||||
|
@ -1640,7 +1760,9 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
askForReset: function (e) {
|
askForReset: function (e) {
|
||||||
if (!confirm(L._('Are you sure you want to cancel your changes?'))) return
|
if (!confirm(L._('Are you sure you want to cancel your changes?'))) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.reset()
|
this.reset()
|
||||||
this.disableEdit()
|
this.disableEdit()
|
||||||
},
|
},
|
||||||
|
@ -1661,7 +1783,9 @@ U.Map = L.Map.extend({
|
||||||
if (confirm(L._('Are you sure you want to delete this map?'))) {
|
if (confirm(L._('Are you sure you want to delete this map?'))) {
|
||||||
const url = this.urls.get('map_delete', { map_id: this.options.umap_id })
|
const url = this.urls.get('map_delete', { map_id: this.options.umap_id })
|
||||||
const [data, response, error] = await this.server.post(url)
|
const [data, response, error] = await this.server.post(url)
|
||||||
if (data.redirect) window.location = data.redirect
|
if (data.redirect) {
|
||||||
|
window.location = data.redirect
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1671,7 +1795,9 @@ U.Map = L.Map.extend({
|
||||||
) {
|
) {
|
||||||
const url = this.urls.get('map_clone', { map_id: this.options.umap_id })
|
const url = this.urls.get('map_clone', { map_id: this.options.umap_id })
|
||||||
const [data, response, error] = await this.server.post(url)
|
const [data, response, error] = await this.server.post(url)
|
||||||
if (data.redirect) window.location = data.redirect
|
if (data.redirect) {
|
||||||
|
window.location = data.redirect
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1715,7 +1841,7 @@ U.Map = L.Map.extend({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (e && e.relatedTarget) {
|
if (e?.relatedTarget) {
|
||||||
if (e.relatedTarget.getContextMenuItems) {
|
if (e.relatedTarget.getContextMenuItems) {
|
||||||
items = items.concat(e.relatedTarget.getContextMenuItems(e))
|
items = items.concat(e.relatedTarget.getContextMenuItems(e))
|
||||||
}
|
}
|
||||||
|
@ -1812,7 +1938,9 @@ U.Map = L.Map.extend({
|
||||||
lng: e.latlng.lng,
|
lng: e.latlng.lng,
|
||||||
zoom: Math.max(this.getZoom(), 16),
|
zoom: Math.max(this.getZoom(), 16),
|
||||||
})
|
})
|
||||||
if (url) window.open(url)
|
if (url) {
|
||||||
|
window.open(url)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
openExternalRouting: function (e) {
|
openExternalRouting: function (e) {
|
||||||
|
@ -1822,7 +1950,9 @@ U.Map = L.Map.extend({
|
||||||
locale: L.getLocale(),
|
locale: L.getLocale(),
|
||||||
zoom: this.getZoom(),
|
zoom: this.getZoom(),
|
||||||
})
|
})
|
||||||
if (url) window.open(url)
|
if (url) {
|
||||||
|
window.open(url)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getMap: function () {
|
getMap: function () {
|
||||||
|
@ -1863,17 +1993,23 @@ U.Map = L.Map.extend({
|
||||||
|
|
||||||
closeInplaceToolbar: function () {
|
closeInplaceToolbar: function () {
|
||||||
const toolbar = this._toolbars[L.Toolbar.Popup._toolbar_class_id]
|
const toolbar = this._toolbars[L.Toolbar.Popup._toolbar_class_id]
|
||||||
if (toolbar) toolbar.remove()
|
if (toolbar) {
|
||||||
|
toolbar.remove()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
search: function () {
|
search: function () {
|
||||||
if (this._controls.search) this._controls.search.open()
|
if (this._controls.search) {
|
||||||
|
this._controls.search.open()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getLayersBounds: function () {
|
getLayersBounds: function () {
|
||||||
const bounds = new L.latLngBounds()
|
const bounds = new L.latLngBounds()
|
||||||
this.eachBrowsableDataLayer((d) => {
|
this.eachBrowsableDataLayer((d) => {
|
||||||
if (d.isVisible()) bounds.extend(d.layer.getBounds())
|
if (d.isVisible()) {
|
||||||
|
bounds.extend(d.layer.getBounds())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
return bounds
|
return bounds
|
||||||
},
|
},
|
||||||
|
|
|
@ -67,7 +67,7 @@ U.Layer.Cluster = L.MarkerClusterGroup.extend({
|
||||||
},
|
},
|
||||||
iconCreateFunction: (cluster) => new U.Icon.Cluster(datalayer, cluster),
|
iconCreateFunction: (cluster) => new U.Icon.Cluster(datalayer, cluster),
|
||||||
}
|
}
|
||||||
if (this.datalayer.options.cluster && this.datalayer.options.cluster.radius) {
|
if (this.datalayer.options.cluster?.radius) {
|
||||||
options.maxClusterRadius = this.datalayer.options.cluster.radius
|
options.maxClusterRadius = this.datalayer.options.cluster.radius
|
||||||
}
|
}
|
||||||
L.MarkerClusterGroup.prototype.initialize.call(this, options)
|
L.MarkerClusterGroup.prototype.initialize.call(this, options)
|
||||||
|
@ -165,7 +165,9 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
|
||||||
|
|
||||||
redraw: function () {
|
redraw: function () {
|
||||||
this.computeBreaks()
|
this.computeBreaks()
|
||||||
if (this._map) this.eachLayer(this._map.addLayer, this._map)
|
if (this._map) {
|
||||||
|
this.eachLayer(this._map.addLayer, this._map)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_getValue: function (feature) {
|
_getValue: function (feature) {
|
||||||
|
@ -177,7 +179,9 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
|
||||||
const values = []
|
const values = []
|
||||||
this.datalayer.eachLayer((layer) => {
|
this.datalayer.eachLayer((layer) => {
|
||||||
const value = this._getValue(layer)
|
const value = this._getValue(layer)
|
||||||
if (!isNaN(value)) values.push(value)
|
if (!Number.isNaN(value)) {
|
||||||
|
values.push(value)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
return values
|
return values
|
||||||
},
|
},
|
||||||
|
@ -190,9 +194,9 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
|
||||||
this.options.colors = []
|
this.options.colors = []
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let mode = this.datalayer.options.choropleth.mode,
|
const mode = this.datalayer.options.choropleth.mode
|
||||||
classes = +this.datalayer.options.choropleth.classes || 5,
|
let classes = +this.datalayer.options.choropleth.classes || 5
|
||||||
breaks
|
let breaks
|
||||||
classes = Math.min(classes, values.length)
|
classes = Math.min(classes, values.length)
|
||||||
if (mode === 'manual') {
|
if (mode === 'manual') {
|
||||||
const manualBreaks = this.datalayer.options.choropleth.breaks
|
const manualBreaks = this.datalayer.options.choropleth.breaks
|
||||||
|
@ -200,7 +204,7 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
|
||||||
breaks = manualBreaks
|
breaks = manualBreaks
|
||||||
.split(',')
|
.split(',')
|
||||||
.map((b) => +b)
|
.map((b) => +b)
|
||||||
.filter((b) => !isNaN(b))
|
.filter((b) => !Number.isNaN(b))
|
||||||
}
|
}
|
||||||
} else if (mode === 'equidistant') {
|
} else if (mode === 'equidistant') {
|
||||||
breaks = ss.equalIntervalBreaks(values, classes)
|
breaks = ss.equalIntervalBreaks(values, classes)
|
||||||
|
@ -219,12 +223,16 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
|
||||||
.join(',')
|
.join(',')
|
||||||
const fillColor = this.datalayer.getOption('fillColor') || this.defaults.fillColor
|
const fillColor = this.datalayer.getOption('fillColor') || this.defaults.fillColor
|
||||||
let colorScheme = this.datalayer.options.choropleth.brewer
|
let colorScheme = this.datalayer.options.choropleth.brewer
|
||||||
if (!colorbrewer[colorScheme]) colorScheme = 'Blues'
|
if (!colorbrewer[colorScheme]) {
|
||||||
|
colorScheme = 'Blues'
|
||||||
|
}
|
||||||
this.options.colors = colorbrewer[colorScheme][this.options.breaks.length - 1] || []
|
this.options.colors = colorbrewer[colorScheme][this.options.breaks.length - 1] || []
|
||||||
},
|
},
|
||||||
|
|
||||||
getColor: function (feature) {
|
getColor: function (feature) {
|
||||||
if (!feature) return // FIXME shold not happen
|
if (!feature) {
|
||||||
|
return // FIXME shold not happen
|
||||||
|
}
|
||||||
const featureValue = this._getValue(feature)
|
const featureValue = this._getValue(feature)
|
||||||
// Find the bucket/step/limit that this value is less than and give it that color
|
// Find the bucket/step/limit that this value is less than and give it that color
|
||||||
for (let i = 1; i < this.options.breaks.length; i++) {
|
for (let i = 1; i < this.options.breaks.length; i++) {
|
||||||
|
@ -243,7 +251,7 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
|
||||||
addLayer: function (layer) {
|
addLayer: function (layer) {
|
||||||
// Do not add yet the layer to the map
|
// Do not add yet the layer to the map
|
||||||
// wait for datachanged event, so we want compute breaks once
|
// wait for datachanged event, so we want compute breaks once
|
||||||
var id = this.getLayerId(layer)
|
const id = this.getLayerId(layer)
|
||||||
this._layers[id] = layer
|
this._layers[id] = layer
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
|
@ -255,17 +263,23 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
|
||||||
|
|
||||||
onEdit: function (field, builder) {
|
onEdit: function (field, builder) {
|
||||||
// Only compute the breaks if we're dealing with choropleth
|
// Only compute the breaks if we're dealing with choropleth
|
||||||
if (!field.startsWith('options.choropleth')) return
|
if (!field.startsWith('options.choropleth')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
// If user touches the breaks, then force manual mode
|
// If user touches the breaks, then force manual mode
|
||||||
if (field === 'options.choropleth.breaks') {
|
if (field === 'options.choropleth.breaks') {
|
||||||
this.datalayer.options.choropleth.mode = 'manual'
|
this.datalayer.options.choropleth.mode = 'manual'
|
||||||
if (builder) builder.helpers['options.choropleth.mode'].fetch()
|
if (builder) {
|
||||||
|
builder.helpers['options.choropleth.mode'].fetch()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.computeBreaks()
|
this.computeBreaks()
|
||||||
// If user changes the mode or the number of classes,
|
// If user changes the mode or the number of classes,
|
||||||
// then update the breaks input value
|
// then update the breaks input value
|
||||||
if (field === 'options.choropleth.mode' || field === 'options.choropleth.classes') {
|
if (field === 'options.choropleth.mode' || field === 'options.choropleth.classes') {
|
||||||
if (builder) builder.helpers['options.choropleth.breaks'].fetch()
|
if (builder) {
|
||||||
|
builder.helpers['options.choropleth.breaks'].fetch()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -326,7 +340,9 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
|
||||||
|
|
||||||
renderLegend: function (container) {
|
renderLegend: function (container) {
|
||||||
const parent = L.DomUtil.create('ul', '', container)
|
const parent = L.DomUtil.create('ul', '', container)
|
||||||
let li, color, label
|
let li
|
||||||
|
let color
|
||||||
|
let label
|
||||||
|
|
||||||
this.options.breaks.slice(0, -1).forEach((limit, index) => {
|
this.options.breaks.slice(0, -1).forEach((limit, index) => {
|
||||||
li = L.DomUtil.create('li', '', parent)
|
li = L.DomUtil.create('li', '', parent)
|
||||||
|
@ -358,12 +374,9 @@ U.Layer.Heat = L.HeatLayer.extend({
|
||||||
|
|
||||||
addLayer: function (layer) {
|
addLayer: function (layer) {
|
||||||
if (layer instanceof L.Marker) {
|
if (layer instanceof L.Marker) {
|
||||||
let latlng = layer.getLatLng(),
|
let latlng = layer.getLatLng()
|
||||||
alt
|
let alt
|
||||||
if (
|
if (this.datalayer.options.heat?.intensityProperty) {
|
||||||
this.datalayer.options.heat &&
|
|
||||||
this.datalayer.options.heat.intensityProperty
|
|
||||||
) {
|
|
||||||
alt = Number.parseFloat(
|
alt = Number.parseFloat(
|
||||||
layer.properties[this.datalayer.options.heat.intensityProperty || 0]
|
layer.properties[this.datalayer.options.heat.intensityProperty || 0]
|
||||||
)
|
)
|
||||||
|
@ -420,7 +433,9 @@ U.Layer.Heat = L.HeatLayer.extend({
|
||||||
// setlalngs call _redraw through setAnimFrame, thus async, so this
|
// setlalngs call _redraw through setAnimFrame, thus async, so this
|
||||||
// can ends with race condition if we remove the layer very faslty after.
|
// can ends with race condition if we remove the layer very faslty after.
|
||||||
// TODO: PR in upstream Leaflet.heat
|
// TODO: PR in upstream Leaflet.heat
|
||||||
if (!this._map) return
|
if (!this._map) {
|
||||||
|
return
|
||||||
|
}
|
||||||
L.HeatLayer.prototype.redraw.call(this)
|
L.HeatLayer.prototype.redraw.call(this)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -430,23 +445,23 @@ U.Layer.Heat = L.HeatLayer.extend({
|
||||||
if (!this._map) {
|
if (!this._map) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var data = [],
|
const data = []
|
||||||
r = this._heat._r,
|
const r = this._heat._r
|
||||||
size = this._map.getSize(),
|
const size = this._map.getSize()
|
||||||
bounds = new L.Bounds(L.point([-r, -r]), size.add([r, r])),
|
const bounds = new L.Bounds(L.point([-r, -r]), size.add([r, r]))
|
||||||
cellSize = r / 2,
|
const cellSize = r / 2
|
||||||
grid = [],
|
const grid = []
|
||||||
panePos = this._map._getMapPanePos(),
|
const panePos = this._map._getMapPanePos()
|
||||||
offsetX = panePos.x % cellSize,
|
const offsetX = panePos.x % cellSize
|
||||||
offsetY = panePos.y % cellSize,
|
const offsetY = panePos.y % cellSize
|
||||||
i,
|
let i
|
||||||
len,
|
let len
|
||||||
p,
|
let p
|
||||||
cell,
|
let cell
|
||||||
x,
|
let x
|
||||||
y,
|
let y
|
||||||
j,
|
let j
|
||||||
len2
|
let len2
|
||||||
|
|
||||||
this._max = 1
|
this._max = 1
|
||||||
|
|
||||||
|
@ -455,7 +470,7 @@ U.Layer.Heat = L.HeatLayer.extend({
|
||||||
x = Math.floor((p.x - offsetX) / cellSize) + 2
|
x = Math.floor((p.x - offsetX) / cellSize) + 2
|
||||||
y = Math.floor((p.y - offsetY) / cellSize) + 2
|
y = Math.floor((p.y - offsetY) / cellSize) + 2
|
||||||
|
|
||||||
var alt =
|
const alt =
|
||||||
this._latlngs[i].alt !== undefined
|
this._latlngs[i].alt !== undefined
|
||||||
? this._latlngs[i].alt
|
? this._latlngs[i].alt
|
||||||
: this._latlngs[i][2] !== undefined
|
: this._latlngs[i][2] !== undefined
|
||||||
|
@ -532,13 +547,17 @@ U.DataLayer = L.Evented.extend({
|
||||||
Object.defineProperty(this, 'isDirty', {
|
Object.defineProperty(this, 'isDirty', {
|
||||||
get: () => isDirty,
|
get: () => isDirty,
|
||||||
set: (status) => {
|
set: (status) => {
|
||||||
if (!isDirty && status) this.fire('dirty')
|
if (!isDirty && status) {
|
||||||
|
this.fire('dirty')
|
||||||
|
}
|
||||||
isDirty = status
|
isDirty = status
|
||||||
if (status) {
|
if (status) {
|
||||||
this.map.addDirtyDatalayer(this)
|
this.map.addDirtyDatalayer(this)
|
||||||
// A layer can be made dirty by indirect action (like dragging layers)
|
// A layer can be made dirty by indirect action (like dragging layers)
|
||||||
// we need to have it loaded before saving it.
|
// we need to have it loaded before saving it.
|
||||||
if (!this.isLoaded()) this.fetchData()
|
if (!this.isLoaded()) {
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.map.removeDirtyDatalayer(this)
|
this.map.removeDirtyDatalayer(this)
|
||||||
this.isDeleted = false
|
this.isDeleted = false
|
||||||
|
@ -552,9 +571,13 @@ U.DataLayer = L.Evented.extend({
|
||||||
Object.defineProperty(this, 'isDeleted', {
|
Object.defineProperty(this, 'isDeleted', {
|
||||||
get: () => isDeleted,
|
get: () => isDeleted,
|
||||||
set: (status) => {
|
set: (status) => {
|
||||||
if (!isDeleted && status) this.fire('deleted')
|
if (!isDeleted && status) {
|
||||||
|
this.fire('deleted')
|
||||||
|
}
|
||||||
isDeleted = status
|
isDeleted = status
|
||||||
if (status) this.isDirty = status
|
if (status) {
|
||||||
|
this.isDirty = status
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -567,19 +590,21 @@ U.DataLayer = L.Evented.extend({
|
||||||
this.options.remoteData = {}
|
this.options.remoteData = {}
|
||||||
}
|
}
|
||||||
// Retrocompat
|
// Retrocompat
|
||||||
if (this.options.remoteData && this.options.remoteData.from) {
|
if (this.options.remoteData?.from) {
|
||||||
this.options.fromZoom = this.options.remoteData.from
|
this.options.fromZoom = this.options.remoteData.from
|
||||||
delete this.options.remoteData.from
|
this.options.remoteData.from = undefined
|
||||||
}
|
}
|
||||||
if (this.options.remoteData && this.options.remoteData.to) {
|
if (this.options.remoteData?.to) {
|
||||||
this.options.toZoom = this.options.remoteData.to
|
this.options.toZoom = this.options.remoteData.to
|
||||||
delete this.options.remoteData.to
|
this.options.remoteData.to = undefined
|
||||||
}
|
}
|
||||||
this.backupOptions()
|
this.backupOptions()
|
||||||
this.connectToMap()
|
this.connectToMap()
|
||||||
this.permissions = new U.DataLayerPermissions(this)
|
this.permissions = new U.DataLayerPermissions(this)
|
||||||
if (!this.umap_id) {
|
if (!this.umap_id) {
|
||||||
if (this.showAtLoad()) this.show()
|
if (this.showAtLoad()) {
|
||||||
|
this.show()
|
||||||
|
}
|
||||||
this.isDirty = true
|
this.isDirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,7 +614,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
// Only layers that are displayed on load must be hidden/shown
|
// Only layers that are displayed on load must be hidden/shown
|
||||||
// Automatically, others will be shown manually, and thus will
|
// Automatically, others will be shown manually, and thus will
|
||||||
// be in the "forced visibility" mode
|
// be in the "forced visibility" mode
|
||||||
if (this.autoLoaded()) this.map.on('zoomend', this.onZoomEnd, this)
|
if (this.autoLoaded()) {
|
||||||
|
this.map.on('zoomend', this.onZoomEnd, this)
|
||||||
|
}
|
||||||
this.on('datachanged', this.map.onDataLayersChanged, this.map)
|
this.on('datachanged', this.map.onDataLayersChanged, this.map)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -629,13 +656,21 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
onMoveEnd: function (e) {
|
onMoveEnd: function (e) {
|
||||||
if (this.isRemoteLayer() && this.showAtZoom()) this.fetchRemoteData()
|
if (this.isRemoteLayer() && this.showAtZoom()) {
|
||||||
|
this.fetchRemoteData()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onZoomEnd: function (e) {
|
onZoomEnd: function (e) {
|
||||||
if (this._forcedVisibility) return
|
if (this._forcedVisibility) {
|
||||||
if (!this.showAtZoom() && this.isVisible()) this.hide()
|
return
|
||||||
if (this.showAtZoom() && !this.isVisible()) this.show()
|
}
|
||||||
|
if (!this.showAtZoom() && this.isVisible()) {
|
||||||
|
this.hide()
|
||||||
|
}
|
||||||
|
if (this.showAtZoom() && !this.isVisible()) {
|
||||||
|
this.show()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
showAtLoad: function () {
|
showAtLoad: function () {
|
||||||
|
@ -643,7 +678,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
autoLoaded: function () {
|
autoLoaded: function () {
|
||||||
if (!this.map.datalayersFromQueryString) return this.options.displayOnLoad
|
if (!this.map.datalayersFromQueryString) {
|
||||||
|
return this.options.displayOnLoad
|
||||||
|
}
|
||||||
const datalayerIds = this.map.datalayersFromQueryString
|
const datalayerIds = this.map.datalayersFromQueryString
|
||||||
let loadMe = datalayerIds.includes(this.umap_id.toString())
|
let loadMe = datalayerIds.includes(this.umap_id.toString())
|
||||||
if (this.options.old_id) {
|
if (this.options.old_id) {
|
||||||
|
@ -653,12 +690,16 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
insertBefore: function (other) {
|
insertBefore: function (other) {
|
||||||
if (!other) return
|
if (!other) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.parentPane.insertBefore(this.pane, other.pane)
|
this.parentPane.insertBefore(this.pane, other.pane)
|
||||||
},
|
},
|
||||||
|
|
||||||
insertAfter: function (other) {
|
insertAfter: function (other) {
|
||||||
if (!other) return
|
if (!other) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.parentPane.insertBefore(this.pane, other.pane.nextSibling)
|
this.parentPane.insertBefore(this.pane, other.pane.nextSibling)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -680,13 +721,19 @@ U.DataLayer = L.Evented.extend({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const visible = this.isVisible()
|
const visible = this.isVisible()
|
||||||
if (this.layer) this.layer.clearLayers()
|
if (this.layer) {
|
||||||
|
this.layer.clearLayers()
|
||||||
|
}
|
||||||
// delete this.layer?
|
// delete this.layer?
|
||||||
if (visible) this.map.removeLayer(this.layer)
|
if (visible) {
|
||||||
|
this.map.removeLayer(this.layer)
|
||||||
|
}
|
||||||
const Class = U.Layer[this.options.type] || U.Layer.Default
|
const Class = U.Layer[this.options.type] || U.Layer.Default
|
||||||
this.layer = new Class(this)
|
this.layer = new Class(this)
|
||||||
this.eachLayer(this.showFeature)
|
this.eachLayer(this.showFeature)
|
||||||
if (visible) this.show()
|
if (visible) {
|
||||||
|
this.show()
|
||||||
|
}
|
||||||
this.propagateRemote()
|
this.propagateRemote()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -707,8 +754,12 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchData: async function () {
|
fetchData: async function () {
|
||||||
if (!this.umap_id) return
|
if (!this.umap_id) {
|
||||||
if (this._loading) return
|
return
|
||||||
|
}
|
||||||
|
if (this._loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this._loading = true
|
this._loading = true
|
||||||
const [geojson, response, error] = await this.map.server.get(this._dataUrl())
|
const [geojson, response, error] = await this.map.server.get(this._dataUrl())
|
||||||
if (!error) {
|
if (!error) {
|
||||||
|
@ -722,7 +773,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
geojson._umap_options.editMode = this.options.editMode
|
geojson._umap_options.editMode = this.options.editMode
|
||||||
}
|
}
|
||||||
// In case of maps pre 1.0 still around
|
// In case of maps pre 1.0 still around
|
||||||
if (geojson._storage) geojson._storage.editMode = this.options.editMode
|
if (geojson._storage) {
|
||||||
|
geojson._storage.editMode = this.options.editMode
|
||||||
|
}
|
||||||
await this.fromUmapGeoJSON(geojson)
|
await this.fromUmapGeoJSON(geojson)
|
||||||
this.backupOptions()
|
this.backupOptions()
|
||||||
this.fire('loaded')
|
this.fire('loaded')
|
||||||
|
@ -739,10 +792,17 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
fromUmapGeoJSON: async function (geojson) {
|
fromUmapGeoJSON: async function (geojson) {
|
||||||
if (geojson._storage) geojson._umap_options = geojson._storage // Retrocompat
|
if (geojson._storage) {
|
||||||
if (geojson._umap_options) this.setOptions(geojson._umap_options)
|
geojson._umap_options = geojson._storage // Retrocompat
|
||||||
if (this.isRemoteLayer()) await this.fetchRemoteData()
|
}
|
||||||
else this.fromGeoJSON(geojson)
|
if (geojson._umap_options) {
|
||||||
|
this.setOptions(geojson._umap_options)
|
||||||
|
}
|
||||||
|
if (this.isRemoteLayer()) {
|
||||||
|
await this.fetchRemoteData()
|
||||||
|
} else {
|
||||||
|
this.fromGeoJSON(geojson)
|
||||||
|
}
|
||||||
this._loaded = true
|
this._loaded = true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -772,26 +832,32 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
showAtZoom: function () {
|
showAtZoom: function () {
|
||||||
const from = Number.parseInt(this.options.fromZoom, 10),
|
const from = Number.parseInt(this.options.fromZoom, 10)
|
||||||
to = Number.parseInt(this.options.toZoom, 10),
|
const to = Number.parseInt(this.options.toZoom, 10)
|
||||||
zoom = this.map.getZoom()
|
const zoom = this.map.getZoom()
|
||||||
return !((!isNaN(from) && zoom < from) || (!isNaN(to) && zoom > to))
|
return !((!Number.isNaN(from) && zoom < from) || (!Number.isNaN(to) && zoom > to))
|
||||||
},
|
},
|
||||||
|
|
||||||
hasDynamicData: function () {
|
hasDynamicData: function () {
|
||||||
return !!(this.options.remoteData && this.options.remoteData.dynamic)
|
return !!this.options.remoteData?.dynamic
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchRemoteData: async function (force) {
|
fetchRemoteData: async function (force) {
|
||||||
if (!this.isRemoteLayer()) return
|
if (!this.isRemoteLayer()) {
|
||||||
if (!this.hasDynamicData() && this.hasDataLoaded() && !force) return
|
return
|
||||||
if (!this.isVisible()) return
|
}
|
||||||
|
if (!this.hasDynamicData() && this.hasDataLoaded() && !force) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.isVisible()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
let url = this.map.localizeUrl(this.options.remoteData.url)
|
let url = this.map.localizeUrl(this.options.remoteData.url)
|
||||||
if (this.options.remoteData.proxy) {
|
if (this.options.remoteData.proxy) {
|
||||||
url = this.map.proxyUrl(url, this.options.remoteData.ttl)
|
url = this.map.proxyUrl(url, this.options.remoteData.ttl)
|
||||||
}
|
}
|
||||||
const response = await this.map.request.get(url)
|
const response = await this.map.request.get(url)
|
||||||
if (response && response.ok) {
|
if (response?.ok) {
|
||||||
this.clear()
|
this.clear()
|
||||||
this.rawToGeoJSON(
|
this.rawToGeoJSON(
|
||||||
await response.text(),
|
await response.text(),
|
||||||
|
@ -802,14 +868,20 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
onceLoaded: function (callback, context) {
|
onceLoaded: function (callback, context) {
|
||||||
if (this.isLoaded()) callback.call(context || this, this)
|
if (this.isLoaded()) {
|
||||||
else this.once('loaded', callback, context)
|
callback.call(context || this, this)
|
||||||
|
} else {
|
||||||
|
this.once('loaded', callback, context)
|
||||||
|
}
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
|
|
||||||
onceDataLoaded: function (callback, context) {
|
onceDataLoaded: function (callback, context) {
|
||||||
if (this.hasDataLoaded()) callback.call(context || this, this)
|
if (this.hasDataLoaded()) {
|
||||||
else this.once('dataloaded', callback, context)
|
callback.call(context || this, this)
|
||||||
|
} else {
|
||||||
|
this.once('dataloaded', callback, context)
|
||||||
|
}
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -823,7 +895,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
|
|
||||||
setUmapId: function (id) {
|
setUmapId: function (id) {
|
||||||
// Datalayer is null when listening creation form
|
// Datalayer is null when listening creation form
|
||||||
if (!this.umap_id && id) this.umap_id = id
|
if (!this.umap_id && id) {
|
||||||
|
this.umap_id = id
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
backupOptions: function () {
|
backupOptions: function () {
|
||||||
|
@ -835,7 +909,7 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
setOptions: function (options) {
|
setOptions: function (options) {
|
||||||
delete options.geojson
|
options.geojson = undefined
|
||||||
this.options = U.Utils.CopyJSON(U.DataLayer.prototype.options) // Start from fresh.
|
this.options = U.Utils.CopyJSON(U.DataLayer.prototype.options) // Start from fresh.
|
||||||
this.updateOptions(options)
|
this.updateOptions(options)
|
||||||
},
|
},
|
||||||
|
@ -849,8 +923,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
const id = L.stamp(this)
|
const id = L.stamp(this)
|
||||||
if (!this.map.datalayers[id]) {
|
if (!this.map.datalayers[id]) {
|
||||||
this.map.datalayers[id] = this
|
this.map.datalayers[id] = this
|
||||||
if (L.Util.indexOf(this.map.datalayers_index, this) === -1)
|
if (L.Util.indexOf(this.map.datalayers_index, this) === -1) {
|
||||||
this.map.datalayers_index.push(this)
|
this.map.datalayers_index.push(this)
|
||||||
|
}
|
||||||
this.map.onDataLayersChanged()
|
this.map.onDataLayersChanged()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -864,16 +939,14 @@ U.DataLayer = L.Evented.extend({
|
||||||
})
|
})
|
||||||
|
|
||||||
// No browser cache for owners/editors.
|
// No browser cache for owners/editors.
|
||||||
if (this.map.hasEditMode()) url = `${url}?${Date.now()}`
|
if (this.map.hasEditMode()) {
|
||||||
|
url = `${url}?${Date.now()}`
|
||||||
|
}
|
||||||
return url
|
return url
|
||||||
},
|
},
|
||||||
|
|
||||||
isRemoteLayer: function () {
|
isRemoteLayer: function () {
|
||||||
return Boolean(
|
return Boolean(this.options.remoteData?.url && this.options.remoteData.format)
|
||||||
this.options.remoteData &&
|
|
||||||
this.options.remoteData.url &&
|
|
||||||
this.options.remoteData.format
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
isClustered: function () {
|
isClustered: function () {
|
||||||
|
@ -881,7 +954,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
showFeature: function (feature) {
|
showFeature: function (feature) {
|
||||||
if (feature.isFiltered()) return
|
if (feature.isFiltered()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.layer.addLayer(feature)
|
this.layer.addLayer(feature)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -893,7 +968,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
this.indexProperties(feature)
|
this.indexProperties(feature)
|
||||||
this.map.features_index[feature.getSlug()] = feature
|
this.map.features_index[feature.getSlug()] = feature
|
||||||
this.showFeature(feature)
|
this.showFeature(feature)
|
||||||
if (this.hasDataLoaded()) this.fire('datachanged')
|
if (this.hasDataLoaded()) {
|
||||||
|
this.fire('datachanged')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
removeLayer: function (feature) {
|
removeLayer: function (feature) {
|
||||||
|
@ -903,24 +980,37 @@ U.DataLayer = L.Evented.extend({
|
||||||
this._index.splice(this._index.indexOf(id), 1)
|
this._index.splice(this._index.indexOf(id), 1)
|
||||||
delete this._layers[id]
|
delete this._layers[id]
|
||||||
delete this.map.features_index[feature.getSlug()]
|
delete this.map.features_index[feature.getSlug()]
|
||||||
if (this.hasDataLoaded()) this.fire('datachanged')
|
if (this.hasDataLoaded()) {
|
||||||
|
this.fire('datachanged')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
indexProperties: function (feature) {
|
indexProperties: function (feature) {
|
||||||
for (const i in feature.properties)
|
for (const i in feature.properties) {
|
||||||
if (typeof feature.properties[i] !== 'object') this.indexProperty(i)
|
if (typeof feature.properties[i] !== 'object') {
|
||||||
|
this.indexProperty(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
indexProperty: function (name) {
|
indexProperty: function (name) {
|
||||||
if (!name) return
|
if (!name) {
|
||||||
if (name.indexOf('_') === 0) return
|
return
|
||||||
if (L.Util.indexOf(this._propertiesIndex, name) !== -1) return
|
}
|
||||||
|
if (name.indexOf('_') === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (L.Util.indexOf(this._propertiesIndex, name) !== -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this._propertiesIndex.push(name)
|
this._propertiesIndex.push(name)
|
||||||
},
|
},
|
||||||
|
|
||||||
deindexProperty: function (name) {
|
deindexProperty: function (name) {
|
||||||
const idx = this._propertiesIndex.indexOf(name)
|
const idx = this._propertiesIndex.indexOf(name)
|
||||||
if (idx !== -1) this._propertiesIndex.splice(idx, 1)
|
if (idx !== -1) {
|
||||||
|
this._propertiesIndex.splice(idx, 1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addData: function (geojson) {
|
addData: function (geojson) {
|
||||||
|
@ -960,7 +1050,7 @@ U.DataLayer = L.Evented.extend({
|
||||||
// csv2geojson fallback to null geometries when it cannot determine
|
// csv2geojson fallback to null geometries when it cannot determine
|
||||||
// lat or lon columns. This is valid geojson, but unwanted from a user
|
// lat or lon columns. This is valid geojson, but unwanted from a user
|
||||||
// point of view.
|
// point of view.
|
||||||
if (result && result.features.length) {
|
if (result?.features.length) {
|
||||||
if (result.features[0].geometry === null) {
|
if (result.features[0].geometry === null) {
|
||||||
err = {
|
err = {
|
||||||
type: 'Error',
|
type: 'Error',
|
||||||
|
@ -981,7 +1071,7 @@ U.DataLayer = L.Evented.extend({
|
||||||
U.Alert.error(message, 10000)
|
U.Alert.error(message, 10000)
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
if (result && result.features.length) {
|
if (result?.features.length) {
|
||||||
callback(result)
|
callback(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1015,8 +1105,10 @@ U.DataLayer = L.Evented.extend({
|
||||||
// It is misleading, as the returned objects are uMap objects, and not
|
// It is misleading, as the returned objects are uMap objects, and not
|
||||||
// GeoJSON features.
|
// GeoJSON features.
|
||||||
geojsonToFeatures: function (geojson) {
|
geojsonToFeatures: function (geojson) {
|
||||||
if (!geojson) return
|
if (!geojson) {
|
||||||
const features = geojson instanceof Array ? geojson : geojson.features
|
return
|
||||||
|
}
|
||||||
|
const features = Array.isArray(geojson) ? geojson : geojson.features
|
||||||
let i
|
let i
|
||||||
let len
|
let len
|
||||||
|
|
||||||
|
@ -1060,12 +1152,17 @@ U.DataLayer = L.Evented.extend({
|
||||||
id = null,
|
id = null,
|
||||||
feature = null,
|
feature = null,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
if (!geometry) return // null geometry is valid geojson.
|
if (!geometry) {
|
||||||
|
return // null geometry is valid geojson.
|
||||||
|
}
|
||||||
const coords = geometry.coordinates
|
const coords = geometry.coordinates
|
||||||
let latlng, latlngs
|
let latlng
|
||||||
|
let latlngs
|
||||||
|
|
||||||
// Create a default geojson if none is provided
|
// Create a default geojson if none is provided
|
||||||
if (geojson === undefined) geojson = { type: 'Feature', geometry: geometry }
|
if (geojson === undefined) {
|
||||||
|
geojson = { type: 'Feature', geometry: geometry }
|
||||||
|
}
|
||||||
|
|
||||||
switch (geometry.type) {
|
switch (geometry.type) {
|
||||||
case 'Point':
|
case 'Point':
|
||||||
|
@ -1087,7 +1184,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
coords,
|
coords,
|
||||||
geometry.type === 'LineString' ? 0 : 1
|
geometry.type === 'LineString' ? 0 : 1
|
||||||
)
|
)
|
||||||
if (!latlngs.length) break
|
if (!latlngs.length) {
|
||||||
|
break
|
||||||
|
}
|
||||||
if (feature) {
|
if (feature) {
|
||||||
feature.setLatLngs(latlngs)
|
feature.setLatLngs(latlngs)
|
||||||
return feature
|
return feature
|
||||||
|
@ -1161,7 +1260,7 @@ U.DataLayer = L.Evented.extend({
|
||||||
importFromUrl: async function (uri, type) {
|
importFromUrl: async function (uri, type) {
|
||||||
uri = this.map.localizeUrl(uri)
|
uri = this.map.localizeUrl(uri)
|
||||||
const response = await this.map.request.get(uri)
|
const response = await this.map.request.get(uri)
|
||||||
if (response && response.ok) {
|
if (response?.ok) {
|
||||||
this.importRaw(await response.text(), type)
|
this.importRaw(await response.text(), type)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1198,7 +1297,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
empty: function () {
|
empty: function () {
|
||||||
if (this.isRemoteLayer()) return
|
if (this.isRemoteLayer()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.clear()
|
this.clear()
|
||||||
this.isDirty = true
|
this.isDirty = true
|
||||||
},
|
},
|
||||||
|
@ -1206,9 +1307,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
clone: function () {
|
clone: function () {
|
||||||
const options = U.Utils.CopyJSON(this.options)
|
const options = U.Utils.CopyJSON(this.options)
|
||||||
options.name = L._('Clone of {name}', { name: this.options.name })
|
options.name = L._('Clone of {name}', { name: this.options.name })
|
||||||
delete options.id
|
options.id = undefined
|
||||||
const geojson = U.Utils.CopyJSON(this._geojson),
|
const geojson = U.Utils.CopyJSON(this._geojson)
|
||||||
datalayer = this.map.createDataLayer(options)
|
const datalayer = this.map.createDataLayer(options)
|
||||||
datalayer.fromGeoJSON(geojson)
|
datalayer.fromGeoJSON(geojson)
|
||||||
return datalayer
|
return datalayer
|
||||||
},
|
},
|
||||||
|
@ -1226,12 +1327,14 @@ U.DataLayer = L.Evented.extend({
|
||||||
this.map.off('zoomend', this.onZoomEnd, this)
|
this.map.off('zoomend', this.onZoomEnd, this)
|
||||||
this.off()
|
this.off()
|
||||||
this.clear()
|
this.clear()
|
||||||
delete this._loaded
|
this._loaded = undefined
|
||||||
delete this._dataloaded
|
this._dataloaded = undefined
|
||||||
},
|
},
|
||||||
|
|
||||||
reset: function () {
|
reset: function () {
|
||||||
if (!this.umap_id) this.erase()
|
if (!this.umap_id) {
|
||||||
|
this.erase()
|
||||||
|
}
|
||||||
|
|
||||||
this.resetOptions()
|
this.resetOptions()
|
||||||
this.parentPane.appendChild(this.pane)
|
this.parentPane.appendChild(this.pane)
|
||||||
|
@ -1240,15 +1343,20 @@ U.DataLayer = L.Evented.extend({
|
||||||
}
|
}
|
||||||
this.clear()
|
this.clear()
|
||||||
this.hide()
|
this.hide()
|
||||||
if (this.isRemoteLayer()) this.fetchRemoteData()
|
if (this.isRemoteLayer()) {
|
||||||
else if (this._geojson_bk) this.fromGeoJSON(this._geojson_bk)
|
this.fetchRemoteData()
|
||||||
|
} else if (this._geojson_bk) {
|
||||||
|
this.fromGeoJSON(this._geojson_bk)
|
||||||
|
}
|
||||||
this._loaded = true
|
this._loaded = true
|
||||||
this.show()
|
this.show()
|
||||||
this.isDirty = false
|
this.isDirty = false
|
||||||
},
|
},
|
||||||
|
|
||||||
redraw: function () {
|
redraw: function () {
|
||||||
if (!this.isVisible()) return
|
if (!this.isVisible()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.hide()
|
this.hide()
|
||||||
this.show()
|
this.show()
|
||||||
},
|
},
|
||||||
|
@ -1257,8 +1365,8 @@ U.DataLayer = L.Evented.extend({
|
||||||
if (!this.map.editEnabled || !this.isLoaded()) {
|
if (!this.map.editEnabled || !this.isLoaded()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const container = L.DomUtil.create('div', 'umap-layer-properties-container'),
|
const container = L.DomUtil.create('div', 'umap-layer-properties-container')
|
||||||
metadataFields = [
|
const metadataFields = [
|
||||||
'options.name',
|
'options.name',
|
||||||
'options.description',
|
'options.description',
|
||||||
['options.type', { handler: 'LayerTypeChooser', label: L._('Type of layer') }],
|
['options.type', { handler: 'LayerTypeChooser', label: L._('Type of layer') }],
|
||||||
|
@ -1406,7 +1514,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
|
|
||||||
if (this.map.options.urls.datalayer_versions) this.buildVersionsFieldset(container)
|
if (this.map.options.urls.datalayer_versions) {
|
||||||
|
this.buildVersionsFieldset(container)
|
||||||
|
}
|
||||||
|
|
||||||
const advancedActions = L.DomUtil.createFieldset(container, L._('Advanced actions'))
|
const advancedActions = L.DomUtil.createFieldset(container, L._('Advanced actions'))
|
||||||
const advancedButtons = L.DomUtil.create('div', 'button-bar half', advancedActions)
|
const advancedButtons = L.DomUtil.create('div', 'button-bar half', advancedActions)
|
||||||
|
@ -1465,21 +1575,25 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
getOwnOption: function (option) {
|
getOwnOption: function (option) {
|
||||||
if (U.Utils.usableOption(this.options, option)) return this.options[option]
|
if (U.Utils.usableOption(this.options, option)) {
|
||||||
|
return this.options[option]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getOption: function (option, feature) {
|
getOption: function (option, feature) {
|
||||||
if (this.layer && this.layer.getOption) {
|
if (this.layer?.getOption) {
|
||||||
const value = this.layer.getOption(option, feature)
|
const value = this.layer.getOption(option, feature)
|
||||||
if (typeof value !== 'undefined') return value
|
if (typeof value !== 'undefined') {
|
||||||
|
return value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (typeof this.getOwnOption(option) !== 'undefined') {
|
if (typeof this.getOwnOption(option) !== 'undefined') {
|
||||||
return this.getOwnOption(option)
|
return this.getOwnOption(option)
|
||||||
} else if (this.layer && this.layer.defaults && this.layer.defaults[option]) {
|
|
||||||
return this.layer.defaults[option]
|
|
||||||
} else {
|
|
||||||
return this.map.getOption(option, feature)
|
|
||||||
}
|
}
|
||||||
|
if (this.layer?.defaults?.[option]) {
|
||||||
|
return this.layer.defaults[option]
|
||||||
|
}
|
||||||
|
return this.map.getOption(option, feature)
|
||||||
},
|
},
|
||||||
|
|
||||||
buildVersionsFieldset: async function (container) {
|
buildVersionsFieldset: async function (container) {
|
||||||
|
@ -1503,24 +1617,37 @@ U.DataLayer = L.Evented.extend({
|
||||||
const [{ versions }, response, error] = await this.map.server.get(
|
const [{ versions }, response, error] = await this.map.server.get(
|
||||||
this.getVersionsUrl()
|
this.getVersionsUrl()
|
||||||
)
|
)
|
||||||
if (!error) versions.forEach(appendVersion)
|
if (!error) {
|
||||||
|
versions.forEach(appendVersion)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
context: this,
|
context: this,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
restore: async function (version) {
|
restore: async function (version) {
|
||||||
if (!this.map.editEnabled) return
|
if (!this.map.editEnabled) {
|
||||||
if (!confirm(L._('Are you sure you want to restore this version?'))) return
|
return
|
||||||
|
}
|
||||||
|
if (!confirm(L._('Are you sure you want to restore this version?'))) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const [geojson, response, error] = await this.map.server.get(
|
const [geojson, response, error] = await this.map.server.get(
|
||||||
this.getVersionUrl(version)
|
this.getVersionUrl(version)
|
||||||
)
|
)
|
||||||
if (!error) {
|
if (!error) {
|
||||||
if (geojson._storage) geojson._umap_options = geojson._storage // Retrocompat.
|
if (geojson._storage) {
|
||||||
if (geojson._umap_options) this.setOptions(geojson._umap_options)
|
geojson._umap_options = geojson._storage // Retrocompat.
|
||||||
|
}
|
||||||
|
if (geojson._umap_options) {
|
||||||
|
this.setOptions(geojson._umap_options)
|
||||||
|
}
|
||||||
this.empty()
|
this.empty()
|
||||||
if (this.isRemoteLayer()) this.fetchRemoteData()
|
if (this.isRemoteLayer()) {
|
||||||
else this.addData(geojson)
|
this.fetchRemoteData()
|
||||||
|
} else {
|
||||||
|
this.addData(geojson)
|
||||||
|
}
|
||||||
this.isDirty = true
|
this.isDirty = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1533,7 +1660,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
|
|
||||||
show: async function () {
|
show: async function () {
|
||||||
this.map.addLayer(this.layer)
|
this.map.addLayer(this.layer)
|
||||||
if (!this.isLoaded()) await this.fetchData()
|
if (!this.isLoaded()) {
|
||||||
|
await this.fetchData()
|
||||||
|
}
|
||||||
this.fire('show')
|
this.fire('show')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1546,12 +1675,17 @@ U.DataLayer = L.Evented.extend({
|
||||||
// From now on, do not try to how/hide
|
// From now on, do not try to how/hide
|
||||||
// automatically this layer.
|
// automatically this layer.
|
||||||
this._forcedVisibility = true
|
this._forcedVisibility = true
|
||||||
if (!this.isVisible()) this.show()
|
if (!this.isVisible()) {
|
||||||
else this.hide()
|
this.show()
|
||||||
|
} else {
|
||||||
|
this.hide()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
zoomTo: function () {
|
zoomTo: function () {
|
||||||
if (!this.isVisible()) return
|
if (!this.isVisible()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const bounds = this.layer.getBounds()
|
const bounds = this.layer.getBounds()
|
||||||
if (bounds.isValid()) {
|
if (bounds.isValid()) {
|
||||||
const options = { maxZoom: this.getOption('zoomTo') }
|
const options = { maxZoom: this.getOption('zoomTo') }
|
||||||
|
@ -1561,7 +1695,7 @@ U.DataLayer = L.Evented.extend({
|
||||||
|
|
||||||
// Is this layer type browsable in theorie
|
// Is this layer type browsable in theorie
|
||||||
isBrowsable: function () {
|
isBrowsable: function () {
|
||||||
return this.layer && this.layer.browsable
|
return this.layer?.browsable
|
||||||
},
|
},
|
||||||
|
|
||||||
// Is this layer browsable in theorie
|
// Is this layer browsable in theorie
|
||||||
|
@ -1590,7 +1724,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
getFeatureByIndex: function (index) {
|
getFeatureByIndex: function (index) {
|
||||||
if (index === -1) index = this._index.length - 1
|
if (index === -1) {
|
||||||
|
index = this._index.length - 1
|
||||||
|
}
|
||||||
const id = this._index[index]
|
const id = this._index[index]
|
||||||
return this._layers[id]
|
return this._layers[id]
|
||||||
},
|
},
|
||||||
|
@ -1623,7 +1759,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
let next
|
let next
|
||||||
const index = this.map.datalayers_index
|
const index = this.map.datalayers_index
|
||||||
while (((id = index[++id] ? id : 0), (next = index[id]))) {
|
while (((id = index[++id] ? id : 0), (next = index[id]))) {
|
||||||
if (next === this || next.canBrowse()) break
|
if (next === this || next.canBrowse()) {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return next
|
return next
|
||||||
},
|
},
|
||||||
|
@ -1633,7 +1771,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
let prev
|
let prev
|
||||||
const index = this.map.datalayers_index
|
const index = this.map.datalayers_index
|
||||||
while (((id = index[--id] ? id : index.length - 1), (prev = index[id]))) {
|
while (((id = index[--id] ? id : index.length - 1), (prev = index[id]))) {
|
||||||
if (prev === this || prev.canBrowse()) break
|
if (prev === this || prev.canBrowse()) {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return prev
|
return prev
|
||||||
},
|
},
|
||||||
|
@ -1661,7 +1801,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
save: async function () {
|
save: async function () {
|
||||||
if (this.isDeleted) return this.saveDelete()
|
if (this.isDeleted) {
|
||||||
|
return this.saveDelete()
|
||||||
|
}
|
||||||
if (!this.isLoaded()) {
|
if (!this.isLoaded()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1705,7 +1847,7 @@ U.DataLayer = L.Evented.extend({
|
||||||
if (data.geojson) {
|
if (data.geojson) {
|
||||||
this.clear()
|
this.clear()
|
||||||
this.fromGeoJSON(data.geojson)
|
this.fromGeoJSON(data.geojson)
|
||||||
delete data.geojson
|
data.geojson = undefined
|
||||||
}
|
}
|
||||||
this._reference_version = response.headers.get('X-Datalayer-Version')
|
this._reference_version = response.headers.get('X-Datalayer-Version')
|
||||||
this.sync.update('_reference_version', this._reference_version)
|
this.sync.update('_reference_version', this._reference_version)
|
||||||
|
@ -1738,7 +1880,9 @@ U.DataLayer = L.Evented.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
tableEdit: function () {
|
tableEdit: function () {
|
||||||
if (this.isRemoteLayer() || !this.isVisible()) return
|
if (this.isRemoteLayer() || !this.isVisible()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const editor = new U.TableEditor(this)
|
const editor = new U.TableEditor(this)
|
||||||
editor.edit()
|
editor.edit()
|
||||||
},
|
},
|
||||||
|
@ -1747,10 +1891,16 @@ U.DataLayer = L.Evented.extend({
|
||||||
// This keys will be used to filter feature from the browser text input.
|
// This keys will be used to filter feature from the browser text input.
|
||||||
// By default, it will we use the "name" property, which is also the one used as label in the features list.
|
// By default, it will we use the "name" property, which is also the one used as label in the features list.
|
||||||
// When map owner has configured another label or sort key, we try to be smart and search in the same keys.
|
// When map owner has configured another label or sort key, we try to be smart and search in the same keys.
|
||||||
if (this.map.options.filterKey) return this.map.options.filterKey
|
if (this.map.options.filterKey) {
|
||||||
else if (this.options.labelKey) return this.options.labelKey
|
return this.map.options.filterKey
|
||||||
else if (this.map.options.sortKey) return this.map.options.sortKey
|
}
|
||||||
else return 'name'
|
if (this.options.labelKey) {
|
||||||
|
return this.options.labelKey
|
||||||
|
}
|
||||||
|
if (this.map.options.sortKey) {
|
||||||
|
return this.map.options.sortKey
|
||||||
|
}
|
||||||
|
return 'name'
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ U.MapPermissions = L.Class.extend({
|
||||||
return (
|
return (
|
||||||
this.map.options.user &&
|
this.map.options.user &&
|
||||||
this.map.options.permissions.owner &&
|
this.map.options.permissions.owner &&
|
||||||
this.map.options.user.id == this.map.options.permissions.owner.id
|
this.map.options.user.id === this.map.options.permissions.owner.id
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -48,7 +48,9 @@ U.MapPermissions = L.Class.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
edit: function () {
|
edit: function () {
|
||||||
if (this.map.options.editMode !== 'advanced') return
|
if (this.map.options.editMode !== 'advanced') {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!this.map.options.umap_id) {
|
if (!this.map.options.umap_id) {
|
||||||
return U.Alert.info(L._('Please save the map first'))
|
return U.Alert.info(L._('Please save the map first'))
|
||||||
}
|
}
|
||||||
|
@ -141,17 +143,21 @@ U.MapPermissions = L.Class.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
save: async function () {
|
save: async function () {
|
||||||
if (!this.isDirty) return this.map.continueSaving()
|
if (!this.isDirty) {
|
||||||
|
return this.map.continueSaving()
|
||||||
|
}
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
if (!this.isAnonymousMap() && this.options.editors) {
|
if (!this.isAnonymousMap() && this.options.editors) {
|
||||||
const editors = this.options.editors.map((u) => u.id)
|
const editors = this.options.editors.map((u) => u.id)
|
||||||
for (let i = 0; i < this.options.editors.length; i++)
|
for (let i = 0; i < this.options.editors.length; i++) {
|
||||||
formData.append('editors', this.options.editors[i].id)
|
formData.append('editors', this.options.editors[i].id)
|
||||||
}
|
}
|
||||||
if (this.isOwner() || this.isAnonymousMap())
|
}
|
||||||
|
if (this.isOwner() || this.isAnonymousMap()) {
|
||||||
formData.append('edit_status', this.options.edit_status)
|
formData.append('edit_status', this.options.edit_status)
|
||||||
|
}
|
||||||
if (this.isOwner()) {
|
if (this.isOwner()) {
|
||||||
formData.append('owner', this.options.owner && this.options.owner.id)
|
formData.append('owner', this.options.owner?.id)
|
||||||
formData.append('share_status', this.options.share_status)
|
formData.append('share_status', this.options.share_status)
|
||||||
}
|
}
|
||||||
const [data, response, error] = await this.map.server.post(
|
const [data, response, error] = await this.map.server.post(
|
||||||
|
@ -180,7 +186,7 @@ U.MapPermissions = L.Class.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
addOwnerLink: function (element, container) {
|
addOwnerLink: function (element, container) {
|
||||||
if (this.options.owner && this.options.owner.name && this.options.owner.url) {
|
if (this.options.owner?.name && this.options.owner.url) {
|
||||||
const ownerContainer = L.DomUtil.add(
|
const ownerContainer = L.DomUtil.add(
|
||||||
element,
|
element,
|
||||||
'umap-map-owner',
|
'umap-map-owner',
|
||||||
|
|
|
@ -14,8 +14,8 @@ U.Popup = L.Popup.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
format: function () {
|
format: function () {
|
||||||
const mode = this.feature.getOption('popupTemplate') || 'Default',
|
const mode = this.feature.getOption('popupTemplate') || 'Default'
|
||||||
klass = U.PopupTemplate[mode] || U.PopupTemplate.Default
|
const klass = U.PopupTemplate[mode] || U.PopupTemplate.Default
|
||||||
this.content = new klass(this.feature, this.container)
|
this.content = new klass(this.feature, this.container)
|
||||||
this.content.render()
|
this.content.render()
|
||||||
const els = this.container.querySelectorAll('img,iframe')
|
const els = this.container.querySelectorAll('img,iframe')
|
||||||
|
@ -125,29 +125,35 @@ U.PopupTemplate.Default = L.Class.extend({
|
||||||
|
|
||||||
renderFooter: function () {
|
renderFooter: function () {
|
||||||
if (this.feature.hasPopupFooter()) {
|
if (this.feature.hasPopupFooter()) {
|
||||||
const footer = L.DomUtil.create('ul', 'umap-popup-footer', this.container),
|
const footer = L.DomUtil.create('ul', 'umap-popup-footer', this.container)
|
||||||
previousLi = L.DomUtil.create('li', 'previous', footer),
|
const previousLi = L.DomUtil.create('li', 'previous', footer)
|
||||||
zoomLi = L.DomUtil.create('li', 'zoom', footer),
|
const zoomLi = L.DomUtil.create('li', 'zoom', footer)
|
||||||
nextLi = L.DomUtil.create('li', 'next', footer),
|
const nextLi = L.DomUtil.create('li', 'next', footer)
|
||||||
next = this.feature.getNext(),
|
const next = this.feature.getNext()
|
||||||
prev = this.feature.getPrevious()
|
const prev = this.feature.getPrevious()
|
||||||
// Fixme: remove me when this is merged and released
|
// Fixme: remove me when this is merged and released
|
||||||
// https://github.com/Leaflet/Leaflet/pull/9052
|
// https://github.com/Leaflet/Leaflet/pull/9052
|
||||||
L.DomEvent.disableClickPropagation(footer)
|
L.DomEvent.disableClickPropagation(footer)
|
||||||
if (next)
|
if (next) {
|
||||||
nextLi.title = L._('Go to «{feature}»', {
|
nextLi.title = L._('Go to «{feature}»', {
|
||||||
feature: next.properties.name || L._('next'),
|
feature: next.properties.name || L._('next'),
|
||||||
})
|
})
|
||||||
if (prev)
|
}
|
||||||
|
if (prev) {
|
||||||
previousLi.title = L._('Go to «{feature}»', {
|
previousLi.title = L._('Go to «{feature}»', {
|
||||||
feature: prev.properties.name || L._('previous'),
|
feature: prev.properties.name || L._('previous'),
|
||||||
})
|
})
|
||||||
|
}
|
||||||
zoomLi.title = L._('Zoom to this feature')
|
zoomLi.title = L._('Zoom to this feature')
|
||||||
L.DomEvent.on(nextLi, 'click', () => {
|
L.DomEvent.on(nextLi, 'click', () => {
|
||||||
if (next) next.zoomTo({ callback: next.view })
|
if (next) {
|
||||||
|
next.zoomTo({ callback: next.view })
|
||||||
|
}
|
||||||
})
|
})
|
||||||
L.DomEvent.on(previousLi, 'click', () => {
|
L.DomEvent.on(previousLi, 'click', () => {
|
||||||
if (prev) prev.zoomTo({ callback: prev.view })
|
if (prev) {
|
||||||
|
prev.zoomTo({ callback: prev.view })
|
||||||
|
}
|
||||||
})
|
})
|
||||||
L.DomEvent.on(
|
L.DomEvent.on(
|
||||||
zoomLi,
|
zoomLi,
|
||||||
|
@ -162,9 +168,13 @@ U.PopupTemplate.Default = L.Class.extend({
|
||||||
|
|
||||||
render: function () {
|
render: function () {
|
||||||
const title = this.renderTitle()
|
const title = this.renderTitle()
|
||||||
if (title) this.container.appendChild(title)
|
if (title) {
|
||||||
|
this.container.appendChild(title)
|
||||||
|
}
|
||||||
const body = this.renderBody()
|
const body = this.renderBody()
|
||||||
if (body) L.DomUtil.add('div', 'umap-popup-content', this.container, body)
|
if (body) {
|
||||||
|
L.DomUtil.add('div', 'umap-popup-content', this.container, body)
|
||||||
|
}
|
||||||
this.renderFooter()
|
this.renderFooter()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -202,7 +212,9 @@ U.PopupTemplate.Table = U.PopupTemplate.BaseWithTitle.extend({
|
||||||
const table = L.DomUtil.create('table')
|
const table = L.DomUtil.create('table')
|
||||||
|
|
||||||
for (const key in this.feature.properties) {
|
for (const key in this.feature.properties) {
|
||||||
if (typeof this.feature.properties[key] === 'object' || key === 'name') continue
|
if (typeof this.feature.properties[key] === 'object' || key === 'name') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
// TODO, manage links (url, mailto, wikipedia...)
|
// TODO, manage links (url, mailto, wikipedia...)
|
||||||
this.addRow(table, key, U.Utils.escapeHTML(this.feature.properties[key]).trim())
|
this.addRow(table, key, U.Utils.escapeHTML(this.feature.properties[key]).trim())
|
||||||
}
|
}
|
||||||
|
@ -240,8 +252,8 @@ U.PopupTemplate.GeoRSSLink = U.PopupTemplate.Default.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
renderBody: function () {
|
renderBody: function () {
|
||||||
const title = this.renderTitle(this),
|
const title = this.renderTitle(this)
|
||||||
a = L.DomUtil.add('a')
|
const a = L.DomUtil.add('a')
|
||||||
a.href = this.feature.properties.link
|
a.href = this.feature.properties.link
|
||||||
a.target = '_blank'
|
a.target = '_blank'
|
||||||
a.appendChild(title)
|
a.appendChild(title)
|
||||||
|
@ -257,7 +269,9 @@ U.PopupTemplate.OSM = U.PopupTemplate.Default.extend({
|
||||||
getName: function () {
|
getName: function () {
|
||||||
const props = this.feature.properties
|
const props = this.feature.properties
|
||||||
const locale = L.getLocale()
|
const locale = L.getLocale()
|
||||||
if (locale && props[`name:${locale}`]) return props[`name:${locale}`]
|
if (locale && props[`name:${locale}`]) {
|
||||||
|
return props[`name:${locale}`]
|
||||||
|
}
|
||||||
return props.name
|
return props.name
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -271,7 +285,9 @@ U.PopupTemplate.OSM = U.PopupTemplate.Default.extend({
|
||||||
const icon = U.Icon.makeIconElement(iconUrl, title)
|
const icon = U.Icon.makeIconElement(iconUrl, title)
|
||||||
L.DomUtil.addClass(icon, 'icon')
|
L.DomUtil.addClass(icon, 'icon')
|
||||||
U.Icon.setIconContrast(icon, title, iconUrl, color)
|
U.Icon.setIconContrast(icon, title, iconUrl, color)
|
||||||
if (L.DomUtil.contrastedColor(title, color)) title.style.color = 'white'
|
if (L.DomUtil.contrastedColor(title, color)) {
|
||||||
|
title.style.color = 'white'
|
||||||
|
}
|
||||||
L.DomUtil.add('span', '', title, this.getName())
|
L.DomUtil.add('span', '', title, this.getName())
|
||||||
const street = props['addr:street']
|
const street = props['addr:street']
|
||||||
if (street) {
|
if (street) {
|
||||||
|
@ -323,7 +339,7 @@ U.PopupTemplate.OSM = U.PopupTemplate.Default.extend({
|
||||||
L.DomUtil.element('a', { href: `mailto:${email}`, textContent: email })
|
L.DomUtil.element('a', { href: `mailto:${email}`, textContent: email })
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const id = props['@id'] || props['id']
|
const id = props['@id'] || props.id
|
||||||
if (id) {
|
if (id) {
|
||||||
L.DomUtil.add(
|
L.DomUtil.add(
|
||||||
'div',
|
'div',
|
||||||
|
|
|
@ -19,11 +19,11 @@ U.Share = L.Class.extend({
|
||||||
formatter: (map) => {
|
formatter: (map) => {
|
||||||
const table = []
|
const table = []
|
||||||
map.eachFeature((feature) => {
|
map.eachFeature((feature) => {
|
||||||
const row = feature.toGeoJSON()['properties'],
|
const row = feature.toGeoJSON().properties
|
||||||
center = feature.getCenter()
|
const center = feature.getCenter()
|
||||||
delete row['_umap_options']
|
row._umap_options = undefined
|
||||||
row['Latitude'] = center.lat
|
row.Latitude = center.lat
|
||||||
row['Longitude'] = center.lng
|
row.Longitude = center.lng
|
||||||
table.push(row)
|
table.push(row)
|
||||||
})
|
})
|
||||||
return csv2geojson.dsv.csvFormat(table)
|
return csv2geojson.dsv.csvFormat(table)
|
||||||
|
@ -152,7 +152,9 @@ U.Share = L.Class.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
open: function () {
|
open: function () {
|
||||||
if (!this.container) this.build()
|
if (!this.container) {
|
||||||
|
this.build()
|
||||||
|
}
|
||||||
this.map.panel.open({ content: this.container })
|
this.map.panel.open({ content: this.container })
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -224,7 +226,7 @@ U.IframeExporter = L.Evented.extend({
|
||||||
if (this.options.viewCurrentFeature && this.map.currentFeature) {
|
if (this.options.viewCurrentFeature && this.map.currentFeature) {
|
||||||
this.queryString.feature = this.map.currentFeature.getSlug()
|
this.queryString.feature = this.map.currentFeature.getSlug()
|
||||||
} else {
|
} else {
|
||||||
delete this.queryString.feature
|
this.queryString.feature = undefined
|
||||||
}
|
}
|
||||||
if (this.options.keepCurrentDatalayers) {
|
if (this.options.keepCurrentDatalayers) {
|
||||||
this.map.eachDataLayer((datalayer) => {
|
this.map.eachDataLayer((datalayer) => {
|
||||||
|
@ -234,7 +236,7 @@ U.IframeExporter = L.Evented.extend({
|
||||||
})
|
})
|
||||||
this.queryString.datalayers = datalayers.join(',')
|
this.queryString.datalayers = datalayers.join(',')
|
||||||
} else {
|
} else {
|
||||||
delete this.queryString.datalayers
|
this.queryString.datalayers = undefined
|
||||||
}
|
}
|
||||||
const currentView = this.options.currentView ? window.location.hash : ''
|
const currentView = this.options.currentView ? window.location.hash : ''
|
||||||
const queryString = L.extend({}, this.queryString, options)
|
const queryString = L.extend({}, this.queryString, options)
|
||||||
|
|
|
@ -20,7 +20,9 @@ U.Slideshow = L.Class.extend({
|
||||||
get: function () {
|
get: function () {
|
||||||
if (!current) {
|
if (!current) {
|
||||||
const datalayer = this.defaultDatalayer()
|
const datalayer = this.defaultDatalayer()
|
||||||
if (datalayer) current = datalayer.getFeatureByIndex(0)
|
if (datalayer) {
|
||||||
|
current = datalayer.getFeatureByIndex(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return current
|
return current
|
||||||
},
|
},
|
||||||
|
@ -68,9 +70,11 @@ U.Slideshow = L.Class.extend({
|
||||||
|
|
||||||
timeSpinner: function () {
|
timeSpinner: function () {
|
||||||
const time = Number.parseInt(this.options.delay, 10)
|
const time = Number.parseInt(this.options.delay, 10)
|
||||||
if (!time) return
|
if (!time) {
|
||||||
const css = `rotation ${time / 1000}s infinite linear`,
|
return
|
||||||
spinners = document.querySelectorAll('.umap-slideshow-toolbox .play .spinner')
|
}
|
||||||
|
const css = `rotation ${time / 1000}s infinite linear`
|
||||||
|
const spinners = document.querySelectorAll('.umap-slideshow-toolbox .play .spinner')
|
||||||
for (let i = 0; i < spinners.length; i++) {
|
for (let i = 0; i < spinners.length; i++) {
|
||||||
spinners[i].style.animation = css
|
spinners[i].style.animation = css
|
||||||
spinners[i].style['-webkit-animation'] = css
|
spinners[i].style['-webkit-animation'] = css
|
||||||
|
@ -93,8 +97,12 @@ U.Slideshow = L.Class.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
play: function () {
|
play: function () {
|
||||||
if (this._id) return
|
if (this._id) {
|
||||||
if (this.map.editEnabled || !this.map.options.slideshow.active) return
|
return
|
||||||
|
}
|
||||||
|
if (this.map.editEnabled || !this.map.options.slideshow.active) {
|
||||||
|
return
|
||||||
|
}
|
||||||
L.DomUtil.addClass(document.body, U.Slideshow.CLASSNAME)
|
L.DomUtil.addClass(document.body, U.Slideshow.CLASSNAME)
|
||||||
this._id = window.setInterval(L.bind(this.loop, this), this.options.delay)
|
this._id = window.setInterval(L.bind(this.loop, this), this.options.delay)
|
||||||
this.resetSpinners()
|
this.resetSpinners()
|
||||||
|
@ -127,30 +135,37 @@ U.Slideshow = L.Class.extend({
|
||||||
|
|
||||||
backward: function () {
|
backward: function () {
|
||||||
this.pause()
|
this.pause()
|
||||||
if (this.current) this.current = this.current.getPrevious()
|
if (this.current) {
|
||||||
|
this.current = this.current.getPrevious()
|
||||||
|
}
|
||||||
this.step()
|
this.step()
|
||||||
},
|
},
|
||||||
|
|
||||||
step: function () {
|
step: function () {
|
||||||
if (!this.current) return this.stop()
|
if (!this.current) {
|
||||||
|
return this.stop()
|
||||||
|
}
|
||||||
this.current.zoomTo({ easing: this.options.easing })
|
this.current.zoomTo({ easing: this.options.easing })
|
||||||
this.current.view()
|
this.current.view()
|
||||||
},
|
},
|
||||||
|
|
||||||
renderToolbox: function (container) {
|
renderToolbox: function (container) {
|
||||||
const box = L.DomUtil.create('ul', 'umap-slideshow-toolbox'),
|
const box = L.DomUtil.create('ul', 'umap-slideshow-toolbox')
|
||||||
play = L.DomUtil.create('li', 'play', box),
|
const play = L.DomUtil.create('li', 'play', box)
|
||||||
stop = L.DomUtil.create('li', 'stop', box),
|
const stop = L.DomUtil.create('li', 'stop', box)
|
||||||
prev = L.DomUtil.create('li', 'prev', box),
|
const prev = L.DomUtil.create('li', 'prev', box)
|
||||||
next = L.DomUtil.create('li', 'next', box)
|
const next = L.DomUtil.create('li', 'next', box)
|
||||||
L.DomUtil.create('div', 'spinner', play)
|
L.DomUtil.create('div', 'spinner', play)
|
||||||
play.title = L._('Start slideshow')
|
play.title = L._('Start slideshow')
|
||||||
stop.title = L._('Stop slideshow')
|
stop.title = L._('Stop slideshow')
|
||||||
next.title = L._('Zoom to the next')
|
next.title = L._('Zoom to the next')
|
||||||
prev.title = L._('Zoom to the previous')
|
prev.title = L._('Zoom to the previous')
|
||||||
const toggle = function () {
|
const toggle = function () {
|
||||||
if (this._id) this.pause()
|
if (this._id) {
|
||||||
else this.play()
|
this.pause()
|
||||||
|
} else {
|
||||||
|
this.play()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
L.DomEvent.on(play, 'click', L.DomEvent.stop).on(play, 'click', toggle, this)
|
L.DomEvent.on(play, 'click', L.DomEvent.stop).on(play, 'click', toggle, this)
|
||||||
L.DomEvent.on(stop, 'click', L.DomEvent.stop).on(stop, 'click', this.stop, this)
|
L.DomEvent.on(stop, 'click', L.DomEvent.stop).on(stop, 'click', this.stop, this)
|
||||||
|
|
|
@ -15,10 +15,10 @@ U.TableEditor = L.Class.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
renderHeader: function (property) {
|
renderHeader: function (property) {
|
||||||
const container = L.DomUtil.create('div', 'tcell', this.header),
|
const container = L.DomUtil.create('div', 'tcell', this.header)
|
||||||
title = L.DomUtil.add('span', '', container, property),
|
const title = L.DomUtil.add('span', '', container, property)
|
||||||
del = L.DomUtil.create('i', 'umap-delete', container),
|
const del = L.DomUtil.create('i', 'umap-delete', container)
|
||||||
rename = L.DomUtil.create('i', 'umap-edit', container)
|
const rename = L.DomUtil.create('i', 'umap-edit', container)
|
||||||
del.title = L._('Delete this property on all the features')
|
del.title = L._('Delete this property on all the features')
|
||||||
rename.title = L._('Rename this property on all the features')
|
rename.title = L._('Rename this property on all the features')
|
||||||
const doDelete = function () {
|
const doDelete = function () {
|
||||||
|
@ -40,7 +40,9 @@ U.TableEditor = L.Class.extend({
|
||||||
L._('Please enter the new name of this property'),
|
L._('Please enter the new name of this property'),
|
||||||
property
|
property
|
||||||
)
|
)
|
||||||
if (!newName || !this.validateName(newName)) return
|
if (!newName || !this.validateName(newName)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.datalayer.eachLayer((feature) => {
|
this.datalayer.eachLayer((feature) => {
|
||||||
feature.renameProperty(property, newName)
|
feature.renameProperty(property, newName)
|
||||||
})
|
})
|
||||||
|
@ -63,10 +65,13 @@ U.TableEditor = L.Class.extend({
|
||||||
|
|
||||||
compileProperties: function () {
|
compileProperties: function () {
|
||||||
this.resetProperties()
|
this.resetProperties()
|
||||||
if (this.properties.length === 0) this.properties = ['name']
|
if (this.properties.length === 0) {
|
||||||
|
this.properties = ['name']
|
||||||
|
}
|
||||||
// description is a forced textarea, don't edit it in a text input, or you lose cariage returns
|
// description is a forced textarea, don't edit it in a text input, or you lose cariage returns
|
||||||
if (this.properties.indexOf('description') !== -1)
|
if (this.properties.indexOf('description') !== -1) {
|
||||||
this.properties.splice(this.properties.indexOf('description'), 1)
|
this.properties.splice(this.properties.indexOf('description'), 1)
|
||||||
|
}
|
||||||
this.properties.sort()
|
this.properties.sort()
|
||||||
this.field_properties = []
|
this.field_properties = []
|
||||||
for (let i = 0; i < this.properties.length; i++) {
|
for (let i = 0; i < this.properties.length; i++) {
|
||||||
|
@ -104,7 +109,9 @@ U.TableEditor = L.Class.extend({
|
||||||
addButton.insertBefore(iconElement, addButton.firstChild)
|
addButton.insertBefore(iconElement, addButton.firstChild)
|
||||||
const addProperty = function () {
|
const addProperty = function () {
|
||||||
const newName = prompt(L._('Please enter the name of the property'))
|
const newName = prompt(L._('Please enter the name of the property'))
|
||||||
if (!newName || !this.validateName(newName)) return
|
if (!newName || !this.validateName(newName)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.datalayer.indexProperty(newName)
|
this.datalayer.indexProperty(newName)
|
||||||
this.edit()
|
this.edit()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue