Feature request: add API to customise front-end HTML rendering of rich text features
See original GitHub issueIssue Summary
New feature: add an additional “rich text features” API to give developers full control over how the front-end HTML is created, for custom and also built-in features.
At the moment, unless the feature is a link with a linktype or an embed (images and actual embeds), we can only define how it is stored as HTML in the DB. This means that the feature’s “storage format” must be the same as its “front-end format”. This is too limiting – for example, it should be possible to add a class attribute to the feature’s front-end output without having it stored in the DB. It should be possible to store a strikethrough
format as <s>
tags but render them on the front-end as a more semantic <del>
, should it make more sense for a given site.
Here is what the current APIs allows you to do:
features.register_converter_rule(
'contentstate', 'blockquote', {
[...]
'to_database_format': {
'block_map': {'blockquote': {
'element': 'blockquote',
# Those presentational attributes will be stored. Bad!
'props': {
'class': 'richtext__blockquote',
}
}}
}
})
Ideally, there should be a separate to_frontend_html
(or equivalent) to control the HTML on the front-end only. Note: it might not make sense to put this in register_converter_rule
, since these are specific to a given converter (editorhtml for Hallo, contentstate for Draftail), whereas the new feature wouldn’t be.
Use cases
Here are the use cases we had when building WagtailDraftail, beyond custom links and embeds:
DRAFT_EXPORTER_BLOCK_MAP = dict(BLOCK_MAP, **{
'unordered-list-item': {
'element': 'li',
'wrapper': 'ul',
# Adding a class to rich text elements to make styling easier.
'wrapper_props': {'class': 'list-styled'},
},
'header-two': 'h3',
'intro': {
'element': 'p',
# Having a rich text format that's based on the same tag as other formats, + some classes.
'props': {'class': 'intro'},
},
})
Context
This is the last missing piece to bring Wagtail’s Draftail integration to parity with WagtailDraftail (and make that plugin useless, yay!).
It would also:
- Support what is requested in #3257 (and thus #1167).
- Help with mitigating #1214.
- Potentially replace the undocumented
register_rich_text_embed_handler
/register_rich_text_link_handler
(#1094)
For the implementation, I’m not sure whether the existing handlers for linktypes and embeds can be repurposed / extended, or construct_whitelister_element_rules
, or whether we need something separate. draftjs_exporter
’s API is meant to support this kind of scenario, so one way to do this would be to do the contentstate from_database_format
conversion, and then use Draft.js exporter to create the HTML (like to_database_format
), but this might be overkill.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:4
- Comments:20 (16 by maintainers)
Top GitHub Comments
Sorry about the repeated reference notification 👆 😰
So loicteixeira/wagtail@428f1081b53af083dec0bd3d99700039a5ce69df implements option 6 and here is the result of a quick benchmark:
Standard Page
. 10 rich-text blocks (body) 1 rich-text field (footer)Methodology
With
debug_toolbar
andtemplate_profiler_panel
to thebakerydemo
project, run the following script twice, once with Wagtail unchanged, and a second time with Wagtail patched.I think we should replace the HTML representation of rich text fields with a JSON based representation based on StreamField and the new ParagraphBlock type described in https://github.com/wagtail/rfcs/pull/46
This would mean rich text fields would need a process for rendering to HTML, like StreamField. I think that could simplify the implementation of an API like this.
I also think that using JSON over HTML would also simplify the implementation of rich-text diffing, commenting, importers, and headless sites.
<script>
tag in the JSON format so you won’t need to consider this