Add Pictogram.category and list pictos grouped by category
This commit is contained in:
parent
4643930870
commit
8c774fb7b3
5 changed files with 71 additions and 31 deletions
17
umap/migrations/0016_pictogram_category.py
Normal file
17
umap/migrations/0016_pictogram_category.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 4.2.2 on 2023-10-30 17:22
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("umap", "0015_alter_pictogram_pictogram"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="pictogram",
|
||||
name="category",
|
||||
field=models.CharField(blank=True, max_length=300, null=True),
|
||||
),
|
||||
]
|
|
@ -284,6 +284,7 @@ class Pictogram(NamedModel):
|
|||
"""
|
||||
|
||||
attribution = models.CharField(max_length=300)
|
||||
category = models.CharField(max_length=300, null=True, blank=True)
|
||||
pictogram = models.FileField(upload_to="pictogram")
|
||||
|
||||
@property
|
||||
|
@ -292,6 +293,7 @@ class Pictogram(NamedModel):
|
|||
"id": self.pk,
|
||||
"attribution": self.attribution,
|
||||
"name": self.name,
|
||||
"category": self.category,
|
||||
"src": self.pictogram.url,
|
||||
}
|
||||
|
||||
|
|
|
@ -521,16 +521,14 @@ i.info {
|
|||
margin-top: -8px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.umap-icon-list, .umap-pictogram-list {
|
||||
clear: both;
|
||||
.umap-pictogram-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.umap-icon-choice {
|
||||
display: block;
|
||||
float: left;
|
||||
.umap-pictogram-choice {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
background-image: url('./img/icon-bg.png');
|
||||
text-align: center;
|
||||
|
@ -538,16 +536,16 @@ i.info {
|
|||
margin-bottom: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.umap-icon-choice img {
|
||||
.umap-pictogram-choice img {
|
||||
vertical-align: middle;
|
||||
max-width: 24px;
|
||||
}
|
||||
.umap-icon-choice:hover,
|
||||
.umap-icon-choice.selected,
|
||||
.umap-pictogram-choice:hover,
|
||||
.umap-pictogram-choice.selected,
|
||||
.umap-color-picker span:hover {
|
||||
box-shadow: 0 0 4px 0 black;
|
||||
}
|
||||
.umap-icon-choice .leaflet-marker-icon {
|
||||
.umap-pictogram-choice .leaflet-marker-icon {
|
||||
bottom: 0;
|
||||
left: 30px;
|
||||
position: absolute;
|
||||
|
|
|
@ -201,6 +201,16 @@ L.Util.greedyTemplate = (str, data, ignore) => {
|
|||
)
|
||||
}
|
||||
|
||||
L.Util.naturalSort = (a, b) => {
|
||||
return a
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.localeCompare(b.toString().toLowerCase(), L.lang || 'en', {
|
||||
sensitivity: 'base',
|
||||
numeric: true,
|
||||
})
|
||||
}
|
||||
|
||||
L.Util.sortFeatures = (features, sortKey) => {
|
||||
const sortKeys = (sortKey || 'name').split(',')
|
||||
|
||||
|
@ -214,19 +224,9 @@ L.Util.sortFeatures = (features, sortKey) => {
|
|||
let score
|
||||
const valA = a.properties[sortKey] || ''
|
||||
const valB = b.properties[sortKey] || ''
|
||||
if (!valA) {
|
||||
score = -1
|
||||
} else if (!valB) {
|
||||
score = 1
|
||||
} else {
|
||||
score = valA
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.localeCompare(valB.toString().toLowerCase(), L.lang || 'en', {
|
||||
sensitivity: 'base',
|
||||
numeric: true,
|
||||
})
|
||||
}
|
||||
if (!valA) score = -1
|
||||
else if (!valB) score = 1
|
||||
else score = L.Util.naturalSort(valA, valB)
|
||||
if (score === 0 && sortKeys[i + 1]) return sort(a, b, i + 1)
|
||||
return score * reverse
|
||||
}
|
||||
|
|
|
@ -547,7 +547,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
const img = L.DomUtil.create(
|
||||
'img',
|
||||
'',
|
||||
L.DomUtil.create('div', 'umap-icon-choice', this.buttonsContainer)
|
||||
L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer)
|
||||
)
|
||||
img.src = this.value()
|
||||
L.DomEvent.on(img, 'click', this.fetchIconList, this)
|
||||
|
@ -555,7 +555,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
const el = L.DomUtil.create(
|
||||
'span',
|
||||
'',
|
||||
L.DomUtil.create('div', 'umap-icon-choice', this.buttonsContainer)
|
||||
L.DomUtil.create('div', 'umap-pictogram-choice', this.buttonsContainer)
|
||||
)
|
||||
el.textContent = this.value()
|
||||
L.DomEvent.on(el, 'click', this.fetchIconList, this)
|
||||
|
@ -570,11 +570,11 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
)
|
||||
},
|
||||
|
||||
addIconPreview: function (pictogram) {
|
||||
const baseClass = 'umap-icon-choice',
|
||||
addIconPreview: function (pictogram, parent) {
|
||||
const baseClass = 'umap-pictogram-choice',
|
||||
value = pictogram.src,
|
||||
className = value === this.value() ? `${baseClass} selected` : baseClass,
|
||||
container = L.DomUtil.create('div', className, this.pictogramsContainer),
|
||||
container = L.DomUtil.create('div', className, parent),
|
||||
img = L.DomUtil.create('img', '', container)
|
||||
img.src = value
|
||||
if (pictogram.name && pictogram.attribution) {
|
||||
|
@ -602,7 +602,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
},
|
||||
|
||||
search: function (e) {
|
||||
const icons = [...this.parentNode.querySelectorAll('.umap-icon-choice')],
|
||||
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'
|
||||
|
@ -610,13 +610,36 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
})
|
||||
},
|
||||
|
||||
addCategory: function (category, items) {
|
||||
const parent = L.DomUtil.create(
|
||||
'div',
|
||||
'umap-pictogram-category',
|
||||
this.pictogramsContainer
|
||||
),
|
||||
title = L.DomUtil.add('h6', '', parent, category),
|
||||
grid = L.DomUtil.create('div', 'umap-pictogram-grid', parent)
|
||||
for (let item of items) {
|
||||
this.addIconPreview(item, grid)
|
||||
}
|
||||
},
|
||||
|
||||
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)
|
||||
for (const idx in data.pictogram_list) {
|
||||
this.addIconPreview(data.pictogram_list[idx])
|
||||
const categories = {}
|
||||
let category
|
||||
for (const props of data.pictogram_list) {
|
||||
category = props.category || L._('Generic')
|
||||
categories[category] = categories[category] || []
|
||||
categories[category].push(props)
|
||||
}
|
||||
const sorted = Object.entries(categories).toSorted(([a], [b]) =>
|
||||
L.Util.naturalSort(a, b)
|
||||
)
|
||||
for (let [category, items] of sorted) {
|
||||
this.addCategory(category, items)
|
||||
}
|
||||
const closeButton = L.DomUtil.createButton(
|
||||
'button action-button',
|
||||
|
|
Loading…
Reference in a new issue