picto field: better handling of default input values

We don't want to have an URL in the "char" field, and vice versa
This commit is contained in:
Yohan Boniface 2023-11-16 09:51:05 +01:00
parent c581172197
commit cdfcce297d
2 changed files with 85 additions and 65 deletions

View file

@ -525,38 +525,50 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
build: function () { build: function () {
L.FormBuilder.BlurInput.prototype.build.call(this) L.FormBuilder.BlurInput.prototype.build.call(this)
this.buttonsContainer = L.DomUtil.create('div', '') this.buttons = L.DomUtil.create('div', '', this.parentNode)
this.pictogramsContainer = L.DomUtil.create('div', 'umap-pictogram-list') this.tabs = L.DomUtil.create('div', 'pictogram-tabs', this.parentNode)
this.tabsContainer = L.DomUtil.create('div', 'pictogram-tabs') this.body = L.DomUtil.create('div', 'umap-pictogram-body', this.parentNode)
L.DomUtil.before(this.input, this.buttonsContainer) this.footer = L.DomUtil.create('div', '', this.parentNode)
L.DomUtil.before(this.input, this.tabsContainer)
L.DomUtil.before(this.input, this.pictogramsContainer)
this.udpatePreview() this.udpatePreview()
this.on('define', this.onDefine) this.on('define', this.onDefine)
}, },
onDefine: function () { onDefine: function () {
this.buttons.innerHTML = ''
this.buildTabs() this.buildTabs()
const value = this.value() const value = this.value()
if (!value || value.startsWith('/')) this.showSymbolsTab() if (!value || value.startsWith('/')) this.showSymbolsTab()
else if (value.startsWith('http')) this.showURLTab() else if (value.startsWith('http')) this.showURLTab()
else this.showCharsTab() else this.showCharsTab()
const closeButton = L.DomUtil.createButton(
'button action-button',
this.footer,
L._('Close'),
function (e) {
this.body.innerHTML = ''
this.tabs.innerHTML = ''
this.footer.innerHTML = ''
if (this.isDefault()) this.undefine(e)
else this.udpatePreview()
},
this
)
}, },
buildTabs: function () { buildTabs: function () {
const symbol = L.DomUtil.add( const symbol = L.DomUtil.add(
'button', 'button',
'flat tab-symbols', 'flat tab-symbols',
this.tabsContainer, this.tabs,
L._('Symbol') L._('Symbol')
), ),
char = L.DomUtil.add( char = L.DomUtil.add(
'button', 'button',
'flat tab-chars', 'flat tab-chars',
this.tabsContainer, this.tabs,
L._('Emoji & Character') L._('Emoji & Character')
) )
url = L.DomUtil.add('button', 'flat tab-url', this.tabsContainer, L._('URL')) url = L.DomUtil.add('button', 'flat tab-url', this.tabs, L._('URL'))
L.DomEvent.on(symbol, 'click', L.DomEvent.stop).on( L.DomEvent.on(symbol, 'click', L.DomEvent.stop).on(
symbol, symbol,
'click', 'click',
@ -572,31 +584,40 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
L.DomEvent.on(url, 'click', L.DomEvent.stop).on(url, 'click', this.showURLTab, this) L.DomEvent.on(url, 'click', L.DomEvent.stop).on(url, 'click', this.showURLTab, this)
}, },
highlightTab: function (name) { openTab: function (name) {
const els = this.tabsContainer.querySelectorAll('button') const els = this.tabs.querySelectorAll('button')
for (let el of els) { for (let el of els) {
L.DomUtil.removeClass(el, 'on') L.DomUtil.removeClass(el, 'on')
} }
let el = this.tabsContainer.querySelector(`.tab-${name}`) let el = this.tabs.querySelector(`.tab-${name}`)
L.DomUtil.addClass(el, 'on') L.DomUtil.addClass(el, 'on')
this.body.innerHTML = ''
}, },
isUrl: function () { isPath: function () {
return this.value() && this.value().indexOf('/') !== -1 const value = this.value()
return value && value.length && value.startsWith('/')
},
isRemoteUrl: function () {
const value = this.value()
return value && value.length && value.startsWith('http')
},
isImg: function () {
return this.isPath() || this.isRemoteUrl()
}, },
udpatePreview: function () { udpatePreview: function () {
if (this.isDefault()) { this.buttons.innerHTML = ''
this.buttonsContainer.innerHTML = '' if (this.isDefault()) return
return
}
if (!L.Util.hasVar(this.value())) { if (!L.Util.hasVar(this.value())) {
// Do not try to render URL with variables // Do not try to render URL with variables
if (this.isUrl()) { if (this.isImg()) {
const img = L.DomUtil.create( const img = L.DomUtil.create(
'img', 'img',
'', '',
L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer) L.DomUtil.create('div', 'umap-pictogram-choice', this.buttons)
) )
img.src = this.value() img.src = this.value()
L.DomEvent.on(img, 'click', this.showSymbolsTab, this) L.DomEvent.on(img, 'click', this.showSymbolsTab, this)
@ -604,7 +625,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
const el = L.DomUtil.create( const el = L.DomUtil.create(
'span', 'span',
'', '',
L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer) L.DomUtil.create('div', 'umap-pictogram-choice', this.buttons)
) )
el.textContent = this.value() el.textContent = this.value()
L.DomEvent.on(el, 'click', this.showSymbolsTab, this) L.DomEvent.on(el, 'click', this.showSymbolsTab, this)
@ -612,7 +633,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
} }
this.button = L.DomUtil.createButton( this.button = L.DomUtil.createButton(
'button action-button', 'button action-button',
this.buttonsContainer, this.buttons,
this.value() ? L._('Change') : L._('Add'), this.value() ? L._('Change') : L._('Add'),
this.onDefine, this.onDefine,
this this
@ -638,7 +659,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
function (e) { function (e) {
this.input.value = value this.input.value = value
this.sync() this.sync()
this.unselectAll(this.gridContainer) this.unselectAll(this.grid)
L.DomUtil.addClass(container, 'selected') L.DomUtil.addClass(container, 'selected')
}, },
this this
@ -648,9 +669,9 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
clear: function () { clear: function () {
this.input.value = '' this.input.value = ''
this.unselectAll(this.pictogramsContainer) this.unselectAll(this.body)
this.sync() this.sync()
this.pictogramsContainer.innerHTML = '' this.body.innerHTML = ''
this.udpatePreview() this.udpatePreview()
}, },
@ -662,11 +683,11 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
for (let item of items) { for (let item of items) {
status = this.addIconPreview(item, grid) || status status = this.addIconPreview(item, grid) || status
} }
if (status) this.gridContainer.appendChild(parent) if (status) this.grid.appendChild(parent)
}, },
buildSymbolsList: function () { buildSymbolsList: function () {
this.gridContainer.innerHTML = '' this.grid.innerHTML = ''
const categories = {} const categories = {}
let category let category
for (const props of this.pictogram_list) { for (const props of this.pictogram_list) {
@ -686,37 +707,13 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
return !this.value() || this.value() === this.obj.getMap().options.default_iconUrl return !this.value() || this.value() === this.obj.getMap().options.default_iconUrl
}, },
showCharsTab: function () {
// Do not show default value here, as it's not a character
// and it has not been explicitely chosen by the user.
this.highlightTab('chars')
if (this.isDefault()) this.input.value = ''
this.input.type = 'text'
this.input.placeholder = L._('Type char or paste emoji')
this.pictogramsContainer.innerHTML = ''
},
showSymbolsTab: function () { showSymbolsTab: function () {
this.highlightTab('symbols') this.openTab('symbols')
this.input.type = 'hidden' this.searchInput = L.DomUtil.create('input', '', this.body)
this.buttonsContainer.innerHTML = ''
this.searchInput = L.DomUtil.create('input', '', this.pictogramsContainer)
this.searchInput.type = 'search' this.searchInput.type = 'search'
this.searchInput.placeholder = L._('Search') this.searchInput.placeholder = L._('Search')
this.gridContainer = L.DomUtil.create('div', '', this.pictogramsContainer) this.grid = L.DomUtil.create('div', '', this.body)
L.DomEvent.on(this.searchInput, 'input', this.buildSymbolsList, this) L.DomEvent.on(this.searchInput, 'input', this.buildSymbolsList, this)
const closeButton = L.DomUtil.createButton(
'button action-button',
this.pictogramsContainer,
L._('Close'),
function (e) {
this.pictogramsContainer.innerHTML = ''
this.tabsContainer.innerHTML = ''
if (this.isDefault()) this.undefine(e)
else this.udpatePreview()
},
this
)
if (this.pictogram_list) { if (this.pictogram_list) {
this.buildSymbolsList() this.buildSymbolsList()
} else { } else {
@ -730,11 +727,34 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
} }
}, },
showCharsTab: function () {
this.openTab('chars')
const value = !this.isImg() ? this.value() : null
const input = this.buildInput(this.body, value)
input.placeholder = L._('Type char or paste emoji')
input.type = 'text'
},
showURLTab: function () { showURLTab: function () {
this.highlightTab('url') this.openTab('url')
this.input.type = 'url' const value = this.isRemoteUrl() ? this.value() : null
this.input.placeholder = L._('Add URL') const input = this.buildInput(this.body, value)
this.pictogramsContainer.innerHTML = '' input.placeholder = L._('Add image URL')
input.type = 'url'
},
buildInput: function (parent, value) {
const input = L.DomUtil.create('input', 'blur', parent)
const button = L.DomUtil.create('span', 'button blur-button', parent)
if (value) input.value = value
L.DomEvent.on(input, 'blur', () => {
// Do not clear this.input when focus-blur
// empty input
if (input.value === value) return
this.input.value = input.value
this.sync()
})
return input
}, },
unselectAll: function (container) { unselectAll: function (container) {

View file

@ -59,7 +59,7 @@ def test_can_change_picto_at_map_level(map, live_server, page, pictos):
define.click() define.click()
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-list input") search = page.locator(".umap-pictogram-body input")
search.type("star") search.type("star")
expect(symbols).to_have_count(1) expect(symbols).to_have_count(1)
symbols.click() symbols.click()
@ -93,7 +93,7 @@ def test_can_change_picto_at_datalayer_level(map, live_server, page, pictos):
define.click() define.click()
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-list input") search = page.locator(".umap-pictogram-body input")
search.type("circle") search.type("circle")
expect(symbols).to_have_count(1) expect(symbols).to_have_count(1)
symbols.click() symbols.click()
@ -127,7 +127,7 @@ def test_can_change_picto_at_marker_level(map, live_server, page, pictos):
define.click() define.click()
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-list input") search = page.locator(".umap-pictogram-body input")
search.type("circle") search.type("circle")
expect(symbols).to_have_count(1) expect(symbols).to_have_count(1)
symbols.click() symbols.click()
@ -156,7 +156,7 @@ def test_can_use_remote_url_as_picto(map, live_server, page, pictos):
expect(define).to_be_visible() expect(define).to_be_visible()
define.click() define.click()
url_tab = page.get_by_role("button", name="URL") url_tab = page.get_by_role("button", name="URL")
input_el = page.locator("input[name='iconUrl']") input_el = page.get_by_placeholder("Add image URL")
expect(input_el).to_be_hidden() expect(input_el).to_be_hidden()
expect(url_tab).to_be_visible() expect(url_tab).to_be_visible()
url_tab.click() url_tab.click()
@ -165,7 +165,7 @@ def test_can_use_remote_url_as_picto(map, live_server, page, pictos):
input_el.blur() input_el.blur()
expect(marker).to_have_attribute("src", "https://foo.bar/img.jpg") expect(marker).to_have_attribute("src", "https://foo.bar/img.jpg")
# Now close and reopen the form, it should still be the URL tab # Now close and reopen the form, it should still be the URL tab
close = page.locator("#umap-ui-container").get_by_text("Close") close = page.locator("#umap-ui-container").get_by_title("Close")
expect(close).to_be_visible() expect(close).to_be_visible()
close.click() close.click()
edit_settings.click() edit_settings.click()
@ -195,7 +195,7 @@ def test_can_use_char_as_picto(map, live_server, page, pictos):
define = page.locator(".umap-field-iconUrl .define") define = page.locator(".umap-field-iconUrl .define")
define.click() define.click()
url_tab = page.get_by_role("button", name="Emoji & Character") url_tab = page.get_by_role("button", name="Emoji & Character")
input_el = page.locator("input[name='iconUrl']") input_el = page.get_by_placeholder("Type char or paste emoji")
expect(input_el).to_be_hidden() expect(input_el).to_be_hidden()
expect(url_tab).to_be_visible() expect(url_tab).to_be_visible()
url_tab.click() url_tab.click()
@ -205,7 +205,7 @@ def test_can_use_char_as_picto(map, live_server, page, pictos):
expect(marker).to_have_count(1) expect(marker).to_have_count(1)
expect(marker).to_have_text("") expect(marker).to_have_text("")
# Now close and reopen the form, it should still be the URL tab # Now close and reopen the form, it should still be the URL tab
close = page.locator("#umap-ui-container").get_by_text("Close") close = page.locator("#umap-ui-container").get_by_title("Close")
expect(close).to_be_visible() expect(close).to_be_visible()
close.click() close.click()
edit_settings.click() edit_settings.click()