diff --git a/umap/static/umap/js/umap.forms.js b/umap/static/umap/js/umap.forms.js index f856f99f..73802d15 100644 --- a/umap/static/umap/js/umap.forms.js +++ b/umap/static/umap/js/umap.forms.js @@ -525,38 +525,50 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ build: function () { L.FormBuilder.BlurInput.prototype.build.call(this) - this.buttonsContainer = L.DomUtil.create('div', '') - this.pictogramsContainer = L.DomUtil.create('div', 'umap-pictogram-list') - this.tabsContainer = L.DomUtil.create('div', 'pictogram-tabs') - L.DomUtil.before(this.input, this.buttonsContainer) - L.DomUtil.before(this.input, this.tabsContainer) - L.DomUtil.before(this.input, this.pictogramsContainer) + this.buttons = L.DomUtil.create('div', '', this.parentNode) + this.tabs = L.DomUtil.create('div', 'pictogram-tabs', this.parentNode) + this.body = L.DomUtil.create('div', 'umap-pictogram-body', this.parentNode) + this.footer = L.DomUtil.create('div', '', this.parentNode) this.udpatePreview() this.on('define', this.onDefine) }, onDefine: function () { + this.buttons.innerHTML = '' this.buildTabs() const value = this.value() if (!value || value.startsWith('/')) this.showSymbolsTab() else if (value.startsWith('http')) this.showURLTab() 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 () { const symbol = L.DomUtil.add( 'button', 'flat tab-symbols', - this.tabsContainer, + this.tabs, L._('Symbol') ), char = L.DomUtil.add( 'button', 'flat tab-chars', - this.tabsContainer, + this.tabs, 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( symbol, '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) }, - highlightTab: function (name) { - const els = this.tabsContainer.querySelectorAll('button') + openTab: function (name) { + const els = this.tabs.querySelectorAll('button') for (let el of els) { L.DomUtil.removeClass(el, 'on') } - let el = this.tabsContainer.querySelector(`.tab-${name}`) + let el = this.tabs.querySelector(`.tab-${name}`) L.DomUtil.addClass(el, 'on') + this.body.innerHTML = '' }, - isUrl: function () { - return this.value() && this.value().indexOf('/') !== -1 + isPath: function () { + 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 () { - if (this.isDefault()) { - this.buttonsContainer.innerHTML = '' - return - } + this.buttons.innerHTML = '' + if (this.isDefault()) return if (!L.Util.hasVar(this.value())) { // Do not try to render URL with variables - if (this.isUrl()) { + if (this.isImg()) { const img = L.DomUtil.create( 'img', '', - L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer) + L.DomUtil.create('div', 'umap-pictogram-choice', this.buttons) ) img.src = this.value() L.DomEvent.on(img, 'click', this.showSymbolsTab, this) @@ -604,7 +625,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ const el = L.DomUtil.create( 'span', '', - L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer) + L.DomUtil.create('div', 'umap-pictogram-choice', this.buttons) ) el.textContent = this.value() L.DomEvent.on(el, 'click', this.showSymbolsTab, this) @@ -612,7 +633,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ } this.button = L.DomUtil.createButton( 'button action-button', - this.buttonsContainer, + this.buttons, this.value() ? L._('Change') : L._('Add'), this.onDefine, this @@ -638,7 +659,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ function (e) { this.input.value = value this.sync() - this.unselectAll(this.gridContainer) + this.unselectAll(this.grid) L.DomUtil.addClass(container, 'selected') }, this @@ -648,9 +669,9 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ clear: function () { this.input.value = '' - this.unselectAll(this.pictogramsContainer) + this.unselectAll(this.body) this.sync() - this.pictogramsContainer.innerHTML = '' + this.body.innerHTML = '' this.udpatePreview() }, @@ -662,11 +683,11 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({ for (let item of items) { status = this.addIconPreview(item, grid) || status } - if (status) this.gridContainer.appendChild(parent) + if (status) this.grid.appendChild(parent) }, buildSymbolsList: function () { - this.gridContainer.innerHTML = '' + this.grid.innerHTML = '' const categories = {} let category 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 }, - 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 () { - this.highlightTab('symbols') - this.input.type = 'hidden' - this.buttonsContainer.innerHTML = '' - this.searchInput = L.DomUtil.create('input', '', this.pictogramsContainer) + this.openTab('symbols') + this.searchInput = L.DomUtil.create('input', '', this.body) this.searchInput.type = '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) - 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) { this.buildSymbolsList() } 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 () { - this.highlightTab('url') - this.input.type = 'url' - this.input.placeholder = L._('Add URL') - this.pictogramsContainer.innerHTML = '' + this.openTab('url') + const value = this.isRemoteUrl() ? this.value() : null + const input = this.buildInput(this.body, value) + 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) { diff --git a/umap/tests/integration/test_picto.py b/umap/tests/integration/test_picto.py index c0c12115..f36d462a 100644 --- a/umap/tests/integration/test_picto.py +++ b/umap/tests/integration/test_picto.py @@ -59,7 +59,7 @@ def test_can_change_picto_at_map_level(map, live_server, page, pictos): define.click() symbols = page.locator(".umap-pictogram-choice") expect(symbols).to_have_count(2) - search = page.locator(".umap-pictogram-list input") + search = page.locator(".umap-pictogram-body input") search.type("star") expect(symbols).to_have_count(1) symbols.click() @@ -93,7 +93,7 @@ def test_can_change_picto_at_datalayer_level(map, live_server, page, pictos): define.click() symbols = page.locator(".umap-pictogram-choice") expect(symbols).to_have_count(2) - search = page.locator(".umap-pictogram-list input") + search = page.locator(".umap-pictogram-body input") search.type("circle") expect(symbols).to_have_count(1) symbols.click() @@ -127,7 +127,7 @@ def test_can_change_picto_at_marker_level(map, live_server, page, pictos): define.click() symbols = page.locator(".umap-pictogram-choice") expect(symbols).to_have_count(2) - search = page.locator(".umap-pictogram-list input") + search = page.locator(".umap-pictogram-body input") search.type("circle") expect(symbols).to_have_count(1) symbols.click() @@ -156,7 +156,7 @@ def test_can_use_remote_url_as_picto(map, live_server, page, pictos): expect(define).to_be_visible() define.click() 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(url_tab).to_be_visible() url_tab.click() @@ -165,7 +165,7 @@ def test_can_use_remote_url_as_picto(map, live_server, page, pictos): input_el.blur() expect(marker).to_have_attribute("src", "https://foo.bar/img.jpg") # 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() close.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.click() 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(url_tab).to_be_visible() 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_text("♩") # 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() close.click() edit_settings.click()