Wagtail Draftail editor moves ending whitespace at the boundary of overlapping or composite HTML tags outside the tag
See original GitHub issueIssue Summary
Italicized words inside a boldfaced string is one instance. But the following is a general issue.
For example, what I want is this: “you may not believe what…”.
Wagtail changes <b>may </b><b><i>not</i></b>
to <b>may</b> <b><i>not</i></b>
while saving (update: it does it while fetching and not saving) the page to the database. The spaceless
templatetag (from Django) removes spaces between the tags, and I rely heavily on it.
So, in the end there is no space between may and not.
The first time such text is added to the editor, the published text looks good. But this issue creeps in if I edit the page and republish it.
Steps to Reproduce
- Install a fresh wagtail site.
- Have this in the home app’s
models.py
file:
from django.db import models
from wagtail.core.models import Page
from wagtail.core.fields import RichTextField
from wagtail.admin.edit_handlers import FieldPanel
class HomePage(Page):
body = RichTextField()
content_panels = Page.content_panels + [
FieldPanel('body', classname="full"),
]
Run makemigrations
and migrate
.
- In
base.html
of the root app, surround the html with:
{% spaceless %}
...
{% endspaceless %}
- In home app’s
home_page.html
, have this:
{% block content %}
<div>
{{page.body|richtext}}
</div>
{% endblock content %}
-
Now run the app using
runserver
, and go to Wagtail admin interface. Add a new page to the Home app, and something like this in the rich text editor: You may not believe what is happening! Publish the page and observe the text - it will look good. -
Edit the page again, do not make any changes, and publish again. The string will change, and there will be no space between may and not.
- I have confirmed that this issue can be reproduced as described on a fresh Wagtail project: yes
Technical details
- Python version: 3.8.5
- Django version: 3.1.5
- Wagtail version: 2.11.3
- Browser version: Chrome 87
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (2 by maintainers)
For anyone interested in this issue, I have worked around by stopping using
{% spaceless %}
. It should be possible to use it around non-rich-text elements, but I chose to simply not use it anywhere for the time being.I’m now using
django.middleware.gzip.GZipMiddleware
which is supported by all major browsers. It does not strip spaces (it is lossless), but otherwise provides very good compression ratio.Spending a bit more time with this, I see that there does seem to be a conversion bug as you describe, even when the markup initially comes from Wagtail.
Authoring this in the rich text editor:
**bold _bolditalic_**
Draftail serializes that as what I’d expect:
The contentstate -> HTML conversion produces an unexpected sequence of tags (see also https://github.com/springload/draftjs_exporter/issues/136), but the whitespace is still within the bold formatting:
Then re-editing this in the CMS, HTML -> ContentState moves the whitespace outside of the bold style:
Saving this again, we get the incorrect but expected:
I see this also happens for juxtaposed links (so I’d assume all inline entities or styles) – again the trailing whitespace moves out of the first tag and goes in-between.
Link content conversions
After authoring
[link ](/)[link](/)
in the editor:Then contentstate -> HTML rendered on the page as:
Then HTML -> contentstate back into the CMS UI:
Then re-rendering this to the page:
Thinking of what this causes in practice – I think the most likely issue would be if people use inline formatting where whitespace is styled, for example with a strikethrough, underline, or background like
s
,mark
,ins
,del
,u
:Strikes backvsStrikesbackvsStrikesback<del>Removed content</del> vs <del>Removed </del><del>content</del> vs <del>Removed</del> <del>content</del>
This would also be an issue for links but it’s not like people are likely to want to link over whitespace anyway.
Back to spaceless though – even if we were to fix this it still won’t change the fact that spaceless breaks the very reasonable
<p><a href="/">link</a> <a href="/">link</a></p>
. So yes I think going for a smarter compressor is mandatory if you want to run this over inline tags. And even then, those compressors only know about elements’ inline vs block formatting as defined by the HTML spec (assuming your site’s stylesheets don’t switch block-level elements to inline).