├── wagtailcontentstream ├── __init__.py ├── tests │ ├── __init__.py │ └── test_models.py ├── templates │ └── wagtailcontentstream │ │ └── blocks │ │ ├── heading.html │ │ ├── section_struct_block.html │ │ └── captioned_image.html ├── models.py ├── wagtail_hooks.py └── blocks.py ├── MANIFEST.in ├── setup.py ├── LICENSE └── README.md /wagtailcontentstream/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wagtailcontentstream/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | recursive-include wagtailcontentstream/templates * 3 | -------------------------------------------------------------------------------- /wagtailcontentstream/templates/wagtailcontentstream/blocks/heading.html: -------------------------------------------------------------------------------- 1 |
` tag.
13 | """
14 | feature_name = "monospace"
15 | draftail_type = "CODE"
16 | html_tag = "code"
17 |
18 | # Configure how Draftail handles the feature in its toolbar.
19 | control = {
20 | "type": draftail_type,
21 | "label": "{ }",
22 | "description": "Monospace",
23 | }
24 |
25 | # Call register_editor_plugin to register the configuration for Draftail.
26 | features.register_editor_plugin(
27 | "draftail", feature_name, InlineStyleFeature(control)
28 | )
29 |
30 | # Configure the content transform from the DB to the editor and back.
31 | db_conversion = {
32 | "from_database_format": {html_tag: InlineStyleElementHandler(draftail_type)},
33 | "to_database_format": {"style_map": {draftail_type: html_tag}},
34 | }
35 |
36 | # Call register_converter_rule to register the content transformation conversion.
37 | features.default_features.append(feature_name)
38 | features.register_converter_rule("contentstate", feature_name, db_conversion)
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) Timothy Allen and individual contributors.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice,
8 | this list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright
11 | notice, this list of conditions and the following disclaimer in the
12 | documentation and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of Django nor the names of its contributors may be used
15 | to endorse or promote products derived from this software without
16 | specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Wagtail Content Stream
2 |
3 | An abstract Django model with a Wagtail StreamField named `body` with multiple blocks I use on a regular basis. This is geared towards developers who need to write examples with code in them. It's opinionated: very little HTML is allowed in the text block, forcing authors to create structured data. The following blocks are included in `ContentStreamBlock`:
4 |
5 | * Heading
6 | * Paragraph
7 | * Captioned Image
8 | * Embed
9 | * Table
10 | * Code Block
11 |
12 | A secondary StreamBlock, `ContentStreamBlockWithRawCode`, also provides an additional block for injecting HTML, JS, and CSS code. Use with care, as this can really blow up your markup and is a potential code injection point!
13 |
14 | Three pages types are provided out-of-the-box.
15 |
16 | ## Example Usage
17 |
18 | You will need to add `wagtailcodeblock` to your `INSTALLED_APPS` Django setting.
19 |
20 | #### Basic Usage: a Title Field and Content Stream
21 |
22 | First, create a page type in your `models.py`:
23 |
24 | ```python
25 | from wagtailcontentstream.models import ContentStreamPage, SectionContentStreamPage, ContentStreamPageWithRawCode
26 |
27 | class StandardPage(ContentStreamPage):
28 | pass
29 |
30 | class SectionStandardPage(SectionContentStreamPage):
31 | pass
32 |
33 | class StandardPageWithRawCode(ContentStreamPageWithRawCode):
34 | pass
35 | ```
36 |
37 | Then in your template:
38 |
39 | ```django
40 | {% load wagtailcore_tags %}
41 |
42 | {{ page.title }}
43 | {% include_block page.body %}
44 | ```
45 |
46 | #### Extended Usage: Adding More Fields
47 |
48 | ```python
49 | from django.conf import settings
50 | from django.db import models
51 | from wagtail.admin.edit_handlers import FieldPanel
52 | from wagtailcontentstream.models import ContentStreamPage
53 |
54 |
55 | class StandardPage(ContentStreamPage):
56 | date = models.DateField("Post Date")
57 | authors = models.ManyToManyField(settings.AUTH_USER_MODEL)
58 |
59 | content_panels = [
60 | FieldPanel('date'),
61 | FieldPanel('authors'),
62 | ] + ContentStreamPage.content_panels
63 | ```
64 |
65 | # Release Notes & Contributors
66 |
67 | * Thank you to our [wonderful contributors](https://github.com/FlipperPA/wagtailcontentstream/graphs/contributors)!
68 | * Release notes are [available on GitHub](https://github.com/FlipperPA/wagtailcontentstream/releases).
69 |
70 | # Project Maintainer
71 |
72 | * Timothy Allen (https://github.com/FlipperPA)
73 |
--------------------------------------------------------------------------------
/wagtailcontentstream/blocks.py:
--------------------------------------------------------------------------------
1 | from wagtail import VERSION as WAGTAIL_VERSION
2 | from wagtail.contrib.table_block.blocks import TableBlock
3 |
4 | if WAGTAIL_VERSION >= (3, 0):
5 | from wagtail.blocks import (
6 | ChoiceBlock,
7 | RichTextBlock,
8 | TextBlock,
9 | StructBlock,
10 | StreamBlock,
11 | )
12 | from wagtail.documents.blocks import DocumentChooserBlock
13 | from wagtail.embeds.blocks import EmbedBlock
14 | from wagtail.images.blocks import ImageChooserBlock
15 | else:
16 | from wagtail.core.blocks import (
17 | ChoiceBlock,
18 | RichTextBlock,
19 | TextBlock,
20 | StructBlock,
21 | StreamBlock,
22 | )
23 | from wagtail.documents.blocks import DocumentChooserBlock
24 | from wagtail.embeds.blocks import EmbedBlock
25 | from wagtail.images.blocks import ImageChooserBlock
26 |
27 | from wagtailcodeblock.blocks import CodeBlock
28 |
29 |
30 | class CaptionedImageBlock(StructBlock):
31 | """
32 | An image block with a caption, credit, and alignment.
33 | """
34 |
35 | image = ImageChooserBlock(
36 | help_text="The image to display.",
37 | )
38 | caption = TextBlock(
39 | required=False, help_text="The caption will appear under the image, if entered."
40 | )
41 | credit = TextBlock(
42 | required=False, help_text="The credit will appear under the image, if entered."
43 | )
44 | align = ChoiceBlock(
45 | choices=[
46 | ("left", "Left"),
47 | ("right", "Right"),
48 | ("center", "Center"),
49 | ("full", "Full Width"),
50 | ],
51 | default="left",
52 | help_text="How to align the image in the body of the page.",
53 | )
54 |
55 | class Meta:
56 | icon = "image"
57 | template = "wagtailcontentstream/blocks/captioned_image.html"
58 | help_text = "Select an image and add a caption (optional)."
59 |
60 |
61 | class ContentStreamBlock(StreamBlock):
62 | """
63 | Contains the elements we'll want to have in a Content Stream.
64 | """
65 |
66 | heading = TextBlock(
67 | icon="title",
68 | template="wagtailcontentstream/blocks/heading.html",
69 | )
70 | paragraph = RichTextBlock(
71 | icon="pilcrow",
72 | features=["bold", "italic", "link", "ol", "ul", "monospace"],
73 | )
74 | image = CaptionedImageBlock()
75 | document = DocumentChooserBlock()
76 | embed = EmbedBlock(icon="media")
77 | table = TableBlock(icon="table")
78 | code = CodeBlock(icon="code")
79 |
80 | class Meta:
81 | help_text = "The main page body."
82 |
83 |
84 | class ContentStreamBlockWithRawCode(ContentStreamBlock):
85 | raw_code = CodeBlock(
86 | icon="code",
87 | language="html",
88 | template="wagtailcodeblock/raw_code.html",
89 | )
90 |
91 |
92 | class SectionStructBlock(StructBlock):
93 | """
94 | Contains the elements we'll want to have in a Sectioned Content Stream block.
95 | """
96 |
97 | section_heading = TextBlock(
98 | icon="title",
99 | help_text="Heading for this section.",
100 | )
101 | body = ContentStreamBlock(
102 | help_text="The body content goes here.",
103 | )
104 |
105 | class Meta:
106 | template = "wagtailcontentstream/blocks/section_struct_block.html"
107 | icon = "doc-full-inverse"
108 |
109 |
110 | class SectionBlock(StreamBlock):
111 | """
112 | Streamblock to associate multiple blocks with a section.
113 | """
114 |
115 | section = SectionStructBlock()
116 |
117 | class Meta:
118 | help_text = "The main page body."
119 |
--------------------------------------------------------------------------------