class ArticlePage(Page): body = StreamField( [ ('heading', CharBlock(classname="full title")), ('paragraph', RichTextBlock()), ('reference_page', PageChooserBlock()), # this is single StructBlock ('struct_data', StructBlock([ ('heading', CharBlock(classname="full title")), ('paragraph', RichTextBlock()), ('reference_page', PageChooserBlock()), ])), # this is StreamBlock ('stream_data', StreamBlock([ ('sub_struct_data', StructBlock([ ('heading', CharBlock(classname="full title")), ('paragraph', RichTextBlock()), ('reference_page', PageChooserBlock()), ])), ])), ('column_struct_data', ColumnStructBlock()), ('column_stream_data', ColumnStreamBlock()) ], null=True, blank=True) # Editor panels configuration content_panels = Page.content_panels + [ StreamFieldPanel('body'), ]
class CustomBlock2(blocks.StructBlock): field_link = PageChooserBlock(required=False) field_link_list = blocks.ListBlock(PageChooserBlock(), required=False) field_image = ImageChooserBlock(required=False) field_image_list = blocks.ListBlock(ImageChooserBlock(), required=False) field_snippet = SnippetChooserBlock(target_model=App2Snippet, required=False) field_snippet_list = blocks.ListBlock( SnippetChooserBlock(target_model=App2Snippet), required=False)
class BaseStreamBlock(StreamBlock): """ Define the custom blocks that `StreamField` will utilize """ link_block = CaptionedPageLink() page = PageChooserBlock() stream = AnotherStreamBlock() rich_text = RichTextBlock() list_of_pages = ListBlock(PageChooserBlock())
class FullPageIntro(StructBlock): backgroundImage = ImageChooserBlock() headline = TextBlock() caption = TextBlock() buttonLeftText = TextBlock() buttonRightText = TextBlock() buttonLeftDestination = PageChooserBlock(required=True) buttonRightDestination = PageChooserBlock(required=True) class Meta: template = 'blocks/full-page.html'
class BasicHeaderBackground(StructBlock): backgroundImage = ImageChooserBlock(required=True) headline = TextBlock(required=False) caption = TextBlock(required=False) buttonLeftText = TextBlock(required=False) buttonRightText = TextBlock(required=False) buttonLeftDestination = PageChooserBlock(required=False) buttonRightDestination = PageChooserBlock(required=False) class Meta: template = 'blocks/basic-header.html'
class ColumnStructBlock(StructBlock): heading = CharBlock(classname="full title") paragraph = RichTextBlock() reference_page = PageChooserBlock() class Meta: template = 'example/blocks/column_struct_block.html'
def _generate_recommended_articles(self, target_id): articles_block = StreamBlock([("page", PageChooserBlock())]) article_ids = self._generate_list_of_article_ids_for_recommended_articles(target_id) recommended_articles = [] for article_id in article_ids: recommended_articles.append(("page", BlogArticlePage.objects.get(id=article_id))) return StreamValue(articles_block, recommended_articles)
def test_that_article_with_no_recommended_articles_should_be_valid(self): author = BossFactory() body_block = StreamBlock([(ArticleBodyBlockNames.PARAGRAPH.value, RichTextBlock())]) body = StreamValue(body_block, [ (ArticleBodyBlockNames.PARAGRAPH.value, RichText("Hello, World")) ]) test_title = "Simple Article Title" blog_article_parameter = { "title": test_title, "page_title": test_title, "date": datetime.now(), "body": body, "author": author, "read_time": 7, "views": 0, } articles_block = StreamBlock([("page", PageChooserBlock())]) blog_article_page = BlogArticlePage(**blog_article_parameter) self.blog_index_page.add_child(instance=blog_article_page) blog_article_page.save() self.assertEqual(blog_article_page.recommended_articles, StreamValue(articles_block, []))
class NestedPageGroup(StructBlock): """Class for a nested page group.""" class Meta: icon = 'list-ul' label = 'Page group' value_class = TransStructValue page = PageChooserBlock( help_text='Optional: top level page for the group', required=False, label='Top level page', ) title_en = CharBlock( help_text='Optional: plain text title for the page group', label='Title [en]', required=False, ) title_fr = CharBlock( help_text='Optional: plain text title for the page group', label='Title [fr]', required=False, ) page_group = ListBlock( TranslatedPage(), required=False, help_text='Optional: group of sub pages, displayed as an indented list', )
class TeasertextBlock(StructBlock): headline = CharBlock(required=True, length=256) text = TextBlock(required=True) link = PageChooserBlock(required=False) externlink = URLBlock(label=_("External Link"), required=False, help_text=_("The external link overwrites the " "link to a local page. It also " "requires a link text.")) link_text = CharBlock(required=False, help_text=_( "Text to be displayed on the link-button." "Should be quite short! If not given, the " "title of the linked page will be used.")) class Meta: template = 'cms_home/blocks/teasertext_block.html' def clean(self, value): result = super().clean(value) errors = {} if value['externlink'] and not value['link_text']: errors['link_text'] = ErrorList([ 'External links require a link text.', ]) if errors: raise ValidationError(_('External links require a link text.'), params=errors) return result
class HomePage(RoutablePageMixin, Page): footer_colour = models.CharField("Hover colour", max_length=255, blank=True, null=True) splash_items = StreamField([ ('image', StructBlock([('image', ImageChooserBlock(blank=True, required=False)), ('title', CharBlock(required=False)), ('page_link', PageChooserBlock(blank=True))], icon='image')), ], blank=True) @route('^checkout/$') def checkout(self, request): context = self.get_context(request) return TemplateResponse(request, 'shop/checkout.html', context) @route('^amend-basket/$') def amend_basket(self, request): context = self.get_context(request) return TemplateResponse(request, 'shop/amend_basket.html', context) content_panels = Page.content_panels + [ StreamFieldPanel('splash_items'), ] promote_panels = [ FieldPanel('footer_colour'), ] + Page.promote_panels
def _clean_recommended_articles(self) -> None: self.recommended_articles = StreamValue( stream_block=StreamBlock([("page", PageChooserBlock())]), stream_data=[("page", stream_child.value) for stream_child in self.recommended_articles if stream_child.value is not None], )
class NavLinks(BaseSetting): links = StreamField([ ('pages', PageChooserBlock()), ('icons', FAIconLinkBlock()), ]) panels = [StreamFieldPanel('links')]
class Link(blocks.StructBlock): link_text = blocks.CharBlock(required=False, blank=True, max_length=50, default='More details') internal_page = PageChooserBlock(required=False) external_link = blocks.URLBlock(required=False) required = True def __init__(self, local_blocks=None, **kwargs): self.required = kwargs.pop('required', self.required) super().__init__(local_blocks, **kwargs) def clean(self, value): errors = {} internal_page = value.get('internal_page') external_link = value.get('external_link') error_message = 'You must enter an external link OR select an internal page' if (not internal_page and not external_link and self.required) or (internal_page and external_link): errors['internal_page'] = ErrorList([error_message]) errors['external_link'] = ErrorList([error_message]) if errors: raise ValidationError('Link validation error', params=errors) return super().clean(value) class Meta: value_class = LinkValue
class ExternalVideo(ExternalContent): resource_type = "video" is_external = True # Meta fields date = DateField( "Video date", default=datetime.date.today, help_text="The date the video was published", ) speakers = StreamField( StreamBlock( [("speaker", PageChooserBlock(target_model="people.Person"))], required=False, ), blank=True, null=True, help_text= "Optional list of people associated with or starring in the video", ) duration = CharField( max_length=30, blank=True, null=True, help_text=("Optional video duration in MM:SS format e.g. “12:34”. " "Shown when the video is displayed as a card"), ) meta_panels = [ FieldPanel("date"), StreamFieldPanel("speakers"), InlinePanel("topics", heading="Topics"), FieldPanel("duration"), ] settings_panels = BasePage.settings_panels + [FieldPanel("slug")] edit_handler = TabbedInterface([ ObjectList(ExternalContent.card_panels, heading="Card"), ObjectList(meta_panels, heading="Meta"), ObjectList(settings_panels, heading="Settings", classname="settings"), ]) # Search config search_fields = BasePage.search_fields + [ # Inherit search_fields from Page # "title" is already specced in BasePage index.SearchField("description"), # Add FilterFields for things we may be filtering on (eg topics) index.FilterField("slug"), ] @property def video(self): return self def has_speaker(self, person): for speaker in self.speakers: # pylint: disable=not-an-iterable if str(speaker.value) == str(person.title): return True return False
class PeopleBlock(StructBlock): title = CharBlock(required=True) intro = RichTextBlock(required=True) people = ListBlock(PageChooserBlock()) class Meta: template = 'blocks/services/people_block.html'
class IconAutoListBlock(StructBlock): """ A streamfield for aesthetically pleasing, automatically generated lists of links with an icon. """ icon = CharBlock(help_text="Add a Font Awesome icon name here") starting_page = PageChooserBlock() def get_context(self, value): context = super(IconAutoListBlock, self).get_context(value) d = [] if value['starting_page']: url_path = value['starting_page'].url_path for child in Page.objects.get(url_path=url_path).get_children( ).in_menu().live().specific(): c = {'title': child.title, 'url': child.url, 'children': []} for grandchild in child.get_children().in_menu().live( ).specific(): c['children'].append({ 'title': grandchild.title, 'url': grandchild.url }) d.append(c) context['descendants'] = d return context class Meta: icon = 'folder' template = 'intranettocs/blocks/icon_automatic_directory_list.html'
class Featured(AbstractHighlight): """Class for a featured item.""" class Meta: help_text = ''' <strong>Featured module</strong><br> Internal page link and short description.<br> Optional: secondary page link and label. ''' icon = 'pick' template = 'navigation/blocks/featured.html' image = ImageChooserBlock( help_text= 'Optional: image for the module. If not selected, the page image will be used, or a fallback if not available', required=False, ) secondary_page = PageChooserBlock( help_text='Optional: secondary page link', required=False, ) link_label_en = CharBlock( help_text='Optional: label for the secondary page link', label='Link label [en]', required=False, ) link_label_fr = CharBlock( help_text='Optional: label for the secondary page link', label='Link label [fr]', required=False, )
class TeamMemberQuoteBlock(StructBlock): quote_text = TextBlock() team_member = PageChooserBlock(page_type='ourteam.TeamMemberPage', required=False) class Meta(): icon = 'fa-users'
class NewsItemBlock(StructBlock): title = CharBlock(label='标题') page = PageChooserBlock(label='文章') class Meta: template = 'ncrcrd/blocks/news_chooser.html' label = '新闻链接'
class CardBlock(StructBlock): """Карточки с изображением, текстом и кнопкой.""" title = CharBlock(required=True, help_text="Add your title") cards = ListBlock( StructBlock( [ ("image", ImageChooserBlock(required=True)), ("title", CharBlock(required=True, max_length=40)), ("text", TextBlock(required=True, max_length=200)), ("button_page", PageChooserBlock(required=False)), ( "button_url", URLBlock( required=False, help_text="Если выбрана страница кнопки выше, она будет использоваться первой.", # noqa ), ), ] ) ) class Meta: # noqa template = "layouts/card_block.html" icon = "placeholder" label = "Карточка с фото"
class ExternalArticle(ExternalContent): resource_type = 'article' date = DateField('Article date', default=datetime.date.today, help_text='The date the article was published') authors = StreamField( StreamBlock([ ('author', PageChooserBlock(target_model='people.Person')), ('external_author', ExternalAuthorBlock()), ], required=False), blank=True, null=True, help_text= ('Optional list of the article’s authors. Use ‘External author’ to add guest authors without creating a ' 'profile on the system'), ) read_time = CharField( max_length=30, blank=True, help_text= ('Optional, approximate read-time for this article, e.g. “2 mins”. This ' 'is shown as a small hint when the article is displayed as a card.')) meta_panels = [ FieldPanel('date'), StreamFieldPanel('authors'), MultiFieldPanel( [ InlinePanel('topics'), ], heading='Topics', help_text='The topic pages this article will appear on'), FieldPanel('read_time'), ] edit_handler = TabbedInterface([ ObjectList(ExternalContent.card_panels, heading='Card'), ObjectList(meta_panels, heading='Meta'), ObjectList(Page.settings_panels, heading='Settings', classname='settings'), ]) @property def article(self): return self @property def month_group(self): return self.date.replace(day=1) def has_author(self, person): for author in self.authors: # pylint: disable=not-an-iterable if (author.block_type == 'author' and str(author.value) == str(person.title)): return True return False
class CarouselItemBlock(StructBlock): title = CharBlock(label='标题') picture = ImageChooserBlock(label='图片') page = PageChooserBlock(label='文章') class Meta: template = 'ncrcrd/blocks/carousel.html' label = '轮播条目'
class LinkBlock(StructBlock): external_url = URLBlock(label='Ekstern lenke', required=False) page_link = PageChooserBlock(label='Intern lenke', required=False) document = DocumentChooserBlock(label='Dokument- lenke', required=False) class Meta: abstract = True help_text = 'Velg kun èn lenke-type (ekstern/intern/dokument).'
class PictureLinkBlock(blocks.StructBlock): title = blocks.CharBlock(max_length=50) image = ImageChooserBlock() page = PageChooserBlock() class Meta: template = 'core/blocks/picture_link.html' icon = 'fa-camera-retro'
class ButtonBlock(StructBlock): classes = ClassBlock() text = CharBlock(required=True) page = PageChooserBlock(required=True) attrs = CharBlock(default='large rounded') class Meta: template = "blocks/button.html"
class LinkBlock(StructBlock): name = CharBlock(max_length=100) description = TextBlock() image = ImageChooserBlock() destination_page = PageChooserBlock() class Meta(): template = "home/blocks/LinkBlock.html"
class TeamStoryBlock(StructBlock): team_story_page = PageChooserBlock(verbose_name='Story Page', page_type=['general.General']) logo = ImageChooserBlock() class Meta(): icon = 'fa-book' verbose_name = 'Team Story'
class CallToActionButtonBlock(StructBlock): button_target = PageChooserBlock(required=False, help_text='Choose where this button should link to.') button_text = CharBlock(required=False, help_text='What should the button say?') class Meta: icon = 'fa-arrow-right' template = 'blocks/button.html' help_text = 'Create a cll to action button to help guide users to the next step.'
def test_that_recommended_articles_should_not_contain_duplicates(self): other_article = self._create_blog_article_page() articles_block = StreamBlock([("page", PageChooserBlock())]) recommended_articles_with_duplicates = StreamValue( articles_block, [("page", other_article), ("page", other_article)]) with self.assertRaises(ValidationError): self._create_blog_article_page( recommended_articles=recommended_articles_with_duplicates)