diff --git a/package.json b/package.json
index aa6b9da3..1440cd52 100644
--- a/package.json
+++ b/package.json
@@ -40,8 +40,9 @@
"@tmcw/togeojson": "^5.8.0",
"colorbrewer": "^1.5.6",
"csv2geojson": "5.1.1",
- "dompurify": "^3.0.3",
+ "dompurify": "^3.0.11",
"georsstogeojson": "^0.1.0",
+ "jsdom": "^24.0.0",
"leaflet": "1.9.4",
"leaflet-contextmenu": "^1.4.0",
"leaflet-editable": "^1.2.0",
diff --git a/scripts/vendorsjs.sh b/scripts/vendorsjs.sh
index 39f8f097..a506a276 100755
--- a/scripts/vendorsjs.sh
+++ b/scripts/vendorsjs.sh
@@ -25,7 +25,7 @@ mkdir -p umap/static/umap/vendors/georsstogeojson/ && cp -r node_modules/georsst
mkdir -p umap/static/umap/vendors/togpx/ && cp -r node_modules/togpx/togpx.js umap/static/umap/vendors/togpx/
mkdir -p umap/static/umap/vendors/tokml && cp -r node_modules/tokml/tokml.js umap/static/umap/vendors/tokml
mkdir -p umap/static/umap/vendors/locatecontrol/ && cp -r node_modules/leaflet.locatecontrol/dist/L.Control.Locate.min.* umap/static/umap/vendors/locatecontrol/
-mkdir -p umap/static/umap/vendors/dompurify/ && cp -r node_modules/dompurify/dist/purify.min.* umap/static/umap/vendors/dompurify/
+mkdir -p umap/static/umap/vendors/dompurify/ && cp -r node_modules/dompurify/dist/*.mjs umap/static/umap/vendors/dompurify/
mkdir -p umap/static/umap/vendors/colorbrewer/ && cp node_modules/colorbrewer/index.js umap/static/umap/vendors/colorbrewer/colorbrewer.js
mkdir -p umap/static/umap/vendors/simple-statistics/ && cp node_modules/simple-statistics/dist/simple-statistics.min.* umap/static/umap/vendors/simple-statistics/
mkdir -p umap/static/umap/vendors/iconlayers/ && cp node_modules/leaflet-iconlayers/dist/* umap/static/umap/vendors/iconlayers/
diff --git a/umap/static/umap/js/modules/global.js b/umap/static/umap/js/modules/global.js
index 25ee3505..c432771e 100644
--- a/umap/static/umap/js/modules/global.js
+++ b/umap/static/umap/js/modules/global.js
@@ -1,7 +1,7 @@
import URLs from './urls.js'
import Browser from './browser.js'
import * as Utils from './utils.js'
-import {SCHEMA} from './schema.js'
+import { SCHEMA } from './schema.js'
import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js'
// Import modules and export them to the global scope.
diff --git a/umap/static/umap/js/modules/urls.js b/umap/static/umap/js/modules/urls.js
index bdf54363..ede3ac54 100644
--- a/umap/static/umap/js/modules/urls.js
+++ b/umap/static/umap/js/modules/urls.js
@@ -1,19 +1,4 @@
-// Vendorized from leaflet.utils
-// https://github.com/Leaflet/Leaflet/blob/108c6717b70f57c63645498f9bd66b6677758786/src/core/Util.js#L132-L151
-var templateRe = /\{ *([\w_ -]+) *\}/g
-
-function template(str, data) {
- return str.replace(templateRe, function (str, key) {
- var value = data[key]
-
- if (value === undefined) {
- throw new Error('No value provided for variable ' + str)
- } else if (typeof value === 'function') {
- value = value(data)
- }
- return value
- })
-}
+import { template } from "./utils.js"
export default class URLs {
constructor(serverUrls) {
diff --git a/umap/static/umap/js/modules/utils.js b/umap/static/umap/js/modules/utils.js
index a5116616..e6117c04 100644
--- a/umap/static/umap/js/modules/utils.js
+++ b/umap/static/umap/js/modules/utils.js
@@ -1,3 +1,5 @@
+import { default as DOMPurifyInitializer } from '../../vendors/dompurify/purify.es.mjs'
+
/**
* Generate a pseudo-unique identifier (5 chars long, mixed-case alphanumeric)
*
@@ -22,3 +24,284 @@ export function checkId(string) {
if (typeof string !== 'string') return false
return /^[A-Za-z0-9]{5}$/.test(string)
}
+
+/**
+ * Import DOM purify, and initialize it.
+ *
+ * If the context is a node server, uses jsdom to provide
+ * DOM APIs
+ */
+export default function getPurify() {
+ if (typeof window === 'undefined') {
+ return DOMPurifyInitializer(new global.JSDOM('').window)
+ } else {
+ return DOMPurifyInitializer(window)
+ }
+}
+
+export function escapeHTML(s) {
+ s = s ? s.toString() : ''
+ s = getPurify().sanitize(s, {
+ USE_PROFILES: { html: true },
+ ADD_TAGS: ['iframe'],
+ ALLOWED_TAGS: [
+ 'h3',
+ 'h4',
+ 'h5',
+ 'hr',
+ 'strong',
+ 'em',
+ 'ul',
+ 'li',
+ 'a',
+ 'div',
+ 'iframe',
+ 'img',
+ 'br',
+ ],
+ ADD_ATTR: ['target', 'allow', 'allowfullscreen', 'frameborder', 'scrolling'],
+ ALLOWED_ATTR: ['href', 'src', 'width', 'height'],
+ // Added: `geo:` URL scheme as defined in RFC5870:
+ // https://www.rfc-editor.org/rfc/rfc5870.html
+ // The base RegExp comes from:
+ // https://github.com/cure53/DOMPurify/blob/main/src/regexp.js#L10
+ ALLOWED_URI_REGEXP:
+ /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|geo):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,
+ })
+ return s
+}
+
+export function toHTML(r, options) {
+ if (!r) return ''
+ const target = (options && options.target) || 'blank'
+ let ii
+
+ // detect newline format
+ const newline = r.indexOf('\r\n') != -1 ? '\r\n' : r.indexOf('\n') != -1 ? '\n' : ''
+
+ // headings and hr
+ r = r.replace(/^### (.*)/gm, '
$1
')
+ r = r.replace(/^## (.*)/gm, '$1
')
+ r = r.replace(/^# (.*)/gm, '$1
')
+ r = r.replace(/^---/gm, '
')
+
+ // bold, italics
+ r = r.replace(/\*\*(.*?)\*\*/g, '$1')
+ r = r.replace(/\*(.*?)\*/g, '$1')
+
+ // unordered lists
+ r = r.replace(/^\*\* (.*)/gm, '')
+ r = r.replace(/^\* (.*)/gm, '')
+ for (ii = 0; ii < 3; ii++)
+ r = r.replace(new RegExp(`${newline}`, 'g'), newline)
+
+ // links
+ r = r.replace(/(\[\[http)/g, '[[h_t_t_p') // Escape for avoiding clash between [[http://xxx]] and http://xxx
+ r = r.replace(/({{http)/g, '{{h_t_t_p')
+ r = r.replace(/(=http)/g, '=h_t_t_p') // http://xxx as query string, see https://github.com/umap-project/umap/issues/607
+ r = r.replace(/(https?:[^ \<)\n]*)/g, `$1`)
+ r = r.replace(
+ /\[\[(h_t_t_ps?:[^\]|]*?)\]\]/g,
+ `$1`
+ )
+ r = r.replace(
+ /\[\[(h_t_t_ps?:[^|]*?)\|(.*?)\]\]/g,
+ `$2`
+ )
+ r = r.replace(/\[\[([^\]|]*?)\]\]/g, `$1`)
+ r = r.replace(/\[\[([^|]*?)\|(.*?)\]\]/g, `$2`)
+
+ // iframe
+ r = r.replace(
+ /{{{(h_t_t_ps?[^ |{]*)}}}/g,
+ ''
+ )
+ r = r.replace(
+ /{{{(h_t_t_ps?[^ |{]*)\|(\d*)(px)?}}}/g,
+ ''
+ )
+ r = r.replace(
+ /{{{(h_t_t_ps?[^ |{]*)\|(\d*)(px)?\*(\d*)(px)?}}}/g,
+ ''
+ )
+
+ // images
+ r = r.replace(/{{([^\]|]*?)}}/g, '
')
+ r = r.replace(
+ /{{([^|]*?)\|(\d*?)(px)?}}/g,
+ '
'
+ )
+
+ //Unescape http
+ r = r.replace(/(h_t_t_p)/g, 'http')
+
+ // Preserver line breaks
+ if (newline) r = r.replace(new RegExp(`${newline}(?=[^]+)`, 'g'), `
${newline}`)
+
+ r = escapeHTML(r)
+
+ return r
+}
+
+export function isObject(what) {
+ return typeof what === 'object' && what !== null
+}
+
+export function CopyJSON(geojson) {
+ return JSON.parse(JSON.stringify(geojson))
+}
+
+export function detectFileType(f) {
+ const filename = f.name ? escape(f.name.toLowerCase()) : ''
+ function ext(_) {
+ return filename.indexOf(_) !== -1
+ }
+ 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 (f.type === 'text/csv' || ext('.csv') || ext('.tsv') || ext('.dsv')) {
+ return 'csv'
+ }
+ if (ext('.xml') || ext('.osm')) return 'osm'
+ if (ext('.umap')) return 'umap'
+}
+
+export function usableOption(options, option) {
+ return options[option] !== undefined && options[option] !== ''
+}
+
+export function greedyTemplate(str, data, ignore) {
+ function getValue(data, path) {
+ let value = data
+ for (let i = 0; i < path.length; i++) {
+ value = value[path[i]]
+ if (value === undefined) break
+ }
+ return value
+ }
+
+ if (typeof str !== 'string') return ''
+
+ return str.replace(
+ /\{ *([^\{\}/\-]+)(?:\|("[^"]*"))? *\}/g,
+ (str, key, staticFallback) => {
+ const vars = key.split('|')
+ let value
+ let path
+ if (staticFallback !== undefined) {
+ vars.push(staticFallback)
+ }
+ for (let i = 0; i < vars.length; i++) {
+ path = vars[i]
+ 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
+ }
+ if (value === undefined) {
+ if (ignore) value = str
+ else value = ''
+ }
+ return value
+ }
+ )
+}
+
+export function naturalSort(a, b, lang) {
+ return a
+ .toString()
+ .toLowerCase()
+ .localeCompare(b.toString().toLowerCase(), lang || 'en', {
+ sensitivity: 'base',
+ numeric: true,
+ })
+}
+
+export function sortFeatures(features, sortKey, lang) {
+ const sortKeys = (sortKey || 'name').split(',')
+
+ const sort = (a, b, i) => {
+ let sortKey = sortKeys[i],
+ reverse = 1
+ if (sortKey[0] === '-') {
+ reverse = -1
+ sortKey = sortKey.substring(1)
+ }
+ 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)
+ return score * reverse
+ }
+
+ features.sort((a, b) => {
+ if (!a.properties || !b.properties) {
+ return 0
+ }
+ return sort(a, b, 0)
+ })
+
+ return features
+}
+
+export function flattenCoordinates(coords) {
+ while (coords[0] && typeof coords[0][0] !== 'number') coords = coords[0]
+ return coords
+}
+
+export function buildQueryString(params) {
+ const query_string = []
+ for (const key in params) {
+ query_string.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
+ }
+ return query_string.join('&')
+}
+
+export function getBaseUrl() {
+ return `//${window.location.host}${window.location.pathname}`
+}
+
+export function hasVar(value) {
+ return typeof value === 'string' && value.indexOf('{') != -1
+}
+
+export function isPath(value) {
+ return value && value.length && value.startsWith('/')
+}
+
+export function isRemoteUrl(value) {
+ return value && value.length && value.startsWith('http')
+}
+
+export function isDataImage(value) {
+ return value && value.length && value.startsWith('data:image')
+}
+
+export function normalize(s) {
+ return (s || '')
+ .toLowerCase()
+ .normalize('NFD')
+ .replace(/[\u0300-\u036f]/g, '')
+}
+
+// Vendorized from leaflet.utils
+// https://github.com/Leaflet/Leaflet/blob/108c6717b70f57c63645498f9bd66b6677758786/src/core/Util.js#L132-L151
+var templateRe = /\{ *([\w_ -]+) *\}/g
+
+export function template(str, data) {
+ return str.replace(templateRe, function (str, key) {
+ var value = data[key]
+
+ if (value === undefined) {
+ throw new Error('No value provided for variable ' + str)
+ } else if (typeof value === 'function') {
+ value = value(data)
+ }
+ return value
+ })
+}
diff --git a/umap/static/umap/js/umap.autocomplete.js b/umap/static/umap/js/umap.autocomplete.js
index 3da1bdeb..c63679e1 100644
--- a/umap/static/umap/js/umap.autocomplete.js
+++ b/umap/static/umap/js/umap.autocomplete.js
@@ -153,7 +153,7 @@ U.AutoComplete = L.Class.extend({
this.displaySelected(choice)
this.hide()
if (this.options.callback) {
- L.Util.bind(this.options.callback, this)(choice)
+ U.Utils.bind(this.options.callback, this)(choice)
}
}
},
diff --git a/umap/static/umap/js/umap.controls.js b/umap/static/umap/js/umap.controls.js
index 138adcde..c6e5e38c 100644
--- a/umap/static/umap/js/umap.controls.js
+++ b/umap/static/umap/js/umap.controls.js
@@ -476,7 +476,7 @@ U.PermanentCreditsControl = L.Control.extend({
},
setCredits: function () {
- this.paragraphContainer.innerHTML = L.Util.toHTML(this.map.options.permanentCredit)
+ this.paragraphContainer.innerHTML = U.Utils.toHTML(this.map.options.permanentCredit)
},
setBackground: function () {
@@ -820,7 +820,7 @@ const ControlsMixin = {
this.permissions.addOwnerLink('h5', container)
if (this.options.description) {
const description = L.DomUtil.create('div', 'umap-map-description', container)
- description.innerHTML = L.Util.toHTML(this.options.description)
+ description.innerHTML = U.Utils.toHTML(this.options.description)
}
const datalayerContainer = L.DomUtil.create('div', 'datalayer-container', container)
this.eachVisibleDataLayer((datalayer) => {
@@ -832,7 +832,7 @@ const ControlsMixin = {
datalayer.onceLoaded(function () {
datalayer.renderLegend(legend)
if (datalayer.options.description) {
- description.innerHTML = L.Util.toHTML(datalayer.options.description)
+ description.innerHTML = U.Utils.toHTML(datalayer.options.description)
}
})
datalayer.renderToolbox(headline)
@@ -846,7 +846,7 @@ const ControlsMixin = {
'p',
'',
credits,
- L.Util.toHTML(this.options.longCredit || this.options.shortCredit)
+ U.Utils.toHTML(this.options.longCredit || this.options.shortCredit)
)
}
if (this.options.licence) {
@@ -1077,7 +1077,7 @@ U.TileLayerControl = L.Control.IconLayers.extend({
// when the tilelayer is actually added to the map (needs this._tileZoom
// to be defined)
// Fixme when https://github.com/Leaflet/Leaflet/pull/9201 is released
- const icon = L.Util.template(
+ const icon = U.Utils.template(
layer.options.url_template,
this.map.demoTileInfos
)
@@ -1150,7 +1150,7 @@ U.TileLayerChooser = L.Control.extend({
el = L.DomUtil.create('li', selectedClass, this._tilelayers_container),
img = L.DomUtil.create('img', '', el),
name = L.DomUtil.create('div', '', el)
- img.src = L.Util.template(tilelayer.options.url_template, this.map.demoTileInfos)
+ img.src = U.Utils.template(tilelayer.options.url_template, this.map.demoTileInfos)
img.loading = 'lazy'
name.textContent = tilelayer.options.name
L.DomEvent.on(
@@ -1187,7 +1187,7 @@ U.AttributionControl = L.Control.Attribution.extend({
const shortCredit = this._map.getOption('shortCredit'),
captionMenus = this._map.getOption('captionMenus')
if (shortCredit) {
- L.DomUtil.add('span', '', container, ` — ${L.Util.toHTML(shortCredit)}`)
+ L.DomUtil.add('span', '', container, ` — ${U.Utils.toHTML(shortCredit)}`)
}
if (captionMenus) {
const link = L.DomUtil.add('a', '', container, ` — ${L._('About')}`)
diff --git a/umap/static/umap/js/umap.core.js b/umap/static/umap/js/umap.core.js
index a7cabbc3..58acb343 100644
--- a/umap/static/umap/js/umap.core.js
+++ b/umap/static/umap/js/umap.core.js
@@ -1,277 +1,3 @@
-/*
- * Utils
- */
-L.Util.queryString = (name, fallback) => {
- const decode = (s) => decodeURIComponent(s.replace(/\+/g, ' '))
- const qs = window.location.search.slice(1).split('&'),
- qa = {}
- for (const i in qs) {
- const key = qs[i].split('=')
- if (!key) continue
- qa[decode(key[0])] = key[1] ? decode(key[1]) : 1
- }
- return qa[name] || fallback
-}
-
-L.Util.booleanFromQueryString = (name) => {
- const value = L.Util.queryString(name)
- return value === '1' || value === 'true'
-}
-
-L.Util.setFromQueryString = (options, name) => {
- const value = L.Util.queryString(name)
- 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'
-}
-L.Util.setNumberFromQueryString = (options, name) => {
- const value = +L.Util.queryString(name)
- if (!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
- options[name] = value
- }
-}
-L.Util.escapeHTML = (s) => {
- s = s ? s.toString() : ''
- s = DOMPurify.sanitize(s, {
- USE_PROFILES: { html: true },
- ADD_TAGS: ['iframe'],
- ALLOWED_TAGS: [
- 'h3',
- 'h4',
- 'h5',
- 'hr',
- 'strong',
- 'em',
- 'ul',
- 'li',
- 'a',
- 'div',
- 'iframe',
- 'img',
- 'br',
- ],
- ADD_ATTR: ['target', 'allow', 'allowfullscreen', 'frameborder', 'scrolling'],
- ALLOWED_ATTR: ['href', 'src', 'width', 'height'],
- // Added: `geo:` URL scheme as defined in RFC5870:
- // https://www.rfc-editor.org/rfc/rfc5870.html
- // The base RegExp comes from:
- // https://github.com/cure53/DOMPurify/blob/main/src/regexp.js#L10
- ALLOWED_URI_REGEXP:
- /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|geo):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,
- })
- return s
-}
-L.Util.toHTML = (r, options) => {
- if (!r) return ''
- const target = (options && options.target) || 'blank'
- let ii
-
- // detect newline format
- const newline = r.indexOf('\r\n') != -1 ? '\r\n' : r.indexOf('\n') != -1 ? '\n' : ''
-
- // headings and hr
- r = r.replace(/^### (.*)/gm, '$1
')
- r = r.replace(/^## (.*)/gm, '$1
')
- r = r.replace(/^# (.*)/gm, '$1
')
- r = r.replace(/^---/gm, '
')
-
- // bold, italics
- r = r.replace(/\*\*(.*?)\*\*/g, '$1')
- r = r.replace(/\*(.*?)\*/g, '$1')
-
- // unordered lists
- r = r.replace(/^\*\* (.*)/gm, '')
- r = r.replace(/^\* (.*)/gm, '')
- for (ii = 0; ii < 3; ii++)
- r = r.replace(new RegExp(`
${newline}`, 'g'), newline)
-
- // links
- r = r.replace(/(\[\[http)/g, '[[h_t_t_p') // Escape for avoiding clash between [[http://xxx]] and http://xxx
- r = r.replace(/({{http)/g, '{{h_t_t_p')
- r = r.replace(/(=http)/g, '=h_t_t_p') // http://xxx as query string, see https://github.com/umap-project/umap/issues/607
- r = r.replace(/(https?:[^ \<)\n]*)/g, `$1`)
- r = r.replace(
- /\[\[(h_t_t_ps?:[^\]|]*?)\]\]/g,
- `$1`
- )
- r = r.replace(
- /\[\[(h_t_t_ps?:[^|]*?)\|(.*?)\]\]/g,
- `$2`
- )
- r = r.replace(/\[\[([^\]|]*?)\]\]/g, `$1`)
- r = r.replace(/\[\[([^|]*?)\|(.*?)\]\]/g, `$2`)
-
- // iframe
- r = r.replace(
- /{{{(h_t_t_ps?[^ |{]*)}}}/g,
- ''
- )
- r = r.replace(
- /{{{(h_t_t_ps?[^ |{]*)\|(\d*)(px)?}}}/g,
- ''
- )
- r = r.replace(
- /{{{(h_t_t_ps?[^ |{]*)\|(\d*)(px)?\*(\d*)(px)?}}}/g,
- ''
- )
-
- // images
- r = r.replace(/{{([^\]|]*?)}}/g, '
')
- r = r.replace(
- /{{([^|]*?)\|(\d*?)(px)?}}/g,
- '
'
- )
-
- //Unescape http
- r = r.replace(/(h_t_t_p)/g, 'http')
-
- // Preserver line breaks
- if (newline) r = r.replace(new RegExp(`${newline}(?=[^]+)`, 'g'), `
${newline}`)
-
- r = L.Util.escapeHTML(r)
-
- return r
-}
-L.Util.isObject = (what) => typeof what === 'object' && what !== null
-L.Util.CopyJSON = (geojson) => JSON.parse(JSON.stringify(geojson))
-L.Util.detectFileType = (f) => {
- const filename = f.name ? escape(f.name.toLowerCase()) : ''
- function ext(_) {
- return filename.indexOf(_) !== -1
- }
- 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 (f.type === 'text/csv' || ext('.csv') || ext('.tsv') || ext('.dsv')) {
- return 'csv'
- }
- if (ext('.xml') || ext('.osm')) return 'osm'
- if (ext('.umap')) return 'umap'
-}
-
-L.Util.usableOption = (options, option) =>
- options[option] !== undefined && options[option] !== ''
-
-L.Util.greedyTemplate = (str, data, ignore) => {
- function getValue(data, path) {
- let value = data
- for (let i = 0; i < path.length; i++) {
- value = value[path[i]]
- if (value === undefined) break
- }
- return value
- }
-
- if (typeof str !== 'string') return ''
-
- return str.replace(
- /\{ *([^\{\}/\-]+)(?:\|("[^"]*"))? *\}/g,
- (str, key, staticFallback) => {
- const vars = key.split('|')
- let value
- let path
- if (staticFallback !== undefined) {
- vars.push(staticFallback)
- }
- for (let i = 0; i < vars.length; i++) {
- path = vars[i]
- 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
- }
- if (value === undefined) {
- if (ignore) value = str
- else value = ''
- }
- return value
- }
- )
-}
-
-L.Util.naturalSort = (a, b) => {
- return a
- .toString()
- .toLowerCase()
- .localeCompare(b.toString().toLowerCase(), L.lang || 'en', {
- sensitivity: 'base',
- numeric: true,
- })
-}
-
-L.Util.sortFeatures = (features, sortKey) => {
- const sortKeys = (sortKey || 'name').split(',')
-
- const sort = (a, b, i) => {
- let sortKey = sortKeys[i],
- reverse = 1
- if (sortKey[0] === '-') {
- reverse = -1
- sortKey = sortKey.substring(1)
- }
- let score
- const valA = a.properties[sortKey] || ''
- const valB = b.properties[sortKey] || ''
- if (!valA) score = -1
- else if (!valB) score = 1
- else score = L.Util.naturalSort(valA, valB)
- if (score === 0 && sortKeys[i + 1]) return sort(a, b, i + 1)
- return score * reverse
- }
-
- features.sort((a, b) => {
- if (!a.properties || !b.properties) {
- return 0
- }
- return sort(a, b, 0)
- })
-
- return features
-}
-
-L.Util.flattenCoordinates = (coords) => {
- while (coords[0] && typeof coords[0][0] !== 'number') coords = coords[0]
- return coords
-}
-
-L.Util.buildQueryString = (params) => {
- const query_string = []
- for (const key in params) {
- query_string.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
- }
- return query_string.join('&')
-}
-
-L.Util.getBaseUrl = () => `//${window.location.host}${window.location.pathname}`
-
-L.Util.hasVar = (value) => {
- return typeof value === 'string' && value.indexOf('{') != -1
-}
-
-L.Util.isPath = function (value) {
- return value && value.length && value.startsWith('/')
-}
-
-L.Util.isRemoteUrl = function (value) {
- return value && value.length && value.startsWith('http')
-}
-
-L.Util.isDataImage = function (value) {
- return value && value.length && value.startsWith('data:image')
-}
-
L.Util.copyToClipboard = function (textToCopy) {
// https://stackoverflow.com/a/65996386
// Navigator clipboard api needs a secure context (https)
@@ -299,11 +25,46 @@ L.Util.copyToClipboard = function (textToCopy) {
}
}
-L.Util.normalize = function (s) {
- return (s || '')
- .toLowerCase()
- .normalize('NFD')
- .replace(/[\u0300-\u036f]/g, '')
+L.Util.queryString = function (name, fallback) {
+ const decode = (s) => decodeURIComponent(s.replace(/\+/g, ' '))
+ const qs = window.location.search.slice(1).split('&'),
+ qa = {}
+ for (const i in qs) {
+ const key = qs[i].split('=')
+ if (!key) continue
+ qa[decode(key[0])] = key[1] ? decode(key[1]) : 1
+ }
+ return qa[name] || fallback
+}
+
+L.Util.booleanFromQueryString = function (name) {
+ const value = L.Util.queryString(name)
+ return value === '1' || value === 'true'
+}
+
+L.Util.setFromQueryString = function (options, name) {
+ const value = L.Util.queryString(name)
+ if (typeof value !== 'undefined') options[name] = value
+}
+
+L.Util.setBooleanFromQueryString = function (options, name) {
+ const value = L.Util.queryString(name)
+ if (typeof value !== 'undefined') options[name] = value == '1' || value == 'true'
+}
+
+L.Util.setNumberFromQueryString = function (options, name) {
+ const value = +L.Util.queryString(name)
+ if (!isNaN(value)) options[name] = value
+}
+
+L.Util.setNullableBooleanFromQueryString = function (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
+ options[name] = value
+ }
}
L.DomUtil.add = (tagName, className, container, content) => {
@@ -367,7 +128,7 @@ L.DomUtil.createCopiableInput = (parent, label, value) => {
'',
wrapper,
'',
- () => L.Util.copyToClipboard(input.value),
+ () => U.Utils.copyToClipboard(input.value),
this
)
button.title = L._('copy')
diff --git a/umap/static/umap/js/umap.datalayer.permissions.js b/umap/static/umap/js/umap.datalayer.permissions.js
index f50706d9..f65b05dc 100644
--- a/umap/static/umap/js/umap.datalayer.permissions.js
+++ b/umap/static/umap/js/umap.datalayer.permissions.js
@@ -46,7 +46,7 @@ U.DataLayerPermissions = L.Class.extend({
},
getUrl: function () {
- return L.Util.template(this.datalayer.map.options.urls.datalayer_permissions, {
+ return U.Utils.template(this.datalayer.map.options.urls.datalayer_permissions, {
map_id: this.datalayer.map.options.umap_id,
pk: this.datalayer.umap_id,
})
diff --git a/umap/static/umap/js/umap.features.js b/umap/static/umap/js/umap.features.js
index 1d41215c..e38595ad 100644
--- a/umap/static/umap/js/umap.features.js
+++ b/umap/static/umap/js/umap.features.js
@@ -59,7 +59,7 @@ U.FeatureMixin = {
getPermalink: function () {
const slug = this.getSlug()
if (slug)
- return `${L.Util.getBaseUrl()}?${L.Util.buildQueryString({ feature: slug })}${
+ return `${U.Utils.getBaseUrl()}?${U.Utils.buildQueryString({ feature: slug })}${
window.location.hash
}`
},
@@ -204,7 +204,8 @@ U.FeatureMixin = {
if (fallback === undefined) fallback = this.datalayer.options.name
const key = this.getOption('labelKey') || 'name'
// Variables mode.
- if (L.Util.hasVar(key)) return L.Util.greedyTemplate(key, this.extendedProperties())
+ if (U.Utils.hasVar(key))
+ return U.Utils.greedyTemplate(key, this.extendedProperties())
// Simple mode.
return this.properties[key] || this.properties.title || fallback
},
@@ -291,7 +292,7 @@ U.FeatureMixin = {
let value = fallback
if (typeof this.staticOptions[option] !== 'undefined') {
value = this.staticOptions[option]
- } else if (L.Util.usableOption(this.properties._umap_options, option)) {
+ } else if (U.Utils.usableOption(this.properties._umap_options, option)) {
value = this.properties._umap_options[option]
} else if (this.datalayer) {
value = this.datalayer.getOption(option, this)
@@ -304,9 +305,9 @@ U.FeatureMixin = {
getDynamicOption: function (option, fallback) {
let value = this.getOption(option, fallback)
// There is a variable inside.
- if (L.Util.hasVar(value)) {
- value = L.Util.greedyTemplate(value, this.properties, true)
- if (L.Util.hasVar(value)) value = this.map.getDefaultOption(option)
+ if (U.Utils.hasVar(value)) {
+ value = U.Utils.greedyTemplate(value, this.properties, true)
+ if (U.Utils.hasVar(value)) value = this.map.getDefaultOption(option)
}
return value
},
@@ -485,7 +486,7 @@ U.FeatureMixin = {
options.permanent = showLabel === true
this.unbindTooltip()
if ((showLabel === true || showLabel === null) && displayName)
- this.bindTooltip(L.Util.escapeHTML(displayName), options)
+ this.bindTooltip(U.Utils.escapeHTML(displayName), options)
},
matchFilter: function (filter, keys) {
@@ -1059,7 +1060,7 @@ U.Polyline = L.Polyline.extend({
const geojson = this.toGeoJSON()
geojson.geometry.type = 'Polygon'
geojson.geometry.coordinates = [
- L.Util.flattenCoordinates(geojson.geometry.coordinates),
+ U.Utils.flattenCoordinates(geojson.geometry.coordinates),
]
const polygon = this.datalayer.geojsonToFeatures(geojson)
polygon.edit()
@@ -1199,7 +1200,7 @@ U.Polygon = L.Polygon.extend({
toPolyline: function () {
const geojson = this.toGeoJSON()
geojson.geometry.type = 'LineString'
- geojson.geometry.coordinates = L.Util.flattenCoordinates(
+ geojson.geometry.coordinates = U.Utils.flattenCoordinates(
geojson.geometry.coordinates
)
const polyline = this.datalayer.geojsonToFeatures(geojson)
diff --git a/umap/static/umap/js/umap.forms.js b/umap/static/umap/js/umap.forms.js
index 5031e152..865da9f5 100644
--- a/umap/static/umap/js/umap.forms.js
+++ b/umap/static/umap/js/umap.forms.js
@@ -492,8 +492,8 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
this.buildTabs()
const value = this.value()
if (U.Icon.RECENT.length) this.showRecentTab()
- else if (!value || L.Util.isPath(value)) this.showSymbolsTab()
- else if (L.Util.isRemoteUrl(value) || L.Util.isDataImage(value)) this.showURLTab()
+ 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',
@@ -567,7 +567,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
updatePreview: function () {
this.buttons.innerHTML = ''
if (this.isDefault()) return
- if (!L.Util.hasVar(this.value())) {
+ 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)
L.DomEvent.on(box, 'click', this.onDefine, this)
@@ -585,11 +585,11 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
addIconPreview: function (pictogram, parent) {
const baseClass = 'umap-pictogram-choice',
value = pictogram.src,
- search = L.Util.normalize(this.searchInput.value),
+ search = U.Utils.normalize(this.searchInput.value),
title = pictogram.attribution
? `${pictogram.name} — © ${pictogram.attribution}`
: pictogram.name || pictogram.src
- if (search && L.Util.normalize(title).indexOf(search) === -1) return
+ 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)
U.Icon.makeIconElement(value, container)
@@ -637,7 +637,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
categories[category].push(props)
}
const sorted = Object.entries(categories).toSorted(([a], [b]) =>
- L.Util.naturalSort(a, b)
+ U.Utils.naturalSort(a, b, L.lang)
)
for (let [name, items] of sorted) {
this.addCategory(items, name)
@@ -688,7 +688,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
showURLTab: function () {
this.openTab('url')
const value =
- L.Util.isRemoteUrl(this.value()) || L.Util.isDataImage(this.value())
+ U.Utils.isRemoteUrl(this.value()) || U.Utils.isDataImage(this.value())
? this.value()
: null
const input = this.buildInput(this.body, value)
diff --git a/umap/static/umap/js/umap.icon.js b/umap/static/umap/js/umap.icon.js
index 7eae6575..80198afd 100644
--- a/umap/static/umap/js/umap.icon.js
+++ b/umap/static/umap/js/umap.icon.js
@@ -18,7 +18,7 @@ U.Icon = L.DivIcon.extend({
},
_setRecent: function (url) {
- if (L.Util.hasVar(url)) 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)
@@ -50,7 +50,10 @@ U.Icon = L.DivIcon.extend({
},
formatUrl: function (url, feature) {
- return L.Util.greedyTemplate(url || '', feature ? feature.extendedProperties() : {})
+ return U.Utils.greedyTemplate(
+ url || '',
+ feature ? feature.extendedProperties() : {}
+ )
},
onAdd: function () {},
@@ -206,7 +209,7 @@ U.Icon.Cluster = L.DivIcon.extend({
})
U.Icon.isImg = function (src) {
- return L.Util.isPath(src) || L.Util.isRemoteUrl(src) || L.Util.isDataImage(src)
+ return U.Utils.isPath(src) || U.Utils.isRemoteUrl(src) || U.Utils.isDataImage(src)
}
U.Icon.makeIconElement = function (src, parent) {
@@ -236,7 +239,11 @@ U.Icon.setIconContrast = function (icon, parent, src, bgcolor) {
if (L.DomUtil.contrastedColor(parent, bgcolor)) {
// Decide whether to switch svg to white or not, but do it
// only for internal SVG, as invert could do weird things
- if (L.Util.isPath(src) && src.endsWith('.svg') && src !== U.SCHEMA.iconUrl.default) {
+ if (
+ U.Utils.isPath(src) &&
+ src.endsWith('.svg') &&
+ src !== U.SCHEMA.iconUrl.default
+ ) {
// Must be called after icon container is added to the DOM
// An image
icon.style.filter = 'invert(1)'
diff --git a/umap/static/umap/js/umap.importer.js b/umap/static/umap/js/umap.importer.js
index 5da209da..0f1a1fdb 100644
--- a/umap/static/umap/js/umap.importer.js
+++ b/umap/static/umap/js/umap.importer.js
@@ -102,7 +102,7 @@ U.Importer = L.Class.extend({
let type = '',
newType
for (let i = 0; i < e.target.files.length; i++) {
- newType = L.Util.detectFileType(e.target.files[i])
+ newType = U.Utils.detectFileType(e.target.files[i])
if (!type && newType) type = newType
if (type && newType !== type) {
type = ''
diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js
index 64ae48b3..1fae103f 100644
--- a/umap/static/umap/js/umap.js
+++ b/umap/static/umap/js/umap.js
@@ -76,6 +76,7 @@ U.Map = L.Map.extend({
.split(',')
}
+
let editedFeature = null
const self = this
try {
@@ -344,7 +345,7 @@ U.Map = L.Map.extend({
document.body,
'umap-caption-bar-enabled',
this.options.captionBar ||
- (this.options.slideshow && this.options.slideshow.active)
+ (this.options.slideshow && this.options.slideshow.active)
)
L.DomUtil.classIf(
document.body,
@@ -732,7 +733,7 @@ U.Map = L.Map.extend({
},
getOption: function (option) {
- if (L.Util.usableOption(this.options, option)) return this.options[option]
+ if (U.Utils.usableOption(this.options, option)) return this.options[option]
return this.getDefaultOption(option)
},
@@ -789,7 +790,7 @@ U.Map = L.Map.extend({
},
processFileToImport: function (file, layer, type) {
- type = type || L.Util.detectFileType(file)
+ type = type || U.Utils.detectFileType(file)
if (!type) {
this.ui.alert({
content: L._('Unable to detect format of file {filename}', {
@@ -992,7 +993,7 @@ U.Map = L.Map.extend({
{
label: L._('Copy link'),
callback: () => {
- L.Util.copyToClipboard(data.permissions.anonymous_edit_url)
+ U.Utils.copyToClipboard(data.permissions.anonymous_edit_url)
this.ui.alert({
content: L._('Secret edit link copied to clipboard!'),
level: 'info',
@@ -1263,7 +1264,7 @@ U.Map = L.Map.extend({
},
_editTilelayer: function (container) {
- if (!L.Util.isObject(this.options.tilelayer)) {
+ if (!U.Utils.isObject(this.options.tilelayer)) {
this.options.tilelayer = {}
}
const tilelayerFields = [
@@ -1316,7 +1317,7 @@ U.Map = L.Map.extend({
},
_editOverlay: function (container) {
- if (!L.Util.isObject(this.options.overlay)) {
+ if (!U.Utils.isObject(this.options.overlay)) {
this.options.overlay = {}
}
const overlayFields = [
@@ -1367,7 +1368,7 @@ U.Map = L.Map.extend({
},
_editBounds: function (container) {
- if (!L.Util.isObject(this.options.limitBounds)) {
+ if (!U.Utils.isObject(this.options.limitBounds)) {
this.options.limitBounds = {}
}
const limitBounds = L.DomUtil.createFieldset(container, L._('Limit bounds'))
@@ -1401,10 +1402,10 @@ U.Map = L.Map.extend({
L._('Use current bounds'),
function () {
const bounds = this.getBounds()
- this.options.limitBounds.south = L.Util.formatNum(bounds.getSouth())
- this.options.limitBounds.west = L.Util.formatNum(bounds.getWest())
- this.options.limitBounds.north = L.Util.formatNum(bounds.getNorth())
- this.options.limitBounds.east = L.Util.formatNum(bounds.getEast())
+ this.options.limitBounds.south = U.Utils.formatNum(bounds.getSouth())
+ this.options.limitBounds.west = U.Utils.formatNum(bounds.getWest())
+ this.options.limitBounds.north = U.Utils.formatNum(bounds.getNorth())
+ this.options.limitBounds.east = U.Utils.formatNum(bounds.getEast())
boundsBuilder.fetchAll()
this.isDirty = true
this.handleLimitBounds()
@@ -1572,10 +1573,10 @@ U.Map = L.Map.extend({
initCaptionBar: function () {
const container = L.DomUtil.create(
- 'div',
- 'umap-caption-bar',
- this._controlContainer
- ),
+ 'div',
+ 'umap-caption-bar',
+ this._controlContainer
+ ),
name = L.DomUtil.create('h3', '', container)
L.DomEvent.disableClickPropagation(container)
this.permissions.addOwnerLink('span', container)
@@ -1796,12 +1797,12 @@ U.Map = L.Map.extend({
},
localizeUrl: function (url) {
- return L.Util.greedyTemplate(url, this.getGeoContext(), true)
+ return U.Utils.greedyTemplate(url, this.getGeoContext(), true)
},
proxyUrl: function (url, ttl) {
if (this.options.urls.ajax_proxy) {
- url = L.Util.greedyTemplate(this.options.urls.ajax_proxy, {
+ url = U.Utils.greedyTemplate(this.options.urls.ajax_proxy, {
url: encodeURIComponent(url),
ttl: ttl,
})
diff --git a/umap/static/umap/js/umap.layer.js b/umap/static/umap/js/umap.layer.js
index 1ae0b1ac..0279691a 100644
--- a/umap/static/umap/js/umap.layer.js
+++ b/umap/static/umap/js/umap.layer.js
@@ -97,7 +97,7 @@ U.Layer.Cluster = L.MarkerClusterGroup.extend({
},
getEditableOptions: function () {
- if (!L.Util.isObject(this.datalayer.options.cluster)) {
+ if (!U.Utils.isObject(this.datalayer.options.cluster)) {
this.datalayer.options.cluster = {}
}
return [
@@ -155,7 +155,7 @@ U.Layer.Choropleth = L.FeatureGroup.extend({
initialize: function (datalayer) {
this.datalayer = datalayer
- if (!L.Util.isObject(this.datalayer.options.choropleth)) {
+ if (!U.Utils.isObject(this.datalayer.options.choropleth)) {
this.datalayer.options.choropleth = {}
}
L.FeatureGroup.prototype.initialize.call(
@@ -381,7 +381,7 @@ U.Layer.Heat = L.HeatLayer.extend({
},
getEditableOptions: function () {
- if (!L.Util.isObject(this.datalayer.options.heat)) {
+ if (!U.Utils.isObject(this.datalayer.options.heat)) {
this.datalayer.options.heat = {}
}
return [
@@ -461,8 +461,8 @@ U.Layer.Heat = L.HeatLayer.extend({
this._latlngs[i].alt !== undefined
? this._latlngs[i].alt
: this._latlngs[i][2] !== undefined
- ? +this._latlngs[i][2]
- : 1
+ ? +this._latlngs[i][2]
+ : 1
grid[y] = grid[y] || []
cell = grid[y][x]
@@ -724,16 +724,16 @@ U.DataLayer = L.Evented.extend({
},
backupData: function () {
- this._geojson_bk = L.Util.CopyJSON(this._geojson)
+ this._geojson_bk = U.Utils.CopyJSON(this._geojson)
},
reindex: function () {
const features = []
this.eachFeature((feature) => features.push(feature))
- L.Util.sortFeatures(features, this.map.getOption('sortKey'))
+ U.Utils.sortFeatures(features, this.map.getOption('sortKey'), L.lang)
this._index = []
for (let i = 0; i < features.length; i++) {
- this._index.push(L.Util.stamp(features[i]))
+ this._index.push(U.Utils.stamp(features[i]))
}
},
@@ -793,16 +793,16 @@ U.DataLayer = L.Evented.extend({
},
backupOptions: function () {
- this._backupOptions = L.Util.CopyJSON(this.options)
+ this._backupOptions = U.Utils.CopyJSON(this.options)
},
resetOptions: function () {
- this.options = L.Util.CopyJSON(this._backupOptions)
+ this.options = U.Utils.CopyJSON(this._backupOptions)
},
setOptions: function (options) {
delete options.geojson
- this.options = L.Util.CopyJSON(U.DataLayer.prototype.options) // Start from fresh.
+ this.options = U.Utils.CopyJSON(U.DataLayer.prototype.options) // Start from fresh.
this.updateOptions(options)
},
@@ -824,7 +824,7 @@ U.DataLayer = L.Evented.extend({
_dataUrl: function () {
const template = this.map.options.urls.datalayer_view
- let url = L.Util.template(template, {
+ let url = U.Utils.template(template, {
pk: this.umap_id,
map_id: this.map.options.umap_id,
})
@@ -971,7 +971,7 @@ U.DataLayer = L.Evented.extend({
let latlngs
if (features) {
- L.Util.sortFeatures(features, this.map.getOption('sortKey'))
+ U.Utils.sortFeatures(features, this.map.getOption('sortKey'), L.lang)
for (i = 0, len = features.length; i < len; i++) {
this.geojsonToFeatures(features[i])
}
@@ -1061,7 +1061,7 @@ U.DataLayer = L.Evented.extend({
importFromFile: function (f, type) {
const reader = new FileReader()
- type = type || L.Util.detectFileType(f)
+ type = type || U.Utils.detectFileType(f)
reader.readAsText(f)
reader.onload = (e) => this.importRaw(e.target.result, type)
},
@@ -1079,21 +1079,21 @@ U.DataLayer = L.Evented.extend({
},
getDeleteUrl: function () {
- return L.Util.template(this.map.options.urls.datalayer_delete, {
+ return U.Utils.template(this.map.options.urls.datalayer_delete, {
pk: this.umap_id,
map_id: this.map.options.umap_id,
})
},
getVersionsUrl: function () {
- return L.Util.template(this.map.options.urls.datalayer_versions, {
+ return U.Utils.template(this.map.options.urls.datalayer_versions, {
pk: this.umap_id,
map_id: this.map.options.umap_id,
})
},
getVersionUrl: function (name) {
- return L.Util.template(this.map.options.urls.datalayer_version, {
+ return U.Utils.template(this.map.options.urls.datalayer_version, {
pk: this.umap_id,
map_id: this.map.options.umap_id,
name: name,
@@ -1112,10 +1112,10 @@ U.DataLayer = L.Evented.extend({
},
clone: function () {
- const options = L.Util.CopyJSON(this.options)
+ const options = U.Utils.CopyJSON(this.options)
options.name = L._('Clone of {name}', { name: this.options.name })
delete options.id
- const geojson = L.Util.CopyJSON(this._geojson),
+ const geojson = U.Utils.CopyJSON(this._geojson),
datalayer = this.map.createDataLayer(options)
datalayer.fromGeoJSON(geojson)
return datalayer
@@ -1276,7 +1276,7 @@ U.DataLayer = L.Evented.extend({
)
popupFieldset.appendChild(builder.build())
- if (!L.Util.isObject(this.options.remoteData)) {
+ if (!U.Utils.isObject(this.options.remoteData)) {
this.options.remoteData = {}
}
const remoteDataFields = [
@@ -1371,7 +1371,7 @@ U.DataLayer = L.Evented.extend({
},
getOwnOption: function (option) {
- if (L.Util.usableOption(this.options, option)) return this.options[option]
+ if (U.Utils.usableOption(this.options, option)) return this.options[option]
},
getOption: function (option, feature) {
@@ -1668,6 +1668,6 @@ L.TileLayer.include({
},
getAttribution: function () {
- return L.Util.toHTML(this.options.attribution)
+ return U.Utils.toHTML(this.options.attribution)
},
})
diff --git a/umap/static/umap/js/umap.permissions.js b/umap/static/umap/js/umap.permissions.js
index 72d601c3..9d01f668 100644
--- a/umap/static/umap/js/umap.permissions.js
+++ b/umap/static/umap/js/umap.permissions.js
@@ -62,9 +62,8 @@ U.MapPermissions = L.Class.extend({
title = L.DomUtil.create('h3', '', container)
if (this.isAnonymousMap()) {
if (this.options.anonymous_edit_url) {
- const helpText = `${L._('Secret edit link:')}
${
- this.options.anonymous_edit_url
- }`
+ const helpText = `${L._('Secret edit link:')}
${this.options.anonymous_edit_url
+ }`
L.DomUtil.add('p', 'help-text', container, helpText)
fields.push([
'options.edit_status',
@@ -171,13 +170,13 @@ U.MapPermissions = L.Class.extend({
},
getUrl: function () {
- return L.Util.template(this.map.options.urls.map_update_permissions, {
+ return U.Utils.template(this.map.options.urls.map_update_permissions, {
map_id: this.map.options.umap_id,
})
},
getAttachUrl: function () {
- return L.Util.template(this.map.options.urls.map_attach_owner, {
+ return U.Utils.template(this.map.options.urls.map_attach_owner, {
map_id: this.map.options.umap_id,
})
},
diff --git a/umap/static/umap/js/umap.popup.js b/umap/static/umap/js/umap.popup.js
index 64db0713..e4354985 100644
--- a/umap/static/umap/js/umap.popup.js
+++ b/umap/static/umap/js/umap.popup.js
@@ -124,12 +124,12 @@ U.PopupTemplate.Default = L.Class.extend({
let center
properties = this.feature.extendedProperties()
// Resolve properties inside description
- properties.description = L.Util.greedyTemplate(
+ properties.description = U.Utils.greedyTemplate(
this.feature.properties.description || '',
properties
)
- content = L.Util.greedyTemplate(template, properties)
- content = L.Util.toHTML(content, { target: target })
+ content = U.Utils.greedyTemplate(template, properties)
+ content = U.Utils.toHTML(content, { target: target })
container.innerHTML = content
return container
},
@@ -211,7 +211,7 @@ U.PopupTemplate.Table = U.PopupTemplate.BaseWithTitle.extend({
for (const key in this.feature.properties) {
if (typeof this.feature.properties[key] === 'object' || key === 'name') continue
// TODO, manage links (url, mailto, wikipedia...)
- this.addRow(table, key, L.Util.escapeHTML(this.feature.properties[key]).trim())
+ this.addRow(table, key, U.Utils.escapeHTML(this.feature.properties[key]).trim())
}
return table
},
diff --git a/umap/static/umap/js/umap.share.js b/umap/static/umap/js/umap.share.js
index ad7c7b14..3284df76 100644
--- a/umap/static/umap/js/umap.share.js
+++ b/umap/static/umap/js/umap.share.js
@@ -51,7 +51,7 @@ U.Share = L.Class.extend({
L.DomUtil.createCopiableInput(
this.container,
L._('Link to view the map'),
- window.location.protocol + L.Util.getBaseUrl()
+ window.location.protocol + U.Utils.getBaseUrl()
)
if (this.map.options.shortUrl) {
@@ -84,7 +84,7 @@ U.Share = L.Class.extend({
this.container,
L._('All data and settings of the map')
)
- const downloadUrl = L.Util.template(this.map.options.urls.map_download, {
+ const downloadUrl = U.Utils.template(this.map.options.urls.map_download, {
map_id: this.map.options.umap_id,
})
const link = L.DomUtil.createLink(
@@ -213,7 +213,7 @@ U.IframeExporter = L.Evented.extend({
initialize: function (map) {
this.map = map
- this.baseUrl = L.Util.getBaseUrl()
+ this.baseUrl = U.Utils.getBaseUrl()
// Use map default, not generic default
this.queryString.onLoadPanel = this.map.getOption('onLoadPanel')
},
@@ -241,7 +241,7 @@ U.IframeExporter = L.Evented.extend({
}
const currentView = this.options.currentView ? window.location.hash : ''
const queryString = L.extend({}, this.queryString, options)
- return `${this.baseUrl}?${L.Util.buildQueryString(queryString)}${currentView}`
+ return `${this.baseUrl}?${U.Utils.buildQueryString(queryString)}${currentView}`
},
build: function () {
diff --git a/umap/static/umap/test/index.html b/umap/static/umap/test/index.html
index 9fee3dba..66ce24ef 100644
--- a/umap/static/umap/test/index.html
+++ b/umap/static/umap/test/index.html
@@ -28,7 +28,6 @@
-
diff --git a/umap/templates/umap/js.html b/umap/templates/umap/js.html
index cc78ea9f..8c8c206e 100644
--- a/umap/templates/umap/js.html
+++ b/umap/templates/umap/js.html
@@ -42,7 +42,6 @@
-