diff --git a/CHANGELOG.txt b/CHANGELOG.txt index b25ab116aa..cf902af6cd 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -35,6 +35,7 @@ Changelog * Improve performance of empty search results by avoiding downloading the entire search index in these scenarios (Lars van de Kerkhof, Coen van der Kamp) * Replace `gulp-sass` with `gulp-dart-sass` to improve core development across different platforms (Thibaud Colas) * Add SVG icons to resolve accessibility and customisation issues and start using them in a subset of Wagtail's admin (Coen van der Kamp, Scott Cranfill, Thibaud Colas) + * Remove markup around rich text rendering by default, provide a way to use old behaviour via `wagtail.contrib.legacy.richtext` (Coen van der Kamp, Dan Braghis) * Fix: Support IPv6 domain (Alex Gleason, Coen van der Kamp) * Fix: Ensure link to add a new user works when no users are visible in the users list (LB (Ben Johnston)) * Fix: `AbstractEmailForm` saved submission fields are now aligned with the email content fields, `form.cleaned_data` will be used instead of `form.fields` (Haydn Greatnews) diff --git a/docs/getting_started/tutorial.rst b/docs/getting_started/tutorial.rst index 819bd84333..eba012adfd 100644 --- a/docs/getting_started/tutorial.rst +++ b/docs/getting_started/tutorial.rst @@ -202,11 +202,9 @@ Produces: .. code-block:: html - <div class="rich-text"> - <p> - <b>Welcome</b> to our new site! - </p> - </div> + <p> + <b>Welcome</b> to our new site! + </p> **Note:** You'll need to include ``{% load wagtailcore_tags %}`` in each template that uses Wagtail's tags. Django will throw a ``TemplateSyntaxError`` diff --git a/docs/reference/contrib/index.rst b/docs/reference/contrib/index.rst index 3405da2c2e..dd26bbeca2 100644 --- a/docs/reference/contrib/index.rst +++ b/docs/reference/contrib/index.rst @@ -17,6 +17,7 @@ Wagtail ships with a variety of extra optional modules. searchpromotions table_block redirects + legacy_richtext :doc:`settings` @@ -72,3 +73,9 @@ Provides a TableBlock for adding HTML tables to pages. ----------------------- Provides a way to manage redirects. + + +:doc:`legacy_richtext` +----------------------- + +Provides the legacy richtext wrapper (``<div class="rich-text"></div>``). diff --git a/docs/reference/contrib/legacy_richtext.rst b/docs/reference/contrib/legacy_richtext.rst new file mode 100644 index 0000000000..64a613cbaf --- /dev/null +++ b/docs/reference/contrib/legacy_richtext.rst @@ -0,0 +1,26 @@ +.. _legacy_richtext: + +===================== +Legacy richtext +===================== + +.. module:: wagtail.contrib.legacy.richtext + +Provides the legacy richtext wrapper. + +Place ``wagtail.contrib.legacy.richtext`` before ``wagtail.core`` in ``INSTALLED_APPS``. + + .. code-block:: python + + INSTALLED_APPS = [ + ... + "wagtail.contrib.legacy.richtext", + "wagtail.core", + ... + ] + +The ``{{ page.body|richtext }}`` template filter will now render: + + .. code-block:: html+django + + <div class="rich-text">...</div> diff --git a/docs/releases/2.10.rst b/docs/releases/2.10.rst index 5ef21045d5..c25cfa9ba5 100644 --- a/docs/releases/2.10.rst +++ b/docs/releases/2.10.rst @@ -48,6 +48,7 @@ Other features * Improve performance of empty search results by avoiding downloading the entire search index in these scenarios (Lars van de Kerkhof, Coen van der Kamp) * Replace ``gulp-sass`` with ``gulp-dart-sass`` to improve core development across different platforms (Thibaud Colas) * Add SVG icons to resolve accessibility and customisation issues and start using them in a subset of Wagtail's admin (Coen van der Kamp, Scott Cranfill, Thibaud Colas) + * Remove markup around rich text rendering by default, provide a way to use old behaviour via ``wagtail.contrib.legacy.richtext``. See :ref:`legacy_richtext`. (Coen van der Kamp, Dan Braghis) Bug fixes @@ -66,6 +67,9 @@ Bug fixes Upgrade considerations ====================== + * Rich text will now be rendered without any markup, to use the old behaviour where a wrapper ``<div class="richt-text">`` is used see :ref:`legacy_richtext`. + + Removed support for Python 3.5 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/wagtail/admin/tests/test_rich_text.py b/wagtail/admin/tests/test_rich_text.py index 5ea01cc872..8aadafdf74 100644 --- a/wagtail/admin/tests/test_rich_text.py +++ b/wagtail/admin/tests/test_rich_text.py @@ -323,8 +323,7 @@ class TestRichTextValue(TestCase): value = RichText(text) result = str(value) expected = ( - '<div class="rich-text"><p>To the <a href="' - '/foo/pointless-suffix/">moon</a>!</p></div>') + '<p>To the <a href="/foo/pointless-suffix/">moon</a>!</p>') self.assertEqual(result, expected) diff --git a/wagtail/contrib/legacy/richtext/templates/wagtailcore/shared/richtext.html b/wagtail/contrib/legacy/richtext/templates/wagtailcore/shared/richtext.html new file mode 100644 index 0000000000..12e914c8ac --- /dev/null +++ b/wagtail/contrib/legacy/richtext/templates/wagtailcore/shared/richtext.html @@ -0,0 +1 @@ +<div class="rich-text">{{ html|safe }}</div> \ No newline at end of file diff --git a/wagtail/contrib/legacy/richtext/tests/__init__.py b/wagtail/contrib/legacy/richtext/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/wagtail/contrib/legacy/richtext/tests/test_templatetag.py b/wagtail/contrib/legacy/richtext/tests/test_templatetag.py new file mode 100644 index 0000000000..e5e7254753 --- /dev/null +++ b/wagtail/contrib/legacy/richtext/tests/test_templatetag.py @@ -0,0 +1,14 @@ +from django.test import TestCase + +from wagtail.core.templatetags.wagtailcore_tags import richtext + + +class TestTemplateTag(TestCase): + def test_no_contrib_legacy_richtext_no_wrapper(self): + self.assertEqual(richtext("Foo"), "Foo") + + def test_contrib_legacy_richtext_renders_wrapper(self): + with self.modify_settings( + INSTALLED_APPS={"prepend": "wagtail.contrib.legacy.richtext"} + ): + self.assertEqual(richtext("Foo"), """<div class="rich-text">Foo</div>""") diff --git a/wagtail/core/rich_text/__init__.py b/wagtail/core/rich_text/__init__.py index 6eef65d738..e90b37d333 100644 --- a/wagtail/core/rich_text/__init__.py +++ b/wagtail/core/rich_text/__init__.py @@ -1,4 +1,5 @@ from django.db.models import Model +from django.template.loader import render_to_string from django.utils.safestring import mark_safe from wagtail.core.rich_text.feature_registry import FeatureRegistry @@ -43,7 +44,7 @@ class RichText: self.source = (source or '') def __html__(self): - return '<div class="rich-text">' + expand_db_html(self.source) + '</div>' + return render_to_string('wagtailcore/shared/richtext.html', {'html': expand_db_html(self.source)}) def __str__(self): return mark_safe(self.__html__()) diff --git a/wagtail/core/templates/wagtailcore/shared/richtext.html b/wagtail/core/templates/wagtailcore/shared/richtext.html new file mode 100644 index 0000000000..cd10e94a25 --- /dev/null +++ b/wagtail/core/templates/wagtailcore/shared/richtext.html @@ -0,0 +1 @@ +{{ html|safe }} \ No newline at end of file diff --git a/wagtail/core/templatetags/wagtailcore_tags.py b/wagtail/core/templatetags/wagtailcore_tags.py index ef871a5738..b7d8287602 100644 --- a/wagtail/core/templatetags/wagtailcore_tags.py +++ b/wagtail/core/templatetags/wagtailcore_tags.py @@ -1,8 +1,8 @@ from django import template from django.shortcuts import reverse from django.template.defaulttags import token_kwargs +from django.template.loader import render_to_string from django.utils.encoding import force_str -from django.utils.safestring import mark_safe from wagtail import VERSION, __version__ from wagtail.core.models import Page, Site @@ -104,8 +104,7 @@ def richtext(value): html = expand_db_html(value) else: raise TypeError("'richtext' template filter received an invalid value; expected string, got {}.".format(type(value))) - - return mark_safe('<div class="rich-text">' + html + '</div>') + return render_to_string('wagtailcore/shared/richtext.html', {'html': html}) class IncludeBlockNode(template.Node): diff --git a/wagtail/core/tests/test_blocks.py b/wagtail/core/tests/test_blocks.py index f39350736c..93885674f8 100644 --- a/wagtail/core/tests/test_blocks.py +++ b/wagtail/core/tests/test_blocks.py @@ -508,7 +508,7 @@ class TestRichTextBlock(TestCase): value = RichText('<p>Merry <a linktype="page" id="4">Christmas</a>!</p>') result = block.render(value) self.assertEqual( - result, '<div class="rich-text"><p>Merry <a href="/events/christmas/">Christmas</a>!</p></div>' + result, '<p>Merry <a href="/events/christmas/">Christmas</a>!</p>' ) def test_render_form(self): @@ -1448,7 +1448,7 @@ class TestStructBlock(SimpleTestCase): 'body': '<b>world</b>', }) body_bound_block = struct_value.bound_blocks['body'] - expected = '<div class="rich-text"><b>world</b></div>' + expected = '<b>world</b>' self.assertEqual(str(body_bound_block), expected) def test_get_form_context(self): @@ -1725,13 +1725,13 @@ class TestStructBlock(SimpleTestCase): block = SectionBlock() value = block.to_python({'title': 'Hello', 'body': '<i>italic</i> world'}) result = block.render(value) - self.assertEqual(result, """<h1>Hello</h1><div class="rich-text"><i>italic</i> world</div>""") + self.assertEqual(result, """<h1>Hello</h1><i>italic</i> world""") def test_render_block_with_extra_context(self): block = SectionBlock() value = block.to_python({'title': 'Bonjour', 'body': 'monde <i>italique</i>'}) result = block.render(value, context={'language': 'fr'}) - self.assertEqual(result, """<h1 lang="fr">Bonjour</h1><div class="rich-text">monde <i>italique</i></div>""") + self.assertEqual(result, """<h1 lang="fr">Bonjour</h1>monde <i>italique</i>""") def test_render_structvalue(self): """ @@ -1740,11 +1740,11 @@ class TestStructBlock(SimpleTestCase): block = SectionBlock() value = block.to_python({'title': 'Hello', 'body': '<i>italic</i> world'}) result = value.__html__() - self.assertEqual(result, """<h1>Hello</h1><div class="rich-text"><i>italic</i> world</div>""") + self.assertEqual(result, """<h1>Hello</h1><i>italic</i> world""") # value.render_as_block() should be equivalent to value.__html__() result = value.render_as_block() - self.assertEqual(result, """<h1>Hello</h1><div class="rich-text"><i>italic</i> world</div>""") + self.assertEqual(result, """<h1>Hello</h1><i>italic</i> world""") def test_str_structvalue(self): """ @@ -1769,7 +1769,7 @@ class TestStructBlock(SimpleTestCase): block = SectionBlock() value = block.to_python({'title': 'Bonjour', 'body': 'monde <i>italique</i>'}) result = value.render_as_block(context={'language': 'fr'}) - self.assertEqual(result, """<h1 lang="fr">Bonjour</h1><div class="rich-text">monde <i>italique</i></div>""") + self.assertEqual(result, """<h1 lang="fr">Bonjour</h1>monde <i>italique</i>""") class TestStructBlockWithCustomStructValue(SimpleTestCase): @@ -2493,8 +2493,8 @@ class TestStreamBlock(WagtailTestUtils, SimpleTestCase): ]) self.assertIn('<div class="block-heading">My title</div>', html) - self.assertIn('<div class="block-paragraph"><div class="rich-text">My <i>first</i> paragraph</div></div>', html) - self.assertIn('<div class="block-paragraph"><div class="rich-text">My second paragraph</div></div>', html) + self.assertIn('<div class="block-paragraph">My <i>first</i> paragraph</div>', html) + self.assertIn('<div class="block-paragraph">My second paragraph</div>', html) def test_render_unknown_type(self): # This can happen if a developer removes a type from their StreamBlock @@ -2510,7 +2510,7 @@ class TestStreamBlock(WagtailTestUtils, SimpleTestCase): ]) self.assertNotIn('foo', html) self.assertNotIn('Hello', html) - self.assertIn('<div class="block-paragraph"><div class="rich-text">My first paragraph</div></div>', html) + self.assertIn('<div class="block-paragraph">My first paragraph</div>', html) def test_render_calls_block_render_on_children(self): """ @@ -3674,7 +3674,7 @@ class TestIncludeBlockTag(TestCase): }) self.assertIn( - """<body><h1 lang="fr">Bonjour</h1><div class="rich-text">monde <i>italique</i></div></body>""", + """<body><h1 lang="fr">Bonjour</h1>monde <i>italique</i></body>""", result ) diff --git a/wagtail/core/tests/test_jinja2.py b/wagtail/core/tests/test_jinja2.py index a47406e783..7685a89f68 100644 --- a/wagtail/core/tests/test_jinja2.py +++ b/wagtail/core/tests/test_jinja2.py @@ -33,7 +33,7 @@ class TestCoreGlobalsAndFilters(TestCase): richtext = '<p>Merry <a linktype="page" id="2">Christmas</a>!</p>' self.assertEqual( self.render('{{ text|richtext }}', {'text': richtext}), - '<div class="rich-text"><p>Merry <a href="/">Christmas</a>!</p></div>') + '<p>Merry <a href="/">Christmas</a>!</p>') def test_pageurl(self): page = Page.objects.get(pk=2) @@ -95,7 +95,7 @@ class TestJinjaEscaping(TestCase): 'value': stream_value, }) - self.assertIn('<div class="rich-text"><p>Merry <a href="/events/christmas/">Christmas</a>!</p></div>', result) + self.assertIn('<p>Merry <a href="/events/christmas/">Christmas</a>!</p>', result) class TestIncludeBlockTag(TestCase): @@ -127,7 +127,7 @@ class TestIncludeBlockTag(TestCase): }) self.assertIn( - """<body><h1 lang="fr">Bonjour</h1><div class="rich-text">monde <i>italique</i></div></body>""", + """<body><h1 lang="fr">Bonjour</h1>monde <i>italique</i></body>""", result ) diff --git a/wagtail/core/tests/test_rich_text.py b/wagtail/core/tests/test_rich_text.py index c3806e2fd2..3962509f7f 100644 --- a/wagtail/core/tests/test_rich_text.py +++ b/wagtail/core/tests/test_rich_text.py @@ -67,7 +67,7 @@ class TestRichTextValue(TestCase): result = str(value) self.assertEqual( result, - '<div class="rich-text"><p>Merry <a href="/events/christmas/">Christmas</a>!</p></div>' + '<p>Merry <a href="/events/christmas/">Christmas</a>!</p>' ) def test_evaluate_value(self): diff --git a/wagtail/core/tests/test_streamfield.py b/wagtail/core/tests/test_streamfield.py index 64b9442641..01bec7272f 100644 --- a/wagtail/core/tests/test_streamfield.py +++ b/wagtail/core/tests/test_streamfield.py @@ -192,8 +192,8 @@ class TestStreamFieldRenderingBase(TestCase): img_tag = self.image.get_rendition('original').img_tag() self.expected = ''.join([ - '<div class="block-rich_text"><div class="rich-text"><p>Rich text</p></div></div>', - '<div class="block-rich_text"><div class="rich-text"><p>Привет, Микола</p></div></div>', + '<div class="block-rich_text"><p>Rich text</p></div>', + '<div class="block-rich_text"><p>Привет, Микола</p></div>', '<div class="block-image">{}</div>'.format(img_tag), '<div class="block-text">Hello, World!</div>', ]) diff --git a/wagtail/core/tests/tests.py b/wagtail/core/tests/tests.py index 42ff571cde..3ddb824d1d 100644 --- a/wagtail/core/tests/tests.py +++ b/wagtail/core/tests/tests.py @@ -311,12 +311,12 @@ class TestResolveModelString(TestCase): class TestRichtextTag(TestCase): def test_call_with_text(self): result = richtext("Hello world!") - self.assertEqual(result, '<div class="rich-text">Hello world!</div>') + self.assertEqual(result, 'Hello world!') self.assertIsInstance(result, SafeString) def test_call_with_none(self): result = richtext(None) - self.assertEqual(result, '<div class="rich-text"></div>') + self.assertEqual(result, '') def test_call_with_invalid_value(self): with self.assertRaisesRegex(TypeError, "'richtext' template filter received an invalid value"):