From 126e47eef92f911657fb9293f21b9b8b3b06f0fd Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Mon, 12 Feb 2024 14:09:23 +0100 Subject: [PATCH] feat: show last used pictograms in list This feature was planned in the initial rework of the pictogram form UI, but not yet done. Some recent discussion in the OSM French forum reactivated the need for it. cf https://forum.openstreetmap.fr/t/marker-and-marker-colors/21051 --- umap/static/umap/js/umap.forms.js | 40 ++++++++++++++-------------- umap/static/umap/js/umap.icon.js | 20 +++++++++++--- umap/tests/integration/test_picto.py | 13 +++++++-- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/umap/static/umap/js/umap.forms.js b/umap/static/umap/js/umap.forms.js index 4ee82042..0f173e5d 100644 --- a/umap/static/umap/js/umap.forms.js +++ b/umap/static/umap/js/umap.forms.js @@ -537,9 +537,13 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ this.on('define', this.onDefine) }, - onDefine: function () { + onDefine: async function () { this.buttons.innerHTML = '' this.footer.innerHTML = '' + const [{ pictogram_list }, response, error] = await this.builder.map.server.get( + this.builder.map.options.urls.pictogram_list_json + ) + if (!error) this.pictogram_list = pictogram_list this.buildTabs() const value = this.value() if (!value || L.Util.isPath(value)) this.showSymbolsTab() @@ -624,12 +628,11 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ search = L.Util.normalize(this.searchInput.value), title = pictogram.attribution ? `${pictogram.name} — © ${pictogram.attribution}` - : pictogram.name + : pictogram.name || pictogram.src if (search && L.Util.normalize(title).indexOf(search) === -1) return const className = value === this.value() ? `${baseClass} selected` : baseClass, - container = L.DomUtil.create('div', className, parent), - img = L.DomUtil.create('img', '', container) - img.src = value + container = L.DomUtil.create('div', className, parent) + U.Icon.makeIconElement(value, container) container.title = title L.DomEvent.on( container, @@ -664,6 +667,15 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ if (status) this.grid.appendChild(parent) }, + showLastUsed: function () { + if (U.Icon.LAST_USED.length) { + const items = U.Icon.LAST_USED.map((src) => ({ + src, + })) + this.addCategory(L._('Used in this map'), items) + } + }, + buildSymbolsList: function () { this.grid.innerHTML = '' const categories = {} @@ -676,6 +688,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ const sorted = Object.entries(categories).toSorted(([a], [b]) => L.Util.naturalSort(a, b) ) + this.showLastUsed() for (let [category, items] of sorted) { this.addCategory(category, items) } @@ -692,17 +705,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ this.searchInput.placeholder = L._('Search') this.grid = L.DomUtil.create('div', '', this.body) L.DomEvent.on(this.searchInput, 'input', this.buildSymbolsList, this) - if (this.pictogram_list) { - this.buildSymbolsList() - } else { - const [{ pictogram_list }, response, error] = await this.builder.map.server.get( - this.builder.map.options.urls.pictogram_list_json - ) - if (!error) { - this.pictogram_list = pictogram_list - this.buildSymbolsList() - } - } + this.buildSymbolsList() }, showCharsTab: function () { @@ -989,10 +992,7 @@ L.FormBuilder.ManageEditors = L.FormBuilder.Element.extend({ on_select: L.bind(this.onSelect, this), on_unselect: L.bind(this.onUnselect, this), } - this.autocomplete = new U.AutoComplete.Ajax.SelectMultiple( - this.parentNode, - options - ) + this.autocomplete = new U.AutoComplete.Ajax.SelectMultiple(this.parentNode, options) this._values = this.toHTML() if (this._values) for (let i = 0; i < this._values.length; i++) diff --git a/umap/static/umap/js/umap.icon.js b/umap/static/umap/js/umap.icon.js index a771108e..288ca1cf 100644 --- a/umap/static/umap/js/umap.icon.js +++ b/umap/static/umap/js/umap.icon.js @@ -1,4 +1,7 @@ U.Icon = L.DivIcon.extend({ + statics: { + LAST_USED: [], + }, initialize: function (map, options) { this.map = map const default_options = { @@ -14,11 +17,22 @@ U.Icon = L.DivIcon.extend({ } }, + _setLastUsed: function (url) { + if (L.Util.hasVar(url)) return + if (url === this.map.options.default_iconUrl) return + if (U.Icon.LAST_USED.indexOf(url) === -1) { + U.Icon.LAST_USED.push(url) + } + }, + _getIconUrl: function (name) { let url - if (this.feature && this.feature._getIconUrl(name)) + if (this.feature && this.feature._getIconUrl(name)) { url = this.feature._getIconUrl(name) - else url = this.options[`${name}Url`] + this._setLastUsed(url) + } else { + url = this.options[`${name}Url`] + } return this.formatUrl(url, this.feature) }, @@ -216,7 +230,7 @@ U.Icon.setIconContrast = function (icon, parent, src, bgcolor) { * src: the raw "icon" value, can be an URL, a path, text, emoticon, etc. * bgcolor: the background color, used for caching and in case we cannot guess the * parent background color - */ + */ if (!icon) return if (L.DomUtil.contrastedColor(parent, bgcolor)) { diff --git a/umap/tests/integration/test_picto.py b/umap/tests/integration/test_picto.py index 96048b08..66bc65c6 100644 --- a/umap/tests/integration/test_picto.py +++ b/umap/tests/integration/test_picto.py @@ -94,7 +94,7 @@ def test_can_change_picto_at_datalayer_level(map, live_server, page, pictos): expect(undefine).to_be_hidden() define.click() symbols = page.locator(".umap-pictogram-choice") - expect(symbols).to_have_count(2) + expect(symbols).to_have_count(3) search = page.locator(".umap-pictogram-body input") search.type("circle") expect(symbols).to_have_count(1) @@ -128,7 +128,7 @@ def test_can_change_picto_at_marker_level(map, live_server, page, pictos): expect(undefine).to_be_hidden() define.click() symbols = page.locator(".umap-pictogram-choice") - expect(symbols).to_have_count(2) + expect(symbols).to_have_count(3) # Include "Last used" picto search = page.locator(".umap-pictogram-body input") search.type("circle") expect(symbols).to_have_count(1) @@ -157,6 +157,10 @@ def test_can_use_remote_url_as_picto(map, live_server, page, pictos): define = page.locator(".umap-field-iconUrl .define") expect(define).to_be_visible() define.click() + expect(page.get_by_text("Used in this map")).to_be_hidden() + # Only default symbols + symbols = page.locator(".umap-pictogram-choice") + expect(symbols).to_have_count(2) url_tab = page.get_by_role("button", name="URL") input_el = page.get_by_placeholder("Add image URL") expect(input_el).to_be_hidden() @@ -177,6 +181,11 @@ def test_can_use_remote_url_as_picto(map, live_server, page, pictos): modify.click() # Should be on URL tab expect(input_el).to_be_visible() + # Symbol should be visible in symbols b + symbols_tab = page.get_by_role("button", name="Symbol") + symbols_tab.click() + expect(page.get_by_text("Used in this map")).to_be_visible() + expect(symbols).to_have_count(3) def test_can_use_char_as_picto(map, live_server, page, pictos):