diff --git a/.travis.yml b/.travis.yml
index 3e0a4bb98..8764f2859 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,7 +12,7 @@ services:
# Package installation
install:
- python setup.py install
- - pip install psycopg2 pyelasticsearch elasticutils==0.8.2 wand embedly
+ - pip install psycopg2 elasticsearch wand embedly
- pip install coveralls
# Pre-test configuration
before_script:
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 19eec21e7..ca58949b4 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -3,6 +3,7 @@ Changelog
0.4 (xx.xx.20xx)
~~~~~~~~~~~~~~~~
+ * ElasticUtils/pyelasticsearch swapped for elasticsearch-py
* Added 'original' as a resizing rule supported by the 'image' tag
* Hallo.js updated to version 1.0.4
* Snippets are now ordered alphabetically
@@ -14,6 +15,7 @@ Changelog
* Aesthetic improvements to preview experience
* 'image' tag now accepts extra keyword arguments to be output as attributes on the img tag
* Added an 'attrs' property to image rendition objects to output src, width, height and alt attributes all in one go
+ * Added 'construct_whitelister_element_rules' hook for customising the HTML whitelist used when saving rich text fields
* Fix: Animated GIFs are now coalesced before resizing
* Fix: Wand backend clones images before modifying them
* Fix: Admin breadcrumb now positioned correctly on mobile
diff --git a/docs/building_your_site/frontenddevelopers.rst b/docs/building_your_site/frontenddevelopers.rst
index a8cf6a25e..8d0c9a3bb 100644
--- a/docs/building_your_site/frontenddevelopers.rst
+++ b/docs/building_your_site/frontenddevelopers.rst
@@ -186,23 +186,42 @@ The available resizing methods are:
More control over the ``img`` tag
---------------------------------
-In some cases greater control over the ``img`` tag is required, for example to add a custom ``class``. Rather than generating the ``img`` element for you, Wagtail can assign the relevant data to another object using Django's ``as`` syntax:
+Wagtail provides two shorcuts to give greater control over the ``img`` element:
+
+.. versionadded:: 0.4
+**Adding attributes to the {% image %} tag**
+
+Extra attributes can be specified with the syntax ``attribute="value"``:
+
+.. code-block:: django
+
+ {% image self.photo width-400 class="foo" id="bar" %}
+
+No validation is performed on attributes add in this way by the developer. It's possible to add `src`, `width`, `height` and `alt` of your own that might conflict with those generated by the tag itself.
+
+
+**Generating the image "as"**
+
+Wagtail can assign the image data to another object using Django's ``as`` syntax:
.. code-block:: django
- {% load image %}
- ...
{% image self.photo width-400 as tmp_photo %}
+.. versionadded:: 0.4
+The ``attrs`` shortcut
+-----------------------
+
You can also use the ``attrs`` property as a shorthand to output the ``src``, ``width``, ``height`` and ``alt`` attributes in one go:
.. code-block:: django
+
.. _rich-text-filter:
Rich text (filter)
diff --git a/docs/editing_api.rst b/docs/editing_api.rst
index 88fc9458f..9f7602b11 100644
--- a/docs/editing_api.rst
+++ b/docs/editing_api.rst
@@ -546,6 +546,28 @@ Where ``'hook'`` is one of the following hook strings and ``function`` is a func
+ 'demo/css/vendor/font-awesome/css/font-awesome.min.css">')
hooks.register('insert_editor_css', editor_css)
+.. _construct_whitelister_element_rules:
+
+``construct_whitelister_element_rules``
+ .. versionadded:: 0.4
+ Customise the rules that define which HTML elements are allowed in rich text areas. By default only a limited set of HTML elements and attributes are whitelisted - all others are stripped out. The callables passed into this hook must return a dict, which maps element names to handler functions that will perform some kind of manipulation of the element. These handler functions receive the element as a `BeautifulSoup
`` element to the whitelist, and allow the ``target`` attribute on ```` elements: + + .. code-block:: python + + from wagtail.wagtailadmin import hooks + from wagtail.wagtailcore.whitelist import attribute_rule, check_url, allow_without_attributes + + def whitelister_element_rules(): + return { + 'blockquote': allow_without_attributes, + 'a': attribute_rule({'href': check_url, 'target': True}), + } + hooks.register('construct_whitelister_element_rules', whitelister_element_rules) + Image Formats in the Rich Text Editor ------------------------------------- diff --git a/docs/wagtail_search.rst b/docs/wagtail_search.rst index 3d8ea26b2..1fa2c6525 100644 --- a/docs/wagtail_search.rst +++ b/docs/wagtail_search.rst @@ -220,17 +220,14 @@ The default DB search backend uses Django's ``__icontains`` filter. Elasticsearch Backend ````````````````````` -Prerequisites are the Elasticsearch service itself and, via pip, the `elasticutils`_ and `pyelasticsearch`_ packages: +Prerequisites are the Elasticsearch service itself and, via pip, the `elasticsearch-py`_ package: .. code-block:: guess - pip install elasticutils==0.8.2 pyelasticsearch + pip install elasticsearch .. note:: - ElasticUtils 0.9+ is not supported. - -.. note:: - The dependency on elasticutils and pyelasticsearch is scheduled to be replaced by a dependency on `elasticsearch-py`_. + If you are using Elasticsearch < 1.0, install elasticsearch-py version 0.4.5: ```pip install elasticsearch==0.4.5``` The backend is configured in settings: @@ -246,7 +243,7 @@ The backend is configured in settings: } } -Other than ``BACKEND`` the keys are optional and default to the values shown. ``FORCE_NEW`` is used by elasticutils. In addition, any other keys are passed directly to the Elasticsearch constructor as case-sensitive keyword arguments (e.g. ``'max_retries': 1``). +Other than ``BACKEND`` the keys are optional and default to the values shown. ``FORCE_NEW`` is used by elasticsearch-py. In addition, any other keys are passed directly to the Elasticsearch constructor as case-sensitive keyword arguments (e.g. ``'max_retries': 1``). If you prefer not to run an Elasticsearch server in development or production, there are many hosted services available, including `Searchly`_, who offer a free account suitable for testing and development. To use Searchly: @@ -256,8 +253,6 @@ If you prefer not to run an Elasticsearch server in development or production, t - Configure ``URLS`` and ``INDEX`` in the Elasticsearch entry in ``WAGTAILSEARCH_BACKENDS`` - Run ``./manage.py update_index`` -.. _elasticutils: http://elasticutils.readthedocs.org -.. _pyelasticsearch: http://pyelasticsearch.readthedocs.org .. _elasticsearch-py: http://elasticsearch-py.readthedocs.org .. _Searchly: http://www.searchly.com/ .. _dashboard.searchly.com/users/sign\_up: https://dashboard.searchly.com/users/sign_up diff --git a/runtests.py b/runtests.py index 96653b40d..efa66910f 100755 --- a/runtests.py +++ b/runtests.py @@ -13,7 +13,7 @@ MEDIA_ROOT = os.path.join(WAGTAIL_ROOT, 'test-media') if not settings.configured: try: - import elasticutils + import elasticsearch has_elasticsearch = True except ImportError: has_elasticsearch = False diff --git a/wagtail/tests/models.py b/wagtail/tests/models.py index f798129dc..ca6d411da 100644 --- a/wagtail/tests/models.py +++ b/wagtail/tests/models.py @@ -303,6 +303,9 @@ class StandardChild(Page): pass class BusinessIndex(Page): + subpage_types = ['tests.BusinessChild', 'tests.BusinessSubIndex'] + +class BusinessSubIndex(Page): subpage_types = ['tests.BusinessChild'] class BusinessChild(Page): diff --git a/wagtail/tests/wagtail_hooks.py b/wagtail/tests/wagtail_hooks.py index 91c76c9f4..5dccca666 100644 --- a/wagtail/tests/wagtail_hooks.py +++ b/wagtail/tests/wagtail_hooks.py @@ -1,4 +1,5 @@ from wagtail.wagtailadmin import hooks +from wagtail.wagtailcore.whitelist import attribute_rule, check_url, allow_without_attributes def editor_css(): return """""" @@ -8,3 +9,11 @@ hooks.register('insert_editor_css', editor_css) def editor_js(): return """""" hooks.register('insert_editor_js', editor_js) + + +def whitelister_element_rules(): + return { + 'blockquote': allow_without_attributes, + 'a': attribute_rule({'href': check_url, 'target': True}), + } +hooks.register('construct_whitelister_element_rules', whitelister_element_rules) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js index eacb8f86d..03adb7aca 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js +++ b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js @@ -329,9 +329,9 @@ $(function() { }); /* Set up behaviour of preview button */ - $('.action-preview').click(function(e) { + $('.action-preview').click(function(e) { e.preventDefault(); - + var previewWindow = window.open($(this).data('placeholder'), $(this).data('windowname')); $.ajax({ @@ -340,18 +340,9 @@ $(function() { data: $('#page-edit-form').serialize(), success: function(data, textStatus, request) { if (request.getResponseHeader('X-Wagtail-Preview') == 'ok') { - var pdoc = previewWindow.document; - var frame = pdoc.getElementById('preview-frame'); - - frame = frame.contentWindow || frame.contentDocument.document || frame.contentDocument; - frame.document.open(); - frame.document.write(data); - frame.document.close(); - - var hideTimeout = setTimeout(function(){ - pdoc.getElementById('loading-spinner-wrapper').className += 'remove'; - clearTimeout(hideTimeout); - }, 50) // just enough to give effect without adding discernible slowness + previewWindow.document.open(); + previewWindow.document.write(data); + previewWindow.document.close(); } else { previewWindow.close(); document.open(); diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html index d5c4b7a51..46a4d2867 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html @@ -11,6 +11,5 @@-