diff --git a/umap/static/umap/js/umap.forms.js b/umap/static/umap/js/umap.forms.js index 4ee82042..30d73020 100644 --- a/umap/static/umap/js/umap.forms.js +++ b/umap/static/umap/js/umap.forms.js @@ -537,12 +537,17 @@ 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() + if (U.Icon.RECENT.length) this.showRecentTab() + else if (!value || L.Util.isPath(value)) this.showSymbolsTab() else if (L.Util.isRemoteUrl(value) || L.Util.isDataImage(value)) this.showURLTab() else this.showCharsTab() const closeButton = L.DomUtil.createButton( @@ -562,6 +567,20 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ buildTabs: function () { this.tabs.innerHTML = '' + if (U.Icon.RECENT.length) { + const recent = L.DomUtil.add( + 'button', + 'flat tab-recent', + this.tabs, + L._('Recent') + ) + L.DomEvent.on(recent, 'click', L.DomEvent.stop).on( + recent, + 'click', + this.showRecentTab, + this + ) + } const symbol = L.DomUtil.add( 'button', 'flat tab-symbols', @@ -624,12 +643,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, @@ -653,10 +671,10 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ this.updatePreview() }, - addCategory: function (category, items) { + addCategory: function (items, name) { const parent = L.DomUtil.create('div', 'umap-pictogram-category'), - title = L.DomUtil.add('h6', '', parent, category), grid = L.DomUtil.create('div', 'umap-pictogram-grid', parent) + if (name) L.DomUtil.add('h6', '', parent, name) let status = false for (let item of items) { status = this.addIconPreview(item, grid) || status @@ -676,33 +694,42 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ const sorted = Object.entries(categories).toSorted(([a], [b]) => L.Util.naturalSort(a, b) ) - for (let [category, items] of sorted) { - this.addCategory(category, items) + for (let [name, items] of sorted) { + this.addCategory(items, name) } }, + buildRecentList: function () { + this.grid.innerHTML = '' + const items = U.Icon.RECENT.map((src) => ({ + src, + })) + this.addCategory(items) + }, + isDefault: function () { return !this.value() || this.value() === U.DEFAULT_ICON_URL }, - showSymbolsTab: async function () { - this.openTab('symbols') + addGrid: function (onSearch) { this.searchInput = L.DomUtil.create('input', '', this.body) this.searchInput.type = 'search' 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() - } - } + L.DomEvent.on(this.searchInput, 'input', onSearch, this) + }, + + showRecentTab: function () { + if (!U.Icon.RECENT.length) return + this.openTab('recent') + this.addGrid(this.buildRecentList) + this.buildRecentList() + }, + + showSymbolsTab: function () { + this.openTab('symbols') + this.addGrid(this.buildSymbolsList) + this.buildSymbolsList() }, showCharsTab: function () { @@ -989,10 +1016,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..5a0189b3 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: { + RECENT: [], + }, initialize: function (map, options) { this.map = map const default_options = { @@ -14,11 +17,22 @@ U.Icon = L.DivIcon.extend({ } }, + _setRecent: function (url) { + if (L.Util.hasVar(url)) return + if (url === U.DEFAULT_ICON_URL) return + if (U.Icon.RECENT.indexOf(url) === -1) { + U.Icon.RECENT.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._setRecent(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..a44e5a02 100644 --- a/umap/tests/integration/test_picto.py +++ b/umap/tests/integration/test_picto.py @@ -58,6 +58,8 @@ def test_can_change_picto_at_map_level(map, live_server, page, pictos): expect(define).to_be_visible() expect(undefine).to_be_hidden() define.click() + # No picto defined yet, so recent should not be visible + expect(page.get_by_text("Recent")).to_be_hidden() symbols = page.locator(".umap-pictogram-choice") expect(symbols).to_have_count(2) search = page.locator(".umap-pictogram-body input") @@ -93,7 +95,13 @@ def test_can_change_picto_at_datalayer_level(map, live_server, page, pictos): expect(define).to_be_visible() expect(undefine).to_be_hidden() define.click() + # Map has an icon defined, so it shold open on Recent tab symbols = page.locator(".umap-pictogram-choice") + expect(page.get_by_text("Recent")).to_be_visible() + expect(symbols).to_have_count(1) + symbol_tab = page.get_by_role("button", name="Symbol") + expect(symbol_tab).to_be_visible() + symbol_tab.click() expect(symbols).to_have_count(2) search = page.locator(".umap-pictogram-body input") search.type("circle") @@ -127,7 +135,13 @@ def test_can_change_picto_at_marker_level(map, live_server, page, pictos): expect(define).to_be_visible() expect(undefine).to_be_hidden() define.click() + # Map has an icon defined, so it shold open on Recent tab symbols = page.locator(".umap-pictogram-choice") + expect(page.get_by_text("Recent")).to_be_visible() + expect(symbols).to_have_count(1) + symbol_tab = page.get_by_role("button", name="Symbol") + expect(symbol_tab).to_be_visible() + symbol_tab.click() expect(symbols).to_have_count(2) search = page.locator(".umap-pictogram-body input") search.type("circle") @@ -175,8 +189,10 @@ def test_can_use_remote_url_as_picto(map, live_server, page, pictos): modify = page.locator(".umap-field-iconUrl").get_by_text("Change") expect(modify).to_be_visible() modify.click() - # Should be on URL tab - expect(input_el).to_be_visible() + # Should be on Recent tab + symbols = page.locator(".umap-pictogram-choice") + expect(page.get_by_text("Recent")).to_be_visible() + expect(symbols).to_have_count(1) def test_can_use_char_as_picto(map, live_server, page, pictos): @@ -216,4 +232,6 @@ def test_can_use_char_as_picto(map, live_server, page, pictos): expect(preview).to_be_visible() preview.click() # Should be on URL tab - expect(input_el).to_be_visible() + symbols = page.locator(".umap-pictogram-choice") + expect(page.get_by_text("Recent")).to_be_visible() + expect(symbols).to_have_count(1)