Allow specifying custom edit handlers for snippets

pull/2115/merge
Mikalai Radchuk 2016-01-25 17:47:59 +03:00 zatwierdzone przez Matt Westcott
rodzic ca343e2358
commit 3f2f5665b0
12 zmienionych plików z 118 dodań i 9 usunięć

Wyświetl plik

@ -5,6 +5,7 @@ Changelog
~~~~~~~~~~~~~~~~
* The `Document` model can now be overridden using the new `WAGTAILDOCS_DOCUMENT_MODEL` setting (Alex Gleason)
* Snippets now support a custom `edit_handler` property (Mikalai Radchuk)
* Date/time pickers now respect the locale's 'first day of week' setting (Peter Quade)
* Refactored the way forms are constructed for the page editor, to allow custom forms to be used
* Notification message on publish now indicates whether the page is being published now or scheduled for publication in future (Chris Rogers)

Wyświetl plik

@ -102,6 +102,7 @@ Contributors
* Matt Fozard
* Chris Rogers
* Josh Schneier
* Mikalai Radchuk
Translators

Wyświetl plik

@ -1,5 +1,5 @@
Customising the page editing interface
======================================
Customising the editing interface
=================================
.. _customising_the_tabbed_interface:
@ -8,7 +8,7 @@ Customising the tabbed interface
.. versionadded:: 1.0
As standard, Wagtail organises panels into three tabs: 'Content', 'Promote' and 'Settings'. Depending on the requirements of your site, you may wish to customise this for specific page types - for example, adding an additional tab for sidebar content. This can be done by specifying an ``edit_handler`` property on the page model. For example:
As standard, Wagtail organises panels for pages into three tabs: 'Content', 'Promote' and 'Settings'. For snippets Wagtail puts all panels into one page. Depending on the requirements of your site, you may wish to customise this for specific page types or snippets - for example, adding an additional tab for sidebar content. This can be done by specifying an ``edit_handler`` attribute on the page or snippet model. For example:
.. code-block:: python

Wyświetl plik

