mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-04-18 22:10:59 +00:00
merging master
This commit is contained in:
commit
05cbcd7546
28 changed files with 185 additions and 198 deletions
|
|
@ -24,6 +24,7 @@ Changelog
|
|||
* Fix: Page slugs are now validated on page edit
|
||||
* Fix: Filter objects are cached to avoid a database hit every time an {% image %} tag is compiled
|
||||
* Fix: Moving or changing a site root page no longer causes URLs for subpages to change to 'None'
|
||||
* Fix: Eliminated raw SQL queries from wagtailcore / wagtailadmin, to ensure cross-database compatibility
|
||||
|
||||
0.2 (11.03.2014)
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ Contributors
|
|||
* Miguel Vieira
|
||||
* Ben Emery
|
||||
* David Smith
|
||||
* Ben Margolis
|
||||
|
||||
Translators
|
||||
===========
|
||||
|
|
|
|||
1
tox.ini
1
tox.ini
|
|
@ -3,7 +3,6 @@ dj16=
|
|||
Django>=1.6,<1.7
|
||||
pyelasticsearch==0.6.1
|
||||
elasticutils==0.8.2
|
||||
unittest2
|
||||
|
||||
[tox]
|
||||
envlist =
|
||||
|
|
|
|||
|
|
@ -1,9 +1,20 @@
|
|||
from django.contrib.auth.models import User
|
||||
|
||||
# We need to make sure that we're using the same unittest library that Django uses internally
|
||||
# Otherwise, we get issues with the "SkipTest" and "ExpectedFailure" exceptions being recognised as errors
|
||||
try:
|
||||
# Firstly, try to import unittest from Django
|
||||
from django.utils import unittest
|
||||
except ImportError:
|
||||
# Django doesn't include unittest
|
||||
# We must be running on Django 1.7+ which doesn't support Python 2.6 so
|
||||
# the standard unittest library should be unittest2
|
||||
import unittest
|
||||
|
||||
|
||||
def login(client):
|
||||
# Create a user
|
||||
User.objects.create_superuser(username='test', email='test@email.com', password='password')
|
||||
|
||||
# Login
|
||||
client.login(username='test', password='password')
|
||||
client.login(username='test', password='password')
|
||||
|
|
|
|||
|
|
@ -1,3 +1,15 @@
|
|||
var halloPlugins = {
|
||||
'halloformat': {},
|
||||
'halloheadings': {formatBlocks: ["p", "h2", "h3", "h4", "h5"]},
|
||||
'hallolists': {},
|
||||
'hallohr': {},
|
||||
'halloreundo': {},
|
||||
'hallowagtaillink': {},
|
||||
};
|
||||
function registerHalloPlugin(name, opts) {
|
||||
halloPlugins[name] = (opts || {});
|
||||
}
|
||||
|
||||
function makeRichTextEditable(id) {
|
||||
var input = $('#' + id);
|
||||
var richText = $('<div class="richtext"></div>').html(input.val());
|
||||
|
|
@ -19,17 +31,7 @@ function makeRichTextEditable(id) {
|
|||
richText.hallo({
|
||||
toolbar: 'halloToolbarFixed',
|
||||
toolbarcssClass: 'testy',
|
||||
plugins: {
|
||||
'halloformat': {},
|
||||
'halloheadings': {formatBlocks: ["p", "h2", "h3", "h4", "h5"]},
|
||||
'hallolists': {},
|
||||
'hallohr': {},
|
||||
'halloreundo': {},
|
||||
'hallowagtailimage': {},
|
||||
'hallowagtailembeds': {},
|
||||
'hallowagtaillink': {},
|
||||
'hallowagtaildoclink': {}
|
||||
}
|
||||
plugins: halloPlugins
|
||||
}).bind('hallomodified', function(event, data) {
|
||||
input.val(data.content);
|
||||
if (!removeStylingPending) {
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ img{
|
|||
}
|
||||
|
||||
.nav-wrapper{
|
||||
@include box-shadow(inset -2px 0px 10px 0px rgba(0, 0, 0, 0.5));
|
||||
@include box-shadow(inset -5px 0px 5px -3px rgba(0, 0, 0, 0.3));
|
||||
position:relative;
|
||||
background: $color-grey-1;
|
||||
margin-left: -100%;
|
||||
|
|
@ -777,13 +777,8 @@ footer, .logo{
|
|||
.wrapper{
|
||||
max-width:$breakpoint-desktop-larger;
|
||||
}
|
||||
.nav-wrapper{
|
||||
@include box-shadow(inset -6px 0px 4px 0px rgba(0, 0, 0, 0.2));
|
||||
|
||||
.inner{
|
||||
background:$color-grey-1;
|
||||
@include box-shadow(inset -6px 0px 4px 0px rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
.nav-wrapper .inner{
|
||||
background:$color-grey-1;
|
||||
}
|
||||
|
||||
footer{
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ form{
|
|||
left: $desktop-nice-padding;
|
||||
margin-top: -1em;
|
||||
top: 50%;
|
||||
font-size:1.5em;
|
||||
}
|
||||
|
||||
.full{
|
||||
|
|
|
|||
|
|
@ -4,11 +4,6 @@
|
|||
CSS declarations to be included on the 'create page' and 'edit page' views
|
||||
{% endcomment %}
|
||||
|
||||
{% comment %}
|
||||
TODO: have a mechanism for sub-apps to specify their own declarations -
|
||||
ideally wagtailadmin shouldn't have to know anything at all about wagtailimages and friends
|
||||
{% endcomment %}
|
||||
|
||||
{% compress css %}
|
||||
<link rel="stylesheet" href="{{ STATIC_URL }}wagtailadmin/scss/layouts/page-editor.scss" type="text/x-scss" />
|
||||
<link rel="stylesheet" href="{{ STATIC_URL }}wagtailadmin/scss/panels/rich-text.scss" type="text/x-scss" />
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@
|
|||
Javascript declarations to be included on the 'create page' and 'edit page' views
|
||||
{% endcomment %}
|
||||
|
||||
<script>
|
||||
window.chooserUrls = {
|
||||
'pageChooser': '{% url "wagtailadmin_choose_page" %}'
|
||||
};
|
||||
</script>
|
||||
|
||||
{% compress js %}
|
||||
<script src="{{ STATIC_URL }}wagtailadmin/js/vendor/rangy-core.js"></script>
|
||||
|
|
@ -14,21 +19,9 @@
|
|||
<script src="{{ STATIC_URL }}wagtailadmin/js/hallo-plugins/hallo-wagtail-toolbar.js"></script>
|
||||
<script src="{{ STATIC_URL }}wagtailadmin/js/hallo-plugins/hallo-wagtaillink.js"></script>
|
||||
<script src="{{ STATIC_URL }}wagtailadmin/js/hallo-plugins/hallo-hr.js"></script>
|
||||
<script src="{{ STATIC_URL }}wagtailimages/js/hallo-plugins/hallo-wagtailimage.js"></script>
|
||||
<script src="{{ STATIC_URL }}wagtailembeds/js/hallo-plugins/hallo-wagtailembeds.js"></script>
|
||||
<script src="{{ STATIC_URL }}wagtaildocs/js/hallo-plugins/hallo-wagtaildoclink.js"></script>
|
||||
<script src="{{ STATIC_URL }}wagtailadmin/js/page-editor.js"></script>
|
||||
|
||||
<script src="{{ STATIC_URL }}wagtailadmin/js/page-chooser.js"></script>
|
||||
{% comment %}
|
||||
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' %}
|
||||
|
|
@ -41,19 +34,10 @@
|
|||
|
||||
{% comment %}
|
||||
Additional js from widgets media. Allows for custom widgets in admin panel.
|
||||
Can be used for TODO above (including image-choser.js at wagtailimages)
|
||||
{% endcomment %}
|
||||
{{ edit_handler.form.media.js }}
|
||||
|
||||
<script>
|
||||
window.chooserUrls = {
|
||||
'documentChooser': '{% url "wagtaildocs_chooser" %}',
|
||||
'imageChooser': '{% url "wagtailimages_chooser" %}',
|
||||
'embedsChooser': '{% url "wagtailembeds_chooser" %}',
|
||||
'pageChooser': '{% url "wagtailadmin_choose_page" %}',
|
||||
'snippetChooser': '{% url "wagtailsnippets_choose_generic" %}'
|
||||
};
|
||||
|
||||
{% get_date_format_override as format_override %}
|
||||
window.overrideDateInputFormat ='{{ format_override }}';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
{% extends "wagtailadmin/base.html" %}
|
||||
{% load i18n %}
|
||||
{% block titletag %}{% blocktrans with page_type=content_type.model_class.get_verbose_name %}Where do you want to create a {{ page_type }}{% endblocktrans %}{% endblock %}
|
||||
{% block content %}
|
||||
{% trans "Where do you want to create this" as where_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=where_str subtitle=content_type.model_class.get_verbose_name icon="doc-empty-inverse" %}
|
||||
|
||||
<ul>
|
||||
{% for page in parent_pages %}
|
||||
<li><a href="{% url 'wagtailadmin_pages_create' content_type.app_label content_type.model page.id %}">{{ page.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
{% extends "wagtailadmin/base.html" %}
|
||||
{% load i18n %}
|
||||
{% block titletag %}{% trans "Create a new page" %}{% endblock %}
|
||||
{% block bodyclass %}menu-explorer{% endblock %}
|
||||
{% block content %}
|
||||
{% trans "Create a new page" as create_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=create_str icon="doc-empty-inverse" %}
|
||||
|
||||
<div class="nice-padding">
|
||||
<p>{% trans "Your new page will be saved in the <em>top level</em> of your website. You can move it after saving." %}</p>
|
||||
|
||||
{% if all_page_types %}
|
||||
<ul class="listing">
|
||||
{% for content_type in all_page_types %}
|
||||
<li><a href="{% url 'wagtailadmin_pages_select_location' content_type.app_label content_type.model %}" class="icon icon-plus-inverse">{{ content_type.model_class.get_verbose_name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -6,10 +6,6 @@
|
|||
{{ menu_item.render_html }}
|
||||
{% endfor %}
|
||||
|
||||
{% comment %}
|
||||
{# TODO: make this work #}
|
||||
<li><a href="{% url 'wagtailadmin_pages_select_type' %}" class="icon teal icon-plus-inverse">{% trans 'New page' %}</a></li>
|
||||
{% endcomment %}
|
||||
<li class="footer">
|
||||
<div class="avatar icon icon-user"><a href="{% url 'wagtailadmin_account' %}" title="{% trans 'Account settings' %}">{% if request.user.email %}<img src="{% gravatar_url request.user.email %}" />{% endif %}</a></div>
|
||||
<a href="{% url 'wagtailadmin_logout' %}">{% trans "Log out" %}</a>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
from django.test import TestCase
|
||||
import unittest2 as unittest
|
||||
from wagtail.tests.models import SimplePage, EventPage
|
||||
from wagtail.tests.utils import login
|
||||
from wagtail.tests.utils import login, unittest
|
||||
from wagtail.wagtailcore.models import Page
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
|
|
@ -37,32 +36,6 @@ class TestPageExplorer(TestCase):
|
|||
self.assertTrue(response.context['pages'].filter(id=self.child_page.id).exists())
|
||||
|
||||
|
||||
class TestPageSelectTypeLocation(TestCase):
|
||||
def setUp(self):
|
||||
# Find root page
|
||||
self.root_page = Page.objects.get(id=2)
|
||||
|
||||
# Login
|
||||
login(self.client)
|
||||
|
||||
def test_select_type(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_select_type'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@unittest.expectedFailure # For some reason, this returns a 302...
|
||||
def test_select_location_testpage(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_select_location', args=('tests', 'eventpage')))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_select_location_nonexistanttype(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_select_location', args=('notanapp', 'notamodel')))
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_select_location_nonpagetype(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_select_location', args=('wagtailimages', 'image')))
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
|
||||
class TestPageCreation(TestCase):
|
||||
def setUp(self):
|
||||
# Find root page
|
||||
|
|
|
|||
|
|
@ -49,8 +49,6 @@ urlpatterns += [
|
|||
url(r'^pages/$', pages.index, name='wagtailadmin_explore_root'),
|
||||
url(r'^pages/(\d+)/$', pages.index, name='wagtailadmin_explore'),
|
||||
|
||||
url(r'^pages/new/$', pages.select_type, name='wagtailadmin_pages_select_type'),
|
||||
url(r'^pages/new/(\w+)/(\w+)/$', pages.select_location, name='wagtailadmin_pages_select_location'),
|
||||
url(r'^pages/new/(\w+)/(\w+)/(\d+)/$', pages.create, name='wagtailadmin_pages_create'),
|
||||
url(r'^pages/new/(\w+)/(\w+)/(\d+)/preview/$', pages.preview_on_create, name='wagtailadmin_pages_preview_on_create'),
|
||||
url(r'^pages/usage/(\w+)/(\w+)/$', pages.content_type_use, name='wagtailadmin_pages_type_use'),
|
||||
|
|
|
|||
|
|
@ -40,28 +40,6 @@ def index(request, parent_page_id=None):
|
|||
})
|
||||
|
||||
|
||||
@permission_required('wagtailadmin.access_admin')
|
||||
def select_type(request):
|
||||
# Get the list of page types that can be created within the pages that currently exist
|
||||
existing_page_types = ContentType.objects.raw("""
|
||||
SELECT DISTINCT content_type_id AS id FROM wagtailcore_page
|
||||
""")
|
||||
|
||||
all_page_types = sorted(get_page_types(), key=lambda pagetype: pagetype.name.lower())
|
||||
page_types = set()
|
||||
for content_type in existing_page_types:
|
||||
allowed_subpage_types = content_type.model_class().clean_subpage_types()
|
||||
for subpage_type in allowed_subpage_types:
|
||||
subpage_content_type = ContentType.objects.get_for_model(subpage_type)
|
||||
|
||||
page_types.add(subpage_content_type)
|
||||
|
||||
return render(request, 'wagtailadmin/pages/select_type.html', {
|
||||
'page_types': page_types,
|
||||
'all_page_types': all_page_types
|
||||
})
|
||||
|
||||
|
||||
@permission_required('wagtailadmin.access_admin')
|
||||
def add_subpage(request, parent_page_id):
|
||||
parent_page = get_object_or_404(Page, id=parent_page_id).specific
|
||||
|
|
@ -78,38 +56,6 @@ def add_subpage(request, parent_page_id):
|
|||
})
|
||||
|
||||
|
||||
@permission_required('wagtailadmin.access_admin')
|
||||
def select_location(request, content_type_app_name, content_type_model_name):
|
||||
try:
|
||||
content_type = ContentType.objects.get_by_natural_key(content_type_app_name, content_type_model_name)
|
||||
except ContentType.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
page_class = content_type.model_class()
|
||||
# page_class must be a Page type and not some other random model
|
||||
if not issubclass(page_class, Page):
|
||||
raise Http404
|
||||
|
||||
# find all the valid locations (parent pages) where a page of the chosen type can be added
|
||||
parent_pages = page_class.allowed_parent_pages()
|
||||
|
||||
if len(parent_pages) == 0:
|
||||
# user cannot create a page of this type anywhere - fail with an error
|
||||
messages.error(request, _("Sorry, you do not have access to create a page of type <em>'{0}'</em>.").format(content_type.name))
|
||||
return redirect('wagtailadmin_pages_select_type')
|
||||
elif len(parent_pages) == 1:
|
||||
# only one possible location - redirect them straight there
|
||||
messages.warning(request, _("Pages of this type can only be created as children of <em>'{0}'</em>. This new page will be saved there.").format(parent_pages[0].title))
|
||||
return redirect('wagtailadmin_pages_create', content_type_app_name, content_type_model_name, parent_pages[0].id)
|
||||
else:
|
||||
# prompt them to select a location
|
||||
return render(request, 'wagtailadmin/pages/select_location.html', {
|
||||
'content_type': content_type,
|
||||
'page_class': page_class,
|
||||
'parent_pages': parent_pages,
|
||||
})
|
||||
|
||||
|
||||
@permission_required('wagtailadmin.access_admin')
|
||||
def content_type_use(request, content_type_app_name, content_type_model_name):
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -638,17 +638,9 @@ def get_navigation_menu_items():
|
|||
# or are at the top-level (this rule required so that an empty site out-of-the-box has a working menu)
|
||||
navigable_content_type_ids = get_navigable_page_content_type_ids()
|
||||
if navigable_content_type_ids:
|
||||
pages = Page.objects.raw("""
|
||||
SELECT * FROM wagtailcore_page
|
||||
WHERE numchild > 0 OR content_type_id IN %s OR depth = 2
|
||||
ORDER BY path
|
||||
""", [tuple(navigable_content_type_ids)])
|
||||
pages = Page.objects.filter(Q(content_type__in=navigable_content_type_ids)|Q(depth=2)|Q(numchild__gt=0)).order_by('path')
|
||||
else:
|
||||
pages = Page.objects.raw("""
|
||||
SELECT * FROM wagtailcore_page
|
||||
WHERE numchild > 0 OR depth = 2
|
||||
ORDER BY path
|
||||
""")
|
||||
pages = Page.objects.filter(Q(depth=2)|Q(numchild__gt=0)).order_by('path')
|
||||
|
||||
# Turn this into a tree structure:
|
||||
# tree_node = (page, children)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
from django.conf import settings
|
||||
from django.conf.urls import include, url
|
||||
from django.core import urlresolvers
|
||||
from django.utils.html import format_html, format_html_join
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
|
|
@ -21,3 +23,23 @@ def construct_main_menu(request, menu_items):
|
|||
MenuItem(_('Documents'), urlresolvers.reverse('wagtaildocs_index'), classnames='icon icon-doc-full-inverse', order=400)
|
||||
)
|
||||
hooks.register('construct_main_menu', construct_main_menu)
|
||||
|
||||
|
||||
def editor_js():
|
||||
js_files = [
|
||||
'wagtaildocs/js/hallo-plugins/hallo-wagtaildoclink.js',
|
||||
'wagtaildocs/js/document-chooser.js',
|
||||
]
|
||||
js_includes = format_html_join('\n', '<script src="{0}{1}"></script>',
|
||||
((settings.STATIC_URL, filename) for filename in js_files)
|
||||
)
|
||||
return js_includes + format_html(
|
||||
"""
|
||||
<script>
|
||||
window.chooserUrls.documentChooser = '{0}';
|
||||
registerHalloPlugin('hallowagtaildoclink');
|
||||
</script>
|
||||
""",
|
||||
urlresolvers.reverse('wagtaildocs_chooser')
|
||||
)
|
||||
hooks.register('insert_editor_js', editor_js)
|
||||
|
|
|
|||
|
|
@ -152,6 +152,17 @@ def get_embed(url, max_width=None, finder=None):
|
|||
finder = get_default_finder()
|
||||
embed_dict = finder(url, max_width)
|
||||
|
||||
# Make sure width and height are valid integers before inserting into database
|
||||
try:
|
||||
embed_dict['width'] = int(embed_dict['width'])
|
||||
except (TypeError, ValueError):
|
||||
embed_dict['width'] = None
|
||||
|
||||
try:
|
||||
embed_dict['height'] = int(embed_dict['height'])
|
||||
except (TypeError, ValueError):
|
||||
embed_dict['height'] = None
|
||||
|
||||
# Create database record
|
||||
embed, created = Embed.objects.get_or_create(
|
||||
url=url,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,20 @@ class TestEmbeds(TestCase):
|
|||
def setUp(self):
|
||||
self.hit_count = 0
|
||||
|
||||
def dummy_finder(self, url, max_width=None):
|
||||
# Up hit count
|
||||
self.hit_count += 1
|
||||
|
||||
# Return a pretend record
|
||||
return {
|
||||
'title': "Test: " + url,
|
||||
'type': 'video',
|
||||
'thumbnail_url': '',
|
||||
'width': max_width if max_width else 640,
|
||||
'height': 480,
|
||||
'html': "<p>Blah blah blah</p>",
|
||||
}
|
||||
|
||||
def test_get_embed(self):
|
||||
embed = get_embed('www.test.com/1234', max_width=400, finder=self.dummy_finder)
|
||||
|
||||
|
|
@ -31,20 +45,23 @@ class TestEmbeds(TestCase):
|
|||
embed = get_embed('www.test.com/4321', finder=self.dummy_finder)
|
||||
self.assertEqual(self.hit_count, 3)
|
||||
|
||||
def dummy_finder(self, url, max_width=None):
|
||||
# Up hit count
|
||||
self.hit_count += 1
|
||||
|
||||
# Return a pretend record
|
||||
def dummy_finder_invalid_width(self, url, max_width=None):
|
||||
# Return a record with an invalid width
|
||||
return {
|
||||
'title': "Test: " + url,
|
||||
'type': 'video',
|
||||
'thumbnail_url': '',
|
||||
'width': max_width if max_width else 640,
|
||||
'width': '100%',
|
||||
'height': 480,
|
||||
'html': "<p>Blah blah blah</p>",
|
||||
}
|
||||
|
||||
def test_invalid_width(self):
|
||||
embed = get_embed('www.test.com/1234', max_width=400, finder=self.dummy_finder_invalid_width)
|
||||
|
||||
# Width must be set to None
|
||||
self.assertEqual(embed.width, None)
|
||||
|
||||
|
||||
class TestChooser(TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
from django.conf import settings
|
||||
from django.conf.urls import include, url
|
||||
from django.core import urlresolvers
|
||||
from django.utils.html import format_html
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
from wagtail.wagtailembeds import urls
|
||||
|
|
@ -9,3 +12,18 @@ def register_admin_urls():
|
|||
url(r'^embeds/', include(urls)),
|
||||
]
|
||||
hooks.register('register_admin_urls', register_admin_urls)
|
||||
|
||||
|
||||
def editor_js():
|
||||
return format_html("""
|
||||
<script src="{0}{1}"></script>
|
||||
<script>
|
||||
window.chooserUrls.embedsChooser = '{2}';
|
||||
registerHalloPlugin('hallowagtailembeds');
|
||||
</script>
|
||||
""",
|
||||
settings.STATIC_URL,
|
||||
'wagtailembeds/js/hallo-plugins/hallo-wagtailembeds.js',
|
||||
urlresolvers.reverse('wagtailembeds_chooser')
|
||||
)
|
||||
hooks.register('insert_editor_js', editor_js)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import os.path
|
|||
from taggit.managers import TaggableManager
|
||||
|
||||
from django.core.files import File
|
||||
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, ValidationError
|
||||
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
||||
from django.db import models
|
||||
from django.db.models.signals import pre_delete
|
||||
from django.dispatch.dispatcher import receiver
|
||||
|
|
@ -17,6 +17,8 @@ from unidecode import unidecode
|
|||
|
||||
from wagtail.wagtailadmin.taggable import TagSearchable
|
||||
from wagtail.wagtailimages.backends import get_image_backend
|
||||
from .utils import validate_image_format
|
||||
|
||||
|
||||
class AbstractImage(models.Model, TagSearchable):
|
||||
title = models.CharField(max_length=255, verbose_name=_('Title') )
|
||||
|
|
@ -34,12 +36,7 @@ class AbstractImage(models.Model, TagSearchable):
|
|||
filename = prefix[:-1] + dot + extension
|
||||
return os.path.join(folder_name, filename)
|
||||
|
||||
def file_extension_validator(ffile):
|
||||
extension = ffile.name.split(".")[-1].lower()
|
||||
if extension not in ["gif", "jpg", "jpeg", "png"]:
|
||||
raise ValidationError(_("Not a valid image format. Please use a gif, jpeg or png file instead."))
|
||||
|
||||
file = models.ImageField(verbose_name=_('File'), upload_to=get_upload_to, width_field='width', height_field='height', validators=[file_extension_validator])
|
||||
file = models.ImageField(verbose_name=_('File'), upload_to=get_upload_to, width_field='width', height_field='height', validators=[validate_image_format])
|
||||
width = models.IntegerField(editable=False)
|
||||
height = models.IntegerField(editable=False)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@ from django.contrib.auth.models import User, Group, Permission
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
|
||||
import unittest2 as unittest
|
||||
|
||||
from wagtail.tests.utils import login
|
||||
from wagtail.tests.utils import login, unittest
|
||||
from wagtail.wagtailimages.models import get_image_model
|
||||
from wagtail.wagtailimages.templatetags import image_tags
|
||||
|
||||
|
|
|
|||
28
wagtail/wagtailimages/utils.py
Normal file
28
wagtail/wagtailimages/utils.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import os
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
def validate_image_format(f):
|
||||
# Check file extension
|
||||
extension = os.path.splitext(f.name)[1].lower()[1:]
|
||||
|
||||
if extension == 'jpg':
|
||||
extension = 'jpeg'
|
||||
|
||||
if extension not in ['gif', 'jpeg', 'png']:
|
||||
raise ValidationError(_("Not a valid image. Please use a gif, jpeg or png file with the correct file extension."))
|
||||
|
||||
if not f.closed:
|
||||
# Open image file
|
||||
file_position = f.tell()
|
||||
f.seek(0)
|
||||
image = Image.open(f)
|
||||
f.seek(file_position)
|
||||
|
||||
# Check that the internal format matches the extension
|
||||
if image.format.upper() != extension.upper():
|
||||
raise ValidationError(_("Not a valid %s image. Please use a gif, jpeg or png file with the correct file extension.") % (extension.upper()))
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
from django.conf import settings
|
||||
from django.conf.urls import include, url
|
||||
from django.core import urlresolvers
|
||||
from django.utils.html import format_html, format_html_join
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
|
|
@ -21,3 +23,23 @@ def construct_main_menu(request, menu_items):
|
|||
MenuItem(_('Images'), urlresolvers.reverse('wagtailimages_index'), classnames='icon icon-image', order=300)
|
||||
)
|
||||
hooks.register('construct_main_menu', construct_main_menu)
|
||||
|
||||
|
||||
def editor_js():
|
||||
js_files = [
|
||||
'wagtailimages/js/hallo-plugins/hallo-wagtailimage.js',
|
||||
'wagtailimages/js/image-chooser.js',
|
||||
]
|
||||
js_includes = format_html_join('\n', '<script src="{0}{1}"></script>',
|
||||
((settings.STATIC_URL, filename) for filename in js_files)
|
||||
)
|
||||
return js_includes + format_html(
|
||||
"""
|
||||
<script>
|
||||
window.chooserUrls.imageChooser = '{0}';
|
||||
registerHalloPlugin('hallowagtailimage');
|
||||
</script>
|
||||
""",
|
||||
urlresolvers.reverse('wagtailimages_chooser')
|
||||
)
|
||||
hooks.register('insert_editor_js', editor_js)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from django.test import TestCase
|
|||
from django.test.utils import override_settings
|
||||
from django.conf import settings
|
||||
from django.core import management
|
||||
import unittest2 as unittest
|
||||
from wagtail.tests.utils import unittest
|
||||
from wagtail.wagtailsearch import models, get_search_backend
|
||||
from wagtail.wagtailsearch.backends.db import DBSearch
|
||||
from wagtail.wagtailsearch.backends import InvalidSearchBackendError
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
from django.test import TestCase
|
||||
from django.core import management
|
||||
from wagtail.wagtailsearch import models
|
||||
from wagtail.tests.utils import login
|
||||
from wagtail.tests.utils import login, unittest
|
||||
from StringIO import StringIO
|
||||
import unittest2 as unittest
|
||||
|
||||
|
||||
class TestHitCounter(TestCase):
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ when you run "manage.py test".
|
|||
Replace this with more appropriate tests for your application.
|
||||
"""
|
||||
|
||||
import unittest2 as unittest
|
||||
from wagtail.tests.utils import unittest
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
from django.conf import settings
|
||||
from django.conf.urls import include, url
|
||||
from django.core import urlresolvers
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from wagtail.wagtailadmin import hooks
|
||||
|
|
@ -22,3 +24,15 @@ def construct_main_menu(request, menu_items):
|
|||
MenuItem(_('Snippets'), urlresolvers.reverse('wagtailsnippets_index'), classnames='icon icon-snippet', order=500)
|
||||
)
|
||||
hooks.register('construct_main_menu', construct_main_menu)
|
||||
|
||||
|
||||
def editor_js():
|
||||
return format_html("""
|
||||
<script src="{0}{1}"></script>
|
||||
<script>window.chooserUrls.snippetChooser = '{2}';</script>
|
||||
""",
|
||||
settings.STATIC_URL,
|
||||
'wagtailsnippets/js/snippet-chooser.js',
|
||||
urlresolvers.reverse('wagtailsnippets_choose_generic')
|
||||
)
|
||||
hooks.register('insert_editor_js', editor_js)
|
||||
|
|
|
|||
Loading…
Reference in a new issue