Refactor icon selector: use tabs, make options more explicit

This commit is contained in:
Yohan Boniface 2023-11-08 18:00:12 +01:00
parent c16a01778b
commit 1bf1543668
2 changed files with 103 additions and 36 deletions

View file

@ -194,6 +194,7 @@ input[type="submit"] {
.dark a { .dark a {
color: #eeeeec; color: #eeeeec;
} }
button.flat,
[type="button"].flat, [type="button"].flat,
.dark [type="button"].flat { .dark [type="button"].flat {
border: none; border: none;
@ -535,9 +536,27 @@ i.info {
margin-top: -8px; margin-top: -8px;
padding: 0 5px; padding: 0 5px;
} }
.umap-pictogram-grid { .pictogram-tabs {
display: flex; display: flex;
flex-wrap: wrap; justify-content: space-around;
font-size: 1.2em;
padding-bottom: 20px;
}
.pictogram-tabs button {
padding: 10px;
color: #fff;
text-decoration: none;
cursor: pointer;
}
.pictogram-tabs .on {
font-weight: bold;
border-bottom: 1px solid #fff;
}
.umap-pictogram-grid {
display: grid;
grid-template-columns: repeat(auto-fill, 30px);
justify-content: space-between;
grid-gap: 5px;
} }
.umap-pictogram-choice { .umap-pictogram-choice {
width: 30px; width: 30px;
@ -547,7 +566,6 @@ i.info {
background-color: #999; background-color: #999;
text-align: center; text-align: center;
margin-bottom: 5px; margin-bottom: 5px;
margin-right: 5px;
} }
.umap-pictogram-choice img { .umap-pictogram-choice img {
vertical-align: middle; vertical-align: middle;
@ -556,7 +574,8 @@ i.info {
.umap-pictogram-choice:hover, .umap-pictogram-choice:hover,
.umap-pictogram-choice.selected, .umap-pictogram-choice.selected,
.umap-color-picker span:hover { .umap-color-picker span:hover {
box-shadow: 0 0 4px 0 black; box-shadow: 0 0 4px 0 rgb(66, 236, 230);
background-color: #aaa;
} }
.umap-pictogram-choice .leaflet-marker-icon { .umap-pictogram-choice .leaflet-marker-icon {
bottom: 0; bottom: 0;

View file

@ -1,4 +1,10 @@
L.FormBuilder.Element.include({ L.FormBuilder.Element.include({
undefine: function () {
L.DomUtil.addClass(this.wrapper, 'undefined')
this.clear()
this.sync()
},
getParentNode: function () { getParentNode: function () {
if (this.options.wrapper) { if (this.options.wrapper) {
return L.DomUtil.create( return L.DomUtil.create(
@ -29,15 +35,10 @@ L.FormBuilder.Element.include({
}, },
this this
) )
L.DomEvent.on( L.DomEvent.on(undefine, 'click', L.DomEvent.stop).on(
undefine, undefine,
'click', 'click',
function (e) { this.undefine,
L.DomEvent.stop(e)
L.DomUtil.addClass(this.wrapper, 'undefined')
this.clear()
this.sync()
},
this this
) )
} }
@ -524,16 +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)
// Try to guess if the icon content has been customized, and if yes
// directly display the field
this.input.type = this.value() && !this.value().startsWith('/') ? 'text' : 'hidden'
this.input.placeholder = L._('Symbol or url')
this.buttonsContainer = L.DomUtil.create('div', '') this.buttonsContainer = L.DomUtil.create('div', '')
this.pictogramsContainer = L.DomUtil.create('div', 'umap-pictogram-list') 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.buttonsContainer)
L.DomUtil.before(this.input, this.tabsContainer)
L.DomUtil.before(this.input, this.pictogramsContainer) L.DomUtil.before(this.input, this.pictogramsContainer)
this.udpatePreview() this.udpatePreview()
this.on('define', this.fetchIconList) this.on('define', this.onDefine)
},
onDefine: function () {
this.buildTabs()
this.showSymbols()
},
buildTabs: function () {
const symbol = L.DomUtil.add(
'button',
'flat on',
this.tabsContainer,
L._('Symbol')
),
char = L.DomUtil.add(
'button',
'flat',
this.tabsContainer,
L._('Emoji & Character')
)
url = L.DomUtil.add('button', 'flat', this.tabsContainer, L._('URL'))
toggle = (e) => {
L.DomUtil.removeClass(symbol, 'on')
L.DomUtil.removeClass(char, 'on')
L.DomUtil.removeClass(url, 'on')
L.DomUtil.addClass(e.target, 'on')
}
L.DomEvent.on(symbol, 'click', L.DomEvent.stop)
.on(symbol, 'click', this.showSymbols, this)
.on(symbol, 'click', toggle)
L.DomEvent.on(char, 'click', L.DomEvent.stop)
.on(char, 'click', this.showChars, this)
.on(char, 'click', toggle)
L.DomEvent.on(url, 'click', L.DomEvent.stop)
.on(url, 'click', this.showURL, this)
.on(url, 'click', toggle)
}, },
isUrl: function () { isUrl: function () {
@ -541,6 +576,10 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
}, },
udpatePreview: function () { udpatePreview: function () {
if (this.isDefault()) {
this.buttonsContainer.innerHTML = ''
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.isUrl()) {
@ -550,7 +589,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer) L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer)
) )
img.src = this.value() img.src = this.value()
L.DomEvent.on(img, 'click', this.fetchIconList, this) L.DomEvent.on(img, 'click', this.showSymbols, this)
} else { } else {
const el = L.DomUtil.create( const el = L.DomUtil.create(
'span', 'span',
@ -558,14 +597,14 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer) L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer)
) )
el.textContent = this.value() el.textContent = this.value()
L.DomEvent.on(el, 'click', this.fetchIconList, this) L.DomEvent.on(el, 'click', this.showSymbols, this)
} }
} }
this.button = L.DomUtil.createButton( this.button = L.DomUtil.createButton(
'button action-button', 'button action-button',
this.buttonsContainer, this.buttonsContainer,
this.value() ? L._('Change') : L._('Add'), this.value() ? L._('Change') : L._('Add'),
this.fetchIconList, this.showSymbols,
this this
) )
}, },
@ -623,7 +662,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
} }
}, },
buildIconList: function (data) { buildSymbolsList: function (data) {
this.searchInput = L.DomUtil.create('input', '', this.pictogramsContainer) 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')
@ -647,35 +686,44 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
L._('Close'), L._('Close'),
function (e) { function (e) {
this.pictogramsContainer.innerHTML = '' this.pictogramsContainer.innerHTML = ''
this.udpatePreview() this.tabsContainer.innerHTML = ''
if (this.isDefault()) this.undefine(e)
else this.udpatePreview()
}, },
this this
) )
closeButton.style.display = 'block'
closeButton.style.clear = 'both'
const customButton = L.DomUtil.createButton(
'flat',
this.pictogramsContainer,
L._('Toggle direct input (advanced)'),
function (e) {
this.input.type = this.input.type === 'text' ? 'hidden' : 'text'
},
this
)
this.builder.map.help.button(customButton, 'formatIconSymbol')
}, },
fetchIconList: function (e) { isDefault: function () {
return !this.value() || this.value() === this.obj.getMap().options.default_iconUrl
},
showChars: function () {
// Do not show default value here, as it's not a character
// and it has not been explicitely chosen by the user.
if (this.isDefault()) this.input.value = ''
this.input.type = 'text'
this.input.placeholder = L._('Type char or paste emoji')
this.pictogramsContainer.innerHTML = ''
},
showSymbols: function () {
this.input.type = 'hidden'
// Clean parent element before calling ajax, to prevent blinking // Clean parent element before calling ajax, to prevent blinking
this.pictogramsContainer.innerHTML = '' this.pictogramsContainer.innerHTML = ''
this.buttonsContainer.innerHTML = '' this.buttonsContainer.innerHTML = ''
this.builder.map.get(this.builder.map.options.urls.pictogram_list_json, { this.builder.map.get(this.builder.map.options.urls.pictogram_list_json, {
callback: this.buildIconList, callback: this.buildSymbolsList,
context: this, context: this,
}) })
}, },
showURL: function () {
this.input.type = 'url'
this.input.placeholder = L._('Add URL')
this.pictogramsContainer.innerHTML = ''
},
unselectAll: function (container) { unselectAll: function (container) {
const els = container.querySelectorAll('div.selected') const els = container.querySelectorAll('div.selected')
for (const el in els) { for (const el in els) {