Decouple frontend link/embed rewriters from editorHTML handling in FeatureRegistry

pull/4079/merge
Matt Westcott 2017-12-07 22:11:29 +00:00
rodzic 3e1ab7e74f
commit 0262c7de00
14 zmienionych plików z 91 dodań i 97 usunięć

Wyświetl plik

@ -21,17 +21,8 @@ def expand_db_html(html):
global FRONTEND_REWRITER
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()
}
embed_rules = features.get_embed_types()
link_rules = features.get_link_types()
FRONTEND_REWRITER = MultiRuleRewriter([
LinkRewriter(link_rules), EmbedRewriter(embed_rules)
])

Wyświetl plik

@ -26,6 +26,17 @@ class FeatureRegistry:
# an explicit `feature` list.
self.default_features = []
# a mapping of linktype names to rewriter functions for converting database representations
# of links (e.g. <a linktype="page" id="123">) into front-end HTML. Each rewriter function
# takes a dict of attributes, and returns the rewritten opening tag as a string
self.link_types = {}
# a mapping of embedtype names to rewriter functions for converting database representations
# of embedded content (e.g. <embed embedtype="image" id="123" format="left" alt="foo">)
# into front-end HTML. Each rewriter function takes a dict of attributes, and returns an
# HTML fragment to replace it with
self.embed_types = {}
# a mapping of feature names to whitelister element rules that should be merged into
# the whitelister element_rules config when the feature is active
self.whitelister_element_rules = {}
@ -62,6 +73,22 @@ class FeatureRegistry:
except KeyError:
return None
def register_link_type(self, link_type, handler):
self.link_types[link_type] = handler
def get_link_types(self):
if not self.has_scanned_for_features:
self._scan_for_features()
return self.link_types
def register_embed_type(self, embed_type, handler):
self.embed_types[embed_type] = handler
def get_embed_types(self):
if not self.has_scanned_for_features:
self._scan_for_features()
return self.embed_types
def register_whitelister_element_rules(self, feature_name, ruleset):
self.whitelister_element_rules[feature_name] = ruleset
@ -80,20 +107,6 @@ class FeatureRegistry:
return self.embed_handler_rules.get(feature_name, {})
def get_all_embed_handler_rules(self):
"""
Return a dictionary of embedtypes to embed handlers, collated from all the
registered embed handler rules
"""
if not self.has_scanned_for_features:
self._scan_for_features()
collated_ruleset = {}
for ruleset in self.embed_handler_rules.values():
collated_ruleset.update(ruleset)
return collated_ruleset
def register_link_handler_rules(self, feature_name, ruleset):
self.link_handler_rules[feature_name] = ruleset
@ -102,17 +115,3 @@ class FeatureRegistry:
self._scan_for_features()
return self.link_handler_rules.get(feature_name, {})
def get_all_link_handler_rules(self):
"""
Return a dictionary of linktypes to link handlers, collated from all the
registered link handler rules
"""
if not self.has_scanned_for_features:
self._scan_for_features()
collated_ruleset = {}
for ruleset in self.link_handler_rules.values():
collated_ruleset.update(ruleset)
return collated_ruleset

Wyświetl plik

