From b92695dd7fbb38ee3e0b02561910eb630d7a0f1c Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 6 Mar 2024 14:27:57 +0100 Subject: [PATCH] wip: first shot on merging data browser and features browser --- umap/static/umap/base.css | 7 + umap/static/umap/img/24-white.svg | 4 +- umap/static/umap/img/24.svg | 7 +- umap/static/umap/img/source/24-white.svg | 8 +- umap/static/umap/img/source/24.svg | 13 +- umap/static/umap/js/modules/browser.js | 74 ++++++--- umap/static/umap/js/modules/orderable.js | 84 ++++++++++ umap/static/umap/js/modules/schema.js | 5 + umap/static/umap/js/umap.controls.js | 200 ++++------------------- umap/static/umap/js/umap.core.js | 88 ---------- umap/static/umap/js/umap.forms.js | 3 - umap/static/umap/js/umap.js | 55 ++++--- umap/static/umap/js/umap.layer.js | 2 - umap/static/umap/map.css | 88 +++++----- 14 files changed, 268 insertions(+), 370 deletions(-) create mode 100644 umap/static/umap/js/modules/orderable.js diff --git a/umap/static/umap/base.css b/umap/static/umap/base.css index 119ff4ba..ccbda217 100644 --- a/umap/static/umap/base.css +++ b/umap/static/umap/base.css @@ -975,6 +975,13 @@ input:invalid { right: 0; visibility: visible; } + #umap-ui-container.condensed { + margin-top: 10px; + margin-right: 10px; + max-height: 300px; + width: 390px; + border-radius: 10px; + } } @media all and (orientation:portrait) { #umap-ui-container { diff --git a/umap/static/umap/img/24-white.svg b/umap/static/umap/img/24-white.svg index 3ee202b4..ac571991 100644 --- a/umap/static/umap/img/24-white.svg +++ b/umap/static/umap/img/24-white.svg @@ -33,7 +33,6 @@ - @@ -58,5 +57,8 @@ + + + diff --git a/umap/static/umap/img/24.svg b/umap/static/umap/img/24.svg index 6d760791..b4b8f678 100644 --- a/umap/static/umap/img/24.svg +++ b/umap/static/umap/img/24.svg @@ -12,10 +12,6 @@ 0 1 - - - - @@ -86,5 +82,8 @@ + + + diff --git a/umap/static/umap/img/source/24-white.svg b/umap/static/umap/img/source/24-white.svg index baa2be5c..149eb62e 100644 --- a/umap/static/umap/img/source/24-white.svg +++ b/umap/static/umap/img/source/24-white.svg @@ -1,8 +1,8 @@ - - + + @@ -54,7 +54,6 @@ - @@ -79,5 +78,8 @@ + + + diff --git a/umap/static/umap/img/source/24.svg b/umap/static/umap/img/source/24.svg index ab7c400e..432831c0 100644 --- a/umap/static/umap/img/source/24.svg +++ b/umap/static/umap/img/source/24.svg @@ -1,9 +1,9 @@ - - - + + + @@ -32,10 +32,6 @@ 0 1 - - - - @@ -106,5 +102,8 @@ + + + diff --git a/umap/static/umap/js/modules/browser.js b/umap/static/umap/js/modules/browser.js index 80c7f358..474183b1 100644 --- a/umap/static/umap/js/modules/browser.js +++ b/umap/static/umap/js/modules/browser.js @@ -1,10 +1,13 @@ -// Uses `L._`` from Leaflet.i18n which we cannot import as a module yet import { DomUtil, DomEvent } from '../../vendors/leaflet/leaflet-src.esm.js' +import Orderable from './orderable.js' +import {translate} from './i18n.js' export default class Browser { constructor(map) { this.map = map this.map.on('moveend', this.onMoveEnd, this) + this.map.on('edit:enabled', this.onEnableEdit, this) + this.map.on('edit:disabled', this.onDisableEdit, this) this.options = { filter: '', inBbox: false, @@ -24,9 +27,9 @@ export default class Browser { symbol = feature._getIconUrl ? U.Icon.prototype.formatUrl(feature._getIconUrl(), feature) : null - zoom_to.title = L._('Bring feature to center') - edit.title = L._('Edit this feature') - del.title = L._('Delete this feature') + zoom_to.title = translate('Bring feature to center') + edit.title = translate('Edit this feature') + del.title = translate('Delete this feature') title.textContent = feature.getDisplayName() || '—' const bgcolor = feature.getDynamicOption('color') colorBox.style.backgroundColor = bgcolor @@ -69,18 +72,20 @@ export default class Browser { } addDataLayer(datalayer, parent) { - const container = DomUtil.create('div', datalayer.getHidableClass(), parent), - headline = DomUtil.create('h5', '', container), - counter = DomUtil.create('span', 'datalayer-counter', headline) + const container = DomUtil.create( + 'div', + `orderable ${datalayer.getHidableClass()}`, + parent + ), + headline = DomUtil.create('h5', '', container) container.id = this.datalayerId(datalayer) - datalayer.renderToolbox(headline) - DomUtil.add('span', '', headline, datalayer.options.name) const ul = DomUtil.create('ul', '', container) this.updateDatalayer(datalayer) datalayer.on('datachanged', this.onDataLayerChanged, this) this.map.ui.once('panel:closed', () => { datalayer.off('datachanged', this.onDataLayerChanged, this) }) + container.dataset.id = L.stamp(datalayer) } updateDatalayer(datalayer) { @@ -90,16 +95,22 @@ export default class Browser { // Panel is not open if (!parent) return DomUtil.classIf(parent, 'off', !datalayer.isVisible()) - const container = parent.querySelector('ul'), - counter = parent.querySelector('.datalayer-counter') + const container = parent.querySelector('ul') + const headline = parent.querySelector('h5') + const toggleList = () => parent.classList.toggle('show-list') + headline.innerHTML = '' + const toggle = DomUtil.create('i', 'datalayer-toggle-list', headline) + DomEvent.on(toggle, 'click', toggleList) + datalayer.renderToolbox(headline) + const name = DomUtil.create('span', 'datalayer-name', headline) + DomEvent.on(name, 'click', toggleList) container.innerHTML = '' datalayer.eachFeature((feature) => this.addFeature(feature, container)) let total = datalayer.count(), current = container.querySelectorAll('li').length, count = total == current ? total : `${current}/${total}` - counter.textContent = count - counter.title = L._('Features in this layer: {count}', { count: count }) + name.textContent = `${datalayer.options.name} (${count})` } onFormChange() { @@ -127,19 +138,14 @@ export default class Browser { // https://github.com/Leaflet/Leaflet/pull/9052 DomEvent.disableClickPropagation(container) - const title = DomUtil.add( - 'h3', - 'umap-browse-title', - container, - this.map.getOption('name') - ) + const title = DomUtil.add('h3', 'umap-browse-title', container, translate('Browse data')) const formContainer = DomUtil.create('div', '', container) const dataContainer = DomUtil.create('div', 'umap-browse-features', container) const fields = [ - ['options.filter', { handler: 'Input', placeholder: L._('Filter') }], - ['options.inBbox', { handler: 'Switch', label: L._('Current map view') }], + ['options.filter', { handler: 'Input', placeholder: translate('Filter') }], + ['options.inBbox', { handler: 'Switch', label: translate('Current map view') }], ] const builder = new U.FormBuilder(this, fields, { makeDirty: false, @@ -150,10 +156,36 @@ export default class Browser { this.map.ui.openPanel({ data: { html: container }, actions: [this.map._aboutLink()], + className: 'condensed' }) this.map.eachBrowsableDataLayer((datalayer) => { this.addDataLayer(datalayer, dataContainer) }) + // After datalayers have been added. + const orderable = new Orderable(dataContainer, L.bind(this.onReorder, this)) + } + + onReorder(src, dst, initialIndex, finalIndex) { + const layer = this.map.datalayers[src.dataset.id], + other = this.map.datalayers[dst.dataset.id], + minIndex = Math.min(layer.getRank(), other.getRank()), + maxIndex = Math.max(layer.getRank(), other.getRank()) + if (finalIndex === 0) layer.bringToTop() + else if (finalIndex > initialIndex) layer.insertBefore(other) + else layer.insertAfter(other) + this.map.eachDataLayerReverse((datalayer) => { + if (datalayer.getRank() >= minIndex && datalayer.getRank() <= maxIndex) + datalayer.isDirty = true + }) + this.map.indexDatalayers() + } + + onEnableEdit () { + this.map.ui._panel.classList.add('dark') + } + + onDisableEdit () { + this.map.ui._panel.classList.remove('dark') } } diff --git a/umap/static/umap/js/modules/orderable.js b/umap/static/umap/js/modules/orderable.js new file mode 100644 index 00000000..76334581 --- /dev/null +++ b/umap/static/umap/js/modules/orderable.js @@ -0,0 +1,84 @@ +import { DomEvent } from '../../vendors/leaflet/leaflet-src.esm.js' + +export default class Orderable { + constructor(parent, onDrop, selector = '.orderable') { + this.parent = parent + this.onCommit = onDrop + this.src = null + this.dst = null + this.els = this.parent.querySelectorAll(selector) + for (let i = 0; i < this.els.length; i++) this.makeDraggable(this.els[i]) + } + + makeDraggable(node) { + node.draggable = true + DomEvent.on(node, 'dragstart', this.onDragStart, this) + DomEvent.on(node, 'dragenter', this.onDragEnter, this) + DomEvent.on(node, 'dragover', this.onDragOver, this) + DomEvent.on(node, 'dragleave', this.onDragLeave, this) + DomEvent.on(node, 'drop', this.onDrop, this) + DomEvent.on(node, 'dragend', this.onDragEnd, this) + } + + nodeIndex(node) { + return Array.prototype.indexOf.call(this.parent.children, node) + } + + findTarget(node) { + while (node) { + if (this.nodeIndex(node) !== -1) return node + node = node.parentNode + } + } + + onDragStart(e) { + // e.target is the source node. + const realSrc = document.elementFromPoint(e.clientX, e.clientY); + // Only allow drag from the handle + if (!realSrc.classList.contains('drag-handle')) { + e.preventDefault() + return + } + this.src = e.target + this.initialIndex = this.nodeIndex(this.src) + this.src.classList.add('ordering') + e.dataTransfer.effectAllowed = 'move' + e.dataTransfer.setData('text/html', this.src.innerHTML) + } + + onDragOver(e) { + DomEvent.stop(e) + if (e.preventDefault) e.preventDefault() // Necessary. Allows us to drop. + e.dataTransfer.dropEffect = 'move' + return false + } + + onDragEnter(e) { + DomEvent.stop(e) + // e.target is the current hover target. + const dst = this.findTarget(e.target) + if (!dst || dst === this.src) return + this.dst = dst + const targetIndex = this.nodeIndex(this.dst), + srcIndex = this.nodeIndex(this.src) + if (targetIndex > srcIndex) this.parent.insertBefore(this.dst, this.src) + else this.parent.insertBefore(this.src, this.dst) + } + + onDragLeave(e) { + // e.target is previous target element. + } + + onDrop(e) { + // e.target is current target element. + if (e.stopPropagation) e.stopPropagation() // Stops the browser from redirecting. + if (!this.dst) return + this.onCommit(this.src, this.dst, this.initialIndex, this.nodeIndex(this.src)) + return false + } + + onDragEnd(e) { + // e.target is the source node. + this.src.classList.remove('ordering') + } +} diff --git a/umap/static/umap/js/modules/schema.js b/umap/static/umap/js/modules/schema.js index aec0d450..05728a94 100644 --- a/umap/static/umap/js/modules/schema.js +++ b/umap/static/umap/js/modules/schema.js @@ -372,6 +372,11 @@ export const SCHEMA = { impacts: ['ui'], label: translate('Allow scroll wheel zoom?'), }, + captionControl: { + type: Boolean, + label: translate('Display the caption control'), + default: true, + }, searchControl: { type: Boolean, impacts: ['ui'], diff --git a/umap/static/umap/js/umap.controls.js b/umap/static/umap/js/umap.controls.js index c6e5e38c..d461c3a1 100644 --- a/umap/static/umap/js/umap.controls.js +++ b/umap/static/umap/js/umap.controls.js @@ -53,17 +53,6 @@ U.ChangeTileLayerAction = U.BaseAction.extend({ }, }) -U.ManageDatalayersAction = U.BaseAction.extend({ - options: { - className: 'dark manage-datalayers', - tooltip: L._('Manage layers'), - }, - - addHooks: function () { - this.map.manageDatalayers() - }, -}) - U.UpdateExtentAction = U.BaseAction.extend({ options: { className: 'update-map-extent dark', @@ -488,174 +477,48 @@ U.PermanentCreditsControl = L.Control.extend({ }, }) -U.DataLayersControl = L.Control.extend({ - options: { - position: 'topleft', - }, - - labels: { - zoomToLayer: L._('Zoom to layer extent'), - toggleLayer: L._('Show/hide layer'), - editLayer: L._('Edit'), - }, - +L.Control.Button = L.Control.extend({ initialize: function (map, options) { this.map = map L.Control.prototype.initialize.call(this, options) }, - _initLayout: function (map) { - const 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 - ) - - L.DomUtil.createButton( - 'umap-browse-link', - actions, - L._('Browse data'), - map.openBrowser, - map - ) - - const toggleButton = L.DomUtil.createButton( - 'umap-browse-toggle', + onAdd: function (map) { + const container = L.DomUtil.create('div', `${this.options.className} umap-control`) + const button = L.DomUtil.createButton( + '', container, - L._('See data layers') + this.options.title, + this.onClick, + this ) - L.DomEvent.on(toggleButton, 'click', L.DomEvent.stop) - - map.whenReady(function () { - this.update() - }, this) - - if (L.Browser.pointer) { - L.DomEvent.disableClickPropagation(container) - L.DomEvent.on(container, 'wheel', 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(toggleButton, 'click', L.DomEvent.stop).on( - toggleButton, - 'click', - this.expand, - this - ) - map.on('click', this.collapse, this) - } - + L.DomEvent.on(button, 'dblclick', L.DomEvent.stopPropagation) return container }, +}) - onAdd: function (map) { - if (!this._container) this._initLayout(map) - if (map.options.datalayersControl === 'expanded') this.expand() - return this._container +U.DataLayersControl = L.Control.Button.extend({ + options: { + position: 'topright', + className: 'leaflet-control-browse', + title: L._('Show datalayers'), }, - onRemove: function (map) { - this.collapse() + onClick: function () { + this.map.openBrowser() + }, +}) + +U.CaptionControl = L.Control.Button.extend({ + options: { + position: 'topright', + className: 'leaflet-control-caption', + title: L._('About'), }, - 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) { - 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: function () { - const datalayer = this.map.createDataLayer({}) - datalayer.edit() - }, - - openPanel: function () { - if (!this.map.editEnabled) return - const container = L.DomUtil.create('ul', 'umap-browse-datalayers') - const title = L.DomUtil.create('h3', '', container) - title.textContent = L._('Manage layers') - this.map.eachDataLayerReverse(function (datalayer) { - this.addDataLayer(container, datalayer, true) - }, this) - const orderable = new U.Orderable(container) - orderable.on( - 'drop', - function (e) { - const layer = this.map.datalayers[e.src.dataset.id], - other = this.map.datalayers[e.dst.dataset.id], - minIndex = Math.min(layer.getRank(), other.getRank()), - maxIndex = Math.max(layer.getRank(), other.getRank()) - if (e.finalIndex === 0) layer.bringToTop() - else if (e.finalIndex > e.initialIndex) layer.insertBefore(other) - else layer.insertAfter(other) - this.map.eachDataLayerReverse((datalayer) => { - if (datalayer.getRank() >= minIndex && datalayer.getRank() <= maxIndex) - datalayer.isDirty = true - }) - this.map.indexDatalayers() - }, - this - ) - - const bar = L.DomUtil.create('div', 'button-bar', container) - L.DomUtil.createButton( - 'show-on-edit block add-datalayer button', - bar, - L._('Add a layer'), - this.newDataLayer, - this - ) - - this.map.ui.openPanel({ data: { html: container }, className: 'dark' }) + onClick: function () { + if (this.map.editEnabled) this.map.editCaption() + else this.map.displayCaption() }, }) @@ -667,6 +530,11 @@ U.DataLayer.include({ }, renderToolbox: function (container) { + L.DomUtil.element( + 'i', + { className: 'drag-handle', title: L._('Drag to reorder') }, + container + ) const 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), @@ -698,7 +566,6 @@ U.DataLayer.include({ L.DomEvent.on(zoomTo, 'click', this.zoomTo, this) L.DomUtil.addClass(container, this.getHidableClass()) L.DomUtil.classIf(container, 'off', !this.isVisible()) - container.dataset.id = L.stamp(this) }, getHidableElements: function () { @@ -748,7 +615,6 @@ const ControlsMixin = { 'locate', 'measure', 'editinosm', - 'datalayers', 'star', 'tilelayers', ], diff --git a/umap/static/umap/js/umap.core.js b/umap/static/umap/js/umap.core.js index 2c8da683..474287dd 100644 --- a/umap/static/umap/js/umap.core.js +++ b/umap/static/umap/js/umap.core.js @@ -531,94 +531,6 @@ U.Help = L.Class.extend({ ), }) -U.Orderable = L.Evented.extend({ - options: { - selector: 'li', - color: '#374E75', - }, - - initialize: function (parent, options) { - L.Util.setOptions(this, options) - this.parent = parent - this.src = null - this.dst = null - this.els = this.parent.querySelectorAll(this.options.selector) - for (let i = 0; i < this.els.length; i++) this.makeDraggable(this.els[i]) - }, - - makeDraggable: function (node) { - node.draggable = true - L.DomEvent.on(node, 'dragstart', this.onDragStart, this) - L.DomEvent.on(node, 'dragenter', this.onDragEnter, this) - L.DomEvent.on(node, 'dragover', this.onDragOver, this) - L.DomEvent.on(node, 'dragleave', this.onDragLeave, this) - L.DomEvent.on(node, 'drop', this.onDrop, this) - L.DomEvent.on(node, 'dragend', this.onDragEnd, this) - }, - - nodeIndex: function (node) { - return Array.prototype.indexOf.call(this.parent.children, node) - }, - - findTarget: function (node) { - while (node) { - if (this.nodeIndex(node) !== -1) return node - node = node.parentNode - } - }, - - onDragStart: function (e) { - // e.target is the source node. - this.src = e.target - this.initialIndex = this.nodeIndex(this.src) - this.srcBackgroundColor = this.src.style.backgroundColor - this.src.style.backgroundColor = this.options.color - e.dataTransfer.effectAllowed = 'move' - e.dataTransfer.setData('text/html', this.src.innerHTML) - }, - - onDragOver: function (e) { - L.DomEvent.stop(e) - if (e.preventDefault) e.preventDefault() // Necessary. Allows us to drop. - e.dataTransfer.dropEffect = 'move' - return false - }, - - onDragEnter: function (e) { - L.DomEvent.stop(e) - // e.target is the current hover target. - const dst = this.findTarget(e.target) - if (!dst || dst === this.src) return - this.dst = dst - const targetIndex = this.nodeIndex(this.dst), - srcIndex = this.nodeIndex(this.src) - if (targetIndex > srcIndex) this.parent.insertBefore(this.dst, this.src) - else this.parent.insertBefore(this.src, this.dst) - }, - - onDragLeave: function (e) { - // e.target is previous target element. - }, - - onDrop: function (e) { - // e.target is current target element. - if (e.stopPropagation) e.stopPropagation() // Stops the browser from redirecting. - if (!this.dst) return - this.fire('drop', { - src: this.src, - initialIndex: this.initialIndex, - finalIndex: this.nodeIndex(this.src), - dst: this.dst, - }) - return false - }, - - onDragEnd: function (e) { - // e.target is the source node. - this.src.style.backgroundColor = this.srcBackgroundColor - }, -}) - L.LatLng.prototype.isValid = function () { return ( isFinite(this.lat) && diff --git a/umap/static/umap/js/umap.forms.js b/umap/static/umap/js/umap.forms.js index 624cb8a2..acd10c61 100644 --- a/umap/static/umap/js/umap.forms.js +++ b/umap/static/umap/js/umap.forms.js @@ -1009,9 +1009,6 @@ U.FormBuilder = L.FormBuilder.extend({ case 'iconUrl': schema.handler = 'IconUrl' break - case 'datalayersControl': - schema.handler = 'DataLayersControl' - break case 'licence': schema.handler = 'LicenceChooser' break diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js index 132b773e..5159e6d0 100644 --- a/umap/static/umap/js/umap.js +++ b/umap/static/umap/js/umap.js @@ -140,6 +140,9 @@ U.Map = L.Map.extend({ } delete this.options.displayDataBrowserOnLoad } + if (this.options.datalayersControl === 'expanded') { + this.options.onLoadPanel = 'databrowser' + } this.ui.on( 'panel:closed', @@ -302,7 +305,7 @@ U.Map = L.Map.extend({ // Specific case for datalayersControl // which accepts "expanded" value, on top of true/false/null if (L.Util.queryString('datalayersControl') === 'expanded') { - L.Util.setFromQueryString(options, 'datalayersControl') + options.datalayersControl = 'expanded' } }, @@ -326,7 +329,6 @@ U.Map = L.Map.extend({ const editActions = [ U.ImportAction, U.EditPropertiesAction, - U.ManageDatalayersAction, U.ChangeTileLayerAction, U.UpdateExtentAction, U.UpdatePermsAction, @@ -338,6 +340,7 @@ U.Map = L.Map.extend({ zoomOutTitle: L._('Zoom out'), }) this._controls.datalayers = new U.DataLayersControl(this) + this._controls.caption = new U.CaptionControl(this) this._controls.locate = new U.Locate(this, { strings: { title: L._('Center map on your location'), @@ -427,6 +430,8 @@ U.Map = L.Map.extend({ L.DomUtil.addClass(control._container, 'display-on-more') else L.DomUtil.removeClass(control._container, 'display-on-more') } + if (this.getOption('datalayersControl')) this._controls.datalayers.addTo(this) + if (this.getOption('captionControl')) this._controls.caption.addTo(this) if (this.getOption('permanentCredit')) this._controls.permanentCredit.addTo(this) if (this.getOption('moreControl')) this._controls.more.addTo(this) if (this.getOption('scaleControl')) this._controls.scale.addTo(this) @@ -460,7 +465,6 @@ U.Map = L.Map.extend({ if (!pane.dataset || !pane.dataset.id) continue this.datalayers_index.push(this.datalayers[pane.dataset.id]) } - this.updateDatalayersControl() }, ensurePanesOrder: function () { @@ -489,10 +493,6 @@ U.Map = L.Map.extend({ return this }, - updateDatalayersControl: function () { - if (this._controls.datalayers) this._controls.datalayers.update() - }, - backupOptions: function () { this._backupOptions = L.extend({}, this.options) this._backupOptions.tilelayer = L.extend({}, this.options.tilelayer) @@ -951,7 +951,6 @@ U.Map = L.Map.extend({ }) this.ensurePanesOrder() this.dirty_datalayers = [] - this.updateDatalayersControl() this.initTileLayers() this.isDirty = false }, @@ -1157,6 +1156,7 @@ U.Map = L.Map.extend({ UIFields.push(`options.${this.HIDDABLE_CONTROLS[i]}Control`) } UIFields = UIFields.concat([ + 'options.datalayersControl', 'options.moreControl', 'options.scrollWheelZoom', 'options.miniMap', @@ -1459,19 +1459,6 @@ U.Map = L.Map.extend({ slideshow.appendChild(slideshowBuilder.build()) }, - _editCredits: function (container) { - const credits = L.DomUtil.createFieldset(container, L._('Credits')) - const creditsFields = [ - 'options.licence', - 'options.shortCredit', - 'options.longCredit', - 'options.permanentCredit', - 'options.permanentCreditBackground', - ] - const creditsBuilder = new U.FormBuilder(this, creditsFields) - credits.appendChild(creditsBuilder.build()) - }, - _advancedActions: function (container) { const advancedActions = L.DomUtil.createFieldset(container, L._('Advanced actions')) const advancedButtons = L.DomUtil.create('div', 'button-bar half', advancedActions) @@ -1514,18 +1501,39 @@ U.Map = L.Map.extend({ ) }, - edit: function () { + editCaption: function () { if (!this.editEnabled) return if (this.options.editMode !== 'advanced') return const container = L.DomUtil.create('div', 'umap-edit-container'), metadataFields = ['options.name', 'options.description'], title = L.DomUtil.create('h3', '', container) - title.textContent = L._('Edit map properties') + title.textContent = L._('Edit map details') const builder = new U.FormBuilder(this, metadataFields, { className: 'map-metadata', }) const form = builder.build() container.appendChild(form) + + const credits = L.DomUtil.createFieldset(container, L._('Credits')) + const creditsFields = [ + 'options.licence', + 'options.shortCredit', + 'options.longCredit', + 'options.permanentCredit', + 'options.permanentCreditBackground', + ] + const creditsBuilder = new U.FormBuilder(this, creditsFields) + credits.appendChild(creditsBuilder.build()) + this.ui.openPanel({ data: { html: container }, className: 'dark' }) + + }, + + edit: function () { + if (!this.editEnabled) return + if (this.options.editMode !== 'advanced') return + const container = L.DomUtil.create('div', 'umap-edit-container') + title = L.DomUtil.create('h3', '', container) + title.textContent = L._('Edit map properties') this._editControls(container) this._editShapeProperties(container) this._editDefaultProperties(container) @@ -1534,7 +1542,6 @@ U.Map = L.Map.extend({ this._editOverlay(container) this._editBounds(container) this._editSlideshow(container) - this._editCredits(container) this._advancedActions(container) this.ui.openPanel({ data: { html: container }, className: 'dark' }) diff --git a/umap/static/umap/js/umap.layer.js b/umap/static/umap/js/umap.layer.js index 21ae6189..56d36383 100644 --- a/umap/static/umap/js/umap.layer.js +++ b/umap/static/umap/js/umap.layer.js @@ -845,7 +845,6 @@ U.DataLayer = L.Evented.extend({ if (L.Util.indexOf(this.map.datalayers_index, this) === -1) this.map.datalayers_index.push(this) } - this.map.updateDatalayersControl() }, _dataUrl: function () { @@ -1153,7 +1152,6 @@ U.DataLayer = L.Evented.extend({ delete this.map.datalayers[L.stamp(this)] this.map.datalayers_index.splice(this.getRank(), 1) this.parentPane.removeChild(this.pane) - this.map.updateDatalayersControl() this.fire('erase') this._leaflet_events_bk = this._leaflet_events this.map.off('moveend', this.onMoveEnd, this) diff --git a/umap/static/umap/map.css b/umap/static/umap/map.css index f6a643a6..b74f89b0 100644 --- a/umap/static/umap/map.css +++ b/umap/static/umap/map.css @@ -841,23 +841,21 @@ ul.photon-autocomplete { /* Datalayers Control */ /* ********************************* */ -.leaflet-control-browse .umap-browse-toggle { +.leaflet-control-caption [type="button"], +.leaflet-control-browse [type="button"] { background-image: url('./img/24.svg'); - width: 36px; - height: 36px; - background-position: -36px -72px; + width: 40px; + height: 40px; + background-position: -34px -70px; background-size: 180px; } -.leaflet-control-browse .umap-browse-actions { - background-color: #fff; - padding: 10px; - display: none; - line-height: 24px; - border-radius: 2px; +.leaflet-control-caption [type="button"] { + background-position: -70px -70px; } -.leaflet-control-browse .umap-browse-datalayers { - max-height: 15em; - overflow-y: auto; +.umap-edit-enabled .leaflet-control-caption [type="button"], +.umap-edit-enabled .leaflet-control-browse [type="button"] { + background-image: url('./img/24-white.svg'); + background-color: var(--color-darkGray); } .search-result-tools i, .leaflet-inplace-toolbar a, @@ -876,11 +874,20 @@ ul.photon-autocomplete { .dark .umap-browse-datalayers i { background-image: url('./img/16-white.svg'); } -.umap-browse-datalayers li[draggable] .drag-handle { - float: right; +.umap-browse-features ul { + display: none; +} +.show-list ul { + display: initial; +} +[draggable] .drag-handle { + display: none; +} +.umap-edit-enabled [draggable] .drag-handle { background-position: -72px -72px; margin-right: 5px; cursor: move; + display: initial; } .leaflet-inplace-toolbar a { background-image: url('./img/16-white.svg'); @@ -892,9 +899,6 @@ ul.photon-autocomplete { .leaflet-inplace-toolbar a:hover { background-color: #353c3e!important; } -.leaflet-control-browse .umap-browse-datalayers .off i { - cursor: inherit; -} .layer-toggle { background-position: -49px -31px; } @@ -958,8 +962,7 @@ ul.photon-autocomplete { .umap-extract-shape-from-multi{ background-position: -119px 2px; } -.umap-browse-features .feature-title, -.leaflet-control-browse .umap-browse-actions .layer-title { +.umap-browse-features .feature-title { width: inherit; cursor: inherit; padding-left: 6px; @@ -968,32 +971,7 @@ ul.photon-autocomplete { font-size: 12px; cursor: pointer; } -.leaflet-control-browse .umap-browse-actions .off .layer-title { - color: rgb(179, 179, 179); -} -.leaflet-control-browse.expanded > a, -.leaflet-control-browse.expanded > button { - display: none; -} -.leaflet-control-browse.expanded .umap-browse-actions { - display: block; -} -.leaflet-control-browse .umap-browse-link { - background-image: none; - background-color: rgb(68, 68, 68); - color: white; - display: block; - height: 24px; - line-height: 24px; - margin-top: 14px; - padding: 0 5px; - text-align: right; - min-width: 160px; - width: 100%; - border-radius: 2px; -} -a.add-datalayer:before, -.leaflet-control-browse .umap-browse-link:before { +a.add-datalayer:before { background-image: url('./img/16.svg'); background-repeat: no-repeat; background-position: -45px -96px; @@ -1006,8 +984,7 @@ a.add-datalayer:before, a.add-datalayer:before { background-position: -20px -20px; } -a.add-datalayer:hover, -.leaflet-control-browse .umap-browse-link:hover { +a.add-datalayer:hover { background-color: rgb(99, 99, 99); } .umap-browse-data .off .feature { @@ -1031,9 +1008,13 @@ a.add-datalayer:hover, padding-left: 5px; height: 30px; line-height: 30px; - background-color: #eeeee0; + background-color: var(--color-lightGray); color: #666; } +.dark .umap-browse-features h5 { + background-color: initial; + color: white; +} .umap-browse-features h5 span { margin-left: 10px; } @@ -1095,9 +1076,16 @@ a.add-datalayer:hover, font-size: 0.9em; margin-bottom: 14px; } -.datalayer-counter { +.datalayer-toggle-list { float: right; margin-right: 5px; + background-position: -145px -70px; +} +.show-list .datalayer-toggle-list { + background-position: -145px -45px; +} +.datalayer-name { + cursor: pointer; }