kopia lustrzana https://github.com/wagtail/wagtail
Decouple frontend link/embed rewriters from editorHTML handling in FeatureRegistry
rodzic
3e1ab7e74f
commit
0262c7de00
|
@ -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)
|
||||
])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>"
|
||||
|
|
|
@ -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">')
|
||||
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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>"
|
||||
|
|
|
@ -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">')
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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'])
|
||||
|
|
|
@ -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/'}
|
||||
)
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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', ''))
|
||||
|
|
|
@ -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'},
|
||||
)
|
||||
|
|
|
@ -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(
|
||||
|
|
Ładowanie…
Reference in New Issue