diff --git a/umap/static/umap/js/umap.autocomplete.js b/umap/static/umap/js/umap.autocomplete.js index efd9bf03..d7f588c3 100644 --- a/umap/static/umap/js/umap.autocomplete.js +++ b/umap/static/umap/js/umap.autocomplete.js @@ -1,314 +1,340 @@ L.U.AutoComplete = L.Class.extend({ + options: { + placeholder: 'Start typing...', + emptyMessage: 'No result', + allowFree: true, + minChar: 2, + maxResults: 5, + }, - options: { - placeholder: 'Start typing...', - emptyMessage: 'No result', - allowFree: true, - minChar: 2, - maxResults: 5 - }, + CACHE: '', + RESULTS: [], - CACHE: '', - RESULTS: [], - - initialize: function (el, options) { - this.el = el; - var ui = new L.U.UI(document.querySelector('header')); - this.xhr = new L.U.Xhr(ui); - L.setOptions(this, options); - var CURRENT = null; - try { - Object.defineProperty(this, 'CURRENT', { - get: function () { - return CURRENT; - }, - set: function (index) { - if (typeof index === 'object') { - index = this.resultToIndex(index); - } - CURRENT = index; - } - }); - } catch (e) { - // Hello IE8 - } - return this; - }, - - createInput: function () { - this.input = L.DomUtil.element('input', { - type: 'text', - placeholder: this.options.placeholder, - autocomplete: 'off', - className: this.options.className - }, this.el); - 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 () { - this.container = L.DomUtil.element('ul', {className: 'umap-autocomplete'}, document.body); - }, - - resizeContainer: function() - { - var l = this.getLeft(this.input); - var t = this.getTop(this.input) + this.input.offsetHeight; - this.container.style.left = l + 'px'; - this.container.style.top = t + 'px'; - var width = this.options.width ? this.options.width : this.input.offsetWidth - 2; - this.container.style.width = width + 'px'; - }, - - - onKeyDown: function (e) { - switch (e.keyCode) { - case L.U.Keys.TAB: - if(this.CURRENT !== null) this.setChoice(); - L.DomEvent.stop(e); - break; - case L.U.Keys.ENTER: - L.DomEvent.stop(e); - this.setChoice(); - break; - case L.U.Keys.ESC: - L.DomEvent.stop(e); - this.hide(); - break; - case L.U.Keys.DOWN: - if(this.RESULTS.length > 0) { - if(this.CURRENT !== null && this.CURRENT < this.RESULTS.length - 1) { // what if one result? - this.CURRENT++; - this.highlight(); - } - else if(this.CURRENT === null) { - this.CURRENT = 0; - this.highlight(); - } - } - break; - case L.U.Keys.UP: - if(this.CURRENT !== null) { - L.DomEvent.stop(e); - } - if(this.RESULTS.length > 0) { - if(this.CURRENT > 0) { - this.CURRENT--; - this.highlight(); - } - else if(this.CURRENT === 0) { - this.CURRENT = null; - this.highlight(); - } - } - break; - } - }, - - onKeyUp: function (e) { - var special = [ - L.U.Keys.TAB, - L.U.Keys.ENTER, - L.U.Keys.LEFT, - L.U.Keys.RIGHT, - L.U.Keys.DOWN, - L.U.Keys.UP, - L.U.Keys.APPLE, - L.U.Keys.SHIFT, - L.U.Keys.ALT, - L.U.Keys.CTRL - ]; - if (special.indexOf(e.keyCode) === -1) - { - this.search(); - } - }, - - onBlur: function () { - var self = this; - setTimeout(function () { - self.hide(); - }, 100); - }, - - clear: function () { - this.RESULTS = []; - this.CURRENT = null; - this.CACHE = ''; - this.container.innerHTML = ''; - }, - - hide: function() { - this.clear(); - this.container.style.display = 'none'; - this.input.value = ''; - }, - - setChoice: function (choice) { - choice = choice || this.RESULTS[this.CURRENT]; - if (choice) { - this.input.value = choice.item.label; - this.options.on_select(choice); - this.displaySelected(choice); - this.hide(); - if (this.options.callback) { - L.Util.bind(this.options.callback, this)(choice); - } - } - }, - - search: function() { - var val = this.input.value; - if (val.length < this.options.minChar) { - this.clear(); - return; - } - if( val + '' === this.CACHE + '') return; - else this.CACHE = val; - this._do_search(val, function (data) { - this.handleResults(data.data); - }, this); - }, - - createResult: function (item) { - var el = L.DomUtil.element('li', {}, this.container); - el.textContent = item.label; - var result = { - item: item, - el: el - }; - L.DomEvent.on(el, 'mouseover', function () { - this.CURRENT = result; - this.highlight(); - }, this); - L.DomEvent.on(el, 'mousedown', function () { - this.setChoice(); - }, this); - return result; - }, - - resultToIndex: function (result) { - var out = null; - this.forEach(this.RESULTS, function (item, index) { - if (item.item.value == result.item.value) { - out = index; - return; - } - }); - return out; - }, - - handleResults: function(data) { - var self = this; - this.clear(); - this.container.style.display = 'block'; - this.resizeContainer(); - this.forEach(data, function (item) { - self.RESULTS.push(self.createResult(item)); - }); - this.CURRENT = 0; - this.highlight(); - //TODO manage no results - }, - - highlight: function () { - var self = this; - this.forEach(this.RESULTS, function (result, index) { - if (index === self.CURRENT) L.DomUtil.addClass(result.el, 'on'); - else L.DomUtil.removeClass(result.el, 'on'); - }); - }, - - getLeft: function (el) { - var tmp = el.offsetLeft; - el = el.offsetParent; - while(el) { - tmp += el.offsetLeft; - el = el.offsetParent; - } - return tmp; - }, - - getTop: function (el) { - var tmp = el.offsetTop; - el = el.offsetParent; - while(el) { - tmp += el.offsetTop; - el = el.offsetParent; - } - return tmp; - }, - - forEach: function (els, callback) { - Array.prototype.forEach.call(els, callback); + initialize(el, options) { + this.el = el + const ui = new L.U.UI(document.querySelector('header')) + this.xhr = new L.U.Xhr(ui) + L.setOptions(this, options) + let CURRENT = null + try { + Object.defineProperty(this, 'CURRENT', { + get() { + return CURRENT + }, + set(index) { + if (typeof index === 'object') { + index = this.resultToIndex(index) + } + CURRENT = index + }, + }) + } catch (e) { + // Hello IE8 } + return this + }, -}); + createInput() { + this.input = L.DomUtil.element( + 'input', + { + type: 'text', + placeholder: this.options.placeholder, + autocomplete: 'off', + className: this.options.className, + }, + this.el + ) + 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() { + this.container = L.DomUtil.element( + 'ul', + { className: 'umap-autocomplete' }, + document.body + ) + }, + + resizeContainer() { + const l = this.getLeft(this.input) + const t = this.getTop(this.input) + this.input.offsetHeight + this.container.style.left = `${l}px` + this.container.style.top = `${t}px` + const width = this.options.width ? this.options.width : this.input.offsetWidth - 2 + this.container.style.width = `${width}px` + }, + + onKeyDown(e) { + switch (e.keyCode) { + case L.U.Keys.TAB: + if (this.CURRENT !== null) this.setChoice() + L.DomEvent.stop(e) + break + case L.U.Keys.ENTER: + L.DomEvent.stop(e) + this.setChoice() + break + case L.U.Keys.ESC: + L.DomEvent.stop(e) + this.hide() + break + case L.U.Keys.DOWN: + if (this.RESULTS.length > 0) { + if (this.CURRENT !== null && this.CURRENT < this.RESULTS.length - 1) { + // what if one result? + this.CURRENT++ + this.highlight() + } else if (this.CURRENT === null) { + this.CURRENT = 0 + this.highlight() + } + } + break + case L.U.Keys.UP: + if (this.CURRENT !== null) { + L.DomEvent.stop(e) + } + if (this.RESULTS.length > 0) { + if (this.CURRENT > 0) { + this.CURRENT-- + this.highlight() + } else if (this.CURRENT === 0) { + this.CURRENT = null + this.highlight() + } + } + break + } + }, + + onKeyUp({ keyCode }) { + const special = [ + L.U.Keys.TAB, + L.U.Keys.ENTER, + L.U.Keys.LEFT, + L.U.Keys.RIGHT, + L.U.Keys.DOWN, + L.U.Keys.UP, + L.U.Keys.APPLE, + L.U.Keys.SHIFT, + L.U.Keys.ALT, + L.U.Keys.CTRL, + ] + if (!special.includes(keyCode)) { + this.search() + } + }, + + onBlur() { + const self = this + setTimeout(() => { + self.hide() + }, 100) + }, + + clear() { + this.RESULTS = [] + this.CURRENT = null + this.CACHE = '' + this.container.innerHTML = '' + }, + + hide() { + this.clear() + this.container.style.display = 'none' + this.input.value = '' + }, + + setChoice(choice = this.RESULTS[this.CURRENT]) { + if (choice) { + this.input.value = choice.item.label + this.options.on_select(choice) + this.displaySelected(choice) + this.hide() + if (this.options.callback) { + L.Util.bind(this.options.callback, this)(choice) + } + } + }, + + search() { + const val = this.input.value + if (val.length < this.options.minChar) { + this.clear() + return + } + if (`${val}` === `${this.CACHE}`) return + else this.CACHE = val + this._do_search( + val, + function (data) { + this.handleResults(data.data) + }, + this + ) + }, + + createResult(item) { + const el = L.DomUtil.element('li', {}, this.container) + el.textContent = item.label + const result = { + item, + el, + } + L.DomEvent.on( + el, + 'mouseover', + function () { + this.CURRENT = result + this.highlight() + }, + this + ) + L.DomEvent.on( + el, + 'mousedown', + function () { + this.setChoice() + }, + this + ) + return result + }, + + resultToIndex(result) { + let out = null + this.forEach(this.RESULTS, (item, index) => { + if (item.item.value == result.item.value) { + out = index + return + } + }) + return out + }, + + handleResults(data) { + const self = this + this.clear() + this.container.style.display = 'block' + this.resizeContainer() + this.forEach(data, (item) => { + self.RESULTS.push(self.createResult(item)) + }) + this.CURRENT = 0 + this.highlight() + //TODO manage no results + }, + + highlight() { + const self = this + this.forEach(this.RESULTS, ({ el }, index) => { + if (index === self.CURRENT) L.DomUtil.addClass(el, 'on') + else L.DomUtil.removeClass(el, 'on') + }) + }, + + getLeft(el) { + let tmp = el.offsetLeft + el = el.offsetParent + while (el) { + tmp += el.offsetLeft + el = el.offsetParent + } + return tmp + }, + + getTop(el) { + let tmp = el.offsetTop + el = el.offsetParent + while (el) { + tmp += el.offsetTop + el = el.offsetParent + } + return tmp + }, + + forEach(els, callback) { + Array.prototype.forEach.call(els, callback) + }, +}) L.U.AutoComplete.Ajax = L.U.AutoComplete.extend({ + initialize(el, options) { + L.U.AutoComplete.prototype.initialize.call(this, el, options) + if (!this.el) return this + this.createInput() + this.createContainer() + this.selected_container = this.initSelectedContainer() + }, - initialize: function (el, options) { - L.U.AutoComplete.prototype.initialize.call(this, el, options); - if (!this.el) return this; - this.createInput(); - this.createContainer(); - this.selected_container = this.initSelectedContainer(); - }, - - optionToResult: function (option) { - return { - value: option.value, - label: option.innerHTML - }; - }, - - _do_search: function (val, callback, context) { - val = val.toLowerCase(); - this.xhr.get('/agnocomplete/AutocompleteUser/?q=' + encodeURIComponent(val), {callback: callback, context: context || this}); + optionToResult({ value, innerHTML }) { + return { + value: value, + label: innerHTML, } + }, -}); + _do_search(val, callback, context) { + val = val.toLowerCase() + this.xhr.get(`/agnocomplete/AutocompleteUser/?q=${encodeURIComponent(val)}`, { + callback, + context: context || this, + }) + }, +}) L.U.AutoComplete.Ajax.SelectMultiple = L.U.AutoComplete.Ajax.extend({ + initSelectedContainer() { + return L.DomUtil.after( + this.input, + L.DomUtil.element('ul', { className: 'umap-multiresult' }) + ) + }, - initSelectedContainer: function () { - return L.DomUtil.after(this.input, L.DomUtil.element('ul', {className: 'umap-multiresult'})); - }, - - displaySelected: function (result) { - var result_el = L.DomUtil.element('li', {}, this.selected_container); - result_el.textContent = result.item.label; - var close = L.DomUtil.element('span', {className: 'close'}, result_el); - close.textContent = '×'; - L.DomEvent.on(close, 'click', function () { - this.selected_container.removeChild(result_el); - this.options.on_unselect(result); - }, this); - this.hide(); - } - -}); - + displaySelected(result) { + const result_el = L.DomUtil.element('li', {}, this.selected_container) + result_el.textContent = result.item.label + const close = L.DomUtil.element('span', { className: 'close' }, result_el) + close.textContent = '×' + L.DomEvent.on( + close, + 'click', + function () { + this.selected_container.removeChild(result_el) + this.options.on_unselect(result) + }, + this + ) + this.hide() + }, +}) L.U.AutoComplete.Ajax.Select = L.U.AutoComplete.Ajax.extend({ + initSelectedContainer() { + return L.DomUtil.after( + this.input, + L.DomUtil.element('div', { className: 'umap-singleresult' }) + ) + }, - initSelectedContainer: function () { - return L.DomUtil.after(this.input, L.DomUtil.element('div', {className: 'umap-singleresult'})); - }, - - displaySelected: function (result) { - var result_el = L.DomUtil.element('div', {}, this.selected_container); - result_el.textContent = result.item.label; - var close = L.DomUtil.element('span', {className: 'close'}, result_el); - close.textContent = '×'; - this.input.style.display = 'none'; - L.DomEvent.on(close, 'click', function () { - this.selected_container.innerHTML = ''; - this.input.style.display = 'block'; - }, this); - this.hide(); - } - -}); + displaySelected({ item }) { + const result_el = L.DomUtil.element('div', {}, this.selected_container) + result_el.textContent = item.label + const close = L.DomUtil.element('span', { className: 'close' }, result_el) + close.textContent = '×' + this.input.style.display = 'none' + L.DomEvent.on( + close, + 'click', + function () { + this.selected_container.innerHTML = '' + this.input.style.display = 'block' + }, + this + ) + this.hide() + }, +}) diff --git a/umap/static/umap/js/umap.controls.js b/umap/static/umap/js/umap.controls.js index 66d4647e..d78a8b4b 100644 --- a/umap/static/umap/js/umap.controls.js +++ b/umap/static/umap/js/umap.controls.js @@ -1,1310 +1,1353 @@ L.U.BaseAction = L.ToolbarAction.extend({ - - initialize: function (map) { - this.map = map; - this.options.toolbarIcon = { - className: this.options.className, - tooltip: this.options.tooltip - }; - L.ToolbarAction.prototype.initialize.call(this); - if (this.options.helpMenu && !this.map.helpMenuActions[this.options.className]) this.map.helpMenuActions[this.options.className] = this; + initialize(map) { + this.map = map + this.options.toolbarIcon = { + className: this.options.className, + tooltip: this.options.tooltip, } - -}); + L.ToolbarAction.prototype.initialize.call(this) + if (this.options.helpMenu && !this.map.helpMenuActions[this.options.className]) + this.map.helpMenuActions[this.options.className] = this + }, +}) L.U.ImportAction = L.U.BaseAction.extend({ + options: { + helpMenu: true, + className: 'upload-data dark', + tooltip: `${L._('Import data')} (Ctrl+I)`, + }, - options: { - helpMenu: true, - className: 'upload-data dark', - tooltip: L._('Import data') + ' (Ctrl+I)' - }, - - addHooks: function () { - this.map.importPanel(); - } - -}); + addHooks() { + this.map.importPanel() + }, +}) L.U.EditPropertiesAction = L.U.BaseAction.extend({ + options: { + helpMenu: true, + className: 'update-map-settings dark', + tooltip: L._('Edit map settings'), + }, - options: { - helpMenu: true, - className: 'update-map-settings dark', - tooltip: L._('Edit map settings') - }, - - addHooks: function () { - this.map.edit(); - } - -}); + addHooks() { + this.map.edit() + }, +}) L.U.ChangeTileLayerAction = L.U.BaseAction.extend({ + options: { + helpMenu: true, + className: 'dark update-map-tilelayers', + tooltip: L._('Change tilelayers'), + }, - options: { - helpMenu: true, - className: 'dark update-map-tilelayers', - tooltip: L._('Change tilelayers') - }, - - addHooks: function () { - this.map.updateTileLayers(); - } - -}); + addHooks() { + this.map.updateTileLayers() + }, +}) L.U.ManageDatalayersAction = L.U.BaseAction.extend({ + options: { + className: 'dark manage-datalayers', + tooltip: L._('Manage layers'), + }, - options: { - className: 'dark manage-datalayers', - tooltip: L._('Manage layers') - }, - - addHooks: function () { - this.map.manageDatalayers(); - } - -}); + addHooks() { + this.map.manageDatalayers() + }, +}) L.U.UpdateExtentAction = L.U.BaseAction.extend({ + options: { + className: 'update-map-extent dark', + tooltip: L._('Save this center and zoom'), + }, - options: { - className: 'update-map-extent dark', - tooltip: L._('Save this center and zoom') - }, - - addHooks: function () { - this.map.updateExtent(); - } - -}); + addHooks() { + this.map.updateExtent() + }, +}) L.U.UpdatePermsAction = L.U.BaseAction.extend({ + options: { + className: 'update-map-permissions dark', + tooltip: L._('Update permissions and editors'), + }, - options: { - className: 'update-map-permissions dark', - tooltip: L._('Update permissions and editors') - }, - - addHooks: function () { - this.map.permissions.edit(); - } - -}); + addHooks() { + this.map.permissions.edit() + }, +}) L.U.DrawMarkerAction = L.U.BaseAction.extend({ + options: { + helpMenu: true, + className: 'umap-draw-marker dark', + tooltip: L._('Draw a marker'), + }, - options: { - helpMenu: true, - className: 'umap-draw-marker dark', - tooltip: L._('Draw a marker') - }, - - addHooks: function () { - this.map.startMarker(); - } - -}); + addHooks() { + this.map.startMarker() + }, +}) L.U.DrawPolylineAction = L.U.BaseAction.extend({ + options: { + helpMenu: true, + className: 'umap-draw-polyline dark', + tooltip: L._('Draw a polyline'), + }, - options: { - helpMenu: true, - className: 'umap-draw-polyline dark', - tooltip: L._('Draw a polyline') - }, - - addHooks: function () { - this.map.startPolyline(); - } - -}); + addHooks() { + this.map.startPolyline() + }, +}) L.U.DrawPolygonAction = L.U.BaseAction.extend({ + options: { + helpMenu: true, + className: 'umap-draw-polygon dark', + tooltip: L._('Draw a polygon'), + }, - options: { - helpMenu: true, - className: 'umap-draw-polygon dark', - tooltip: L._('Draw a polygon') - }, - - addHooks: function () { - this.map.startPolygon(); - } - -}); + addHooks() { + this.map.startPolygon() + }, +}) L.U.AddPolylineShapeAction = L.U.BaseAction.extend({ + options: { + className: 'umap-draw-polyline-multi dark', + tooltip: L._('Add a line to the current multi'), + }, - options: { - className: 'umap-draw-polyline-multi dark', - tooltip: L._('Add a line to the current multi') - }, - - addHooks: function () { - this.map.editedFeature.editor.newShape(); - } - -}); + addHooks() { + this.map.editedFeature.editor.newShape() + }, +}) L.U.AddPolygonShapeAction = L.U.AddPolylineShapeAction.extend({ - - options: { - className: 'umap-draw-polygon-multi dark', - tooltip: L._('Add a polygon to the current multi') - } - -}); + options: { + className: 'umap-draw-polygon-multi dark', + tooltip: L._('Add a polygon to the current multi'), + }, +}) L.U.BaseFeatureAction = L.ToolbarAction.extend({ + initialize(map, feature, latlng) { + this.map = map + this.feature = feature + this.latlng = latlng + L.ToolbarAction.prototype.initialize.call(this) + this.postInit() + }, - initialize: function (map, feature, latlng) { - this.map = map; - this.feature = feature; - this.latlng = latlng; - L.ToolbarAction.prototype.initialize.call(this); - this.postInit(); - }, + postInit() {}, - postInit: function () {}, + hideToolbar() { + this.map.removeLayer(this.toolbar) + }, - hideToolbar: function () { - this.map.removeLayer(this.toolbar); - }, - - addHooks: function () { - this.onClick({latlng: this.latlng}); - this.hideToolbar(); - } - -}); + addHooks() { + this.onClick({ latlng: this.latlng }) + this.hideToolbar() + }, +}) L.U.CreateHoleAction = L.U.BaseFeatureAction.extend({ - - options: { - toolbarIcon: { - className: 'umap-new-hole', - tooltip: L._('Start a hole here') - } + options: { + toolbarIcon: { + className: 'umap-new-hole', + tooltip: L._('Start a hole here'), }, + }, - onClick: function (e) { - this.feature.startHole(e); - } - -}); + onClick(e) { + this.feature.startHole(e) + }, +}) L.U.ToggleEditAction = L.U.BaseFeatureAction.extend({ - - options: { - toolbarIcon: { - className: 'umap-toggle-edit', - tooltip: L._('Toggle edit mode (Shift+Click)') - } + options: { + toolbarIcon: { + className: 'umap-toggle-edit', + tooltip: L._('Toggle edit mode (Shift+Click)'), }, + }, - onClick: function (e) { - if (this.feature._toggleEditing) this.feature._toggleEditing(e); // Path - else this.feature.edit(e); // Marker - } - -}); + onClick(e) { + if (this.feature._toggleEditing) this.feature._toggleEditing(e) // Path + else this.feature.edit(e) // Marker + }, +}) L.U.DeleteFeatureAction = L.U.BaseFeatureAction.extend({ - - options: { - toolbarIcon: { - className: 'umap-delete-all', - tooltip: L._('Delete this feature') - } + options: { + toolbarIcon: { + className: 'umap-delete-all', + tooltip: L._('Delete this feature'), }, + }, - postInit: function () { - if (!this.feature.isMulti()) this.options.toolbarIcon.className = 'umap-delete-one-of-one'; - }, + postInit() { + if (!this.feature.isMulti()) + this.options.toolbarIcon.className = 'umap-delete-one-of-one' + }, - onClick: function (e) { - this.feature.confirmDelete(e); - } - -}); + onClick(e) { + this.feature.confirmDelete(e) + }, +}) L.U.DeleteShapeAction = L.U.BaseFeatureAction.extend({ - - options: { - toolbarIcon: { - className: 'umap-delete-one-of-multi', - tooltip: L._('Delete this shape') - } + options: { + toolbarIcon: { + className: 'umap-delete-one-of-multi', + tooltip: L._('Delete this shape'), }, + }, - onClick: function (e) { - this.feature.enableEdit().deleteShapeAt(e.latlng); - } - -}); + onClick({ latlng }) { + this.feature.enableEdit().deleteShapeAt(latlng) + }, +}) L.U.ExtractShapeFromMultiAction = L.U.BaseFeatureAction.extend({ - - options: { - toolbarIcon: { - className: 'umap-extract-shape-from-multi', - tooltip: L._('Extract shape to separate feature') - } + options: { + toolbarIcon: { + className: 'umap-extract-shape-from-multi', + tooltip: L._('Extract shape to separate feature'), }, + }, - onClick: function (e) { - this.feature.isolateShape(e.latlng); - } - -}); + onClick({ latlng }) { + this.feature.isolateShape(latlng) + }, +}) L.U.BaseVertexAction = L.U.BaseFeatureAction.extend({ - - initialize: function (map, feature, latlng, vertex) { - this.vertex = vertex; - L.U.BaseFeatureAction.prototype.initialize.call(this, map, feature, latlng); - } - -}); + initialize(map, feature, latlng, vertex) { + this.vertex = vertex + L.U.BaseFeatureAction.prototype.initialize.call(this, map, feature, latlng) + }, +}) L.U.DeleteVertexAction = L.U.BaseVertexAction.extend({ - - options: { - toolbarIcon: { - className: 'umap-delete-vertex', - tooltip: L._('Delete this vertex (Alt+Click)') - } + options: { + toolbarIcon: { + className: 'umap-delete-vertex', + tooltip: L._('Delete this vertex (Alt+Click)'), }, + }, - onClick: function () { - this.vertex.delete(); - } - -}); + onClick() { + this.vertex.delete() + }, +}) L.U.SplitLineAction = L.U.BaseVertexAction.extend({ - - options: { - toolbarIcon: { - className: 'umap-split-line', - tooltip: L._('Split line') - } + options: { + toolbarIcon: { + className: 'umap-split-line', + tooltip: L._('Split line'), }, + }, - onClick: function () { - this.vertex.split(); - } - -}); + onClick() { + this.vertex.split() + }, +}) L.U.ContinueLineAction = L.U.BaseVertexAction.extend({ - - options: { - toolbarIcon: { - className: 'umap-continue-line', - tooltip: L._('Continue line') - } + options: { + toolbarIcon: { + className: 'umap-continue-line', + tooltip: L._('Continue line'), }, + }, - onClick: function () { - this.vertex.continue(); - } - -}); + onClick() { + this.vertex.continue() + }, +}) // Leaflet.Toolbar doesn't allow twice same toolbar class… -L.U.SettingsToolbar = L.Toolbar.Control.extend({}); +L.U.SettingsToolbar = L.Toolbar.Control.extend({}) L.U.DrawToolbar = L.Toolbar.Control.extend({ + initialize(options) { + L.Toolbar.Control.prototype.initialize.call(this, options) + this.map = this.options.map + this.map.on('seteditedfeature', this.redraw, this) + }, - initialize: function (options) { - L.Toolbar.Control.prototype.initialize.call(this, options); - this.map = this.options.map; - this.map.on('seteditedfeature', this.redraw, this); - }, - - appendToContainer: function (container) { - this.options.actions = []; - if (this.map.options.enableMarkerDraw) { - this.options.actions.push(L.U.DrawMarkerAction); - } - if (this.map.options.enablePolylineDraw) { - this.options.actions.push(L.U.DrawPolylineAction); - if (this.map.editedFeature && this.map.editedFeature instanceof L.U.Polyline) { - this.options.actions.push(L.U.AddPolylineShapeAction); - } - } - if (this.map.options.enablePolygonDraw) { - this.options.actions.push(L.U.DrawPolygonAction); - if (this.map.editedFeature && this.map.editedFeature instanceof L.U.Polygon) { - this.options.actions.push(L.U.AddPolygonShapeAction); - } - } - L.Toolbar.Control.prototype.appendToContainer.call(this, container); - }, - - redraw: function () { - var container = this._control.getContainer(); - container.innerHTML = ''; - this.appendToContainer(container); + appendToContainer(container) { + this.options.actions = [] + if (this.map.options.enableMarkerDraw) { + this.options.actions.push(L.U.DrawMarkerAction) } + if (this.map.options.enablePolylineDraw) { + this.options.actions.push(L.U.DrawPolylineAction) + if (this.map.editedFeature && this.map.editedFeature instanceof L.U.Polyline) { + this.options.actions.push(L.U.AddPolylineShapeAction) + } + } + if (this.map.options.enablePolygonDraw) { + this.options.actions.push(L.U.DrawPolygonAction) + if (this.map.editedFeature && this.map.editedFeature instanceof L.U.Polygon) { + this.options.actions.push(L.U.AddPolygonShapeAction) + } + } + L.Toolbar.Control.prototype.appendToContainer.call(this, container) + }, -}); - + redraw() { + const container = this._control.getContainer() + container.innerHTML = '' + this.appendToContainer(container) + }, +}) L.U.EditControl = L.Control.extend({ + options: { + position: 'topright', + }, - options: { - position: 'topright' - }, + onAdd(map) { + const container = L.DomUtil.create( + 'div', + 'leaflet-control-edit-enable umap-control' + ) + const edit = L.DomUtil.create('a', '', container) + edit.href = '#' + edit.title = `${L._('Enable editing')} (Ctrl+E)` - onAdd: function (map) { - var container = L.DomUtil.create('div', 'leaflet-control-edit-enable umap-control'), - edit = L.DomUtil.create('a', '', container); - edit.href = '#'; - edit.title = L._('Enable editing') + ' (Ctrl+E)'; - - L.DomEvent - .addListener(edit, 'click', L.DomEvent.stop) - .addListener(edit, 'click', map.enableEdit, map); - return container; - } - -}); + L.DomEvent.addListener(edit, 'click', L.DomEvent.stop).addListener( + edit, + 'click', + map.enableEdit, + map + ) + return container + }, +}) /* Share control */ L.Control.Embed = L.Control.extend({ + options: { + position: 'topleft', + }, - options: { - position: 'topleft' - }, + onAdd(map) { + const container = L.DomUtil.create('div', 'leaflet-control-embed umap-control') - onAdd: function (map) { - var container = L.DomUtil.create('div', 'leaflet-control-embed umap-control'); + const link = L.DomUtil.create('a', '', container) + link.href = '#' + link.title = L._('Embed and share this map') - var link = L.DomUtil.create('a', '', container); - link.href = '#'; - link.title = L._('Embed and share this map'); + L.DomEvent.on(link, 'click', L.DomEvent.stop) + .on(link, 'click', map.renderShareBox, map) + .on(link, 'dblclick', L.DomEvent.stopPropagation) - L.DomEvent - .on(link, 'click', L.DomEvent.stop) - .on(link, 'click', map.renderShareBox, map) - .on(link, 'dblclick', L.DomEvent.stopPropagation); - - return container; - } -}); + return container + }, +}) L.U.MoreControls = L.Control.extend({ + options: { + position: 'topleft', + }, - options: { - position: 'topleft' - }, + onAdd() { + const container = L.DomUtil.create('div', '') + const more = L.DomUtil.create('a', 'umap-control-more umap-control-text', container) + const less = L.DomUtil.create('a', 'umap-control-less umap-control-text', container) + more.href = '#' + more.title = L._('More controls') - onAdd: function () { - var container = L.DomUtil.create('div', ''), - more = L.DomUtil.create('a', 'umap-control-more umap-control-text', container), - less = L.DomUtil.create('a', 'umap-control-less umap-control-text', container); - more.href = '#'; - more.title = L._('More controls'); + L.DomEvent.on(more, 'click', L.DomEvent.stop).on(more, 'click', this.toggle, this) - L.DomEvent - .on(more, 'click', L.DomEvent.stop) - .on(more, 'click', this.toggle, this); + less.href = '#' + less.title = L._('Hide controls') - less.href = '#'; - less.title = L._('Hide controls'); + L.DomEvent.on(less, 'click', L.DomEvent.stop).on(less, 'click', this.toggle, this) - L.DomEvent - .on(less, 'click', L.DomEvent.stop) - .on(less, 'click', this.toggle, this); - - return container; - }, - - toggle: function () { - var pos = this.getPosition(), - corner = this._map._controlCorners[pos], - className = 'umap-more-controls'; - if (L.DomUtil.hasClass(corner, className)) L.DomUtil.removeClass(corner, className); - else L.DomUtil.addClass(corner, className); - } - -}); + return container + }, + toggle() { + const pos = this.getPosition() + const corner = this._map._controlCorners[pos] + const className = 'umap-more-controls' + if (L.DomUtil.hasClass(corner, className)) L.DomUtil.removeClass(corner, className) + else L.DomUtil.addClass(corner, className) + }, +}) L.U.PermanentCreditsControl = L.Control.extend({ + options: { + position: 'bottomleft', + }, - options: { - position: 'bottomleft' - }, + initialize(map, options) { + this.map = map + L.Control.prototype.initialize.call(this, options) + }, - initialize: function (map, options) { - this.map = map; - L.Control.prototype.initialize.call(this, options); - }, + onAdd() { + const paragraphContainer = L.DomUtil.create( + 'div', + 'umap-permanent-credits-container' + ) + const creditsParagraph = L.DomUtil.create('p', '', paragraphContainer) - onAdd: function () { - var paragraphContainer = L.DomUtil.create('div', 'umap-permanent-credits-container'), - creditsParagraph = L.DomUtil.create('p', '', paragraphContainer); + this.paragraphContainer = paragraphContainer + this.setCredits() + this.setBackground() - this.paragraphContainer = paragraphContainer; - this.setCredits(); - this.setBackground(); + return paragraphContainer + }, - return paragraphContainer; - }, + setCredits() { + this.paragraphContainer.innerHTML = L.Util.toHTML(this.map.options.permanentCredit) + }, - setCredits: function () { - this.paragraphContainer.innerHTML = L.Util.toHTML(this.map.options.permanentCredit); - }, - - setBackground: function () { - if (this.map.options.permanentCreditBackground) { - this.paragraphContainer.style.backgroundColor = '#FFFFFFB0'; - } else { - this.paragraphContainer.style.backgroundColor = ''; - } + setBackground() { + if (this.map.options.permanentCreditBackground) { + this.paragraphContainer.style.backgroundColor = '#FFFFFFB0' + } else { + this.paragraphContainer.style.backgroundColor = '' } - -}); - + }, +}) L.U.DataLayersControl = L.Control.extend({ + options: { + position: 'topleft', + }, - options: { - position: 'topleft' - }, + labels: { + zoomToLayer: L._('Zoom to layer extent'), + toggleLayer: L._('Show/hide layer'), + editLayer: L._('Edit'), + }, - labels: { - zoomToLayer: L._('Zoom to layer extent'), - toggleLayer: L._('Show/hide layer'), - editLayer: L._('Edit') - }, + initialize(map, options) { + this.map = map + L.Control.prototype.initialize.call(this, options) + }, - initialize: function (map, options) { - this.map = map; - L.Control.prototype.initialize.call(this, options); - }, + _initLayout(map) { + const container = (this._container = L.DomUtil.create( + 'div', + 'leaflet-control-browse umap-control' + )) + const actions = L.DomUtil.create('div', 'umap-browse-actions', container) + this._datalayers_container = L.DomUtil.create( + 'ul', + 'umap-browse-datalayers', + actions + ) - _initLayout: function (map) { - var container = this._container = L.DomUtil.create('div', 'leaflet-control-browse umap-control'), - actions = L.DomUtil.create('div', 'umap-browse-actions', container); - this._datalayers_container = L.DomUtil.create('ul', 'umap-browse-datalayers', actions); + const link = L.DomUtil.create('a', 'umap-browse-link', actions) + link.href = '#' + link.title = link.textContent = L._('Browse data') - var link = L.DomUtil.create('a', 'umap-browse-link', actions); - link.href = '#'; - link.title = link.textContent = L._('Browse data'); + const toggle = L.DomUtil.create('a', 'umap-browse-toggle', container) + toggle.href = '#' + toggle.title = L._('See data layers') - var toggle = L.DomUtil.create('a', 'umap-browse-toggle', container); - toggle.href = '#'; - toggle.title = L._('See data layers') + L.DomEvent.on(toggle, 'click', L.DomEvent.stop) - L.DomEvent - .on(toggle, 'click', L.DomEvent.stop); + L.DomEvent.on(link, 'click', L.DomEvent.stop).on( + link, + 'click', + map.openBrowser, + map + ) - L.DomEvent - .on(link, 'click', L.DomEvent.stop) - .on(link, 'click', map.openBrowser, map); + map.whenReady(function () { + this.update() + }, this) - map.whenReady(function () { - this.update(); - }, this); - - if (L.Browser.pointer) { - L.DomEvent.disableClickPropagation(container); - L.DomEvent.on(container, 'mousewheel', L.DomEvent.stopPropagation); - L.DomEvent.on(container, 'MozMousePixelScroll', L.DomEvent.stopPropagation); - } - if (!L.Browser.touch) { - L.DomEvent.on(container, { - mouseenter: this.expand, - mouseleave: this.collapse - }, this); - } else { - L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation); - L.DomEvent.on(toggle, 'click', L.DomEvent.stop) - .on(toggle, 'click', this.expand, this); - map.on('click', this.collapse, this); - } - - return container; - }, - - onAdd: function (map) { - if (!this._container) this._initLayout(map); - if (map.options.datalayersControl === 'expanded') this.expand(); - return this._container; - }, - - onRemove: function (map) { - this.collapse(); - }, - - update: function () { - if (this._datalayers_container && this._map) { - this._datalayers_container.innerHTML = ''; - this._map.eachDataLayerReverse(function (datalayer) { - this.addDataLayer(this._datalayers_container, datalayer); - }, this) - } - }, - - expand: function () { - L.DomUtil.addClass(this._container, 'expanded'); - }, - - collapse: function () { - if (this._map.options.datalayersControl === 'expanded') return; - L.DomUtil.removeClass(this._container, 'expanded'); - }, - - addDataLayer: function (container, datalayer, draggable) { - var datalayerLi = L.DomUtil.create('li', '', container); - if (draggable) L.DomUtil.element('i', {className: 'drag-handle', title: L._('Drag to reorder')}, datalayerLi); - datalayer.renderToolbox(datalayerLi); - var title = L.DomUtil.add('span', 'layer-title', datalayerLi, datalayer.options.name); - - datalayerLi.id = 'browse_data_toggle_' + L.stamp(datalayer); - L.DomUtil.classIf(datalayerLi, 'off', !datalayer.isVisible()); - - title.textContent = datalayer.options.name; - }, - - newDataLayer: function () { - var datalayer = this.map.createDataLayer({}); - datalayer.edit(); - }, - - openPanel: function () { - if (!this.map.editEnabled) return; - var container = L.DomUtil.create('ul', 'umap-browse-datalayers'); - this.map.eachDataLayerReverse(function (datalayer) { - this.addDataLayer(container, datalayer, true); - }, this); - var orderable = new L.U.Orderable(container); - orderable.on('drop', function (e) { - var layer = this.map.datalayers[e.src.dataset.id], - other = this.map.datalayers[e.dst.dataset.id], - minIndex = Math.min(e.initialIndex, e.finalIndex); - if (e.finalIndex === 0) layer.bringToTop(); - else if (e.finalIndex > e.initialIndex) layer.insertBefore(other); - else layer.insertAfter(other); - this.map.eachDataLayerReverse(function (datalayer) { - if (datalayer.getRank() >= minIndex) datalayer.isDirty = true; - }); - this.map.indexDatalayers(); - }, this); - - var bar = L.DomUtil.create('div', 'button-bar', container), - add = L.DomUtil.create('a', 'show-on-edit block add-datalayer button', bar); - add.href = '#'; - add.textContent = add.title = L._('Add a layer'); - - L.DomEvent - .on(add, 'click', L.DomEvent.stop) - .on(add, 'click', this.newDataLayer, this); - - this.map.ui.openPanel({data: {html: container}, className: 'dark'}); + if (L.Browser.pointer) { + L.DomEvent.disableClickPropagation(container) + L.DomEvent.on(container, 'mousewheel', L.DomEvent.stopPropagation) + L.DomEvent.on(container, 'MozMousePixelScroll', L.DomEvent.stopPropagation) + } + if (!L.Browser.touch) { + L.DomEvent.on( + container, + { + mouseenter: this.expand, + mouseleave: this.collapse, + }, + this + ) + } else { + L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation) + L.DomEvent.on(toggle, 'click', L.DomEvent.stop).on( + toggle, + 'click', + this.expand, + this + ) + map.on('click', this.collapse, this) } -}); + return container + }, + + onAdd(map) { + if (!this._container) this._initLayout(map) + if (map.options.datalayersControl === 'expanded') this.expand() + return this._container + }, + + onRemove(map) { + this.collapse() + }, + + update() { + if (this._datalayers_container && this._map) { + this._datalayers_container.innerHTML = '' + this._map.eachDataLayerReverse(function (datalayer) { + this.addDataLayer(this._datalayers_container, datalayer) + }, this) + } + }, + + expand() { + L.DomUtil.addClass(this._container, 'expanded') + }, + + collapse() { + if (this._map.options.datalayersControl === 'expanded') return + L.DomUtil.removeClass(this._container, 'expanded') + }, + + addDataLayer(container, datalayer, draggable) { + const datalayerLi = L.DomUtil.create('li', '', container) + if (draggable) + L.DomUtil.element( + 'i', + { className: 'drag-handle', title: L._('Drag to reorder') }, + datalayerLi + ) + datalayer.renderToolbox(datalayerLi) + const title = L.DomUtil.add( + 'span', + 'layer-title', + datalayerLi, + datalayer.options.name + ) + + datalayerLi.id = `browse_data_toggle_${L.stamp(datalayer)}` + L.DomUtil.classIf(datalayerLi, 'off', !datalayer.isVisible()) + + title.textContent = datalayer.options.name + }, + + newDataLayer() { + const datalayer = this.map.createDataLayer({}) + datalayer.edit() + }, + + openPanel() { + if (!this.map.editEnabled) return + const container = L.DomUtil.create('ul', 'umap-browse-datalayers') + this.map.eachDataLayerReverse(function (datalayer) { + this.addDataLayer(container, datalayer, true) + }, this) + const orderable = new L.U.Orderable(container) + orderable.on( + 'drop', + function ({ src, dst, initialIndex, finalIndex }) { + const layer = this.map.datalayers[src.dataset.id] + const other = this.map.datalayers[dst.dataset.id] + const minIndex = Math.min(initialIndex, finalIndex) + if (finalIndex === 0) layer.bringToTop() + else if (finalIndex > initialIndex) layer.insertBefore(other) + else layer.insertAfter(other) + this.map.eachDataLayerReverse((datalayer) => { + if (datalayer.getRank() >= minIndex) datalayer.isDirty = true + }) + this.map.indexDatalayers() + }, + this + ) + + const bar = L.DomUtil.create('div', 'button-bar', container) + const add = L.DomUtil.create('a', 'show-on-edit block add-datalayer button', bar) + add.href = '#' + add.textContent = add.title = L._('Add a layer') + + L.DomEvent.on(add, 'click', L.DomEvent.stop).on( + add, + 'click', + this.newDataLayer, + this + ) + + this.map.ui.openPanel({ data: { html: container }, className: 'dark' }) + }, +}) L.U.DataLayer.include({ + renderToolbox(container) { + const toggle = L.DomUtil.create('i', 'layer-toggle', container) + const zoomTo = L.DomUtil.create('i', 'layer-zoom_to', container) + const edit = L.DomUtil.create('i', 'layer-edit show-on-edit', container) + const table = L.DomUtil.create('i', 'layer-table-edit show-on-edit', container) + const remove = L.DomUtil.create('i', 'layer-delete show-on-edit', container) + zoomTo.title = L._('Zoom to layer extent') + toggle.title = L._('Show/hide layer') + edit.title = L._('Edit') + table.title = L._('Edit properties in a table') + remove.title = L._('Delete layer') + L.DomEvent.on(toggle, 'click', this.toggle, this) + L.DomEvent.on(zoomTo, 'click', this.zoomTo, this) + L.DomEvent.on(edit, 'click', this.edit, this) + L.DomEvent.on(table, 'click', this.tableEdit, this) + L.DomEvent.on( + remove, + 'click', + function () { + if (!this.isVisible()) return + if (!confirm(L._('Are you sure you want to delete this layer?'))) return + this._delete() + this.map.ui.closePanel() + }, + this + ) + L.DomUtil.addClass(container, this.getHidableClass()) + L.DomUtil.classIf(container, 'off', !this.isVisible()) + container.dataset.id = L.stamp(this) + }, - renderToolbox: function (container) { - var toggle = L.DomUtil.create('i', 'layer-toggle', container), - zoomTo = L.DomUtil.create('i', 'layer-zoom_to', container), - edit = L.DomUtil.create('i', 'layer-edit show-on-edit', container), - table = L.DomUtil.create('i', 'layer-table-edit show-on-edit', container), - remove = L.DomUtil.create('i', 'layer-delete show-on-edit', container); - zoomTo.title = L._('Zoom to layer extent'); - toggle.title = L._('Show/hide layer'); - edit.title = L._('Edit'); - table.title = L._('Edit properties in a table'); - remove.title = L._('Delete layer'); - L.DomEvent.on(toggle, 'click', this.toggle, this); - L.DomEvent.on(zoomTo, 'click', this.zoomTo, this); - L.DomEvent.on(edit, 'click', this.edit, this); - L.DomEvent.on(table, 'click', this.tableEdit, this); - L.DomEvent.on(remove, 'click', function () { - if (!this.isVisible()) return; - if (!confirm(L._('Are you sure you want to delete this layer?'))) return; - this._delete(); - this.map.ui.closePanel(); - }, this); - L.DomUtil.addClass(container, this.getHidableClass()); - L.DomUtil.classIf(container, 'off', !this.isVisible()); - container.dataset.id = L.stamp(this); - }, + getHidableElements() { + return document.querySelectorAll(`.${this.getHidableClass()}`) + }, - getHidableElements: function () { - return document.querySelectorAll('.' + this.getHidableClass()); - }, + getHidableClass() { + return `show_with_datalayer_${L.stamp(this)}` + }, - getHidableClass: function () { - return 'show_with_datalayer_' + L.stamp(this); - }, - - propagateRemote: function () { - var els = this.getHidableElements(); - for (var i = 0; i < els.length; i++) { - L.DomUtil.classIf(els[i], 'remotelayer', this.isRemoteLayer()); - } - }, - - propagateHide: function () { - var els = this.getHidableElements(); - for (var i = 0; i < els.length; i++) { - L.DomUtil.addClass(els[i], 'off'); - } - }, - - propagateShow: function () { - this.onceLoaded(function () { - var els = this.getHidableElements(); - for (var i = 0; i < els.length; i++) { - L.DomUtil.removeClass(els[i], 'off'); - } - }, this); + propagateRemote() { + const els = this.getHidableElements() + for (let i = 0; i < els.length; i++) { + L.DomUtil.classIf(els[i], 'remotelayer', this.isRemoteLayer()) } + }, -}); + propagateHide() { + const els = this.getHidableElements() + for (let i = 0; i < els.length; i++) { + L.DomUtil.addClass(els[i], 'off') + } + }, + + propagateShow() { + this.onceLoaded(function () { + const els = this.getHidableElements() + for (let i = 0; i < els.length; i++) { + L.DomUtil.removeClass(els[i], 'off') + } + }, this) + }, +}) L.U.DataLayer.addInitHook(function () { - this.on('hide', this.propagateHide); - this.on('show', this.propagateShow); - this.propagateShow(); -}); - + this.on('hide', this.propagateHide) + this.on('show', this.propagateShow) + this.propagateShow() +}) L.U.Map.include({ + _openBrowser() { + const browserContainer = L.DomUtil.create('div', 'umap-browse-data') + const title = L.DomUtil.add( + 'h3', + 'umap-browse-title', + browserContainer, + this.options.name + ) + const filter = L.DomUtil.create('input', '', browserContainer) + let filterValue = '' + const featuresContainer = L.DomUtil.create( + 'div', + 'umap-browse-features', + browserContainer + ) + const filterKeys = this.getFilterKeys() + filter.type = 'text' + filter.placeholder = L._('Filter…') + filter.value = this.options.filter || '' - _openBrowser: function () { - var browserContainer = L.DomUtil.create('div', 'umap-browse-data'), - title = L.DomUtil.add('h3', 'umap-browse-title', browserContainer, this.options.name), - filter = L.DomUtil.create('input', '', browserContainer), - filterValue = '', - featuresContainer = L.DomUtil.create('div', 'umap-browse-features', browserContainer), - filterKeys = this.getFilterKeys(); - filter.type = 'text'; - filter.placeholder = L._('Filter…'); - filter.value = this.options.filter || ''; - - var addFeature = function (feature) { - var feature_li = L.DomUtil.create('li', feature.getClassName() + ' feature'), - zoom_to = L.DomUtil.create('i', 'feature-zoom_to', feature_li), - edit = L.DomUtil.create('i', 'show-on-edit feature-edit', feature_li), - color = L.DomUtil.create('i', 'feature-color', feature_li), - title = L.DomUtil.create('span', 'feature-title', feature_li), - symbol = feature._getIconUrl ? L.U.Icon.prototype.formatUrl(feature._getIconUrl(), feature): null; - zoom_to.title = L._('Bring feature to center'); - edit.title = L._('Edit this feature'); - title.textContent = feature.getDisplayName() || '—'; - color.style.backgroundColor = feature.getOption('color'); - if (symbol) { - color.style.backgroundImage = 'url(' + symbol + ')'; - } - L.DomEvent.on(zoom_to, 'click', function (e) { - e.callback = L.bind(this.view, this); - this.zoomTo(e); - }, feature); - L.DomEvent.on(title, 'click', function (e) { - e.callback = L.bind(this.view, this) - this.zoomTo(e); - }, feature); - L.DomEvent.on(edit, 'click', function () { - this.edit(); - }, feature); - return feature_li; - }; - - var append = function (datalayer) { - var container = L.DomUtil.create('div', datalayer.getHidableClass(), featuresContainer), - headline = L.DomUtil.create('h5', '', container); - container.id = 'browse_data_datalayer_' + datalayer.umap_id; - datalayer.renderToolbox(headline); - L.DomUtil.add('span', '', headline, datalayer.options.name); - var ul = L.DomUtil.create('ul', '', container); - L.DomUtil.classIf(container, 'off', !datalayer.isVisible()); - - var build = function () { - ul.innerHTML = ''; - datalayer.eachFeature(function (feature) { - if ((filterValue && !feature.matchFilter(filterValue, filterKeys)) || feature.properties.isVisible === false) return; - ul.appendChild(addFeature(feature)); - }); - }; - build(); - datalayer.on('datachanged', build); - datalayer.map.ui.once('panel:closed', function () { - datalayer.off('datachanged', build); - }); - datalayer.map.ui.once('panel:ready', function () { - datalayer.map.ui.once('panel:ready', function () { - datalayer.off('datachanged', build); - }); - }); - }; - - var appendAll = function () { - this.options.filter = filterValue = filter.value; - featuresContainer.innerHTML = ''; - this.eachBrowsableDataLayer(function (datalayer) { - append(datalayer); - }); - }; - var resetLayers = function () { - this.eachBrowsableDataLayer(function (datalayer) { - datalayer.resetLayer(true); - }); - } - L.bind(appendAll, this)(); - L.DomEvent.on(filter, 'input', appendAll, this); - L.DomEvent.on(filter, 'input', resetLayers, this); - var link = L.DomUtil.create('li', ''); - L.DomUtil.create('i', 'umap-icon-16 umap-caption', link); - var label = L.DomUtil.create('span', '', link); - label.textContent = label.title = L._('About'); - L.DomEvent.on(link, 'click', this.displayCaption, this); - this.ui.openPanel({data: {html: browserContainer}, actions: [link]}); - }, - - _openFilter: function () { - var filterContainer = L.DomUtil.create('div', 'umap-filter-data'), - title = L.DomUtil.add('h3', 'umap-filter-title', filterContainer, this.options.name), - propertiesContainer = L.DomUtil.create('div', 'umap-filter-properties', filterContainer), - advancedFilterKeys = this.getAdvancedFilterKeys(); - - var advancedFiltersFull = {}; - var filtersAlreadyLoaded = true; - if (!this.getMap().options.advancedFilters) { - this.getMap().options.advancedFilters = {}; - filtersAlreadyLoaded = false; - } - advancedFilterKeys.forEach(property => { - advancedFiltersFull[property] = []; - if (!filtersAlreadyLoaded || !this.getMap().options.advancedFilters[property]) { - this.getMap().options.advancedFilters[property] = []; - } - }); - this.eachDataLayer(function (datalayer) { - datalayer.eachFeature(function (feature) { - advancedFilterKeys.forEach(property => { - if (feature.properties[property]) { - if (!advancedFiltersFull[property].includes(feature.properties[property])) { - advancedFiltersFull[property].push(feature.properties[property]); - } - } - }); - }); - }); - - var addPropertyValue = function (property, value) { - var property_li = L.DomUtil.create('li', ''), - filter_check = L.DomUtil.create('input', '', property_li), - filter_label = L.DomUtil.create('label', '', property_li); - filter_check.type = 'checkbox'; - filter_check.id = `checkbox_${property}_${value}`; - filter_check.checked = this.getMap().options.advancedFilters[property] && this.getMap().options.advancedFilters[property].includes(value); - filter_check.setAttribute('data-property', property); - filter_check.setAttribute('data-value', value); - filter_label.htmlFor = `checkbox_${property}_${value}`; - filter_label.innerHTML = value; - L.DomEvent.on(filter_check, 'change', function (e) { - var property = e.srcElement.dataset.property; - var value = e.srcElement.dataset.value; - if (e.srcElement.checked) { - this.getMap().options.advancedFilters[property].push(value); - } else { - this.getMap().options.advancedFilters[property].splice(this.getMap().options.advancedFilters[property].indexOf(value), 1); - } - L.bind(filterFeatures, this)(); - }, this); - return property_li - }; - - var addProperty = function (property) { - var container = L.DomUtil.create('div', 'property-container', propertiesContainer), - headline = L.DomUtil.add('h5', '', container, property); - var ul = L.DomUtil.create('ul', '', container); - var orderedValues = advancedFiltersFull[property]; - orderedValues.sort(); - orderedValues.forEach(value => { - ul.appendChild(L.bind(addPropertyValue, this)(property, value)); - }); - }; - - var filterFeatures = function () { - var noResults = true; - this.eachDataLayer(function (datalayer) { - datalayer.eachFeature(function (feature) { - feature.properties.isVisible = true; - for (const [property, values] of Object.entries(this.map.options.advancedFilters)) { - if (values.length > 0) { - if (!feature.properties[property] || !values.includes(feature.properties[property])) { - feature.properties.isVisible = false; - } - } - } - if (feature.properties.isVisible) { - noResults = false; - if (!this.isLoaded()) this.fetchData(); - this.map.addLayer(feature); - this.fire('show'); - } else { - this.map.removeLayer(feature); - this.fire('hide'); - } - }); - }); - if (noResults) { - this.help.show('advancedFiltersNoResults'); - } else { - this.help.hide(); - } - }; - - propertiesContainer.innerHTML = ''; - advancedFilterKeys.forEach(property => { - L.bind(addProperty, this)(property); - }); - - var link = L.DomUtil.create('li', ''); - L.DomUtil.create('i', 'umap-icon-16 umap-caption', link); - var label = L.DomUtil.create('span', '', link); - label.textContent = label.title = L._('About'); - L.DomEvent.on(link, 'click', this.displayCaption, this); - this.ui.openPanel({ data: { html: filterContainer }, actions: [link] }); + const addFeature = (feature) => { + const feature_li = L.DomUtil.create('li', `${feature.getClassName()} feature`) + const zoom_to = L.DomUtil.create('i', 'feature-zoom_to', feature_li) + const edit = L.DomUtil.create('i', 'show-on-edit feature-edit', feature_li) + const color = L.DomUtil.create('i', 'feature-color', feature_li) + const title = L.DomUtil.create('span', 'feature-title', feature_li) + const symbol = feature._getIconUrl + ? L.U.Icon.prototype.formatUrl(feature._getIconUrl(), feature) + : null + zoom_to.title = L._('Bring feature to center') + edit.title = L._('Edit this feature') + title.textContent = feature.getDisplayName() || '—' + color.style.backgroundColor = feature.getOption('color') + if (symbol) { + color.style.backgroundImage = `url(${symbol})` + } + L.DomEvent.on( + zoom_to, + 'click', + function (e) { + e.callback = L.bind(this.view, this) + this.zoomTo(e) + }, + feature + ) + L.DomEvent.on( + title, + 'click', + function (e) { + e.callback = L.bind(this.view, this) + this.zoomTo(e) + }, + feature + ) + L.DomEvent.on( + edit, + 'click', + function () { + this.edit() + }, + feature + ) + return feature_li } -}); + const append = (datalayer) => { + const container = L.DomUtil.create( + 'div', + datalayer.getHidableClass(), + featuresContainer + ) + const headline = L.DomUtil.create('h5', '', container) + container.id = `browse_data_datalayer_${datalayer.umap_id}` + datalayer.renderToolbox(headline) + L.DomUtil.add('span', '', headline, datalayer.options.name) + const ul = L.DomUtil.create('ul', '', container) + L.DomUtil.classIf(container, 'off', !datalayer.isVisible()) + const build = () => { + ul.innerHTML = '' + datalayer.eachFeature((feature) => { + if ( + (filterValue && !feature.matchFilter(filterValue, filterKeys)) || + feature.properties.isVisible === false + ) + return + ul.appendChild(addFeature(feature)) + }) + } + build() + datalayer.on('datachanged', build) + datalayer.map.ui.once('panel:closed', () => { + datalayer.off('datachanged', build) + }) + datalayer.map.ui.once('panel:ready', () => { + datalayer.map.ui.once('panel:ready', () => { + datalayer.off('datachanged', build) + }) + }) + } + const appendAll = function () { + this.options.filter = filterValue = filter.value + featuresContainer.innerHTML = '' + this.eachBrowsableDataLayer((datalayer) => { + append(datalayer) + }) + } + const resetLayers = function () { + this.eachBrowsableDataLayer((datalayer) => { + datalayer.resetLayer(true) + }) + } + L.bind(appendAll, this)() + L.DomEvent.on(filter, 'input', appendAll, this) + L.DomEvent.on(filter, 'input', resetLayers, this) + const link = L.DomUtil.create('li', '') + L.DomUtil.create('i', 'umap-icon-16 umap-caption', link) + const label = L.DomUtil.create('span', '', link) + label.textContent = label.title = L._('About') + L.DomEvent.on(link, 'click', this.displayCaption, this) + this.ui.openPanel({ data: { html: browserContainer }, actions: [link] }) + }, + + _openFilter() { + const filterContainer = L.DomUtil.create('div', 'umap-filter-data') + const title = L.DomUtil.add( + 'h3', + 'umap-filter-title', + filterContainer, + this.options.name + ) + const propertiesContainer = L.DomUtil.create( + 'div', + 'umap-filter-properties', + filterContainer + ) + const advancedFilterKeys = this.getAdvancedFilterKeys() + + const advancedFiltersFull = {} + let filtersAlreadyLoaded = true + if (!this.getMap().options.advancedFilters) { + this.getMap().options.advancedFilters = {} + filtersAlreadyLoaded = false + } + advancedFilterKeys.forEach((property) => { + advancedFiltersFull[property] = [] + if (!filtersAlreadyLoaded || !this.getMap().options.advancedFilters[property]) { + this.getMap().options.advancedFilters[property] = [] + } + }) + this.eachDataLayer((datalayer) => { + datalayer.eachFeature(({ properties }) => { + advancedFilterKeys.forEach((property) => { + if (properties[property]) { + if (!advancedFiltersFull[property].includes(properties[property])) { + advancedFiltersFull[property].push(properties[property]) + } + } + }) + }) + }) + + const addPropertyValue = function (property, value) { + const property_li = L.DomUtil.create('li', '') + const filter_check = L.DomUtil.create('input', '', property_li) + const filter_label = L.DomUtil.create('label', '', property_li) + filter_check.type = 'checkbox' + filter_check.id = `checkbox_${property}_${value}` + filter_check.checked = + this.getMap().options.advancedFilters[property] && + this.getMap().options.advancedFilters[property].includes(value) + filter_check.setAttribute('data-property', property) + filter_check.setAttribute('data-value', value) + filter_label.htmlFor = `checkbox_${property}_${value}` + filter_label.innerHTML = value + L.DomEvent.on( + filter_check, + 'change', + function ({ srcElement }) { + const property = srcElement.dataset.property + const value = srcElement.dataset.value + if (srcElement.checked) { + this.getMap().options.advancedFilters[property].push(value) + } else { + this.getMap().options.advancedFilters[property].splice( + this.getMap().options.advancedFilters[property].indexOf(value), + 1 + ) + } + L.bind(filterFeatures, this)() + }, + this + ) + return property_li + } + + const addProperty = function (property) { + const container = L.DomUtil.create( + 'div', + 'property-container', + propertiesContainer + ) + const headline = L.DomUtil.add('h5', '', container, property) + const ul = L.DomUtil.create('ul', '', container) + const orderedValues = advancedFiltersFull[property] + orderedValues.sort() + orderedValues.forEach((value) => { + ul.appendChild(L.bind(addPropertyValue, this)(property, value)) + }) + } + + var filterFeatures = function () { + let noResults = true + this.eachDataLayer((datalayer) => { + datalayer.eachFeature(function (feature) { + feature.properties.isVisible = true + for (const [property, values] of Object.entries( + this.map.options.advancedFilters + )) { + if (values.length > 0) { + if ( + !feature.properties[property] || + !values.includes(feature.properties[property]) + ) { + feature.properties.isVisible = false + } + } + } + if (feature.properties.isVisible) { + noResults = false + if (!this.isLoaded()) this.fetchData() + this.map.addLayer(feature) + this.fire('show') + } else { + this.map.removeLayer(feature) + this.fire('hide') + } + }) + }) + if (noResults) { + this.help.show('advancedFiltersNoResults') + } else { + this.help.hide() + } + } + + propertiesContainer.innerHTML = '' + advancedFilterKeys.forEach((property) => { + L.bind(addProperty, this)(property) + }) + + const link = L.DomUtil.create('li', '') + L.DomUtil.create('i', 'umap-icon-16 umap-caption', link) + const label = L.DomUtil.create('span', '', link) + label.textContent = label.title = L._('About') + L.DomEvent.on(link, 'click', this.displayCaption, this) + this.ui.openPanel({ data: { html: filterContainer }, actions: [link] }) + }, +}) L.U.TileLayerControl = L.Control.extend({ + options: { + position: 'topleft', + }, - options: { - position: 'topleft' - }, + initialize(map, options) { + this.map = map + L.Control.prototype.initialize.call(this, options) + }, - initialize: function (map, options) { - this.map = map; - L.Control.prototype.initialize.call(this, options); - }, + onAdd() { + const container = L.DomUtil.create('div', 'leaflet-control-tilelayers umap-control') - onAdd: function () { - var container = L.DomUtil.create('div', 'leaflet-control-tilelayers umap-control'); + const link = L.DomUtil.create('a', '', container) + link.href = '#' + link.title = L._('Change map background') - var link = L.DomUtil.create('a', '', container); - link.href = '#'; - link.title = L._('Change map background'); + L.DomEvent.on(link, 'click', L.DomEvent.stop) + .on(link, 'click', this.openSwitcher, this) + .on(link, 'dblclick', L.DomEvent.stopPropagation) - L.DomEvent - .on(link, 'click', L.DomEvent.stop) - .on(link, 'click', this.openSwitcher, this) - .on(link, 'dblclick', L.DomEvent.stopPropagation); + return container + }, - return container; - }, + openSwitcher(options) { + this._tilelayers_container = L.DomUtil.create( + 'ul', + 'umap-tilelayer-switcher-container' + ) + this.buildList(options) + }, - openSwitcher: function (options) { - this._tilelayers_container = L.DomUtil.create('ul', 'umap-tilelayer-switcher-container'); - this.buildList(options); - }, + buildList(options) { + this.map.eachTileLayer(function (tilelayer) { + if ( + window.location.protocol === 'https:' && + tilelayer.options.url_template.indexOf('http:') === 0 + ) + return + this.addTileLayerElement(tilelayer, options) + }, this) + this.map.ui.openPanel({ + data: { html: this._tilelayers_container }, + className: options.className, + }) + }, - buildList: function (options) { - this.map.eachTileLayer(function (tilelayer) { - if (window.location.protocol === 'https:' && tilelayer.options.url_template.indexOf('http:') === 0) return; - this.addTileLayerElement(tilelayer, options); - }, this); - this.map.ui.openPanel({data: {html: this._tilelayers_container}, className: options.className}); - }, - - addTileLayerElement: function (tilelayer, options) { - var selectedClass = this.map.hasLayer(tilelayer) ? 'selected' : '', - el = L.DomUtil.create('li', selectedClass, this._tilelayers_container), - img = L.DomUtil.create('img', '', el), - name = L.DomUtil.create('div', '', el); - img.src = L.Util.template(tilelayer.options.url_template, this.map.demoTileInfos); - name.textContent = tilelayer.options.name; - L.DomEvent.on(el, 'click', function () { - this.map.selectTileLayer(tilelayer); - this.map.ui.closePanel(); - if (options && options.callback) options.callback(tilelayer); - }, this); - } - - -}); + addTileLayerElement(tilelayer, options) { + const selectedClass = this.map.hasLayer(tilelayer) ? 'selected' : '' + const el = L.DomUtil.create('li', selectedClass, this._tilelayers_container) + const img = L.DomUtil.create('img', '', el) + const name = L.DomUtil.create('div', '', el) + img.src = L.Util.template(tilelayer.options.url_template, this.map.demoTileInfos) + name.textContent = tilelayer.options.name + L.DomEvent.on( + el, + 'click', + function () { + this.map.selectTileLayer(tilelayer) + this.map.ui.closePanel() + if (options && options.callback) options.callback(tilelayer) + }, + this + ) + }, +}) L.U.AttributionControl = L.Control.Attribution.extend({ + options: { + prefix: '', + }, - options: { - prefix: '' - }, - - _update: function () { - L.Control.Attribution.prototype._update.call(this); - if (this._map.options.shortCredit) { - L.DomUtil.add('span', '', this._container, ' — ' + L.Util.toHTML(this._map.options.shortCredit)); - } - if (this._map.options.captionMenus) { - var link = L.DomUtil.add('a', '', this._container, ' — ' + L._('About')); - L.DomEvent - .on(link, 'click', L.DomEvent.stop) - .on(link, 'click', this._map.displayCaption, this._map) - .on(link, 'dblclick', L.DomEvent.stop); - } - if (window.top === window.self && this._map.options.captionMenus) { - // We are not in iframe mode - var home = L.DomUtil.add('a', '', this._container, ' — ' + L._('Home')); - home.href = '/'; - } + _update() { + L.Control.Attribution.prototype._update.call(this) + if (this._map.options.shortCredit) { + L.DomUtil.add( + 'span', + '', + this._container, + ` — ${L.Util.toHTML(this._map.options.shortCredit)}` + ) } - -}); - + if (this._map.options.captionMenus) { + const link = L.DomUtil.add('a', '', this._container, ` — ${L._('About')}`) + L.DomEvent.on(link, 'click', L.DomEvent.stop) + .on(link, 'click', this._map.displayCaption, this._map) + .on(link, 'dblclick', L.DomEvent.stop) + } + if (window.top === window.self && this._map.options.captionMenus) { + // We are not in iframe mode + const home = L.DomUtil.add('a', '', this._container, ` — ${L._('Home')}`) + home.href = '/' + } + }, +}) L.U.Search = L.PhotonSearch.extend({ + initialize(map, input, options) { + L.PhotonSearch.prototype.initialize.call(this, map, input, options) + this.options.url = map.options.urls.search + }, - initialize: function (map, input, options) { - L.PhotonSearch.prototype.initialize.call(this, map, input, options); - this.options.url = map.options.urls.search; - }, + onBlur(e) { + // Overrided because we don't want to hide the results on blur. + this.fire('blur') + }, - onBlur: function (e) { - // Overrided because we don't want to hide the results on blur. - this.fire('blur'); - }, + formatResult(feature, el) { + const self = this + const tools = L.DomUtil.create('span', 'search-result-tools', el) + const zoom = L.DomUtil.create('i', 'feature-zoom_to', tools) + const edit = L.DomUtil.create('i', 'feature-edit show-on-edit', tools) + zoom.title = L._('Zoom to this place') + edit.title = L._('Save this location as new feature') + // We need to use "mousedown" because Leaflet.Photon listen to mousedown + // on el. + L.DomEvent.on(zoom, 'mousedown', (e) => { + L.DomEvent.stop(e) + self.zoomToFeature(feature) + }) + L.DomEvent.on(edit, 'mousedown', (e) => { + L.DomEvent.stop(e) + const datalayer = self.map.defaultDataLayer() + const layer = datalayer.geojsonToFeatures(feature) + layer.isDirty = true + layer.edit() + }) + this._formatResult(feature, el) + }, - formatResult: function (feature, el) { - var self = this; - var tools = L.DomUtil.create('span', 'search-result-tools', el), - zoom = L.DomUtil.create('i', 'feature-zoom_to', tools), - edit = L.DomUtil.create('i', 'feature-edit show-on-edit', tools); - zoom.title = L._('Zoom to this place'); - edit.title = L._('Save this location as new feature'); - // We need to use "mousedown" because Leaflet.Photon listen to mousedown - // on el. - L.DomEvent.on(zoom, 'mousedown', function (e) { - L.DomEvent.stop(e); - self.zoomToFeature(feature); - }); - L.DomEvent.on(edit, 'mousedown', function (e) { - L.DomEvent.stop(e); - var datalayer = self.map.defaultDataLayer(); - var layer = datalayer.geojsonToFeatures(feature); - layer.isDirty = true; - layer.edit(); - }); - this._formatResult(feature, el); - }, + zoomToFeature({ geometry }) { + const zoom = Math.max(this.map.getZoom(), 16) // Never unzoom. + this.map.setView([geometry.coordinates[1], geometry.coordinates[0]], zoom) + }, - zoomToFeature: function (feature) { - var zoom = Math.max(this.map.getZoom(), 16); // Never unzoom. - this.map.setView([feature.geometry.coordinates[1], feature.geometry.coordinates[0]], zoom); - }, - - onSelected: function (feature) { - this.zoomToFeature(feature); - this.map.ui.closePanel(); - } - -}); + onSelected(feature) { + this.zoomToFeature(feature) + this.map.ui.closePanel() + }, +}) L.U.SearchControl = L.Control.extend({ + options: { + position: 'topleft', + }, - options: { - position: 'topleft', - }, + onAdd(map) { + const container = L.DomUtil.create('div', 'leaflet-control-search umap-control') + const self = this - onAdd: function (map) { - var container = L.DomUtil.create('div', 'leaflet-control-search umap-control'), - self = this; + L.DomEvent.disableClickPropagation(container) + const link = L.DomUtil.create('a', '', container) + link.href = '#' + link.title = L._('Search a place name') + L.DomEvent.on(link, 'click', (e) => { + L.DomEvent.stop(e) + self.openPanel(map) + }) + return container + }, - L.DomEvent.disableClickPropagation(container); - var link = L.DomUtil.create('a', '', container); - link.href = '#'; - link.title = L._('Search a place name') - L.DomEvent.on(link, 'click', function (e) { - L.DomEvent.stop(e); - self.openPanel(map); - }); - return container; - }, - - openPanel: function (map) { - var options = { - limit: 10, - noResultLabel: L._('No results'), - } - if (map.options.photonUrl) options.url = map.options.photonUrl; - var container = L.DomUtil.create('div', ''); - - var title = L.DomUtil.create('h3', '', container); - title.textContent = L._('Search location'); - var input = L.DomUtil.create('input', 'photon-input', container); - var resultsContainer = L.DomUtil.create('div', 'photon-autocomplete', container); - this.search = new L.U.Search(map, input, options); - var id = Math.random(); - this.search.on('ajax:send', function () { - map.fire('dataloading', {id: id}); - }); - this.search.on('ajax:return', function () { - map.fire('dataload', {id: id}); - }); - this.search.resultsContainer = resultsContainer; - map.ui.once('panel:ready', function () { - input.focus(); - }); - map.ui.openPanel({data: {html: container}}); + openPanel(map) { + const options = { + limit: 10, + noResultLabel: L._('No results'), } + if (map.options.photonUrl) options.url = map.options.photonUrl + const container = L.DomUtil.create('div', '') -}); - + const title = L.DomUtil.create('h3', '', container) + title.textContent = L._('Search location') + const input = L.DomUtil.create('input', 'photon-input', container) + const resultsContainer = L.DomUtil.create('div', 'photon-autocomplete', container) + this.search = new L.U.Search(map, input, options) + const id = Math.random() + this.search.on('ajax:send', () => { + map.fire('dataloading', { id }) + }) + this.search.on('ajax:return', () => { + map.fire('dataload', { id }) + }) + this.search.resultsContainer = resultsContainer + map.ui.once('panel:ready', () => { + input.focus() + }) + map.ui.openPanel({ data: { html: container } }) + }, +}) L.Control.MiniMap.include({ + initialize(layer, options) { + L.Util.setOptions(this, options) + this._layer = this._cloneLayer(layer) + }, - initialize: function (layer, options) { - L.Util.setOptions(this, options); - this._layer = this._cloneLayer(layer); - }, - - onMainMapBaseLayerChange: function (e) { - var layer = this._cloneLayer(e.layer); - if (this._miniMap.hasLayer(this._layer)) { - this._miniMap.removeLayer(this._layer); - } - this._layer = layer; - this._miniMap.addLayer(this._layer); - }, - - _cloneLayer: function (layer) { - return new L.TileLayer(layer._url, L.Util.extend({}, layer.options)); + onMainMapBaseLayerChange(e) { + const layer = this._cloneLayer(e.layer) + if (this._miniMap.hasLayer(this._layer)) { + this._miniMap.removeLayer(this._layer) } + this._layer = layer + this._miniMap.addLayer(this._layer) + }, -}); - + _cloneLayer({ _url, options }) { + return new L.TileLayer(_url, L.Util.extend({}, options)) + }, +}) L.Control.Loading.include({ + onAdd(map) { + this._container = L.DomUtil.create('div', 'umap-loader', map._controlContainer) + map.on('baselayerchange', this._layerAdd, this) + this._addMapListeners(map) + this._map = map + }, - onAdd: function (map) { - this._container = L.DomUtil.create('div', 'umap-loader', map._controlContainer); - map.on('baselayerchange', this._layerAdd, this); - this._addMapListeners(map); - this._map = map; - }, - - _showIndicator: function () { - L.DomUtil.addClass(this._map._container, 'umap-loading'); - }, - - _hideIndicator: function() { - L.DomUtil.removeClass(this._map._container, 'umap-loading'); - } - -}); + _showIndicator() { + L.DomUtil.addClass(this._map._container, 'umap-loading') + }, + _hideIndicator() { + L.DomUtil.removeClass(this._map._container, 'umap-loading') + }, +}) /* -* Make it dynamic -*/ + * Make it dynamic + */ L.U.ContextMenu = L.Map.ContextMenu.extend({ + _createItems(e) { + this._map.setContextMenuItems(e) + L.Map.ContextMenu.prototype._createItems.call(this) + }, - _createItems: function (e) { - this._map.setContextMenuItems(e); - L.Map.ContextMenu.prototype._createItems.call(this); - }, - - _showAtPoint: function (pt, e) { - this._items = []; - this._container.innerHTML = ''; - this._createItems(e); - L.Map.ContextMenu.prototype._showAtPoint.call(this, pt, e); - } - -}); + _showAtPoint(pt, e) { + this._items = [] + this._container.innerHTML = '' + this._createItems(e) + L.Map.ContextMenu.prototype._showAtPoint.call(this, pt, e) + }, +}) L.U.IframeExporter = L.Evented.extend({ + options: { + includeFullScreenLink: true, + currentView: false, + keepCurrentDatalayers: false, + viewCurrentFeature: false, + }, - options: { - includeFullScreenLink: true, - currentView: false, - keepCurrentDatalayers: false, - viewCurrentFeature: false - }, + queryString: { + scaleControl: false, + miniMap: false, + scrollWheelZoom: false, + zoomControl: true, + allowEdit: false, + moreControl: true, + searchControl: null, + tilelayersControl: null, + embedControl: null, + datalayersControl: true, + onLoadPanel: 'none', + captionBar: false, + captionMenus: true, + }, - queryString: { - scaleControl: false, - miniMap: false, - scrollWheelZoom: false, - zoomControl: true, - allowEdit: false, - moreControl: true, - searchControl: null, - tilelayersControl: null, - embedControl: null, - datalayersControl: true, - onLoadPanel: 'none', - captionBar: false, - captionMenus: true - }, + dimensions: { + width: '100%', + height: '300px', + }, - dimensions: { - width: '100%', - height: '300px' - }, + initialize(map) { + this.map = map + this.baseUrl = L.Util.getBaseUrl() + // Use map default, not generic default + this.queryString.onLoadPanel = this.map.options.onLoadPanel + }, - initialize: function (map) { - this.map = map; - this.baseUrl = L.Util.getBaseUrl(); - // Use map default, not generic default - this.queryString.onLoadPanel = this.map.options.onLoadPanel; - }, + getMap() { + return this.map + }, - getMap: function () { - return this.map; - }, - - build: function () { - var datalayers = []; - if (this.options.viewCurrentFeature && this.map.currentFeature) { - this.queryString.feature = this.map.currentFeature.getSlug(); - } - if (this.options.keepCurrentDatalayers) { - this.map.eachDataLayer(function (datalayer) { - if (datalayer.isVisible() && datalayer.umap_id) { - datalayers.push(datalayer.umap_id); - } - }); - this.queryString.datalayers = datalayers.join(','); - } else { - delete this.queryString.datalayers; - } - var currentView = this.options.currentView ? window.location.hash : '', - iframeUrl = this.baseUrl + '?' + L.Util.buildQueryString(this.queryString) + currentView, - code = ''; - if (this.options.includeFullScreenLink) { - code += '

' + L._('See full screen') + '

'; - } - return code; + build() { + const datalayers = [] + if (this.options.viewCurrentFeature && this.map.currentFeature) { + this.queryString.feature = this.map.currentFeature.getSlug() } - -}); + if (this.options.keepCurrentDatalayers) { + this.map.eachDataLayer((datalayer) => { + if (datalayer.isVisible() && datalayer.umap_id) { + datalayers.push(datalayer.umap_id) + } + }) + this.queryString.datalayers = datalayers.join(',') + } else { + delete this.queryString.datalayers + } + const currentView = this.options.currentView ? window.location.hash : '' + const iframeUrl = `${this.baseUrl}?${L.Util.buildQueryString( + this.queryString + )}${currentView}` + let code = `` + if (this.options.includeFullScreenLink) { + code += `

${L._('See full screen')}

` + } + return code + }, +}) L.U.Editable = L.Editable.extend({ + initialize(map, options) { + L.Editable.prototype.initialize.call(this, map, options) + this.on( + 'editable:drawing:start editable:drawing:click editable:drawing:move', + this.drawingTooltip + ) + this.on('editable:drawing:end', this.closeTooltip) + // Layer for items added by users + this.on('editable:drawing:cancel', ({ layer }) => { + if (layer._latlngs && layer._latlngs.length < layer.editor.MIN_VERTEX) layer.del() + if (layer instanceof L.U.Marker) layer.del() + }) + this.on('editable:drawing:commit', function (e) { + e.layer.isDirty = true + if (this.map.editedFeature !== e.layer) e.layer.edit(e) + }) + this.on('editable:editing', (e) => { + const layer = e.layer + layer.isDirty = true + if (layer._tooltip && layer.isTooltipOpen()) { + layer._tooltip.setLatLng(layer.getCenter()) + layer._tooltip.update() + } + }) + this.on('editable:vertex:ctrlclick', ({ vertex }) => { + const index = vertex.getIndex() + if (index === 0 || (index === vertex.getLastIndex() && vertex.continue)) + vertex.continue() + }) + this.on('editable:vertex:altclick', ({ vertex }) => { + if (vertex.editor.vertexCanBeDeleted(vertex)) vertex.delete() + }) + this.on('editable:vertex:rawclick', this.onVertexRawClick) + }, - initialize: function (map, options) { - L.Editable.prototype.initialize.call(this, map, options); - this.on('editable:drawing:start editable:drawing:click editable:drawing:move', this.drawingTooltip); - this.on('editable:drawing:end', this.closeTooltip); - // Layer for items added by users - this.on('editable:drawing:cancel', function (e) { - if (e.layer._latlngs && e.layer._latlngs.length < e.layer.editor.MIN_VERTEX) e.layer.del(); - if (e.layer instanceof L.U.Marker) e.layer.del(); - }); - this.on('editable:drawing:commit', function (e) { - e.layer.isDirty = true; - if (this.map.editedFeature !== e.layer) e.layer.edit(e); - }); - this.on('editable:editing', function (e) { - var layer = e.layer; - layer.isDirty = true; - if (layer._tooltip && layer.isTooltipOpen()) { - layer._tooltip.setLatLng(layer.getCenter()); - layer._tooltip.update(); - } - }); - this.on('editable:vertex:ctrlclick', function (e) { - var index = e.vertex.getIndex(); - if (index === 0 || index === e.vertex.getLastIndex() && e.vertex.continue) e.vertex.continue(); - }); - this.on('editable:vertex:altclick', function (e) { - if (e.vertex.editor.vertexCanBeDeleted(e.vertex)) e.vertex.delete(); - }); - this.on('editable:vertex:rawclick', this.onVertexRawClick); - }, + createPolyline(latlngs) { + return new L.U.Polyline(this.map, latlngs) + }, - createPolyline: function (latlngs) { - return new L.U.Polyline(this.map, latlngs); - }, + createPolygon(latlngs) { + const polygon = new L.U.Polygon(this.map, latlngs) + return polygon + }, - createPolygon: function (latlngs) { - var polygon = new L.U.Polygon(this.map, latlngs); - return polygon; - }, + createMarker(latlng) { + return new L.U.Marker(this.map, latlng) + }, - createMarker: function (latlng) { - return new L.U.Marker(this.map, latlng); - }, + connectCreatedToMap(layer) { + // Overrided from Leaflet.Editable + const datalayer = this.map.defaultDataLayer() + datalayer.addLayer(layer) + layer.isDirty = true + return layer + }, - connectCreatedToMap: function (layer) { - // Overrided from Leaflet.Editable - var datalayer = this.map.defaultDataLayer(); - datalayer.addLayer(layer); - layer.isDirty = true; - return layer; - }, - - drawingTooltip: function (e) { - if (e.layer instanceof L.Marker && e.type != "editable:drawing:move") { - this.map.ui.tooltip({content: L._('Click to add a marker')}); - } - if (!(e.layer instanceof L.Polyline)) { - // only continue with Polylines and Polygons - return; - } - - var content; - var measure; - if (e.layer.editor._drawnLatLngs) { - // when drawing (a Polyline or Polygon) - if (!e.layer.editor._drawnLatLngs.length) { - // when drawing first point - if (e.layer instanceof L.Polygon){ - content = L._('Click to start drawing a polygon'); - } else if (e.layer instanceof L.Polyline) { - content = L._('Click to start drawing a line'); - } - } else { - var tmpLatLngs = e.layer.editor._drawnLatLngs.slice(); - tmpLatLngs.push(e.latlng); - measure = e.layer.getMeasure(tmpLatLngs); - - if (e.layer.editor._drawnLatLngs.length < e.layer.editor.MIN_VERTEX) { - // when drawing second point - content = L._('Click to continue drawing'); - } else { - // when drawing third point (or more) - content = L._('Click last point to finish shape'); - } - } - } else { - // when moving an existing point - measure = e.layer.getMeasure(); - } - if (measure){ - if (e.layer instanceof L.Polygon){ - content += L._(' (area: {measure})', { measure: measure }); - } else if (e.layer instanceof L.Polyline) { - content += L._(' (length: {measure})', { measure: measure }); - } - } - if (content) { - this.map.ui.tooltip({content: content}); - } - }, - - closeTooltip: function () { - this.map.ui.closeTooltip(); - }, - - onVertexRawClick: function (e) { - e.layer.onVertexRawClick(e); - L.DomEvent.stop(e); - e.cancel(); + drawingTooltip({ layer, type, latlng }) { + if (layer instanceof L.Marker && type != 'editable:drawing:move') { + this.map.ui.tooltip({ content: L._('Click to add a marker') }) + } + if (!(layer instanceof L.Polyline)) { + // only continue with Polylines and Polygons + return } -}); + let content + let measure + if (layer.editor._drawnLatLngs) { + // when drawing (a Polyline or Polygon) + if (!layer.editor._drawnLatLngs.length) { + // when drawing first point + if (layer instanceof L.Polygon) { + content = L._('Click to start drawing a polygon') + } else if (layer instanceof L.Polyline) { + content = L._('Click to start drawing a line') + } + } else { + const tmpLatLngs = layer.editor._drawnLatLngs.slice() + tmpLatLngs.push(latlng) + measure = layer.getMeasure(tmpLatLngs) + + if (layer.editor._drawnLatLngs.length < layer.editor.MIN_VERTEX) { + // when drawing second point + content = L._('Click to continue drawing') + } else { + // when drawing third point (or more) + content = L._('Click last point to finish shape') + } + } + } else { + // when moving an existing point + measure = layer.getMeasure() + } + if (measure) { + if (layer instanceof L.Polygon) { + content += L._(' (area: {measure})', { measure }) + } else if (layer instanceof L.Polyline) { + content += L._(' (length: {measure})', { measure }) + } + } + if (content) { + this.map.ui.tooltip({ content }) + } + }, + + closeTooltip() { + this.map.ui.closeTooltip() + }, + + onVertexRawClick(e) { + e.layer.onVertexRawClick(e) + L.DomEvent.stop(e) + e.cancel() + }, +}) diff --git a/umap/static/umap/js/umap.core.js b/umap/static/umap/js/umap.core.js index 614fce48..31705b30 100644 --- a/umap/static/umap/js/umap.core.js +++ b/umap/static/umap/js/umap.core.js @@ -1,560 +1,622 @@ /* Poor man pub/sub handler, enough for now */ -L.UmapSingleton = L.Evented.extend({}); -L.U = new L.UmapSingleton(); -L.U.Map = L.Map.extend({}); +L.UmapSingleton = L.Evented.extend({}) +L.U = new L.UmapSingleton() +L.U.Map = L.Map.extend({}) /* -* Utils -*/ -L.Util.queryString = function (name, fallback) { - var decode = function (s) { return decodeURIComponent(s.replace(/\+/g, ' ')); }; - var qs = window.location.search.slice(1).split('&'), qa = {}; - for (var i in qs) { - var key = qs[i].split('='); - if (!key) continue; - qa[decode(key[0])] = key[1] ? decode(key[1]) : 1; + * Utils + */ +L.Util.queryString = (name, fallback) => { + const decode = (s) => decodeURIComponent(s.replace(/\+/g, ' ')) + const qs = window.location.search.slice(1).split('&') + const qa = {} + for (const i in qs) { + const key = qs[i].split('=') + if (!key) continue + qa[decode(key[0])] = key[1] ? decode(key[1]) : 1 + } + return qa[name] || fallback +} + +L.Util.booleanFromQueryString = (name) => { + const value = L.Util.queryString(name) + return value === '1' || value === 'true' +} + +L.Util.setFromQueryString = (options, name) => { + const value = L.Util.queryString(name) + if (typeof value !== 'undefined') options[name] = value +} + +L.Util.setBooleanFromQueryString = (options, name) => { + const value = L.Util.queryString(name) + if (typeof value !== 'undefined') options[name] = value == '1' || value == 'true' +} +L.Util.setNullableBooleanFromQueryString = (options, name) => { + let value = L.Util.queryString(name) + if (typeof value !== 'undefined') { + if (value === 'null') value = null + else if (value === '0' || value === 'false') value = false + else value = true + options[name] = value + } +} +L.Util.escapeHTML = (s) => { + s = s ? s.toString() : '' + return s.replace(/ { + if (!r) return '' + let ii + + // detect newline format + const newline = r.includes('\r\n') ? '\r\n' : r.includes('\n') ? '\n' : '' + + // Escape tags + r = r.replace(/$1') + r = r.replace(/^## (.*)/gm, '

$1

') + r = r.replace(/^# (.*)/gm, '

$1

') + r = r.replace(/^---/gm, '
') + + // bold, italics + r = r.replace(/\*\*(.*?)\*\*/g, '$1') + r = r.replace(/\*(.*?)\*/g, '$1') + + // unordered lists + r = r.replace(/^\*\* (.*)/gm, '') + r = r.replace(/^\* (.*)/gm, '') + for (ii = 0; ii < 3; ii++) + r = r.replace(new RegExp(`${newline}' + newline + '