kopia lustrzana https://github.com/wagtail/wagtail
Add a feature-aware HTMLConverter object to handle editorHTML / dbHTML conversion in both directions
rodzic
e65c5a6106
commit
3e1ab7e74f
|
@ -7,8 +7,8 @@ from django.utils.module_loading import import_string
|
|||
|
||||
from wagtail.utils.widgets import WidgetWithScript
|
||||
from wagtail.admin.edit_handlers import RichTextFieldPanel
|
||||
from wagtail.admin.rich_text.converters.editor_html import DbWhitelister
|
||||
from wagtail.core.rich_text import expand_db_html, features
|
||||
from wagtail.admin.rich_text.converters.editor_html import EditorHTMLConverter
|
||||
from wagtail.core.rich_text import features
|
||||
|
||||
|
||||
class HalloPlugin:
|
||||
|
@ -91,9 +91,9 @@ class HalloRichTextArea(WidgetWithScript, widgets.Textarea):
|
|||
self.features = kwargs.pop('features', None)
|
||||
if self.features is None:
|
||||
self.features = features.get_default_features()
|
||||
self.whitelister = DbWhitelister()
|
||||
self.converter = EditorHTMLConverter()
|
||||
else:
|
||||
self.whitelister = DbWhitelister(self.features)
|
||||
self.converter = EditorHTMLConverter(self.features)
|
||||
|
||||
# construct a list of plugin objects, by querying the feature registry
|
||||
# and keeping the non-null responses from get_editor_plugin
|
||||
|
@ -109,7 +109,7 @@ class HalloRichTextArea(WidgetWithScript, widgets.Textarea):
|
|||
if value is None:
|
||||
translated_value = None
|
||||
else:
|
||||
translated_value = expand_db_html(value, for_editor=True)
|
||||
translated_value = self.converter.from_database_format(value)
|
||||
return super().render(name, translated_value, attrs)
|
||||
|
||||
def render_js_init(self, id_, name, value):
|
||||
|
@ -129,7 +129,7 @@ class HalloRichTextArea(WidgetWithScript, widgets.Textarea):
|
|||
original_value = super().value_from_datadict(data, files, name)
|
||||
if original_value is None:
|
||||
return None
|
||||
return self.whitelister.clean(original_value)
|
||||
return self.converter.to_database_format(original_value)
|
||||
|
||||
@property
|
||||
def media(self):
|
||||
|
|
|
@ -2,6 +2,7 @@ from django.utils.functional import cached_property
|
|||
|
||||
from wagtail.core import hooks
|
||||
from wagtail.core.rich_text import features
|
||||
from wagtail.core.rich_text.rewriters import EmbedRewriter, LinkRewriter, MultiRuleRewriter
|
||||
from wagtail.core.whitelist import allow_without_attributes, Whitelister, DEFAULT_ELEMENT_RULES
|
||||
|
||||
|
||||
|
@ -108,3 +109,37 @@ class DbWhitelister(Whitelister):
|
|||
tag.name = 'p'
|
||||
|
||||
super(DbWhitelister, self).clean_tag_node(doc, tag)
|
||||
|
||||
|
||||
class EditorHTMLConverter:
|
||||
def __init__(self, features=None):
|
||||
self.features = features
|
||||
self.whitelister = DbWhitelister(features)
|
||||
|
||||
def to_database_format(self, html):
|
||||
return self.whitelister.clean(html)
|
||||
|
||||
@cached_property
|
||||
def html_rewriter(self):
|
||||
if self.features is None:
|
||||
feature_list = features.get_default_features()
|
||||
else:
|
||||
feature_list = self.features
|
||||
|
||||
embed_rules = {}
|
||||
link_rules = {}
|
||||
for feature in feature_list:
|
||||
embed_handlers = features.get_embed_handler_rules(feature)
|
||||
for handler_name, handler in embed_handlers.items():
|
||||
embed_rules[handler_name] = handler.expand_db_attributes_for_editor
|
||||
|
||||
link_handlers = features.get_link_handler_rules(feature)
|
||||
for handler_name, handler in link_handlers.items():
|
||||
link_rules[handler_name] = handler.expand_db_attributes_for_editor
|
||||
|
||||
return MultiRuleRewriter([
|
||||
LinkRewriter(link_rules), EmbedRewriter(embed_rules)
|
||||
])
|
||||
|
||||
def from_database_format(self, html):
|
||||
return self.html_rewriter(html)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from bs4 import BeautifulSoup
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
|
@ -459,3 +461,33 @@ class TestWidgetWhitelisting(TestCase, WagtailTestUtils):
|
|||
'body': '<p>image <img src="foo" data-embedtype="image" data-id="123" data-format="left" data-alt="test alt" /> embed <span data-embedtype="media" data-url="https://www.youtube.com/watch?v=vwyuB8QKzBI">blah</span></p>'
|
||||
}, {}, 'body')
|
||||
self.assertHTMLEqual(result, '<p>image <embed embedtype="image" id="123" format="left" alt="test alt" /> embed </p>')
|
||||
|
||||
|
||||
class TestWidgetRendering(TestCase, WagtailTestUtils):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_default_features(self):
|
||||
widget = HalloRichTextArea()
|
||||
|
||||
result = widget.render(
|
||||
'foo',
|
||||
'<p>a <a linktype="page" id="3">page</a> and a <a linktype="document" id="1">document</a></p>',
|
||||
{'id': 'id_foo'},
|
||||
)
|
||||
soup = BeautifulSoup(result, 'html.parser')
|
||||
result_value = soup.textarea.string
|
||||
|
||||
self.assertHTMLEqual(result_value, '<p>a <a data-linktype="page" data-id="3" data-parent-id="2" href="/events/">page</a> and a <a data-linktype="document" data-id="1" href="/documents/1/test.pdf">document</a></p>')
|
||||
|
||||
def test_custom_features(self):
|
||||
widget = HalloRichTextArea(features=['h1', 'link', 'somethingijustmadeup'])
|
||||
|
||||
result = widget.render(
|
||||
'foo',
|
||||
'<p>a <a linktype="page" id="3">page</a> and a <a linktype="document" id="1">document</a></p>',
|
||||
{'id': 'id_foo'},
|
||||
)
|
||||
soup = BeautifulSoup(result, 'html.parser')
|
||||
result_value = soup.textarea.string
|
||||
|
||||
self.assertHTMLEqual(result_value, '<p>a <a data-linktype="page" data-id="3" data-parent-id="2" href="/events/">page</a> and a <a>document</a></p>')
|
||||
|
|
|
@ -7,60 +7,36 @@ from wagtail.core.rich_text.rewriters import EmbedRewriter, LinkRewriter, MultiR
|
|||
features = FeatureRegistry()
|
||||
|
||||
|
||||
# Rewriter functions to be built up on first call to expand_db_html, using the utility classes
|
||||
# Rewriter function to be built up on first call to expand_db_html, using the utility classes
|
||||
# from wagtail.core.rich_text.rewriters along with the embed handlers / link handlers registered
|
||||
# with the feature registry
|
||||
|
||||
FRONTEND_REWRITER = None
|
||||
EDITOR_REWRITER = None
|
||||
|
||||
|
||||
def expand_db_html(html, for_editor=False):
|
||||
def expand_db_html(html):
|
||||
"""
|
||||
Expand database-representation HTML into proper HTML usable in either
|
||||
templates or the rich text editor
|
||||
Expand database-representation HTML into proper HTML usable on front-end templates
|
||||
"""
|
||||
global FRONTEND_REWRITER, EDITOR_REWRITER
|
||||
global FRONTEND_REWRITER
|
||||
|
||||
if for_editor:
|
||||
if FRONTEND_REWRITER is None:
|
||||
embed_handlers = features.get_all_embed_handler_rules()
|
||||
embed_rules = {
|
||||
handler_name: handler.expand_db_attributes
|
||||
for handler_name, handler in embed_handlers.items()
|
||||
}
|
||||
link_handlers = features.get_all_link_handler_rules()
|
||||
link_rules = {
|
||||
handler_name: handler.expand_db_attributes
|
||||
for handler_name, handler in link_handlers.items()
|
||||
}
|
||||
|
||||
if EDITOR_REWRITER is None:
|
||||
embed_handlers = features.get_all_embed_handler_rules()
|
||||
embed_rules = {
|
||||
handler_name: handler.expand_db_attributes_for_editor
|
||||
for handler_name, handler in embed_handlers.items()
|
||||
}
|
||||
link_handlers = features.get_all_link_handler_rules()
|
||||
link_rules = {
|
||||
handler_name: handler.expand_db_attributes_for_editor
|
||||
for handler_name, handler in link_handlers.items()
|
||||
}
|
||||
FRONTEND_REWRITER = MultiRuleRewriter([
|
||||
LinkRewriter(link_rules), EmbedRewriter(embed_rules)
|
||||
])
|
||||
|
||||
EDITOR_REWRITER = MultiRuleRewriter([
|
||||
LinkRewriter(link_rules), EmbedRewriter(embed_rules)
|
||||
])
|
||||
|
||||
return EDITOR_REWRITER(html)
|
||||
|
||||
else:
|
||||
|
||||
if FRONTEND_REWRITER is None:
|
||||
embed_handlers = features.get_all_embed_handler_rules()
|
||||
embed_rules = {
|
||||
handler_name: handler.expand_db_attributes
|
||||
for handler_name, handler in embed_handlers.items()
|
||||
}
|
||||
link_handlers = features.get_all_link_handler_rules()
|
||||
link_rules = {
|
||||
handler_name: handler.expand_db_attributes
|
||||
for handler_name, handler in link_handlers.items()
|
||||
}
|
||||
|
||||
FRONTEND_REWRITER = MultiRuleRewriter([
|
||||
LinkRewriter(link_rules), EmbedRewriter(embed_rules)
|
||||
])
|
||||
|
||||
return FRONTEND_REWRITER(html)
|
||||
return FRONTEND_REWRITER(html)
|
||||
|
||||
|
||||
class RichText:
|
||||
|
|
Ładowanie…
Reference in New Issue