Template render richtext without wrapper, add wagtail.contrib.legacy.richtext

* Add wagtail.contrib.legacy.richtext with tests & docs
* Make RichText.__html__ behave the same as template filter
* Resolves #1214
pull/6050/head
Coen van der Kamp 2020-05-16 21:35:22 +02:00 zatwierdzone przez LB
rodzic eed16e0034
commit a1a2c35c1c
17 zmienionych plików z 81 dodań i 30 usunięć

Wyświetl plik

@ -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)

Wyświetl plik

@ -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``

Wyświetl plik

@ -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>``).

Wyświetl plik

@ -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>

Wyświetl plik

@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Wyświetl plik

@ -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)

Wyświetl plik

@ -0,0 +1 @@
<div class="rich-text">{{ html|safe }}</div>

Wyświetl plik

@ -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>""")

Wyświetl plik

@ -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__())

Wyświetl plik

@ -0,0 +1 @@
{{ html|safe }}

Wyświetl plik

@ -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):

Wyświetl plik

@ -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
)

Wyświetl plik

@ -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
)

Wyświetl plik

@ -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):

Wyświetl plik

@ -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>',
])

Wyświetl plik

@ -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"):