mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-04-19 22:41:00 +00:00
Merge pull request #182 from gasman/feature/editor_css_hook
Add hook for inserting site-specific CSS/JS into the editor interface
This commit is contained in:
commit
b994fcdf3b
26 changed files with 121 additions and 92 deletions
|
|
@ -85,6 +85,7 @@ if not settings.configured:
|
|||
PASSWORD_HASHERS=(
|
||||
'django.contrib.auth.hashers.MD5PasswordHasher', # don't use the intentionally slow default password hasher
|
||||
),
|
||||
COMPRESS_ENABLED=False, # disable compression so that we can run tests on the content of the compress tag
|
||||
WAGTAILSEARCH_BACKENDS=WAGTAILSEARCH_BACKENDS,
|
||||
WAGTAIL_SITE_NAME='Test Site'
|
||||
)
|
||||
|
|
|
|||
10
wagtail/tests/wagtail_hooks.py
Normal file
10
wagtail/tests/wagtail_hooks.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
from wagtail.wagtailadmin import hooks
|
||||
|
||||
def editor_css():
|
||||
return """<link rel="stylesheet" href="/path/to/my/custom.css">"""
|
||||
hooks.register('insert_editor_css', editor_css)
|
||||
|
||||
|
||||
def editor_js():
|
||||
return """<script src="/path/to/my/custom.js"></script>"""
|
||||
hooks.register('insert_editor_js', editor_js)
|
||||
|
|
@ -79,8 +79,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* === CSS BELOW THIS POINT IS CUSTOM TO RCA === */
|
||||
/* TODO: find extensible way for developers to style rich text to suit their implementation, without making changes to anything within wagtailadmin */
|
||||
/* Set some reasonable default heading styles. These can be overridden in site-specific custom CSS
|
||||
to make them better reflect their appearance on the front-end (however, it's arguably better for editors
|
||||
NOT to be thinking about a specific visual appearance when they choose heading levels...) */
|
||||
|
||||
h1,h2,h3,h4,h5,h6{
|
||||
font-family:inherit;
|
||||
|
|
@ -90,9 +91,7 @@
|
|||
h2 {
|
||||
font-size: 2em;
|
||||
line-height: 1.2em;
|
||||
padding-top:0.5em;
|
||||
border-top:1px solid #CCC;
|
||||
clear:both
|
||||
clear:both;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.7em;
|
||||
|
|
@ -111,19 +110,20 @@
|
|||
hr {
|
||||
border-bottom: 1px solid #ccc;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
/*
|
||||
These styles correspond to the image formats defined in wagtailimages/formats.py,
|
||||
so that images displayed in the rich text field receive more or less the same
|
||||
styling that they would receive on the site front-end.
|
||||
TODO: when we implement a mechanism to configure the image format list on a
|
||||
per-installation / per-site basis, we'll need a way to insert the corresponding
|
||||
CSS here.
|
||||
|
||||
Wagtail installations that define their own image formats (in a myapp.image_formats module)
|
||||
should ideally use the insert_editor_css hook to pass in their own custom CSS to have those
|
||||
images render within the rich text area in the same styles that would appear on the front-end.
|
||||
*/
|
||||
|
||||
.bodytext-image {
|
||||
.richtext-image {
|
||||
margin-top: 3px; /* close as possible to match line-height space above p */
|
||||
img {
|
||||
width:100%;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "wagtailadmin/admin_base.html" %}
|
||||
{% load wagtailadmin_nav %}
|
||||
{% load wagtailadmin_tags %}
|
||||
{% load i18n %}
|
||||
{% block furniture %}
|
||||
<div class="nav-wrapper">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% load compress %}
|
||||
{% load compress wagtailadmin_tags %}
|
||||
|
||||
{% comment %}
|
||||
CSS declarations to be included on the 'create page' and 'edit page' views
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
{# we'll want tag-it included, for the benefit of any modals that use it, like images. #}
|
||||
{# TODO: a method of injecting these sorts of things on demand when the modal is spawned #}
|
||||
<link rel="stylesheet" href="{{ STATIC_URL }}wagtailadmin/scss/vendor/jquery.tagit.css">
|
||||
|
||||
{% hook_output 'insert_editor_css' %}
|
||||
{% endcompress %}
|
||||
|
||||
{{ edit_handler.form.media.css }}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
{% load compress %}
|
||||
{% load localize %}
|
||||
{% load wagtailadmin_tags compress localize %}
|
||||
|
||||
{% comment %}
|
||||
Javascript declarations to be included on the 'create page' and 'edit page' views
|
||||
|
|
@ -22,15 +21,17 @@
|
|||
|
||||
<script src="{{ STATIC_URL }}wagtailadmin/js/page-chooser.js"></script>
|
||||
{% comment %}
|
||||
TODO: have a mechanism to specify image-chooser.js (and hallo-wagtailimage.js)
|
||||
within the wagtailimages app -
|
||||
ideally wagtailadmin shouldn't have to know anything at all about wagtailimages
|
||||
TODO: use the insert_editor_js hook to inject things like image-chooser.js and hallo-wagtailimage.js
|
||||
from their respective apps such as wagtailimages -
|
||||
ideally wagtailadmin shouldn't have to know anything at all about wagtailimages.
|
||||
TODO: a method of injecting these sorts of things on demand when the modal is spawned.
|
||||
{% endcomment %}
|
||||
<script src="{{ STATIC_URL }}wagtailimages/js/image-chooser.js"></script>
|
||||
<script src="{{ STATIC_URL }}wagtaildocs/js/document-chooser.js"></script>
|
||||
<script src="{{ STATIC_URL }}wagtailsnippets/js/snippet-chooser.js"></script>
|
||||
<script src="{{ STATIC_URL }}admin/js/urlify.js"></script>
|
||||
|
||||
{% hook_output 'insert_editor_js' %}
|
||||
{% endcompress %}
|
||||
|
||||
{% comment %}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "wagtailadmin/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load meta_description %}
|
||||
{% load wagtailadmin_tags %}
|
||||
|
||||
{% block bodyclass %}menu-explorer{% endblock %}
|
||||
{% block titletag %}{% blocktrans with title=parent_page.title %}Create a page in {{ title }}{% endblocktrans %}{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "wagtailadmin/base.html" %}
|
||||
{% load page_permissions %}
|
||||
{% load wagtailadmin_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block titletag %}{% blocktrans with page_type=content_type.model_class.get_verbose_name %}New {{ page_type }}{% endblocktrans %}{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "wagtailadmin/base.html" %}
|
||||
{% load page_permissions %}
|
||||
{% load wagtailadmin_tags %}
|
||||
{% load gravatar %}
|
||||
{% load i18n %}
|
||||
{% block titletag %}{% blocktrans with title=page.title %}Editing {{ title }}{% endblocktrans %}{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "wagtailadmin/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load page_permissions %}
|
||||
{% load wagtailadmin_tags %}
|
||||
{% block titletag %}{% blocktrans with title=parent_page.title %}Exploring {{ title }}{% endblocktrans %}{% endblock %}
|
||||
{% block bodyclass %}menu-explorer page-explorer {% if ordering == 'ord' %}reordering{% endif %}{% endblock %}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{% load i18n %}
|
||||
{% load page_permissions %}
|
||||
{% load wagtailadmin_tags %}
|
||||
<table class="listing{% if full_width %} full-width{% endif %}{% if moving or choosing %} chooser{% endif %}">
|
||||
{% if orderable %}
|
||||
<col width="50px" />
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% load wagtailadmin_nav %}
|
||||
{% load wagtailadmin_tags %}
|
||||
|
||||
{% for page, children in nodes %}
|
||||
<li {% if children %}class="has-children"{% endif %}>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% load fieldtype %}
|
||||
{% load wagtailadmin_tags %}
|
||||
<li class="{{ field.css_classes }} {{ field|fieldtype }} {% if field.errors %}error{% endif %}">
|
||||
<div class="field">
|
||||
{% if field|fieldtype != "boolean_field" %}{{ field.label_tag }}{% endif %}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% load gravatar wagtailadmin_nav %}
|
||||
{% load gravatar wagtailadmin_tags %}
|
||||
{% load i18n %}
|
||||
<nav class="nav-main">
|
||||
<ul>
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter("ellipsistrim")
|
||||
def ellipsistrim(value, max_length):
|
||||
if len(value) > max_length:
|
||||
truncd_val = value[:max_length]
|
||||
if not len(value) == max_length+1 and value[max_length+1] != " ":
|
||||
truncd_val = truncd_val[:truncd_val.rfind(" ")]
|
||||
return truncd_val + "..."
|
||||
return value
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
from django import template
|
||||
|
||||
from wagtail.wagtailcore.util import camelcase_to_underscore
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
def fieldtype(bound_field):
|
||||
try:
|
||||
return camelcase_to_underscore(bound_field.field.__class__.__name__)
|
||||
except AttributeError:
|
||||
return ""
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
def meta_description(model):
|
||||
try:
|
||||
return model.model_class()._meta.description
|
||||
except:
|
||||
return ""
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
from django import template
|
||||
|
||||
from wagtail.wagtailcore.models import UserPagePermissionsProxy
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.assignment_tag(takes_context=True)
|
||||
def page_permissions(context, page):
|
||||
"""
|
||||
Usage: {% page_permissions page as page_perms %}
|
||||
Sets the variable 'page_perms' to a PagePermissionTester object that can be queried to find out
|
||||
what actions the current logged-in user can perform on the given page.
|
||||
"""
|
||||
# Create a UserPagePermissionsProxy object to represent the user's global permissions, and
|
||||
# cache it in the context for the duration of the page request, if one does not exist already
|
||||
if 'user_page_permissions' not in context:
|
||||
context['user_page_permissions'] = UserPagePermissionsProxy(context['request'].user)
|
||||
|
||||
# Now retrieve a PagePermissionTester from it, specific to the given page
|
||||
return context['user_page_permissions'].for_page(page)
|
||||
|
|
@ -5,7 +5,8 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from wagtail.wagtailadmin import hooks
|
||||
from wagtail.wagtailadmin.menu import MenuItem
|
||||
|
||||
from wagtail.wagtailcore.models import get_navigation_menu_items
|
||||
from wagtail.wagtailcore.models import get_navigation_menu_items, UserPagePermissionsProxy
|
||||
from wagtail.wagtailcore.util import camelcase_to_underscore
|
||||
|
||||
from wagtail.wagtailsnippets.permissions import user_can_edit_snippets # TODO: reorganise into pluggable architecture so that wagtailsnippets registers its own menu item
|
||||
|
||||
|
|
@ -73,3 +74,57 @@ def main_nav(context):
|
|||
'menu_items': sorted(menu_items, key=lambda i: i.order),
|
||||
'request': request,
|
||||
}
|
||||
|
||||
|
||||
@register.filter("ellipsistrim")
|
||||
def ellipsistrim(value, max_length):
|
||||
if len(value) > max_length:
|
||||
truncd_val = value[:max_length]
|
||||
if not len(value) == max_length+1 and value[max_length+1] != " ":
|
||||
truncd_val = truncd_val[:truncd_val.rfind(" ")]
|
||||
return truncd_val + "..."
|
||||
return value
|
||||
|
||||
|
||||
@register.filter
|
||||
def fieldtype(bound_field):
|
||||
try:
|
||||
return camelcase_to_underscore(bound_field.field.__class__.__name__)
|
||||
except AttributeError:
|
||||
return ""
|
||||
|
||||
|
||||
@register.filter
|
||||
def meta_description(model):
|
||||
try:
|
||||
return model.model_class()._meta.description
|
||||
except:
|
||||
return ""
|
||||
|
||||
|
||||
@register.assignment_tag(takes_context=True)
|
||||
def page_permissions(context, page):
|
||||
"""
|
||||
Usage: {% page_permissions page as page_perms %}
|
||||
Sets the variable 'page_perms' to a PagePermissionTester object that can be queried to find out
|
||||
what actions the current logged-in user can perform on the given page.
|
||||
"""
|
||||
# Create a UserPagePermissionsProxy object to represent the user's global permissions, and
|
||||
# cache it in the context for the duration of the page request, if one does not exist already
|
||||
if 'user_page_permissions' not in context:
|
||||
context['user_page_permissions'] = UserPagePermissionsProxy(context['request'].user)
|
||||
|
||||
# Now retrieve a PagePermissionTester from it, specific to the given page
|
||||
return context['user_page_permissions'].for_page(page)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def hook_output(hook_name):
|
||||
"""
|
||||
Example: {% hook_output 'insert_editor_css' %}
|
||||
Whenever we have a hook whose functions take no parameters and return a string, this tag can be used
|
||||
to output the concatenation of all of those return values onto the page.
|
||||
Note that the output is not escaped - it is the hook function's responsibility to escape unsafe content.
|
||||
"""
|
||||
snippets = [fn() for fn in hooks.get_hooks(hook_name)]
|
||||
return u''.join(snippets)
|
||||
|
|
@ -308,3 +308,21 @@ class TestPageMove(TestCase):
|
|||
def test_page_set_page_position(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_set_page_position', args=(self.test_page.id, )))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
class TestEditorHooks(TestCase):
|
||||
def setUp(self):
|
||||
self.homepage = Page.objects.get(id=2)
|
||||
login(self.client)
|
||||
|
||||
def test_editor_css_and_js_hooks_on_add(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.homepage.id)))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, '<link rel="stylesheet" href="/path/to/my/custom.css">')
|
||||
self.assertContains(response, '<script src="/path/to/my/custom.js"></script>')
|
||||
|
||||
def test_editor_css_and_js_hooks_on_edit(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_edit', args=(self.homepage.id, )))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, '<link rel="stylesheet" href="/path/to/my/custom.css">')
|
||||
self.assertContains(response, '<script src="/path/to/my/custom.js"></script>')
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% load image_tags ellipsistrim%}
|
||||
{% load image_tags %}
|
||||
{% load i18n %}
|
||||
{% trans "Insert embed" as ins_emb_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=ins_emb_str merged=1 %}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,6 @@ def search_for_image_formats():
|
|||
|
||||
|
||||
# Define default image formats
|
||||
register_image_format(Format('fullwidth', 'Full width', 'full-width', 'width-800'))
|
||||
register_image_format(Format('left', 'Left-aligned', 'left', 'width-500'))
|
||||
register_image_format(Format('right', 'Right-aligned', 'right', 'width-500'))
|
||||
register_image_format(Format('fullwidth', 'Full width', 'richtext-image full-width', 'width-800'))
|
||||
register_image_format(Format('left', 'Left-aligned', 'richtext-image left', 'width-500'))
|
||||
register_image_format(Format('right', 'Right-aligned', 'richtext-image right', 'width-500'))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% load image_tags ellipsistrim%}
|
||||
{% load image_tags %}
|
||||
{% load i18n %}
|
||||
{% trans "Choose an image" as choose_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=choose_str merged=1 tabbed=1 icon="image" %}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% load image_tags ellipsistrim %}
|
||||
{% load image_tags wagtailadmin_tags %}
|
||||
{% load i18n %}
|
||||
{% if images %}
|
||||
{% if is_searching %}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "wagtailadmin/base.html" %}
|
||||
{% load image_tags ellipsistrim %}
|
||||
{% load image_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block titletag %}{% trans "Images" %}{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% load image_tags ellipsistrim %}
|
||||
{% load image_tags wagtailadmin_tags %}
|
||||
{% load i18n %}
|
||||
{% if images %}
|
||||
{% if is_searching %}
|
||||
|
|
|
|||
Loading…
Reference in a new issue