diff --git a/network-api/networkapi/wagtailpages/migrations/0162_alter_articlepage_body.py b/network-api/networkapi/wagtailpages/migrations/0162_alter_articlepage_body.py new file mode 100644 index 00000000000..d8a022be414 --- /dev/null +++ b/network-api/networkapi/wagtailpages/migrations/0162_alter_articlepage_body.py @@ -0,0 +1,1285 @@ +# Generated by Django 4.2.15 on 2024-09-12 12:35 + +import django.core.validators +import wagtail.blocks +import wagtail.contrib.table_block.blocks +import wagtail.documents.blocks +import wagtail.embeds.blocks +import wagtail.fields +import wagtail.images.blocks +from django.db import migrations +from wagtail.blocks.migrations.migrate_operation import MigrateStreamData + +import networkapi.wagtailpages.pagemodels.customblocks.articles +import networkapi.wagtailpages.validators +from networkapi.utility.migration.operations import AlterStreamChildBlockDataOperation + + +def migrate_tableblock(source_block): + """Copy old table data to new table in a StructBlock.""" + return { + **source_block, + "value": { + "table": source_block["value"], + "wide": True, + }, + } + + +class Migration(migrations.Migration): + + dependencies = [ + ("wagtailpages", "0161_alter_homepage_ideas_headline_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="articlepage", + name="body", + field=wagtail.fields.StreamField( + [ + ( + "accordion", + wagtail.blocks.StructBlock( + [ + ( + "accordion_items", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "title", + wagtail.blocks.CharBlock( + help_text="Heading for the Accordion Item" + ), + ), + ( + "content", + wagtail.blocks.StreamBlock( + [ + ( + "rich_text", + wagtail.blocks.RichTextBlock( + blank=True, + features=[ + "bold", + "italic", + "link", + "ul", + "ol", + "document-link", + ], + ), + ), + ( + "datawrapper", + wagtail.embeds.blocks.EmbedBlock( + help_text='Enter the "visualization only" link of the Datawrapper chart. It looks something like this: https://datawrapper.dwcdn.net/KwSKp/1/', + icon="image", + template="wagtailpages/blocks/datawrapper_block.html", + ), + ), + ( + "image", + wagtail.blocks.StructBlock( + [ + ( + "image", + wagtail.images.blocks.ImageChooserBlock(), + ), + ( + "altText", + wagtail.blocks.CharBlock( + help_text="Image description (for screen readers).", + required=True, + ), + ), + ] + ), + ), + ( + "video", + wagtail.blocks.StructBlock( + [ + ( + "url", + wagtail.blocks.URLBlock( + help_text="For YouTube: go to your YouTube video and click “Share,” then “Embed,” and then copy and paste the provided URL only. For example: https://www.youtube.com/embed/3FIVXBawyQw For Vimeo: follow similar steps to grab the embed URL. For example: https://player.vimeo.com/video/9004979", + label="Embed URL", + ), + ), + ( + "caption", + wagtail.blocks.CharBlock(required=False), + ), + ( + "caption_url", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "link_to", + wagtail.blocks.ChoiceBlock( + choices=[ + ("page", "Page"), + ( + "external_url", + "External URL", + ), + ( + "relative_url", + "Relative URL", + ), + ("email", "Email"), + ( + "anchor", + "Anchor", + ), + ("file", "File"), + ("phone", "Phone"), + ], + label="Link to", + ), + ), + ( + "page", + wagtail.blocks.PageChooserBlock( + label="Page", + required=False, + ), + ), + ( + "external_url", + wagtail.blocks.URLBlock( + help_text="Enter a full URL including http:// or https://", + label="External URL", + max_length=300, + required=False, + ), + ), + ( + "relative_url", + wagtail.blocks.CharBlock( + help_text='A path relative to this domain. For example, "/foo/bar" or "?foo=bar".', + label="Relative URL", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.RelativeURLValidator() + ], + ), + ), + ( + "anchor", + wagtail.blocks.CharBlock( + help_text='An id attribute of an element on the current page. For example, "#section-1"', + label="#", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.AnchorLinkValidator() + ], + ), + ), + ( + "email", + wagtail.blocks.EmailBlock( + required=False + ), + ), + ( + "file", + wagtail.documents.blocks.DocumentChooserBlock( + label="File", + required=False, + ), + ), + ( + "phone", + wagtail.blocks.CharBlock( + label="Phone", + max_length=30, + required=False, + ), + ), + ( + "new_window", + wagtail.blocks.BooleanBlock( + label="Open in new window", + required=False, + ), + ), + ] + ), + help_text="Optional URL that this caption should link out to.", + max_num=1, + min_num=0, + ), + ), + ( + "video_width", + wagtail.blocks.ChoiceBlock( + choices=[ + ("normal", "Normal"), + ("wide", "Wide"), + ("full_width", "Full Width"), + ], + help_text="Wide videos are col-12, Full-Width videos reach both ends of the screen.", + ), + ), + ] + ), + ), + ] + ), + ), + ] + ) + ), + ) + ] + ), + ), + ( + "airtable", + wagtail.blocks.StructBlock( + [ + ( + "url", + wagtail.blocks.URLBlock( + help_text="Copied from the Airtable embed code. The word 'embed' will be in the url" + ), + ), + ( + "height", + wagtail.blocks.IntegerBlock( + default=533, + help_text="The pixel height on desktop view, usually copied from the Airtable embed code", + ), + ), + ] + ), + ), + ( + "datawrapper", + wagtail.embeds.blocks.EmbedBlock( + help_text='Enter the "visualization only" link of the Datawrapper chart. It looks something like this: https://datawrapper.dwcdn.net/KwSKp/1/', + icon="image", + template="wagtailpages/blocks/datawrapper_block.html", + ), + ), + ( + "callout", + wagtail.blocks.RichTextBlock( + features=["bold", "italic", "link", "h2", "h3", "h4", "ul", "ol"], + template="wagtailpages/blocks/article_blockquote_block.html", + ), + ), + ( + "card_grid", + wagtail.blocks.StructBlock( + [ + ( + "cards", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ("image", wagtail.images.blocks.ImageChooserBlock()), + ( + "alt_text", + wagtail.blocks.CharBlock( + help_text="Alt text for card's image.", required=False + ), + ), + ("title", wagtail.blocks.CharBlock(help_text="Heading for the card.")), + ("body", wagtail.blocks.TextBlock(help_text="Body text of the card.")), + ( + "link", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ("label", wagtail.blocks.CharBlock()), + ( + "link_to", + wagtail.blocks.ChoiceBlock( + choices=[ + ("page", "Page"), + ("external_url", "External URL"), + ("relative_url", "Relative URL"), + ("email", "Email"), + ("anchor", "Anchor"), + ("file", "File"), + ("phone", "Phone"), + ], + label="Link to", + ), + ), + ( + "page", + wagtail.blocks.PageChooserBlock( + label="Page", required=False + ), + ), + ( + "external_url", + wagtail.blocks.URLBlock( + help_text="Enter a full URL including http:// or https://", + label="External URL", + max_length=300, + required=False, + ), + ), + ( + "relative_url", + wagtail.blocks.CharBlock( + help_text='A path relative to this domain. For example, "/foo/bar" or "?foo=bar".', + label="Relative URL", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.RelativeURLValidator() + ], + ), + ), + ( + "anchor", + wagtail.blocks.CharBlock( + help_text='An id attribute of an element on the current page. For example, "#section-1"', + label="#", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.AnchorLinkValidator() + ], + ), + ), + ("email", wagtail.blocks.EmailBlock(required=False)), + ( + "file", + wagtail.documents.blocks.DocumentChooserBlock( + label="File", required=False + ), + ), + ( + "phone", + wagtail.blocks.CharBlock( + label="Phone", max_length=30, required=False + ), + ), + ( + "new_window", + wagtail.blocks.BooleanBlock( + label="Open in new window", required=False + ), + ), + ] + ), + help_text="Optional link that this card should link out to.", + max_num=1, + min_num=0, + ), + ), + ] + ), + help_text="Please use a minimum of 2 cards.", + ), + ) + ] + ), + ), + ( + "content", + networkapi.wagtailpages.pagemodels.customblocks.articles.ArticleRichText( + features=[ + "bold", + "italic", + "link", + "h2", + "h3", + "h4", + "h5", + "ol", + "ul", + "hr", + "document-link", + "large", + "image", + "footnotes", + ] + ), + ), + ( + "image", + wagtail.blocks.StructBlock( + [ + ("image", wagtail.images.blocks.ImageChooserBlock()), + ( + "caption", + wagtail.blocks.RichTextBlock( + features=["bold", "italic", "link"], label="Image caption", required=False + ), + ), + ("alt_text", wagtail.blocks.CharBlock(required=False)), + ( + "wide_image", + wagtail.blocks.BooleanBlock( + default=False, + help_text='Checking this will use a wider version of this image, but not full width. For an edge-to-edge image, use the "Wide Image" block.', + required=False, + ), + ), + ] + ), + ), + ( + "image_grid", + wagtail.blocks.StructBlock( + [ + ( + "grid_items", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ("image", wagtail.images.blocks.ImageChooserBlock()), + ( + "alt_text", + wagtail.blocks.CharBlock( + help_text="Alt text for this image.", required=False + ), + ), + ( + "caption", + wagtail.blocks.CharBlock( + help_text="Please remember to properly attribute any images we use.", + required=False, + ), + ), + ( + "link", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "link_to", + wagtail.blocks.ChoiceBlock( + choices=[ + ("page", "Page"), + ("external_url", "External URL"), + ("relative_url", "Relative URL"), + ("email", "Email"), + ("anchor", "Anchor"), + ("file", "File"), + ("phone", "Phone"), + ], + label="Link to", + ), + ), + ( + "page", + wagtail.blocks.PageChooserBlock( + label="Page", required=False + ), + ), + ( + "external_url", + wagtail.blocks.URLBlock( + help_text="Enter a full URL including http:// or https://", + label="External URL", + max_length=300, + required=False, + ), + ), + ( + "relative_url", + wagtail.blocks.CharBlock( + help_text='A path relative to this domain. For example, "/foo/bar" or "?foo=bar".', + label="Relative URL", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.RelativeURLValidator() + ], + ), + ), + ( + "anchor", + wagtail.blocks.CharBlock( + help_text='An id attribute of an element on the current page. For example, "#section-1"', + label="#", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.AnchorLinkValidator() + ], + ), + ), + ("email", wagtail.blocks.EmailBlock(required=False)), + ( + "file", + wagtail.documents.blocks.DocumentChooserBlock( + label="File", required=False + ), + ), + ( + "phone", + wagtail.blocks.CharBlock( + label="Phone", max_length=30, required=False + ), + ), + ( + "new_window", + wagtail.blocks.BooleanBlock( + label="Open in new window", required=False + ), + ), + ] + ), + help_text="Optional link that this figure should link out to.", + max_num=1, + min_num=0, + ), + ), + ( + "square_image", + wagtail.blocks.BooleanBlock( + default=True, + help_text="If left checked, the image will be cropped to be square.", + required=False, + ), + ), + ] + ) + ), + ) + ] + ), + ), + ( + "image_text", + wagtail.blocks.StructBlock( + [ + ("image", wagtail.images.blocks.ImageChooserBlock()), + ( + "altText", + wagtail.blocks.CharBlock( + help_text="Image description (for screen readers).", required=True + ), + ), + ( + "text", + wagtail.blocks.RichTextBlock( + features=[ + "bold", + "italic", + "link", + "h2", + "h3", + "h4", + "h5", + "ol", + "ul", + "hr", + "document-link", + ] + ), + ), + ( + "url", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "link_to", + wagtail.blocks.ChoiceBlock( + choices=[ + ("page", "Page"), + ("external_url", "External URL"), + ("relative_url", "Relative URL"), + ("email", "Email"), + ("anchor", "Anchor"), + ("file", "File"), + ("phone", "Phone"), + ], + label="Link to", + ), + ), + ( + "page", + wagtail.blocks.PageChooserBlock(label="Page", required=False), + ), + ( + "external_url", + wagtail.blocks.URLBlock( + help_text="Enter a full URL including http:// or https://", + label="External URL", + max_length=300, + required=False, + ), + ), + ( + "relative_url", + wagtail.blocks.CharBlock( + help_text='A path relative to this domain. For example, "/foo/bar" or "?foo=bar".', + label="Relative URL", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.RelativeURLValidator() + ], + ), + ), + ( + "anchor", + wagtail.blocks.CharBlock( + help_text='An id attribute of an element on the current page. For example, "#section-1"', + label="#", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.AnchorLinkValidator() + ], + ), + ), + ("email", wagtail.blocks.EmailBlock(required=False)), + ( + "file", + wagtail.documents.blocks.DocumentChooserBlock( + label="File", required=False + ), + ), + ( + "phone", + wagtail.blocks.CharBlock( + label="Phone", max_length=30, required=False + ), + ), + ( + "new_window", + wagtail.blocks.BooleanBlock( + label="Open in new window", required=False + ), + ), + ] + ), + help_text="Optional URL that this image should link out to.", + max_num=1, + min_num=0, + ), + ), + ( + "top_divider", + wagtail.blocks.BooleanBlock( + help_text="Optional divider above content block.", required=False + ), + ), + ( + "bottom_divider", + wagtail.blocks.BooleanBlock( + help_text="Optional divider below content block.", required=False + ), + ), + ] + ), + ), + ( + "double_image", + wagtail.blocks.StructBlock( + [ + ("image_1", wagtail.images.blocks.ImageChooserBlock()), + ( + "image_1_caption", + wagtail.blocks.RichTextBlock( + features=["bold", "italic", "link"], label="Image caption", required=False + ), + ), + ("image_2", wagtail.images.blocks.ImageChooserBlock()), + ( + "image_2_caption", + wagtail.blocks.RichTextBlock( + features=["bold", "italic", "link"], label="Image caption", required=False + ), + ), + ] + ), + ), + ( + "full_width_image", + wagtail.blocks.StructBlock( + [ + ("image", wagtail.images.blocks.ImageChooserBlock()), + ( + "image_height", + wagtail.blocks.IntegerBlock( + default=410, + help_text="A custom height for this image. The image will be 1400px wide by this height. Note: This may cause images to look pixelated. If the browser is wider than 1400px the height will scale vertically while the width scales horizontally", + ), + ), + ( + "caption", + wagtail.blocks.RichTextBlock( + features=["bold", "italic", "link"], label="Image caption", required=False + ), + ), + ] + ), + ), + ( + "iframe", + wagtail.blocks.StructBlock( + [ + ( + "url", + wagtail.blocks.CharBlock( + help_text="Please note that only URLs from allow-listed domains will work." + ), + ), + ( + "height", + wagtail.blocks.IntegerBlock( + help_text="Optional integer pixel value for custom iFrame height", + required=False, + ), + ), + ("caption", wagtail.blocks.CharBlock(required=False)), + ( + "caption_url", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "link_to", + wagtail.blocks.ChoiceBlock( + choices=[ + ("page", "Page"), + ("external_url", "External URL"), + ("relative_url", "Relative URL"), + ("email", "Email"), + ("anchor", "Anchor"), + ("file", "File"), + ("phone", "Phone"), + ], + label="Link to", + ), + ), + ( + "page", + wagtail.blocks.PageChooserBlock(label="Page", required=False), + ), + ( + "external_url", + wagtail.blocks.URLBlock( + help_text="Enter a full URL including http:// or https://", + label="External URL", + max_length=300, + required=False, + ), + ), + ( + "relative_url", + wagtail.blocks.CharBlock( + help_text='A path relative to this domain. For example, "/foo/bar" or "?foo=bar".', + label="Relative URL", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.RelativeURLValidator() + ], + ), + ), + ( + "anchor", + wagtail.blocks.CharBlock( + help_text='An id attribute of an element on the current page. For example, "#section-1"', + label="#", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.AnchorLinkValidator() + ], + ), + ), + ("email", wagtail.blocks.EmailBlock(required=False)), + ( + "file", + wagtail.documents.blocks.DocumentChooserBlock( + label="File", required=False + ), + ), + ( + "phone", + wagtail.blocks.CharBlock( + label="Phone", max_length=30, required=False + ), + ), + ( + "new_window", + wagtail.blocks.BooleanBlock( + label="Open in new window", required=False + ), + ), + ] + ), + help_text="Optional URL that this caption should link out to.", + max_num=1, + min_num=0, + ), + ), + ( + "iframe_width", + wagtail.blocks.ChoiceBlock( + choices=[("normal", "Normal"), ("wide", "Wide"), ("full_width", "Full Width")], + help_text="Wide iframes are col-12, Full-Width iframes reach both ends of the screen", + ), + ), + ( + "disable_scroll", + wagtail.blocks.BooleanBlock( + default=False, + help_text='Checking this will add "scrolling=no" to the iframe. Use this if your iframe is rendering an unnecessary scroll bar or whitespace below it.', + required=False, + ), + ), + ] + ), + ), + ( + "linkbutton", + wagtail.blocks.StructBlock( + [ + ("label", wagtail.blocks.CharBlock()), + ( + "link_to", + wagtail.blocks.ChoiceBlock( + choices=[ + ("page", "Page"), + ("external_url", "External URL"), + ("relative_url", "Relative URL"), + ("email", "Email"), + ("anchor", "Anchor"), + ("file", "File"), + ("phone", "Phone"), + ], + label="Link to", + ), + ), + ("page", wagtail.blocks.PageChooserBlock(label="Page", required=False)), + ( + "external_url", + wagtail.blocks.URLBlock( + help_text="Enter a full URL including http:// or https://", + label="External URL", + max_length=300, + required=False, + ), + ), + ( + "relative_url", + wagtail.blocks.CharBlock( + help_text='A path relative to this domain. For example, "/foo/bar" or "?foo=bar".', + label="Relative URL", + max_length=300, + required=False, + validators=[networkapi.wagtailpages.validators.RelativeURLValidator()], + ), + ), + ( + "anchor", + wagtail.blocks.CharBlock( + help_text='An id attribute of an element on the current page. For example, "#section-1"', + label="#", + max_length=300, + required=False, + validators=[networkapi.wagtailpages.validators.AnchorLinkValidator()], + ), + ), + ("email", wagtail.blocks.EmailBlock(required=False)), + ("file", wagtail.documents.blocks.DocumentChooserBlock(label="File", required=False)), + ("phone", wagtail.blocks.CharBlock(label="Phone", max_length=30, required=False)), + ( + "new_window", + wagtail.blocks.BooleanBlock(label="Open in new window", required=False), + ), + ( + "styling", + wagtail.blocks.ChoiceBlock( + choices=[ + ("btn-primary", "Primary button"), + ("btn-secondary", "Secondary button"), + ] + ), + ), + ] + ), + ), + ( + "single_quote", + wagtail.blocks.StructBlock( + [ + ("quote", wagtail.blocks.RichTextBlock(features=["bold"])), + ("attribution", wagtail.blocks.CharBlock(required=False)), + ( + "attribution_info", + wagtail.blocks.RichTextBlock(features=["bold", "link", "large"], required=False), + ), + ] + ), + ), + ( + "slider", + wagtail.blocks.StructBlock( + [ + ( + "title", + wagtail.blocks.CharBlock(help_text="Heading for the slider.", required=False), + ), + ( + "slides", + wagtail.blocks.StreamBlock( + [ + ( + "slide", + wagtail.blocks.StructBlock( + [ + ( + "title", + wagtail.blocks.CharBlock( + help_text="Heading of the card.", required=False + ), + ), + ( + "image", + wagtail.images.blocks.ImageChooserBlock( + help_text="The image associated with this event." + ), + ), + ( + "caption", + wagtail.blocks.TextBlock( + help_text="Caption for slider image", required=False + ), + ), + ( + "body", + wagtail.blocks.RichTextBlock( + blank=True, + features=["bold", "italic", "link", "large"], + required=False, + ), + ), + ( + "buttons", + wagtail.blocks.StreamBlock( + [ + ( + "internal", + wagtail.blocks.StructBlock( + [ + ( + "label", + wagtail.blocks.CharBlock( + help_text="Label for this link." + ), + ), + ( + "link", + wagtail.blocks.PageChooserBlock( + help_text="Page that this should link out to." + ), + ), + ] + ), + ), + ( + "external", + wagtail.blocks.StructBlock( + [ + ( + "label", + wagtail.blocks.CharBlock( + help_text="Label for this link." + ), + ), + ( + "link", + wagtail.blocks.URLBlock( + help_text="URL that this should link out to." + ), + ), + ] + ), + ), + ( + "document", + wagtail.blocks.StructBlock( + [ + ( + "label", + wagtail.blocks.CharBlock( + help_text="Label for this link." + ), + ), + ( + "document", + wagtail.documents.blocks.DocumentChooserBlock( + help_text="Document that this should link out to." + ), + ), + ], + help_text='An iCal document can be attached here for an "Add to Calendar" button.', + ), + ), + ], + help_text="A list of buttons that will appear at the bottom of the card.", + max_num=2, + required=False, + ), + ), + ] + ), + ) + ], + help_text="A list of slides.", + ), + ), + ] + ), + ), + ( + "spacer", + wagtail.blocks.StructBlock( + [ + ( + "size", + wagtail.blocks.ChoiceBlock( + choices=[ + ("1", "quarter spacing"), + ("2", "half spacing"), + ("3", "single spacing"), + ("4", "one and a half spacing"), + ("5", "triple spacing"), + ] + ), + ) + ] + ), + ), + ( + "table", + wagtail.blocks.StructBlock( + [ + ("table", wagtail.contrib.table_block.blocks.TableBlock()), + ( + "wide", + wagtail.blocks.BooleanBlock( + default=True, + help_text="If checked, the table will render wider than the other page body content.", + required=False, + ), + ), + ] + ), + ), + ( + "video", + wagtail.blocks.StructBlock( + [ + ( + "url", + wagtail.blocks.URLBlock( + help_text="For YouTube: go to your YouTube video and click “Share,” then “Embed,” and then copy and paste the provided URL only. For example: https://www.youtube.com/embed/3FIVXBawyQw For Vimeo: follow similar steps to grab the embed URL. For example: https://player.vimeo.com/video/9004979", + label="Embed URL", + ), + ), + ("caption", wagtail.blocks.CharBlock(required=False)), + ( + "caption_url", + wagtail.blocks.ListBlock( + wagtail.blocks.StructBlock( + [ + ( + "link_to", + wagtail.blocks.ChoiceBlock( + choices=[ + ("page", "Page"), + ("external_url", "External URL"), + ("relative_url", "Relative URL"), + ("email", "Email"), + ("anchor", "Anchor"), + ("file", "File"), + ("phone", "Phone"), + ], + label="Link to", + ), + ), + ( + "page", + wagtail.blocks.PageChooserBlock(label="Page", required=False), + ), + ( + "external_url", + wagtail.blocks.URLBlock( + help_text="Enter a full URL including http:// or https://", + label="External URL", + max_length=300, + required=False, + ), + ), + ( + "relative_url", + wagtail.blocks.CharBlock( + help_text='A path relative to this domain. For example, "/foo/bar" or "?foo=bar".', + label="Relative URL", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.RelativeURLValidator() + ], + ), + ), + ( + "anchor", + wagtail.blocks.CharBlock( + help_text='An id attribute of an element on the current page. For example, "#section-1"', + label="#", + max_length=300, + required=False, + validators=[ + networkapi.wagtailpages.validators.AnchorLinkValidator() + ], + ), + ), + ("email", wagtail.blocks.EmailBlock(required=False)), + ( + "file", + wagtail.documents.blocks.DocumentChooserBlock( + label="File", required=False + ), + ), + ( + "phone", + wagtail.blocks.CharBlock( + label="Phone", max_length=30, required=False + ), + ), + ( + "new_window", + wagtail.blocks.BooleanBlock( + label="Open in new window", required=False + ), + ), + ] + ), + help_text="Optional URL that this caption should link out to.", + max_num=1, + min_num=0, + ), + ), + ( + "video_width", + wagtail.blocks.ChoiceBlock( + choices=[("normal", "Normal"), ("wide", "Wide"), ("full_width", "Full Width")], + help_text="Wide videos are col-12, Full-Width videos reach both ends of the screen.", + ), + ), + ] + ), + ), + ( + "advanced_table", + wagtail.blocks.StructBlock( + [ + ( + "header", + wagtail.blocks.BooleanBlock( + help_text="Display the first row as a header.", required=False + ), + ), + ( + "column", + wagtail.blocks.BooleanBlock( + help_text="Display the first column as a header.", required=False + ), + ), + ( + "caption", + wagtail.blocks.CharBlock( + help_text="A heading that identifies the overall topic of the table, and is useful for screen reader users", + required=False, + ), + ), + ( + "wide", + wagtail.blocks.BooleanBlock( + default=True, + help_text="If this is checked, the table will render wider than the other page body content.", + required=False, + ), + ), + ( + "table", + wagtail.blocks.StreamBlock( + [ + ( + "row", + wagtail.blocks.StreamBlock( + [ + ( + "cell", + wagtail.blocks.StructBlock( + [ + ( + "centered_text", + wagtail.blocks.BooleanBlock(required=False), + ), + ( + "column_width", + wagtail.blocks.IntegerBlock( + default=1, + help_text="Enter the number of extra cell columns you want to merge together. Merging a cell column will expand a cell to the right. To merge two cells together, set the column width to 2. For 3, set 3. Default is 1. Min 1. Max 20.", + validators=[ + django.core.validators.MaxValueValidator( + 20 + ), + django.core.validators.MinValueValidator( + 1 + ), + ], + ), + ), + ( + "content", + wagtail.blocks.RichTextBlock( + features=[ + "bold", + "italic", + "link", + "ul", + "ol", + ] + ), + ), + ] + ), + ) + ] + ), + ) + ] + ), + ), + ] + ), + ), + ], + use_json_field=True, + ), + ), + MigrateStreamData( + app_name="wagtailpages", + model_name="ArticlePage", + field_name="body", + operations_and_block_paths=[ + (AlterStreamChildBlockDataOperation(block="table", operation=migrate_tableblock), ""), + ], + ), + ] diff --git a/network-api/networkapi/wagtailpages/pagemodels/article_fields.py b/network-api/networkapi/wagtailpages/pagemodels/article_fields.py index 1925be94cc9..c6afece6844 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/article_fields.py +++ b/network-api/networkapi/wagtailpages/pagemodels/article_fields.py @@ -3,7 +3,6 @@ """ from wagtail import blocks -from wagtail.contrib.table_block.blocks import TableBlock from . import customblocks from .customblocks.base_rich_text_options import base_rich_text_options @@ -37,7 +36,7 @@ ("single_quote", customblocks.SingleQuoteBlock()), ("slider", customblocks.FoundationSliderBlock()), ("spacer", customblocks.BootstrapSpacerBlock()), - ("table", TableBlock(template="wagtailpages/blocks/article_table_block.html")), + ("table", customblocks.WideTableBlock()), ("video", customblocks.VideoBlock()), ("advanced_table", customblocks.AdvancedTableBlock()), ] diff --git a/network-api/networkapi/wagtailpages/pagemodels/customblocks/__init__.py b/network-api/networkapi/wagtailpages/pagemodels/customblocks/__init__.py index eb9cb5dc0b4..54e7ab37fbe 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/customblocks/__init__.py +++ b/network-api/networkapi/wagtailpages/pagemodels/customblocks/__init__.py @@ -51,6 +51,7 @@ from .session_slider_block import SessionSliderBlock from .single_quote_block import SingleQuoteBlock from .spaces_block import SpacesBlock +from .table_block import WideTableBlock from .text_only_teaser import TextOnlyTeaserBlock from .tito_widget import TitoWidgetBlock from .video_block import ExternalVideoBlock, VideoBlock, WagtailVideoChooserBlock diff --git a/network-api/networkapi/wagtailpages/pagemodels/customblocks/table_block.py b/network-api/networkapi/wagtailpages/pagemodels/customblocks/table_block.py new file mode 100644 index 00000000000..d2d77328c79 --- /dev/null +++ b/network-api/networkapi/wagtailpages/pagemodels/customblocks/table_block.py @@ -0,0 +1,37 @@ +from wagtail import blocks +from wagtail.contrib.table_block.blocks import TableBlock + + +class WideTableBlock(blocks.StructBlock): + """ + A custom block that contains a table and an option to render it wider than the page body content. + """ + + table = TableBlock() + + wide = blocks.BooleanBlock( + required=False, + default=True, + help_text="If checked, the table will render wider than the other page body content.", + ) + + def get_context(self, value, parent_context=None): + """ + Override get_context to add the table body logic to the template context. + If `first_row_is_table_header` is True, it slices the data to skip the first row. + Otherwise, it returns the full data set. + """ + context = super().get_context(value, parent_context=parent_context) + + # Check if the first row is a header and slice the data accordingly + if value.get("table").get("first_row_is_table_header") is True: + context["table_body"] = value["table"]["data"][1:] # Skip the first row + else: + context["table_body"] = value["table"]["data"] # Return the full data set + + return context + + class Meta: + icon = "table" + label = "Table" + template = "wagtailpages/blocks/wide_table_block.html" diff --git a/network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/article_table_block.html b/network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/article_table_block.html deleted file mode 100644 index cdce4d92e6a..00000000000 --- a/network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/article_table_block.html +++ /dev/null @@ -1,67 +0,0 @@ -{% extends "./base_streamfield_block.html" %} -{% load wagtailcore_tags table_block_tags %} - -{% block block_content %} -
- {% comment %} - Modified table template comes from "table_block/blocks/table.html" - {% endcomment %} - - {% if table_caption %} - - {% endif %} - {% if table_header %} - - - {% for column in table_header %} - {% with forloop.counter0 as col_index %} - - {% endwith %} - {% endfor %} - - - {% endif %} - - {% for row in data %} - {% with forloop.counter0 as row_index %} - - {% for column in row %} - {% with forloop.counter0 as col_index %} - {% if first_col_is_header and forloop.first %} - - {% else %} - - {% endif %} - {% endwith %} - {% endfor %} - - {% endwith %} - {% endfor %} - -
{{ table_caption }}
- {% if column.strip %} - {% if html_renderer %} - {{ column.strip|safe|linebreaksbr }} - {% else %} - {{ column.strip|linebreaksbr }} - {% endif %} - {% endif %} -
- {% if column.strip %} - {% if html_renderer %} - {{ column.strip|safe|linebreaksbr }} - {% else %} - {{ column.strip|linebreaksbr }} - {% endif %} - {% endif %} - - {% if column.strip %} - {% if html_renderer %} - {{ column.strip|safe|linebreaksbr }} - {% else %} - {{ column.strip|linebreaksbr }} - {% endif %} - {% endif %} -
-
-{% endblock %} diff --git a/network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/wide_table_block.html b/network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/wide_table_block.html new file mode 100644 index 00000000000..a5e81539802 --- /dev/null +++ b/network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/wide_table_block.html @@ -0,0 +1,59 @@ +{% extends "./base_streamfield_block.html" %} +{% load wagtailcore_tags table_block_tags %} + +{% block block_content %} + {% with self.table as table %} +
+ {% comment %} + Modified table template comes from "table_block/blocks/table.html" + {% endcomment %} + + {% if table.table_caption %} + + {% endif %} + {% if table.first_row_is_table_header %} + + + {% for column in table.data.0 %} + + {% endfor %} + + + {% endif %} + + {% for row in table_body %} + {% with forloop.counter0 as row_index %} + + {% for column in row %} + {% with forloop.counter0 as col_index %} + {% if table.first_col_is_header and forloop.first %} + + {% else %} + + {% endif %} + {% endwith %} + {% endfor %} + + {% endwith %} + {% endfor %} + +
{{ table.table_caption }}
{{ column }}
+ {% if column.strip %} + {% if html_renderer %} + {{ column.strip|safe|linebreaksbr }} + {% else %} + {{ column.strip|linebreaksbr }} + {% endif %} + {% endif %} + + {% if column.strip %} + {% if html_renderer %} + {{ column.strip|safe|linebreaksbr }} + {% else %} + {{ column.strip|linebreaksbr }} + {% endif %} + {% endif %} +
+
+ {% endwith %} +{% endblock block_content %} diff --git a/pyproject.toml b/pyproject.toml index 810352ab920..fb745a13eea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -123,7 +123,6 @@ ignore="H017" "network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/article_double_image_block.html" = "H006,T003" "network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/article_full_width_image_block.html" = "H006,T003" "network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/article_image_block.html" = "H006,T003" -"network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/article_table_block.html" = "T003" "network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/article_teaser_block.html" = "H006,T003" "network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/audio_block.html" = "T002,T003" "network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/base_streamfield_block.html" = "T003"