-
Tomi Valentová authoredTomi Valentová authored
blocks.py 7.03 KiB
import json
from uuid import uuid4
from django.forms.utils import ErrorList
from django.utils.text import slugify
from wagtail import blocks
from wagtail.blocks.struct_block import StructBlockValidationError
from wagtail.images.blocks import ImageChooserBlock
from .const import (
DEFAULT_MAP_STYLE,
MAP_STYLES,
SUPPORTED_FEATURE_TYPES,
TILE_SERVER_CONFIG,
)
from .validation import validators
class MapPointBlock(blocks.StructBlock):
lat = blocks.DecimalBlock(label="Zeměpisná šířka", help_text="Např. 50.04075")
lon = blocks.DecimalBlock(label="Zeměpisná délka", help_text="Např. 15.77659")
hex_color = blocks.CharBlock(
label="Barva špendlíku (HEX)",
help_text="Zadejte barvu pomocí HEX notace (bez # na začátku).",
default="000000",
)
zoom = blocks.IntegerBlock(
label="Výchozí zoom", min_value=1, max_value=18, default=15
)
style = blocks.ChoiceBlock(
choices=MAP_STYLES, label="Styl", default=DEFAULT_MAP_STYLE
)
height = blocks.IntegerBlock(label="Výška v px", min_value=100, max_value=1000)
class Meta:
label = "Mapa se špendlíkem"
template = "maps_utils/blocks/map_point.html"
icon = "thumbtack"
group = "2. Obrázky"
def get_context(self, value, parent_context=None):
context = super().get_context(value, parent_context)
feature_id = str(uuid4())
context["js_map"] = {
"tile_server_config": json.dumps(TILE_SERVER_CONFIG),
"geojson": json.dumps(
[
{
"type": "FeatureCollection",
"properties": {
"slug": feature_id,
"title": None,
"collectionTitle": None,
"collectionDescription": None,
},
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
float(value["lon"]),
float(value["lat"]),
],
},
"properties": {
"id": feature_id,
"slug": feature_id,
"title": None,
"description": None,
"collectionTitle": None,
"collectionDescription": None,
"image": None,
"color": value["hex_color"],
},
},
],
}
]
),
}
return context
class MapFeatureBlock(blocks.StructBlock):
title = blocks.CharBlock(label="Titulek", required=True)
description = blocks.TextBlock(label="Popisek", required=False)
geojson = blocks.TextBlock(
label="Geodata",
help_text="Vložte surový GeoJSON objekt typu 'Feature'. Vyrobit jej můžete např. pomocí online služby geojson.io. Pokud u objektu poskytnete properties 'title' a 'description', zobrazí se jak na mapě, tak i v detailu.",
required=True,
)
image = ImageChooserBlock(label="Obrázek", required=False)
link = blocks.URLBlock(label="Odkaz", required=False)
hex_color = blocks.CharBlock(
label="Barva (HEX)",
help_text="Zadejte barvu pomocí HEX notace (bez # na začátku).",
default="000000",
)
class Meta:
label = "Položka mapové kolekce"
icon = "list-ul"
def clean(self, value):
errors = {}
if value["geojson"]:
try:
value["geojson"] = validators.normalize_geojson_feature(
value["geojson"], allowed_types=SUPPORTED_FEATURE_TYPES
)
except ValueError as exc:
print(exc)
errors["geojson"] = ErrorList(str(exc))
if errors:
raise StructBlockValidationError(errors)
return super().clean(value)
class MapFeatureCollectionBlock(blocks.StructBlock):
features = blocks.ListBlock(MapFeatureBlock(required=True), label="Součásti")
zoom = blocks.IntegerBlock(
label="Výchozí zoom", min_value=1, max_value=18, default=15
)
style = blocks.ChoiceBlock(
choices=MAP_STYLES, label="Styl", default=DEFAULT_MAP_STYLE
)
height = blocks.IntegerBlock(label="Výška v px", min_value=100, max_value=1000)
class Meta:
label = "Mapová kolekce"
template = "maps_utils/blocks/map_feature_collection.html"
icon = "site"
group = "2. Obrázky"
def get_context(self, value, parent_context=None):
def _geojson_feature_with_props(feature_id, feature):
fwp = json.loads(feature["geojson"])
fwp["properties"].update(
{
"id": feature_id,
"slug": f"0-{feature_id}-{slugify(feature['title'])}",
# Individual features are suppressed to emulate collection-like style.
"title": None,
"description": None,
"collectionTitle": feature["title"],
"collectionDescription": feature["description"],
"image": feature["image"]
.get_rendition("fill-1200x675|jpegquality-80")
.url
if feature["image"]
else None,
"link": feature["link"],
"color": feature["hex_color"],
}
)
return fwp
features = [
_geojson_feature_with_props(i, f) for i, f in enumerate(value["features"])
]
context = super().get_context(value, parent_context)
context["js_map"] = {
"tile_server_config": json.dumps(TILE_SERVER_CONFIG),
"geojson": json.dumps(
[
# Each feature dumped as individual collection to make things consistent.
{
"type": "FeatureCollection",
"properties": {
"slug": f"{f['properties']['id']}-{slugify(f['properties']['collectionTitle'])}",
"collectionTitle": f["properties"]["collectionTitle"],
"collectionDescription": f["properties"][
"collectionDescription"
],
"image": f["properties"]["image"],
},
"features": [f],
}
for f in features
]
),
}
return context