Browse Source

feat(models): add center and zoom levels' config to the map

main
Jérôme Lebleu 8 months ago
parent
commit
b36fde1df5
  1. 2
      tests/factories.py
  2. 35
      tests/test_admin.py
  3. 2
      tests/test_api.py
  4. 25
      tests/test_blocks.py
  5. 23
      wagtail_maps/admin.py
  6. 22
      wagtail_maps/blocks.py
  7. 34
      wagtail_maps/models.py

2
tests/factories.py

@ -16,6 +16,8 @@ class PointFactory(DjangoModelFactory): @@ -16,6 +16,8 @@ class PointFactory(DjangoModelFactory):
class MapFactory(DjangoModelFactory):
name = factory.Sequence(lambda n: "Map #%d" % n)
center_latitude = factory.Faker('latitude')
center_longitude = factory.Faker('longitude')
points = factory.RelatedFactoryList(PointFactory, 'map', size=3)
class Meta:

35
tests/test_admin.py

@ -43,6 +43,9 @@ class TestMapAdminViews: @@ -43,6 +43,9 @@ class TestMapAdminViews:
data = nested_form_data(
{
'name': "Map example",
'center_latitude': '50.9523',
'center_longitude': '1.8689',
'min_zoom': '3',
'points': inline_formset(
[
{
@ -70,6 +73,8 @@ class TestMapAdminViews: @@ -70,6 +73,8 @@ class TestMapAdminViews:
data = nested_form_data(
{
'name': "Map example",
'center_latitude': '50.9523',
'center_longitude': '1.8689',
'points': inline_formset(
[
{
@ -87,3 +92,33 @@ class TestMapAdminViews: @@ -87,3 +92,33 @@ class TestMapAdminViews:
assert response.status_code == 200
formset = response.context['form'].formsets['points']
assert set(formset.errors[0].keys()) == {'page_link', 'external_link'}
def test_create_min_max_zoom_error(self, admin_client):
data = nested_form_data(
{
'name': "Map example",
'center_latitude': '50.9523',
'center_longitude': '1.8689',
'min_zoom': '3',
'max_zoom': '2',
'points': inline_formset(
[
{
'title': "Foo",
'latitude': '50.9523',
'longitude': '1.8689',
}
]
),
}
)
response = admin_client.post(self.create_url, data)
assert response.status_code == 200
form = response.context['form']
assert set(form.errors.keys()) == {'min_zoom', 'max_zoom'}
data['min_zoom'] = '0'
response = admin_client.post(self.create_url, data)
assert response.status_code == 200
form = response.context['form']
assert set(form.errors.keys()) == {'min_zoom'}

2
tests/test_api.py

@ -16,6 +16,8 @@ MAP_POINT_LON = '1.8689' @@ -16,6 +16,8 @@ MAP_POINT_LON = '1.8689'
def map_example(root_page):
return Map.objects.create(
name="Map example",
center_latitude=MAP_POINT_LAT,
center_longitude=MAP_POINT_LON,
points=[
Point(
title="Point 1",

25
tests/test_blocks.py

@ -31,21 +31,40 @@ class TestMapBlock: @@ -31,21 +31,40 @@ class TestMapBlock:
def test_render(self):
assertHTMLEqual(
self.render({'map': MapFactory().id}),
self.render(
{
'map': MapFactory(
center_latitude=0.0, center_longitude=1.0
).id
}
),
"""
<div class="map" data-map
data-map-api-url="/maps/api/v1/1/">
data-map-api-url="/maps/api/v1/1/"
data-map-center-lat="0.0000"
data-map-center-lng="1.0000">
</div>
""",
)
def test_render_with_attrs(self):
assertHTMLEqual(
self.render({'map': MapFactory().id, 'zoom': '1', 'height': '10'}),
self.render(
{
'map': MapFactory(
center_latitude=0.0, center_longitude=1.0, min_zoom=2
).id,
'zoom': '1',
'height': '10',
}
),
"""
<div class="map" data-map
data-map-api-url="/maps/api/v1/1/"
data-map-center-lat="0.0000"
data-map-center-lng="1.0000"
data-map-height="10"
data-map-min-zoom="2"
data-map-zoom="1">
</div>
""",

23
wagtail_maps/admin.py

@ -4,6 +4,7 @@ from wagtail.admin.edit_handlers import ( @@ -4,6 +4,7 @@ from wagtail.admin.edit_handlers import (
FieldPanel,
FieldRowPanel,
InlinePanel,
MultiFieldPanel,
PageChooserPanel,
)
from wagtail.contrib.modeladmin.options import ModelAdmin
@ -18,6 +19,28 @@ class MapAdmin(ModelAdmin): @@ -18,6 +19,28 @@ class MapAdmin(ModelAdmin):
panels = [
FieldPanel('name', classname='title'),
MultiFieldPanel(
[
FieldRowPanel(
[
FieldPanel('center_latitude', heading=_("Latitude")),
FieldPanel('center_longitude', heading=_("Longitude")),
]
)
],
heading=_("Center of the map"),
),
MultiFieldPanel(
[
FieldRowPanel(
[
FieldPanel('min_zoom', heading=_("Minimum")),
FieldPanel('max_zoom', heading=_("Maximum")),
]
)
],
heading=_("Zoom levels"),
),
InlinePanel(
'points',
panels=[

22
wagtail_maps/blocks.py

@ -6,6 +6,14 @@ from wagtail.core import blocks @@ -6,6 +6,14 @@ from wagtail.core import blocks
from wagtail.core.utils import resolve_model_string
def build_map_attrs(**config):
attrs = {}
for name, value in config.items():
if value not in (None, ''):
attrs[f'data-map-{name}'] = value
return attrs
class MapChooserBlock(blocks.ChooserBlock):
class Meta:
label = _("Map")
@ -50,8 +58,14 @@ class MapBlock(blocks.StructBlock): @@ -50,8 +58,14 @@ class MapBlock(blocks.StructBlock):
def get_context(self, value, **kwargs):
context = super().get_context(value, **kwargs)
context['attrs'] = {}
for name in ('height', 'zoom'):
if value.get(name):
context['attrs'][f'data-map-{name}'] = value[name]
context['attrs'] = build_map_attrs(
**{
'center-lat': value['map'].center_latitude,
'center-lng': value['map'].center_longitude,
'max-zoom': value['map'].max_zoom,
'min-zoom': value['map'].min_zoom,
'height': value.get('height'),
'zoom': value.get('zoom'),
}
)
return context

34
wagtail_maps/models.py

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.utils.translation import gettext
from django.utils.translation import gettext_lazy as _
@ -8,10 +9,38 @@ from wagtail.core.fields import RichTextField @@ -8,10 +9,38 @@ from wagtail.core.fields import RichTextField
from modelcluster.fields import ParentalKey
from modelcluster.models import ClusterableModel
zoom_validators = [
MinValueValidator(1),
MaxValueValidator(20),
]
class Map(ClusterableModel):
name = models.CharField(verbose_name=_("name"), max_length=30)
center_latitude = models.DecimalField(
verbose_name=_("center point's latitude"),
max_digits=7,
decimal_places=4,
)
center_longitude = models.DecimalField(
verbose_name=_("center point's longitude"),
max_digits=7,
decimal_places=4,
)
min_zoom = models.PositiveSmallIntegerField(
verbose_name=_("minimum zoom level"),
blank=True,
null=True,
validators=zoom_validators,
)
max_zoom = models.PositiveSmallIntegerField(
verbose_name=_("maximum zoom level"),
blank=True,
null=True,
validators=zoom_validators,
)
class Meta:
verbose_name = _("map")
verbose_name_plural = _("maps")
@ -19,6 +48,11 @@ class Map(ClusterableModel): @@ -19,6 +48,11 @@ class Map(ClusterableModel):
def __str__(self):
return self.name
def clean(self):
if self.min_zoom and self.max_zoom and self.min_zoom > self.max_zoom:
msg = gettext("Minimum zoom level must be smaller than maximum.")
raise ValidationError({'min_zoom': msg, 'max_zoom': msg})
class Point(models.Model):
title = models.CharField(verbose_name=_("title"), max_length=50)

Map all the world