kopia lustrzana https://github.com/wagtail/wagtail
Allow customization of preview device sizes
Co-authored-by: Bartosz Cieliński <bart@fullfatthings.com>pull/12414/head
rodzic
49f9ae3a96
commit
b38141ad82
|
@ -202,6 +202,12 @@ See also [django-treebeard](https://django-treebeard.readthedocs.io/en/latest/in
|
|||
|
||||
.. autoattribute:: preview_modes
|
||||
|
||||
.. autoattribute:: default_preview_mode
|
||||
|
||||
.. autoattribute:: preview_sizes
|
||||
|
||||
.. autoattribute:: default_preview_size
|
||||
|
||||
.. automethod:: serve_preview
|
||||
|
||||
.. automethod:: get_parent
|
||||
|
@ -576,6 +582,10 @@ Pages already include this mixin, so there is no need to add it.
|
|||
.. autoattribute:: preview_modes
|
||||
|
||||
.. autoattribute:: default_preview_mode
|
||||
|
||||
.. autoattribute:: preview_sizes
|
||||
|
||||
.. autoattribute:: default_preview_size
|
||||
|
||||
.. automethod:: is_previewable
|
||||
|
||||
|
|
|
@ -12,18 +12,25 @@
|
|||
>
|
||||
<div class="w-preview__sizes">
|
||||
{% block size_buttons %}
|
||||
<label class="w-preview__size-button">
|
||||
{% icon name="mobile-alt" %}
|
||||
<input type="radio" class="w-preview__proxy" name="preview-size" value="mobile" data-action="w-preview#togglePreviewSize" data-w-preview-target="size" data-device-width="375" data-default-size checked aria-label="{% trans 'Preview in mobile size' %}" />
|
||||
</label>
|
||||
<label class="w-preview__size-button">
|
||||
{% icon name="tablet-alt" %}
|
||||
<input type="radio" class="w-preview__proxy" name="preview-size" value="tablet" data-action="w-preview#togglePreviewSize" data-w-preview-target="size" data-device-width="768" aria-label="{% trans 'Preview in tablet size' %}" />
|
||||
</label>
|
||||
<label class="w-preview__size-button">
|
||||
{% icon name="desktop" %}
|
||||
<input type="radio" class="w-preview__proxy" name="preview-size" value="desktop" data-action="w-preview#togglePreviewSize" data-w-preview-target="size" data-device-width="1280" aria-label="{% trans 'Preview in desktop size' %}" />
|
||||
</label>
|
||||
{% for size in object.preview_sizes %}
|
||||
<label class="w-preview__size-button">
|
||||
{% icon name=size.icon %}
|
||||
<input
|
||||
type="radio"
|
||||
class="w-preview__proxy"
|
||||
name="preview-size"
|
||||
value="{{ size.name }}"
|
||||
data-action="w-preview#togglePreviewSize"
|
||||
data-w-preview-target="size"
|
||||
aria-label="{{ size.label }}"
|
||||
data-device-width="{{ size.device_width|stringformat:'s' }}"
|
||||
{% if object.default_preview_size == size.name %}
|
||||
data-default-size
|
||||
checked
|
||||
{% endif %}
|
||||
/>
|
||||
</label>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block new_tab_button %}
|
||||
|
|
|
@ -9,6 +9,7 @@ from freezegun import freeze_time
|
|||
from wagtail.admin.views.pages.preview import PreviewOnEdit
|
||||
from wagtail.models import Page
|
||||
from wagtail.test.testapp.models import (
|
||||
CustomPreviewSizesPage,
|
||||
EventCategory,
|
||||
MultiPreviewModesPage,
|
||||
SimplePage,
|
||||
|
@ -415,6 +416,26 @@ class TestPreview(WagtailTestUtils, TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, template)
|
||||
|
||||
def test_preview_sizes(self):
|
||||
page = CustomPreviewSizesPage(title="Custom preview size")
|
||||
self.home_page.add_child(instance=page)
|
||||
edit_url = reverse("wagtailadmin_pages:edit", args=(page.id,))
|
||||
|
||||
response = self.client.get(edit_url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
soup = self.get_soup(response.content)
|
||||
|
||||
radios = soup.select('input[type="radio"][name="preview-size"]')
|
||||
self.assertEqual(len(radios), 2)
|
||||
|
||||
self.assertEqual("412", radios[0]["data-device-width"])
|
||||
self.assertEqual("Custom mobile preview", radios[0]["aria-label"])
|
||||
self.assertFalse(radios[0].has_attr("checked"))
|
||||
|
||||
self.assertEqual("1280", radios[1]["data-device-width"])
|
||||
self.assertEqual("Original desktop", radios[1]["aria-label"])
|
||||
self.assertTrue(radios[1].has_attr("checked"))
|
||||
|
||||
|
||||
class TestEnablePreview(WagtailTestUtils, TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
@ -805,6 +805,26 @@ class PreviewableMixin:
|
|||
full_url = property(get_full_url)
|
||||
|
||||
DEFAULT_PREVIEW_MODES = [("", _("Default"))]
|
||||
DEFAULT_PREVIEW_SIZES = [
|
||||
{
|
||||
"name": "mobile",
|
||||
"icon": "mobile-alt",
|
||||
"device_width": 375,
|
||||
"label": _("Preview in mobile size"),
|
||||
},
|
||||
{
|
||||
"name": "tablet",
|
||||
"icon": "tablet-alt",
|
||||
"device_width": 768,
|
||||
"label": _("Preview in tablet size"),
|
||||
},
|
||||
{
|
||||
"name": "desktop",
|
||||
"icon": "desktop",
|
||||
"device_width": 1280,
|
||||
"label": _("Preview in desktop size"),
|
||||
},
|
||||
]
|
||||
|
||||
@property
|
||||
def preview_modes(self):
|
||||
|
@ -828,6 +848,43 @@ class PreviewableMixin:
|
|||
"""
|
||||
return self.preview_modes[0][0]
|
||||
|
||||
@property
|
||||
def preview_sizes(self):
|
||||
"""
|
||||
Returns a list of dictionaries, each representing a preview size option for this object.
|
||||
Override this property to customize the preview sizes.
|
||||
Each dictionary in the list should include the following keys:
|
||||
|
||||
- `name`: A string representing the internal name of the preview size.
|
||||
- `icon`: A string specifying the icon's name for the preview size button.
|
||||
- `device_width`: An integer indicating the device's width in pixels.
|
||||
- `label`: A string for the aria label on the preview size button.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@property
|
||||
def preview_sizes(self):
|
||||
return [
|
||||
{
|
||||
"name": "mobile",
|
||||
"icon": "mobile-icon",
|
||||
"device_width": 320,
|
||||
"label": "Preview in mobile size"
|
||||
},
|
||||
# Add more preview size dictionaries as needed.
|
||||
]
|
||||
"""
|
||||
return PreviewableMixin.DEFAULT_PREVIEW_SIZES
|
||||
|
||||
@property
|
||||
def default_preview_size(self):
|
||||
"""
|
||||
The default preview size name to use in live preview.
|
||||
Defaults to ``"mobile"``, which is the first one defined in ``preview_sizes``.
|
||||
If ``preview_sizes`` is empty, an ``IndexError`` will be raised.
|
||||
"""
|
||||
return self.preview_sizes[0]["name"]
|
||||
|
||||
def is_previewable(self):
|
||||
"""Returns ``True`` if at least one preview mode is specified in ``preview_modes``."""
|
||||
return bool(self.preview_modes)
|
||||
|
|
|
@ -63,10 +63,12 @@ from wagtail.test.testapp.models import (
|
|||
AdvertWithCustomPrimaryKey,
|
||||
AdvertWithCustomUUIDPrimaryKey,
|
||||
AdvertWithTabbedInterface,
|
||||
CustomPreviewSizesModel,
|
||||
DraftStateCustomPrimaryKeyModel,
|
||||
DraftStateModel,
|
||||
FullFeaturedSnippet,
|
||||
MultiPreviewModesModel,
|
||||
PreviewableModel,
|
||||
RevisableChildModel,
|
||||
RevisableModel,
|
||||
SnippetChooserModel,
|
||||
|
@ -1991,6 +1993,49 @@ class TestSnippetEditView(BaseTestSnippetEditView):
|
|||
html=True,
|
||||
)
|
||||
|
||||
def test_previewable_snippet(self):
|
||||
self.test_snippet = PreviewableModel.objects.create(
|
||||
text="Preview-enabled snippet"
|
||||
)
|
||||
response = self.get()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
soup = self.get_soup(response.content)
|
||||
|
||||
radios = soup.select('input[type="radio"][name="preview-size"]')
|
||||
self.assertEqual(len(radios), 3)
|
||||
|
||||
self.assertEqual(
|
||||
[
|
||||
"Preview in mobile size",
|
||||
"Preview in tablet size",
|
||||
"Preview in desktop size",
|
||||
],
|
||||
[radio["aria-label"] for radio in radios],
|
||||
)
|
||||
|
||||
self.assertEqual("375", radios[0]["data-device-width"])
|
||||
self.assertTrue(radios[0].has_attr("checked"))
|
||||
|
||||
def test_custom_preview_sizes(self):
|
||||
self.test_snippet = CustomPreviewSizesModel.objects.create(
|
||||
text="Preview-enabled with custom sizes",
|
||||
)
|
||||
|
||||
response = self.get()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
soup = self.get_soup(response.content)
|
||||
|
||||
radios = soup.select('input[type="radio"][name="preview-size"]')
|
||||
self.assertEqual(len(radios), 2)
|
||||
|
||||
self.assertEqual("412", radios[0]["data-device-width"])
|
||||
self.assertEqual("Custom mobile preview", radios[0]["aria-label"])
|
||||
self.assertFalse(radios[0].has_attr("checked"))
|
||||
|
||||
self.assertEqual("1280", radios[1]["data-device-width"])
|
||||
self.assertEqual("Original desktop", radios[1]["aria-label"])
|
||||
self.assertTrue(radios[1].has_attr("checked"))
|
||||
|
||||
|
||||
class TestEditTabbedSnippet(BaseTestSnippetEditView):
|
||||
def setUp(self):
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
# Generated by Django 5.0.9 on 2024-10-16 05:17
|
||||
|
||||
import django.db.models.deletion
|
||||
import wagtail.models
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("tests", "0043_customimage_description"),
|
||||
("wagtailcore", "0094_alter_page_locale"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="CustomPreviewSizesModel",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("text", models.TextField()),
|
||||
],
|
||||
bases=(wagtail.models.PreviewableMixin, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="CustomPreviewSizesPage",
|
||||
fields=[
|
||||
(
|
||||
"page_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="wagtailcore.page",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
bases=("wagtailcore.page",),
|
||||
),
|
||||
]
|
|
@ -215,6 +215,31 @@ class MultiPreviewModesPage(Page):
|
|||
return super().get_preview_template(request, mode_name)
|
||||
|
||||
|
||||
class CustomPreviewSizesPage(Page):
|
||||
template = "tests/simple_page.html"
|
||||
|
||||
@property
|
||||
def preview_sizes(self):
|
||||
return [
|
||||
{
|
||||
"name": "custom-mobile",
|
||||
"icon": "mobile-alt",
|
||||
"device_width": 412,
|
||||
"label": "Custom mobile preview",
|
||||
},
|
||||
{
|
||||
"name": "desktop",
|
||||
"icon": "desktop",
|
||||
"device_width": 1280,
|
||||
"label": "Original desktop",
|
||||
},
|
||||
]
|
||||
|
||||
@property
|
||||
def default_preview_size(self):
|
||||
return "desktop"
|
||||
|
||||
|
||||
# Page with Excluded Fields when copied
|
||||
class PageWithExcludedCopyField(Page):
|
||||
content = models.TextField()
|
||||
|
@ -1083,6 +1108,34 @@ class PreviewableModel(PreviewableMixin, ClusterableModel):
|
|||
register_snippet(PreviewableModel)
|
||||
|
||||
|
||||
class CustomPreviewSizesModel(PreviewableMixin, models.Model):
|
||||
text = models.TextField()
|
||||
|
||||
@property
|
||||
def preview_sizes(self):
|
||||
return [
|
||||
{
|
||||
"name": "custom-mobile",
|
||||
"icon": "mobile-alt",
|
||||
"device_width": 412,
|
||||
"label": "Custom mobile preview",
|
||||
},
|
||||
{
|
||||
"name": "desktop",
|
||||
"icon": "desktop",
|
||||
"device_width": 1280,
|
||||
"label": "Original desktop",
|
||||
},
|
||||
]
|
||||
|
||||
@property
|
||||
def default_preview_size(self):
|
||||
return "desktop"
|
||||
|
||||
|
||||
register_snippet(CustomPreviewSizesModel)
|
||||
|
||||
|
||||
class MultiPreviewModesModel(PreviewableMixin, RevisionMixin, models.Model):
|
||||
text = models.TextField()
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue