def setUp(self): # a custom tabbed interface for EventPage self.EventPageTabbedInterface = TabbedInterface([ ObjectList([ FieldPanel('title', widget=forms.Textarea), FieldPanel('date_from'), FieldPanel('date_to'), ], heading='Event details', classname="shiny"), ObjectList([ InlinePanel('speakers', label="Speakers"), ], heading='Speakers'), ]).bind_to_model(EventPage)
def setUp(self): self.request = RequestFactory().get('/') user = AnonymousUser() # technically, Anonymous users cannot access the admin self.request.user = user # a custom tabbed interface for EventPage self.event_page_tabbed_interface = TabbedInterface([ ObjectList([ FieldPanel('title', widget=forms.Textarea), FieldPanel('date_from'), FieldPanel('date_to'), ], heading='Event details', classname="shiny"), ObjectList([ InlinePanel('speakers', label="Speakers"), ], heading='Speakers'), ]).bind_to(model=EventPage, request=self.request)
class StreamPage(ThemeablePage): body = article_fields.BodyField() search_fields = Page.search_fields + [ index.SearchField('body'), ] content_panels = Page.content_panels + [StreamFieldPanel('body')] style_panels = ThemeablePage.style_panels edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(style_panels, heading='Page Style Options'), ObjectList(Page.promote_panels, heading='Promote'), ObjectList(Page.settings_panels, heading='Settings', classname="settings"), ])
class Person(models.Model): """model used to test model.edit_handlers usage in get_edit_handler""" first_name = models.CharField(max_length=255) last_name = models.CharField(max_length=255) phone_number = models.CharField(max_length=255) address = models.CharField(max_length=255) panels = [ FieldPanel('first_name'), FieldPanel('last_name'), FieldPanel('phone_number'), ] edit_handler = TabbedInterface([ ObjectList(panels), ]) def __str__(self): return self.first_name
class EventIndexPage(RoutablePageMixin, FixUrlMixin, Page): """Archive of all events""" title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_("The page title as you'd like it to be seen by the public"), ) title_translated = TranslatedField("title", "title_en") content_panels = Page.content_panels + [FieldPanel("intro", classname="full")] subpage_types = ["home.Event"] content_panels_sk = Page.content_panels content_panels_en = [ FieldPanel("title_en", classname="full title"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) @route(r"^(\d+)/(.+)/") def event_with_id_in_url(self, request, event_id, slug): event = Event.objects.get(event_id=event_id) if slug == event.slug: return event.serve(request) return redirect(event.get_url(request)) @route(r"^json/$") def json_index(self, request): return JsonResponse(ArchiveQueryset().json()) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["header_festival"] = last_festival(self) context["events"] = ArchiveQueryset().events() # context["events_json"] = ArchiveQueryset().json() return context
class TranslationSettings(BaseSetting): watch_video_button_sk = models.TextField(blank=True) watch_video_button_en = models.TextField(blank=True) watch_video_button = TranslatedField( "watch_video_button_sk", "watch_video_button_en" ) buy_ticket_button_sk = models.TextField(blank=True) buy_ticket_button_en = models.TextField(blank=True) buy_ticket_button = TranslatedField("buy_ticket_button_sk", "buy_ticket_button_en") # Permanentka season_ticket_button_sk = models.TextField(blank=True) season_ticket_button_en = models.TextField(blank=True) season_ticket_button = TranslatedField( "season_ticket_button_sk", "season_ticket_button_en" ) season_ticket_url = models.URLField(blank=True) content_panels_sk = [ FieldPanel("watch_video_button_sk"), FieldPanel("buy_ticket_button_sk"), FieldPanel("season_ticket_button_sk"), FieldPanel("season_ticket_url"), ] content_panels_en = [ FieldPanel("watch_video_button_en"), FieldPanel("buy_ticket_button_en"), FieldPanel("season_ticket_button_en"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ] ) def save( self, force_insert=False, force_update=False, using=None, update_fields=None ): super().save(force_insert, force_update, using, update_fields) CloudFlare().purge_everything()
class People(Page): subpage_types = ['Person'] template = 'people.html' # Meta fields keywords = ClusterTaggableManager(through=PeopleTag, blank=True) # Meta panels meta_panels = [ MultiFieldPanel([ FieldPanel('seo_title'), FieldPanel('search_description'), FieldPanel('keywords'), ], heading='SEO'), ] # Settings panels settings_panels = [ FieldPanel('slug'), ] edit_handler = TabbedInterface([ ObjectList(Page.content_panels, heading='Content'), ObjectList(meta_panels, heading='Meta'), ObjectList(settings_panels, heading='Settings', classname='settings'), ]) class Meta: verbose_name_plural = 'People' def get_context(self, request): context = super().get_context(request) context['filters'] = self.get_filters() return context @property def people(self): return Person.objects.all().public().live().order_by('title') def get_filters(self): from ..topics.models import Topic return { 'topics': Topic.objects.live().public().order_by('title'), }
class NewsPage(Page): parent_page_types = ['vcssa.NewsIndexPage'] subpage_types = [] author = models.CharField(max_length=30, null=True, blank=True) date = models.DateTimeField(auto_now=True) cover_image = models.ForeignKey('wagtailimages.Image', null=True, on_delete=models.SET_NULL, related_name='+') intro = models.CharField(max_length=255, null=True, blank=True) body = RichTextField() tags = ClusterTaggableManager(through=NewsPageTag, blank=True) theme = models.ForeignKey(Theme, on_delete=models.SET_NULL, null=True, blank=False, related_name="news_page_theme", limit_choices_to={'type': "NEWS"}) content_panels = Page.content_panels + [ FieldPanel('author'), ImageChooserPanel('cover_image'), FieldPanel('intro'), FieldPanel('tags'), FieldPanel('body') ] theme_panels = [ FieldPanel('theme', widget=RadioSelectWithPicture), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(theme_panels, heading='Theme Setting'), ObjectList(Page.promote_panels, heading='Promote'), ObjectList(Page.settings_panels, heading='Settings', classname="settings"), ]) def get_context(self, request, *args, **kwargs): context = super().get_context(request) context['theme'] = self.theme.template_path return context
class Topics(BasePage): parent_page_types = ["home.HomePage"] subpage_types = ["Topic"] template = "topics.html" # Meta fields keywords = ClusterTaggableManager(through=TopicsTag, blank=True) # Meta panels meta_panels = [ MultiFieldPanel( [ FieldPanel("seo_title"), FieldPanel("search_description"), ImageChooserPanel("social_image"), FieldPanel("keywords"), ], heading="SEO", help_text=("Optional fields to override the default " "title and description for SEO purposes"), ) ] # Settings panels settings_panels = [FieldPanel("slug"), FieldPanel("show_in_menus")] edit_handler = TabbedInterface([ ObjectList(BasePage.content_panels, heading="Content"), ObjectList(meta_panels, heading="Meta"), ObjectList(settings_panels, heading="Settings", classname="settings"), ]) class Meta: verbose_name_plural = "Topics" @classmethod def can_create_at(cls, parent): # Allow only one instance of this page type return super().can_create_at(parent) and not cls.objects.exists() @property def topics(self): return Topic.published_objects.order_by("title")
class BlogIndexPage(SingletonMixin, PaginatorMixin, Page): title_de = models.CharField(max_length=255, blank=True) image = models.ForeignKey('wagtailimages.Image', blank=True, null=True, on_delete=models.SET_NULL, related_name='+') image_credit = RichTextField(blank=True) color = models.ForeignKey('core.Color', blank=True, null=True, on_delete=models.SET_NULL, related_name='+') trans_title = TranslatedTextField('title') trans_intro = TranslatedTextField('intro', note=True) content_panels = [ FieldPanel('title', classname="full title"), ] content_de_panels = [ FieldPanel('title_de', classname="full title"), ] promote_panels = Page.promote_panels + [ ImageChooserPanel('image'), FieldPanel('image_credit', classname='full'), SnippetChooserPanel('color'), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(content_de_panels, heading='Content DE'), ObjectList(promote_panels, heading='Promote'), ObjectList(Page.settings_panels, heading='Settings', classname="settings"), ]) subpage_types = ['blog.BlogPage']
def get_edit_handler_class(self): from .models import AbstractMainMenu, AbstractFlatMenu if hasattr(self.model, 'edit_handler'): edit_handler = self.model.edit_handler elif (( issubclass(self.model, AbstractMainMenu) and self.model.panels is not AbstractMainMenu.panels ) or ( issubclass(self.model, AbstractFlatMenu) and self.model.panels is not AbstractFlatMenu.panels )): edit_handler = ObjectList(self.model.panels) else: edit_handler = TabbedInterface([ ObjectList(self.model.content_panels, heading=_("Content")), ObjectList(self.model.settings_panels, heading=_("Settings"), classname="settings"), ]) return edit_handler.bind_to_model(self.model)
class SelectionGridPage(Page): body = StreamField([ ('heading_hero', HeroImageBlock()), ('selection_grid', blocks.ListBlock(GridItem)), ]) content_panels = Page.content_panels + [ StreamFieldPanel('body'), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(Page.promote_panels, heading='Promote'), ObjectList(Page.settings_panels, heading='Settings', classname="settings"), ]) api_fields = ('body', )
class FacebookModelMixin(Page): og_title = models.CharField( max_length=95, blank=True, null=True, verbose_name=_("Facebook title"), ) og_description = models.CharField( max_length=250, blank=True, null=True, verbose_name=_("Facebook description"), ) og_image = models.ForeignKey( get_image_model_string(), null=True, blank=True, on_delete=models.SET_NULL, related_name="+", verbose_name=_("Facebook image"), ) promote_panels = [ MultiFieldPanel( [ FieldPanel("og_title"), FieldPanel("og_description"), ImageChooserPanel("og_image"), ], heading="Facebook", ), FacebookPreviewPanel(heading="Facebook Preview"), ] edit_handler = TabbedInterface([ ObjectList(Page.content_panels, heading="Content"), ObjectList(Page.promote_panels + promote_panels, heading="Promote"), ]) class Meta: abstract = True
class Videos(Page): parent_page_types = ['home.HomePage'] subpage_types = ['Video'] template = 'videos.html' # Meta fields keywords = ClusterTaggableManager(through=VideosTag, blank=True) meta_panels = [ MultiFieldPanel( [ FieldPanel('seo_title'), FieldPanel('search_description'), FieldPanel('keywords'), ], heading='SEO', help_text= 'Optional fields to override the default title and description for SEO purposes' ), ] settings_panels = [ FieldPanel('slug'), FieldPanel('show_in_menus'), ] edit_handler = TabbedInterface([ ObjectList(Page.content_panels, heading='Content'), ObjectList(meta_panels, heading='Meta'), ObjectList(settings_panels, heading='Settings', classname='settings'), ]) class Meta: verbose_name_plural = 'Videos' @classmethod def can_create_at(cls, parent): # Allow only one instance of this page type return super().can_create_at(parent) and not cls.objects.exists() @property def videos(self): return Video.objects.live().public().order_by('title')
class ContactPage(Page): socials = ParentalManyToManyField('blog.Social', blank=True) body = StreamField([ ('heading', blocks.CharBlock(classname="full title")), ('paragraph', blocks.RichTextBlock()), ]) content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('socials', widget=forms.CheckboxSelectMultiple), ], heading="Socials linked in contact page"), StreamFieldPanel('body'), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ])
class StandardPage(Page): sub_title = models.CharField( blank=True, max_length=255, help_text='if a subtitle is used, entire title section of the page will be bigger') body = StreamField(StandardPageStreamBlock(required=False), blank=True) content_panels = Page.content_panels + [ FieldPanel('sub_title', classname='full'), StreamFieldPanel('body') ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(Page.promote_panels, heading='Page Configuration'), ]) class Meta: verbose_name = 'Standard Page'
class DonatePage(FixUrlMixin, Page): title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_("The page title as you'd like it to be seen by the public"), ) title_translated = TranslatedField("title", "title_en") body_sk = StreamField( [ ("heading", blocks.CharBlock(classname="title")), ("paragraph", blocks.RichTextBlock()), ] ) body_en = StreamField( [ ("heading", blocks.CharBlock(classname="title")), ("paragraph", blocks.RichTextBlock()), ] ) body = TranslatedField("body_sk", "body_en") content_panels_sk = Page.content_panels + [ StreamFieldPanel("body_sk"), ] content_panels_en = [ FieldPanel("title_en", classname="full title"), StreamFieldPanel("body_en"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["header_festival"] = last_festival(self) return context
class ServicePage(Page): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) steps = RichTextField(features=WYSIWYG_FEATURES, verbose_name='Write out the steps a resident needs to take to use the service') dynamic_content = StreamField( [ ('map_block', custom_blocks.SnippetChooserBlockWithAPIGoodness('base.Map', icon='site')), ('what_do_i_do_with_block', custom_blocks.WhatDoIDoWithBlock()), ('collection_schedule_block', custom_blocks.CollectionScheduleBlock()), ('recollect_block', custom_blocks.RecollectBlock()), ], verbose_name='Add any forms, maps, apps, or content that will help the resident use the service', ) additional_content = RichTextField(features=WYSIWYG_FEATURES, verbose_name='Write any additional content describing the service', blank=True) topic = models.ForeignKey( 'base.Topic', on_delete=models.PROTECT, related_name='services', ) image = models.ForeignKey(TranslatedImage, null=True, on_delete=models.SET_NULL, related_name='+') parent_page_types = ['base.HomePage'] subpage_types = [] base_form_class = custom_forms.ServicePageForm content_panels = [ FieldPanel('topic'), FieldPanel('title'), ImageChooserPanel('image'), FieldPanel('steps'), StreamFieldPanel('dynamic_content'), FieldPanel('additional_content'), InlinePanel('contacts', label='Contacts'), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(Page.promote_panels, heading='Promote'), # TODO: What should we do with the fields in settings? # ObjectList(Page.settings_panels, heading='Settings', classname='settings'), ])
def make_translated_interface( content_panels, settings_panels=None, other_panels=None ): panels = [] for code, name in settings.LANGUAGES: panels.append( ObjectList( [translate_panel(panel, code) for panel in content_panels], heading=name ) ) if settings_panels: panels.append( ObjectList( settings_panels, classname='settings', heading='Settings' ) ) if other_panels: panels += other_panels return TabbedInterface(panels)
class Menu(TranslatedPage): """ This model implements a menu indepent from the hierachic structure """ subpage_types = ['website.MenuItem'] parent_page_types = ['wagtailcore.Page'] content_panels = [ MultiFieldPanel([ FieldPanel('title'), FieldPanel('title_de'), ], heading=_('title')), ] settings_panels = [FieldPanel('slug')] edit_handler = TabbedInterface([ ObjectList(content_panels, heading=_('content')), ObjectList(settings_panels, heading=_('settings')), ]) is_creatable = False
class MetaModelMixin(TwitterModelMixin, FacebookModelMixin): promote_panels_fields = [ FacebookFieldPreviewPanel( [ FieldPanel("og_title"), FieldPanel("og_description"), ImageChooserPanel("og_image"), ], heading="Facebook", ), TwitterFieldPreviewPanel( [ FieldPanel("twitter_title"), FieldPanel("twitter_description"), ImageChooserPanel("twitter_image"), ], heading="Twitter", ), GoogleFieldPreviewPanel( [ FieldPanel("seo_title"), FieldPanel("search_description"), ], heading="Google", ), ] promote_panels = [ FacebookPreviewPanel(heading="Facebook Preview"), TwitterPreviewPanel(heading="Twitter Preview"), GooglePreviewPanel(heading="Google Preview"), ] edit_handler = TabbedInterface([ ObjectList(Page.content_panels, heading="Content"), ObjectList(promote_panels_fields, heading="Previews with fields"), ObjectList(promote_panels, heading="Previews without fields"), ]) class Meta: abstract = True
class BrowseFilterablePage(FilterableListMixin, CFGOVPage): header = StreamField([ ('text_introduction', molecules.TextIntroduction()), ('featured_content', organisms.FeaturedContent()), ]) content = StreamField(BrowseFilterableContent) secondary_nav_exclude_sibling_pages = models.BooleanField(default=False) # General content tab content_panels = CFGOVPage.content_panels + [ StreamFieldPanel('header'), StreamFieldPanel('content'), ] sidefoot_panels = CFGOVPage.sidefoot_panels + [ FieldPanel('secondary_nav_exclude_sibling_pages'), ] # Tab handler interface edit_handler = TabbedInterface([ ObjectList(content_panels, heading='General Content'), ObjectList(sidefoot_panels, heading='SideFoot'), ObjectList(CFGOVPage.settings_panels, heading='Configuration'), ]) template = 'browse-filterable/index.html' objects = PageManager() search_fields = CFGOVPage.search_fields + [ index.SearchField('content'), index.SearchField('header') ] @property def page_js(self): return ( super(BrowseFilterablePage, self).page_js + ['secondary-navigation.js'] )
class WebPage(Page): # ---- General Page information ------ title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') body_en = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [ ('google_calendar', GoogleCalendarBlock()), ('google_drive', GoogleDriveBlock()), ('google_form', GoogleFormBlock()), ('news', LatestNewsBlock()), ], blank=True, ) body_sv = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [ ('google_calendar', GoogleCalendarBlock()), ('google_drive', GoogleDriveBlock()), ('google_form', GoogleFormBlock()), ('news', LatestNewsBlock()), ], blank=True, ) body = TranslatedField('body_en', 'body_sv') content_panels_en = Page.content_panels + [ StreamFieldPanel('body_en'), ] content_panels_sv = [ FieldPanel('title_sv', classname="full title"), StreamFieldPanel('body_sv'), ] edit_handler = TabbedInterface([ ObjectList(content_panels_en, heading=_('English')), ObjectList(content_panels_sv, heading=_('Swedish')), ObjectList(Page.promote_panels, heading=_('Promote')), ObjectList(Page.settings_panels, heading=_('Settings')), ])
class Topics(Page): parent_page_types = ['home.HomePage'] subpage_types = ['Topic'] template = 'topics.html' # Meta fields keywords = ClusterTaggableManager(through=TopicsTag, blank=True) # Meta panels meta_panels = [ MultiFieldPanel([ FieldPanel('seo_title'), FieldPanel('search_description'), FieldPanel('keywords'), ], heading='SEO'), ] # Settings panels settings_panels = [ FieldPanel('slug'), FieldPanel('show_in_menus'), ] edit_handler = TabbedInterface([ ObjectList(Page.content_panels, heading='Content'), ObjectList(meta_panels, heading='Meta'), ObjectList(settings_panels, heading='Settings', classname='settings'), ]) class Meta: verbose_name_plural = 'Topics' @classmethod def can_create_at(cls, parent): # Allow only one instance of this page type return super().can_create_at(parent) and not cls.objects.exists() @property def topics(self): return Topic.objects.live().public().order_by('title')
class ExternalContent(Page): is_external = True subpage_types = [] # Card fields description = TextField(max_length=250, blank=True, default='') external_url = URLField('URL', max_length=2048, blank=True, default='') image = ForeignKey('mozimages.MozImage', null=True, blank=True, on_delete=SET_NULL, related_name='+') card_panels = Page.content_panels + [ FieldPanel('description'), ImageChooserPanel('image'), FieldPanel('external_url'), ] edit_handler = TabbedInterface([ ObjectList(card_panels, heading='Card'), ObjectList(Page.settings_panels, heading='Settings', classname='settings'), ]) class Meta: verbose_name_plural = 'External Content' def get_full_url(self, request=None): return self.external_url def get_url(self, request=None, current_site=None): return self.external_url def relative_url(self, current_site, request=None): return self.external_url @property def url(self): return self.external_url
class ExternalEvent(ExternalContent): resource_type = 'event' start_date = DateField(default=datetime.date.today) end_date = DateField(blank=True, null=True) venue = TextField( max_length=250, blank=True, default='', help_text= 'Full address of the event venue, displayed on the event detail page') location = CharField( max_length=100, blank=True, default='', help_text= 'Location details (city and country), displayed on event cards') meta_panels = [ MultiFieldPanel([ FieldPanel('start_date'), FieldPanel('end_date'), FieldPanel('venue'), FieldPanel('location'), ], heading='Event details'), InlinePanel('topics', heading='Topics'), InlinePanel('speakers', heading='Speakers'), ] edit_handler = TabbedInterface([ ObjectList(ExternalContent.card_panels, heading='Card'), ObjectList(meta_panels, heading='Meta'), ObjectList(Page.settings_panels, heading='Settings', classname='settings'), ]) @property def event(self): return self
class CrowdfundingRocket2Page(FixUrlMixin, Page): class Meta: verbose_name = "crowdfunding - rocket 2" title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_("The page title as you'd like it to be seen by the public"), ) target_amount = models.IntegerField() title_translated = TranslatedField("title", "title_en") body_sk = StreamField([("text", blocks.TextBlock())]) body_en = StreamField([("text", blocks.TextBlock())]) body = TranslatedField("body_sk", "body_en") content_panels_sk = Page.content_panels + [ FieldPanel("target_amount"), StreamFieldPanel("body_sk"), ] content_panels_en = [ FieldPanel("title_en", classname="full title"), StreamFieldPanel("body_en"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) festival = self.get_ancestors().type(FestivalPage).first() if festival: context["festival"] = festival.specific else: context["festival"] = last_festival(self) return context
class PayingForCollegePage(CFGOVPage): """A base class for our suite of PFC pages.""" header = StreamField([ ('text_introduction', molecules.TextIntroduction()), ('featured_content', organisms.FeaturedContent()), ], blank=True) content_panels = CFGOVPage.content_panels + [ StreamFieldPanel('header'), StreamFieldPanel('content'), ] # Tab handler interface edit_handler = TabbedInterface([ ObjectList(content_panels, heading='General Content'), ObjectList(CFGOVPage.sidefoot_panels, heading='Sidebar'), ObjectList(CFGOVPage.settings_panels, heading='Configuration'), ]) objects = CFGOVPageManager() class Meta: abstract = True
class PurchaseOrderWagtailAdmin(ModelAdmin): model = PurchaseOrder menu_label = _("Purchase Orders") menu_icon = "tag" menu_order = 200 list_display = ("number", "status", "estimated_arrival", "supplier", "created_at") list_filter = ("status",) edit_template_name = "purchases/modeladmin/edit.html" receive_view_extra_css = [] panels = [ FieldPanel("number", classname="title"), FieldPanel("estimated_arrival"), FieldPanel("supplier"), FieldPanel("status"), InlinePanel( "items", [FieldPanel("status"), FieldPanel("quantity")], label=_("Items"), ), ] edit_handlers = TabbedInterface([ObjectList(panels, heading=_("Details"))])
class ContentSection(Page, SectionBase): """A content section with an WYSIWYG Richtext editro""" content_richtext = RichTextField() # basic tab panels basic_panels = Page.content_panels + [ SectionBase.section_content_panels, RichTextFieldPanel( 'content_richtext', heading='Richtext', ), SectionBase.section_layout_panels, SectionBase.section_design_panels, ] # Register Tabs edit_handler = TabbedInterface([ ObjectList(basic_panels, heading="Basic"), ]) # Page settings template = 'sections/content_section_preview.html' parent_page_types = ['home.HomePage'] subpage_types = [] # Overring methods def set_url_path(self, parent): """ Populate the url_path field based on this page's slug and the specified parent page. (We pass a parent in here, rather than retrieving it via get_parent, so that we can give new unsaved pages a meaningful URL when previewing them; at that point the page has not been assigned a position in the tree, as far as treebeard is concerned. """ if parent: self.url_path = '' else: # a page without a parent is the tree root, which always has a url_path of '/' self.url_path = '/' return self.url_path
class Project(Subprogram): parent_page_types = ['programs.Program'] subpage_types = [ 'article.ProgramArticlesPage', 'book.ProgramBooksPage', 'blog.ProgramBlogPostsPage', 'event.ProgramEventsPage', 'podcast.ProgramPodcastsPage', 'report.ReportsHomepage', 'policy_paper.ProgramPolicyPapersPage', 'press_release.ProgramPressReleasesPage', 'quoted.ProgramQuotedPage', 'home.ProgramSimplePage', 'person.ProgramPeoplePage', 'issue.IssueOrTopic', 'home.RedirectPage', 'PublicationsPage', 'other_content.ProgramOtherPostsPage', 'home.ProgramAboutHomePage' ] redirect_page = models.ForeignKey( 'wagtailcore.Page', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', help_text='Select a report or other post that you would like to show up as a project in your Initiatives & Projects list' ) content_panels = [ PageChooserPanel('redirect_page') ] + Subprogram.content_panels edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(Subprogram.featured_panels, heading='Featured'), ObjectList(Subprogram.promote_panels, heading='Promote'), ObjectList(Subprogram.settings_panels, heading='Settings', classname='settings'), ])
class PageWithCustomEditHandler(Page): foo_field = models.TextField() bar_field = models.TextField() baz_field = models.TextField() foo_panels = [ FieldPanel('foo_field'), ] bar_panels = [ FieldPanel('bar_field'), FieldPanel('baz_field'), ] edit_handler = TabbedInterface([ ObjectList(bar_panels, heading="Bar"), ObjectList([InlinePanel('child_objects')], heading="Child objects"), ObjectList(foo_panels, heading="Foo"), ObjectList(Page.content_panels, heading="Content"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings"), ])
class TestTabbedInterface(TestCase): def setUp(self): self.request = RequestFactory().get('/') user = AnonymousUser() # technically, Anonymous users cannot access the admin self.request.user = user # a custom tabbed interface for EventPage self.event_page_tabbed_interface = TabbedInterface([ ObjectList([ FieldPanel('title', widget=forms.Textarea), FieldPanel('date_from'), FieldPanel('date_to'), ], heading='Event details', classname="shiny"), ObjectList([ InlinePanel('speakers', label="Speakers"), ], heading='Speakers'), ]).bind_to(model=EventPage, request=self.request) def test_get_form_class(self): EventPageForm = self.event_page_tabbed_interface.get_form_class() form = EventPageForm() # form must include the 'speakers' formset required by the speakers InlinePanel self.assertIn('speakers', form.formsets) # form must respect any overridden widgets self.assertEqual(type(form.fields['title'].widget), forms.Textarea) def test_render(self): EventPageForm = self.event_page_tabbed_interface.get_form_class() event = EventPage(title='Abergavenny sheepdog trials') form = EventPageForm(instance=event) tabbed_interface = self.event_page_tabbed_interface.bind_to( instance=event, form=form, ) result = tabbed_interface.render() # result should contain tab buttons self.assertIn('<a href="#tab-event-details" class="active">Event details</a>', result) self.assertIn('<a href="#tab-speakers" class="">Speakers</a>', result) # result should contain tab panels self.assertIn('<div class="tab-content">', result) self.assertIn('<section id="tab-event-details" class="shiny active">', result) self.assertIn('<section id="tab-speakers" class=" ">', result) # result should contain rendered content from descendants self.assertIn('Abergavenny sheepdog trials</textarea>', result) # this result should not include fields that are not covered by the panel definition self.assertNotIn('signup_link', result) def test_required_fields(self): # required_fields should report the set of form fields to be rendered recursively by children of TabbedInterface result = set(self.event_page_tabbed_interface.required_fields()) self.assertEqual(result, set(['title', 'date_from', 'date_to'])) def test_render_form_content(self): EventPageForm = self.event_page_tabbed_interface.get_form_class() event = EventPage(title='Abergavenny sheepdog trials') form = EventPageForm(instance=event) tabbed_interface = self.event_page_tabbed_interface.bind_to( instance=event, form=form, ) result = tabbed_interface.render_form_content() # rendered output should contain field content as above self.assertIn('Abergavenny sheepdog trials</textarea>', result) # rendered output should NOT include fields that are in the model but not represented # in the panel definition self.assertNotIn('signup_link', result)