@ -19,14 +19,6 @@ class PageLinkHandler:
"""
return {'id': tag['data-id']}
@staticmethod
def expand_db_attributes(attrs):
try:
page = Page.objects.get(id=attrs['id'])
return '<a href="%s">' % escape(page.specific.url)
except Page.DoesNotExist:
return "<a>"
@staticmethod
def expand_db_attributes_for_editor(attrs):
try:
@ -40,3 +32,11 @@ class PageLinkHandler:
return '<a %shref="%s">' % (attrs, escape(page.specific.url))
except Page.DoesNotExist:
return "<a>"
def page_linktype_handler(attrs):
try:
page = Page.objects.get(id=attrs['id'])
return '<a href="%s">' % escape(page.specific.url)
except Page.DoesNotExist:
return "<a>"

Wyświetl plik

@ -5,7 +5,7 @@ from mock import patch
from wagtail.core.models import Page
from wagtail.core.rich_text import RichText, expand_db_html
from wagtail.core.rich_text.feature_registry import FeatureRegistry
from wagtail.core.rich_text.pages import PageLinkHandler
from wagtail.core.rich_text.pages import PageLinkHandler, page_linktype_handler
from wagtail.core.rich_text.rewriters import extract_attrs
@ -20,7 +20,7 @@ class TestPageLinkHandler(TestCase):
{'id': 'test-id'})
def test_expand_db_attributes_page_does_not_exist(self):
result = PageLinkHandler.expand_db_attributes({'id': 0})
result = page_linktype_handler({'id': 0})
self.assertEqual(result, '<a>')
def test_expand_db_attributes_for_editor(self):
@ -38,7 +38,7 @@ class TestPageLinkHandler(TestCase):
)
def test_expand_db_attributes_not_for_editor(self):
result = PageLinkHandler.expand_db_attributes({'id': 1})
result = page_linktype_handler({'id': 1})
self.assertEqual(result, '<a href="None">')

Wyświetl plik

@ -4,7 +4,7 @@ from django.urls import reverse
from wagtail.core import hooks
from wagtail.core.models import PageViewRestriction
from wagtail.core.rich_text.pages import PageLinkHandler
from wagtail.core.rich_text.pages import PageLinkHandler, page_linktype_handler
from wagtail.core.whitelist import allow_without_attributes, attribute_rule, check_url
@ -42,6 +42,7 @@ def register_core_features(features):
features.default_features.append('link')
features.register_whitelister_element_rules('link', {'a': attribute_rule({'href': check_url})})
features.register_link_type('page', page_linktype_handler)
features.register_link_handler_rules('link', {'page': PageLinkHandler})
features.default_features.append('bold')

Wyświetl plik

@ -8,15 +8,6 @@ class DocumentLinkHandler:
def get_db_attributes(tag):
return {'id': tag['data-id']}
@staticmethod
def expand_db_attributes(attrs):
Document = get_document_model()
try:
doc = Document.objects.get(id=attrs['id'])
return '<a href="%s">' % escape(doc.url)
except Document.DoesNotExist:
return "<a>"
@staticmethod
def expand_db_attributes_for_editor(attrs):
Document = get_document_model()
@ -25,3 +16,12 @@ class DocumentLinkHandler:
return '<a data-linktype="document" data-id="%d" href="%s">' % (doc.id, escape(doc.url))
except Document.DoesNotExist:
return "<a>"
def document_linktype_handler(attrs):
Document = get_document_model()
try:
doc = Document.objects.get(id=attrs['id'])
return '<a href="%s">' % escape(doc.url)
except Document.DoesNotExist:
return "<a>"

Wyświetl plik

@ -1,7 +1,7 @@
from bs4 import BeautifulSoup
from django.test import TestCase
from wagtail.documents.rich_text import DocumentLinkHandler
from wagtail.documents.rich_text import DocumentLinkHandler, document_linktype_handler
class TestDocumentRichTextLinkHandler(TestCase):
@ -15,7 +15,7 @@ class TestDocumentRichTextLinkHandler(TestCase):
{'id': 'test-id'})
def test_expand_db_attributes_document_does_not_exist(self):
result = DocumentLinkHandler.expand_db_attributes({'id': 0})
result = document_linktype_handler({'id': 0})
self.assertEqual(result, '<a>')
def test_expand_db_attributes_for_editor(self):
@ -24,6 +24,6 @@ class TestDocumentRichTextLinkHandler(TestCase):
'<a data-linktype="document" data-id="1" href="/documents/1/test.pdf">')
def test_expand_db_attributes_not_for_editor(self):
result = DocumentLinkHandler.expand_db_attributes({'id': 1})
result = document_linktype_handler({'id': 1})
self.assertEqual(result,
'<a href="/documents/1/test.pdf">')

Wyświetl plik

@ -19,7 +19,7 @@ from wagtail.documents.api.admin.endpoints import DocumentsAdminAPIEndpoint
from wagtail.documents.forms import GroupDocumentPermissionFormSet
from wagtail.documents.models import get_document_model
from wagtail.documents.permissions import permission_policy
from wagtail.documents.rich_text import DocumentLinkHandler
from wagtail.documents.rich_text import DocumentLinkHandler, document_linktype_handler
@hooks.register('register_admin_urls')
@ -73,6 +73,7 @@ def editor_js():
@hooks.register('register_rich_text_features')
def register_document_feature(features):
features.register_link_type('document', document_linktype_handler)
features.register_editor_plugin(
'hallo', 'document-link',
HalloPlugin(

Wyświetl plik

@ -20,14 +20,6 @@ class MediaEmbedHandler:
'url': tag['data-url'],
}
@staticmethod
def expand_db_attributes(attrs):
"""
Given a dict of attributes from the <embed> tag, return the real HTML
representation for use on the front-end.
"""
return format.embed_to_frontend_html(attrs['url'])
@staticmethod
def expand_db_attributes_for_editor(attrs):
"""
@ -39,3 +31,11 @@ class MediaEmbedHandler:
except EmbedException:
# Could be replaced with a nice error message
return ''
def media_embedtype_handler(attrs):
"""
Given a dict of attributes from the <embed> tag, return the real HTML
representation for use on the front-end.
"""
return format.embed_to_frontend_html(attrs['url'])

Wyświetl plik

