Merge pull request #1595 from umap-project/last-used-icons

feat: show last used pictograms in a separate tab
This commit is contained in:
Yohan Boniface 2024-02-15 11:02:03 +01:00 committed by GitHub
commit a3d1655041
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 90 additions and 34 deletions

View file

@ -537,12 +537,17 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
this.on('define', this.onDefine) this.on('define', this.onDefine)
}, },
onDefine: function () { onDefine: async function () {
this.buttons.innerHTML = '' this.buttons.innerHTML = ''
this.footer.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() this.buildTabs()
const value = this.value() 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 if (L.Util.isRemoteUrl(value) || L.Util.isDataImage(value)) this.showURLTab()
else this.showCharsTab() else this.showCharsTab()
const closeButton = L.DomUtil.createButton( const closeButton = L.DomUtil.createButton(
@ -562,6 +567,20 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
buildTabs: function () { buildTabs: function () {
this.tabs.innerHTML = '' 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( const symbol = L.DomUtil.add(
'button', 'button',
'flat tab-symbols', 'flat tab-symbols',
@ -624,12 +643,11 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
search = L.Util.normalize(this.searchInput.value), search = L.Util.normalize(this.searchInput.value),
title = pictogram.attribution title = pictogram.attribution
? `${pictogram.name} — © ${pictogram.attribution}` ? `${pictogram.name} — © ${pictogram.attribution}`
: pictogram.name : pictogram.name || pictogram.src
if (search && L.Util.normalize(title).indexOf(search) === -1) return if (search && L.Util.normalize(title).indexOf(search) === -1) return
const className = value === this.value() ? `${baseClass} selected` : baseClass, const className = value === this.value() ? `${baseClass} selected` : baseClass,
container = L.DomUtil.create('div', className, parent), container = L.DomUtil.create('div', className, parent)
img = L.DomUtil.create('img', '', container) U.Icon.makeIconElement(value, container)
img.src = value
container.title = title container.title = title
L.DomEvent.on( L.DomEvent.on(
container, container,
@ -653,10 +671,10 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
this.updatePreview() this.updatePreview()
}, },
addCategory: function (category, items) { addCategory: function (items, name) {
const parent = L.DomUtil.create('div', 'umap-pictogram-category'), 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) grid = L.DomUtil.create('div', 'umap-pictogram-grid', parent)
if (name) L.DomUtil.add('h6', '', parent, name)
let status = false let status = false
for (let item of items) { for (let item of items) {
status = this.addIconPreview(item, grid) || status 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]) => const sorted = Object.entries(categories).toSorted(([a], [b]) =>
L.Util.naturalSort(a, b) L.Util.naturalSort(a, b)
) )
for (let [category, items] of sorted) { for (let [name, items] of sorted) {
this.addCategory(category, items) this.addCategory(items, name)
} }
}, },
buildRecentList: function () {
this.grid.innerHTML = ''
const items = U.Icon.RECENT.map((src) => ({
src,
}))
this.addCategory(items)
},
isDefault: function () { isDefault: function () {
return !this.value() || this.value() === U.DEFAULT_ICON_URL return !this.value() || this.value() === U.DEFAULT_ICON_URL
}, },
showSymbolsTab: async function () { addGrid: function (onSearch) {
this.openTab('symbols')
this.searchInput = L.DomUtil.create('input', '', this.body) this.searchInput = L.DomUtil.create('input', '', this.body)
this.searchInput.type = 'search' this.searchInput.type = 'search'
this.searchInput.placeholder = L._('Search') this.searchInput.placeholder = L._('Search')
this.grid = L.DomUtil.create('div', '', this.body) this.grid = L.DomUtil.create('div', '', this.body)
L.DomEvent.on(this.searchInput, 'input', this.buildSymbolsList, this) L.DomEvent.on(this.searchInput, 'input', onSearch, this)
if (this.pictogram_list) { },
this.buildSymbolsList()
} else { showRecentTab: function () {
const [{ pictogram_list }, response, error] = await this.builder.map.server.get( if (!U.Icon.RECENT.length) return
this.builder.map.options.urls.pictogram_list_json this.openTab('recent')
) this.addGrid(this.buildRecentList)
if (!error) { this.buildRecentList()
this.pictogram_list = pictogram_list },
this.buildSymbolsList()
} showSymbolsTab: function () {
} this.openTab('symbols')
this.addGrid(this.buildSymbolsList)
this.buildSymbolsList()
}, },
showCharsTab: function () { showCharsTab: function () {
@ -989,10 +1016,7 @@ L.FormBuilder.ManageEditors = L.FormBuilder.Element.extend({
on_select: L.bind(this.onSelect, this), on_select: L.bind(this.onSelect, this),
on_unselect: L.bind(this.onUnselect, this), on_unselect: L.bind(this.onUnselect, this),
} }
this.autocomplete = new U.AutoComplete.Ajax.SelectMultiple( this.autocomplete = new U.AutoComplete.Ajax.SelectMultiple(this.parentNode, options)
this.parentNode,
options
)
this._values = this.toHTML() this._values = this.toHTML()
if (this._values) if (this._values)
for (let i = 0; i < this._values.length; i++) for (let i = 0; i < this._values.length; i++)

View file

@ -1,4 +1,7 @@
U.Icon = L.DivIcon.extend({ U.Icon = L.DivIcon.extend({
statics: {
RECENT: [],
},
initialize: function (map, options) { initialize: function (map, options) {
this.map = map this.map = map
const default_options = { 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) { _getIconUrl: function (name) {
let url let url
if (this.feature && this.feature._getIconUrl(name)) if (this.feature && this.feature._getIconUrl(name)) {
url = 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) 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. * 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 * bgcolor: the background color, used for caching and in case we cannot guess the
* parent background color * parent background color
*/ */
if (!icon) return if (!icon) return
if (L.DomUtil.contrastedColor(parent, bgcolor)) { if (L.DomUtil.contrastedColor(parent, bgcolor)) {

View file

@ -58,6 +58,8 @@ def test_can_change_picto_at_map_level(map, live_server, page, pictos):
expect(define).to_be_visible() expect(define).to_be_visible()
expect(undefine).to_be_hidden() expect(undefine).to_be_hidden()
define.click() 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") symbols = page.locator(".umap-pictogram-choice")
expect(symbols).to_have_count(2) expect(symbols).to_have_count(2)
search = page.locator(".umap-pictogram-body input") 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(define).to_be_visible()
expect(undefine).to_be_hidden() expect(undefine).to_be_hidden()
define.click() define.click()
# Map has an icon defined, so it shold open on Recent tab
symbols = page.locator(".umap-pictogram-choice") 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) expect(symbols).to_have_count(2)
search = page.locator(".umap-pictogram-body input") search = page.locator(".umap-pictogram-body input")
search.type("circle") 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(define).to_be_visible()
expect(undefine).to_be_hidden() expect(undefine).to_be_hidden()
define.click() define.click()
# Map has an icon defined, so it shold open on Recent tab
symbols = page.locator(".umap-pictogram-choice") 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) expect(symbols).to_have_count(2)
search = page.locator(".umap-pictogram-body input") search = page.locator(".umap-pictogram-body input")
search.type("circle") 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") modify = page.locator(".umap-field-iconUrl").get_by_text("Change")
expect(modify).to_be_visible() expect(modify).to_be_visible()
modify.click() modify.click()
# Should be on URL tab # Should be on Recent 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)
def test_can_use_char_as_picto(map, live_server, page, pictos): 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() expect(preview).to_be_visible()
preview.click() preview.click()
# Should be on URL tab # 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)