chore: apply Biome unsafe changes

This commit is contained in:
David Larlet 2024-06-25 10:03:54 -04:00
parent ef33a26f11
commit ec645fb6e6
No known key found for this signature in database
GPG key ID: 3E2953A359E7E7BD
32 changed files with 1431 additions and 714 deletions

View file

@ -71,7 +71,9 @@ export class BaseAutocomplete {
onKeyDown(e) {
switch (e.key) {
case 'Tab':
if (this.current !== null) this.setChoice()
if (this.current !== null) {
this.setChoice()
}
DomEvent.stop(e)
break
case 'Enter':
@ -195,8 +197,11 @@ export class BaseAutocomplete {
highlight() {
this.results.forEach((result, index) => {
if (index === this.current) DomUtil.addClass(result.el, 'on')
else DomUtil.removeClass(result.el, 'on')
if (index === this.current) {
DomUtil.addClass(result.el, 'on')
} else {
DomUtil.removeClass(result.el, 'on')
}
})
}
@ -249,8 +254,10 @@ export class BaseAjax extends BaseAutocomplete {
this.clear()
return
}
if (val === this.cache) return
else this.cache = val
if (val === this.cache) {
return
}
this.cache = val
val = val.toLowerCase()
const url = Util.template(this.url, { q: encodeURIComponent(val) })
this.handleResults(await this._search(url))
@ -258,7 +265,7 @@ export class BaseAjax extends BaseAutocomplete {
async _search(url) {
const response = await this.request.get(url)
if (response && response.ok) {
if (response?.ok) {
return await response.json()
}
}

View file

@ -13,8 +13,12 @@ export default class Browser {
}
addFeature(feature, parent) {
if (feature.isFiltered()) return
if (this.options.inBbox && !feature.isOnScreen(this.bounds)) return
if (feature.isFiltered()) {
return
}
if (this.options.inBbox && !feature.isOnScreen(this.bounds)) {
return
}
const row = DomUtil.create('li', `${feature.getClassName()} feature`)
const zoom_to = DomUtil.createButtonIcon(
row,
@ -62,9 +66,11 @@ export default class Browser {
addDataLayer(datalayer, parent) {
let className = `datalayer ${datalayer.getHidableClass()}`
if (this.mode !== 'layers') className += ' show-list'
const container = DomUtil.create('div', className, parent),
headline = DomUtil.create('h5', '', container)
if (this.mode !== 'layers') {
className += ' show-list'
}
const container = DomUtil.create('div', className, parent)
const headline = DomUtil.create('h5', '', container)
container.id = this.datalayerId(datalayer)
const ul = DomUtil.create('ul', '', container)
this.updateDatalayer(datalayer)
@ -75,7 +81,9 @@ export default class Browser {
this.bounds = this.map.getBounds()
const parent = DomUtil.get(this.datalayerId(datalayer))
// Panel is not open
if (!parent) return
if (!parent) {
return
}
parent.classList.toggle('off', !datalayer.isVisible())
const container = parent.querySelector('ul')
const headline = parent.querySelector('h5')
@ -90,9 +98,9 @@ export default class Browser {
container.innerHTML = ''
datalayer.eachFeature((feature) => this.addFeature(feature, container))
const total = datalayer.count(),
current = container.querySelectorAll('li').length,
count = total == current ? total : `${current}/${total}`
const total = datalayer.count()
const current = container.querySelectorAll('li').length
const count = total === current ? total : `${current}/${total}`
const counter = DomUtil.create('span', 'datalayer-counter', headline)
counter.textContent = `(${count})`
counter.title = translate(`Features in this layer: ${count}`)
@ -112,7 +120,9 @@ export default class Browser {
}
redraw() {
if (this.isOpen()) this.open()
if (this.isOpen()) {
this.open()
}
}
isOpen() {
@ -124,16 +134,22 @@ export default class Browser {
}
onMoveEnd() {
if (!this.isOpen()) return
if (!this.isOpen()) {
return
}
const isListDynamic = this.options.inBbox
this.map.eachBrowsableDataLayer((datalayer) => {
if (!isListDynamic && !datalayer.hasDynamicData()) return
if (!isListDynamic && !datalayer.hasDynamicData()) {
return
}
this.updateDatalayer(datalayer)
})
}
update() {
if (!this.isOpen()) return
if (!this.isOpen()) {
return
}
this.dataContainer.innerHTML = ''
this.map.eachBrowsableDataLayer((datalayer) => {
this.addDataLayer(datalayer, this.dataContainer)
@ -142,7 +158,9 @@ export default class Browser {
open(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')
// HOTFIX. Remove when this is released:
// https://github.com/Leaflet/Leaflet/pull/9052
@ -185,7 +203,9 @@ export default class Browser {
}
const reset = DomUtil.createButton('flat', formContainer, '', () => {
builder.form.reset()
if (filtersBuilder) filtersBuilder.form.reset()
if (filtersBuilder) {
filtersBuilder.form.reset()
}
})
DomUtil.createIcon(reset, 'icon-restore')
DomUtil.element({

View file

@ -12,7 +12,9 @@ export default class Caption {
}
refresh() {
if (!this.isOpen()) return
if (!this.isOpen()) {
return
}
this.open()
}
@ -39,10 +41,12 @@ export default class Caption {
}
addDataLayer(datalayer, container) {
if (!datalayer.options.inCaption) return
const p = DomUtil.create('p', 'datalayer-legend', container),
legend = DomUtil.create('span', '', p),
headline = DomUtil.create('strong', '', p)
if (!datalayer.options.inCaption) {
return
}
const p = DomUtil.create('p', 'datalayer-legend', container)
const legend = DomUtil.create('span', '', p)
const headline = DomUtil.create('strong', '', p)
datalayer.onceLoaded(() => {
datalayer.renderLegend(legend)
if (datalayer.options.description) {

View file

@ -6,7 +6,6 @@ console.log(DOMPurifyInitializer)
export default function getPurify() {
if (typeof window === 'undefined') {
return DOMPurifyInitializer(new JSDOM('').window)
} else {
}
return DOMPurifyInitializer(window)
}
}

View file

@ -13,7 +13,7 @@ export default class Facets {
let selected
names.forEach((name) => {
const type = defined[name]['type']
const type = defined[name].type
properties[name] = { type: type }
selected = this.selected[name] || {}
selected.type = type
@ -28,18 +28,24 @@ export default class Facets {
datalayer.eachFeature((feature) => {
names.forEach((name) => {
let value = feature.properties[name]
const type = defined[name]['type']
const type = defined[name].type
const parser = this.getParser(type)
value = parser(value)
switch (type) {
case 'date':
case 'datetime':
case 'number':
if (!isNaN(value)) {
if (isNaN(properties[name].min) || properties[name].min > value) {
if (!Number.isNaN(value)) {
if (
Number.isNaN(properties[name].min) ||
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
}
}
@ -58,7 +64,7 @@ export default class Facets {
isActive() {
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
}
}
@ -73,7 +79,7 @@ export default class Facets {
const fields = names.map((name) => {
const criteria = facetProperties[name]
let handler = 'FacetSearchChoices'
switch (criteria['type']) {
switch (criteria.type) {
case 'number':
handler = 'FacetSearchNumber'
break
@ -84,7 +90,7 @@ export default class Facets {
handler = 'FacetSearchDateTime'
break
}
const label = defined[name]['label']
const label = defined[name].label
return [
`selected.${name}`,
{

View file

@ -191,7 +191,7 @@ export default class Help {
const container = DomUtil.add('div')
DomUtil.createTitle(container, translate('Help'))
// Special dynamic case. Do we still think this dialog is usefull ?
if (entries == 'edit') {
if (entries === 'edit') {
DomUtil.element({
tagName: 'div',
className: 'umap-help-entry',

View file

@ -179,15 +179,17 @@ export default class Importer {
this.format === 'umap' || !this.url
)
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) {
let type = '',
newType
let type = ''
let newType
for (const file of e.target.files) {
newType = U.Utils.detectFileType(file)
if (!type && newType) type = newType
if (!type && newType) {
type = newType
}
if (type && newType !== type) {
type = ''
break
@ -223,7 +225,9 @@ export default class Importer {
}
open() {
if (!this.container) this.build()
if (!this.container) {
this.build()
}
const onLoad = this.map.editPanel.open({ content: this.container })
onLoad.then(() => this.onLoad())
}
@ -294,7 +298,9 @@ export default class Importer {
return false
}
const layer = this.layer
if (this.clear) layer.empty()
if (this.clear) {
layer.empty()
}
if (this.files.length) {
for (const file of this.files) {
this.map.processFileToImport(file, layer, this.format)

View file

@ -52,7 +52,7 @@ export class Importer {
container.innerHTML = TEMPLATE
const response = await importer.map.request.get(`${this.baseUrl}/themes`)
const select = container.querySelector('select')
if (response && response.ok) {
if (response?.ok) {
const { themes } = await response.json()
themes.sort((a, b) => Utils.naturalSort(a['name:fr'], b['name:fr']))
for (const theme of themes) {

View file

@ -65,12 +65,18 @@ export class Importer {
return
}
const outMode = container.querySelector('[name=out-mode]').value
if (!tags.startsWith('[')) tags = `[${tags}]`
if (!tags.startsWith('[')) {
tags = `[${tags}]`
}
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};`
importer.url = `${this.baseUrl}?data=${query}`
if (boundary) importer.layerName = boundaryName
if (boundary) {
importer.layerName = boundaryName
}
importer.format = 'osm'
importer.dialog.close()
}

View file

@ -7,7 +7,9 @@ export default class Orderable {
this.src = null
this.dst = null
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) {
@ -26,7 +28,9 @@ export default class Orderable {
findTarget(node) {
while (node) {
if (this.nodeIndex(node) !== -1) return node
if (this.nodeIndex(node) !== -1) {
return node
}
node = node.parentNode
}
}
@ -48,7 +52,9 @@ export default class Orderable {
onDragOver(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'
return false
}
@ -57,12 +63,17 @@ export default class Orderable {
DomEvent.stop(e)
// e.target is the current hover target.
const dst = this.findTarget(e.target)
if (!dst || dst === this.src) return
if (!dst || dst === this.src) {
return
}
this.dst = dst
const targetIndex = this.nodeIndex(this.dst),
srcIndex = this.nodeIndex(this.src)
if (targetIndex > srcIndex) this.parent.insertBefore(this.dst, this.src)
else this.parent.insertBefore(this.src, this.dst)
const targetIndex = this.nodeIndex(this.dst)
const srcIndex = this.nodeIndex(this.src)
if (targetIndex > srcIndex) {
this.parent.insertBefore(this.dst, this.src)
} else {
this.parent.insertBefore(this.src, this.dst)
}
}
onDragLeave(e) {
@ -71,8 +82,12 @@ export default class Orderable {
onDrop(e) {
// e.target is current target element.
if (e.stopPropagation) e.stopPropagation() // Stops the browser from redirecting.
if (!this.dst) return
if (e.stopPropagation) {
e.stopPropagation() // Stops the browser from redirecting.
}
if (!this.dst) {
return
}
this.onCommit(this.src, this.dst, this.initialIndex, this.nodeIndex(this.src))
return false
}

View file

@ -64,7 +64,9 @@ export class Request extends BaseRequest {
)
return response
} catch (error) {
if (error instanceof NOKError) return this._onNOK(error)
if (error instanceof NOKError) {
return this._onNOK(error)
}
return this._onError(error)
} finally {
this.fire('dataload', { id: id })
@ -122,7 +124,9 @@ export class ServerRequest extends Request {
}
async _as_json(response) {
if (Array.isArray(response)) return response
if (Array.isArray(response)) {
return response
}
try {
const data = await response.json()
if (data.info) {

View file

@ -18,7 +18,9 @@ class Rule {
set isDirty(status) {
this._isDirty = status
if (status) this.map.isDirty = status
if (status) {
this.map.isDirty = status
}
}
constructor(map, condition = '', options = {}) {
@ -49,7 +51,7 @@ class Rule {
}
not_equal(other) {
return this.expected != other
return this.expected !== other
}
gt(other) {
@ -71,16 +73,23 @@ class Rule {
break
}
}
if (vars.length != 2) return
if (vars.length !== 2) {
return
}
this.key = vars[0]
this.expected = vars[1]
if (!isNaN(this.expected)) this.cast = Number.parseFloat
else if (['true', 'false'].includes(this.expected)) this.cast = (v) => !!v
if (!Number.isNaN(this.expected)) {
this.cast = Number.parseFloat
} else if (['true', 'false'].includes(this.expected)) {
this.cast = (v) => !!v
}
this.expected = this.cast(this.expected)
}
match(props) {
if (!this.operator || !this.active) return false
if (!this.operator || !this.active) {
return false
}
return this.operator(this.cast(props[this.key]))
}
@ -144,7 +153,9 @@ class Rule {
remove,
'click',
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.map.editPanel.close()
},
@ -161,7 +172,7 @@ class Rule {
}
_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() {
if (!this.map.options.rules?.length) return
if (!this.map.options.rules?.length) {
return
}
for (const { condition, options } of this.map.options.rules) {
if (!condition) continue
if (!condition) {
continue
}
this.rules.push(new Rule(this.map, condition, options))
}
}
onReorder(src, dst, initialIndex, finalIndex) {
const moved = this.rules.find((rule) => stamp(rule) == src.dataset.id)
const reference = this.rules.find((rule) => stamp(rule) == dst.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 movedIdx = this.rules.indexOf(moved)
let referenceIdx = this.rules.indexOf(reference)
const minIndex = Math.min(movedIdx, referenceIdx)
@ -190,9 +205,13 @@ export default class Rules {
moved._delete() // Remove from array
referenceIdx = this.rules.indexOf(reference)
let newIdx
if (finalIndex === 0) newIdx = 0
else if (finalIndex > initialIndex) newIdx = referenceIdx
else newIdx = referenceIdx + 1
if (finalIndex === 0) {
newIdx = 0
} else if (finalIndex > initialIndex) {
newIdx = referenceIdx
} else {
newIdx = referenceIdx + 1
}
this.rules.splice(newIdx, 0, moved)
moved.isDirty = true
this.map.render(['rules'])
@ -231,7 +250,9 @@ export default class Rules {
getOption(option, feature) {
for (const rule of this.rules) {
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
}
}

View file

@ -23,7 +23,9 @@ export class SyncEngine {
}
stop() {
if (this.transport) this.transport.close()
if (this.transport) {
this.transport.close()
}
this.transport = undefined
}
@ -36,7 +38,7 @@ export class SyncEngine {
// This method is called by the transport layer on new messages
receive({ kind, ...payload }) {
if (kind == 'operation') {
if (kind === 'operation') {
const updater = this._getUpdater(payload.subject, payload.metadata)
updater.applyMessage(payload)
} else {

View file

@ -15,11 +15,15 @@ class BaseUpdater {
// Reduce the current list of attributes,
// to find the object to set the property onto
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)
// In case the given path doesn't exist, stop here
if (objectToSet === undefined) return
if (objectToSet === undefined) {
return
}
// Set the value (or delete it)
if (typeof value === 'undefined') {
@ -30,7 +34,9 @@ class BaseUpdater {
}
getDataLayerFromID(layerId) {
if (layerId) return this.map.getDataLayerByUmapId(layerId)
if (layerId) {
return this.map.getDataLayerByUmapId(layerId)
}
return this.map.defaultEditDataLayer()
}
@ -89,9 +95,10 @@ export class FeatureUpdater extends BaseUpdater {
console.error(`Unable to find feature with id = ${metadata.id}.`)
}
switch (key) {
case 'geometry':
case 'geometry': {
const datalayer = this.getDataLayerFromID(metadata.layerId)
datalayer.geoJSONToLeaflet({ geometry: value, id: metadata.id, feature })
}
default:
this.updateObjectValue(feature, key, value)
feature.datalayer.indexProperties(feature)
@ -104,6 +111,8 @@ export class FeatureUpdater extends BaseUpdater {
// XXX Distinguish between properties getting deleted
// and the wole feature getting deleted
const feature = this.getFeatureFromMetadata(metadata)
if (feature) feature.del(false)
if (feature) {
feature.del(false)
}
}
}

View file

@ -31,9 +31,14 @@ export default class Dialog {
open({ className, content, modal } = {}) {
this.container.innerHTML = ''
const currentZIndex = this.currentZIndex()
if (currentZIndex) this.container.style.zIndex = currentZIndex + 1
if (modal) this.container.showModal()
else this.container.show()
if (currentZIndex) {
this.container.style.zIndex = currentZIndex + 1
}
if (modal) {
this.container.showModal()
} else {
this.container.show()
}
if (className) {
// Reset
this.container.className = this.className

View file

@ -17,7 +17,9 @@ export class Panel {
}
setDefaultMode(mode) {
if (!this.mode) this.mode = mode
if (!this.mode) {
this.mode = mode
}
}
isOpen() {
@ -46,7 +48,9 @@ export class Panel {
const element = DomUtil.element({ tagName: 'li', parent: actionsContainer })
element.appendChild(action)
}
if (className) DomUtil.addClass(body, className)
if (className) {
DomUtil.addClass(body, className)
}
const promise = new Promise((resolve, reject) => {
DomUtil.addClass(this.container, 'on')
resolve()

View file

@ -44,8 +44,8 @@ export default class Tooltip {
const left =
this.parent.offsetLeft +
this.parent.clientWidth / 2 -
this.container.clientWidth / 2,
top = this.parent.offsetTop + 75
this.container.clientWidth / 2
const top = this.parent.offsetTop + 75
this.setPosition({ top: top, left: left })
}
@ -80,7 +80,9 @@ export default class Tooltip {
// Clear timetout even if a new tooltip has been added
// in the meantime. Eg. after a mouseout from the anchor.
window.clearTimeout(id)
if (id && id !== this.TOOLTIP_ID) return
if (id && id !== this.TOOLTIP_ID) {
return
}
this.container.className = ''
this.container.innerHTML = ''
this.setPosition({})
@ -92,14 +94,26 @@ export default class Tooltip {
}
setPosition(coords) {
if (coords.left) this.container.style.left = `${coords.left}px`
else this.container.style.left = 'initial'
if (coords.right) this.container.style.right = `${coords.right}px`
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'
if (coords.left) {
this.container.style.left = `${coords.left}px`
} else {
this.container.style.left = 'initial'
}
if (coords.right) {
this.container.style.right = `${coords.right}px`
} 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() {

View file

@ -6,24 +6,29 @@ export default class URLs {
}
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)) {
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.
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')
}
// Update the layer if pk is passed, create otherwise.
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)
}
}

View file

@ -21,7 +21,9 @@ export function generateId() {
* @returns {boolean}
*/
export function checkId(string) {
if (typeof string !== 'string') return false
if (typeof string !== 'string') {
return false
}
return /^[A-Za-z0-9]{5}$/.test(string)
}
@ -63,9 +65,8 @@ export function getImpactsFromSchema(fields, schema) {
export default function getPurify() {
if (typeof window === 'undefined') {
return DOMPurifyInitializer(new global.JSDOM('').window)
} else {
return DOMPurifyInitializer(window)
}
return DOMPurifyInitializer(window)
}
export function escapeHTML(s) {
@ -113,8 +114,10 @@ export function escapeHTML(s) {
}
export function toHTML(r, options) {
if (!r) return ''
const target = (options && options.target) || 'blank'
if (!r) {
return ''
}
const target = options?.target || 'blank'
// unordered lists
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')) {
return 'kml'
}
if (ext('.gpx')) return 'gpx'
if (ext('.geojson') || ext('.json')) return 'geojson'
if (ext('.gpx')) {
return 'gpx'
}
if (ext('.geojson') || ext('.json')) {
return 'geojson'
}
if (f.type === 'text/csv' || ext('.csv') || ext('.tsv') || ext('.dsv')) {
return 'csv'
}
if (ext('.xml') || ext('.osm')) return 'osm'
if (ext('.umap')) return 'umap'
if (ext('.xml') || ext('.osm')) {
return 'osm'
}
if (ext('.umap')) {
return 'umap'
}
}
export function usableOption(options, option) {
@ -225,12 +236,16 @@ export function greedyTemplate(str, data, ignore) {
let value = data
for (let i = 0; i < path.length; i++) {
value = value[path[i]]
if (value === undefined) break
if (value === undefined) {
break
}
}
return value
}
if (typeof str !== 'string') return ''
if (typeof str !== 'string') {
return ''
}
return str.replace(
/\{ *([^\{\}/\-]+)(?:\|("[^"]*"))? *\}/g,
@ -243,14 +258,21 @@ export function greedyTemplate(str, data, ignore) {
}
for (let i = 0; i < vars.length; i++) {
path = vars[i]
if (path.startsWith('"') && path.endsWith('"'))
if (path.startsWith('"') && path.endsWith('"')) {
value = path.substring(1, path.length - 1) // static default value.
else value = getValue(data, path.split('.'))
if (value !== undefined) break
} else {
value = getValue(data, path.split('.'))
}
if (value !== undefined) {
break
}
}
if (value === undefined) {
if (ignore) value = str
else value = ''
if (ignore) {
value = str
} else {
value = ''
}
}
return value
}
@ -271,8 +293,8 @@ export function sortFeatures(features, sortKey, lang) {
const sortKeys = (sortKey || 'name').split(',')
const sort = (a, b, i) => {
let sortKey = sortKeys[i],
reverse = 1
let sortKey = sortKeys[i]
let reverse = 1
if (sortKey[0] === '-') {
reverse = -1
sortKey = sortKey.substring(1)
@ -280,10 +302,16 @@ export function sortFeatures(features, sortKey, lang) {
let score
const valA = a.properties[sortKey] || ''
const valB = b.properties[sortKey] || ''
if (!valA) score = -1
else if (!valB) score = 1
else score = naturalSort(valA, valB, lang)
if (score === 0 && sortKeys[i + 1]) return sort(a, b, i + 1)
if (!valA) {
score = -1
} else if (!valB) {
score = 1
} else {
score = naturalSort(valA, valB, lang)
}
if (score === 0 && sortKeys[i + 1]) {
return sort(a, b, i + 1)
}
return score * reverse
}
@ -298,7 +326,9 @@ export function sortFeatures(features, sortKey, lang) {
}
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
}
@ -315,19 +345,19 @@ export function getBaseUrl() {
}
export function hasVar(value) {
return typeof value === 'string' && value.indexOf('{') != -1
return typeof value === 'string' && value.indexOf('{') !== -1
}
export function isPath(value) {
return value && value.length && value.startsWith('/')
return value?.length && value.startsWith('/')
}
export function isRemoteUrl(value) {
return value && value.length && value.startsWith('http')
return value?.length && value.startsWith('http')
}
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
// 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) {
return str.replace(templateRe, (str, key) => {
var value = data[key]
let value = data[key]
if (value === undefined) {
throw new Error('No value provided for variable ' + str)
} else if (typeof value === 'function') {
throw new Error(`No value provided for variable ${str}`)
}
if (typeof value === 'function') {
value = value(data)
}
return value
@ -371,9 +402,16 @@ export function parseNaiveDate(value) {
}
export function toggleBadge(element, value) {
if (!element.nodeType) element = document.querySelector(element)
if (!element) return
// True means simple badge, without content
if (value) element.dataset.badge = value === true ? ' ' : value
else delete element.dataset.badge
if (!element.nodeType) {
element = document.querySelector(element)
}
if (!element) {
return
}
// True means simple badge, without content
if (value) {
element.dataset.badge = value === true ? ' ' : value
} else {
delete element.dataset.badge
}
}

View file

@ -12,8 +12,9 @@ U.BaseAction = L.ToolbarAction.extend({
tooltip: this.options.tooltip,
}
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
}
},
})
@ -213,8 +214,9 @@ U.DeleteFeatureAction = U.BaseFeatureAction.extend({
},
postInit: function () {
if (!this.feature.isMulti())
if (!this.feature.isMulti()) {
this.options.toolbarIcon.className = 'umap-delete-one-of-one'
}
},
onClick: function (e) {
@ -434,11 +436,14 @@ U.MoreControls = L.Control.extend({
},
toggle: function () {
const pos = this.getPosition(),
corner = this._map._controlCorners[pos],
className = 'umap-more-controls'
if (L.DomUtil.hasClass(corner, className)) L.DomUtil.removeClass(corner, className)
else L.DomUtil.addClass(corner, className)
const pos = this.getPosition()
const corner = this._map._controlCorners[pos]
const className = 'umap-more-controls'
if (L.DomUtil.hasClass(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(
'div',
'umap-permanent-credits-container'
),
creditsParagraph = L.DomUtil.create('p', '', paragraphContainer)
)
const creditsParagraph = L.DomUtil.create('p', '', paragraphContainer)
this.paragraphContainer = paragraphContainer
this.setCredits()
@ -564,7 +569,9 @@ L.Control.Embed = L.Control.Button.extend({
U.DataLayer.include({
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)
color.style.backgroundColor = this.getColor()
},
@ -604,8 +611,12 @@ U.DataLayer.include({
remove,
'click',
function () {
if (!this.isVisible()) return
if (!confirm(L._('Are you sure you want to delete this layer?'))) return
if (!this.isVisible()) {
return
}
if (!confirm(L._('Are you sure you want to delete this layer?'))) {
return
}
this._delete()
},
this
@ -660,7 +671,9 @@ U.DataLayer.addInitHook(function () {
this.on('hide', this.propagateHide)
this.on('show', this.propagateShow)
this.on('erase', this.propagateDelete)
if (this.isVisible()) this.propagateShow()
if (this.isVisible()) {
this.propagateShow()
}
})
const ControlsMixin = {
@ -745,7 +758,7 @@ const ControlsMixin = {
L.DomUtil.createLink(
'umap-user',
rightContainer,
L._(`My Dashboard ({username})`, {
L._('My Dashboard ({username})', {
username: this.options.user.name,
}),
this.options.user.url
@ -818,7 +831,9 @@ const ControlsMixin = {
},
editDatalayers: function () {
if (!this.editEnabled) return
if (!this.editEnabled) {
return
}
const container = L.DomUtil.create('div')
L.DomUtil.createTitle(container, L._('Manage layers'), 'icon-layers')
const ul = L.DomUtil.create('ul', '', container)
@ -832,16 +847,21 @@ const ControlsMixin = {
row.dataset.id = L.stamp(datalayer)
})
const onReorder = (src, dst, initialIndex, finalIndex) => {
const layer = this.datalayers[src.dataset.id],
other = this.datalayers[dst.dataset.id],
minIndex = Math.min(layer.getRank(), other.getRank()),
maxIndex = Math.max(layer.getRank(), other.getRank())
if (finalIndex === 0) layer.bringToTop()
else if (finalIndex > initialIndex) layer.insertBefore(other)
else layer.insertAfter(other)
const layer = this.datalayers[src.dataset.id]
const other = this.datalayers[dst.dataset.id]
const minIndex = Math.min(layer.getRank(), other.getRank())
const maxIndex = Math.max(layer.getRank(), other.getRank())
if (finalIndex === 0) {
layer.bringToTop()
} else if (finalIndex > initialIndex) {
layer.insertBefore(other)
} else {
layer.insertAfter(other)
}
this.eachDataLayerReverse((datalayer) => {
if (datalayer.getRank() >= minIndex && datalayer.getRank() <= maxIndex)
if (datalayer.getRank() >= minIndex && datalayer.getRank() <= maxIndex) {
datalayer.isDirty = true
}
})
this.indexDatalayers()
}
@ -897,7 +917,9 @@ U.TileLayerControl = L.Control.IconLayers.extend({
}
const maxShown = 10
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 (
window.location.protocol === 'https:' &&
tilelayer.options.url_template.indexOf('http:') === 0
)
) {
return
}
this.addTileLayerElement(tilelayer, options)
}, this)
},
addTileLayerElement: function (tilelayer, options) {
const selectedClass = this.map.hasLayer(tilelayer) ? 'selected' : '',
el = L.DomUtil.create('li', selectedClass, this._tilelayers_container),
img = L.DomUtil.create('img', '', el),
name = L.DomUtil.create('div', '', el)
const selectedClass = this.map.hasLayer(tilelayer) ? 'selected' : ''
const el = L.DomUtil.create('li', selectedClass, this._tilelayers_container)
const img = L.DomUtil.create('img', '', el)
const name = L.DomUtil.create('div', '', el)
img.src = U.Utils.template(tilelayer.options.url_template, this.map.demoTileInfos)
img.loading = 'lazy'
name.textContent = tilelayer.options.name
@ -961,7 +984,9 @@ U.TileLayerChooser = L.Control.extend({
function () {
this.map.selectTileLayer(tilelayer)
this.map._controls.tilelayers.setLayers()
if (options && options.callback) options.callback(tilelayer)
if (options?.callback) {
options.callback(tilelayer)
}
},
this
)
@ -975,15 +1000,17 @@ U.AttributionControl = L.Control.Attribution.extend({
_update: function () {
// Layer is no more on the map
if (!this._map) return
if (!this._map) {
return
}
L.Control.Attribution.prototype._update.call(this)
// Use our own container, so we can hide/show on small screens
const credits = this._container.innerHTML
this._container.innerHTML = ''
const container = L.DomUtil.create('div', 'attribution-container', this._container)
container.innerHTML = credits
const shortCredit = this._map.getOption('shortCredit'),
captionMenus = this._map.getOption('captionMenus')
const shortCredit = this._map.getOption('shortCredit')
const captionMenus = this._map.getOption('captionMenus')
if (shortCredit) {
L.DomUtil.element({
tagName: 'span',
@ -1045,7 +1072,9 @@ U.Locate = L.Control.Locate.extend({
// This occurs because we do create the control and call its activate
// method before adding the control button itself to the map, in the
// 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)
},
})
@ -1056,7 +1085,9 @@ U.Search = L.PhotonSearch.extend({
this.options.location_bias_scale = 0.5
L.PhotonSearch.prototype.initialize.call(this, map, input, options)
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({
handleResults: (geojson) => {
this.handleResultsWithReverse(geojson)
@ -1091,7 +1122,9 @@ U.Search = L.PhotonSearch.extend({
return
}
// Only numbers, abort.
if (/^[\d .,]*$/.test(this.input.value)) return
if (/^[\d .,]*$/.test(this.input.value)) {
return
}
// Do normal search
this.options.includePosition = this.map.getZoom() > 10
L.PhotonSearch.prototype.search.call(this)
@ -1171,7 +1204,9 @@ U.SearchControl = L.Control.extend({
limit: 10,
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', '')
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
// (eg. line has only one drawn point)
// So let's check if the layer has no more shape
if (!e.layer.hasGeom()) e.layer.del()
else e.layer.edit()
if (!e.layer.hasGeom()) {
e.layer.del()
} else {
e.layer.edit()
}
})
// Layer for items added by users
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) {
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) => {
const layer = e.layer
@ -1272,11 +1314,14 @@ U.Editable = L.Editable.extend({
})
this.on('editable:vertex:ctrlclick', (e) => {
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()
}
})
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)
},
@ -1310,7 +1355,7 @@ U.Editable = L.Editable.extend({
},
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') })
}
if (!(e.layer instanceof L.Polyline)) {

View file

@ -27,11 +27,13 @@ L.Util.copyToClipboard = (textToCopy) => {
L.Util.queryString = (name, fallback) => {
const decode = (s) => decodeURIComponent(s.replace(/\+/g, ' '))
const qs = window.location.search.slice(1).split('&'),
qa = {}
const qs = window.location.search.slice(1).split('&')
const qa = {}
for (const i in qs) {
const key = qs[i].split('=')
if (!key) continue
if (!key) {
continue
}
qa[decode(key[0])] = key[1] ? decode(key[1]) : 1
}
return qa[name] || fallback
@ -44,25 +46,35 @@ L.Util.booleanFromQueryString = (name) => {
L.Util.setFromQueryString = (options, 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) => {
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) => {
const value = +L.Util.queryString(name)
if (!isNaN(value)) options[name] = value
if (!Number.isNaN(value)) {
options[name] = value
}
}
L.Util.setNullableBooleanFromQueryString = (options, name) => {
let value = L.Util.queryString(name)
if (typeof value !== 'undefined') {
if (value === 'null') value = null
else if (value === '0' || value === 'false') value = false
else value = true
if (value === 'null') {
value = null
} else if (value === '0' || value === 'false') {
value = false
} else {
value = true
}
options[name] = value
}
}
@ -83,13 +95,17 @@ L.DomUtil.createFieldset = (container, legend, options) => {
options = options || {}
const details = L.DomUtil.create('details', options.className || '', container)
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)
const fieldset = L.DomUtil.add('fieldset', '', details)
details.open = options.on === true
if (options.callback) {
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
@ -139,7 +155,9 @@ L.DomUtil.createButtonIcon = (parent, className, title, size = 16) => {
L.DomUtil.createTitle = (parent, text, className, tag = 'h3') => {
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)
return title
}
@ -192,8 +210,10 @@ L.DomUtil.after = (target, el) => {
// convert colour in range 0-255 to the modifier used within luminance calculation
L.DomUtil.colourMod = (colour) => {
const sRGB = colour / 255
let mod = Math.pow((sRGB + 0.055) / 1.055, 2.4)
if (sRGB < 0.03928) mod = sRGB / 12.92
let mod = ((sRGB + 0.055) / 1.055) ** 2.4
if (sRGB < 0.03928) {
mod = sRGB / 12.92
}
return mod
}
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) => {
// Return 0 for black and 1 for white
// bgcolor is a human color, it can be a any keyword (purple…)
if (typeof _CACHE_CONSTRAST[bgcolor] !== 'undefined') return _CACHE_CONSTRAST[bgcolor]
if (typeof _CACHE_CONSTRAST[bgcolor] !== 'undefined') {
return _CACHE_CONSTRAST[bgcolor]
}
let out = 0
let rgb = window.getComputedStyle(el).getPropertyValue('background-color')
rgb = L.DomUtil.RGBRegex.exec(rgb)
if (!rgb || rgb.length !== 4) return out
if (!rgb || rgb.length !== 4) {
return out
}
rgb = [
Number.parseInt(rgb[1], 10),
Number.parseInt(rgb[2], 10),
Number.parseInt(rgb[3], 10),
]
out = L.DomUtil.contrastWCAG21(rgb)
if (bgcolor) _CACHE_CONSTRAST[bgcolor] = out
if (bgcolor) {
_CACHE_CONSTRAST[bgcolor] = out
}
return out
}
L.DomEvent.once = (el, types, fn, context) => {
@ -251,9 +277,9 @@ L.DomEvent.once = (el, types, fn, context) => {
L.LatLng.prototype.isValid = function () {
return (
isFinite(this.lat) &&
Number.isFinite(this.lat) &&
Math.abs(this.lat) <= 90 &&
isFinite(this.lng) &&
Number.isFinite(this.lng) &&
Math.abs(this.lng) <= 180
)
}

View file

@ -12,7 +12,9 @@ U.DataLayerPermissions = L.Class.extend({
get: () => isDirty,
set: (status) => {
isDirty = status
if (status) this.datalayer.isDirty = status
if (status) {
this.datalayer.isDirty = status
}
},
})
} catch (e) {
@ -34,11 +36,11 @@ U.DataLayerPermissions = L.Class.extend({
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',
}),
form = builder.build()
})
const form = builder.build()
container.appendChild(form)
},
@ -49,7 +51,9 @@ U.DataLayerPermissions = L.Class.extend({
})
},
save: async function () {
if (!this.isDirty) return this.datalayer.map.continueSaving()
if (!this.isDirty) {
return this.datalayer.map.continueSaving()
}
const formData = new FormData()
formData.append('edit_status', this.options.edit_status)
const [data, response, error] = await this.datalayer.map.server.post(

View file

@ -15,7 +15,9 @@ U.FeatureMixin = {
onCommit: function () {
// 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.
if (this.datalayer.isRemoteLayer()) return
if (this.datalayer.isRemoteLayer()) {
return
}
this.sync.upsert(this.toGeoJSON())
},
@ -82,7 +84,7 @@ U.FeatureMixin = {
preInit: () => {},
isReadOnly: function () {
return this.datalayer && this.datalayer.isDataReadOnly()
return this.datalayer?.isDataReadOnly()
},
getSlug: function () {
@ -91,10 +93,11 @@ U.FeatureMixin = {
getPermalink: function () {
const slug = this.getSlug()
if (slug)
if (slug) {
return `${U.Utils.getBaseUrl()}?${U.Utils.buildQueryString({ feature: slug })}${
window.location.hash
}`
}
},
view: function (e) {
@ -139,7 +142,9 @@ U.FeatureMixin = {
},
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')
L.DomUtil.createTitle(
container,
@ -182,7 +187,9 @@ U.FeatureMixin = {
builder.helpers['properties.name'].input.focus()
})
this.map.editedFeature = this
if (!this.isOnScreen()) this.zoomTo(e)
if (!this.isOnScreen()) {
this.zoomTo(e)
}
},
getAdvancedEditActions: function (container) {
@ -192,7 +199,9 @@ U.FeatureMixin = {
L._('Delete'),
function (e) {
L.DomEvent.stop(e)
if (this.confirmDelete()) this.map.editPanel.close()
if (this.confirmDelete()) {
this.map.editPanel.close()
}
},
this
)
@ -238,19 +247,25 @@ U.FeatureMixin = {
endEdit: () => {},
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'
// Variables mode.
if (U.Utils.hasVar(key))
if (U.Utils.hasVar(key)) {
return U.Utils.greedyTemplate(key, this.extendedProperties())
}
// Simple mode.
return this.properties[key] || this.properties.title || fallback
},
hasPopupFooter: function () {
if (L.Browser.ielt9) return false
if (this.datalayer.isRemoteLayer() && this.datalayer.options.remoteData.dynamic)
if (L.Browser.ielt9) {
return false
}
if (this.datalayer.isRemoteLayer() && this.datalayer.options.remoteData.dynamic) {
return false
}
return this.map.getOption('displayPopupFooter')
},
@ -278,7 +293,9 @@ U.FeatureMixin = {
this.datalayer.removeLayer(this)
this.disconnectFromDataLayer(this.datalayer)
if (sync !== false) this.syncDelete()
if (sync !== false) {
this.syncDelete()
}
}
},
@ -312,7 +329,7 @@ U.FeatureMixin = {
// Retrocompat
if (this.properties._umap_options.clickable === 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.
if (U.Utils.hasVar(value)) {
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
},
zoomTo: function ({ easing, latlng, callback } = {}) {
if (easing === undefined) easing = this.map.getOption('easing')
if (callback) this.map.once('moveend', callback.call(this))
if (easing === undefined) {
easing = this.map.getOption('easing')
}
if (callback) {
this.map.once('moveend', callback.call(this))
}
if (easing) {
this.map.flyTo(this.getCenter(), this.getBestZoom())
} else {
@ -377,7 +400,7 @@ U.FeatureMixin = {
const properties = L.extend({}, this.properties)
properties._umap_options = L.extend({}, properties._umap_options)
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
},
@ -396,7 +419,7 @@ U.FeatureMixin = {
const geojson = this.parentClass.prototype.toGeoJSON.call(this)
geojson.properties = this.cloneProperties()
geojson.id = this.id
delete geojson.properties._storage_options
geojson.properties._storage_options = undefined
return geojson
},
@ -406,7 +429,9 @@ U.FeatureMixin = {
},
_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
if (!this.map.editEnabled) {
this.view(e)
@ -415,8 +440,11 @@ U.FeatureMixin = {
if (e.originalEvent.ctrlKey || e.originalEvent.metaKey) {
this.datalayer.edit(e)
} else {
if (this._toggleEditing) this._toggleEditing(e)
else this.edit(e)
if (this._toggleEditing) {
this._toggleEditing(e)
} else {
this.edit(e)
}
}
} else {
new L.Toolbar.Popup(e.latlng, {
@ -451,13 +479,14 @@ U.FeatureMixin = {
getContextMenuItems: function (e) {
const permalink = this.getPermalink()
let items = []
if (permalink)
if (permalink) {
items.push({
text: L._('Permalink'),
callback: () => {
window.open(permalink)
},
})
}
if (this.map.editEnabled && !this.isReadOnly()) {
items = items.concat(this.getContextMenuEditItems(e))
}
@ -468,7 +497,7 @@ U.FeatureMixin = {
let items = ['-']
if (this.map.editedFeature !== this) {
items.push({
text: L._('Edit this feature') + ' (⇧+Click)',
text: `${L._('Edit this feature')} (⇧+Click)`,
callback: this.edit,
context: this,
iconCls: 'umap-edit',
@ -505,7 +534,9 @@ U.FeatureMixin = {
},
resetTooltip: function () {
if (!this.hasGeom()) return
if (!this.hasGeom()) {
return
}
const displayName = this.getDisplayName(null)
let showLabel = this.getOption('showLabel')
const oldLabelHover = this.getOption('labelHover')
@ -515,18 +546,25 @@ U.FeatureMixin = {
interactive: this.getOption('labelInteractive'),
}
if (oldLabelHover && showLabel) showLabel = null // Retrocompat.
if (oldLabelHover && showLabel) {
showLabel = null // Retrocompat.
}
options.permanent = showLabel === true
this.unbindTooltip()
if ((showLabel === true || showLabel === null) && displayName)
if ((showLabel === true || showLabel === null) && displayName) {
this.bindTooltip(U.Utils.escapeHTML(displayName), options)
}
},
isFiltered: function () {
const filterKeys = this.datalayer.getFilterKeys()
const filter = this.map.browser.options.filter
if (filter && !this.matchFilter(filter, filterKeys)) return true
if (!this.matchFacets()) return true
if (filter && !this.matchFilter(filter, filterKeys)) {
return true
}
if (!this.matchFacets()) {
return true
}
return false
},
@ -537,8 +575,10 @@ U.FeatureMixin = {
}
keys = keys.split(',')
for (let i = 0, value; i < keys.length; i++) {
value = (this.properties[keys[i]] || '') + ''
if (value.toLowerCase().indexOf(filter) !== -1) return true
value = `${this.properties[keys[i]] || ''}`
if (value.toLowerCase().indexOf(filter) !== -1) {
return true
}
}
return false
},
@ -553,12 +593,18 @@ U.FeatureMixin = {
case 'date':
case 'datetime':
case 'number':
if (!isNaN(min) && !isNaN(value) && min > value) return false
if (!isNaN(max) && !isNaN(value) && max < value) return false
if (!Number.isNaN(min) && !Number.isNaN(value) && min > value) {
return false
}
if (!Number.isNaN(max) && !Number.isNaN(value) && max < value) {
return false
}
break
default:
value = value || L._('<empty value>')
if (choices?.length && !choices.includes(value)) return false
if (choices?.length && !choices.includes(value)) {
return false
}
break
}
}
@ -578,8 +624,8 @@ U.FeatureMixin = {
clone: function () {
const geoJSON = this.toGeoJSON()
delete geoJSON.id
delete geoJSON.properties.id
geoJSON.id = undefined
geoJSON.properties.id = undefined
const layer = this.datalayer.geojsonToFeatures(geoJSON)
layer.isDirty = true
layer.edit()
@ -590,8 +636,12 @@ U.FeatureMixin = {
// Include context properties
properties = this.map.getGeoContext()
const locale = L.getLocale()
if (locale) properties.locale = locale
if (L.lang) properties.lang = L.lang
if (locale) {
properties.locale = locale
}
if (L.lang) {
properties.lang = L.lang
}
properties.rank = this.getRank() + 1
if (this._map && this.hasGeom()) {
center = this.getCenter()
@ -638,7 +688,9 @@ U.Marker = L.Marker.extend({
this
)
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._popupHandlersAdded = true // prevent Leaflet from binding event on bindPopup
this.on('popupopen', this.highlight)
@ -650,11 +702,7 @@ U.Marker = L.Marker.extend({
},
_onMouseOut: function () {
if (
this.dragging &&
this.dragging._draggable &&
!this.dragging._draggable._moving
) {
if (this.dragging?._draggable && !this.dragging._draggable._moving) {
// Do not disable if the mouse went out while dragging
this._disableDragging()
}
@ -663,7 +711,9 @@ U.Marker = L.Marker.extend({
_enableDragging: function () {
// TODO: start dragging after 1 second on mouse down
if (this.map.editEnabled) {
if (!this.editEnabled()) this.enableEdit()
if (!this.editEnabled()) {
this.enableEdit()
}
// Enabling dragging on the marker override the Draggable._OnDown
// event, which, as it stopPropagation, refrain the call of
// _onDown with map-pane element, which is responsible to
@ -675,14 +725,16 @@ U.Marker = L.Marker.extend({
_disableDragging: function () {
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
this.disableEdit()
}
},
_redraw: function () {
if (this.datalayer && this.datalayer.isVisible()) {
if (this.datalayer?.isVisible()) {
this._initIcon()
this.update()
}
@ -697,8 +749,8 @@ U.Marker = L.Marker.extend({
},
_getTooltipAnchor: function () {
const anchor = this.options.icon.options.tooltipAnchor.clone(),
direction = this.getOption('labelDirection')
const anchor = this.options.icon.options.tooltipAnchor.clone()
const direction = this.getOption('labelDirection')
if (direction === 'left') {
anchor.x *= -1
} else if (direction === 'bottom') {
@ -716,7 +768,9 @@ U.Marker = L.Marker.extend({
},
_getIconUrl: function (name) {
if (typeof name === 'undefined') name = 'icon'
if (typeof name === 'undefined') {
name = 'icon'
}
return this.getOption(`${name}Url`)
},
@ -797,7 +851,9 @@ U.PathMixin = {
edit: function (e) {
if (this.map.editEnabled) {
if (!this.editEnabled()) this.enableEdit()
if (!this.editEnabled()) {
this.enableEdit()
}
U.FeatureMixin.edit.call(this, e)
}
},
@ -847,13 +903,16 @@ U.PathMixin = {
option = this.styleOptions[idx]
options[option] = this.getDynamicOption(option)
}
if (options.interactive) this.options.pointerEvents = 'visiblePainted'
else this.options.pointerEvents = 'stroke'
if (options.interactive) {
this.options.pointerEvents = 'visiblePainted'
} else {
this.options.pointerEvents = 'stroke'
}
this.parentClass.prototype.setStyle.call(this, options)
},
_redraw: function () {
if (this.datalayer && this.datalayer.isVisible()) {
if (this.datalayer?.isVisible()) {
this.setStyle()
this.resetTooltip()
}
@ -867,14 +926,18 @@ U.PathMixin = {
// this.map.on('showmeasure', this.showMeasureTooltip, this);
// this.map.on('hidemeasure', this.removeTooltip, this);
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()
},
onRemove: function (map) {
// this.map.off('showmeasure', this.showMeasureTooltip, 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)
},
@ -896,7 +959,7 @@ U.PathMixin = {
},
_onMouseOver: function () {
if (this.map.measureTools && this.map.measureTools.enabled()) {
if (this.map.measureTools?.enabled()) {
this.map.tooltip.open({ content: this.getMeasure(), anchor: this })
} else if (this.map.editEnabled && !this.map.editedFeature) {
this.map.tooltip.open({ content: L._('Click to edit'), anchor: this })
@ -914,22 +977,32 @@ U.PathMixin = {
},
_onDrag: function () {
if (this._tooltip) this._tooltip.setLatLng(this.getCenter())
if (this._tooltip) {
this._tooltip.setLatLng(this.getCenter())
}
},
transferShape: function (at, to) {
const shape = this.enableEdit().deleteShapeAt(at)
this.disableEdit()
if (!shape) return
if (!shape) {
return
}
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) {
if (!this.isMulti()) return
if (!this.isMulti()) {
return
}
const shape = this.enableEdit().deleteShapeAt(at)
this.disableEdit()
if (!shape) return
if (!shape) {
return
}
const properties = this.cloneProperties()
const other = new (this instanceof U.Polyline ? U.Polyline : U.Polygon)(
this.map,
@ -1033,7 +1106,9 @@ U.PathMixin = {
} else {
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),
]
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)
polygon.edit()
@ -1142,11 +1217,11 @@ U.Polyline = L.Polyline.extend({
from.reverse()
toMerge = [from, to]
}
const a = toMerge[0],
b = toMerge[1],
p1 = this.map.latLngToContainerPoint(a[a.length - 1]),
p2 = this.map.latLngToContainerPoint(b[0]),
tolerance = 5 // px on screen
const a = toMerge[0]
const b = toMerge[1]
const p1 = this.map.latLngToContainerPoint(a[a.length - 1])
const p2 = this.map.latLngToContainerPoint(b[0])
const tolerance = 5 // px on screen
if (Math.abs(p1.x - p2.x) <= tolerance && Math.abs(p1.y - p2.y) <= tolerance) {
a.pop()
}
@ -1154,14 +1229,20 @@ U.Polyline = L.Polyline.extend({
},
mergeShapes: function () {
if (!this.isMulti()) return
if (!this.isMulti()) {
return
}
const latlngs = this.getLatLngs()
if (!latlngs.length) return
if (!latlngs.length) {
return
}
while (latlngs.length > 1) {
latlngs.splice(0, 2, this._mergeShapes(latlngs[1], latlngs[0]))
}
this.setLatLngs(latlngs[0])
if (!this.editEnabled()) this.edit()
if (!this.editEnabled()) {
this.edit()
}
this.editor.reset()
this.isDirty = true
},
@ -1171,11 +1252,13 @@ U.Polyline = L.Polyline.extend({
},
getVertexActions: function (e) {
const actions = U.FeatureMixin.getVertexActions.call(this, e),
index = e.vertex.getIndex()
if (index === 0 || index === e.vertex.getLastIndex())
const actions = U.FeatureMixin.getVertexActions.call(this, e)
const index = e.vertex.getIndex()
if (index === 0 || index === e.vertex.getLastIndex()) {
actions.push(U.ContinueLineAction)
else actions.push(U.SplitLineAction)
} else {
actions.push(U.SplitLineAction)
}
return actions
},
})
@ -1214,8 +1297,8 @@ U.Polygon = L.Polygon.extend({
},
getContextMenuEditItems: function (e) {
const items = U.PathMixin.getContextMenuEditItems.call(this, e),
shape = this.shapeAt(e.latlng)
const items = U.PathMixin.getContextMenuEditItems.call(this, e)
const shape = this.shapeAt(e.latlng)
// No multi and no holes.
if (shape && !this.isMulti() && (L.LineUtil.isFlat(shape) || shape.length === 1)) {
items.push({
@ -1238,8 +1321,8 @@ U.Polygon = L.Polygon.extend({
toPolyline: function () {
const geojson = this.toGeoJSON()
delete geojson.id
delete geojson.properties.id
geojson.id = undefined
geojson.properties.id = undefined
geojson.geometry.type = 'LineString'
geojson.geometry.coordinates = U.Utils.flattenCoordinates(
geojson.geometry.coordinates

View file

@ -60,9 +60,11 @@ L.FormBuilder.Element.include({
},
get: function (own) {
if (!this.options.inheritable || own) return this.builder.getter(this.field)
const path = this.field.split('.'),
key = path[path.length - 1]
if (!this.options.inheritable || own) {
return this.builder.getter(this.field)
}
const path = this.field.split('.')
const key = path[path.length - 1]
return this.obj.getOption(key)
},
@ -70,9 +72,9 @@ L.FormBuilder.Element.include({
if (this.options.label) {
this.label = L.DomUtil.create('label', '', this.getLabelParent())
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)
else if (this.options.helpTooltip) {
} else if (this.options.helpTooltip) {
const info = L.DomUtil.create('i', 'info', this.label)
L.DomEvent.on(
info,
@ -97,7 +99,9 @@ L.FormBuilder.Select.include({
},
getDefault: function () {
if (this.options.inheritable) return undefined
if (this.options.inheritable) {
return undefined
}
return this.getOptions()[0][0]
},
})
@ -309,8 +313,11 @@ L.FormBuilder.ColorPicker = L.FormBuilder.Input.extend({
},
spreadColor: function () {
if (this.input.value) this.input.style.backgroundColor = this.input.value
else this.input.style.backgroundColor = 'inherit'
if (this.input.value) {
this.input.style.backgroundColor = this.input.value
} else {
this.input.style.backgroundColor = 'inherit'
}
},
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(
this.builder.map.options.urls.pictogram_list_json
)
if (!error) this.pictogram_list = pictogram_list
if (!error) {
this.pictogram_list = pictogram_list
}
this.buildTabs()
const value = this.value()
if (U.Icon.RECENT.length) this.showRecentTab()
else if (!value || U.Utils.isPath(value)) this.showSymbolsTab()
else if (U.Utils.isRemoteUrl(value) || U.Utils.isDataImage(value)) this.showURLTab()
else this.showCharsTab()
if (U.Icon.RECENT.length) {
this.showRecentTab()
} else if (!value || U.Utils.isPath(value)) {
this.showSymbolsTab()
} else if (U.Utils.isRemoteUrl(value) || U.Utils.isDataImage(value)) {
this.showURLTab()
} else {
this.showCharsTab()
}
const closeButton = L.DomUtil.createButton(
'button action-button',
this.footer,
@ -491,8 +505,11 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
this.body.innerHTML = ''
this.tabs.innerHTML = ''
this.footer.innerHTML = ''
if (this.isDefault()) this.undefine(e)
else this.updatePreview()
if (this.isDefault()) {
this.undefine(e)
} else {
this.updatePreview()
}
},
this
)
@ -514,13 +531,8 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
this
)
}
const symbol = L.DomUtil.add(
'button',
'flat tab-symbols',
this.tabs,
L._('Symbol')
),
char = L.DomUtil.add(
const symbol = L.DomUtil.add('button', 'flat tab-symbols', this.tabs, L._('Symbol'))
const char = L.DomUtil.add(
'button',
'flat tab-chars',
this.tabs,
@ -554,7 +566,9 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
updatePreview: function () {
this.buttons.innerHTML = ''
if (this.isDefault()) return
if (this.isDefault()) {
return
}
if (!U.Utils.hasVar(this.value())) {
// Do not try to render URL with variables
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) {
const baseClass = 'umap-pictogram-choice',
value = pictogram.src,
search = U.Utils.normalize(this.searchInput.value),
title = pictogram.attribution
const baseClass = 'umap-pictogram-choice'
const value = pictogram.src
const search = U.Utils.normalize(this.searchInput.value)
const title = pictogram.attribution
? `${pictogram.name} — © ${pictogram.attribution}`
: pictogram.name || pictogram.src
if (search && U.Utils.normalize(title).indexOf(search) === -1) return
const className = value === this.value() ? `${baseClass} selected` : baseClass,
container = L.DomUtil.create('div', className, parent)
if (search && U.Utils.normalize(title).indexOf(search) === -1) {
return
}
const className = value === this.value() ? `${baseClass} selected` : baseClass
const container = L.DomUtil.create('div', className, parent)
U.Icon.makeIconElement(value, container)
container.title = title
L.DomEvent.on(
@ -606,13 +622,17 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
addCategory: function (items, name) {
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)
let status = false
for (const item of items) {
status = this.addIconPreview(item, grid) || status
}
if (status) this.grid.appendChild(parent)
if (status) {
this.grid.appendChild(parent)
}
},
buildSymbolsList: function () {
@ -653,7 +673,9 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
},
showRecentTab: function () {
if (!U.Icon.RECENT.length) return
if (!U.Icon.RECENT.length) {
return
}
this.openTab('recent')
this.addGrid(this.buildRecentList)
this.buildRecentList()
@ -687,11 +709,15 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
buildInput: function (parent, value) {
const input = L.DomUtil.create('input', 'blur', 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', () => {
// Do not clear this.input when focus-blur
// empty input
if (input.value === value) return
if (input.value === value) {
return
}
this.input.value = input.value
this.sync()
})
@ -701,7 +727,9 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
unselectAll: (container) => {
const els = container.querySelectorAll('div.selected')
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({
getParentNode: function () {
L.FormBuilder.CheckBox.prototype.getParentNode.call(this)
if (this.options.inheritable) return this.quickContainer
if (this.options.inheritable) {
return this.quickContainer
}
return this.extendedContainer
},
build: function () {
L.FormBuilder.CheckBox.prototype.build.apply(this)
if (this.options.inheritable)
if (this.options.inheritable) {
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')
const id = `${this.builder.options.id || Date.now()}.${this.name}`
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.appendChild(this.label)
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.forEach((value) => this.buildLi(value))
},
@ -758,7 +790,7 @@ L.FormBuilder.FacetSearchChoices = L.FormBuilder.FacetSearchBase.extend({
input.type = this.type
input.name = `${this.type}_${this.name}`
input.checked = this.get()['choices'].includes(value)
input.checked = this.get().choices.includes(value)
input.dataset.value = value
L.DomEvent.on(input, 'change', (e) => this.sync())
@ -845,13 +877,13 @@ L.FormBuilder.MinMaxBase = L.FormBuilder.FacetSearchBase.extend({
isMinModified: function () {
const default_ = this.minInput.getAttribute('value')
const current = this.minInput.value
return current != default_
return current !== default_
},
isMaxModified: function () {
const default_ = this.maxInput.getAttribute('value')
const current = this.maxInput.value
return current != default_
return current !== default_
},
toJS: function () {
@ -879,7 +911,9 @@ L.FormBuilder.FacetSearchDate = L.FormBuilder.MinMaxBase.extend({
prepareForHTML: function (value) {
// Value must be in local time
if (isNaN(value)) return
if (Number.isNaN(value)) {
return
}
return this.toLocaleDateTime(value).toISOString().substr(0, 10)
},
@ -891,7 +925,9 @@ L.FormBuilder.FacetSearchDateTime = L.FormBuilder.FacetSearchDate.extend({
prepareForHTML: function (value) {
// Value must be in local time
if (isNaN(value)) return
if (Number.isNaN(value)) {
return
}
return this.toLocaleDateTime(value).toISOString().slice(0, -1)
},
})
@ -902,7 +938,9 @@ L.FormBuilder.MultiChoice = L.FormBuilder.Element.extend({
clear: function () {
const checked = this.container.querySelector('input[type="radio"]:checked')
if (checked) checked.checked = false
if (checked) {
checked.checked = false
}
},
fetch: function () {
@ -920,7 +958,9 @@ L.FormBuilder.MultiChoice = L.FormBuilder.Element.extend({
value: function () {
const checked = this.container.querySelector('input[type="radio"]:checked')
if (checked) return checked.value
if (checked) {
return checked.value
}
},
getChoices: function () {
@ -992,8 +1032,9 @@ L.FormBuilder.DataLayersControl = L.FormBuilder.TernaryChoices.extend({
toJS: function () {
let value = this.value()
if (value !== 'expanded')
if (value !== 'expanded') {
value = L.FormBuilder.TernaryChoices.prototype.toJS.call(this)
}
return value
},
})
@ -1037,10 +1078,11 @@ L.FormBuilder.ManageOwner = L.FormBuilder.Element.extend({
}
this.autocomplete = new U.AjaxAutocomplete(this.parentNode, options)
const owner = this.toHTML()
if (owner)
if (owner) {
this.autocomplete.displaySelected({
item: { value: owner.id, label: owner.name },
})
}
},
value: function () {
@ -1066,11 +1108,13 @@ L.FormBuilder.ManageEditors = L.FormBuilder.Element.extend({
}
this.autocomplete = new U.AjaxAutocompleteMultiple(this.parentNode, options)
this._values = this.toHTML()
if (this._values)
for (let i = 0; i < this._values.length; i++)
if (this._values) {
for (let i = 0; i < this._values.length; i++) {
this.autocomplete.displaySelected({
item: { value: this._values[i].id, label: this._values[i].name },
})
}
}
},
value: function () {
@ -1103,13 +1147,19 @@ U.FormBuilder = L.FormBuilder.extend({
computeDefaultOptions: function () {
for (const [key, schema] of Object.entries(U.SCHEMA)) {
if (schema.type === Boolean) {
if (schema.nullable) schema.handler = 'NullableChoices'
else schema.handler = 'Switch'
if (schema.nullable) {
schema.handler = 'NullableChoices'
} else {
schema.handler = 'Switch'
}
} else if (schema.type === 'Text') {
schema.handler = 'Textarea'
} else if (schema.type === Number) {
if (schema.step) schema.handler = 'Range'
else schema.handler = 'IntInput'
if (schema.step) {
schema.handler = 'Range'
} else {
schema.handler = 'IntInput'
}
} else if (schema.choices) {
const text_length = schema.choices.reduce(
(acc, [value, label]) => acc + label.length,
@ -1138,7 +1188,7 @@ U.FormBuilder = L.FormBuilder.extend({
}
}
// FormBuilder use this key for the input type itself
delete schema.type
schema.type = undefined
this.defaultOptions[key] = schema
}
},

View file

@ -12,14 +12,18 @@ U.Icon = L.DivIcon.extend({
options = L.Util.extend({}, default_options, options)
L.Icon.prototype.initialize.call(this, options)
this.feature = this.options.feature
if (this.feature && this.feature.isReadOnly()) {
if (this.feature?.isReadOnly()) {
this.options.className += ' readonly'
}
},
_setRecent: (url) => {
if (U.Utils.hasVar(url)) return
if (url === U.SCHEMA.iconUrl.default) return
if (U.Utils.hasVar(url)) {
return
}
if (url === U.SCHEMA.iconUrl.default) {
return
}
if (U.Icon.RECENT.indexOf(url) === -1) {
U.Icon.RECENT.push(url)
}
@ -27,7 +31,7 @@ U.Icon = L.DivIcon.extend({
_getIconUrl: function (name) {
let url
if (this.feature && this.feature._getIconUrl(name)) {
if (this.feature?._getIconUrl(name)) {
url = this.feature._getIconUrl(name)
this._setRecent(url)
} else {
@ -38,14 +42,20 @@ U.Icon = L.DivIcon.extend({
_getColor: function () {
let color
if (this.feature) color = this.feature.getDynamicOption('color')
else if (this.options.color) color = this.options.color
else color = this.map.getDefaultOption('color')
if (this.feature) {
color = this.feature.getDynamicOption('color')
} else if (this.options.color) {
color = this.options.color
} else {
color = this.map.getDefaultOption('color')
}
return color
},
_getOpacity: function () {
if (this.feature) return this.feature.getOption('iconOpacity')
if (this.feature) {
return this.feature.getOption('iconOpacity')
}
return this.map.getDefaultOption('iconOpacity')
},
@ -70,8 +80,8 @@ U.Icon.Default = U.Icon.extend({
_setIconStyles: function (img, name) {
U.Icon.prototype._setIconStyles.call(this, img, name)
const color = this._getColor(),
opacity = this._getOpacity()
const color = this._getColor()
const opacity = this._getOpacity()
this.elements.container.style.backgroundColor = color
this.elements.arrow.style.borderTopColor = color
this.elements.container.style.opacity = opacity
@ -185,10 +195,10 @@ U.Icon.Cluster = L.DivIcon.extend({
},
createIcon: function () {
const container = L.DomUtil.create('div', 'leaflet-marker-icon marker-cluster'),
div = L.DomUtil.create('div', '', container),
span = L.DomUtil.create('span', '', div),
backgroundColor = this.datalayer.getColor()
const container = L.DomUtil.create('div', 'leaflet-marker-icon marker-cluster')
const div = L.DomUtil.create('div', '', container)
const span = L.DomUtil.create('span', '', div)
const backgroundColor = this.datalayer.getColor()
span.textContent = this.cluster.getChildCount()
div.style.backgroundColor = backgroundColor
return container
@ -197,7 +207,7 @@ U.Icon.Cluster = L.DivIcon.extend({
computeTextColor: function (el) {
let color
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
}
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
* parent background color
*/
if (!icon) return
if (!icon) {
return
}
if (L.DomUtil.contrastedColor(parent, bgcolor)) {
// Decide whether to switch svg to white or not, but do it

View file

@ -34,11 +34,15 @@ U.Map = L.Map.extend({
this.sync = this.sync_engine.proxy(this)
// Locale name (pt_PT, en_US…)
// 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…)
// 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)
// Prevent default creation of controls
@ -49,10 +53,14 @@ U.Map = L.Map.extend({
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
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.panel = new U.Panel(this)
@ -99,16 +107,12 @@ U.Map = L.Map.extend({
}
// Retrocompat
if (
this.options.slideshow &&
this.options.slideshow.delay &&
this.options.slideshow.active === undefined
) {
if (this.options.slideshow?.delay && this.options.slideshow.active === undefined) {
this.options.slideshow.active = true
}
if (this.options.advancedFilterKey) {
this.options.facetKey = this.options.advancedFilterKey
delete this.options.advancedFilterKey
this.options.advancedFilterKey = undefined
}
// Global storage for retrieving datalayers and features
@ -134,14 +138,14 @@ U.Map = L.Map.extend({
if (!this.options.onLoadPanel) {
this.options.onLoadPanel = 'caption'
}
delete this.options.displayCaptionOnLoad
this.options.displayCaptionOnLoad = undefined
}
if (this.options.displayDataBrowserOnLoad) {
// Retrocompat
if (!this.options.onLoadPanel) {
this.options.onLoadPanel = 'databrowser'
}
delete this.options.displayDataBrowserOnLoad
this.options.displayDataBrowserOnLoad = undefined
}
if (this.options.datalayersControl === 'expanded') {
this.options.onLoadPanel = 'datalayers'
@ -165,7 +169,9 @@ U.Map = L.Map.extend({
this.on(
'baselayerchange',
function (e) {
if (this._controls.miniMap) this._controls.miniMap.onMainMapBaseLayerChange(e)
if (this._controls.miniMap) {
this._controls.miniMap.onMainMapBaseLayerChange(e)
}
},
this
)
@ -211,8 +217,10 @@ U.Map = L.Map.extend({
},
initSyncEngine: async function () {
if (this.options.websocketEnabled == false) return
if (this.options.syncEnabled != true) {
if (this.options.websocketEnabled === false) {
return
}
if (this.options.syncEnabled !== true) {
this.sync.stop()
} else {
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)) {
switch (schema.type) {
case Boolean:
if (schema.nullable) L.Util.setNullableBooleanFromQueryString(options, key)
else L.Util.setBooleanFromQueryString(options, key)
if (schema.nullable) {
L.Util.setNullableBooleanFromQueryString(options, key)
} else {
L.Util.setBooleanFromQueryString(options, key)
}
break
case Number:
L.Util.setNumberFromQueryString(options, key)
@ -297,7 +308,9 @@ U.Map = L.Map.extend({
},
setViewFromQueryString: function () {
if (this.options.noControl) return
if (this.options.noControl) {
return
}
this.initCaptionBar()
if (L.Util.queryString('share')) {
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
// take precedence.
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 (this.hasEditMode()) this.enableEdit()
if (this.hasEditMode()) {
this.enableEdit()
}
// Sometimes users share the ?edit link by mistake, let's remove
// this search parameter from URL to prevent this
const url = new URL(window.location)
@ -388,7 +405,9 @@ U.Map = L.Map.extend({
this._controls.search = new U.SearchControl()
this._controls.embed = new L.Control.Embed(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({
position: 'topleft',
widgetOptions: {
@ -401,8 +420,11 @@ U.Map = L.Map.extend({
this._controls.more = new U.MoreControls()
this._controls.scale = L.control.scale()
this._controls.permanentCredit = new U.PermanentCreditsControl(this)
if (this.options.scrollWheelZoom) this.scrollWheelZoom.enable()
else this.scrollWheelZoom.disable()
if (this.options.scrollWheelZoom) {
this.scrollWheelZoom.enable()
} else {
this.scrollWheelZoom.disable()
}
this.browser = new U.Browser(this)
this.facets = new U.Facets(this)
this.caption = new U.Caption(this)
@ -414,16 +436,16 @@ U.Map = L.Map.extend({
},
renderControls: function () {
const hasSlideshow = Boolean(
this.options.slideshow && this.options.slideshow.active
)
const hasSlideshow = Boolean(this.options.slideshow?.active)
const barEnabled = this.options.captionBar || hasSlideshow
document.body.classList.toggle('umap-caption-bar-enabled', barEnabled)
document.body.classList.toggle('umap-slideshow-enabled', hasSlideshow)
for (const control of Object.values(this._controls)) {
this.removeControl(control)
}
if (this.options.noControl) return
if (this.options.noControl) {
return
}
this._controls.attribution = new U.AttributionControl().addTo(this)
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++) {
name = this.HIDDABLE_CONTROLS[i]
status = this.getOption(`${name}Control`)
if (status === false) continue
control = this._controls[name]
if (!control) continue
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 (status === false) {
continue
}
control = this._controls[name]
if (!control) {
continue
}
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()
},
@ -474,7 +510,9 @@ U.Map = L.Map.extend({
this.datalayersLoaded = true
this.fire('datalayersloaded')
for (const datalayer of Object.values(this.datalayers)) {
if (datalayer.showAtLoad()) await datalayer.show()
if (datalayer.showAtLoad()) {
await datalayer.show()
}
}
this.dataloaded = true
this.fire('dataloaded')
@ -486,14 +524,18 @@ U.Map = L.Map.extend({
this.datalayers_index = []
for (let i = 0; i < panes.children.length; 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.onDataLayersChanged()
},
onDataLayersChanged: function () {
if (this.browser) this.browser.update()
if (this.browser) {
this.browser.update()
}
this.caption.refresh()
},
@ -557,7 +599,9 @@ U.Map = L.Map.extend({
}
// 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') {
L.DomEvent.stop(e)
@ -565,7 +609,9 @@ U.Map = L.Map.extend({
}
/* Edit mode only shortcuts */
if (!this.hasEditMode()) return
if (!this.hasEditMode()) {
return
}
// Edit mode Off
if (!this.editEnabled) {
@ -582,13 +628,19 @@ U.Map = L.Map.extend({
let used = true
switch (e.key) {
case 'e':
if (!this.isDirty) this.disableEdit()
if (!this.isDirty) {
this.disableEdit()
}
break
case 's':
if (this.isDirty) this.save()
if (this.isDirty) {
this.save()
}
break
case 'z':
if (this.isDirty) this.askForReset()
if (this.isDirty) {
this.askForReset()
}
break
case 'm':
this.editTools.startMarker()
@ -611,7 +663,9 @@ U.Map = L.Map.extend({
default:
used = false
}
if (used) L.DomEvent.stop(e)
if (used) {
L.DomEvent.stop(e)
}
}
L.DomEvent.addListener(document, 'keydown', globalShortcuts, this)
},
@ -629,17 +683,15 @@ U.Map = L.Map.extend({
this.options.tilelayer.attribution = props.attribution
}
}
if (
this.options.tilelayer &&
this.options.tilelayer.url_template &&
this.options.tilelayer.attribution
) {
if (this.options.tilelayer?.url_template && this.options.tilelayer.attribution) {
this.customTilelayer = this.createTileLayer(this.options.tilelayer)
this.selectTileLayer(this.customTilelayer)
} else {
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),
@ -656,13 +708,13 @@ U.Map = L.Map.extend({
}
this.selected_tilelayer = tilelayer
if (
!isNaN(this.selected_tilelayer.options.minZoom) &&
!Number.isNaN(this.selected_tilelayer.options.minZoom) &&
this.getZoom() < this.selected_tilelayer.options.minZoom
) {
this.setZoom(this.selected_tilelayer.options.minZoom)
}
if (
!isNaN(this.selected_tilelayer.options.maxZoom) &&
!Number.isNaN(this.selected_tilelayer.options.maxZoom) &&
this.getZoom() > 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,
// while adding selected/custom on top of the list
const url = layer.options.url_template
if (urls.indexOf(url) !== -1) return
if (urls.indexOf(url) !== -1) {
return
}
callback.call(context, layer)
urls.push(url)
}
if (this.selected_tilelayer) callOne(this.selected_tilelayer)
if (this.customTilelayer) callOne(this.customTilelayer)
if (this.selected_tilelayer) {
callOne(this.selected_tilelayer)
}
if (this.customTilelayer) {
callOne(this.customTilelayer)
}
this.tilelayers.forEach(callOne)
},
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)
try {
this.addLayer(overlay)
if (this.overlay) this.removeLayer(this.overlay)
if (this.overlay) {
this.removeLayer(this.overlay)
}
this.overlay = overlay
} catch (e) {
this.removeLayer(overlay)
@ -713,19 +775,25 @@ U.Map = L.Map.extend({
hasData: function () {
for (const datalayer of this.datalayers_index) {
if (datalayer.hasData()) return true
if (datalayer.hasData()) {
return true
}
}
},
fitDataBounds: function () {
const bounds = this.getLayersBounds()
if (!this.hasData() || !bounds.isValid()) return false
if (!this.hasData() || !bounds.isValid()) {
return false
}
this.fitBounds(bounds)
},
initCenter: function () {
this._setDefaultCenter()
if (this.options.hash) this.addHash()
if (this.options.hash) {
this.addHash()
}
if (this.options.hash && this._hash.parseHash(location.hash)) {
// FIXME An invalid hash will cause the load to fail
this._hash.update()
@ -735,7 +803,9 @@ U.Map = L.Map.extend({
this.onceDataLoaded(this.fitDataBounds)
} else if (this.options.defaultView === 'latest') {
this.onceDataLoaded(() => {
if (!this.hasData()) return
if (!this.hasData()) {
return
}
const datalayer = this.firstVisibleDatalayer()
let feature
if (datalayer) {
@ -759,11 +829,16 @@ U.Map = L.Map.extend({
},
handleLimitBounds: function () {
const south = Number.parseFloat(this.options.limitBounds.south),
west = Number.parseFloat(this.options.limitBounds.west),
north = Number.parseFloat(this.options.limitBounds.north),
east = Number.parseFloat(this.options.limitBounds.east)
if (!isNaN(south) && !isNaN(west) && !isNaN(north) && !isNaN(east)) {
const south = Number.parseFloat(this.options.limitBounds.south)
const west = Number.parseFloat(this.options.limitBounds.west)
const north = Number.parseFloat(this.options.limitBounds.north)
const east = Number.parseFloat(this.options.limitBounds.east)
if (
!Number.isNaN(south) &&
!Number.isNaN(west) &&
!Number.isNaN(north) &&
!Number.isNaN(east)
) {
const bounds = L.latLngBounds([
[south, west],
[north, east],
@ -793,7 +868,7 @@ U.Map = L.Map.extend({
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}`
const datalayer = new U.DataLayer(this, options, sync)
@ -808,14 +883,18 @@ U.Map = L.Map.extend({
datalayer.edit()
},
getDefaultOption: (option) => U.SCHEMA[option] && U.SCHEMA[option].default,
getDefaultOption: (option) => U.SCHEMA[option]?.default,
getOption: function (option, feature) {
if (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)
},
@ -836,11 +915,12 @@ U.Map = L.Map.extend({
this.options.tilelayer = tilelayer.toJSON()
this.isDirty = true
}
if (this._controls.tilelayersChooser)
if (this._controls.tilelayersChooser) {
this._controls.tilelayersChooser.openSwitcher({
callback: callback,
className: 'dark',
})
}
},
toGeoJSON: function () {
@ -859,7 +939,9 @@ U.Map = L.Map.extend({
eachFeature: function (callback, context) {
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') {
this.importFromFile(file, 'umap')
} else {
if (!layer) layer = this.createDataLayer({ name: file.name })
if (!layer) {
layer = this.createDataLayer({ name: file.name })
}
layer.importFromFile(file, type)
}
},
importFromUrl: async function (uri) {
const response = await this.request.get(uri)
if (response && response.ok) {
if (response?.ok) {
this.importRaw(await response.text())
}
},
@ -896,15 +980,19 @@ U.Map = L.Map.extend({
for (const option of Object.keys(U.SCHEMA)) {
if (typeof importedData.properties[option] !== 'undefined') {
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) => {
if (!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
const dataLayer = this.createDataLayer(geojson._umap_options)
@ -915,7 +1003,9 @@ U.Map = L.Map.extend({
this.renderControls()
this.handleLimitBounds()
this.eachDataLayer((datalayer) => {
if (mustReindex) datalayer.reindex()
if (mustReindex) {
datalayer.reindex()
}
datalayer.redraw()
})
this.fire('postsync')
@ -952,7 +1042,9 @@ U.Map = L.Map.extend({
eachDataLayerReverse: function (method, context, filter) {
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])
}
},
@ -967,9 +1059,10 @@ U.Map = L.Map.extend({
findDataLayer: function (method, context) {
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]
}
}
},
backup: function () {
@ -978,11 +1071,15 @@ U.Map = L.Map.extend({
},
reset: function () {
if (this.editTools) this.editTools.stopDrawing()
if (this.editTools) {
this.editTools.stopDrawing()
}
this.resetOptions()
this.datalayers_index = [].concat(this._datalayers_index_bk)
this.dirty_datalayers.slice().forEach((datalayer) => {
if (datalayer.isDeleted) datalayer.connectToMap()
if (datalayer.isDeleted) {
datalayer.connectToMap()
}
datalayer.reset()
})
this.ensurePanesOrder()
@ -1011,8 +1108,11 @@ U.Map = L.Map.extend({
},
continueSaving: function () {
if (this.dirty_datalayers.length) this.dirty_datalayers[0].save()
else this.fire('saved')
if (this.dirty_datalayers.length) {
this.dirty_datalayers[0].save()
} else {
this.fire('saved')
}
},
exportOptions: function () {
@ -1085,8 +1185,12 @@ U.Map = L.Map.extend({
},
save: function () {
if (!this.isDirty) return
if (this._default_extent) this._setCenterAndZoom()
if (!this.isDirty) {
return
}
if (this._default_extent) {
this._setCenterAndZoom()
}
this.backup()
this.once('saved', () => {
this.isDirty = false
@ -1126,7 +1230,9 @@ U.Map = L.Map.extend({
firstVisibleDatalayer: function () {
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)
// cf https://github.com/umap-project/umap/issues/585
defaultEditDataLayer: function () {
let datalayer, fallback
let datalayer
let fallback
datalayer = this.lastUsedDataLayer
if (
datalayer &&
@ -1147,10 +1254,14 @@ U.Map = L.Map.extend({
datalayer = this.findDataLayer((datalayer) => {
if (!datalayer.isDataReadOnly() && datalayer.isBrowsable()) {
fallback = datalayer
if (datalayer.isVisible()) return true
if (datalayer.isVisible()) {
return true
}
}
})
if (datalayer) return datalayer
if (datalayer) {
return datalayer
}
if (fallback) {
// No datalayer visible, let's force one
fallback.show()
@ -1160,7 +1271,7 @@ U.Map = L.Map.extend({
},
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) {
@ -1340,7 +1451,6 @@ U.Map = L.Map.extend({
'options.overlay.url_template',
{
handler: 'BlurInput',
helpText: `${L._('Supported scheme')}: http://{s}.domain.com/{z}/{x}/{y}.png`,
placeholder: 'url',
helpText: L._('Background overlay url'),
type: 'url',
@ -1522,8 +1632,12 @@ U.Map = L.Map.extend({
},
editCaption: function () {
if (!this.editEnabled) return
if (this.options.editMode !== 'advanced') return
if (!this.editEnabled) {
return
}
if (this.options.editMode !== 'advanced') {
return
}
const container = L.DomUtil.create('div', 'umap-edit-container')
const metadataFields = ['options.name', 'options.description']
@ -1548,8 +1662,12 @@ U.Map = L.Map.extend({
},
edit: function () {
if (!this.editEnabled) return
if (this.options.editMode !== 'advanced') return
if (!this.editEnabled) {
return
}
if (this.options.editMode !== 'advanced') {
return
}
const container = L.DomUtil.create('div')
L.DomUtil.createTitle(container, L._('Map advanced properties'), 'icon-settings')
this._editControls(container)
@ -1578,7 +1696,9 @@ U.Map = L.Map.extend({
},
disableEdit: function () {
if (this.isDirty) return
if (this.isDirty) {
return
}
this.drop.disable()
L.DomUtil.removeClass(document.body, 'umap-edit-enabled')
this.editedFeature = null
@ -1602,8 +1722,8 @@ U.Map = L.Map.extend({
'div',
'umap-caption-bar',
this._controlContainer
),
name = L.DomUtil.create('h3', '', container)
)
const name = L.DomUtil.create('h3', '', container)
L.DomEvent.disableClickPropagation(container)
this.permissions.addOwnerLink('span', container)
if (this.getOption('captionMenus')) {
@ -1640,7 +1760,9 @@ U.Map = L.Map.extend({
},
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.disableEdit()
},
@ -1661,7 +1783,9 @@ U.Map = L.Map.extend({
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 [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 [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) {
items = items.concat(e.relatedTarget.getContextMenuItems(e))
}
@ -1812,7 +1938,9 @@ U.Map = L.Map.extend({
lng: e.latlng.lng,
zoom: Math.max(this.getZoom(), 16),
})
if (url) window.open(url)
if (url) {
window.open(url)
}
},
openExternalRouting: function (e) {
@ -1822,7 +1950,9 @@ U.Map = L.Map.extend({
locale: L.getLocale(),
zoom: this.getZoom(),
})
if (url) window.open(url)
if (url) {
window.open(url)
}
},
getMap: function () {
@ -1863,17 +1993,23 @@ U.Map = L.Map.extend({
closeInplaceToolbar: function () {
const toolbar = this._toolbars[L.Toolbar.Popup._toolbar_class_id]
if (toolbar) toolbar.remove()
if (toolbar) {
toolbar.remove()
}
},
search: function () {
if (this._controls.search) this._controls.search.open()
if (this._controls.search) {
this._controls.search.open()
}
},
getLayersBounds: function () {
const bounds = new L.latLngBounds()
this.eachBrowsableDataLayer((d) => {
if (d.isVisible()) bounds.extend(d.layer.getBounds())
if (d.isVisible()) {
bounds.extend(d.layer.getBounds())
}
})
return bounds
},

View file

@ -67,7 +67,7 @@ U.Layer.Cluster = L.MarkerClusterGroup.extend({
},
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
}
L.MarkerClusterGroup.prototype.initialize.call(this, options)
@ -165,7 +165,9 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
redraw: function () {
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) {
@ -177,7 +179,9 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
const values = []
this.datalayer.eachLayer((layer) => {
const value = this._getValue(layer)
if (!isNaN(value)) values.push(value)
if (!Number.isNaN(value)) {
values.push(value)
}
})
return values
},
@ -190,9 +194,9 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
this.options.colors = []
return
}
let mode = this.datalayer.options.choropleth.mode,
classes = +this.datalayer.options.choropleth.classes || 5,
breaks
const mode = this.datalayer.options.choropleth.mode
let classes = +this.datalayer.options.choropleth.classes || 5
let breaks
classes = Math.min(classes, values.length)
if (mode === 'manual') {
const manualBreaks = this.datalayer.options.choropleth.breaks
@ -200,7 +204,7 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
breaks = manualBreaks
.split(',')
.map((b) => +b)
.filter((b) => !isNaN(b))
.filter((b) => !Number.isNaN(b))
}
} else if (mode === 'equidistant') {
breaks = ss.equalIntervalBreaks(values, classes)
@ -219,12 +223,16 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
.join(',')
const fillColor = this.datalayer.getOption('fillColor') || this.defaults.fillColor
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] || []
},
getColor: function (feature) {
if (!feature) return // FIXME shold not happen
if (!feature) {
return // FIXME shold not happen
}
const featureValue = this._getValue(feature)
// 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++) {
@ -243,7 +251,7 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
addLayer: function (layer) {
// Do not add yet the layer to the map
// wait for datachanged event, so we want compute breaks once
var id = this.getLayerId(layer)
const id = this.getLayerId(layer)
this._layers[id] = layer
return this
},
@ -255,17 +263,23 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
onEdit: function (field, builder) {
// 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 (field === 'options.choropleth.breaks') {
this.datalayer.options.choropleth.mode = 'manual'
if (builder) builder.helpers['options.choropleth.mode'].fetch()
if (builder) {
builder.helpers['options.choropleth.mode'].fetch()
}
}
this.computeBreaks()
// If user changes the mode or the number of classes,
// then update the breaks input value
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) {
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) => {
li = L.DomUtil.create('li', '', parent)
@ -358,12 +374,9 @@ U.Layer.Heat = L.HeatLayer.extend({
addLayer: function (layer) {
if (layer instanceof L.Marker) {
let latlng = layer.getLatLng(),
alt
if (
this.datalayer.options.heat &&
this.datalayer.options.heat.intensityProperty
) {
let latlng = layer.getLatLng()
let alt
if (this.datalayer.options.heat?.intensityProperty) {
alt = Number.parseFloat(
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
// can ends with race condition if we remove the layer very faslty after.
// TODO: PR in upstream Leaflet.heat
if (!this._map) return
if (!this._map) {
return
}
L.HeatLayer.prototype.redraw.call(this)
},
@ -430,23 +445,23 @@ U.Layer.Heat = L.HeatLayer.extend({
if (!this._map) {
return
}
var data = [],
r = this._heat._r,
size = this._map.getSize(),
bounds = new L.Bounds(L.point([-r, -r]), size.add([r, r])),
cellSize = r / 2,
grid = [],
panePos = this._map._getMapPanePos(),
offsetX = panePos.x % cellSize,
offsetY = panePos.y % cellSize,
i,
len,
p,
cell,
x,
y,
j,
len2
const data = []
const r = this._heat._r
const size = this._map.getSize()
const bounds = new L.Bounds(L.point([-r, -r]), size.add([r, r]))
const cellSize = r / 2
const grid = []
const panePos = this._map._getMapPanePos()
const offsetX = panePos.x % cellSize
const offsetY = panePos.y % cellSize
let i
let len
let p
let cell
let x
let y
let j
let len2
this._max = 1
@ -455,7 +470,7 @@ U.Layer.Heat = L.HeatLayer.extend({
x = Math.floor((p.x - offsetX) / cellSize) + 2
y = Math.floor((p.y - offsetY) / cellSize) + 2
var alt =
const alt =
this._latlngs[i].alt !== undefined
? this._latlngs[i].alt
: this._latlngs[i][2] !== undefined
@ -532,13 +547,17 @@ U.DataLayer = L.Evented.extend({
Object.defineProperty(this, 'isDirty', {
get: () => isDirty,
set: (status) => {
if (!isDirty && status) this.fire('dirty')
if (!isDirty && status) {
this.fire('dirty')
}
isDirty = status
if (status) {
this.map.addDirtyDatalayer(this)
// A layer can be made dirty by indirect action (like dragging layers)
// we need to have it loaded before saving it.
if (!this.isLoaded()) this.fetchData()
if (!this.isLoaded()) {
this.fetchData()
}
} else {
this.map.removeDirtyDatalayer(this)
this.isDeleted = false
@ -552,9 +571,13 @@ U.DataLayer = L.Evented.extend({
Object.defineProperty(this, 'isDeleted', {
get: () => isDeleted,
set: (status) => {
if (!isDeleted && status) this.fire('deleted')
if (!isDeleted && status) {
this.fire('deleted')
}
isDeleted = status
if (status) this.isDirty = status
if (status) {
this.isDirty = status
}
},
})
} catch (e) {
@ -567,19 +590,21 @@ U.DataLayer = L.Evented.extend({
this.options.remoteData = {}
}
// Retrocompat
if (this.options.remoteData && this.options.remoteData.from) {
if (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
delete this.options.remoteData.to
this.options.remoteData.to = undefined
}
this.backupOptions()
this.connectToMap()
this.permissions = new U.DataLayerPermissions(this)
if (!this.umap_id) {
if (this.showAtLoad()) this.show()
if (this.showAtLoad()) {
this.show()
}
this.isDirty = true
}
@ -589,7 +614,9 @@ U.DataLayer = L.Evented.extend({
// Only layers that are displayed on load must be hidden/shown
// Automatically, others will be shown manually, and thus will
// 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)
},
@ -629,13 +656,21 @@ U.DataLayer = L.Evented.extend({
},
onMoveEnd: function (e) {
if (this.isRemoteLayer() && this.showAtZoom()) this.fetchRemoteData()
if (this.isRemoteLayer() && this.showAtZoom()) {
this.fetchRemoteData()
}
},
onZoomEnd: function (e) {
if (this._forcedVisibility) return
if (!this.showAtZoom() && this.isVisible()) this.hide()
if (this.showAtZoom() && !this.isVisible()) this.show()
if (this._forcedVisibility) {
return
}
if (!this.showAtZoom() && this.isVisible()) {
this.hide()
}
if (this.showAtZoom() && !this.isVisible()) {
this.show()
}
},
showAtLoad: function () {
@ -643,7 +678,9 @@ U.DataLayer = L.Evented.extend({
},
autoLoaded: function () {
if (!this.map.datalayersFromQueryString) return this.options.displayOnLoad
if (!this.map.datalayersFromQueryString) {
return this.options.displayOnLoad
}
const datalayerIds = this.map.datalayersFromQueryString
let loadMe = datalayerIds.includes(this.umap_id.toString())
if (this.options.old_id) {
@ -653,12 +690,16 @@ U.DataLayer = L.Evented.extend({
},
insertBefore: function (other) {
if (!other) return
if (!other) {
return
}
this.parentPane.insertBefore(this.pane, other.pane)
},
insertAfter: function (other) {
if (!other) return
if (!other) {
return
}
this.parentPane.insertBefore(this.pane, other.pane.nextSibling)
},
@ -680,13 +721,19 @@ U.DataLayer = L.Evented.extend({
return
}
const visible = this.isVisible()
if (this.layer) this.layer.clearLayers()
if (this.layer) {
this.layer.clearLayers()
}
// 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
this.layer = new Class(this)
this.eachLayer(this.showFeature)
if (visible) this.show()
if (visible) {
this.show()
}
this.propagateRemote()
},
@ -707,8 +754,12 @@ U.DataLayer = L.Evented.extend({
},
fetchData: async function () {
if (!this.umap_id) return
if (this._loading) return
if (!this.umap_id) {
return
}
if (this._loading) {
return
}
this._loading = true
const [geojson, response, error] = await this.map.server.get(this._dataUrl())
if (!error) {
@ -722,7 +773,9 @@ U.DataLayer = L.Evented.extend({
geojson._umap_options.editMode = this.options.editMode
}
// 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)
this.backupOptions()
this.fire('loaded')
@ -739,10 +792,17 @@ U.DataLayer = L.Evented.extend({
},
fromUmapGeoJSON: async function (geojson) {
if (geojson._storage) geojson._umap_options = geojson._storage // Retrocompat
if (geojson._umap_options) this.setOptions(geojson._umap_options)
if (this.isRemoteLayer()) await this.fetchRemoteData()
else this.fromGeoJSON(geojson)
if (geojson._storage) {
geojson._umap_options = geojson._storage // Retrocompat
}
if (geojson._umap_options) {
this.setOptions(geojson._umap_options)
}
if (this.isRemoteLayer()) {
await this.fetchRemoteData()
} else {
this.fromGeoJSON(geojson)
}
this._loaded = true
},
@ -772,26 +832,32 @@ U.DataLayer = L.Evented.extend({
},
showAtZoom: function () {
const from = Number.parseInt(this.options.fromZoom, 10),
to = Number.parseInt(this.options.toZoom, 10),
zoom = this.map.getZoom()
return !((!isNaN(from) && zoom < from) || (!isNaN(to) && zoom > to))
const from = Number.parseInt(this.options.fromZoom, 10)
const to = Number.parseInt(this.options.toZoom, 10)
const zoom = this.map.getZoom()
return !((!Number.isNaN(from) && zoom < from) || (!Number.isNaN(to) && zoom > to))
},
hasDynamicData: function () {
return !!(this.options.remoteData && this.options.remoteData.dynamic)
return !!this.options.remoteData?.dynamic
},
fetchRemoteData: async function (force) {
if (!this.isRemoteLayer()) return
if (!this.hasDynamicData() && this.hasDataLoaded() && !force) return
if (!this.isVisible()) return
if (!this.isRemoteLayer()) {
return
}
if (!this.hasDynamicData() && this.hasDataLoaded() && !force) {
return
}
if (!this.isVisible()) {
return
}
let url = this.map.localizeUrl(this.options.remoteData.url)
if (this.options.remoteData.proxy) {
url = this.map.proxyUrl(url, this.options.remoteData.ttl)
}
const response = await this.map.request.get(url)
if (response && response.ok) {
if (response?.ok) {
this.clear()
this.rawToGeoJSON(
await response.text(),
@ -802,14 +868,20 @@ U.DataLayer = L.Evented.extend({
},
onceLoaded: function (callback, context) {
if (this.isLoaded()) callback.call(context || this, this)
else this.once('loaded', callback, context)
if (this.isLoaded()) {
callback.call(context || this, this)
} else {
this.once('loaded', callback, context)
}
return this
},
onceDataLoaded: function (callback, context) {
if (this.hasDataLoaded()) callback.call(context || this, this)
else this.once('dataloaded', callback, context)
if (this.hasDataLoaded()) {
callback.call(context || this, this)
} else {
this.once('dataloaded', callback, context)
}
return this
},
@ -823,7 +895,9 @@ U.DataLayer = L.Evented.extend({
setUmapId: function (id) {
// 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 () {
@ -835,7 +909,7 @@ U.DataLayer = L.Evented.extend({
},
setOptions: function (options) {
delete options.geojson
options.geojson = undefined
this.options = U.Utils.CopyJSON(U.DataLayer.prototype.options) // Start from fresh.
this.updateOptions(options)
},
@ -849,8 +923,9 @@ U.DataLayer = L.Evented.extend({
const id = L.stamp(this)
if (!this.map.datalayers[id]) {
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.onDataLayersChanged()
}
},
@ -864,16 +939,14 @@ U.DataLayer = L.Evented.extend({
})
// No browser cache for owners/editors.
if (this.map.hasEditMode()) url = `${url}?${Date.now()}`
if (this.map.hasEditMode()) {
url = `${url}?${Date.now()}`
}
return url
},
isRemoteLayer: function () {
return Boolean(
this.options.remoteData &&
this.options.remoteData.url &&
this.options.remoteData.format
)
return Boolean(this.options.remoteData?.url && this.options.remoteData.format)
},
isClustered: function () {
@ -881,7 +954,9 @@ U.DataLayer = L.Evented.extend({
},
showFeature: function (feature) {
if (feature.isFiltered()) return
if (feature.isFiltered()) {
return
}
this.layer.addLayer(feature)
},
@ -893,7 +968,9 @@ U.DataLayer = L.Evented.extend({
this.indexProperties(feature)
this.map.features_index[feature.getSlug()] = feature
this.showFeature(feature)
if (this.hasDataLoaded()) this.fire('datachanged')
if (this.hasDataLoaded()) {
this.fire('datachanged')
}
},
removeLayer: function (feature) {
@ -903,24 +980,37 @@ U.DataLayer = L.Evented.extend({
this._index.splice(this._index.indexOf(id), 1)
delete this._layers[id]
delete this.map.features_index[feature.getSlug()]
if (this.hasDataLoaded()) this.fire('datachanged')
if (this.hasDataLoaded()) {
this.fire('datachanged')
}
},
indexProperties: function (feature) {
for (const i in feature.properties)
if (typeof feature.properties[i] !== 'object') this.indexProperty(i)
for (const i in feature.properties) {
if (typeof feature.properties[i] !== 'object') {
this.indexProperty(i)
}
}
},
indexProperty: function (name) {
if (!name) return
if (name.indexOf('_') === 0) return
if (L.Util.indexOf(this._propertiesIndex, name) !== -1) return
if (!name) {
return
}
if (name.indexOf('_') === 0) {
return
}
if (L.Util.indexOf(this._propertiesIndex, name) !== -1) {
return
}
this._propertiesIndex.push(name)
},
deindexProperty: function (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) {
@ -960,7 +1050,7 @@ U.DataLayer = L.Evented.extend({
// csv2geojson fallback to null geometries when it cannot determine
// lat or lon columns. This is valid geojson, but unwanted from a user
// point of view.
if (result && result.features.length) {
if (result?.features.length) {
if (result.features[0].geometry === null) {
err = {
type: 'Error',
@ -981,7 +1071,7 @@ U.DataLayer = L.Evented.extend({
U.Alert.error(message, 10000)
console.error(err)
}
if (result && result.features.length) {
if (result?.features.length) {
callback(result)
}
}
@ -1015,8 +1105,10 @@ U.DataLayer = L.Evented.extend({
// It is misleading, as the returned objects are uMap objects, and not
// GeoJSON features.
geojsonToFeatures: function (geojson) {
if (!geojson) return
const features = geojson instanceof Array ? geojson : geojson.features
if (!geojson) {
return
}
const features = Array.isArray(geojson) ? geojson : geojson.features
let i
let len
@ -1060,12 +1152,17 @@ U.DataLayer = L.Evented.extend({
id = null,
feature = null,
} = {}) {
if (!geometry) return // null geometry is valid geojson.
if (!geometry) {
return // null geometry is valid geojson.
}
const coords = geometry.coordinates
let latlng, latlngs
let latlng
let latlngs
// 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) {
case 'Point':
@ -1087,7 +1184,9 @@ U.DataLayer = L.Evented.extend({
coords,
geometry.type === 'LineString' ? 0 : 1
)
if (!latlngs.length) break
if (!latlngs.length) {
break
}
if (feature) {
feature.setLatLngs(latlngs)
return feature
@ -1161,7 +1260,7 @@ U.DataLayer = L.Evented.extend({
importFromUrl: async function (uri, type) {
uri = this.map.localizeUrl(uri)
const response = await this.map.request.get(uri)
if (response && response.ok) {
if (response?.ok) {
this.importRaw(await response.text(), type)
}
},
@ -1198,7 +1297,9 @@ U.DataLayer = L.Evented.extend({
},
empty: function () {
if (this.isRemoteLayer()) return
if (this.isRemoteLayer()) {
return
}
this.clear()
this.isDirty = true
},
@ -1206,9 +1307,9 @@ U.DataLayer = L.Evented.extend({
clone: function () {
const options = U.Utils.CopyJSON(this.options)
options.name = L._('Clone of {name}', { name: this.options.name })
delete options.id
const geojson = U.Utils.CopyJSON(this._geojson),
datalayer = this.map.createDataLayer(options)
options.id = undefined
const geojson = U.Utils.CopyJSON(this._geojson)
const datalayer = this.map.createDataLayer(options)
datalayer.fromGeoJSON(geojson)
return datalayer
},
@ -1226,12 +1327,14 @@ U.DataLayer = L.Evented.extend({
this.map.off('zoomend', this.onZoomEnd, this)
this.off()
this.clear()
delete this._loaded
delete this._dataloaded
this._loaded = undefined
this._dataloaded = undefined
},
reset: function () {
if (!this.umap_id) this.erase()
if (!this.umap_id) {
this.erase()
}
this.resetOptions()
this.parentPane.appendChild(this.pane)
@ -1240,15 +1343,20 @@ U.DataLayer = L.Evented.extend({
}
this.clear()
this.hide()
if (this.isRemoteLayer()) this.fetchRemoteData()
else if (this._geojson_bk) this.fromGeoJSON(this._geojson_bk)
if (this.isRemoteLayer()) {
this.fetchRemoteData()
} else if (this._geojson_bk) {
this.fromGeoJSON(this._geojson_bk)
}
this._loaded = true
this.show()
this.isDirty = false
},
redraw: function () {
if (!this.isVisible()) return
if (!this.isVisible()) {
return
}
this.hide()
this.show()
},
@ -1257,8 +1365,8 @@ U.DataLayer = L.Evented.extend({
if (!this.map.editEnabled || !this.isLoaded()) {
return
}
const container = L.DomUtil.create('div', 'umap-layer-properties-container'),
metadataFields = [
const container = L.DomUtil.create('div', 'umap-layer-properties-container')
const metadataFields = [
'options.name',
'options.description',
['options.type', { handler: 'LayerTypeChooser', label: L._('Type of layer') }],
@ -1406,7 +1514,9 @@ U.DataLayer = L.Evented.extend({
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 advancedButtons = L.DomUtil.create('div', 'button-bar half', advancedActions)
@ -1465,21 +1575,25 @@ U.DataLayer = L.Evented.extend({
},
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) {
if (this.layer && this.layer.getOption) {
if (this.layer?.getOption) {
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') {
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) {
@ -1503,24 +1617,37 @@ U.DataLayer = L.Evented.extend({
const [{ versions }, response, error] = await this.map.server.get(
this.getVersionsUrl()
)
if (!error) versions.forEach(appendVersion)
if (!error) {
versions.forEach(appendVersion)
}
},
context: this,
})
},
restore: async function (version) {
if (!this.map.editEnabled) return
if (!confirm(L._('Are you sure you want to restore this version?'))) return
if (!this.map.editEnabled) {
return
}
if (!confirm(L._('Are you sure you want to restore this version?'))) {
return
}
const [geojson, response, error] = await this.map.server.get(
this.getVersionUrl(version)
)
if (!error) {
if (geojson._storage) geojson._umap_options = geojson._storage // Retrocompat.
if (geojson._umap_options) this.setOptions(geojson._umap_options)
if (geojson._storage) {
geojson._umap_options = geojson._storage // Retrocompat.
}
if (geojson._umap_options) {
this.setOptions(geojson._umap_options)
}
this.empty()
if (this.isRemoteLayer()) this.fetchRemoteData()
else this.addData(geojson)
if (this.isRemoteLayer()) {
this.fetchRemoteData()
} else {
this.addData(geojson)
}
this.isDirty = true
}
},
@ -1533,7 +1660,9 @@ U.DataLayer = L.Evented.extend({
show: async function () {
this.map.addLayer(this.layer)
if (!this.isLoaded()) await this.fetchData()
if (!this.isLoaded()) {
await this.fetchData()
}
this.fire('show')
},
@ -1546,12 +1675,17 @@ U.DataLayer = L.Evented.extend({
// From now on, do not try to how/hide
// automatically this layer.
this._forcedVisibility = true
if (!this.isVisible()) this.show()
else this.hide()
if (!this.isVisible()) {
this.show()
} else {
this.hide()
}
},
zoomTo: function () {
if (!this.isVisible()) return
if (!this.isVisible()) {
return
}
const bounds = this.layer.getBounds()
if (bounds.isValid()) {
const options = { maxZoom: this.getOption('zoomTo') }
@ -1561,7 +1695,7 @@ U.DataLayer = L.Evented.extend({
// Is this layer type browsable in theorie
isBrowsable: function () {
return this.layer && this.layer.browsable
return this.layer?.browsable
},
// Is this layer browsable in theorie
@ -1590,7 +1724,9 @@ U.DataLayer = L.Evented.extend({
},
getFeatureByIndex: function (index) {
if (index === -1) index = this._index.length - 1
if (index === -1) {
index = this._index.length - 1
}
const id = this._index[index]
return this._layers[id]
},
@ -1623,7 +1759,9 @@ U.DataLayer = L.Evented.extend({
let next
const index = this.map.datalayers_index
while (((id = index[++id] ? id : 0), (next = index[id]))) {
if (next === this || next.canBrowse()) break
if (next === this || next.canBrowse()) {
break
}
}
return next
},
@ -1633,7 +1771,9 @@ U.DataLayer = L.Evented.extend({
let prev
const index = this.map.datalayers_index
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
},
@ -1661,7 +1801,9 @@ U.DataLayer = L.Evented.extend({
},
save: async function () {
if (this.isDeleted) return this.saveDelete()
if (this.isDeleted) {
return this.saveDelete()
}
if (!this.isLoaded()) {
return
}
@ -1705,7 +1847,7 @@ U.DataLayer = L.Evented.extend({
if (data.geojson) {
this.clear()
this.fromGeoJSON(data.geojson)
delete data.geojson
data.geojson = undefined
}
this._reference_version = response.headers.get('X-Datalayer-Version')
this.sync.update('_reference_version', this._reference_version)
@ -1738,7 +1880,9 @@ U.DataLayer = L.Evented.extend({
},
tableEdit: function () {
if (this.isRemoteLayer() || !this.isVisible()) return
if (this.isRemoteLayer() || !this.isVisible()) {
return
}
const editor = new U.TableEditor(this)
editor.edit()
},
@ -1747,10 +1891,16 @@ U.DataLayer = L.Evented.extend({
// 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.
// 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
else if (this.options.labelKey) return this.options.labelKey
else if (this.map.options.sortKey) return this.map.options.sortKey
else return 'name'
if (this.map.options.filterKey) {
return this.map.options.filterKey
}
if (this.options.labelKey) {
return this.options.labelKey
}
if (this.map.options.sortKey) {
return this.map.options.sortKey
}
return 'name'
},
})

View file

@ -35,7 +35,7 @@ U.MapPermissions = L.Class.extend({
return (
this.map.options.user &&
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 () {
if (this.map.options.editMode !== 'advanced') return
if (this.map.options.editMode !== 'advanced') {
return
}
if (!this.map.options.umap_id) {
return U.Alert.info(L._('Please save the map first'))
}
@ -141,17 +143,21 @@ U.MapPermissions = L.Class.extend({
},
save: async function () {
if (!this.isDirty) return this.map.continueSaving()
if (!this.isDirty) {
return this.map.continueSaving()
}
const formData = new FormData()
if (!this.isAnonymousMap() && this.options.editors) {
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)
}
if (this.isOwner() || this.isAnonymousMap())
}
if (this.isOwner() || this.isAnonymousMap()) {
formData.append('edit_status', this.options.edit_status)
}
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)
}
const [data, response, error] = await this.map.server.post(
@ -180,7 +186,7 @@ U.MapPermissions = L.Class.extend({
},
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(
element,
'umap-map-owner',

View file

@ -14,8 +14,8 @@ U.Popup = L.Popup.extend({
},
format: function () {
const mode = this.feature.getOption('popupTemplate') || 'Default',
klass = U.PopupTemplate[mode] || U.PopupTemplate.Default
const mode = this.feature.getOption('popupTemplate') || 'Default'
const klass = U.PopupTemplate[mode] || U.PopupTemplate.Default
this.content = new klass(this.feature, this.container)
this.content.render()
const els = this.container.querySelectorAll('img,iframe')
@ -125,29 +125,35 @@ U.PopupTemplate.Default = L.Class.extend({
renderFooter: function () {
if (this.feature.hasPopupFooter()) {
const footer = L.DomUtil.create('ul', 'umap-popup-footer', this.container),
previousLi = L.DomUtil.create('li', 'previous', footer),
zoomLi = L.DomUtil.create('li', 'zoom', footer),
nextLi = L.DomUtil.create('li', 'next', footer),
next = this.feature.getNext(),
prev = this.feature.getPrevious()
const footer = L.DomUtil.create('ul', 'umap-popup-footer', this.container)
const previousLi = L.DomUtil.create('li', 'previous', footer)
const zoomLi = L.DomUtil.create('li', 'zoom', footer)
const nextLi = L.DomUtil.create('li', 'next', footer)
const next = this.feature.getNext()
const prev = this.feature.getPrevious()
// Fixme: remove me when this is merged and released
// https://github.com/Leaflet/Leaflet/pull/9052
L.DomEvent.disableClickPropagation(footer)
if (next)
if (next) {
nextLi.title = L._('Go to «{feature}»', {
feature: next.properties.name || L._('next'),
})
if (prev)
}
if (prev) {
previousLi.title = L._('Go to «{feature}»', {
feature: prev.properties.name || L._('previous'),
})
}
zoomLi.title = L._('Zoom to this feature')
L.DomEvent.on(nextLi, 'click', () => {
if (next) next.zoomTo({ callback: next.view })
if (next) {
next.zoomTo({ callback: next.view })
}
})
L.DomEvent.on(previousLi, 'click', () => {
if (prev) prev.zoomTo({ callback: prev.view })
if (prev) {
prev.zoomTo({ callback: prev.view })
}
})
L.DomEvent.on(
zoomLi,
@ -162,9 +168,13 @@ U.PopupTemplate.Default = L.Class.extend({
render: function () {
const title = this.renderTitle()
if (title) this.container.appendChild(title)
if (title) {
this.container.appendChild(title)
}
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()
},
})
@ -202,7 +212,9 @@ U.PopupTemplate.Table = U.PopupTemplate.BaseWithTitle.extend({
const table = L.DomUtil.create('table')
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...)
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 () {
const title = this.renderTitle(this),
a = L.DomUtil.add('a')
const title = this.renderTitle(this)
const a = L.DomUtil.add('a')
a.href = this.feature.properties.link
a.target = '_blank'
a.appendChild(title)
@ -257,7 +269,9 @@ U.PopupTemplate.OSM = U.PopupTemplate.Default.extend({
getName: function () {
const props = this.feature.properties
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
},
@ -271,7 +285,9 @@ U.PopupTemplate.OSM = U.PopupTemplate.Default.extend({
const icon = U.Icon.makeIconElement(iconUrl, title)
L.DomUtil.addClass(icon, 'icon')
U.Icon.setIconContrast(icon, title, iconUrl, color)
if (L.DomUtil.contrastedColor(title, color)) title.style.color = 'white'
if (L.DomUtil.contrastedColor(title, color)) {
title.style.color = 'white'
}
L.DomUtil.add('span', '', title, this.getName())
const street = props['addr:street']
if (street) {
@ -323,7 +339,7 @@ U.PopupTemplate.OSM = U.PopupTemplate.Default.extend({
L.DomUtil.element('a', { href: `mailto:${email}`, textContent: email })
)
}
const id = props['@id'] || props['id']
const id = props['@id'] || props.id
if (id) {
L.DomUtil.add(
'div',

View file

@ -19,11 +19,11 @@ U.Share = L.Class.extend({
formatter: (map) => {
const table = []
map.eachFeature((feature) => {
const row = feature.toGeoJSON()['properties'],
center = feature.getCenter()
delete row['_umap_options']
row['Latitude'] = center.lat
row['Longitude'] = center.lng
const row = feature.toGeoJSON().properties
const center = feature.getCenter()
row._umap_options = undefined
row.Latitude = center.lat
row.Longitude = center.lng
table.push(row)
})
return csv2geojson.dsv.csvFormat(table)
@ -152,7 +152,9 @@ U.Share = L.Class.extend({
},
open: function () {
if (!this.container) this.build()
if (!this.container) {
this.build()
}
this.map.panel.open({ content: this.container })
},
@ -224,7 +226,7 @@ U.IframeExporter = L.Evented.extend({
if (this.options.viewCurrentFeature && this.map.currentFeature) {
this.queryString.feature = this.map.currentFeature.getSlug()
} else {
delete this.queryString.feature
this.queryString.feature = undefined
}
if (this.options.keepCurrentDatalayers) {
this.map.eachDataLayer((datalayer) => {
@ -234,7 +236,7 @@ U.IframeExporter = L.Evented.extend({
})
this.queryString.datalayers = datalayers.join(',')
} else {
delete this.queryString.datalayers
this.queryString.datalayers = undefined
}
const currentView = this.options.currentView ? window.location.hash : ''
const queryString = L.extend({}, this.queryString, options)

View file

@ -20,7 +20,9 @@ U.Slideshow = L.Class.extend({
get: function () {
if (!current) {
const datalayer = this.defaultDatalayer()
if (datalayer) current = datalayer.getFeatureByIndex(0)
if (datalayer) {
current = datalayer.getFeatureByIndex(0)
}
}
return current
},
@ -68,9 +70,11 @@ U.Slideshow = L.Class.extend({
timeSpinner: function () {
const time = Number.parseInt(this.options.delay, 10)
if (!time) return
const css = `rotation ${time / 1000}s infinite linear`,
spinners = document.querySelectorAll('.umap-slideshow-toolbox .play .spinner')
if (!time) {
return
}
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++) {
spinners[i].style.animation = css
spinners[i].style['-webkit-animation'] = css
@ -93,8 +97,12 @@ U.Slideshow = L.Class.extend({
},
play: function () {
if (this._id) return
if (this.map.editEnabled || !this.map.options.slideshow.active) return
if (this._id) {
return
}
if (this.map.editEnabled || !this.map.options.slideshow.active) {
return
}
L.DomUtil.addClass(document.body, U.Slideshow.CLASSNAME)
this._id = window.setInterval(L.bind(this.loop, this), this.options.delay)
this.resetSpinners()
@ -127,30 +135,37 @@ U.Slideshow = L.Class.extend({
backward: function () {
this.pause()
if (this.current) this.current = this.current.getPrevious()
if (this.current) {
this.current = this.current.getPrevious()
}
this.step()
},
step: function () {
if (!this.current) return this.stop()
if (!this.current) {
return this.stop()
}
this.current.zoomTo({ easing: this.options.easing })
this.current.view()
},
renderToolbox: function (container) {
const box = L.DomUtil.create('ul', 'umap-slideshow-toolbox'),
play = L.DomUtil.create('li', 'play', box),
stop = L.DomUtil.create('li', 'stop', box),
prev = L.DomUtil.create('li', 'prev', box),
next = L.DomUtil.create('li', 'next', box)
const box = L.DomUtil.create('ul', 'umap-slideshow-toolbox')
const play = L.DomUtil.create('li', 'play', box)
const stop = L.DomUtil.create('li', 'stop', box)
const prev = L.DomUtil.create('li', 'prev', box)
const next = L.DomUtil.create('li', 'next', box)
L.DomUtil.create('div', 'spinner', play)
play.title = L._('Start slideshow')
stop.title = L._('Stop slideshow')
next.title = L._('Zoom to the next')
prev.title = L._('Zoom to the previous')
const toggle = function () {
if (this._id) this.pause()
else this.play()
if (this._id) {
this.pause()
} else {
this.play()
}
}
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)

View file

@ -15,10 +15,10 @@ U.TableEditor = L.Class.extend({
},
renderHeader: function (property) {
const container = L.DomUtil.create('div', 'tcell', this.header),
title = L.DomUtil.add('span', '', container, property),
del = L.DomUtil.create('i', 'umap-delete', container),
rename = L.DomUtil.create('i', 'umap-edit', container)
const container = L.DomUtil.create('div', 'tcell', this.header)
const title = L.DomUtil.add('span', '', container, property)
const del = L.DomUtil.create('i', 'umap-delete', container)
const rename = L.DomUtil.create('i', 'umap-edit', container)
del.title = L._('Delete this property on all the features')
rename.title = L._('Rename this property on all the features')
const doDelete = function () {
@ -40,7 +40,9 @@ U.TableEditor = L.Class.extend({
L._('Please enter the new name of this property'),
property
)
if (!newName || !this.validateName(newName)) return
if (!newName || !this.validateName(newName)) {
return
}
this.datalayer.eachLayer((feature) => {
feature.renameProperty(property, newName)
})
@ -63,10 +65,13 @@ U.TableEditor = L.Class.extend({
compileProperties: function () {
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
if (this.properties.indexOf('description') !== -1)
if (this.properties.indexOf('description') !== -1) {
this.properties.splice(this.properties.indexOf('description'), 1)
}
this.properties.sort()
this.field_properties = []
for (let i = 0; i < this.properties.length; i++) {
@ -104,7 +109,9 @@ U.TableEditor = L.Class.extend({
addButton.insertBefore(iconElement, addButton.firstChild)
const addProperty = function () {
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.edit()
}