@ -22,7 +22,7 @@ from wagtail.embeds.finders.embedly import EmbedlyFinder as EmbedlyFinder
from wagtail.embeds.finders.embedly import AccessDeniedEmbedlyException, EmbedlyException
from wagtail.embeds.finders.oembed import OEmbedFinder as OEmbedFinder
from wagtail.embeds.models import Embed
from wagtail.embeds.rich_text import MediaEmbedHandler
from wagtail.embeds.rich_text import MediaEmbedHandler, media_embedtype_handler
from wagtail.embeds.templatetags.wagtailembeds_tags import embed_tag
try:
@ -598,7 +598,7 @@ class TestMediaEmbedHandler(TestCase):
height=1000,
)
result = MediaEmbedHandler.expand_db_attributes(
result = media_embedtype_handler(
{'url': 'http://www.youtube.com/watch/'}
)
self.assertIn('test html', result)
@ -607,7 +607,7 @@ class TestMediaEmbedHandler(TestCase):
def test_expand_db_attributes_catches_embed_not_found(self, get_embed):
get_embed.side_effect = EmbedNotFoundException
result = MediaEmbedHandler.expand_db_attributes(
result = media_embedtype_handler(
{'url': 'http://www.youtube.com/watch/'}
)

Wyświetl plik

@ -5,7 +5,7 @@ from django.utils.html import format_html
from wagtail.admin.rich_text import HalloPlugin
from wagtail.core import hooks
from wagtail.embeds import urls
from wagtail.embeds.rich_text import MediaEmbedHandler
from wagtail.embeds.rich_text import MediaEmbedHandler, media_embedtype_handler
@hooks.register('register_admin_urls')
@ -29,6 +29,7 @@ def editor_js():
@hooks.register('register_rich_text_features')
def register_embed_feature(features):
features.register_embed_type('media', media_embedtype_handler)
features.register_editor_plugin(
'hallo', 'embed',
HalloPlugin(

Wyświetl plik

@ -22,21 +22,6 @@ class ImageEmbedHandler:
'alt': tag['data-alt'],
}
@staticmethod
def expand_db_attributes(attrs):
"""
Given a dict of attributes from the <embed> tag, return the real HTML
representation for use on the front-end.
"""
Image = get_image_model()
try:
image = Image.objects.get(id=attrs['id'])
except Image.DoesNotExist:
return "<img>"
image_format = get_image_format(attrs['format'])
return image_format.image_to_html(image, attrs.get('alt', ''))
@staticmethod
def expand_db_attributes_for_editor(attrs):
"""
@ -52,3 +37,18 @@ class ImageEmbedHandler:
image_format = get_image_format(attrs['format'])
return image_format.image_to_editor_html(image, attrs.get('alt', ''))
def image_embedtype_handler(attrs):
"""
Given a dict of attributes from the <embed> tag, return the real HTML
representation for use on the front-end.
"""
Image = get_image_model()
try:
image = Image.objects.get(id=attrs['id'])
except Image.DoesNotExist:
return "<img>"
image_format = get_image_format(attrs['format'])
return image_format.image_to_html(image, attrs.get('alt', ''))

Wyświetl plik

@ -1,7 +1,7 @@
from bs4 import BeautifulSoup
from django.test import TestCase
from wagtail.images.rich_text import ImageEmbedHandler
from wagtail.images.rich_text import ImageEmbedHandler, image_embedtype_handler
from .utils import Image, get_test_image_file
@ -20,12 +20,12 @@ class TestImageEmbedHandler(TestCase):
'format': 'test-format'})
def test_expand_db_attributes_image_does_not_exist(self):
result = ImageEmbedHandler.expand_db_attributes({'id': 0})
result = image_embedtype_handler({'id': 0})
self.assertEqual(result, '<img>')
def test_expand_db_attributes_not_for_editor(self):
Image.objects.create(id=1, title='Test', file=get_test_image_file())
result = ImageEmbedHandler.expand_db_attributes(
result = image_embedtype_handler(
{'id': 1,
'alt': 'test-alt',
'format': 'left'}
@ -34,7 +34,7 @@ class TestImageEmbedHandler(TestCase):
def test_expand_db_attributes_escapes_alt_text(self):
Image.objects.create(id=1, title='Test', file=get_test_image_file())
result = ImageEmbedHandler.expand_db_attributes(
result = image_embedtype_handler(
{'id': 1,
'alt': 'Arthur "two sheds" Jackson',
'format': 'left'},
@ -43,7 +43,7 @@ class TestImageEmbedHandler(TestCase):
def test_expand_db_attributes_with_missing_alt(self):
Image.objects.create(id=1, title='Test', file=get_test_image_file())
result = ImageEmbedHandler.expand_db_attributes(
result = image_embedtype_handler(
{'id': 1,
'format': 'left'},
)

Wyświetl plik

@ -14,7 +14,7 @@ from wagtail.images import admin_urls, get_image_model, image_operations
from wagtail.images.api.admin.endpoints import ImagesAdminAPIEndpoint
from wagtail.images.forms import GroupImagePermissionFormSet
from wagtail.images.permissions import permission_policy
from wagtail.images.rich_text import ImageEmbedHandler
from wagtail.images.rich_text import ImageEmbedHandler, image_embedtype_handler
@hooks.register('register_admin_urls')
@ -65,6 +65,7 @@ def editor_js():
@hooks.register('register_rich_text_features')
def register_image_feature(features):
features.register_embed_type('image', image_embedtype_handler)
features.register_editor_plugin(
'hallo', 'image',
HalloPlugin(