Apply PrettierJS and Lebab to all remaining JS files

This commit is contained in:
David Larlet 2023-05-10 22:00:37 -04:00
parent 48288cc8cb
commit 5ef666a069
13 changed files with 8575 additions and 7450 deletions

View file

@ -1,113 +1,117 @@
L.U.AutoComplete = L.Class.extend({ L.U.AutoComplete = L.Class.extend({
options: { options: {
placeholder: 'Start typing...', placeholder: 'Start typing...',
emptyMessage: 'No result', emptyMessage: 'No result',
allowFree: true, allowFree: true,
minChar: 2, minChar: 2,
maxResults: 5 maxResults: 5,
}, },
CACHE: '', CACHE: '',
RESULTS: [], RESULTS: [],
initialize: function (el, options) { initialize(el, options) {
this.el = el; this.el = el
var ui = new L.U.UI(document.querySelector('header')); const ui = new L.U.UI(document.querySelector('header'))
this.xhr = new L.U.Xhr(ui); this.xhr = new L.U.Xhr(ui)
L.setOptions(this, options); L.setOptions(this, options)
var CURRENT = null; let CURRENT = null
try { try {
Object.defineProperty(this, 'CURRENT', { Object.defineProperty(this, 'CURRENT', {
get: function () { get() {
return CURRENT; return CURRENT
}, },
set: function (index) { set(index) {
if (typeof index === 'object') { if (typeof index === 'object') {
index = this.resultToIndex(index); index = this.resultToIndex(index)
} }
CURRENT = index; CURRENT = index
} },
}); })
} catch (e) { } catch (e) {
// Hello IE8 // Hello IE8
} }
return this; return this
}, },
createInput: function () { createInput() {
this.input = L.DomUtil.element('input', { this.input = L.DomUtil.element(
'input',
{
type: 'text', type: 'text',
placeholder: this.options.placeholder, placeholder: this.options.placeholder,
autocomplete: 'off', autocomplete: 'off',
className: this.options.className className: this.options.className,
}, this.el); },
L.DomEvent.on(this.input, 'keydown', this.onKeyDown, this); this.el
L.DomEvent.on(this.input, 'keyup', this.onKeyUp, this); )
L.DomEvent.on(this.input, 'blur', this.onBlur, this); L.DomEvent.on(this.input, 'keydown', this.onKeyDown, this)
L.DomEvent.on(this.input, 'keyup', this.onKeyUp, this)
L.DomEvent.on(this.input, 'blur', this.onBlur, this)
}, },
createContainer: function () { createContainer() {
this.container = L.DomUtil.element('ul', {className: 'umap-autocomplete'}, document.body); this.container = L.DomUtil.element(
'ul',
{ className: 'umap-autocomplete' },
document.body
)
}, },
resizeContainer: function() resizeContainer() {
{ const l = this.getLeft(this.input)
var l = this.getLeft(this.input); const t = this.getTop(this.input) + this.input.offsetHeight
var t = this.getTop(this.input) + this.input.offsetHeight; this.container.style.left = `${l}px`
this.container.style.left = l + 'px'; this.container.style.top = `${t}px`
this.container.style.top = t + 'px'; const width = this.options.width ? this.options.width : this.input.offsetWidth - 2
var width = this.options.width ? this.options.width : this.input.offsetWidth - 2; this.container.style.width = `${width}px`
this.container.style.width = width + 'px';
}, },
onKeyDown(e) {
onKeyDown: function (e) {
switch (e.keyCode) { switch (e.keyCode) {
case L.U.Keys.TAB: case L.U.Keys.TAB:
if(this.CURRENT !== null) this.setChoice(); if (this.CURRENT !== null) this.setChoice()
L.DomEvent.stop(e); L.DomEvent.stop(e)
break; break
case L.U.Keys.ENTER: case L.U.Keys.ENTER:
L.DomEvent.stop(e); L.DomEvent.stop(e)
this.setChoice(); this.setChoice()
break; break
case L.U.Keys.ESC: case L.U.Keys.ESC:
L.DomEvent.stop(e); L.DomEvent.stop(e)
this.hide(); this.hide()
break; break
case L.U.Keys.DOWN: case L.U.Keys.DOWN:
if(this.RESULTS.length > 0) { if (this.RESULTS.length > 0) {
if(this.CURRENT !== null && this.CURRENT < this.RESULTS.length - 1) { // what if one result? if (this.CURRENT !== null && this.CURRENT < this.RESULTS.length - 1) {
this.CURRENT++; // what if one result?
this.highlight(); this.CURRENT++
} this.highlight()
else if(this.CURRENT === null) { } else if (this.CURRENT === null) {
this.CURRENT = 0; this.CURRENT = 0
this.highlight(); this.highlight()
} }
} }
break; break
case L.U.Keys.UP: case L.U.Keys.UP:
if(this.CURRENT !== null) { if (this.CURRENT !== null) {
L.DomEvent.stop(e); L.DomEvent.stop(e)
} }
if(this.RESULTS.length > 0) { if (this.RESULTS.length > 0) {
if(this.CURRENT > 0) { if (this.CURRENT > 0) {
this.CURRENT--; this.CURRENT--
this.highlight(); this.highlight()
} } else if (this.CURRENT === 0) {
else if(this.CURRENT === 0) { this.CURRENT = null
this.CURRENT = null; this.highlight()
this.highlight();
} }
} }
break; break
} }
}, },
onKeyUp: function (e) { onKeyUp({ keyCode }) {
var special = [ const special = [
L.U.Keys.TAB, L.U.Keys.TAB,
L.U.Keys.ENTER, L.U.Keys.ENTER,
L.U.Keys.LEFT, L.U.Keys.LEFT,
@ -117,198 +121,220 @@ L.U.AutoComplete = L.Class.extend({
L.U.Keys.APPLE, L.U.Keys.APPLE,
L.U.Keys.SHIFT, L.U.Keys.SHIFT,
L.U.Keys.ALT, L.U.Keys.ALT,
L.U.Keys.CTRL L.U.Keys.CTRL,
]; ]
if (special.indexOf(e.keyCode) === -1) if (!special.includes(keyCode)) {
{ this.search()
this.search();
} }
}, },
onBlur: function () { onBlur() {
var self = this; const self = this
setTimeout(function () { setTimeout(() => {
self.hide(); self.hide()
}, 100); }, 100)
}, },
clear: function () { clear() {
this.RESULTS = []; this.RESULTS = []
this.CURRENT = null; this.CURRENT = null
this.CACHE = ''; this.CACHE = ''
this.container.innerHTML = ''; this.container.innerHTML = ''
}, },
hide: function() { hide() {
this.clear(); this.clear()
this.container.style.display = 'none'; this.container.style.display = 'none'
this.input.value = ''; this.input.value = ''
}, },
setChoice: function (choice) { setChoice(choice = this.RESULTS[this.CURRENT]) {
choice = choice || this.RESULTS[this.CURRENT];
if (choice) { if (choice) {
this.input.value = choice.item.label; this.input.value = choice.item.label
this.options.on_select(choice); this.options.on_select(choice)
this.displaySelected(choice); this.displaySelected(choice)
this.hide(); this.hide()
if (this.options.callback) { if (this.options.callback) {
L.Util.bind(this.options.callback, this)(choice); L.Util.bind(this.options.callback, this)(choice)
} }
} }
}, },
search: function() { search() {
var val = this.input.value; const val = this.input.value
if (val.length < this.options.minChar) { if (val.length < this.options.minChar) {
this.clear(); this.clear()
return; return
} }
if( val + '' === this.CACHE + '') return; if (`${val}` === `${this.CACHE}`) return
else this.CACHE = val; else this.CACHE = val
this._do_search(val, function (data) { this._do_search(
this.handleResults(data.data); val,
}, this); function (data) {
this.handleResults(data.data)
},
this
)
}, },
createResult: function (item) { createResult(item) {
var el = L.DomUtil.element('li', {}, this.container); const el = L.DomUtil.element('li', {}, this.container)
el.textContent = item.label; el.textContent = item.label
var result = { const result = {
item: item, item,
el: el el,
}; }
L.DomEvent.on(el, 'mouseover', function () { L.DomEvent.on(
this.CURRENT = result; el,
this.highlight(); 'mouseover',
}, this); function () {
L.DomEvent.on(el, 'mousedown', function () { this.CURRENT = result
this.setChoice(); this.highlight()
}, this); },
return result; this
)
L.DomEvent.on(
el,
'mousedown',
function () {
this.setChoice()
},
this
)
return result
}, },
resultToIndex: function (result) { resultToIndex(result) {
var out = null; let out = null
this.forEach(this.RESULTS, function (item, index) { this.forEach(this.RESULTS, (item, index) => {
if (item.item.value == result.item.value) { if (item.item.value == result.item.value) {
out = index; out = index
return; return
} }
}); })
return out; return out
}, },
handleResults: function(data) { handleResults(data) {
var self = this; const self = this
this.clear(); this.clear()
this.container.style.display = 'block'; this.container.style.display = 'block'
this.resizeContainer(); this.resizeContainer()
this.forEach(data, function (item) { this.forEach(data, (item) => {
self.RESULTS.push(self.createResult(item)); self.RESULTS.push(self.createResult(item))
}); })
this.CURRENT = 0; this.CURRENT = 0
this.highlight(); this.highlight()
//TODO manage no results //TODO manage no results
}, },
highlight: function () { highlight() {
var self = this; const self = this
this.forEach(this.RESULTS, function (result, index) { this.forEach(this.RESULTS, ({ el }, index) => {
if (index === self.CURRENT) L.DomUtil.addClass(result.el, 'on'); if (index === self.CURRENT) L.DomUtil.addClass(el, 'on')
else L.DomUtil.removeClass(result.el, 'on'); else L.DomUtil.removeClass(el, 'on')
}); })
}, },
getLeft: function (el) { getLeft(el) {
var tmp = el.offsetLeft; let tmp = el.offsetLeft
el = el.offsetParent; el = el.offsetParent
while(el) { while (el) {
tmp += el.offsetLeft; tmp += el.offsetLeft
el = el.offsetParent; el = el.offsetParent
} }
return tmp; return tmp
}, },
getTop: function (el) { getTop(el) {
var tmp = el.offsetTop; let tmp = el.offsetTop
el = el.offsetParent; el = el.offsetParent
while(el) { while (el) {
tmp += el.offsetTop; tmp += el.offsetTop
el = el.offsetParent; el = el.offsetParent
} }
return tmp; return tmp
}, },
forEach: function (els, callback) { forEach(els, callback) {
Array.prototype.forEach.call(els, callback); Array.prototype.forEach.call(els, callback)
} },
})
});
L.U.AutoComplete.Ajax = L.U.AutoComplete.extend({ L.U.AutoComplete.Ajax = L.U.AutoComplete.extend({
initialize(el, options) {
initialize: function (el, options) { L.U.AutoComplete.prototype.initialize.call(this, el, options)
L.U.AutoComplete.prototype.initialize.call(this, el, options); if (!this.el) return this
if (!this.el) return this; this.createInput()
this.createInput(); this.createContainer()
this.createContainer(); this.selected_container = this.initSelectedContainer()
this.selected_container = this.initSelectedContainer();
}, },
optionToResult: function (option) { optionToResult({ value, innerHTML }) {
return { return {
value: option.value, value: value,
label: option.innerHTML label: innerHTML,
}; }
}, },
_do_search: function (val, callback, context) { _do_search(val, callback, context) {
val = val.toLowerCase(); val = val.toLowerCase()
this.xhr.get('/agnocomplete/AutocompleteUser/?q=' + encodeURIComponent(val), {callback: callback, context: context || this}); this.xhr.get(`/agnocomplete/AutocompleteUser/?q=${encodeURIComponent(val)}`, {
} callback,
context: context || this,
}); })
},
})
L.U.AutoComplete.Ajax.SelectMultiple = L.U.AutoComplete.Ajax.extend({ L.U.AutoComplete.Ajax.SelectMultiple = L.U.AutoComplete.Ajax.extend({
initSelectedContainer() {
initSelectedContainer: function () { return L.DomUtil.after(
return L.DomUtil.after(this.input, L.DomUtil.element('ul', {className: 'umap-multiresult'})); this.input,
L.DomUtil.element('ul', { className: 'umap-multiresult' })
)
}, },
displaySelected: function (result) { displaySelected(result) {
var result_el = L.DomUtil.element('li', {}, this.selected_container); const result_el = L.DomUtil.element('li', {}, this.selected_container)
result_el.textContent = result.item.label; result_el.textContent = result.item.label
var close = L.DomUtil.element('span', {className: 'close'}, result_el); const close = L.DomUtil.element('span', { className: 'close' }, result_el)
close.textContent = '×'; close.textContent = '×'
L.DomEvent.on(close, 'click', function () { L.DomEvent.on(
this.selected_container.removeChild(result_el); close,
this.options.on_unselect(result); 'click',
}, this); function () {
this.hide(); this.selected_container.removeChild(result_el)
} this.options.on_unselect(result)
},
}); this
)
this.hide()
},
})
L.U.AutoComplete.Ajax.Select = L.U.AutoComplete.Ajax.extend({ L.U.AutoComplete.Ajax.Select = L.U.AutoComplete.Ajax.extend({
initSelectedContainer() {
initSelectedContainer: function () { return L.DomUtil.after(
return L.DomUtil.after(this.input, L.DomUtil.element('div', {className: 'umap-singleresult'})); this.input,
L.DomUtil.element('div', { className: 'umap-singleresult' })
)
}, },
displaySelected: function (result) { displaySelected({ item }) {
var result_el = L.DomUtil.element('div', {}, this.selected_container); const result_el = L.DomUtil.element('div', {}, this.selected_container)
result_el.textContent = result.item.label; result_el.textContent = item.label
var close = L.DomUtil.element('span', {className: 'close'}, result_el); const close = L.DomUtil.element('span', { className: 'close' }, result_el)
close.textContent = '×'; close.textContent = '×'
this.input.style.display = 'none'; this.input.style.display = 'none'
L.DomEvent.on(close, 'click', function () { L.DomEvent.on(
this.selected_container.innerHTML = ''; close,
this.input.style.display = 'block'; 'click',
}, this); function () {
this.hide(); this.selected_container.innerHTML = ''
} this.input.style.display = 'block'
},
}); this
)
this.hide()
},
})

File diff suppressed because it is too large Load diff

View file

@ -1,304 +1,309 @@
/* Poor man pub/sub handler, enough for now */ /* Poor man pub/sub handler, enough for now */
L.UmapSingleton = L.Evented.extend({}); L.UmapSingleton = L.Evented.extend({})
L.U = new L.UmapSingleton(); L.U = new L.UmapSingleton()
L.U.Map = L.Map.extend({}); L.U.Map = L.Map.extend({})
/* /*
* Utils * Utils
*/ */
L.Util.queryString = function (name, fallback) { L.Util.queryString = (name, fallback) => {
var decode = function (s) { return decodeURIComponent(s.replace(/\+/g, ' ')); }; const decode = (s) => decodeURIComponent(s.replace(/\+/g, ' '))
var qs = window.location.search.slice(1).split('&'), qa = {}; const qs = window.location.search.slice(1).split('&')
for (var i in qs) { const qa = {}
var key = qs[i].split('='); for (const i in qs) {
if (!key) continue; const key = qs[i].split('=')
qa[decode(key[0])] = key[1] ? decode(key[1]) : 1; if (!key) continue
qa[decode(key[0])] = key[1] ? decode(key[1]) : 1
} }
return qa[name] || fallback; return qa[name] || fallback
}; }
L.Util.booleanFromQueryString = function (name) { L.Util.booleanFromQueryString = (name) => {
var value = L.Util.queryString(name); const value = L.Util.queryString(name)
return value === '1' || value === 'true'; return value === '1' || value === 'true'
}; }
L.Util.setFromQueryString = function (options, name) { L.Util.setFromQueryString = (options, name) => {
var value = L.Util.queryString(name); const value = L.Util.queryString(name)
if (typeof value !== 'undefined') options[name] = value; if (typeof value !== 'undefined') options[name] = value
}; }
L.Util.setBooleanFromQueryString = function (options, name) { L.Util.setBooleanFromQueryString = (options, name) => {
var value = L.Util.queryString(name); const value = L.Util.queryString(name)
if (typeof value !== 'undefined') options[name] = value == '1' || value == 'true'; if (typeof value !== 'undefined') options[name] = value == '1' || value == 'true'
}; }
L.Util.setNullableBooleanFromQueryString = function (options, name) { L.Util.setNullableBooleanFromQueryString = (options, name) => {
var value = L.Util.queryString(name); let value = L.Util.queryString(name)
if (typeof value !== 'undefined') { if (typeof value !== 'undefined') {
if (value === 'null') value = null; if (value === 'null') value = null
else if (value === '0' || value === 'false') value = false; else if (value === '0' || value === 'false') value = false
else value = true; else value = true
options[name] = value; options[name] = value
} }
}; }
L.Util.escapeHTML = function (s) { L.Util.escapeHTML = (s) => {
s = s? s.toString() : ''; s = s ? s.toString() : ''
return s.replace(/</gm, '&lt;'); return s.replace(/</gm, '&lt;')
}; }
L.Util.toHTML = function (r) { L.Util.toHTML = (r) => {
if (!r) return ''; if (!r) return ''
var ii; let ii
// detect newline format // detect newline format
var newline = r.indexOf('\r\n') != -1 ? '\r\n' : r.indexOf('\n') != -1 ? '\n' : ''; const newline = r.includes('\r\n') ? '\r\n' : r.includes('\n') ? '\n' : ''
// Escape tags // Escape tags
r = r.replace(/</gm, '&lt;'); r = r.replace(/</gm, '&lt;')
// headings and hr // headings and hr
r = r.replace(/^### (.*)/gm, '<h5>$1</h5>'); r = r.replace(/^### (.*)/gm, '<h5>$1</h5>')
r = r.replace(/^## (.*)/gm, '<h4>$1</h4>'); r = r.replace(/^## (.*)/gm, '<h4>$1</h4>')
r = r.replace(/^# (.*)/gm, '<h3>$1</h3>'); r = r.replace(/^# (.*)/gm, '<h3>$1</h3>')
r = r.replace(/^---/gm, '<hr>'); r = r.replace(/^---/gm, '<hr>')
// bold, italics // bold, italics
r = r.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>'); r = r.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
r = r.replace(/\*(.*?)\*/g, '<em>$1</em>'); r = r.replace(/\*(.*?)\*/g, '<em>$1</em>')
// unordered lists // unordered lists
r = r.replace(/^\*\* (.*)/gm, '<ul><ul><li>$1</li></ul></ul>'); r = r.replace(/^\*\* (.*)/gm, '<ul><ul><li>$1</li></ul></ul>')
r = r.replace(/^\* (.*)/gm, '<ul><li>$1</li></ul>'); r = r.replace(/^\* (.*)/gm, '<ul><li>$1</li></ul>')
for (ii = 0; ii < 3; ii++) r = r.replace(new RegExp('</ul>' + newline + '<ul>', 'g'), newline); for (ii = 0; ii < 3; ii++)
r = r.replace(new RegExp(`</ul>${newline}<ul>`, 'g'), newline)
// links // 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') // 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')
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(/(=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, '<a target="_blank" href="$1">$1</a>'); r = r.replace(/(https?:[^ \<)\n]*)/g, '<a target="_blank" href="$1">$1</a>')
r = r.replace(/\[\[(h_t_t_ps?:[^\]|]*?)\]\]/g, '<a target="_blank" href="$1">$1</a>'); r = r.replace(/\[\[(h_t_t_ps?:[^\]|]*?)\]\]/g, '<a target="_blank" href="$1">$1</a>')
r = r.replace(/\[\[(h_t_t_ps?:[^|]*?)\|(.*?)\]\]/g, '<a target="_blank" href="$1">$2</a>'); r = r.replace(
r = r.replace(/\[\[([^\]|]*?)\]\]/g, '<a href="$1">$1</a>'); /\[\[(h_t_t_ps?:[^|]*?)\|(.*?)\]\]/g,
r = r.replace(/\[\[([^|]*?)\|(.*?)\]\]/g, '<a href="$1">$2</a>'); '<a target="_blank" href="$1">$2</a>'
)
r = r.replace(/\[\[([^\]|]*?)\]\]/g, '<a href="$1">$1</a>')
r = r.replace(/\[\[([^|]*?)\|(.*?)\]\]/g, '<a href="$1">$2</a>')
// iframe // iframe
r = r.replace(/{{{(h_t_t_ps?[^ |{]*)}}}/g, '<div><iframe frameborder="0" src="$1" width="100%" height="300px"></iframe></div>'); r = r.replace(
r = r.replace(/{{{(h_t_t_ps?[^ |{]*)\|(\d*)(px)?}}}/g, '<div><iframe frameborder="0" src="$1" width="100%" height="$2px"></iframe></div>'); /{{{(h_t_t_ps?[^ |{]*)}}}/g,
r = r.replace(/{{{(h_t_t_ps?[^ |{]*)\|(\d*)(px)?\*(\d*)(px)?}}}/g, '<div><iframe frameborder="0" src="$1" width="$4px" height="$2px"></iframe></div>'); '<div><iframe frameborder="0" src="$1" width="100%" height="300px"></iframe></div>'
)
r = r.replace(
/{{{(h_t_t_ps?[^ |{]*)\|(\d*)(px)?}}}/g,
'<div><iframe frameborder="0" src="$1" width="100%" height="$2px"></iframe></div>'
)
r = r.replace(
/{{{(h_t_t_ps?[^ |{]*)\|(\d*)(px)?\*(\d*)(px)?}}}/g,
'<div><iframe frameborder="0" src="$1" width="$4px" height="$2px"></iframe></div>'
)
// images // images
r = r.replace(/{{([^\]|]*?)}}/g, '<img src="$1">'); r = r.replace(/{{([^\]|]*?)}}/g, '<img src="$1">')
r = r.replace(/{{([^|]*?)\|(\d*?)}}/g, '<img src="$1" width="$2">'); r = r.replace(/{{([^|]*?)\|(\d*?)}}/g, '<img src="$1" width="$2">')
//Unescape http //Unescape http
r = r.replace(/(h_t_t_p)/g, 'http'); r = r.replace(/(h_t_t_p)/g, 'http')
// Preserver line breaks // Preserver line breaks
if (newline) r = r.replace(new RegExp(newline + '(?=[^]+)', 'g'), '<br>' + newline); if (newline) r = r.replace(new RegExp(`${newline}(?=[^]+)`, 'g'), `<br>${newline}`)
return r; return r
}; }
L.Util.isObject = function (what) { L.Util.isObject = (what) => typeof what === 'object' && what !== null
return typeof what === 'object' && what !== null; L.Util.CopyJSON = (geojson) => JSON.parse(JSON.stringify(geojson))
}; L.Util.detectFileType = ({ name, type }) => {
L.Util.CopyJSON = function (geojson) { const filename = name ? escape(name.toLowerCase()) : ''
return JSON.parse(JSON.stringify(geojson));
};
L.Util.detectFileType = function (f) {
var filename = f.name ? escape(f.name.toLowerCase()) : '';
function ext(_) { function ext(_) {
return filename.indexOf(_) !== -1; return filename.includes(_)
} }
if (f.type === 'application/vnd.google-earth.kml+xml' || ext('.kml')) { if (type === 'application/vnd.google-earth.kml+xml' || ext('.kml')) {
return 'kml'; return 'kml'
} }
if (ext('.gpx')) return 'gpx'; if (ext('.gpx')) return 'gpx'
if (ext('.geojson') || ext('.json')) return 'geojson'; if (ext('.geojson') || ext('.json')) return 'geojson'
if (f.type === 'text/csv' || ext('.csv') || ext('.tsv') || ext('.dsv')) { if (type === 'text/csv' || ext('.csv') || ext('.tsv') || ext('.dsv')) {
return 'csv'; return 'csv'
} }
if (ext('.xml') || ext('.osm')) return 'osm'; if (ext('.xml') || ext('.osm')) return 'osm'
if (ext('.umap')) return 'umap'; if (ext('.umap')) return 'umap'
}; }
L.Util.usableOption = function (options, option) { L.Util.usableOption = (options, option) =>
return options[option] !== undefined && options[option] !== ''; options[option] !== undefined && options[option] !== ''
};
L.Util.greedyTemplate = function (str, data, ignore) { L.Util.greedyTemplate = (str, data, ignore) => {
function getValue(data, path) { function getValue(data, path) {
var value = data let value = data
for (var i = 0; i < path.length; i++) { for (let i = 0; i < path.length; i++) {
value = value[path[i]] value = value[path[i]]
if (value === undefined) break; if (value === undefined) break
} }
return value; return value
} }
return str.replace(/\{ *([\w_\:\.\|]+)(?:\|("[^"]*"))? *\}/g, function (str, key, staticFallback) { return str.replace(
var vars = key.split('|'), value, path; /\{ *([\w_\:\.\|]+)(?:\|("[^"]*"))? *\}/g,
(str, key, staticFallback) => {
const vars = key.split('|')
let value
let path
if (staticFallback !== undefined) { if (staticFallback !== undefined) {
vars.push(staticFallback); vars.push(staticFallback)
} }
for (var i = 0; i < vars.length; i++) { for (let i = 0; i < vars.length; i++) {
path = vars[i]; path = vars[i]
if (path.startsWith('"') && path.endsWith('"')) value = path.substring(1, path.length -1); // static default value. if (path.startsWith('"') && path.endsWith('"'))
else value = getValue(data, path.split('.')); value = path.substring(1, path.length - 1) // static default value.
if (value !== undefined) break; else value = getValue(data, path.split('.'))
if (value !== undefined) break
} }
if (value === undefined) { if (value === undefined) {
if (ignore) value = str; if (ignore) value = str
else value = ''; else value = ''
} }
return value; return value
}); }
}; )
}
L.Util.sortFeatures = function (features, sortKey) { L.Util.sortFeatures = (features, sortKey) => {
var sortKeys = (sortKey || 'name').split(','); const sortKeys = (sortKey || 'name').split(',')
var sort = function (a, b, i) { const sort = (a, b, i) => {
var sortKey = sortKeys[i], score, const sortKey = sortKeys[i]
valA = a.properties[sortKey] || '', let score
valB = b.properties[sortKey] || ''; const valA = a.properties[sortKey] || ''
const valB = b.properties[sortKey] || ''
if (!valA) { if (!valA) {
score = -1; score = -1
} else if (!valB) { } else if (!valB) {
score = 1; score = 1
} else { } else {
score = valA.toString().toLowerCase().localeCompare(valB.toString().toLowerCase()); score = valA.toString().toLowerCase().localeCompare(valB.toString().toLowerCase())
}
if (score === 0 && sortKeys[i + 1]) return sort(a, b, i + 1)
return score
} }
if (score === 0 && sortKeys[i + 1]) return sort(a, b, i + 1);
return score;
};
features.sort(function (a, b) { features.sort((a, b) => {
if (!a.properties || !b.properties) { if (!a.properties || !b.properties) {
return 0; return 0
} }
return sort(a, b, 0); return sort(a, b, 0)
}); })
return features
}
return features; L.Util.flattenCoordinates = (coords) => {
}; while (coords[0] && typeof coords[0][0] !== 'number') coords = coords[0]
return coords
}
L.Util.flattenCoordinates = function (coords) { L.Util.buildQueryString = (params) => {
while (coords[0] && typeof coords[0][0] !== 'number') coords = coords[0]; const query_string = []
return coords; for (const key in params) {
}; query_string.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
L.Util.buildQueryString = function (params) {
var query_string = [];
for (var key in params) {
query_string.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
} }
return query_string.join('&'); return query_string.join('&')
}; }
L.Util.getBaseUrl = function () { L.Util.getBaseUrl = () => `//${window.location.host}${window.location.pathname}`
return '//' + window.location.host + window.location.pathname;
};
L.DomUtil.add = function (tagName, className, container, content) { L.DomUtil.add = (tagName, className, container, content) => {
var el = L.DomUtil.create(tagName, className, container); const el = L.DomUtil.create(tagName, className, container)
if (content) { if (content) {
if (content.nodeType && content.nodeType === 1) { if (content.nodeType && content.nodeType === 1) {
el.appendChild(content); el.appendChild(content)
} } else {
else { el.innerHTML = content
el.innerHTML = content;
} }
} }
return el; return el
}; }
L.DomUtil.createFieldset = function (container, legend, options) { L.DomUtil.createFieldset = (container, legend, options = {}) => {
options = options || {}; const fieldset = L.DomUtil.create('div', 'fieldset toggle', container)
var fieldset = L.DomUtil.create('div', 'fieldset toggle', container); const legendEl = L.DomUtil.add('h5', 'legend style_options_toggle', fieldset, legend)
var legendEl = L.DomUtil.add('h5', 'legend style_options_toggle', fieldset, legend); const fieldsEl = L.DomUtil.add('div', 'fields with-transition', fieldset)
var fieldsEl = L.DomUtil.add('div', 'fields with-transition', fieldset);
L.DomEvent.on(legendEl, 'click', function () { L.DomEvent.on(legendEl, 'click', function () {
if (L.DomUtil.hasClass(fieldset, 'on')) { if (L.DomUtil.hasClass(fieldset, 'on')) {
L.DomUtil.removeClass(fieldset, 'on'); L.DomUtil.removeClass(fieldset, 'on')
} else { } else {
L.DomUtil.addClass(fieldset, 'on'); L.DomUtil.addClass(fieldset, 'on')
if (options.callback) options.callback.call(options.context || this); if (options.callback) options.callback.call(options.context || this)
} }
}); })
return fieldsEl; return fieldsEl
}; }
L.DomUtil.classIf = function (el, className, bool) { L.DomUtil.classIf = (el, className, bool) => {
if (bool) L.DomUtil.addClass(el, className); if (bool) L.DomUtil.addClass(el, className)
else L.DomUtil.removeClass(el, className); else L.DomUtil.removeClass(el, className)
}; }
L.DomUtil.element = (what, attrs, parent) => {
L.DomUtil.element = function (what, attrs, parent) { const el = document.createElement(what)
var el = document.createElement(what); for (const attr in attrs) {
for (var attr in attrs) { el[attr] = attrs[attr]
el[attr] = attrs[attr];
} }
if (typeof parent !== 'undefined') { if (typeof parent !== 'undefined') {
parent.appendChild(el); parent.appendChild(el)
} }
return el; return el
}; }
L.DomUtil.before = (target, el) => {
target.parentNode.insertBefore(el, target)
return el
}
L.DomUtil.before = function (target, el) { L.DomUtil.after = ({ parentNode, nextSibling }, el) => {
target.parentNode.insertBefore(el, target); parentNode.insertBefore(el, nextSibling)
return el; return el
}; }
L.DomUtil.after = function (target, el) L.DomUtil.RGBRegex = /rgb *\( *([0-9]{1,3}) *, *([0-9]{1,3}) *, *([0-9]{1,3}) *\)/
{
target.parentNode.insertBefore(el, target.nextSibling);
return el;
};
L.DomUtil.RGBRegex = /rgb *\( *([0-9]{1,3}) *, *([0-9]{1,3}) *, *([0-9]{1,3}) *\)/; L.DomUtil.TextColorFromBackgroundColor = (el) => {
let out = '#000000'
L.DomUtil.TextColorFromBackgroundColor = function (el) { if (!window.getComputedStyle) {
var out = '#000000'; return out
if (!window.getComputedStyle) {return out;}
var rgb = window.getComputedStyle(el).getPropertyValue('background-color');
rgb = L.DomUtil.RGBRegex.exec(rgb);
if (!rgb || rgb.length !== 4) {return out;}
rgb = parseInt(rgb[1], 10) + parseInt(rgb[2], 10) + parseInt(rgb[3], 10);
if (rgb < (255 * 3 / 2)) {
out = '#ffffff';
} }
return out; let rgb = window.getComputedStyle(el).getPropertyValue('background-color')
}; rgb = L.DomUtil.RGBRegex.exec(rgb)
L.DomEvent.once = function (el, types, fn, context) { if (!rgb || rgb.length !== 4) {
return out
}
rgb = parseInt(rgb[1], 10) + parseInt(rgb[2], 10) + parseInt(rgb[3], 10)
if (rgb < (255 * 3) / 2) {
out = '#ffffff'
}
return out
}
L.DomEvent.once = (el, types, fn, context) => {
// cf https://github.com/Leaflet/Leaflet/pull/3528#issuecomment-134551575 // cf https://github.com/Leaflet/Leaflet/pull/3528#issuecomment-134551575
if (typeof types === 'object') { if (typeof types === 'object') {
for (var type in types) { for (const type in types) {
L.DomEvent.once(el, type, types[type], fn); L.DomEvent.once(el, type, types[type], fn)
} }
return L.DomEvent; return L.DomEvent
} }
var handler = L.bind(function () { const handler = L.bind(() => {
L.DomEvent L.DomEvent.off(el, types, fn, context).off(el, types, handler, context)
.off(el, types, fn, context) }, L.DomEvent)
.off(el, types, handler, context);
}, L.DomEvent);
// add a listener that's executed once and removed after that // add a listener that's executed once and removed after that
return L.DomEvent return L.DomEvent.on(el, types, fn, context).on(el, types, handler, context)
.on(el, types, fn, context) }
.on(el, types, handler, context);
};
/* /*
* Global events * Global events
*/ */
L.U.Keys = { L.U.Keys = {
LEFT: 37, LEFT: 37,
UP: 38, UP: 38,
@ -319,133 +324,187 @@ L.U.Keys = {
M: 77, M: 77,
P: 80, P: 80,
S: 83, S: 83,
Z: 90 Z: 90,
}; }
L.U.Help = L.Class.extend({ L.U.Help = L.Class.extend({
initialize(map) {
initialize: function (map) { this.map = map
this.map = map; this.box = L.DomUtil.create(
this.box = L.DomUtil.create('div', 'umap-help-box with-transition dark', document.body); 'div',
var closeLink = L.DomUtil.create('a', 'umap-close-link', this.box); 'umap-help-box with-transition dark',
closeLink.href = '#'; document.body
L.DomUtil.add('i', 'umap-close-icon', closeLink); )
var label = L.DomUtil.create('span', '', closeLink); const closeLink = L.DomUtil.create('a', 'umap-close-link', this.box)
label.title = label.textContent = L._('Close'); closeLink.href = '#'
this.content = L.DomUtil.create('div', 'umap-help-content', this.box); L.DomUtil.add('i', 'umap-close-icon', closeLink)
L.DomEvent.on(closeLink, 'click', this.hide, this); const label = L.DomUtil.create('span', '', closeLink)
label.title = label.textContent = L._('Close')
this.content = L.DomUtil.create('div', 'umap-help-content', this.box)
L.DomEvent.on(closeLink, 'click', this.hide, this)
}, },
onKeyDown: function (e) { onKeyDown({ keyCode }) {
var key = e.keyCode, const key = keyCode
ESC = 27; const ESC = 27
if (key === ESC) { if (key === ESC) {
this.hide(); this.hide()
} }
}, },
show: function () { show(...args) {
this.content.innerHTML = ''; this.content.innerHTML = ''
for (var i = 0, name; i < arguments.length; i++) { for (let i = 0, name; i < args.length; i++) {
name = arguments[i]; name = args[i]
L.DomUtil.add('div', 'umap-help-entry', this.content, this.resolve(name)); L.DomUtil.add('div', 'umap-help-entry', this.content, this.resolve(name))
} }
L.DomUtil.addClass(document.body, 'umap-help-on'); L.DomUtil.addClass(document.body, 'umap-help-on')
}, },
hide: function () { hide() {
L.DomUtil.removeClass(document.body, 'umap-help-on'); L.DomUtil.removeClass(document.body, 'umap-help-on')
}, },
visible: function () { visible() {
return L.DomUtil.hasClass(document.body, 'umap-help-on') return L.DomUtil.hasClass(document.body, 'umap-help-on')
}, },
resolve: function (name) { resolve(name) {
return typeof this[name] === 'function' ? this[name]() : this[name]; return typeof this[name] === 'function' ? this[name]() : this[name]
}, },
button: function (container, entries) { button(container, entries) {
var helpButton = L.DomUtil.create('a', 'umap-help-button', container); const helpButton = L.DomUtil.create('a', 'umap-help-button', container)
helpButton.href = '#'; helpButton.href = '#'
if (entries) { if (entries) {
L.DomEvent L.DomEvent.on(helpButton, 'click', L.DomEvent.stop).on(
.on(helpButton, 'click', L.DomEvent.stop) helpButton,
.on(helpButton, 'click', function (e) { 'click',
var args = typeof entries === 'string' ? [entries] : entries; function (e) {
this.show.apply(this, args); const args = typeof entries === 'string' ? [entries] : entries
}, this); this.show(...args)
},
this
)
} }
return helpButton; return helpButton
}, },
edit: function () { edit() {
var container = L.DomUtil.create('div', ''), const container = L.DomUtil.create('div', '')
self = this, const self = this
title = L.DomUtil.create('h3', '', container), const title = L.DomUtil.create('h3', '', container)
actionsContainer = L.DomUtil.create('ul', 'umap-edit-actions', container); const actionsContainer = L.DomUtil.create('ul', 'umap-edit-actions', container)
var addAction = function (action) { const addAction = (action) => {
var actionContainer = L.DomUtil.add('li', '', actionsContainer); const actionContainer = L.DomUtil.add('li', '', actionsContainer)
L.DomUtil.add('i', action.options.className, actionContainer), L.DomUtil.add('i', action.options.className, actionContainer),
L.DomUtil.add('span', '', actionContainer, action.options.tooltip); L.DomUtil.add('span', '', actionContainer, action.options.tooltip)
L.DomEvent.on(actionContainer, 'click', action.addHooks, action); L.DomEvent.on(actionContainer, 'click', action.addHooks, action)
L.DomEvent.on(actionContainer, 'click', self.hide, self); L.DomEvent.on(actionContainer, 'click', self.hide, self)
};
title.textContent = L._('Where do we go from here?');
for (var id in this.map.helpMenuActions) {
addAction(this.map.helpMenuActions[id]);
} }
return container; title.textContent = L._('Where do we go from here?')
for (const id in this.map.helpMenuActions) {
addAction(this.map.helpMenuActions[id])
}
return container
}, },
importFormats: function () { importFormats() {
var container = L.DomUtil.create('div'); const container = L.DomUtil.create('div')
L.DomUtil.add('h3', '', container, 'GeojSON'); L.DomUtil.add('h3', '', container, 'GeojSON')
L.DomUtil.add('p', '', container, L._('All properties are imported.')); L.DomUtil.add('p', '', container, L._('All properties are imported.'))
L.DomUtil.add('h3', '', container, 'GPX'); L.DomUtil.add('h3', '', container, 'GPX')
L.DomUtil.add('p', '', container, L._('Properties imported:') + 'name, desc'); L.DomUtil.add('p', '', container, `${L._('Properties imported:')}name, desc`)
L.DomUtil.add('h3', '', container, 'KML'); L.DomUtil.add('h3', '', container, 'KML')
L.DomUtil.add('p', '', container, L._('Properties imported:') + 'name, description'); L.DomUtil.add('p', '', container, `${L._('Properties imported:')}name, description`)
L.DomUtil.add('h3', '', container, 'CSV'); L.DomUtil.add('h3', '', container, 'CSV')
L.DomUtil.add('p', '', container, L._('Comma, tab or semi-colon separated values. SRS WGS84 is implied. Only Point geometries are imported. The import will look at the column headers for any mention of «lat» and «lon» at the begining of the header, case insensitive. All other column are imported as properties.')); L.DomUtil.add(
L.DomUtil.add('h3', '', container, 'uMap'); 'p',
L.DomUtil.add('p', '', container, L._('Imports all umap data, including layers and settings.')); '',
return container; container,
L._(
'Comma, tab or semi-colon separated values. SRS WGS84 is implied. Only Point geometries are imported. The import will look at the column headers for any mention of «lat» and «lon» at the begining of the header, case insensitive. All other column are imported as properties.'
)
)
L.DomUtil.add('h3', '', container, 'uMap')
L.DomUtil.add(
'p',
'',
container,
L._('Imports all umap data, including layers and settings.')
)
return container
}, },
textFormatting: function () { textFormatting() {
var container = L.DomUtil.create('div'), const container = L.DomUtil.create('div')
title = L.DomUtil.add('h3', '', container, L._('Text formatting')), const title = L.DomUtil.add('h3', '', container, L._('Text formatting'))
elements = L.DomUtil.create('ul', '', container); const elements = L.DomUtil.create('ul', '', container)
L.DomUtil.add('li', '', elements, L._('*simple star for italic*')); L.DomUtil.add('li', '', elements, L._('*simple star for italic*'))
L.DomUtil.add('li', '', elements, L._('**double star for bold**')); L.DomUtil.add('li', '', elements, L._('**double star for bold**'))
L.DomUtil.add('li', '', elements, L._('# one hash for main heading')); L.DomUtil.add('li', '', elements, L._('# one hash for main heading'))
L.DomUtil.add('li', '', elements, L._('## two hashes for second heading')); L.DomUtil.add('li', '', elements, L._('## two hashes for second heading'))
L.DomUtil.add('li', '', elements, L._('### three hashes for third heading')); L.DomUtil.add('li', '', elements, L._('### three hashes for third heading'))
L.DomUtil.add('li', '', elements, L._('Simple link: [[http://example.com]]')); L.DomUtil.add('li', '', elements, L._('Simple link: [[http://example.com]]'))
L.DomUtil.add('li', '', elements, L._('Link with text: [[http://example.com|text of the link]]')); L.DomUtil.add(
L.DomUtil.add('li', '', elements, L._('Image: {{http://image.url.com}}')); 'li',
L.DomUtil.add('li', '', elements, L._('Image with custom width (in px): {{http://image.url.com|width}}')); '',
L.DomUtil.add('li', '', elements, L._('Iframe: {{{http://iframe.url.com}}}')); elements,
L.DomUtil.add('li', '', elements, L._('Iframe with custom height (in px): {{{http://iframe.url.com|height}}}')); L._('Link with text: [[http://example.com|text of the link]]')
L.DomUtil.add('li', '', elements, L._('Iframe with custom height and width (in px): {{{http://iframe.url.com|height*width}}}')); )
L.DomUtil.add('li', '', elements, L._('--- for an horizontal rule')); L.DomUtil.add('li', '', elements, L._('Image: {{http://image.url.com}}'))
return container; L.DomUtil.add(
'li',
'',
elements,
L._('Image with custom width (in px): {{http://image.url.com|width}}')
)
L.DomUtil.add('li', '', elements, L._('Iframe: {{{http://iframe.url.com}}}'))
L.DomUtil.add(
'li',
'',
elements,
L._('Iframe with custom height (in px): {{{http://iframe.url.com|height}}}')
)
L.DomUtil.add(
'li',
'',
elements,
L._(
'Iframe with custom height and width (in px): {{{http://iframe.url.com|height*width}}}'
)
)
L.DomUtil.add('li', '', elements, L._('--- for an horizontal rule'))
return container
}, },
dynamicProperties: function () { dynamicProperties() {
var container = L.DomUtil.create('div'); const container = L.DomUtil.create('div')
L.DomUtil.add('h3', '', container, L._('Dynamic properties')); L.DomUtil.add('h3', '', container, L._('Dynamic properties'))
L.DomUtil.add('p', '', container, L._('Use placeholders with feature properties between brackets, eg. &#123;name&#125;, they will be dynamically replaced by the corresponding values.')); L.DomUtil.add(
return container; 'p',
'',
container,
L._(
'Use placeholders with feature properties between brackets, eg. &#123;name&#125;, they will be dynamically replaced by the corresponding values.'
)
)
return container
}, },
formatURL: L._('Supported variables that will be dynamically replaced') + ': {bbox}, {lat}, {lng}, {zoom}, {east}, {north}..., {left}, {top}...', formatURL: `${L._(
formatIconSymbol: L._('Symbol can be either a unicode character or an URL. You can use feature properties as variables: ex.: with "http://myserver.org/images/{name}.png", the {name} variable will be replaced by the "name" value of each marker.'), 'Supported variables that will be dynamically replaced'
)}: {bbox}, {lat}, {lng}, {zoom}, {east}, {north}..., {left}, {top}...`,
formatIconSymbol: L._(
'Symbol can be either a unicode character or an URL. You can use feature properties as variables: ex.: with "http://myserver.org/images/{name}.png", the {name} variable will be replaced by the "name" value of each marker.'
),
colorValue: L._('Must be a valid CSS value (eg.: DarkBlue or #123456)'), colorValue: L._('Must be a valid CSS value (eg.: DarkBlue or #123456)'),
smoothFactor: L._('How much to simplify the polyline on each zoom level (more = better performance and smoother look, less = more accurate)'), smoothFactor: L._(
dashArray: L._('A comma separated list of numbers that defines the stroke dash pattern. Ex.: "5, 10, 15".'), 'How much to simplify the polyline on each zoom level (more = better performance and smoother look, less = more accurate)'
),
dashArray: L._(
'A comma separated list of numbers that defines the stroke dash pattern. Ex.: "5, 10, 15".'
),
zoomTo: L._('Zoom level for automatic zooms'), zoomTo: L._('Zoom level for automatic zooms'),
labelKey: L._('The name of the property to use as feature label (ex.: "nom")'), labelKey: L._('The name of the property to use as feature label (ex.: "nom")'),
stroke: L._('Whether to display or not polygons paths.'), stroke: L._('Whether to display or not polygons paths.'),
@ -453,108 +512,111 @@ L.U.Help = L.Class.extend({
fillColor: L._('Optional. Same as color if not set.'), fillColor: L._('Optional. Same as color if not set.'),
shortCredit: L._('Will be displayed in the bottom right corner of the map'), shortCredit: L._('Will be displayed in the bottom right corner of the map'),
longCredit: L._('Will be visible in the caption of the map'), longCredit: L._('Will be visible in the caption of the map'),
permanentCredit: L._('Will be permanently visible in the bottom left corner of the map'), permanentCredit: L._(
'Will be permanently visible in the bottom left corner of the map'
),
sortKey: L._('Property to use for sorting features'), sortKey: L._('Property to use for sorting features'),
slugKey: L._('The name of the property to use as feature unique identifier.'), slugKey: L._('The name of the property to use as feature unique identifier.'),
filterKey: L._('Comma separated list of properties to use when filtering features'), filterKey: L._('Comma separated list of properties to use when filtering features'),
advancedFilterKey: L._('Comma separated list of properties to use for checkbox filtering'), advancedFilterKey: L._(
'Comma separated list of properties to use for checkbox filtering'
),
advancedFiltersNoResults: L._('No results for these filters'), advancedFiltersNoResults: L._('No results for these filters'),
interactive: L._('If false, the polygon will act as a part of the underlying map.'), interactive: L._('If false, the polygon will act as a part of the underlying map.'),
outlink: L._('Define link to open in a new window on polygon click.'), outlink: L._('Define link to open in a new window on polygon click.'),
dynamicRemoteData: L._('Fetch data each time map view changes.'), dynamicRemoteData: L._('Fetch data each time map view changes.'),
proxyRemoteData: L._('To use if remote server doesn\'t allow cross domain (slower)'), proxyRemoteData: L._("To use if remote server doesn't allow cross domain (slower)"),
browsable: L._('Set it to false to hide this layer from the slideshow, the data browser, the popup navigation…') browsable: L._(
}); 'Set it to false to hide this layer from the slideshow, the data browser, the popup navigation…'
),
})
L.U.Orderable = L.Evented.extend({ L.U.Orderable = L.Evented.extend({
options: { options: {
selector: 'li', selector: 'li',
color: '#374E75' color: '#374E75',
}, },
initialize: function (parent, options) { initialize(parent, options) {
L.Util.setOptions(this, options); L.Util.setOptions(this, options)
this.parent = parent; this.parent = parent
this.src = null; this.src = null
this.dst = null; this.dst = null
this.els = this.parent.querySelectorAll(this.options.selector); this.els = this.parent.querySelectorAll(this.options.selector)
for (var 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: function (node) { makeDraggable(node) {
node.draggable = true; node.draggable = true
L.DomEvent.on(node, 'dragstart', this.onDragStart, this); L.DomEvent.on(node, 'dragstart', this.onDragStart, this)
L.DomEvent.on(node, 'dragenter', this.onDragEnter, this); L.DomEvent.on(node, 'dragenter', this.onDragEnter, this)
L.DomEvent.on(node, 'dragover', this.onDragOver, this); L.DomEvent.on(node, 'dragover', this.onDragOver, this)
L.DomEvent.on(node, 'dragleave', this.onDragLeave, this); L.DomEvent.on(node, 'dragleave', this.onDragLeave, this)
L.DomEvent.on(node, 'drop', this.onDrop, this); L.DomEvent.on(node, 'drop', this.onDrop, this)
L.DomEvent.on(node, 'dragend', this.onDragEnd, this); L.DomEvent.on(node, 'dragend', this.onDragEnd, this)
}, },
nodeIndex: function (node) { nodeIndex(node) {
return Array.prototype.indexOf.call(this.parent.children, node); return Array.prototype.indexOf.call(this.parent.children, node)
}, },
findTarget: function (node) { findTarget(node) {
while (node) { while (node) {
if (this.nodeIndex(node) !== -1) return node; if (this.nodeIndex(node) !== -1) return node
node = node.parentNode; node = node.parentNode
} }
}, },
onDragStart: function (e) { onDragStart({ target, dataTransfer }) {
// e.target is the source node. // e.target is the source node.
this.src = e.target; this.src = target
this.initialIndex = this.nodeIndex(this.src); this.initialIndex = this.nodeIndex(this.src)
this.srcBackgroundColor = this.src.style.backgroundColor; this.srcBackgroundColor = this.src.style.backgroundColor
this.src.style.backgroundColor = this.options.color; this.src.style.backgroundColor = this.options.color
e.dataTransfer.effectAllowed = 'move'; dataTransfer.effectAllowed = 'move'
e.dataTransfer.setData('text/html', this.src.innerHTML); dataTransfer.setData('text/html', this.src.innerHTML)
}, },
onDragOver: function (e) { onDragOver(e) {
if (e.preventDefault) e.preventDefault(); // Necessary. Allows us to drop. if (e.preventDefault) e.preventDefault() // Necessary. Allows us to drop.
e.dataTransfer.dropEffect = 'move'; e.dataTransfer.dropEffect = 'move'
return false; return false
}, },
onDragEnter: function (e) { onDragEnter({ target }) {
// e.target is the current hover target. // e.target is the current hover target.
var dst = this.findTarget(e.target); const dst = this.findTarget(target)
if (!dst || dst === this.src) return; if (!dst || dst === this.src) return
this.dst = dst; this.dst = dst
var targetIndex = this.nodeIndex(this.dst), const targetIndex = this.nodeIndex(this.dst)
srcIndex = this.nodeIndex(this.src); const srcIndex = this.nodeIndex(this.src)
if (targetIndex > srcIndex) this.parent.insertBefore(this.dst, this.src); if (targetIndex > srcIndex) this.parent.insertBefore(this.dst, this.src)
else this.parent.insertBefore(this.src, this.dst); else this.parent.insertBefore(this.src, this.dst)
}, },
onDragLeave: function (e) { onDragLeave(e) {
// e.target is previous target element. // e.target is previous target element.
}, },
onDrop: function (e) { onDrop(e) {
// e.target is current target element. // e.target is current target element.
if (e.stopPropagation) e.stopPropagation(); // Stops the browser from redirecting. if (e.stopPropagation) e.stopPropagation() // Stops the browser from redirecting.
if (!this.dst) return; if (!this.dst) return
this.fire('drop', { this.fire('drop', {
src: this.src, src: this.src,
initialIndex: this.initialIndex, initialIndex: this.initialIndex,
finalIndex: this.nodeIndex(this.src), finalIndex: this.nodeIndex(this.src),
dst: this.dst dst: this.dst,
}); })
return false; return false
}, },
onDragEnd: function (e) { onDragEnd(e) {
// e.target is the source node. // e.target is the source node.
this.src.style.backgroundColor = this.srcBackgroundColor; this.src.style.backgroundColor = this.srcBackgroundColor
} },
})
});
L.LatLng.prototype.isValid = function () { L.LatLng.prototype.isValid = function () {
return !isNaN(this.lat) && !isNaN(this.lng); return !isNaN(this.lat) && !isNaN(this.lng)
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,143 +1,197 @@
// Dedicated object so we can deal with a separate dirty status, and thus // Dedicated object so we can deal with a separate dirty status, and thus
// call the endpoint only when needed, saving one call at each save. // call the endpoint only when needed, saving one call at each save.
L.U.MapPermissions = L.Class.extend({ L.U.MapPermissions = L.Class.extend({
options: { options: {
owner: null, owner: null,
editors: [], editors: [],
share_status: null, share_status: null,
edit_status: null edit_status: null,
}, },
initialize: function (map) { initialize(map) {
this.setOptions(map.options.permissions); this.setOptions(map.options.permissions)
this.map = map; this.map = map
var isDirty = false, let isDirty = false
self = this; const self = this
try { try {
Object.defineProperty(this, 'isDirty', { Object.defineProperty(this, 'isDirty', {
get: function () { get() {
return isDirty; return isDirty
}, },
set: function (status) { set(status) {
isDirty = status; isDirty = status
if (status) self.map.isDirty = status; if (status) self.map.isDirty = status
} },
}); })
} } catch (e) {
catch (e) {
// Certainly IE8, which has a limited version of defineProperty // Certainly IE8, which has a limited version of defineProperty
} }
}, },
setOptions: function (options) { setOptions(options) {
this.options = L.Util.setOptions(this, options); this.options = L.Util.setOptions(this, options)
}, },
isOwner: function () { isOwner() {
return this.map.options.user && this.map.options.permissions.owner && this.map.options.user.id == this.map.options.permissions.owner.id; return (
this.map.options.user &&
this.map.options.permissions.owner &&
this.map.options.user.id == this.map.options.permissions.owner.id
)
}, },
isAnonymousMap: function () { isAnonymousMap() {
return !this.map.options.permissions.owner; return !this.map.options.permissions.owner
}, },
getMap: function () { getMap() {
return this.map; return this.map
}, },
edit: function () { edit() {
if (!this.map.options.umap_id) return this.map.ui.alert({content: L._('Please save the map first'), level: 'info'}); if (!this.map.options.umap_id)
var container = L.DomUtil.create('div', 'permissions-panel'), return this.map.ui.alert({
fields = [], content: L._('Please save the map first'),
title = L.DomUtil.create('h4', '', container); level: 'info',
})
const container = L.DomUtil.create('div', 'permissions-panel')
const fields = []
const title = L.DomUtil.create('h4', '', container)
if (this.isAnonymousMap()) { if (this.isAnonymousMap()) {
if (this.options.anonymous_edit_url) { if (this.options.anonymous_edit_url) {
var helpText = L._('Secret edit link is:<br>{link}', {link: this.options.anonymous_edit_url}); const helpText = L._('Secret edit link is:<br>{link}', {
fields.push(['options.edit_status', {handler: 'IntSelect', label: L._('Who can edit'), selectOptions: this.map.options.anonymous_edit_statuses, helpText: helpText}]); link: this.options.anonymous_edit_url,
})
fields.push([
'options.edit_status',
{
handler: 'IntSelect',
label: L._('Who can edit'),
selectOptions: this.map.options.anonymous_edit_statuses,
helpText,
},
])
} }
} else { } else {
if (this.isOwner()) { if (this.isOwner()) {
fields.push(['options.edit_status', {handler: 'IntSelect', label: L._('Who can edit'), selectOptions: this.map.options.edit_statuses}]); fields.push([
fields.push(['options.share_status', {handler: 'IntSelect', label: L._('Who can view'), selectOptions: this.map.options.share_statuses}]); 'options.edit_status',
fields.push(['options.owner', {handler: 'ManageOwner', label: L._("Map's owner")}]); {
handler: 'IntSelect',
label: L._('Who can edit'),
selectOptions: this.map.options.edit_statuses,
},
])
fields.push([
'options.share_status',
{
handler: 'IntSelect',
label: L._('Who can view'),
selectOptions: this.map.options.share_statuses,
},
])
fields.push([
'options.owner',
{ handler: 'ManageOwner', label: L._("Map's owner") },
])
} }
fields.push(['options.editors', {handler: 'ManageEditors', label: L._("Map's editors")}]); fields.push([
'options.editors',
{ handler: 'ManageEditors', label: L._("Map's editors") },
])
} }
title.textContent = L._('Update permissions'); title.textContent = L._('Update permissions')
var builder = new L.U.FormBuilder(this, fields); const builder = new L.U.FormBuilder(this, fields)
var form = builder.build(); const form = builder.build()
container.appendChild(form); container.appendChild(form)
if (this.isAnonymousMap() && this.map.options.user) { if (this.isAnonymousMap() && this.map.options.user) {
// We have a user, and this user has come through here, so they can edit the map, so let's allow to own the map. // We have a user, and this user has come through here, so they can edit the map, so let's allow to own the map.
// Note: real check is made on the back office anyway. // Note: real check is made on the back office anyway.
var advancedActions = L.DomUtil.createFieldset(container, L._('Advanced actions')); const advancedActions = L.DomUtil.createFieldset(
var advancedButtons = L.DomUtil.create('div', 'button-bar', advancedActions); container,
var download = L.DomUtil.create('a', 'button', advancedButtons); L._('Advanced actions')
download.href = '#'; )
download.textContent = L._('Attach the map to my account'); const advancedButtons = L.DomUtil.create('div', 'button-bar', advancedActions)
L.DomEvent const download = L.DomUtil.create('a', 'button', advancedButtons)
.on(download, 'click', L.DomEvent.stop) download.href = '#'
.on(download, 'click', this.attach, this); download.textContent = L._('Attach the map to my account')
L.DomEvent.on(download, 'click', L.DomEvent.stop).on(
download,
'click',
this.attach,
this
)
} }
this.map.ui.openPanel({data: {html: container}, className: 'dark'}); this.map.ui.openPanel({ data: { html: container }, className: 'dark' })
}, },
attach: function () { attach() {
this.map.post(this.getAttachUrl(), { this.map.post(this.getAttachUrl(), {
callback: function () { callback() {
this.options.owner = this.map.options.user; this.options.owner = this.map.options.user
this.map.ui.alert({content: L._("Map has been attached to your account"), level: 'info'}); this.map.ui.alert({
this.map.ui.closePanel(); content: L._('Map has been attached to your account'),
level: 'info',
})
this.map.ui.closePanel()
}, },
context: this context: this,
}) })
}, },
save: function () { save() {
if (!this.isDirty) return this.map.continueSaving(); if (!this.isDirty) return this.map.continueSaving()
var formData = new FormData(); const formData = new FormData()
if (!this.isAnonymousMap() && this.options.editors) { if (!this.isAnonymousMap() && this.options.editors) {
var editors = this.options.editors.map(function (u) {return u.id}); const editors = this.options.editors.map(({ id }) => id)
for (var i = 0; i < this.options.editors.length; i++) formData.append('editors', this.options.editors[i].id); for (let i = 0; i < this.options.editors.length; i++)
formData.append('editors', this.options.editors[i].id)
} }
if (this.isOwner() || this.isAnonymousMap()) formData.append('edit_status', this.options.edit_status); if (this.isOwner() || this.isAnonymousMap())
formData.append('edit_status', this.options.edit_status)
if (this.isOwner()) { if (this.isOwner()) {
formData.append('owner', this.options.owner && this.options.owner.id); formData.append('owner', this.options.owner && this.options.owner.id)
formData.append('share_status', this.options.share_status); formData.append('share_status', this.options.share_status)
} }
this.map.post(this.getUrl(), { this.map.post(this.getUrl(), {
data: formData, data: formData,
context: this, context: this,
callback: function (data) { callback(data) {
this.commit(); this.commit()
this.isDirty = false; this.isDirty = false
this.map.continueSaving(); this.map.continueSaving()
} },
}); })
}, },
getUrl: function () { getUrl() {
return L.Util.template(this.map.options.urls.map_update_permissions, {'map_id': this.map.options.umap_id}); return L.Util.template(this.map.options.urls.map_update_permissions, {
map_id: this.map.options.umap_id,
})
}, },
getAttachUrl: function () { getAttachUrl() {
return L.Util.template(this.map.options.urls.map_attach_owner, {'map_id': this.map.options.umap_id}); return L.Util.template(this.map.options.urls.map_attach_owner, {
map_id: this.map.options.umap_id,
})
}, },
addOwnerLink: function (element, container) { addOwnerLink(element, container) {
if (this.options.owner && this.options.owner.name && this.options.owner.url) { if (this.options.owner && this.options.owner.name && this.options.owner.url) {
var ownerContainer = L.DomUtil.add(element, 'umap-map-owner', container, ' ' + L._('by') + ' '), const ownerContainer = L.DomUtil.add(
owner = L.DomUtil.create('a'); element,
owner.href = this.options.owner.url; 'umap-map-owner',
owner.textContent = this.options.owner.name; container,
ownerContainer.appendChild(owner); ` ${L._('by')} `
)
const owner = L.DomUtil.create('a')
owner.href = this.options.owner.url
owner.textContent = this.options.owner.name
ownerContainer.appendChild(owner)
} }
}, },
commit: function () { commit() {
L.Util.extend(this.map.options.permissions, this.options); L.Util.extend(this.map.options.permissions, this.options)
} },
})
});

View file

@ -1,224 +1,239 @@
/* Shapes */ /* Shapes */
L.U.Popup = L.Popup.extend({ L.U.Popup = L.Popup.extend({
options: { options: {
parseTemplate: true parseTemplate: true,
}, },
initialize: function (feature) { initialize(feature) {
this.feature = feature; this.feature = feature
this.container = L.DomUtil.create('div', 'umap-popup'); this.container = L.DomUtil.create('div', 'umap-popup')
this.format(); this.format()
L.Popup.prototype.initialize.call(this, {}, feature); L.Popup.prototype.initialize.call(this, {}, feature)
this.setContent(this.container); this.setContent(this.container)
}, },
format: function () { format() {
var mode = this.feature.getOption('popupTemplate') || 'Default', const mode = this.feature.getOption('popupTemplate') || 'Default'
klass = L.U.PopupTemplate[mode] || L.U.PopupTemplate.Default; const klass = L.U.PopupTemplate[mode] || L.U.PopupTemplate.Default
this.content = new klass(this.feature, this.container); this.content = new klass(this.feature, this.container)
this.content.render(); this.content.render()
var els = this.container.querySelectorAll('img,iframe'); const els = this.container.querySelectorAll('img,iframe')
for (var i = 0; i < els.length; i++) { for (let i = 0; i < els.length; i++) {
this.onElementLoaded(els[i]); this.onElementLoaded(els[i])
} }
if (!els.length && this.container.textContent.replace('\n', '') === '') { if (!els.length && this.container.textContent.replace('\n', '') === '') {
this.container.innerHTML = ''; this.container.innerHTML = ''
L.DomUtil.add('h3', '', this.container, this.feature.getDisplayName()); L.DomUtil.add('h3', '', this.container, this.feature.getDisplayName())
} }
}, },
onElementLoaded: function (el) { onElementLoaded(el) {
L.DomEvent.on(el, 'load', function () { L.DomEvent.on(
this._updateLayout(); el,
this._updatePosition(); 'load',
this._adjustPan(); function () {
}, this); this._updateLayout()
} this._updatePosition()
this._adjustPan()
}); },
this
)
},
})
L.U.Popup.Large = L.U.Popup.extend({ L.U.Popup.Large = L.U.Popup.extend({
options: { options: {
maxWidth: 500, maxWidth: 500,
className: 'umap-popup-large' className: 'umap-popup-large',
} },
}); })
L.U.Popup.Panel = L.U.Popup.extend({ L.U.Popup.Panel = L.U.Popup.extend({
options: { options: {
zoomAnimation: false zoomAnimation: false,
}, },
allButton: function () { allButton() {
var button = L.DomUtil.create('li', ''); const button = L.DomUtil.create('li', '')
L.DomUtil.create('i', 'umap-icon-16 umap-list', button); L.DomUtil.create('i', 'umap-icon-16 umap-list', button)
var label = L.DomUtil.create('span', '', button); const label = L.DomUtil.create('span', '', button)
label.textContent = label.title = L._('See all'); label.textContent = label.title = L._('See all')
L.DomEvent.on(button, 'click', this.feature.map.openBrowser, this.feature.map); L.DomEvent.on(button, 'click', this.feature.map.openBrowser, this.feature.map)
return button; return button
}, },
update: function () { update() {
this.feature.map.ui.openPanel({data: {html: this._content}, actions: [this.allButton()]}); this.feature.map.ui.openPanel({
data: { html: this._content },
actions: [this.allButton()],
})
}, },
onRemove: function (map) { onRemove(map) {
map.ui.closePanel(); map.ui.closePanel()
L.U.Popup.prototype.onRemove.call(this, map); L.U.Popup.prototype.onRemove.call(this, map)
}, },
_initLayout: function () {this._container = L.DomUtil.create('span');}, _initLayout() {
_updateLayout: function () {}, this._container = L.DomUtil.create('span')
_updatePosition: function () {}, },
_adjustPan: function () {} _updateLayout() {},
_updatePosition() {},
}); _adjustPan() {},
L.U.Popup.SimplePanel = L.U.Popup.Panel; // Retrocompat. })
L.U.Popup.SimplePanel = L.U.Popup.Panel // Retrocompat.
/* Content templates */ /* Content templates */
L.U.PopupTemplate = {}; L.U.PopupTemplate = {}
L.U.PopupTemplate.Default = L.Class.extend({ L.U.PopupTemplate.Default = L.Class.extend({
initialize(feature, container) {
initialize: function (feature, container) { this.feature = feature
this.feature = feature; this.container = container
this.container = container;
}, },
renderTitle: function () {}, renderTitle() {},
renderBody: function () { renderBody() {
var template = this.feature.getOption('popupContentTemplate'), const template = this.feature.getOption('popupContentTemplate')
container = L.DomUtil.create('div', 'umap-popup-container'), const container = L.DomUtil.create('div', 'umap-popup-container')
content = '', properties, center; let content = ''
properties = this.feature.extendedProperties(); let properties
let center
properties = this.feature.extendedProperties()
// Resolve properties inside description // Resolve properties inside description
properties.description = L.Util.greedyTemplate(this.feature.properties.description || '', properties); properties.description = L.Util.greedyTemplate(
content = L.Util.greedyTemplate(template, properties); this.feature.properties.description || '',
content = L.Util.toHTML(content); properties
container.innerHTML = content; )
return container; content = L.Util.greedyTemplate(template, properties)
content = L.Util.toHTML(content)
container.innerHTML = content
return container
}, },
renderFooter: function () { renderFooter() {
if (this.feature.hasPopupFooter()) { if (this.feature.hasPopupFooter()) {
var footerContainer = L.DomUtil.create('div', 'umap-footer-container', this.container), const footerContainer = L.DomUtil.create(
footer = L.DomUtil.create('ul', 'umap-popup-footer', footerContainer), 'div',
previousLi = L.DomUtil.create('li', 'previous', footer), 'umap-footer-container',
zoomLi = L.DomUtil.create('li', 'zoom', footer), this.container
nextLi = L.DomUtil.create('li', 'next', footer), )
next = this.feature.getNext(), const footer = L.DomUtil.create('ul', 'umap-popup-footer', footerContainer)
prev = this.feature.getPrevious(); const previousLi = L.DomUtil.create('li', 'previous', footer)
if (next) nextLi.title = L._('Go to «{feature}»', {feature: next.properties.name || L._('next')}); const zoomLi = L.DomUtil.create('li', 'zoom', footer)
if (prev) previousLi.title = L._('Go to «{feature}»', {feature: prev.properties.name || L._('previous')}); const nextLi = L.DomUtil.create('li', 'next', footer)
zoomLi.title = L._('Zoom to this feature'); const next = this.feature.getNext()
L.DomEvent.on(nextLi, 'click', function () { const prev = this.feature.getPrevious()
if (next) next.zoomTo({callback: next.view}); if (next)
}); nextLi.title = L._('Go to «{feature}»', {
L.DomEvent.on(previousLi, 'click', function () { feature: next.properties.name || L._('next'),
if (prev) prev.zoomTo({callback: prev.view}); })
}); if (prev)
L.DomEvent.on(zoomLi, 'click', function () { previousLi.title = L._('Go to «{feature}»', {
this.zoomTo(); feature: prev.properties.name || L._('previous'),
}, this.feature); })
zoomLi.title = L._('Zoom to this feature')
L.DomEvent.on(nextLi, 'click', () => {
if (next) next.zoomTo({ callback: next.view })
})
L.DomEvent.on(previousLi, 'click', () => {
if (prev) prev.zoomTo({ callback: prev.view })
})
L.DomEvent.on(
zoomLi,
'click',
function () {
this.zoomTo()
},
this.feature
)
} }
}, },
render: function () { render() {
var title = this.renderTitle(); const title = this.renderTitle()
if (title) this.container.appendChild(title); if (title) this.container.appendChild(title)
var body = this.renderBody(); const body = this.renderBody()
if (body) L.DomUtil.add('div', 'umap-popup-content', this.container, body); if (body) L.DomUtil.add('div', 'umap-popup-content', this.container, body)
this.renderFooter(); this.renderFooter()
} },
})
});
L.U.PopupTemplate.BaseWithTitle = L.U.PopupTemplate.Default.extend({ L.U.PopupTemplate.BaseWithTitle = L.U.PopupTemplate.Default.extend({
renderTitle() {
renderTitle: function () { let title
var title;
if (this.feature.getDisplayName()) { if (this.feature.getDisplayName()) {
title = L.DomUtil.create('h3', 'popup-title'); title = L.DomUtil.create('h3', 'popup-title')
title.textContent = this.feature.getDisplayName(); title.textContent = this.feature.getDisplayName()
} }
return title; return title
} },
})
});
L.U.PopupTemplate.Table = L.U.PopupTemplate.BaseWithTitle.extend({ L.U.PopupTemplate.Table = L.U.PopupTemplate.BaseWithTitle.extend({
formatRow(key, value) {
formatRow: function (key, value) {
if (value.indexOf('http') === 0) { if (value.indexOf('http') === 0) {
value = '<a href="' + value + '" target="_blank">' + value + '</a>'; value = `<a href="${value}" target="_blank">${value}</a>`
} }
return value; return value
}, },
addRow: function (container, key, value) { addRow(container, key, value) {
var tr = L.DomUtil.create('tr', '', container); const tr = L.DomUtil.create('tr', '', container)
L.DomUtil.add('th', '', tr, key); L.DomUtil.add('th', '', tr, key)
L.DomUtil.add('td', '', tr, this.formatRow(key, value)); L.DomUtil.add('td', '', tr, this.formatRow(key, value))
}, },
renderBody: function () { renderBody() {
var table = L.DomUtil.create('table'); const table = L.DomUtil.create('table')
for (var key in this.feature.properties) { for (const key in this.feature.properties) {
if (typeof this.feature.properties[key] === 'object' || key === 'name') continue; if (typeof this.feature.properties[key] === 'object' || key === 'name') continue
// TODO, manage links (url, mailto, wikipedia...) // TODO, manage links (url, mailto, wikipedia...)
this.addRow(table, key, L.Util.escapeHTML(this.feature.properties[key]).trim()); this.addRow(table, key, L.Util.escapeHTML(this.feature.properties[key]).trim())
} }
return table; return table
} },
})
});
L.U.PopupTemplate.GeoRSSImage = L.U.PopupTemplate.BaseWithTitle.extend({ L.U.PopupTemplate.GeoRSSImage = L.U.PopupTemplate.BaseWithTitle.extend({
options: { options: {
minWidth: 300, minWidth: 300,
maxWidth: 500, maxWidth: 500,
className: 'umap-popup-large umap-georss-image' className: 'umap-popup-large umap-georss-image',
}, },
renderBody: function () { renderBody() {
var container = L.DomUtil.create('a'); const container = L.DomUtil.create('a')
container.href = this.feature.properties.link; container.href = this.feature.properties.link
container.target = '_blank'; container.target = '_blank'
if (this.feature.properties.img) { if (this.feature.properties.img) {
var img = L.DomUtil.create('img', '', container); const img = L.DomUtil.create('img', '', container)
img.src = this.feature.properties.img; img.src = this.feature.properties.img
// Sadly, we are unable to override this from JS the clean way // Sadly, we are unable to override this from JS the clean way
// See https://github.com/Leaflet/Leaflet/commit/61d746818b99d362108545c151a27f09d60960ee#commitcomment-6061847 // See https://github.com/Leaflet/Leaflet/commit/61d746818b99d362108545c151a27f09d60960ee#commitcomment-6061847
img.style.maxWidth = this.options.maxWidth + 'px'; img.style.maxWidth = `${this.options.maxWidth}px`
img.style.maxHeight = this.options.maxWidth + 'px'; img.style.maxHeight = `${this.options.maxWidth}px`
this.onElementLoaded(img); this.onElementLoaded(img)
} }
return container; return container
} },
})
});
L.U.PopupTemplate.GeoRSSLink = L.U.PopupTemplate.Default.extend({ L.U.PopupTemplate.GeoRSSLink = L.U.PopupTemplate.Default.extend({
options: { options: {
className: 'umap-georss-link' className: 'umap-georss-link',
}, },
renderBody: function () { renderBody() {
var title = this.renderTitle(this), const title = this.renderTitle(this)
a = L.DomUtil.add('a'); const a = L.DomUtil.add('a')
a.href = this.feature.properties.link; a.href = this.feature.properties.link
a.target = '_blank'; a.target = '_blank'
a.appendChild(title); a.appendChild(title)
return a; return a
} },
}); })

View file

@ -1,164 +1,165 @@
L.U.Slideshow = L.Class.extend({ L.U.Slideshow = L.Class.extend({
statics: { statics: {
CLASSNAME: 'umap-slideshow-active' CLASSNAME: 'umap-slideshow-active',
}, },
options: { options: {
delay: 5000, delay: 5000,
autoplay: false autoplay: false,
}, },
initialize: function (map, options) { initialize(map, options) {
this.setOptions(options); this.setOptions(options)
this.map = map; this.map = map
this._id = null; this._id = null
var current = null, // current feature
self = this; let // current feature
current = null
const self = this
try { try {
Object.defineProperty(this, 'current', { Object.defineProperty(this, 'current', {
get: function () { get() {
if (!current) { if (!current) {
var datalayer = this.defaultDatalayer(); const datalayer = this.defaultDatalayer()
if (datalayer) current = datalayer.getFeatureByIndex(0); if (datalayer) current = datalayer.getFeatureByIndex(0)
} }
return current; return current
}, },
set: function (feature) { set(feature) {
current = feature; current = feature
} },
}); })
} } catch (e) {
catch (e) {
// Certainly IE8, which has a limited version of defineProperty // Certainly IE8, which has a limited version of defineProperty
} }
try { try {
Object.defineProperty(this, 'next', { Object.defineProperty(this, 'next', {
get: function () { get() {
if (!current) { if (!current) {
return self.current; return self.current
} }
return current.getNext(); return current.getNext()
} },
}); })
} } catch (e) {
catch (e) {
// Certainly IE8, which has a limited version of defineProperty // Certainly IE8, which has a limited version of defineProperty
} }
if (this.options.autoplay) { if (this.options.autoplay) {
this.map.onceDataLoaded(function () { this.map.onceDataLoaded(function () {
this.play(); this.play()
}, this); }, this)
} }
this.map.on('edit:enabled', function () { this.map.on(
this.stop(); 'edit:enabled',
}, this); function () {
this.stop()
},
this
)
}, },
setOptions: function (options) { setOptions(options) {
L.setOptions(this, options); L.setOptions(this, options)
this.timeSpinner(); this.timeSpinner()
}, },
defaultDatalayer: function () { defaultDatalayer() {
return this.map.findDataLayer(function (d) { return d.allowBrowse() && d.hasData(); }); return this.map.findDataLayer((d) => d.allowBrowse() && d.hasData())
}, },
timeSpinner: function () { timeSpinner() {
var time = parseInt(this.options.delay, 10); const time = parseInt(this.options.delay, 10)
if (!time) return; if (!time) return
var css = 'rotation ' + time / 1000 + 's infinite linear', const css = `rotation ${time / 1000}s infinite linear`
spinners = document.querySelectorAll('.umap-slideshow-toolbox .play .spinner'); const spinners = document.querySelectorAll('.umap-slideshow-toolbox .play .spinner')
for (var i = 0; i < spinners.length; i++) { for (let i = 0; i < spinners.length; i++) {
spinners[i].style.animation = css; spinners[i].style.animation = css
spinners[i].style['-webkit-animation'] = css; spinners[i].style['-webkit-animation'] = css
spinners[i].style['-moz-animation'] = css; spinners[i].style['-moz-animation'] = css
spinners[i].style['-o-animation'] = css; spinners[i].style['-o-animation'] = css
} }
}, },
resetSpinners: function () { resetSpinners() {
// Make that animnation is coordinated with user actions // Make that animnation is coordinated with user actions
var spinners = document.querySelectorAll('.umap-slideshow-toolbox .play .spinner'), const spinners = document.querySelectorAll('.umap-slideshow-toolbox .play .spinner')
el, newOne;
for (var i = 0; i < spinners.length; i++) { let el
el = spinners[i]; let newOne
newOne = el.cloneNode(true); for (let i = 0; i < spinners.length; i++) {
el.parentNode.replaceChild(newOne, el); el = spinners[i]
newOne = el.cloneNode(true)
el.parentNode.replaceChild(newOne, el)
} }
}, },
play: function () { play() {
if (this._id) return; if (this._id) return
if (this.map.editEnabled || !this.map.options.slideshow.active) return; if (this.map.editEnabled || !this.map.options.slideshow.active) return
L.DomUtil.addClass(document.body, L.U.Slideshow.CLASSNAME); L.DomUtil.addClass(document.body, L.U.Slideshow.CLASSNAME)
this._id = window.setInterval(L.bind(this.loop, this), this.options.delay); this._id = window.setInterval(L.bind(this.loop, this), this.options.delay)
this.resetSpinners(); this.resetSpinners()
this.loop(); this.loop()
}, },
loop: function () { loop() {
this.current = this.next; this.current = this.next
this.step(); this.step()
}, },
pause: function () { pause() {
if (this._id) { if (this._id) {
L.DomUtil.removeClass(document.body, L.U.Slideshow.CLASSNAME); L.DomUtil.removeClass(document.body, L.U.Slideshow.CLASSNAME)
window.clearInterval(this._id); window.clearInterval(this._id)
this._id = null; this._id = null
} }
}, },
stop: function () { stop() {
this.pause(); this.pause()
this.current = null; this.current = null
}, },
forward: function () { forward() {
this.pause(); this.pause()
this.current = this.next; this.current = this.next
this.step(); this.step()
}, },
backward: function () { backward() {
this.pause(); this.pause()
if (this.current) this.current = this.current.getPrevious(); if (this.current) this.current = this.current.getPrevious()
this.step(); this.step()
}, },
step: function () { step() {
if(!this.current) return this.stop(); if (!this.current) return this.stop()
this.current.zoomTo({easing: this.options.easing}); this.current.zoomTo({ easing: this.options.easing })
this.current.view(); this.current.view()
}, },
renderToolbox: function (container) { renderToolbox(container) {
var box = L.DomUtil.create('ul', 'umap-slideshow-toolbox'), const box = L.DomUtil.create('ul', 'umap-slideshow-toolbox')
play = L.DomUtil.create('li', 'play', box), const play = L.DomUtil.create('li', 'play', box)
stop = L.DomUtil.create('li', 'stop', box), const stop = L.DomUtil.create('li', 'stop', box)
prev = L.DomUtil.create('li', 'prev', box), const prev = L.DomUtil.create('li', 'prev', box)
next = L.DomUtil.create('li', 'next', box); const next = L.DomUtil.create('li', 'next', box)
L.DomUtil.create('div', 'spinner', play); L.DomUtil.create('div', 'spinner', play)
play.title = L._('Start slideshow'); play.title = L._('Start slideshow')
stop.title = L._('Stop slideshow'); stop.title = L._('Stop slideshow')
next.title = L._('Zoom to the next'); next.title = L._('Zoom to the next')
prev.title = L._('Zoom to the previous'); prev.title = L._('Zoom to the previous')
var toggle = function () { const toggle = function () {
if (this._id) this.pause(); if (this._id) this.pause()
else this.play(); 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);
L.DomEvent.on(prev, 'click', L.DomEvent.stop)
.on(prev, 'click', this.backward, this);
L.DomEvent.on(next, 'click', L.DomEvent.stop)
.on(next, 'click', this.forward, this);
container.appendChild(box);
this.timeSpinner();
return box;
} }
L.DomEvent.on(play, 'click', L.DomEvent.stop).on(play, 'click', toggle, this)
}); L.DomEvent.on(stop, 'click', L.DomEvent.stop).on(stop, 'click', this.stop, this)
L.DomEvent.on(prev, 'click', L.DomEvent.stop).on(prev, 'click', this.backward, this)
L.DomEvent.on(next, 'click', L.DomEvent.stop).on(next, 'click', this.forward, this)
container.appendChild(box)
this.timeSpinner()
return box
},
})

View file

@ -1,107 +1,124 @@
L.U.TableEditor = L.Class.extend({ L.U.TableEditor = L.Class.extend({
initialize(datalayer) {
initialize: function (datalayer) { this.datalayer = datalayer
this.datalayer = datalayer; this.table = L.DomUtil.create('div', 'table')
this.table = L.DomUtil.create('div', 'table'); this.header = L.DomUtil.create('div', 'thead', this.table)
this.header = L.DomUtil.create('div', 'thead', this.table); this.body = L.DomUtil.create('div', 'tbody', this.table)
this.body = L.DomUtil.create('div', 'tbody', this.table); this.resetProperties()
this.resetProperties();
}, },
renderHeaders: function () { renderHeaders() {
this.header.innerHTML = ''; this.header.innerHTML = ''
for (var i = 0; i < this.properties.length; i++) { for (let i = 0; i < this.properties.length; i++) {
this.renderHeader(this.properties[i]); this.renderHeader(this.properties[i])
} }
}, },
renderHeader: function (property) { renderHeader(property) {
var container = L.DomUtil.create('div', 'tcell', this.header), const container = L.DomUtil.create('div', 'tcell', this.header)
title = L.DomUtil.add('span', '', container, property), const title = L.DomUtil.add('span', '', container, property)
del = L.DomUtil.create('i', 'umap-delete', container), const del = L.DomUtil.create('i', 'umap-delete', container)
rename = L.DomUtil.create('i', 'umap-edit', container); const rename = L.DomUtil.create('i', 'umap-edit', container)
del.title = L._('Delete this property on all the features'); del.title = L._('Delete this property on all the features')
rename.title = L._('Rename this property on all the features'); rename.title = L._('Rename this property on all the features')
var doDelete = function () { const doDelete = function () {
if (confirm(L._('Are you sure you want to delete this property on all the features?'))) { if (
this.datalayer.eachLayer(function (feature) { confirm(
feature.deleteProperty(property); L._('Are you sure you want to delete this property on all the features?')
}); )
this.datalayer.deindexProperty(property); ) {
this.resetProperties(); this.datalayer.eachLayer((feature) => {
this.edit(); feature.deleteProperty(property)
})
this.datalayer.deindexProperty(property)
this.resetProperties()
this.edit()
} }
}; }
var doRename = function () { const doRename = function () {
var newName = prompt(L._('Please enter the new name of this property'), property); const newName = prompt(
if (!newName || !this.validateName(newName)) return; L._('Please enter the new name of this property'),
this.datalayer.eachLayer(function (feature) { property
feature.renameProperty(property, newName); )
}); if (!newName || !this.validateName(newName)) return
this.datalayer.deindexProperty(property); this.datalayer.eachLayer((feature) => {
this.datalayer.indexProperty(newName); feature.renameProperty(property, newName)
this.resetProperties(); })
this.edit(); this.datalayer.deindexProperty(property)
}; this.datalayer.indexProperty(newName)
L.DomEvent.on(del, 'click', doDelete, this); this.resetProperties()
L.DomEvent.on(rename, 'click', doRename, this); this.edit()
}
L.DomEvent.on(del, 'click', doDelete, this)
L.DomEvent.on(rename, 'click', doRename, this)
}, },
renderRow: function (feature) { renderRow(feature) {
var builder = new L.U.FormBuilder(feature, this.field_properties, const builder = new L.U.FormBuilder(feature, this.field_properties, {
{ id: `umap-feature-properties_${L.stamp(feature)}`,
id: 'umap-feature-properties_' + L.stamp(feature),
className: 'trow', className: 'trow',
callback: feature.resetTooltip callback: feature.resetTooltip,
} })
); this.body.appendChild(builder.build())
this.body.appendChild(builder.build());
}, },
compileProperties: function () { compileProperties() {
if (this.properties.length === 0) this.properties = ['name']; if (this.properties.length === 0) this.properties = ['name']
// description is a forced textarea, don't edit it in a text input, or you lose cariage returns // description is a forced textarea, don't edit it in a text input, or you lose cariage returns
if (this.properties.indexOf('description') !== -1) this.properties.splice(this.properties.indexOf('description'), 1); if (this.properties.includes('description'))
this.properties.sort(); this.properties.splice(this.properties.indexOf('description'), 1)
this.field_properties = []; this.properties.sort()
for (var i = 0; i < this.properties.length; i++) { this.field_properties = []
this.field_properties.push(['properties.' + this.properties[i], {wrapper: 'div', wrapperClass: 'tcell'}]); for (let i = 0; i < this.properties.length; i++) {
this.field_properties.push([
`properties.${this.properties[i]}`,
{ wrapper: 'div', wrapperClass: 'tcell' },
])
} }
}, },
resetProperties: function () { resetProperties() {
this.properties = this.datalayer._propertiesIndex; this.properties = this.datalayer._propertiesIndex
}, },
validateName: function (name) { validateName(name) {
if (name.indexOf(".") !== -1) { if (name.includes('.')) {
this.datalayer.map.ui.alert({content: L._('Invalide property name: {name}', {name: name}), level: 'error'}); this.datalayer.map.ui.alert({
return false; content: L._('Invalide property name: {name}', { name }),
level: 'error',
})
return false
} }
return true; return true
}, },
edit: function () { edit() {
var id = 'tableeditor:edit'; const id = 'tableeditor:edit'
this.datalayer.map.fire('dataloading', {id: id}); this.datalayer.map.fire('dataloading', { id })
this.compileProperties(); this.compileProperties()
this.renderHeaders(); this.renderHeaders()
this.body.innerHTML = ''; this.body.innerHTML = ''
this.datalayer.eachLayer(this.renderRow, this); this.datalayer.eachLayer(this.renderRow, this)
var addButton = L.DomUtil.create('li', 'add-property'); const addButton = L.DomUtil.create('li', 'add-property')
L.DomUtil.create('i', 'umap-icon-16 umap-add', addButton); L.DomUtil.create('i', 'umap-icon-16 umap-add', addButton)
var label = L.DomUtil.create('span', '', addButton); const label = L.DomUtil.create('span', '', addButton)
label.textContent = label.title = L._('Add a new property'); label.textContent = label.title = L._('Add a new property')
var addProperty = function () { const addProperty = function () {
var newName = prompt(L._('Please enter the name of the property')); const newName = prompt(L._('Please enter the name of the property'))
if (!newName || !this.validateName(newName)) return; if (!newName || !this.validateName(newName)) return
this.datalayer.indexProperty(newName); this.datalayer.indexProperty(newName)
this.edit(); this.edit()
};
L.DomEvent.on(addButton, 'click', addProperty, this);
var className = (this.properties.length > 2) ? 'umap-table-editor fullwidth dark' : 'umap-table-editor dark';
this.datalayer.map.ui.openPanel({data: {html: this.table}, className: className, actions: [addButton]});
this.datalayer.map.fire('dataload', {id: id});
} }
L.DomEvent.on(addButton, 'click', addProperty, this)
}); const className =
this.properties.length > 2
? 'umap-table-editor fullwidth dark'
: 'umap-table-editor dark'
this.datalayer.map.ui.openPanel({
data: { html: this.table },
className,
actions: [addButton],
})
this.datalayer.map.fire('dataload', { id })
},
})

View file

@ -1,176 +1,209 @@
/* /*
* Modals * Modals
*/ */
L.U.UI = L.Evented.extend({ L.U.UI = L.Evented.extend({
ALERTS: Array(), ALERTS: Array(),
ALERT_ID: null, ALERT_ID: null,
TOOLTIP_ID: null, TOOLTIP_ID: null,
initialize: function (parent) { initialize(parent) {
this.parent = parent; this.parent = parent
this.container = L.DomUtil.create('div', 'leaflet-ui-container', this.parent); this.container = L.DomUtil.create('div', 'leaflet-ui-container', this.parent)
L.DomEvent.disableClickPropagation(this.container); L.DomEvent.disableClickPropagation(this.container)
L.DomEvent.on(this.container, 'contextmenu', L.DomEvent.stopPropagation); // Do not activate our custom context menu. L.DomEvent.on(this.container, 'contextmenu', L.DomEvent.stopPropagation) // Do not activate our custom context menu.
L.DomEvent.on(this.container, 'mousewheel', L.DomEvent.stopPropagation); L.DomEvent.on(this.container, 'mousewheel', L.DomEvent.stopPropagation)
L.DomEvent.on(this.container, 'MozMousePixelScroll', L.DomEvent.stopPropagation); L.DomEvent.on(this.container, 'MozMousePixelScroll', L.DomEvent.stopPropagation)
this._panel = L.DomUtil.create('div', '', this.container); this._panel = L.DomUtil.create('div', '', this.container)
this._panel.id = 'umap-ui-container'; this._panel.id = 'umap-ui-container'
this._alert = L.DomUtil.create('div', 'with-transition', this.container); this._alert = L.DomUtil.create('div', 'with-transition', this.container)
this._alert.id = 'umap-alert-container'; this._alert.id = 'umap-alert-container'
this._tooltip = L.DomUtil.create('div', '', this.container); this._tooltip = L.DomUtil.create('div', '', this.container)
this._tooltip.id = 'umap-tooltip-container'; this._tooltip.id = 'umap-tooltip-container'
}, },
resetPanelClassName: function () { resetPanelClassName() {
this._panel.className = 'with-transition'; this._panel.className = 'with-transition'
}, },
openPanel: function (e) { openPanel({ data, actions, className }) {
this.fire('panel:open'); this.fire('panel:open')
// We reset all because we can't know which class has been added // We reset all because we can't know which class has been added
// by previous ui processes... // by previous ui processes...
this.resetPanelClassName(); this.resetPanelClassName()
this._panel.innerHTML = ''; this._panel.innerHTML = ''
var actionsContainer = L.DomUtil.create('ul', 'toolbox', this._panel); const actionsContainer = L.DomUtil.create('ul', 'toolbox', this._panel)
var body = L.DomUtil.create('div', 'body', this._panel); const body = L.DomUtil.create('div', 'body', this._panel)
if (e.data.html.nodeType && e.data.html.nodeType === 1) body.appendChild(e.data.html); if (data.html.nodeType && data.html.nodeType === 1) body.appendChild(data.html)
else body.innerHTML = e.data.html; else body.innerHTML = data.html
var closeLink = L.DomUtil.create('li', 'umap-close-link', actionsContainer); const closeLink = L.DomUtil.create('li', 'umap-close-link', actionsContainer)
L.DomUtil.add('i', 'umap-close-icon', closeLink); L.DomUtil.add('i', 'umap-close-icon', closeLink)
var label = L.DomUtil.create('span', '', closeLink); const label = L.DomUtil.create('span', '', closeLink)
label.title = label.textContent = L._('Close'); label.title = label.textContent = L._('Close')
if (e.actions) { if (actions) {
for (var i = 0; i < e.actions.length; i++) { for (let i = 0; i < actions.length; i++) {
actionsContainer.appendChild(e.actions[i]); actionsContainer.appendChild(actions[i])
} }
} }
if (e.className) L.DomUtil.addClass(this._panel, e.className); if (className) L.DomUtil.addClass(this._panel, className)
if (L.DomUtil.hasClass(this.parent, 'umap-ui')) { if (L.DomUtil.hasClass(this.parent, 'umap-ui')) {
// Already open. // Already open.
this.fire('panel:ready'); this.fire('panel:ready')
} else { } else {
L.DomEvent.once(this._panel, 'transitionend', function (e) { L.DomEvent.once(
this.fire('panel:ready'); this._panel,
}, this); 'transitionend',
L.DomUtil.addClass(this.parent, 'umap-ui'); function (e) {
this.fire('panel:ready')
},
this
)
L.DomUtil.addClass(this.parent, 'umap-ui')
} }
L.DomEvent.on(closeLink, 'click', this.closePanel, this); L.DomEvent.on(closeLink, 'click', this.closePanel, this)
}, },
closePanel: function () { closePanel() {
this.resetPanelClassName(); this.resetPanelClassName()
L.DomUtil.removeClass(this.parent, 'umap-ui'); L.DomUtil.removeClass(this.parent, 'umap-ui')
this.fire('panel:closed'); this.fire('panel:closed')
}, },
alert: function (e) { alert(e) {
if (L.DomUtil.hasClass(this.parent, 'umap-alert')) this.ALERTS.push(e); if (L.DomUtil.hasClass(this.parent, 'umap-alert')) this.ALERTS.push(e)
else this.popAlert(e); else this.popAlert(e)
}, },
popAlert: function (e) { popAlert(e) {
var self = this; const self = this
if(!e) { if (!e) {
if (this.ALERTS.length) e = this.ALERTS.pop(); if (this.ALERTS.length) e = this.ALERTS.pop()
else return; else return
} }
var timeoutID, let timeoutID
level_class = e.level && e.level == 'info'? 'info': 'error'; const level_class = e.level && e.level == 'info' ? 'info' : 'error'
this._alert.innerHTML = ''; this._alert.innerHTML = ''
L.DomUtil.addClass(this.parent, 'umap-alert'); L.DomUtil.addClass(this.parent, 'umap-alert')
L.DomUtil.addClass(this._alert, level_class); L.DomUtil.addClass(this._alert, level_class)
var close = function () { const close = function () {
if (timeoutID !== this.ALERT_ID) { return;} // Another alert has been forced if (timeoutID !== this.ALERT_ID) {
this._alert.innerHTML = ''; return
L.DomUtil.removeClass(this.parent, 'umap-alert'); } // Another alert has been forced
L.DomUtil.removeClass(this._alert, level_class); this._alert.innerHTML = ''
if (timeoutID) window.clearTimeout(timeoutID); L.DomUtil.removeClass(this.parent, 'umap-alert')
this.popAlert(); L.DomUtil.removeClass(this._alert, level_class)
}; if (timeoutID) window.clearTimeout(timeoutID)
var closeLink = L.DomUtil.create('a', 'umap-close-link', this._alert); this.popAlert()
closeLink.href = '#'; }
L.DomUtil.add('i', 'umap-close-icon', closeLink); const closeLink = L.DomUtil.create('a', 'umap-close-link', this._alert)
var label = L.DomUtil.create('span', '', closeLink); closeLink.href = '#'
label.title = label.textContent = L._('Close'); L.DomUtil.add('i', 'umap-close-icon', closeLink)
L.DomEvent.on(closeLink, 'click', L.DomEvent.stop) const label = L.DomUtil.create('span', '', closeLink)
.on(closeLink, 'click', close, this); label.title = label.textContent = L._('Close')
L.DomUtil.add('div', '', this._alert, e.content); L.DomEvent.on(closeLink, 'click', L.DomEvent.stop).on(
closeLink,
'click',
close,
this
)
L.DomUtil.add('div', '', this._alert, e.content)
if (e.actions) { if (e.actions) {
var action, el; let action
for (var i = 0; i < e.actions.length; i++) { let el
action = e.actions[i]; for (let i = 0; i < e.actions.length; i++) {
el = L.DomUtil.element('a', {'className': 'umap-action'}, this._alert); action = e.actions[i]
el.href = '#'; el = L.DomUtil.element('a', { className: 'umap-action' }, this._alert)
el.textContent = action.label; el.href = '#'
L.DomEvent.on(el, 'click', L.DomEvent.stop) el.textContent = action.label
.on(el, 'click', close, this); L.DomEvent.on(el, 'click', L.DomEvent.stop).on(el, 'click', close, this)
if (action.callback) L.DomEvent.on(el, 'click', action.callback, action.callbackContext || this.map); if (action.callback)
L.DomEvent.on(
el,
'click',
action.callback,
action.callbackContext || this.map
)
} }
} }
self.ALERT_ID = timeoutID = window.setTimeout(L.bind(close, this), e.duration || 3000); self.ALERT_ID = timeoutID = window.setTimeout(
L.bind(close, this),
e.duration || 3000
)
}, },
tooltip: function (e) { tooltip({ anchor, position, content, duration }) {
this.TOOLTIP_ID = Math.random(); this.TOOLTIP_ID = Math.random()
var id = this.TOOLTIP_ID; const id = this.TOOLTIP_ID
L.DomUtil.addClass(this.parent, 'umap-tooltip'); L.DomUtil.addClass(this.parent, 'umap-tooltip')
if (e.anchor && e.position === 'top') this.anchorTooltipTop(e.anchor); if (anchor && position === 'top') this.anchorTooltipTop(anchor)
else if (e.anchor && e.position === 'left') this.anchorTooltipLeft(e.anchor); else if (anchor && position === 'left') this.anchorTooltipLeft(anchor)
else this.anchorTooltipAbsolute(); else this.anchorTooltipAbsolute()
this._tooltip.innerHTML = e.content; this._tooltip.innerHTML = content
function closeIt () { this.closeTooltip(id); } function closeIt() {
if (e.anchor) L.DomEvent.once(e.anchor, 'mouseout', closeIt, this); this.closeTooltip(id)
if (e.duration !== Infinity) window.setTimeout(L.bind(closeIt, this), e.duration || 3000); }
if (anchor) L.DomEvent.once(anchor, 'mouseout', closeIt, this)
if (duration !== Infinity)
window.setTimeout(L.bind(closeIt, this), duration || 3000)
}, },
anchorTooltipAbsolute: function () { anchorTooltipAbsolute() {
this._tooltip.className = ''; this._tooltip.className = ''
var left = this.parent.offsetLeft + (this.parent.clientWidth / 2) - (this._tooltip.clientWidth / 2), const left =
top = this.parent.offsetTop + 75; this.parent.offsetLeft +
this.setTooltipPosition({top: top, left: left}); this.parent.clientWidth / 2 -
this._tooltip.clientWidth / 2
const top = this.parent.offsetTop + 75
this.setTooltipPosition({ top, left })
}, },
anchorTooltipTop: function (el) { anchorTooltipTop(el) {
this._tooltip.className = 'tooltip-top'; this._tooltip.className = 'tooltip-top'
var coords = this.getPosition(el); const coords = this.getPosition(el)
this.setTooltipPosition({left: coords.left - 10, bottom: this.getDocHeight() - coords.top + 11}); this.setTooltipPosition({
left: coords.left - 10,
bottom: this.getDocHeight() - coords.top + 11,
})
}, },
anchorTooltipLeft: function (el) { anchorTooltipLeft(el) {
this._tooltip.className = 'tooltip-left'; this._tooltip.className = 'tooltip-left'
var coords = this.getPosition(el); const coords = this.getPosition(el)
this.setTooltipPosition({top: coords.top, right: document.documentElement.offsetWidth - coords.left + 11}); this.setTooltipPosition({
top: coords.top,
right: document.documentElement.offsetWidth - coords.left + 11,
})
}, },
closeTooltip: function (id) { closeTooltip(id) {
if (id && id !== this.TOOLTIP_ID) return; if (id && id !== this.TOOLTIP_ID) return
this._tooltip.innerHTML = ''; this._tooltip.innerHTML = ''
L.DomUtil.removeClass(this.parent, 'umap-tooltip'); L.DomUtil.removeClass(this.parent, 'umap-tooltip')
}, },
getPosition: function (el) { getPosition(el) {
return el.getBoundingClientRect(); return el.getBoundingClientRect()
}, },
setTooltipPosition: function (coords) { setTooltipPosition({ left, right, top, bottom }) {
if (coords.left) this._tooltip.style.left = coords.left + 'px'; if (left) this._tooltip.style.left = `${left}px`
else this._tooltip.style.left = 'initial'; else this._tooltip.style.left = 'initial'
if (coords.right) this._tooltip.style.right = coords.right + 'px'; if (right) this._tooltip.style.right = `${right}px`
else this._tooltip.style.right = 'initial'; else this._tooltip.style.right = 'initial'
if (coords.top) this._tooltip.style.top = coords.top + 'px'; if (top) this._tooltip.style.top = `${top}px`
else this._tooltip.style.top = 'initial'; else this._tooltip.style.top = 'initial'
if (coords.bottom) this._tooltip.style.bottom = coords.bottom + 'px'; if (bottom) this._tooltip.style.bottom = `${bottom}px`
else this._tooltip.style.bottom = 'initial'; else this._tooltip.style.bottom = 'initial'
}, },
getDocHeight: function () { getDocHeight() {
var D = document; const D = document
return Math.max( return Math.max(
D.body.scrollHeight, D.documentElement.scrollHeight, D.body.scrollHeight,
D.body.offsetHeight, D.documentElement.offsetHeight, D.documentElement.scrollHeight,
D.body.clientHeight, D.documentElement.clientHeight D.body.offsetHeight,
); D.documentElement.offsetHeight,
D.body.clientHeight,
D.documentElement.clientHeight
)
}, },
})
});

View file

@ -1,285 +1,291 @@
L.U.Xhr = L.Evented.extend({ L.U.Xhr = L.Evented.extend({
initialize(ui) {
initialize: function (ui) { this.ui = ui
this.ui = ui;
}, },
_wrapper: function () { _wrapper() {
var wrapper; let wrapper
if (window.XMLHttpRequest === undefined) { if (window.XMLHttpRequest === undefined) {
wrapper = function() { wrapper = () => {
try { try {
return new window.ActiveXObject('Microsoft.XMLHTTP.6.0'); return new window.ActiveXObject('Microsoft.XMLHTTP.6.0')
} } catch (e1) {
catch (e1) {
try { try {
return new window.ActiveXObject('Microsoft.XMLHTTP.3.0'); return new window.ActiveXObject('Microsoft.XMLHTTP.3.0')
} } catch (e2) {
catch (e2) { throw new Error('XMLHttpRequest is not supported')
throw new Error('XMLHttpRequest is not supported');
} }
} }
};
} }
else { } else {
wrapper = window.XMLHttpRequest; wrapper = window.XMLHttpRequest
} }
return new wrapper(); return new wrapper()
}, },
_ajax: function (settings) { _ajax(settings) {
var xhr = this._wrapper(), id = Math.random(), self = this; const xhr = this._wrapper()
this.fire('dataloading', {id: id}); const id = Math.random()
var loaded = function () {self.fire('dataload', {id: id});}; const self = this
this.fire('dataloading', { id })
const loaded = () => {
self.fire('dataload', { id })
}
try { try {
xhr.open(settings.verb, settings.uri, true); xhr.open(settings.verb, settings.uri, true)
} catch (err) { } catch (err) {
// Unknown protocol? // Unknown protocol?
this.ui.alert({content: L._('Error while fetching {url}', {url: settings.uri}), level: 'error'}); this.ui.alert({
loaded(); content: L._('Error while fetching {url}', { url: settings.uri }),
level: 'error',
})
loaded()
return return
} }
if (settings.uri.indexOf('http') !== 0 || settings.uri.indexOf(window.location.origin) === 0) { if (
settings.uri.indexOf('http') !== 0 ||
settings.uri.indexOf(window.location.origin) === 0
) {
// "X-" mode headers cause the request to be in preflight mode, // "X-" mode headers cause the request to be in preflight mode,
// we don"t want that by default for CORS requests // we don"t want that by default for CORS requests
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
} }
if (settings.headers) { if (settings.headers) {
for (var name in settings.headers) { for (const name in settings.headers) {
xhr.setRequestHeader(name, settings.headers[name]); xhr.setRequestHeader(name, settings.headers[name])
} }
} }
xhr.onreadystatechange = () => {
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) { if (xhr.readyState === 4) {
if (xhr.status == 200) { if (xhr.status == 200) {
settings.callback.call(settings.context || xhr, xhr.responseText, xhr); settings.callback.call(settings.context || xhr, xhr.responseText, xhr)
} } else if (xhr.status === 403) {
else if (xhr.status === 403) { self.ui.alert({
self.ui.alert({content: xhr.responseText || L._('Action not allowed :('), level: 'error'}); content: xhr.responseText || L._('Action not allowed :('),
} level: 'error',
else if (xhr.status === 412) { })
var msg = L._('Woops! Someone else seems to have edited the data. You can save anyway, but this will erase the changes made by others.'); } else if (xhr.status === 412) {
var actions = [ const msg = L._(
'Woops! Someone else seems to have edited the data. You can save anyway, but this will erase the changes made by others.'
)
const actions = [
{ {
label: L._('Save anyway'), label: L._('Save anyway'),
callback: function () { callback() {
delete settings.headers['If-Match']; delete settings.headers['If-Match']
self._ajax(settings); self._ajax(settings)
}, },
callbackContext: self callbackContext: self,
}, },
{ {
label: L._('Cancel') label: L._('Cancel'),
} },
]; ]
self.ui.alert({content: msg, level: 'error', duration: 100000, actions: actions}); self.ui.alert({ content: msg, level: 'error', duration: 100000, actions })
} } else {
else { if (xhr.status !== 0) {
if (xhr.status !== 0) { // 0 === request cut by user // 0 === request cut by user
self.ui.alert({'content': L._('Problem in the response'), 'level': 'error'}); self.ui.alert({ content: L._('Problem in the response'), level: 'error' })
} }
} }
loaded(); loaded()
}
} }
};
try { try {
xhr.send(settings.data); xhr.send(settings.data)
} catch (e) { } catch (e) {
// Pass // Pass
loaded(); loaded()
console.error('Bad Request', e); console.error('Bad Request', e)
} }
}, },
// supports only JSON as response data type // supports only JSON as response data type
_json: function (verb, uri, options) { _json(verb, uri, options) {
var args = arguments, const args = arguments
self = this; const self = this
var default_options = { const default_options = {
'async': true, async: true,
'callback': null, callback: null,
'responseType': 'text', responseType: 'text',
'data': null, data: null,
'listen_form': null // optional form to listen in default callback listen_form: null, // optional form to listen in default callback
}; }
var settings = L.Util.extend({}, default_options, options); const settings = L.Util.extend({}, default_options, options)
if (verb === 'POST') { if (verb === 'POST') {
// find a way not to make this django specific // find a way not to make this django specific
var token = document.cookie.replace(/(?:(?:^|.*;\s*)csrftoken\s*\=\s*([^;]*).*$)|^.*$/, '$1'); const token = document.cookie.replace(
/(?:(?:^|.*;\s*)csrftoken\s*\=\s*([^;]*).*$)|^.*$/,
'$1'
)
if (token) { if (token) {
settings.headers = settings.headers || {}; settings.headers = settings.headers || {}
settings.headers['X-CSRFToken'] = token; settings.headers['X-CSRFToken'] = token
} }
} }
var callback = function(responseText, response) { const callback = function (responseText, response) {
var data; let data
try { try {
data = JSON.parse(responseText); data = JSON.parse(responseText)
} } catch (err) {
catch (err) { console.log(err)
console.log(err); self.ui.alert({
self.ui.alert({content: L._('Problem in the response format'), level: 'error'}); content: L._('Problem in the response format'),
return; level: 'error',
})
return
} }
if (data.errors) { if (data.errors) {
console.log(data.errors); console.log(data.errors)
self.ui.alert({content: L._('An error occured'), level: 'error'}); self.ui.alert({ content: L._('An error occured'), level: 'error' })
} else if (data.login_required) { } else if (data.login_required) {
// login_required should be an URL for the login form // login_required should be an URL for the login form
if (settings.login_callback) settings.login_callback(data); if (settings.login_callback) settings.login_callback(data)
else self.login(data, args); else self.login(data, args)
} else {
if (settings.callback)
L.bind(settings.callback, settings.context || this)(data, response)
else self.default_callback(data, settings, response)
} }
else {
if (settings.callback) L.bind(settings.callback, settings.context || this)(data, response);
else self.default_callback(data, settings, response);
} }
};
this._ajax({ this._ajax({
verb: verb, verb,
uri: uri, uri,
data: settings.data, data: settings.data,
callback: callback, callback,
headers: settings.headers, headers: settings.headers,
listener: settings.listener listener: settings.listener,
}); })
}, },
get: function(uri, options) { get(uri, options) {
this._json('GET', uri, options); this._json('GET', uri, options)
}, },
post: function(uri, options) { post(uri, options) {
this._json('POST', uri, options); this._json('POST', uri, options)
}, },
submit_form: function(form_id, options) { submit_form(form_id, options) {
if(typeof options === 'undefined') options = {}; if (typeof options === 'undefined') options = {}
var form = L.DomUtil.get(form_id); const form = L.DomUtil.get(form_id)
var formData = new FormData(form); const formData = new FormData(form)
if(options.extraFormData) formData.append(options.extraFormData); if (options.extraFormData) formData.append(options.extraFormData)
options.data = formData; options.data = formData
this.post(form.action, options); this.post(form.action, options)
return false; return false
}, },
listen_form: function (form_id, options) { listen_form(form_id, options) {
var form = L.DomUtil.get(form_id), self = this; const form = L.DomUtil.get(form_id)
if (!form) return; const self = this
L.DomEvent if (!form) return
.on(form, 'submit', L.DomEvent.stopPropagation) L.DomEvent.on(form, 'submit', L.DomEvent.stopPropagation)
.on(form, 'submit', L.DomEvent.preventDefault) .on(form, 'submit', L.DomEvent.preventDefault)
.on(form, 'submit', function () { .on(form, 'submit', () => {
self.submit_form(form_id, options); self.submit_form(form_id, options)
}); })
}, },
listen_link: function (link_id, options) { listen_link(link_id, options) {
var link = L.DomUtil.get(link_id), self = this; const link = L.DomUtil.get(link_id)
const self = this
if (link) { if (link) {
L.DomEvent L.DomEvent.on(link, 'click', L.DomEvent.stop).on(link, 'click', () => {
.on(link, 'click', L.DomEvent.stop) if (options.confirm && !confirm(options.confirm)) {
.on(link, 'click', function () { return
if (options.confirm && !confirm(options.confirm)) { return;} }
self.get(link.href, options); self.get(link.href, options)
}); })
} }
}, },
default_callback: function (data, options) { default_callback(data, options) {
// default callback, to avoid boilerplate // default callback, to avoid boilerplate
if (data.redirect) { if (data.redirect) {
var newPath = data.redirect; const newPath = data.redirect
if (window.location.pathname == newPath) window.location.reload(); // Keep the hash, so the current view if (window.location.pathname == newPath)
else window.location = newPath; window.location.reload() // Keep the hash, so the current view
} else window.location = newPath
else if (data.info) { } else if (data.info) {
this.ui.alert({content: data.info, level: 'info'}); this.ui.alert({ content: data.info, level: 'info' })
this.ui.closePanel(); this.ui.closePanel()
} } else if (data.error) {
else if (data.error) { this.ui.alert({ content: data.error, level: 'error' })
this.ui.alert({content: data.error, level: 'error'}); } else if (data.html) {
} const ui_options = { data: data }
else if (data.html) { let listen_options
var ui_options = {'data': data}, if (options.className) ui_options.className = options.className
listen_options; this.ui.openPanel(ui_options)
if (options.className) ui_options.className = options.className;
this.ui.openPanel(ui_options);
// To low boilerplate, if there is a form, listen it // To low boilerplate, if there is a form, listen it
if (options.listen_form) { if (options.listen_form) {
// Listen form again // Listen form again
listen_options = L.Util.extend({}, options, options.listen_form.options); listen_options = L.Util.extend({}, options, options.listen_form.options)
this.listen_form(options.listen_form.id, listen_options); this.listen_form(options.listen_form.id, listen_options)
} }
if (options.listen_link) { if (options.listen_link) {
for (var i=0, l=options.listen_link.length; i<l; i++) { for (let i = 0, l = options.listen_link.length; i < l; i++) {
// Listen link again // Listen link again
listen_options = L.Util.extend({}, options, options.listen_link[i].options); listen_options = L.Util.extend({}, options, options.listen_link[i].options)
this.listen_link(options.listen_link[i].id, listen_options); this.listen_link(options.listen_link[i].id, listen_options)
} }
} }
} } else if (options.success) {
else if (options.success) {
// Success is called only if data contain no msg and no html // Success is called only if data contain no msg and no html
options.success(data); options.success(data)
} }
}, },
login: function (data, args) { login(data, args) {
// data.html: login form // data.html: login form
// args: args of the first _json call, to call again at process end // args: args of the first _json call, to call again at process end
var self = this; const self = this
var proceed = function () { const proceed = () => {
self.ui.closePanel(); self.ui.closePanel()
if (typeof args !== 'undefined') self._json.apply(self, args); if (typeof args !== 'undefined') self._json(...args)
else self.default_callback(data, {}); else self.default_callback(data, {})
};
var ask_for_login = function (data) {
self.ui.openPanel({'data': data, className: 'login-panel'});
self.listen_form('login_form', {
'callback': function (data) {
if (data.html) ask_for_login(data); // Problem in the login - ask again
else proceed();
} }
}); const ask_for_login = (data) => {
self.ui.openPanel({ data: data, className: 'login-panel' })
self.listen_form('login_form', {
callback: function (data) {
if (data.html) ask_for_login(data) // Problem in the login - ask again
else proceed()
},
})
// Auth links // Auth links
var links = document.getElementsByClassName('umap-login-popup'); const links = document.getElementsByClassName('umap-login-popup')
Object.keys(links).forEach(function (el) { Object.keys(links).forEach((el) => {
var link = links[el]; const link = links[el]
L.DomEvent L.DomEvent.on(link, 'click', L.DomEvent.stop).on(link, 'click', () => {
.on(link, 'click', L.DomEvent.stop) self.ui.closePanel()
.on(link, 'click', function () { const win = window.open(link.href)
self.ui.closePanel(); window.umap_proceed = () => {
var win = window.open(link.href); proceed()
window.umap_proceed = function () { win.close()
proceed(); }
win.close(); })
}; })
}); }
});
};
if (data.login_required) { if (data.login_required) {
this.get(data.login_required, { this.get(data.login_required, {
'callback': function (data) { callback: function (data) {
ask_for_login(data); ask_for_login(data)
} },
}); })
} } else {
else { ask_for_login(data)
ask_for_login(data);
} }
}, },
logout: function(url) { logout(url) {
this.get(url); this.get(url)
} },
})
});