@ -19,6 +19,7 @@ The `Document` model can now be overridden using the new `WAGTAILDOCS_DOCUMENT_M
Minor features
~~~~~~~~~~~~~~
* Snippets now support a custom ``edit_handler`` property; this can be used to implement a tabbed interface, for example. See :ref:`customising_the_tabbed_interface` (Mikalai Radchuk)
* Date/time pickers now respect the locale's 'first day of week' setting (Peter Quade)
* Refactored the way forms are constructed for the page editor, to allow custom forms to be used
* Notification message on publish now indicates whether the page is being published now or scheduled for publication in future (Chris Rogers)

Wyświetl plik

@ -706,6 +706,15 @@
"url": "http://www.example.com"
}
},
{
"pk": 1,
"model": "tests.advertwithtabbedinterface",
"fields": {
"text": "test_advert",
"url": "http://www.example.com",
"something_else": "Model with tabbed interface"
}
},
{
"pk": 1,
"model": "wagtaildocs.Document",

Wyświetl plik

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('tests', '0023_mycustompage'),
]
operations = [
migrations.CreateModel(
name='AdvertWithTabbedInterface',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('url', models.URLField(null=True, blank=True)),
('text', models.CharField(max_length=255)),
('something_else', models.CharField(max_length=255)),
],
),
]

Wyświetl plik

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-01-28 12:53
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('tests', '0024_validatedpage'),
('tests', '0024_advertwithtabbedinterface'),
]
operations = [
]

Wyświetl plik

@ -371,6 +371,33 @@ class Advert(ClusterableModel):
register_snippet(Advert)
@python_2_unicode_compatible
class AdvertWithTabbedInterface(models.Model):
url = models.URLField(null=True, blank=True)
text = models.CharField(max_length=255)
something_else = models.CharField(max_length=255)
advert_panels = [
FieldPanel('url'),
FieldPanel('text'),
]
other_panels = [
FieldPanel('something_else'),
]
edit_handler = TabbedInterface([
ObjectList(advert_panels, heading='Advert'),
ObjectList(other_panels, heading='Other'),
])
def __str__(self):
return self.text
register_snippet(AdvertWithTabbedInterface)
class StandardIndex(Page):
""" Index for the site """
parent_page_types = [Page]

Wyświetl plik

@ -3,7 +3,7 @@
{% block titletag %}{% blocktrans with snippet_type_name=model_opts.verbose_name %}New {{ snippet_type_name }}{% endblocktrans %}{% endblock %}
{% block content %}
{% trans "New" as new_str %}
{% include "wagtailadmin/shared/header.html" with title=new_str subtitle=model_opts.verbose_name icon="snippet" %}
{% include "wagtailadmin/shared/header.html" with title=new_str subtitle=model_opts.verbose_name icon="snippet" tabbed=1 merged=1 %}
<form action="{% url 'wagtailsnippets:add' model_opts.app_label model_opts.model_name %}" method="POST">
{% csrf_token %}

Wyświetl plik

@ -3,7 +3,7 @@
{% block titletag %}{% blocktrans with snippet_type_name=model_opts.verbose_name %}Editing {{ snippet_type_name }} - {{ instance }}{% endblocktrans %}{% endblock %}
{% block content %}
{% trans "Editing" as editing_str %}
{% include "wagtailadmin/shared/header.html" with title=editing_str subtitle=instance icon="snippet" usage_object=instance %}
{% include "wagtailadmin/shared/header.html" with title=editing_str subtitle=instance icon="snippet" usage_object=instance tabbed=1 merged=1 %}
<form action="{% url 'wagtailsnippets:edit' model_opts.app_label model_opts.model_name instance.id %}" method="POST">
{% csrf_token %}

Wyświetl plik

@ -8,7 +8,7 @@ from django.core.exceptions import ImproperlyConfigured
from taggit.models import Tag
from wagtail.tests.utils import WagtailTestUtils
from wagtail.tests.testapp.models import Advert, SnippetChooserModel
from wagtail.tests.testapp.models import Advert, SnippetChooserModel, AdvertWithTabbedInterface
from wagtail.tests.snippets.models import (
AlphaSnippet, ZuluSnippet, RegisterDecorator, RegisterFunction, SearchableSnippet
)
@ -131,6 +131,19 @@ class TestSnippetCreateView(TestCase, WagtailTestUtils):
response = self.get()
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailsnippets/snippets/create.html')
self.assertNotContains(response, '<ul class="tab-nav merged">')
self.assertNotContains(response, '<a href="#advert" class="active">Advert</a>', html=True)
self.assertNotContains(response, '<a href="#other" class="">Other</a>', html=True)
def test_snippet_with_tabbed_interface(self):
response = self.client.get(reverse('wagtailsnippets:add',
args=('tests', 'advertwithtabbedinterface')))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailsnippets/snippets/create.html')
self.assertContains(response, '<ul class="tab-nav merged">')
self.assertContains(response, '<a href="#advert" class="active">Advert</a>', html=True)
self.assertContains(response, '<a href="#other" class="">Other</a>', html=True)
def test_create_invalid(self):
response = self.post(post_data={'foo': 'bar'})
@ -169,6 +182,7 @@ class TestSnippetEditView(TestCase, WagtailTestUtils):
def setUp(self):
self.test_snippet = Advert.objects.get(id=1)
self.test_snippet_with_tabbed_interface = AdvertWithTabbedInterface.objects.get(id=1)
self.login()
def get(self, params={}):
@ -185,6 +199,19 @@ class TestSnippetEditView(TestCase, WagtailTestUtils):
response = self.get()
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailsnippets/snippets/edit.html')
self.assertNotContains(response, '<ul class="tab-nav merged">')
self.assertNotContains(response, '<a href="#advert" class="active">Advert</a>', html=True)
self.assertNotContains(response, '<a href="#other" class="">Other</a>', html=True)
def test_snippet_with_tabbed_interface(self):
reverse_args = ('tests', 'advertwithtabbedinterface', self.test_snippet_with_tabbed_interface.id)
response = self.client.get(reverse('wagtailsnippets:edit', args=reverse_args))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailsnippets/snippets/edit.html')
self.assertContains(response, '<ul class="tab-nav merged">')
self.assertContains(response, '<a href="#advert" class="active">Advert</a>', html=True)
self.assertContains(response, '<a href="#other" class="">Other</a>', html=True)
def test_non_existant_model(self):
response = self.client.get(reverse('wagtailsnippets:edit', args=('tests', 'foo', self.test_snippet.id)))

Wyświetl plik

@ -40,10 +40,14 @@ SNIPPET_EDIT_HANDLERS = {}
def get_snippet_edit_handler(model):
if model not in SNIPPET_EDIT_HANDLERS:
panels = extract_panel_definitions_from_model_class(model)
edit_handler = ObjectList(panels).bind_to_model(model)
if hasattr(model, 'edit_handler'):
# use the edit handler specified on the page class
edit_handler = model.edit_handler
else:
panels = extract_panel_definitions_from_model_class(model)
edit_handler = ObjectList(panels)
SNIPPET_EDIT_HANDLERS[model] = edit_handler
SNIPPET_EDIT_HANDLERS[model] = edit_handler.bind_to_model(model)
return SNIPPET_EDIT_HANDLERS[model]