From 49496348d2d4e4d16822e337bba748579c17a6ab Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 23 Apr 2025 09:21:35 +0200 Subject: [PATCH 1/8] chore: remove unused L.DomUtil.createLink method --- umap/static/umap/js/umap.core.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/umap/static/umap/js/umap.core.js b/umap/static/umap/js/umap.core.js index ffd4ff4f..38441fb4 100644 --- a/umap/static/umap/js/umap.core.js +++ b/umap/static/umap/js/umap.core.js @@ -65,18 +65,6 @@ L.DomUtil.createButton = (className, container, content, callback, context) => { return el } -L.DomUtil.createLink = (className, container, content, url, target, title) => { - const el = L.DomUtil.add('a', className, container, content) - el.href = url - if (target) { - el.target = target - } - if (title) { - el.title = title - } - return el -} - L.DomUtil.createIcon = (parent, className, title, size = 16) => { return L.DomUtil.element({ tagName: 'i', From 3f5d282477b76483ce639ef31f8fc9ff1ee1b399 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 23 Apr 2025 10:14:22 +0200 Subject: [PATCH 2/8] chore: remove DomUtil and DomEvent dependency from rules.js --- umap/static/umap/js/modules/rules.js | 82 +++++++++---------- .../integration/test_conditional_rules.py | 4 +- 2 files changed, 39 insertions(+), 47 deletions(-) diff --git a/umap/static/umap/js/modules/rules.js b/umap/static/umap/js/modules/rules.js index 4ecf3724..4b7fc3a2 100644 --- a/umap/static/umap/js/modules/rules.js +++ b/umap/static/umap/js/modules/rules.js @@ -1,4 +1,4 @@ -import { DomEvent, DomUtil, stamp } from '../../vendors/leaflet/leaflet-src.esm.js' +import { stamp } from '../../vendors/leaflet/leaflet-src.esm.js' import { AutocompleteDatalist } from './autocomplete.js' import { MutatingForm } from './form/builder.js' import { translate } from './i18n.js' @@ -119,10 +119,9 @@ class Rule { 'options.smoothFactor', 'options.dashArray', ] - const container = DomUtil.create('div') const builder = new MutatingForm(this, options) - const defaultShapeProperties = DomUtil.add('div', '', container) - defaultShapeProperties.appendChild(builder.build()) + const container = document.createElement('div') + container.appendChild(builder.build()) const autocomplete = new AutocompleteDatalist(builder.helpers.condition.input) const properties = this._umap.allProperties() autocomplete.suggestions = properties @@ -140,40 +139,28 @@ class Rule { this._umap.editPanel.open({ content: container, highlight: 'settings' }) } - renderToolbox(row) { - row.classList.toggle('off', !this.active) - const toggle = DomUtil.createButtonIcon( - row, - 'icon-eye', - translate('Show/hide layer') - ) - const edit = DomUtil.createButtonIcon( - row, - 'icon-edit show-on-edit', - translate('Edit') - ) - const remove = DomUtil.createButtonIcon( - row, - 'icon-delete show-on-edit', - translate('Delete layer') - ) - DomEvent.on(edit, 'click', this.edit, this) - DomEvent.on( - remove, - 'click', - function () { - if (!confirm(translate('Are you sure you want to delete this rule?'))) return - this._delete() - this._umap.editPanel.close() - }, - this - ) - DomUtil.add('span', '', row, this.condition || translate('empty rule')) - DomUtil.createIcon(row, 'icon-drag', translate('Drag to reorder')) - row.dataset.id = stamp(this) - DomEvent.on(toggle, 'click', () => { + renderToolbox(ul) { + const template = ` +
  • + + + + ${this.condition || translate('empty rule')} + +
  • + ` + const [li, { toggle, edit, remove }] = Utils.loadTemplateWithRefs(template) + ul.appendChild(li) + li.classList.toggle('off', !this.active) + edit.addEventListener('click', () => this.edit()) + remove.addEventListener('click', () => { + if (!confirm(translate('Are you sure you want to delete this rule?'))) return + this._delete() + this._umap.editPanel.close() + }) + toggle.addEventListener('click', () => { this.active = !this.active - row.classList.toggle('off', !this.active) + li.classList.toggle('off', !this.active) this._umap.render(['rules']) }) } @@ -207,8 +194,8 @@ export default class Rules { } onReorder(src, dst, initialIndex, finalIndex) { - const moved = this.rules.find((rule) => stamp(rule) === src.dataset.id) - const reference = this.rules.find((rule) => stamp(rule) === dst.dataset.id) + const moved = this.rules.find((rule) => stamp(rule) === +src.dataset.id) + const reference = this.rules.find((rule) => stamp(rule) === +dst.dataset.id) const movedIdx = this.rules.indexOf(moved) let referenceIdx = this.rules.indexOf(reference) const minIndex = Math.min(movedIdx, referenceIdx) @@ -225,17 +212,22 @@ export default class Rules { } edit(container) { - const body = DomUtil.createFieldset(container, translate('Conditional style rules')) + const template = ` +
    + ${translate('Conditional style rules')} +
      + +
      + ` + const [body, { ul, add }] = Utils.loadTemplateWithRefs(template) if (this.rules.length) { - const ul = DomUtil.create('ul', '', body) for (const rule of this.rules) { - rule.renderToolbox(DomUtil.create('li', 'orderable', ul)) + rule.renderToolbox(ul) } - const orderable = new Orderable(ul, this.onReorder.bind(this)) } - - DomUtil.createButton('umap-add', body, translate('Add rule'), this.addRule, this) + add.addEventListener('click', () => this.addRule()) + container.appendChild(body) } addRule() { diff --git a/umap/tests/integration/test_conditional_rules.py b/umap/tests/integration/test_conditional_rules.py index d72d36bd..1edcc27d 100644 --- a/umap/tests/integration/test_conditional_rules.py +++ b/umap/tests/integration/test_conditional_rules.py @@ -281,10 +281,10 @@ def test_can_deactive_rule_from_list(live_server, page, openmap): page.get_by_role("button", name="Edit").click() page.get_by_role("button", name="Map advanced properties").click() page.get_by_text("Conditional style rules").click() - page.get_by_role("button", name="Show/hide layer").click() + page.get_by_role("button", name="Toggle rule").click() colors = getColors(markers) assert colors.count("rgb(240, 248, 255)") == 0 - page.get_by_role("button", name="Show/hide layer").click() + page.get_by_role("button", name="Toggle rule").click() colors = getColors(markers) assert colors.count("rgb(240, 248, 255)") == 3 From fad182c5f3f98b134451d0e4d372d146b10b7776 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 23 Apr 2025 10:19:19 +0200 Subject: [PATCH 3/8] fix: make rules reordering syncable, savable and undoable --- umap/static/umap/js/modules/rules.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/umap/static/umap/js/modules/rules.js b/umap/static/umap/js/modules/rules.js index 4b7fc3a2..3298ee2e 100644 --- a/umap/static/umap/js/modules/rules.js +++ b/umap/static/umap/js/modules/rules.js @@ -194,6 +194,7 @@ export default class Rules { } onReorder(src, dst, initialIndex, finalIndex) { + const oldRules = Utils.CopyJSON(this._umap.properties.rules || {}) const moved = this.rules.find((rule) => stamp(rule) === +src.dataset.id) const reference = this.rules.find((rule) => stamp(rule) === +dst.dataset.id) const movedIdx = this.rules.indexOf(moved) @@ -209,6 +210,7 @@ export default class Rules { this.rules.splice(newIdx, 0, moved) this._umap.render(['rules']) this.commit() + this._umap.sync.update('properties.rules', this._umap.properties.rules, oldRules) } edit(container) { From 67ed6d5b44c3ee082a69f52ff1d829fd83850c69 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 23 Apr 2025 10:55:39 +0200 Subject: [PATCH 4/8] feat: add a back button in rules form To go back in rules list. fix #2631 --- umap/static/umap/js/modules/rules.js | 24 ++++++++++++++++++++---- umap/static/umap/js/modules/umap.js | 2 +- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/umap/static/umap/js/modules/rules.js b/umap/static/umap/js/modules/rules.js index 4b7fc3a2..c00eae05 100644 --- a/umap/static/umap/js/modules/rules.js +++ b/umap/static/umap/js/modules/rules.js @@ -136,7 +136,21 @@ class Rule { .map((str) => `${value}${str || ''}`) } }) - this._umap.editPanel.open({ content: container, highlight: 'settings' }) + const backButton = Utils.loadTemplate(` + `) + backButton.addEventListener('click', () => + this._umap.edit().then(() => { + this._umap.editPanel.container.querySelector('details#rules').open = true + }) + ) + + this._umap.editPanel.open({ + content: container, + highlight: 'settings', + actions: [backButton], + }) } renderToolbox(ul) { @@ -213,10 +227,12 @@ export default class Rules { edit(container) { const template = ` -
      +
      ${translate('Conditional style rules')} -
        - +
        +
          + +
          ` const [body, { ul, add }] = Utils.loadTemplateWithRefs(template) diff --git a/umap/static/umap/js/modules/umap.js b/umap/static/umap/js/modules/umap.js index e7a98085..61f4e120 100644 --- a/umap/static/umap/js/modules/umap.js +++ b/umap/static/umap/js/modules/umap.js @@ -1181,7 +1181,7 @@ export default class Umap { } this._advancedActions(container) - this.editPanel.open({ + return this.editPanel.open({ content: container, className: 'dark', highlight: 'settings', From bf2e9dc175a988305f3592e0a17b7888b8da5ef2 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 23 Apr 2025 11:33:12 +0200 Subject: [PATCH 5/8] chore: remove call to DomUtil.createIcon in umap.js --- umap/static/umap/js/modules/umap.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/umap/static/umap/js/modules/umap.js b/umap/static/umap/js/modules/umap.js index e7a98085..cd7ca8f9 100644 --- a/umap/static/umap/js/modules/umap.js +++ b/umap/static/umap/js/modules/umap.js @@ -1512,12 +1512,17 @@ export default class Umap { editDatalayers() { if (!this.editEnabled) return - const container = DomUtil.create('div') - DomUtil.createTitle(container, translate('Manage layers'), 'icon-layers') - const ul = DomUtil.create('ul', '', container) + const template = ` +
          +

          ${translate('Manage layers')}

          +
            +
            + ` + const [container, { ul }] = Utils.loadTemplateWithRefs(template) this.eachDataLayerReverse((datalayer) => { - const row = DomUtil.create('li', 'orderable', ul) - DomUtil.createIcon(row, 'icon-drag', translate('Drag to reorder')) + const row = Utils.loadTemplate( + `
          • ` + ) datalayer.renderToolbox(row) const builder = new MutatingForm( datalayer, @@ -1528,6 +1533,7 @@ export default class Umap { row.appendChild(form) row.classList.toggle('off', !datalayer.isVisible()) row.dataset.id = datalayer.id + ul.appendChild(row) }) const onReorder = (src, dst, initialIndex, finalIndex) => { const movedLayer = this.datalayers[src.dataset.id] From 60ac4b35f23e08dc765b5b2ddd9f9edfb586a22a Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 23 Apr 2025 16:05:29 +0200 Subject: [PATCH 6/8] chore: remove most of DomUtil/DomEvent from browser.js --- umap/static/umap/js/modules/browser.js | 175 +++++++++--------- umap/static/umap/js/modules/data/layer.js | 27 +++ .../umap/js/modules/rendering/controls.js | 5 +- umap/tests/integration/test_browser.py | 6 +- umap/tests/integration/test_edit_map.py | 12 +- 5 files changed, 128 insertions(+), 97 deletions(-) diff --git a/umap/static/umap/js/modules/browser.js b/umap/static/umap/js/modules/browser.js index ac2fea86..5f7d14e6 100644 --- a/umap/static/umap/js/modules/browser.js +++ b/umap/static/umap/js/modules/browser.js @@ -5,6 +5,7 @@ import { translate } from './i18n.js' import * as Icon from './rendering/icon.js' import ContextMenu from './ui/contextmenu.js' import * as Utils from './utils.js' +import { SCHEMA } from './schema.js' export default class Browser { constructor(umap, leafletMap) { @@ -21,35 +22,24 @@ export default class Browser { addFeature(feature, parent) { if (feature.isFiltered()) return if (this.options.inBbox && !feature.isOnScreen(this.bounds)) return - const row = DomUtil.create('li', `${feature.getClassName()} feature`) - const zoom_to = DomUtil.createButtonIcon( - row, - 'icon-zoom', - translate('Bring feature to center') - ) - const edit = DomUtil.createButtonIcon( - row, - 'show-on-edit icon-edit', - translate('Edit this feature') - ) - const del = DomUtil.createButtonIcon( - row, - 'show-on-edit icon-delete', - translate('Delete this feature') - ) - const colorBox = DomUtil.create( - 'i', - `icon icon-16 icon-${feature.getClassName()} feature-color`, - row - ) - const title = DomUtil.create('span', 'feature-title', row) + const template = ` +
          • + + + + + +
          • + ` + const [row, { zoom, edit, remove, colorBox, label }] = + Utils.loadTemplateWithRefs(template) + label.textContent = label.title = feature.getDisplayName() || '—' const symbol = feature._getIconUrl ? Icon.formatUrl(feature._getIconUrl(), feature) : null - title.textContent = title.title = feature.getDisplayName() || '—' const bgcolor = feature.getPreviewColor() colorBox.style.backgroundColor = bgcolor - if (symbol && symbol !== U.SCHEMA.iconUrl.default) { + if (symbol && symbol !== SCHEMA.iconUrl.default) { const icon = Icon.makeElement(symbol, colorBox) Icon.setContrast(icon, colorBox, symbol, bgcolor) } else if (DomUtil.contrastedColor(colorBox, bgcolor)) { @@ -58,10 +48,10 @@ export default class Browser { const viewFeature = (e) => { feature.zoomTo({ ...e, callback: () => feature.view() }) } - DomEvent.on(zoom_to, 'click', viewFeature) - DomEvent.on(title, 'click', viewFeature) - DomEvent.on(edit, 'click', feature.edit, feature) - DomEvent.on(del, 'click', feature.del, feature) + zoom.addEventListener('click', viewFeature) + label.addEventListener('click', viewFeature) + edit.addEventListener('click', () => feature.edit()) + remove.addEventListener('click', () => feature.del()) // HOTFIX. Remove when this is released: // https://github.com/Leaflet/Leaflet/pull/9052 DomEvent.disableClickPropagation(row) @@ -75,45 +65,51 @@ export default class Browser { addDataLayer(datalayer, parent) { let className = `datalayer ${datalayer.getHidableClass()}` if (this.mode !== 'layers') className += ' show-list' - const container = DomUtil.create('div', className, parent) - const headline = DomUtil.create('h5', '', container) - container.id = this.datalayerId(datalayer) - const ul = DomUtil.create('ul', '', container) + const [container, { headline, toolbox, toggle, label }] = + Utils.loadTemplateWithRefs(` +
            +
            + + + + +
            +
              +
              + `) + datalayer.renderToolbox(toolbox) + parent.appendChild(container) + const toggleList = () => parent.classList.toggle('show-list') + toggle.addEventListener('click', toggleList) + label.addEventListener('click', toggleList) this.updateDatalayer(datalayer) } updateDatalayer(datalayer) { // Compute once, but use it for each feature later. this.bounds = this._leafletMap.getBounds() - const parent = DomUtil.get(this.datalayerId(datalayer)) + const id = this.datalayerId(datalayer) + const parent = document.getElementById(id) // Panel is not open if (!parent) return parent.classList.toggle('off', !datalayer.isVisible()) + const label = parent.querySelector('.datalayer-name') const container = parent.querySelector('ul') - const headline = parent.querySelector('h5') - const toggleList = () => parent.classList.toggle('show-list') - headline.innerHTML = '' - const toggle = DomUtil.create('i', 'icon icon-16 datalayer-toggle-list', headline) - DomEvent.on(toggle, 'click', toggleList) - datalayer.renderToolbox(headline) - const name = DomUtil.create('span', 'datalayer-name', headline) - name.textContent = name.title = datalayer.options.name - DomEvent.on(name, 'click', toggleList) container.innerHTML = '' datalayer.eachFeature((feature) => this.addFeature(feature, container)) - + datalayer.propagate(['properties.name']) const total = datalayer.count() if (!total) return const current = container.querySelectorAll('li').length const count = total === current ? total : `${current}/${total}` - const counter = DomUtil.create('span', 'datalayer-counter', headline) + const counter = parent.querySelector('.datalayer-counter') counter.textContent = `(${count})` counter.title = translate(`Features in this layer: ${count}`) } toggleBadge() { - U.Utils.toggleBadge(this.filtersTitle, this.hasFilters()) - U.Utils.toggleBadge('.umap-control-browse', this.hasFilters()) + Utils.toggleBadge(this.filtersTitle, this.hasFilters()) + Utils.toggleBadge('.umap-control-browse', this.hasFilters()) } onFormChange() { @@ -157,21 +153,51 @@ export default class Browser { open(mode) { // Force only if mode is known, otherwise keep current mode. if (mode) this.mode = mode - const container = DomUtil.create('div') + const template = ` +
              +

              ${translate('Data browser')}

              +
              + ${translate('Filters')} +
              +
              +
              + +
              +
              +
              + + + +
              +
              +
              + ` + const [ + container, + { + details, + filtersTitle, + toggle, + fitBounds, + download, + dataContainer, + formContainer, + reset, + }, + ] = Utils.loadTemplateWithRefs(template) // HOTFIX. Remove when this is released: // https://github.com/Leaflet/Leaflet/pull/9052 DomEvent.disableClickPropagation(container) + details.open = this.mode === 'filters' + toggle.addEventListener('click', () => this.toggleLayers()) + fitBounds.addEventListener('click', () => this._umap.fitDataBounds()) + download.addEventListener('click', () => this.downloadVisible(download)) + download.hidden = this._umap.getProperty('embedControl') === false - DomUtil.createTitle(container, translate('Data browser'), 'icon-layers') - this.formContainer = DomUtil.createFieldset(container, L._('Filters'), { - on: this.mode === 'filters', - className: 'filters', - icon: 'icon-filters', - }) - this.filtersTitle = container.querySelector('summary') + this.filtersTitle = filtersTitle + this.dataContainer = dataContainer + this.formContainer = formContainer this.toggleBadge() - this.addMainToolbox(container) - this.dataContainer = DomUtil.create('div', '', container) let fields = [ [ @@ -184,27 +210,19 @@ export default class Browser { builder.on('set', () => this.onFormChange()) let filtersBuilder this.formContainer.appendChild(builder.build()) - DomEvent.on(builder.form, 'reset', () => { + builder.form.addEventListener('reset', () => { window.setTimeout(builder.syncAll.bind(builder)) }) if (this._umap.properties.facetKey) { fields = this._umap.facets.build() filtersBuilder = new Form(this._umap.facets, fields) filtersBuilder.on('set', () => this.onFormChange()) - DomEvent.on(filtersBuilder.form, 'reset', () => { + filtersBuilder.form.addEventListener('reset', () => { window.setTimeout(filtersBuilder.syncAll.bind(filtersBuilder)) }) this.formContainer.appendChild(filtersBuilder.build()) } - const reset = DomUtil.createButton('flat', this.formContainer, '', () => - this.resetFilters() - ) - DomUtil.createIcon(reset, 'icon-restore') - DomUtil.element({ - tagName: 'span', - parent: reset, - textContent: translate('Reset all'), - }) + reset.addEventListener('click', () => this.resetFilters()) this._umap.panel.open({ content: container, @@ -220,21 +238,6 @@ export default class Browser { } } - addMainToolbox(container) { - const [toolbox, { toggle, fitBounds, download }] = Utils.loadTemplateWithRefs(` -
              - - - -
              - `) - container.appendChild(toolbox) - toggle.addEventListener('click', () => this.toggleLayers()) - fitBounds.addEventListener('click', () => this._umap.fitDataBounds()) - download.addEventListener('click', () => this.downloadVisible(download)) - download.hidden = this._umap.getProperty('embedControl') === false - } - downloadVisible(element) { const menu = new ContextMenu({ fixed: true }) const items = [] @@ -265,15 +268,13 @@ export default class Browser { } static backButton(umap) { - const button = DomUtil.createButtonIcon( - DomUtil.create('li', '', undefined), - 'icon-back', - translate('Back to browser') + const button = Utils.loadTemplate( + `` ) // Fixme: remove me when this is merged and released // https://github.com/Leaflet/Leaflet/pull/9052 DomEvent.disableClickPropagation(button) - DomEvent.on(button, 'click', () => umap.openBrowser()) + button.addEventListener('click', () => umap.openBrowser()) return button } } diff --git a/umap/static/umap/js/modules/data/layer.js b/umap/static/umap/js/modules/data/layer.js index 617fea1a..1de3f731 100644 --- a/umap/static/umap/js/modules/data/layer.js +++ b/umap/static/umap/js/modules/data/layer.js @@ -130,6 +130,10 @@ export class DataLayer { } render(fields, builder) { + // Propagate will remove the fields it has already + // processed + fields = this.propagate(fields) + const impacts = Utils.getImpactsFromSchema(fields) for (const impact of impacts) { @@ -153,6 +157,29 @@ export class DataLayer { } } + // This method does a targeted update of the UI, + // it whould be merged with `render`` method and the + // SCHEMA at some point + propagate(fields = []) { + const impacts = { + 'properties.name': () => { + Utils.eachElement('.datalayer-name', (el) => { + if (el.dataset.id === this.id) { + el.textContent = this.getName() + el.title = this.getName() + } + }) + }, + } + for (const [field, impact] of Object.entries(impacts)) { + if (!fields.length || fields.includes(field)) { + impact() + fields = fields.filter((item) => item !== field) + } + } + return fields + } + showAtLoad() { return this.autoLoaded() && this.showAtZoom() } diff --git a/umap/static/umap/js/modules/rendering/controls.js b/umap/static/umap/js/modules/rendering/controls.js index 6379b827..c50c1a2d 100644 --- a/umap/static/umap/js/modules/rendering/controls.js +++ b/umap/static/umap/js/modules/rendering/controls.js @@ -99,7 +99,10 @@ const BaseButton = Control.extend({ ` const [container, { button }] = Utils.loadTemplateWithRefs(template) - button.addEventListener('click', () => this.onClick()) + button.addEventListener('click', (event) => { + event.stopPropagation() + this.onClick() + }) button.addEventListener('dblclick', (event) => { event.stopPropagation() }) diff --git a/umap/tests/integration/test_browser.py b/umap/tests/integration/test_browser.py index 453d7275..558808b1 100644 --- a/umap/tests/integration/test_browser.py +++ b/umap/tests/integration/test_browser.py @@ -465,19 +465,19 @@ def test_main_toolbox_toggle_all_layers(live_server, map, page): expect(page.locator(".datalayer.off")).to_have_count(1) # Click on button - page.locator(".umap-browser [data-ref=toggle]").click() + page.locator(".umap-browser").get_by_title("Show/hide all layers").click() # Should have hidden the two other layers expect(page.locator(".datalayer.off")).to_have_count(3) expect(markers).to_have_count(0) # Click again - page.locator(".umap-browser [data-ref=toggle]").click() + page.locator(".umap-browser").get_by_title("Show/hide all layers").click() # Should shown all layers expect(page.locator(".datalayer.off")).to_have_count(0) expect(markers).to_have_count(3) # Click again - page.locator(".umap-browser [data-ref=toggle]").click() + page.locator(".umap-browser").get_by_title("Show/hide all layers").click() # Should hidden again all layers expect(page.locator(".datalayer.off")).to_have_count(3) expect(markers).to_have_count(0) diff --git a/umap/tests/integration/test_edit_map.py b/umap/tests/integration/test_edit_map.py index 02744d2e..71eaffda 100644 --- a/umap/tests/integration/test_edit_map.py +++ b/umap/tests/integration/test_edit_map.py @@ -180,9 +180,9 @@ def test_sortkey_impacts_datalayerindex(map, live_server, page): first_listed_feature = page.locator(".umap-browser .datalayer ul > li").nth(0) second_listed_feature = page.locator(".umap-browser .datalayer ul > li").nth(1) third_listed_feature = page.locator(".umap-browser .datalayer ul > li").nth(2) - assert "X Third" == first_listed_feature.text_content() - assert "Y Second" == second_listed_feature.text_content() - assert "Z First" == third_listed_feature.text_content() + assert "X Third" == first_listed_feature.text_content().strip() + assert "Y Second" == second_listed_feature.text_content().strip() + assert "Z First" == third_listed_feature.text_content().strip() # Change the default sortkey to be "key" page.get_by_role("button", name="Edit").click() @@ -201,9 +201,9 @@ def test_sortkey_impacts_datalayerindex(map, live_server, page): first_listed_feature = page.locator(".umap-browser .datalayer ul > li").nth(0) second_listed_feature = page.locator(".umap-browser .datalayer ul > li").nth(1) third_listed_feature = page.locator(".umap-browser .datalayer ul > li").nth(2) - assert "Z First" == first_listed_feature.text_content() - assert "Y Second" == second_listed_feature.text_content() - assert "X Third" == third_listed_feature.text_content() + assert "Z First" == first_listed_feature.text_content().strip() + assert "Y Second" == second_listed_feature.text_content().strip() + assert "X Third" == third_listed_feature.text_content().strip() def test_hover_tooltip_setting_should_be_persistent(live_server, map, page): From 7991d6cdbe92358d846c703d8b558ff1ef8d95b5 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 23 Apr 2025 16:50:13 +0200 Subject: [PATCH 7/8] chore: remove DomUtil.after/before --- umap/static/umap/js/modules/autocomplete.js | 15 +++++++-------- umap/static/umap/js/umap.core.js | 10 ---------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/umap/static/umap/js/modules/autocomplete.js b/umap/static/umap/js/modules/autocomplete.js index 003c82fb..ffc7cdbd 100644 --- a/umap/static/umap/js/modules/autocomplete.js +++ b/umap/static/umap/js/modules/autocomplete.js @@ -7,6 +7,7 @@ import { import { translate } from './i18n.js' import { Request, ServerRequest } from './request.js' import { escapeHTML, generateId } from './utils.js' +import * as Utils from './utils.js' export class BaseAutocomplete { constructor(parent, options) { @@ -291,10 +292,9 @@ class BaseServerAjax extends BaseAjax { export const SingleMixin = (Base) => class extends Base { initSelectedContainer() { - return DomUtil.after( - this.input, - DomUtil.element({ tagName: 'div', className: 'umap-singleresult' }) - ) + const el = Utils.loadTemplate('
              ') + this.input.parentNode.insertBefore(el, this.input.nextSibling) + return el } displaySelected(result) { @@ -322,10 +322,9 @@ export const SingleMixin = (Base) => export const MultipleMixin = (Base) => class extends Base { initSelectedContainer() { - return DomUtil.after( - this.input, - DomUtil.element({ tagName: 'ul', className: 'umap-multiresult' }) - ) + const el = Utils.loadTemplate('
                ') + this.input.parentNode.insertBefore(el, this.input.nextSibling) + return el } displaySelected(result) { diff --git a/umap/static/umap/js/umap.core.js b/umap/static/umap/js/umap.core.js index 38441fb4..695c6d85 100644 --- a/umap/static/umap/js/umap.core.js +++ b/umap/static/umap/js/umap.core.js @@ -128,16 +128,6 @@ L.DomUtil.element = ({ tagName, parent, ...attrs }) => { return el } -L.DomUtil.before = (target, el) => { - target.parentNode.insertBefore(el, target) - return el -} - -L.DomUtil.after = (target, el) => { - target.parentNode.insertBefore(el, target.nextSibling) - return el -} - // From https://gist.github.com/Accudio/b9cb16e0e3df858cef0d31e38f1fe46f // convert colour in range 0-255 to the modifier used within luminance calculation L.DomUtil.colourMod = (colour) => { From 07363fa5fe2ac18cada975ae0582ce82e6e9d639 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 23 Apr 2025 16:52:55 +0200 Subject: [PATCH 8/8] chore: remove unused DomEvent.once --- umap/static/umap/js/umap.core.js | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/umap/static/umap/js/umap.core.js b/umap/static/umap/js/umap.core.js index 695c6d85..5d653d37 100644 --- a/umap/static/umap/js/umap.core.js +++ b/umap/static/umap/js/umap.core.js @@ -192,24 +192,6 @@ L.DomUtil.contrastedColor = (el, bgcolor) => { if (bgcolor) _CACHE_CONSTRAST[bgcolor] = out return out } -L.DomEvent.once = (el, types, fn, context) => { - // cf https://github.com/Leaflet/Leaflet/pull/3528#issuecomment-134551575 - - if (typeof types === 'object') { - for (const type in types) { - L.DomEvent.once(el, type, types[type], fn) - } - return L.DomEvent - } - - const handler = L.bind(() => { - L.DomEvent.off(el, types, fn, context).off(el, types, handler, context) - }, L.DomEvent) - - // add a listener that's executed once and removed after that - return L.DomEvent.on(el, types, fn, context).on(el, types, handler, context) -} - L.LatLng.prototype.isValid = function () { return ( Number.isFinite(this.lat) &&