diff --git a/docs/core_components/pages/editing_api.rst b/docs/core_components/pages/editing_api.rst index 3c5c790d0..a228421ea 100644 --- a/docs/core_components/pages/editing_api.rst +++ b/docs/core_components/pages/editing_api.rst @@ -376,6 +376,40 @@ For more on ``django-modelcluster``, visit `the django-modelcluster github proje .. _the django-modelcluster github project page: https://github.com/torchbox/django-modelcluster +.. _customising_the_tabbed_interface: + +Customising the tabbed interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 0.9 + +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: + +.. code-block:: python + + from wagtail.wagtailadmin.edit_handlers import TabbedInterface, ObjectList + + class BlogPage(Page): + # field definitions omitted + + BlogPage.content_panels = [ + FieldPanel('title', classname="full title"), + FieldPanel('date'), + FieldPanel('body', classname="full"), + ] + BlogPage.sidebar_content_panels = [ + SnippetChooserPanel('advert', Advert), + InlinePanel('related_links', label="Related links"), + ] + + BlogPage.edit_handler = TabbedInterface([ + ObjectList(BlogPage.content_panels, heading='Content'), + ObjectList(BlogPage.sidebar_content_panels, heading='Sidebar content'), + ObjectList(BlogPage.promote_panels, heading='Promote'), + ObjectList(BlogPage.settings_panels, heading='Settings', classname="settings"), + ]) + + .. _extending_wysiwyg: Extending the WYSIWYG Editor (hallo.js) diff --git a/wagtail/tests/models.py b/wagtail/tests/models.py index 59c20d4e5..bb6f5f007 100644 --- a/wagtail/tests/models.py +++ b/wagtail/tests/models.py @@ -14,7 +14,7 @@ from modelcluster.tags import ClusterTaggableManager from wagtail.wagtailcore.models import Page, Orderable from wagtail.wagtailcore.fields import RichTextField -from wagtail.wagtailadmin.edit_handlers import FieldPanel, MultiFieldPanel, InlinePanel, PageChooserPanel +from wagtail.wagtailadmin.edit_handlers import FieldPanel, MultiFieldPanel, InlinePanel, PageChooserPanel, TabbedInterface, ObjectList from wagtail.wagtailimages.edit_handlers import ImageChooserPanel from wagtail.wagtaildocs.edit_handlers import DocumentChooserPanel from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField @@ -393,15 +393,27 @@ class StandardIndex(Page): parent_page_types = [] +# A custom panel setup where all Promote fields are placed in the Content tab instead; +# we use this to test that the 'promote' tab is left out of the output when empty StandardIndex.content_panels = [ FieldPanel('title', classname="full title"), + FieldPanel('seo_title'), + FieldPanel('slug'), InlinePanel('advert_placements', label="Adverts"), ] +StandardIndex.promote_panels = [] class StandardChild(Page): pass +# Test overriding edit_handler with a custom one +StandardChild.edit_handler = TabbedInterface([ + ObjectList(StandardChild.content_panels, heading='Content'), + ObjectList(StandardChild.promote_panels, heading='Promote'), + ObjectList(StandardChild.settings_panels, heading='Settings', classname='settings'), + ObjectList([], heading='Dinosaurs'), +]) class BusinessIndex(Page): """ Can be placed anywhere, can only have Business children """ diff --git a/wagtail/wagtailadmin/tests/test_pages_views.py b/wagtail/wagtailadmin/tests/test_pages_views.py index de8b2fb2b..be6cc6a26 100644 --- a/wagtail/wagtailadmin/tests/test_pages_views.py +++ b/wagtail/wagtailadmin/tests/test_pages_views.py @@ -158,6 +158,27 @@ class TestPageCreation(TestCase, WagtailTestUtils): def test_create_simplepage(self): response = self.client.get(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id))) self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Content') + self.assertContains(response, 'Promote') + + def test_create_page_without_promote_tab(self): + """ + Test that the Promote tab is not rendered for page classes that define it as empty + """ + response = self.client.get(reverse('wagtailadmin_pages_create', args=('tests', 'standardindex', self.root_page.id))) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Content') + self.assertNotContains(response, 'Promote') + + def test_create_page_with_custom_tabs(self): + """ + Test that custom edit handlers are rendered + """ + response = self.client.get(reverse('wagtailadmin_pages_create', args=('tests', 'standardchild', self.root_page.id))) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Content') + self.assertContains(response, 'Promote') + self.assertContains(response, 'Dinosaurs') def test_create_simplepage_bad_permissions(self): # Remove privileges from user diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index a9c5c6fe5..f4c5c675d 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -707,11 +707,24 @@ PAGE_EDIT_HANDLERS = {} def get_page_edit_handler(page_class): if page_class not in PAGE_EDIT_HANDLERS: - PAGE_EDIT_HANDLERS[page_class] = TabbedInterface([ - ObjectList(page_class.content_panels, heading='Content'), - ObjectList(page_class.promote_panels, heading='Promote'), - ObjectList(page_class.settings_panels, heading='Settings', classname="settings") - ]).bind_to_model(page_class) + if hasattr(page_class, 'edit_handler'): + # use the edit handler specified on the page class + edit_handler = page_class.edit_handler + else: + # construct a TabbedInterface made up of content_panels, promote_panels + # and settings_panels, skipping any which are empty + tabs = [] + + if page_class.content_panels: + tabs.append(ObjectList(page_class.content_panels, heading='Content')) + if page_class.promote_panels: + tabs.append(ObjectList(page_class.promote_panels, heading='Promote')) + if page_class.settings_panels: + tabs.append(ObjectList(page_class.settings_panels, heading='Settings', classname="settings")) + + edit_handler = TabbedInterface(tabs) + + PAGE_EDIT_HANDLERS[page_class] = edit_handler.bind_to_model(page_class) return PAGE_EDIT_HANDLERS[page_class]