Merge pull request #1395 from umap-project/picto-ui
Refactor icon selector: use tabs, make options more explicit
This commit is contained in:
commit
0db7f377c3
9 changed files with 440 additions and 100 deletions
|
@ -194,6 +194,7 @@ input[type="submit"] {
|
|||
.dark a {
|
||||
color: #eeeeec;
|
||||
}
|
||||
button.flat,
|
||||
[type="button"].flat,
|
||||
.dark [type="button"].flat {
|
||||
border: none;
|
||||
|
@ -536,9 +537,30 @@ i.info {
|
|||
margin-top: -8px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.umap-pictogram-grid {
|
||||
.pictogram-tabs {
|
||||
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-category h6 {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
.umap-pictogram-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, 30px);
|
||||
justify-content: space-between;
|
||||
grid-gap: 5px;
|
||||
}
|
||||
.umap-pictogram-choice {
|
||||
width: 30px;
|
||||
|
@ -548,17 +570,20 @@ i.info {
|
|||
background-color: #999;
|
||||
text-align: center;
|
||||
margin-bottom: 5px;
|
||||
margin-right: 5px;
|
||||
display: block;
|
||||
}
|
||||
.umap-pictogram-choice img {
|
||||
vertical-align: middle;
|
||||
max-width: 24px;
|
||||
}
|
||||
.umap-pictogram-choice:hover,
|
||||
.umap-pictogram-choice.selected,
|
||||
.umap-color-picker span:hover {
|
||||
box-shadow: 0 0 4px 0 black;
|
||||
background-color: #bebebe;
|
||||
}
|
||||
.umap-pictogram-choice.selected {
|
||||
box-shadow: inset 0 0 0 1px #e9e9e9;
|
||||
}
|
||||
|
||||
.umap-pictogram-choice .leaflet-marker-icon {
|
||||
bottom: 0;
|
||||
left: 30px;
|
||||
|
|
|
@ -287,6 +287,13 @@ L.Util.copyToClipboard = function (textToCopy) {
|
|||
}
|
||||
}
|
||||
|
||||
L.Util.normalize = function (s) {
|
||||
return (s || '')
|
||||
.toLowerCase()
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
}
|
||||
|
||||
L.DomUtil.add = (tagName, className, container, content) => {
|
||||
const el = L.DomUtil.create(tagName, className, container)
|
||||
if (content) {
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
L.FormBuilder.Element.include({
|
||||
undefine: function () {
|
||||
L.DomUtil.addClass(this.wrapper, 'undefined')
|
||||
this.clear()
|
||||
this.sync()
|
||||
},
|
||||
|
||||
getParentNode: function () {
|
||||
if (this.options.wrapper) {
|
||||
return L.DomUtil.create(
|
||||
|
@ -29,15 +35,10 @@ L.FormBuilder.Element.include({
|
|||
},
|
||||
this
|
||||
)
|
||||
L.DomEvent.on(
|
||||
L.DomEvent.on(undefine, 'click', L.DomEvent.stop).on(
|
||||
undefine,
|
||||
'click',
|
||||
function (e) {
|
||||
L.DomEvent.stop(e)
|
||||
L.DomUtil.addClass(this.wrapper, 'undefined')
|
||||
this.clear()
|
||||
this.sync()
|
||||
},
|
||||
this.undefine,
|
||||
this
|
||||
)
|
||||
}
|
||||
|
@ -524,48 +525,111 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
|
||||
build: function () {
|
||||
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.pictogramsContainer = L.DomUtil.create('div', 'umap-pictogram-list')
|
||||
L.DomUtil.before(this.input, this.buttonsContainer)
|
||||
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.fetchIconList)
|
||||
this.on('define', this.onDefine)
|
||||
},
|
||||
|
||||
isUrl: function () {
|
||||
return this.value() && this.value().indexOf('/') !== -1
|
||||
onDefine: function () {
|
||||
this.buttons.innerHTML = ''
|
||||
this.footer.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 () {
|
||||
this.tabs.innerHTML = ''
|
||||
const symbol = L.DomUtil.add(
|
||||
'button',
|
||||
'flat tab-symbols',
|
||||
this.tabs,
|
||||
L._('Symbol')
|
||||
),
|
||||
char = L.DomUtil.add(
|
||||
'button',
|
||||
'flat tab-chars',
|
||||
this.tabs,
|
||||
L._('Emoji & Character')
|
||||
)
|
||||
url = L.DomUtil.add('button', 'flat tab-url', this.tabs, L._('URL'))
|
||||
L.DomEvent.on(symbol, 'click', L.DomEvent.stop).on(
|
||||
symbol,
|
||||
'click',
|
||||
this.showSymbolsTab,
|
||||
this
|
||||
)
|
||||
L.DomEvent.on(char, 'click', L.DomEvent.stop).on(
|
||||
char,
|
||||
'click',
|
||||
this.showCharsTab,
|
||||
this
|
||||
)
|
||||
L.DomEvent.on(url, 'click', L.DomEvent.stop).on(url, 'click', this.showURLTab, this)
|
||||
},
|
||||
|
||||
openTab: function (name) {
|
||||
const els = this.tabs.querySelectorAll('button')
|
||||
for (let el of els) {
|
||||
L.DomUtil.removeClass(el, 'on')
|
||||
}
|
||||
let el = this.tabs.querySelector(`.tab-${name}`)
|
||||
L.DomUtil.addClass(el, 'on')
|
||||
this.body.innerHTML = ''
|
||||
},
|
||||
|
||||
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 () {
|
||||
this.buttons.innerHTML = ''
|
||||
if (this.isDefault()) return
|
||||
if (!L.Util.hasVar(this.value())) {
|
||||
// Do not try to render URL with variables
|
||||
if (this.isUrl()) {
|
||||
const img = L.DomUtil.create(
|
||||
'img',
|
||||
'',
|
||||
L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer)
|
||||
)
|
||||
const box = L.DomUtil.create('div', 'umap-pictogram-choice', this.buttons)
|
||||
L.DomEvent.on(box, 'click', this.onDefine, this)
|
||||
if (this.isImg()) {
|
||||
const img = L.DomUtil.create('img', '', box)
|
||||
img.src = this.value()
|
||||
L.DomEvent.on(img, 'click', this.fetchIconList, this)
|
||||
} else {
|
||||
const el = L.DomUtil.create(
|
||||
'span',
|
||||
'',
|
||||
L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer)
|
||||
)
|
||||
const el = L.DomUtil.create('span', '', box)
|
||||
el.textContent = this.value()
|
||||
L.DomEvent.on(el, 'click', this.fetchIconList, this)
|
||||
}
|
||||
}
|
||||
this.button = L.DomUtil.createButton(
|
||||
'button action-button',
|
||||
this.buttonsContainer,
|
||||
this.buttons,
|
||||
this.value() ? L._('Change') : L._('Add'),
|
||||
this.fetchIconList,
|
||||
this.onDefine,
|
||||
this
|
||||
)
|
||||
},
|
||||
|
@ -573,64 +637,54 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
addIconPreview: function (pictogram, parent) {
|
||||
const baseClass = 'umap-pictogram-choice',
|
||||
value = pictogram.src,
|
||||
className = value === this.value() ? `${baseClass} selected` : baseClass,
|
||||
search = L.Util.normalize(this.searchInput.value),
|
||||
title = pictogram.attribution
|
||||
? `${pictogram.name} — © ${pictogram.attribution}`
|
||||
: pictogram.name
|
||||
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
|
||||
if (pictogram.name && pictogram.attribution) {
|
||||
container.title = `${pictogram.name} — © ${pictogram.attribution}`
|
||||
}
|
||||
container.title = title
|
||||
L.DomEvent.on(
|
||||
container,
|
||||
'click',
|
||||
function (e) {
|
||||
this.input.value = value
|
||||
this.sync()
|
||||
this.unselectAll(this.pictogramsContainer)
|
||||
this.unselectAll(this.grid)
|
||||
L.DomUtil.addClass(container, 'selected')
|
||||
},
|
||||
this
|
||||
)
|
||||
return true // Icon has been added (not filtered)
|
||||
},
|
||||
|
||||
clear: function () {
|
||||
this.input.value = ''
|
||||
this.unselectAll(this.pictogramsContainer)
|
||||
this.unselectAll(this.body)
|
||||
this.sync()
|
||||
this.pictogramsContainer.innerHTML = ''
|
||||
this.body.innerHTML = ''
|
||||
this.udpatePreview()
|
||||
},
|
||||
|
||||
search: function (e) {
|
||||
const icons = [...this.parentNode.querySelectorAll('.umap-pictogram-choice')],
|
||||
search = this.searchInput.value.toLowerCase()
|
||||
icons.forEach((el) => {
|
||||
if (el.title.toLowerCase().indexOf(search) != -1) el.style.display = 'block'
|
||||
else el.style.display = 'none'
|
||||
})
|
||||
},
|
||||
|
||||
addCategory: function (category, items) {
|
||||
const parent = L.DomUtil.create(
|
||||
'div',
|
||||
'umap-pictogram-category',
|
||||
this.pictogramsContainer
|
||||
),
|
||||
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)
|
||||
let status = false
|
||||
for (let item of items) {
|
||||
this.addIconPreview(item, grid)
|
||||
status = this.addIconPreview(item, grid) || status
|
||||
}
|
||||
if (status) this.grid.appendChild(parent)
|
||||
},
|
||||
|
||||
buildIconList: function (data) {
|
||||
this.searchInput = L.DomUtil.create('input', '', this.pictogramsContainer)
|
||||
this.searchInput.type = 'search'
|
||||
this.searchInput.placeholder = L._('Search')
|
||||
L.DomEvent.on(this.searchInput, 'input', this.search, this)
|
||||
buildSymbolsList: function () {
|
||||
this.grid.innerHTML = ''
|
||||
const categories = {}
|
||||
let category
|
||||
for (const props of data.pictogram_list) {
|
||||
for (const props of this.pictogram_list) {
|
||||
category = props.category || L._('Generic')
|
||||
categories[category] = categories[category] || []
|
||||
categories[category].push(props)
|
||||
|
@ -641,39 +695,60 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
for (let [category, items] of sorted) {
|
||||
this.addCategory(category, items)
|
||||
}
|
||||
const closeButton = L.DomUtil.createButton(
|
||||
'button action-button',
|
||||
this.pictogramsContainer,
|
||||
L._('Close'),
|
||||
function (e) {
|
||||
this.pictogramsContainer.innerHTML = ''
|
||||
this.udpatePreview()
|
||||
},
|
||||
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) {
|
||||
// Clean parent element before calling ajax, to prevent blinking
|
||||
this.pictogramsContainer.innerHTML = ''
|
||||
this.buttonsContainer.innerHTML = ''
|
||||
isDefault: function () {
|
||||
return !this.value() || this.value() === this.obj.getMap().options.default_iconUrl
|
||||
},
|
||||
|
||||
showSymbolsTab: function () {
|
||||
this.openTab('symbols')
|
||||
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 {
|
||||
this.builder.map.get(this.builder.map.options.urls.pictogram_list_json, {
|
||||
callback: this.buildIconList,
|
||||
callback: (data) => {
|
||||
this.pictogram_list = data.pictogram_list
|
||||
this.buildSymbolsList()
|
||||
},
|
||||
context: this,
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
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.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) {
|
||||
|
|
|
@ -1298,6 +1298,7 @@ a.add-datalayer:hover,
|
|||
vertical-align: middle;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
.umap-circle-icon {
|
||||
border: 1px solid white;
|
||||
|
|
|
@ -475,6 +475,16 @@ describe('L.Util', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe("#normalize()", function () {
|
||||
|
||||
if('should remove accents', function () {
|
||||
// French é
|
||||
assert.equal(L.Util.normalize('aéroport'), 'aeroport')
|
||||
// American é
|
||||
assert.equal(L.Util.normalize('aéroport'), 'aeroport')
|
||||
})
|
||||
})
|
||||
|
||||
describe("#sortFeatures()", function () {
|
||||
let feat1, feat2, feat3
|
||||
before(function () {
|
||||
|
|
|
@ -24,11 +24,8 @@ def pytest_configure(config):
|
|||
settings.MEDIA_ROOT = TMP_ROOT
|
||||
|
||||
|
||||
def pytest_unconfigure(config):
|
||||
shutil.rmtree(TMP_ROOT, ignore_errors=True)
|
||||
|
||||
|
||||
def pytest_runtest_teardown():
|
||||
shutil.rmtree(TMP_ROOT, ignore_errors=True)
|
||||
cache.clear()
|
||||
|
||||
|
||||
|
|
4
umap/tests/fixtures/circle.svg
vendored
Normal file
4
umap/tests/fixtures/circle.svg
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" id="circle" xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 15 15">
|
||||
<path d="M14,7.5c0,3.5899-2.9101,6.5-6.5,6.5S1,11.0899,1,7.5S3.9101,1,7.5,1S14,3.9101,14,7.5z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 254 B |
4
umap/tests/fixtures/star.svg
vendored
Normal file
4
umap/tests/fixtures/star.svg
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" id="star" xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 15 15">
|
||||
<path id="path4749-2-8-2" d="M7.5,0l-2,5h-5l4,3.5l-2,6l5-3.5
	l5,3.5l-2-6l4-3.5h-5L7.5,0z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 256 B |
217
umap/tests/integration/test_picto.py
Normal file
217
umap/tests/integration/test_picto.py
Normal file
|
@ -0,0 +1,217 @@
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from playwright.sync_api import expect
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
from umap.models import Map, Pictogram
|
||||
|
||||
from ..base import DataLayerFactory
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
DATALAYER_DATA = {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [13.68896484375, 48.55297816440071],
|
||||
},
|
||||
"properties": {"_umap_options": {"color": "DarkCyan"}, "name": "Here"},
|
||||
}
|
||||
],
|
||||
"_umap_options": {"displayOnLoad": True, "name": "FooBarFoo"},
|
||||
}
|
||||
FIXTURES = Path(__file__).parent.parent / "fixtures"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pictos():
|
||||
path = FIXTURES / "star.svg"
|
||||
Pictogram(name="star", pictogram=ContentFile(path.read_text(), path.name)).save()
|
||||
path = FIXTURES / "circle.svg"
|
||||
Pictogram(name="circle", pictogram=ContentFile(path.read_text(), path.name)).save()
|
||||
|
||||
|
||||
def test_can_change_picto_at_map_level(map, live_server, page, pictos):
|
||||
# Faster than doing a login
|
||||
map.edit_status = Map.ANONYMOUS
|
||||
map.save()
|
||||
DataLayerFactory(map=map, data=DATALAYER_DATA)
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||
marker = page.locator(".umap-div-icon img")
|
||||
expect(marker).to_have_count(1)
|
||||
# Should have default img
|
||||
expect(marker).to_have_attribute("src", "/static/umap/img/marker.png")
|
||||
edit_settings = page.get_by_title("Edit map settings")
|
||||
expect(edit_settings).to_be_visible()
|
||||
edit_settings.click()
|
||||
shape_settings = page.get_by_text("Default shape properties")
|
||||
expect(shape_settings).to_be_visible()
|
||||
shape_settings.click()
|
||||
define = page.locator(".umap-field-iconUrl .define")
|
||||
undefine = page.locator(".umap-field-iconUrl .undefine")
|
||||
expect(define).to_be_visible()
|
||||
expect(undefine).to_be_hidden()
|
||||
define.click()
|
||||
symbols = page.locator(".umap-pictogram-choice")
|
||||
expect(symbols).to_have_count(2)
|
||||
search = page.locator(".umap-pictogram-body input")
|
||||
search.type("star")
|
||||
expect(symbols).to_have_count(1)
|
||||
symbols.click()
|
||||
expect(marker).to_have_attribute("src", "/uploads/pictogram/star.svg")
|
||||
undefine.click()
|
||||
expect(marker).to_have_attribute("src", "/static/umap/img/marker.png")
|
||||
|
||||
|
||||
def test_can_change_picto_at_datalayer_level(map, live_server, page, pictos):
|
||||
# Faster than doing a login
|
||||
map.edit_status = Map.ANONYMOUS
|
||||
map.settings["properties"]["iconUrl"] = "/uploads/pictogram/star.svg"
|
||||
map.save()
|
||||
DataLayerFactory(map=map, data=DATALAYER_DATA)
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||
marker = page.locator(".umap-div-icon img")
|
||||
expect(marker).to_have_count(1)
|
||||
# Should have default img
|
||||
expect(marker).to_have_attribute("src", "/uploads/pictogram/star.svg")
|
||||
# Edit datalayer
|
||||
marker.click(modifiers=["Control", "Shift"])
|
||||
settings = page.get_by_text("Layer properties")
|
||||
expect(settings).to_be_visible()
|
||||
shape_settings = page.get_by_text("Shape properties")
|
||||
expect(shape_settings).to_be_visible()
|
||||
shape_settings.click()
|
||||
define = page.locator(".umap-field-iconUrl .define")
|
||||
undefine = page.locator(".umap-field-iconUrl .undefine")
|
||||
expect(define).to_be_visible()
|
||||
expect(undefine).to_be_hidden()
|
||||
define.click()
|
||||
symbols = page.locator(".umap-pictogram-choice")
|
||||
expect(symbols).to_have_count(2)
|
||||
search = page.locator(".umap-pictogram-body input")
|
||||
search.type("circle")
|
||||
expect(symbols).to_have_count(1)
|
||||
symbols.click()
|
||||
expect(marker).to_have_attribute("src", "/uploads/pictogram/circle.svg")
|
||||
undefine.click()
|
||||
expect(marker).to_have_attribute("src", "/uploads/pictogram/star.svg")
|
||||
|
||||
|
||||
def test_can_change_picto_at_marker_level(map, live_server, page, pictos):
|
||||
# Faster than doing a login
|
||||
map.edit_status = Map.ANONYMOUS
|
||||
map.settings["properties"]["iconUrl"] = "/uploads/pictogram/star.svg"
|
||||
map.save()
|
||||
DataLayerFactory(map=map, data=DATALAYER_DATA)
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||
marker = page.locator(".umap-div-icon img")
|
||||
expect(marker).to_have_count(1)
|
||||
# Should have default img
|
||||
expect(marker).to_have_attribute("src", "/uploads/pictogram/star.svg")
|
||||
# Edit marker
|
||||
marker.click(modifiers=["Shift"])
|
||||
settings = page.get_by_text("Feature properties")
|
||||
expect(settings).to_be_visible()
|
||||
shape_settings = page.get_by_text("Shape properties")
|
||||
expect(shape_settings).to_be_visible()
|
||||
shape_settings.click()
|
||||
define = page.locator(".umap-field-iconUrl .define")
|
||||
undefine = page.locator(".umap-field-iconUrl .undefine")
|
||||
expect(define).to_be_visible()
|
||||
expect(undefine).to_be_hidden()
|
||||
define.click()
|
||||
symbols = page.locator(".umap-pictogram-choice")
|
||||
expect(symbols).to_have_count(2)
|
||||
search = page.locator(".umap-pictogram-body input")
|
||||
search.type("circle")
|
||||
expect(symbols).to_have_count(1)
|
||||
symbols.click()
|
||||
expect(marker).to_have_attribute("src", "/uploads/pictogram/circle.svg")
|
||||
undefine.click()
|
||||
expect(marker).to_have_attribute("src", "/uploads/pictogram/star.svg")
|
||||
|
||||
|
||||
def test_can_use_remote_url_as_picto(map, live_server, page, pictos):
|
||||
# Faster than doing a login
|
||||
map.edit_status = Map.ANONYMOUS
|
||||
map.save()
|
||||
DataLayerFactory(map=map, data=DATALAYER_DATA)
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||
marker = page.locator(".umap-div-icon img")
|
||||
expect(marker).to_have_count(1)
|
||||
# Should have default img
|
||||
expect(marker).to_have_attribute("src", "/static/umap/img/marker.png")
|
||||
edit_settings = page.get_by_title("Edit map settings")
|
||||
expect(edit_settings).to_be_visible()
|
||||
edit_settings.click()
|
||||
shape_settings = page.get_by_text("Default shape properties")
|
||||
expect(shape_settings).to_be_visible()
|
||||
shape_settings.click()
|
||||
define = page.locator(".umap-field-iconUrl .define")
|
||||
expect(define).to_be_visible()
|
||||
define.click()
|
||||
url_tab = page.get_by_role("button", name="URL")
|
||||
input_el = page.get_by_placeholder("Add image URL")
|
||||
expect(input_el).to_be_hidden()
|
||||
expect(url_tab).to_be_visible()
|
||||
url_tab.click()
|
||||
expect(input_el).to_be_visible()
|
||||
input_el.fill("https://foo.bar/img.jpg")
|
||||
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_title("Close")
|
||||
expect(close).to_be_visible()
|
||||
close.click()
|
||||
edit_settings.click()
|
||||
shape_settings.click()
|
||||
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()
|
||||
|
||||
|
||||
def test_can_use_char_as_picto(map, live_server, page, pictos):
|
||||
# Faster than doing a login
|
||||
map.edit_status = Map.ANONYMOUS
|
||||
map.save()
|
||||
DataLayerFactory(map=map, data=DATALAYER_DATA)
|
||||
page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||
marker = page.locator(".umap-div-icon span")
|
||||
# Should have default img, so not a span
|
||||
expect(marker).to_have_count(0)
|
||||
edit_settings = page.get_by_title("Edit map settings")
|
||||
expect(edit_settings).to_be_visible()
|
||||
edit_settings.click()
|
||||
shape_settings = page.get_by_text("Default shape properties")
|
||||
expect(shape_settings).to_be_visible()
|
||||
shape_settings.click()
|
||||
define = page.locator(".umap-field-iconUrl .define")
|
||||
define.click()
|
||||
url_tab = page.get_by_role("button", name="Emoji & Character")
|
||||
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()
|
||||
expect(input_el).to_be_visible()
|
||||
input_el.fill("♩")
|
||||
input_el.blur()
|
||||
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_title("Close")
|
||||
expect(close).to_be_visible()
|
||||
close.click()
|
||||
edit_settings.click()
|
||||
shape_settings.click()
|
||||
preview = page.locator(".umap-pictogram-choice")
|
||||
expect(preview).to_be_visible()
|
||||
preview.click()
|
||||
# Should be on URL tab
|
||||
expect(input_el).to_be_visible()
|
Loading…
Reference in a new issue