mirror of
https://github.com/wagtail/wagtail.git
synced 2024-12-01 11:41:20 +01:00
Merge pull request #1093 from gasman/feature/richtext-hooks
Register rich text handlers for docs / images / media through hooks
This commit is contained in:
commit
391e3825f0
@ -4,15 +4,6 @@ from django.utils.html import escape
|
||||
|
||||
from wagtail.wagtailcore.whitelist import Whitelister
|
||||
from wagtail.wagtailcore.models import Page
|
||||
|
||||
from wagtail.wagtaildocs.models import Document
|
||||
|
||||
# FIXME: we don't really want to import wagtailimages within core.
|
||||
# For that matter, we probably don't want core to be concerned about translating
|
||||
# HTML for the benefit of the hallo.js editor...
|
||||
from wagtail.wagtailimages.models import get_image_model
|
||||
from wagtail.wagtailimages.formats import get_image_format
|
||||
|
||||
from wagtail.wagtailcore import hooks
|
||||
|
||||
|
||||
@ -22,80 +13,6 @@ from wagtail.wagtailcore import hooks
|
||||
# elsewhere in the database and is liable to change - from real HTML representation
|
||||
# to DB representation and back again.
|
||||
|
||||
class ImageEmbedHandler(object):
|
||||
"""
|
||||
ImageEmbedHandler will be invoked whenever we encounter an element in HTML content
|
||||
with an attribute of data-embedtype="image". The resulting element in the database
|
||||
representation will be:
|
||||
<embed embedtype="image" id="42" format="thumb" alt="some custom alt text">
|
||||
"""
|
||||
@staticmethod
|
||||
def get_db_attributes(tag):
|
||||
"""
|
||||
Given a tag that we've identified as an image embed (because it has a
|
||||
data-embedtype="image" attribute), return a dict of the attributes we should
|
||||
have on the resulting <embed> element.
|
||||
"""
|
||||
return {
|
||||
'id': tag['data-id'],
|
||||
'format': tag['data-format'],
|
||||
'alt': tag['data-alt'],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def expand_db_attributes(attrs, for_editor):
|
||||
"""
|
||||
Given a dict of attributes from the <embed> tag, return the real HTML
|
||||
representation.
|
||||
"""
|
||||
Image = get_image_model()
|
||||
try:
|
||||
image = Image.objects.get(id=attrs['id'])
|
||||
format = get_image_format(attrs['format'])
|
||||
|
||||
if for_editor:
|
||||
try:
|
||||
return format.image_to_editor_html(image, attrs['alt'])
|
||||
except:
|
||||
return ''
|
||||
else:
|
||||
return format.image_to_html(image, attrs['alt'])
|
||||
|
||||
except Image.DoesNotExist:
|
||||
return "<img>"
|
||||
|
||||
|
||||
class MediaEmbedHandler(object):
|
||||
"""
|
||||
MediaEmbedHandler will be invoked whenever we encounter an element in HTML content
|
||||
with an attribute of data-embedtype="media". The resulting element in the database
|
||||
representation will be:
|
||||
<embed embedtype="media" url="http://vimeo.com/XXXXX">
|
||||
"""
|
||||
@staticmethod
|
||||
def get_db_attributes(tag):
|
||||
"""
|
||||
Given a tag that we've identified as a media embed (because it has a
|
||||
data-embedtype="media" attribute), return a dict of the attributes we should
|
||||
have on the resulting <embed> element.
|
||||
"""
|
||||
return {
|
||||
'url': tag['data-url'],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def expand_db_attributes(attrs, for_editor):
|
||||
"""
|
||||
Given a dict of attributes from the <embed> tag, return the real HTML
|
||||
representation.
|
||||
"""
|
||||
from wagtail.wagtailembeds import format
|
||||
if for_editor:
|
||||
return format.embed_to_editor_html(attrs['url'])
|
||||
else:
|
||||
return format.embed_to_frontend_html(attrs['url'])
|
||||
|
||||
|
||||
class PageLinkHandler(object):
|
||||
"""
|
||||
PageLinkHandler will be invoked whenever we encounter an <a> element in HTML content
|
||||
@ -127,35 +44,38 @@ class PageLinkHandler(object):
|
||||
return "<a>"
|
||||
|
||||
|
||||
class DocumentLinkHandler(object):
|
||||
@staticmethod
|
||||
def get_db_attributes(tag):
|
||||
return {'id': tag['data-id']}
|
||||
|
||||
@staticmethod
|
||||
def expand_db_attributes(attrs, for_editor):
|
||||
try:
|
||||
doc = Document.objects.get(id=attrs['id'])
|
||||
|
||||
if for_editor:
|
||||
editor_attrs = 'data-linktype="document" data-id="%d" ' % doc.id
|
||||
else:
|
||||
editor_attrs = ''
|
||||
|
||||
return '<a %shref="%s">' % (editor_attrs, escape(doc.url))
|
||||
except Document.DoesNotExist:
|
||||
return "<a>"
|
||||
|
||||
|
||||
EMBED_HANDLERS = {
|
||||
'image': ImageEmbedHandler,
|
||||
'media': MediaEmbedHandler,
|
||||
}
|
||||
EMBED_HANDLERS = {}
|
||||
LINK_HANDLERS = {
|
||||
'page': PageLinkHandler,
|
||||
'document': DocumentLinkHandler,
|
||||
}
|
||||
|
||||
has_loaded_embed_handlers = False
|
||||
has_loaded_link_handlers = False
|
||||
|
||||
def get_embed_handler(embed_type):
|
||||
global EMBED_HANDLERS, has_loaded_embed_handlers
|
||||
|
||||
if not has_loaded_embed_handlers:
|
||||
for hook in hooks.get_hooks('register_rich_text_embed_handler'):
|
||||
handler_name, handler = hook()
|
||||
EMBED_HANDLERS[handler_name] = handler
|
||||
|
||||
has_loaded_embed_handlers = True
|
||||
|
||||
return EMBED_HANDLERS[embed_type]
|
||||
|
||||
def get_link_handler(link_type):
|
||||
global LINK_HANDLERS, has_loaded_link_handlers
|
||||
|
||||
if not has_loaded_link_handlers:
|
||||
for hook in hooks.get_hooks('register_rich_text_link_handler'):
|
||||
handler_name, handler = hook()
|
||||
LINK_HANDLERS[handler_name] = handler
|
||||
|
||||
has_loaded_link_handlers = True
|
||||
|
||||
return LINK_HANDLERS[link_type]
|
||||
|
||||
|
||||
class DbWhitelister(Whitelister):
|
||||
"""
|
||||
@ -189,7 +109,7 @@ class DbWhitelister(Whitelister):
|
||||
if 'data-embedtype' in tag.attrs:
|
||||
embed_type = tag['data-embedtype']
|
||||
# fetch the appropriate embed handler for this embedtype
|
||||
embed_handler = EMBED_HANDLERS[embed_type]
|
||||
embed_handler = get_embed_handler(embed_type)
|
||||
embed_attrs = embed_handler.get_db_attributes(tag)
|
||||
embed_attrs['embedtype'] = embed_type
|
||||
|
||||
@ -202,7 +122,7 @@ class DbWhitelister(Whitelister):
|
||||
cls.clean_node(doc, child)
|
||||
|
||||
link_type = tag['data-linktype']
|
||||
link_handler = LINK_HANDLERS[link_type]
|
||||
link_handler = get_link_handler(link_type)
|
||||
link_attrs = link_handler.get_db_attributes(tag)
|
||||
link_attrs['linktype'] = link_type
|
||||
tag.attrs.clear()
|
||||
@ -238,12 +158,12 @@ def expand_db_html(html, for_editor=False):
|
||||
if 'linktype' not in attrs:
|
||||
# return unchanged
|
||||
return m.group(0)
|
||||
handler = LINK_HANDLERS[attrs['linktype']]
|
||||
handler = get_link_handler(attrs['linktype'])
|
||||
return handler.expand_db_attributes(attrs, for_editor)
|
||||
|
||||
def replace_embed_tag(m):
|
||||
attrs = extract_attrs(m.group(1))
|
||||
handler = EMBED_HANDLERS[attrs['embedtype']]
|
||||
handler = get_embed_handler(attrs['embedtype'])
|
||||
return handler.expand_db_attributes(attrs, for_editor)
|
||||
|
||||
html = FIND_A_TAG.sub(replace_a_tag, html)
|
||||
|
@ -3,10 +3,7 @@ from mock import patch
|
||||
from django.test import TestCase
|
||||
|
||||
from wagtail.wagtailcore.rich_text import (
|
||||
ImageEmbedHandler,
|
||||
MediaEmbedHandler,
|
||||
PageLinkHandler,
|
||||
DocumentLinkHandler,
|
||||
DbWhitelister,
|
||||
extract_attrs,
|
||||
expand_db_html
|
||||
@ -14,112 +11,6 @@ from wagtail.wagtailcore.rich_text import (
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
|
||||
class TestImageEmbedHandler(TestCase):
|
||||
fixtures = ['wagtail/tests/fixtures/test.json']
|
||||
|
||||
def test_get_db_attributes(self):
|
||||
soup = BeautifulSoup(
|
||||
'<b data-id="test-id" data-format="test-format" data-alt="test-alt">foo</b>'
|
||||
)
|
||||
tag = soup.b
|
||||
result = ImageEmbedHandler.get_db_attributes(tag)
|
||||
self.assertEqual(result,
|
||||
{'alt': 'test-alt',
|
||||
'id': 'test-id',
|
||||
'format': 'test-format'})
|
||||
|
||||
def test_expand_db_attributes_page_does_not_exist(self):
|
||||
result = ImageEmbedHandler.expand_db_attributes(
|
||||
{'id': 0},
|
||||
False
|
||||
)
|
||||
self.assertEqual(result, '<img>')
|
||||
|
||||
@patch('wagtail.wagtailimages.models.Image')
|
||||
@patch('django.core.files.File')
|
||||
def test_expand_db_attributes_not_for_editor(self, mock_file, mock_image):
|
||||
result = ImageEmbedHandler.expand_db_attributes(
|
||||
{'id': 1,
|
||||
'alt': 'test-alt',
|
||||
'format': 'left'},
|
||||
False
|
||||
)
|
||||
self.assertIn('<img class="richtext-image left"', result)
|
||||
|
||||
@patch('wagtail.wagtailimages.models.Image')
|
||||
@patch('django.core.files.File')
|
||||
def test_expand_db_attributes_for_editor(self, mock_file, mock_image):
|
||||
result = ImageEmbedHandler.expand_db_attributes(
|
||||
{'id': 1,
|
||||
'alt': 'test-alt',
|
||||
'format': 'left'},
|
||||
True
|
||||
)
|
||||
self.assertIn('<img data-embedtype="image" data-id="1" data-format="left" data-alt="test-alt" class="richtext-image left"', result)
|
||||
|
||||
@patch('wagtail.wagtailimages.models.Image')
|
||||
@patch('django.core.files.File')
|
||||
def test_expand_db_attributes_for_editor_throws_exception(self, mock_file, mock_image):
|
||||
result = ImageEmbedHandler.expand_db_attributes(
|
||||
{'id': 1,
|
||||
'format': 'left'},
|
||||
True
|
||||
)
|
||||
self.assertEqual(result, '')
|
||||
|
||||
|
||||
class TestMediaEmbedHandler(TestCase):
|
||||
def test_get_db_attributes(self):
|
||||
soup = BeautifulSoup(
|
||||
'<b data-url="test-url">foo</b>'
|
||||
)
|
||||
tag = soup.b
|
||||
result = MediaEmbedHandler.get_db_attributes(tag)
|
||||
self.assertEqual(result,
|
||||
{'url': 'test-url'})
|
||||
|
||||
@patch('wagtail.wagtailembeds.embeds.oembed')
|
||||
def test_expand_db_attributes_for_editor(self, oembed):
|
||||
oembed.return_value = {
|
||||
'title': 'test title',
|
||||
'author_name': 'test author name',
|
||||
'provider_name': 'test provider name',
|
||||
'type': 'test type',
|
||||
'thumbnail_url': 'test thumbnail url',
|
||||
'width': 'test width',
|
||||
'height': 'test height',
|
||||
'html': 'test html'
|
||||
}
|
||||
result = MediaEmbedHandler.expand_db_attributes(
|
||||
{'url': 'http://www.youtube.com/watch/'},
|
||||
True
|
||||
)
|
||||
self.assertIn('<div class="embed-placeholder" contenteditable="false" data-embedtype="media" data-url="http://www.youtube.com/watch/">', result)
|
||||
self.assertIn('<h3>test title</h3>', result)
|
||||
self.assertIn('<p>URL: http://www.youtube.com/watch/</p>', result)
|
||||
self.assertIn('<p>Provider: test provider name</p>', result)
|
||||
self.assertIn('<p>Author: test author name</p>', result)
|
||||
self.assertIn('<img src="test thumbnail url" alt="test title">', result)
|
||||
|
||||
@patch('wagtail.wagtailembeds.embeds.oembed')
|
||||
def test_expand_db_attributes_not_for_editor(self, oembed):
|
||||
oembed.return_value = {
|
||||
'title': 'test title',
|
||||
'author_name': 'test author name',
|
||||
'provider_name': 'test provider name',
|
||||
'type': 'test type',
|
||||
'thumbnail_url': 'test thumbnail url',
|
||||
'width': 'test width',
|
||||
'height': 'test height',
|
||||
'html': 'test html'
|
||||
}
|
||||
result = MediaEmbedHandler.expand_db_attributes(
|
||||
{'url': 'http://www.youtube.com/watch/'},
|
||||
False
|
||||
)
|
||||
self.assertIn('test html', result)
|
||||
|
||||
|
||||
class TestPageLinkHandler(TestCase):
|
||||
fixtures = ['wagtail/tests/fixtures/test.json']
|
||||
|
||||
@ -155,42 +46,6 @@ class TestPageLinkHandler(TestCase):
|
||||
self.assertEqual(result, '<a href="None">')
|
||||
|
||||
|
||||
class TestDocumentLinkHandler(TestCase):
|
||||
fixtures = ['wagtail/tests/fixtures/test.json']
|
||||
|
||||
def test_get_db_attributes(self):
|
||||
soup = BeautifulSoup(
|
||||
'<a data-id="test-id">foo</a>'
|
||||
)
|
||||
tag = soup.a
|
||||
result = DocumentLinkHandler.get_db_attributes(tag)
|
||||
self.assertEqual(result,
|
||||
{'id': 'test-id'})
|
||||
|
||||
def test_expand_db_attributes_document_does_not_exist(self):
|
||||
result = DocumentLinkHandler.expand_db_attributes(
|
||||
{'id': 0},
|
||||
False
|
||||
)
|
||||
self.assertEqual(result, '<a>')
|
||||
|
||||
def test_expand_db_attributes_for_editor(self):
|
||||
result = DocumentLinkHandler.expand_db_attributes(
|
||||
{'id': 1},
|
||||
True
|
||||
)
|
||||
self.assertEqual(result,
|
||||
'<a data-linktype="document" data-id="1" href="/documents/1/">')
|
||||
|
||||
def test_expand_db_attributes_not_for_editor(self):
|
||||
result = DocumentLinkHandler.expand_db_attributes(
|
||||
{'id': 1},
|
||||
False
|
||||
)
|
||||
self.assertEqual(result,
|
||||
'<a href="/documents/1/">')
|
||||
|
||||
|
||||
class TestDbWhiteLister(TestCase):
|
||||
def test_clean_tag_node_div(self):
|
||||
soup = BeautifulSoup(
|
||||
|
23
wagtail/wagtaildocs/rich_text.py
Normal file
23
wagtail/wagtaildocs/rich_text.py
Normal file
@ -0,0 +1,23 @@
|
||||
from django.utils.html import escape
|
||||
|
||||
from wagtail.wagtaildocs.models import Document
|
||||
|
||||
|
||||
class DocumentLinkHandler(object):
|
||||
@staticmethod
|
||||
def get_db_attributes(tag):
|
||||
return {'id': tag['data-id']}
|
||||
|
||||
@staticmethod
|
||||
def expand_db_attributes(attrs, for_editor):
|
||||
try:
|
||||
doc = Document.objects.get(id=attrs['id'])
|
||||
|
||||
if for_editor:
|
||||
editor_attrs = 'data-linktype="document" data-id="%d" ' % doc.id
|
||||
else:
|
||||
editor_attrs = ''
|
||||
|
||||
return '<a %shref="%s">' % (editor_attrs, escape(doc.url))
|
||||
except Document.DoesNotExist:
|
||||
return "<a>"
|
@ -1,6 +1,7 @@
|
||||
from six import b
|
||||
import unittest
|
||||
import mock
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from django.test import TestCase
|
||||
from django.contrib.auth import get_user_model
|
||||
@ -16,6 +17,7 @@ from wagtail.tests.models import EventPage, EventPageRelatedLink
|
||||
from wagtail.wagtaildocs.models import Document
|
||||
|
||||
from wagtail.wagtaildocs import models
|
||||
from wagtail.wagtaildocs.rich_text import DocumentLinkHandler
|
||||
|
||||
|
||||
class TestDocumentPermissions(TestCase):
|
||||
@ -576,3 +578,39 @@ class TestServeView(TestCase):
|
||||
def test_with_incorrect_filename(self):
|
||||
response = self.client.get(reverse('wagtaildocs_serve', args=(self.document.id, 'incorrectfilename')))
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
|
||||
class TestDocumentLinkHandler(TestCase):
|
||||
fixtures = ['wagtail/tests/fixtures/test.json']
|
||||
|
||||
def test_get_db_attributes(self):
|
||||
soup = BeautifulSoup(
|
||||
'<a data-id="test-id">foo</a>'
|
||||
)
|
||||
tag = soup.a
|
||||
result = DocumentLinkHandler.get_db_attributes(tag)
|
||||
self.assertEqual(result,
|
||||
{'id': 'test-id'})
|
||||
|
||||
def test_expand_db_attributes_document_does_not_exist(self):
|
||||
result = DocumentLinkHandler.expand_db_attributes(
|
||||
{'id': 0},
|
||||
False
|
||||
)
|
||||
self.assertEqual(result, '<a>')
|
||||
|
||||
def test_expand_db_attributes_for_editor(self):
|
||||
result = DocumentLinkHandler.expand_db_attributes(
|
||||
{'id': 1},
|
||||
True
|
||||
)
|
||||
self.assertEqual(result,
|
||||
'<a data-linktype="document" data-id="1" href="/documents/1/">')
|
||||
|
||||
def test_expand_db_attributes_not_for_editor(self):
|
||||
result = DocumentLinkHandler.expand_db_attributes(
|
||||
{'id': 1},
|
||||
False
|
||||
)
|
||||
self.assertEqual(result,
|
||||
'<a href="/documents/1/">')
|
||||
|
@ -10,6 +10,7 @@ from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailadmin.menu import MenuItem
|
||||
|
||||
from wagtail.wagtaildocs import admin_urls
|
||||
from wagtail.wagtaildocs.rich_text import DocumentLinkHandler
|
||||
|
||||
|
||||
@hooks.register('register_admin_urls')
|
||||
@ -53,3 +54,8 @@ def register_permissions():
|
||||
document_content_type = ContentType.objects.get(app_label='wagtaildocs', model='document')
|
||||
document_permissions = Permission.objects.filter(content_type = document_content_type)
|
||||
return document_permissions
|
||||
|
||||
|
||||
@hooks.register('register_rich_text_link_handler')
|
||||
def register_document_link_handler():
|
||||
return ('document', DocumentLinkHandler)
|
||||
|
30
wagtail/wagtailembeds/rich_text.py
Normal file
30
wagtail/wagtailembeds/rich_text.py
Normal file
@ -0,0 +1,30 @@
|
||||
from wagtail.wagtailembeds import format
|
||||
|
||||
class MediaEmbedHandler(object):
|
||||
"""
|
||||
MediaEmbedHandler will be invoked whenever we encounter an element in HTML content
|
||||
with an attribute of data-embedtype="media". The resulting element in the database
|
||||
representation will be:
|
||||
<embed embedtype="media" url="http://vimeo.com/XXXXX">
|
||||
"""
|
||||
@staticmethod
|
||||
def get_db_attributes(tag):
|
||||
"""
|
||||
Given a tag that we've identified as a media embed (because it has a
|
||||
data-embedtype="media" attribute), return a dict of the attributes we should
|
||||
have on the resulting <embed> element.
|
||||
"""
|
||||
return {
|
||||
'url': tag['data-url'],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def expand_db_attributes(attrs, for_editor):
|
||||
"""
|
||||
Given a dict of attributes from the <embed> tag, return the real HTML
|
||||
representation.
|
||||
"""
|
||||
if for_editor:
|
||||
return format.embed_to_editor_html(attrs['url'])
|
||||
else:
|
||||
return format.embed_to_frontend_html(attrs['url'])
|
@ -2,8 +2,10 @@ import six.moves.urllib.request
|
||||
from six.moves.urllib.error import URLError
|
||||
|
||||
from mock import patch
|
||||
import warnings
|
||||
import unittest
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from wagtail.wagtailembeds.rich_text import MediaEmbedHandler
|
||||
|
||||
try:
|
||||
import embedly
|
||||
@ -320,3 +322,55 @@ class TestEmbedBlock(TestCase):
|
||||
|
||||
# Check that the embed was in the returned HTML
|
||||
self.assertIn('<h1>Hello world!</h1>', html)
|
||||
|
||||
|
||||
class TestMediaEmbedHandler(TestCase):
|
||||
def test_get_db_attributes(self):
|
||||
soup = BeautifulSoup(
|
||||
'<b data-url="test-url">foo</b>'
|
||||
)
|
||||
tag = soup.b
|
||||
result = MediaEmbedHandler.get_db_attributes(tag)
|
||||
self.assertEqual(result,
|
||||
{'url': 'test-url'})
|
||||
|
||||
@patch('wagtail.wagtailembeds.embeds.oembed')
|
||||
def test_expand_db_attributes_for_editor(self, oembed):
|
||||
oembed.return_value = {
|
||||
'title': 'test title',
|
||||
'author_name': 'test author name',
|
||||
'provider_name': 'test provider name',
|
||||
'type': 'test type',
|
||||
'thumbnail_url': 'test thumbnail url',
|
||||
'width': 'test width',
|
||||
'height': 'test height',
|
||||
'html': 'test html'
|
||||
}
|
||||
result = MediaEmbedHandler.expand_db_attributes(
|
||||
{'url': 'http://www.youtube.com/watch/'},
|
||||
True
|
||||
)
|
||||
self.assertIn('<div class="embed-placeholder" contenteditable="false" data-embedtype="media" data-url="http://www.youtube.com/watch/">', result)
|
||||
self.assertIn('<h3>test title</h3>', result)
|
||||
self.assertIn('<p>URL: http://www.youtube.com/watch/</p>', result)
|
||||
self.assertIn('<p>Provider: test provider name</p>', result)
|
||||
self.assertIn('<p>Author: test author name</p>', result)
|
||||
self.assertIn('<img src="test thumbnail url" alt="test title">', result)
|
||||
|
||||
@patch('wagtail.wagtailembeds.embeds.oembed')
|
||||
def test_expand_db_attributes_not_for_editor(self, oembed):
|
||||
oembed.return_value = {
|
||||
'title': 'test title',
|
||||
'author_name': 'test author name',
|
||||
'provider_name': 'test provider name',
|
||||
'type': 'test type',
|
||||
'thumbnail_url': 'test thumbnail url',
|
||||
'width': 'test width',
|
||||
'height': 'test height',
|
||||
'html': 'test html'
|
||||
}
|
||||
result = MediaEmbedHandler.expand_db_attributes(
|
||||
{'url': 'http://www.youtube.com/watch/'},
|
||||
False
|
||||
)
|
||||
self.assertIn('test html', result)
|
||||
|
@ -5,6 +5,7 @@ from django.utils.html import format_html
|
||||
|
||||
from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailembeds import urls
|
||||
from wagtail.wagtailembeds.rich_text import MediaEmbedHandler
|
||||
|
||||
|
||||
@hooks.register('register_admin_urls')
|
||||
@ -27,3 +28,8 @@ def editor_js():
|
||||
'wagtailembeds/js/hallo-plugins/hallo-wagtailembeds.js',
|
||||
urlresolvers.reverse('wagtailembeds_chooser')
|
||||
)
|
||||
|
||||
|
||||
@hooks.register('register_rich_text_embed_handler')
|
||||
def register_media_embed_handler():
|
||||
return ('media', MediaEmbedHandler)
|
||||
|
44
wagtail/wagtailimages/rich_text.py
Normal file
44
wagtail/wagtailimages/rich_text.py
Normal file
@ -0,0 +1,44 @@
|
||||
from wagtail.wagtailimages.models import get_image_model
|
||||
from wagtail.wagtailimages.formats import get_image_format
|
||||
|
||||
class ImageEmbedHandler(object):
|
||||
"""
|
||||
ImageEmbedHandler will be invoked whenever we encounter an element in HTML content
|
||||
with an attribute of data-embedtype="image". The resulting element in the database
|
||||
representation will be:
|
||||
<embed embedtype="image" id="42" format="thumb" alt="some custom alt text">
|
||||
"""
|
||||
@staticmethod
|
||||
def get_db_attributes(tag):
|
||||
"""
|
||||
Given a tag that we've identified as an image embed (because it has a
|
||||
data-embedtype="image" attribute), return a dict of the attributes we should
|
||||
have on the resulting <embed> element.
|
||||
"""
|
||||
return {
|
||||
'id': tag['data-id'],
|
||||
'format': tag['data-format'],
|
||||
'alt': tag['data-alt'],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def expand_db_attributes(attrs, for_editor):
|
||||
"""
|
||||
Given a dict of attributes from the <embed> tag, return the real HTML
|
||||
representation.
|
||||
"""
|
||||
Image = get_image_model()
|
||||
try:
|
||||
image = Image.objects.get(id=attrs['id'])
|
||||
format = get_image_format(attrs['format'])
|
||||
|
||||
if for_editor:
|
||||
try:
|
||||
return format.image_to_editor_html(image, attrs['alt'])
|
||||
except:
|
||||
return ''
|
||||
else:
|
||||
return format.image_to_html(image, attrs['alt'])
|
||||
|
||||
except Image.DoesNotExist:
|
||||
return "<img>"
|
60
wagtail/wagtailimages/tests/test_rich_text.py
Normal file
60
wagtail/wagtailimages/tests/test_rich_text.py
Normal file
@ -0,0 +1,60 @@
|
||||
from django.test import TestCase
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from mock import patch
|
||||
|
||||
from wagtail.wagtailimages.rich_text import ImageEmbedHandler
|
||||
|
||||
|
||||
class TestImageEmbedHandler(TestCase):
|
||||
fixtures = ['wagtail/tests/fixtures/test.json']
|
||||
|
||||
def test_get_db_attributes(self):
|
||||
soup = BeautifulSoup(
|
||||
'<b data-id="test-id" data-format="test-format" data-alt="test-alt">foo</b>'
|
||||
)
|
||||
tag = soup.b
|
||||
result = ImageEmbedHandler.get_db_attributes(tag)
|
||||
self.assertEqual(result,
|
||||
{'alt': 'test-alt',
|
||||
'id': 'test-id',
|
||||
'format': 'test-format'})
|
||||
|
||||
def test_expand_db_attributes_page_does_not_exist(self):
|
||||
result = ImageEmbedHandler.expand_db_attributes(
|
||||
{'id': 0},
|
||||
False
|
||||
)
|
||||
self.assertEqual(result, '<img>')
|
||||
|
||||
@patch('wagtail.wagtailimages.models.Image')
|
||||
@patch('django.core.files.File')
|
||||
def test_expand_db_attributes_not_for_editor(self, mock_file, mock_image):
|
||||
result = ImageEmbedHandler.expand_db_attributes(
|
||||
{'id': 1,
|
||||
'alt': 'test-alt',
|
||||
'format': 'left'},
|
||||
False
|
||||
)
|
||||
self.assertIn('<img class="richtext-image left"', result)
|
||||
|
||||
@patch('wagtail.wagtailimages.models.Image')
|
||||
@patch('django.core.files.File')
|
||||
def test_expand_db_attributes_for_editor(self, mock_file, mock_image):
|
||||
result = ImageEmbedHandler.expand_db_attributes(
|
||||
{'id': 1,
|
||||
'alt': 'test-alt',
|
||||
'format': 'left'},
|
||||
True
|
||||
)
|
||||
self.assertIn('<img data-embedtype="image" data-id="1" data-format="left" data-alt="test-alt" class="richtext-image left"', result)
|
||||
|
||||
@patch('wagtail.wagtailimages.models.Image')
|
||||
@patch('django.core.files.File')
|
||||
def test_expand_db_attributes_for_editor_throws_exception(self, mock_file, mock_image):
|
||||
result = ImageEmbedHandler.expand_db_attributes(
|
||||
{'id': 1,
|
||||
'format': 'left'},
|
||||
True
|
||||
)
|
||||
self.assertEqual(result, '')
|
@ -11,6 +11,7 @@ from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailadmin.menu import MenuItem
|
||||
|
||||
from wagtail.wagtailimages import admin_urls, image_operations
|
||||
from wagtail.wagtailimages.rich_text import ImageEmbedHandler
|
||||
|
||||
|
||||
@hooks.register('register_admin_urls')
|
||||
@ -108,3 +109,8 @@ def register_image_operations():
|
||||
('width', image_operations.WidthHeightOperation),
|
||||
('height', image_operations.WidthHeightOperation),
|
||||
]
|
||||
|
||||
|
||||
@hooks.register('register_rich_text_embed_handler')
|
||||
def register_image_embed_handler():
|
||||
return ('image', ImageEmbedHandler)
|
||||
|
Loading…
Reference in New Issue
Block a user