Merge branch 'master' into copy-page-slug-available

pull/5138/head
Casper Timmers 2019-03-14 09:57:59 +01:00 zatwierdzone przez GitHub
commit 389f3262de
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
17 zmienionych plików z 131 dodań i 44 usunięć

Wyświetl plik

@ -18,6 +18,7 @@ Changelog
* Add Learn Wagtail to third-party tutorials in documentation (Matt Westcott)
* Add a Django setting `TAG_LIMIT` to limit number of tags that can be added to any taggit model (Mani)
* Added instructions on how to generate urls for `ModelAdmin` to documentation (LB (Ben Johnston), Andy Babic)
* Added option to specify a fallback URL on `{% pageurl %}` (Arthur Holzner)
* Fix: Set `SERVER_PORT` to 443 in `Page.dummy_request()` for HTTPS sites (Sergey Fedoseev)
* Fix: Include port number in `Host` header of `Page.dummy_request()` (Sergey Fedoseev)
* Fix: Validation error messages in `InlinePanel` no longer count towards `max_num` when disabling the 'add' button (Todd Dembrey, Thibaud Colas)
@ -31,6 +32,8 @@ Changelog
* Fix: Unclear error message when saving image after focal point edit (Hugo van den Berg)
* Fix: `send_mail` now correctly uses the `html_message` kwarg for HTML messages (Tiago Requeijo)
* Fix: Page copying no longer allowed if page model has reached its `max_count` (Andy Babic)
* Fix: Don't show page type on page chooser button when multiple types are allowed (Thijs Kramer)
* Fix: Make sure page chooser search results correspond to the latest search by canceling previous requests (Esper Kuijs)
* Fix: Inform user when moving a page from one parent to another where there is an already existing page with the same slug (Casper Timmers)

Wyświetl plik

@ -353,6 +353,7 @@ Contributors
* Gassan Gousseinov
* Thomas Kremmel
* patta42
* Esper Kuijs
Translators
===========

Wyświetl plik

@ -48,6 +48,7 @@ Want to know more about customising ``ModelAdmin``?
create_edit_delete_views
inspectview
chooseparentview
tips_and_tricks/index
.. _modeladmin_usage:
@ -222,10 +223,3 @@ the same ``wagtail_hooks.py`` file if you want. The example below will create
modeladmin_register(BookAdmin)
modeladmin_register(MovieAdmin)
modeladmin_register(MusicAdminGroup)
-------------------------
Additional Tips & Tricks
-------------------------
* To programatically generate URLs for any of your ``ModelAdmin`` views, see :ref:`modeladmin_reversing_urls`.

Wyświetl plik

@ -0,0 +1,10 @@
==========================
Additional tips and tricks
==========================
This section explores some of modeladmin's lesser-known features, and provides examples to help with modeladmin customisation. More pages will be added in future.
.. toctree::
:maxdepth: 1
reversing_urls

Wyświetl plik

@ -28,6 +28,7 @@ Other features
* Add Learn Wagtail to third-party tutorials in documentation (Matt Westcott)
* Add a Django setting ``TAG_LIMIT`` to limit number of tags that can be added to any taggit model (Mani)
* Added instructions on how to generate urls for ``ModelAdmin`` to documentation (LB (Ben Johnston), Andy Babic)
* Added option to specify a fallback URL on ``{% pageurl %}`` (Arthur Holzner)
Bug fixes
@ -47,6 +48,8 @@ Bug fixes
* Increase max length on ``Embed.thumbnail_url`` to 255 characters (Kevin Howbrook)
* ``send_mail`` now correctly uses the ``html_message`` kwarg for HTML messages (Tiago Requeijo)
* Page copying no longer allowed if page model has reached its ``max_count`` (Andy Babic)
* Don't show page type on page chooser button when multiple types are allowed (Thijs Kramer)
* Make sure page chooser search results correspond to the latest search by canceling previous requests (Esper Kuijs)
Upgrade considerations

Wyświetl plik

@ -160,7 +160,23 @@ Takes a Page object and returns a relative URL (``/foo/bar/``) if within the sam
{% load wagtailcore_tags %}
...
<a href="{% pageurl page.blog_page %}">
<a href="{% pageurl page.get_parent %}">Back to index</a>
A ``fallback`` keyword argument can be provided - this should be a URL route name that takes no parameters, and will be used as a substitute URL when the passed page is ``None``.
.. code-block:: html+django
{% load wagtailcore_tags %}
{% for publication in page.related_publications.all %}
<li>
<a href="{% pageurl publication.detail_page fallback='coming_soon' %}">
{{ publication.title }}
</a>
</li>
{% endfor %}
.. _slugurl_tag:

Wyświetl plik

@ -25,16 +25,19 @@ PAGE_CHOOSER_MODAL_ONLOAD_HANDLERS = {
/* save initial page browser HTML, so that we can restore it if the search box gets cleared */
var initialPageResultsHtml = $('.page-results', modal.body).html();
var request;
function search() {
var query = $('#id_q', modal.body).val();
if (query != '') {
$.ajax({
request = $.ajax({
url: searchUrl,
data: {
q: query,
results_only: true
},
success: function(data, status) {
request = null;
$('.page-results', modal.body).html(data);
ajaxifySearchResults();
}
@ -48,6 +51,9 @@ PAGE_CHOOSER_MODAL_ONLOAD_HANDLERS = {
}
$('#id_q', modal.body).on('input', function() {
if(request) {
request.abort();
}
clearTimeout($.data(this, 'timer'));
var wait = setTimeout(search, 200);
$(this).data('timer', wait);

Wyświetl plik

@ -14,7 +14,7 @@
{% csrf_token %}
{% page_permissions parent_page as parent_page_perms %}
{% include "wagtailadmin/pages/listing/_list_explore.html" with sortable=1 full_width=1 show_ordering_column=1 parent_page=parent_page orderable=parent_page_perms.can_reorder_children %}
{% include "wagtailadmin/pages/listing/_list_explore.html" with sortable=1 sortable_by_type=1 full_width=1 show_ordering_column=1 parent_page=parent_page orderable=parent_page_perms.can_reorder_children %}
{% if do_paginate %}
{% url 'wagtailadmin_explore' parent_page.id as pagination_base_url %}

Wyświetl plik

@ -5,6 +5,7 @@
Table headers for the page listing, when in 'explore' mode. Expects the following variables:
sortable: if true, headings are links to wagtailadmin_explore with sort parameters applied.
sortable_by_type: must be true to allow sorting on the 'type' column
show_ordering_column: if true, an 'ordering' column is added.
orderable: if true, the 'ordering' column is populated (again with links to wagtailadmin_explore).
@ -28,43 +29,31 @@ ordering: the current sort parameter
</th>
{% endif %}
<th class="title">
{% if sortable %}
<a href="{% if ordering == 'title' %}{% querystring ordering='-title' %}{% else %}{% querystring ordering='title' %}{% endif %}" class="icon icon-arrow-{% if ordering == 'title' %}down-after{% elif ordering == '-title' %}up-after{% else %}down-after{% endif %} {% if ordering == 'title' or ordering == '-title' %}teal{% endif %}">
{% trans 'Title' %}
</a>
{% else %}
{% trans 'Title' %}
{% endif %}
{% trans 'Title' as title_label %}
{% table_header_label label=title_label sortable=sortable sort_field='title' %}
</th>
{% if show_parent %}
<th class="parent">{% trans 'Parent' %}</th>
<th class="parent">
{% trans 'Parent' as parent_label %}
{% table_header_label label=parent_label sortable=0 %}
</th>
{% endif %}
<th class="updated">
{% if sortable %}
<a href="{% if ordering == 'latest_revision_created_at' %}{% querystring ordering='-latest_revision_created_at' %}{% else %}{% querystring ordering='latest_revision_created_at' %}{% endif %}" class="icon icon-arrow-{% if ordering == '-latest_revision_created_at' %}up-after{% else %}down-after{% endif %} {% if ordering == 'latest_revision_created_at' or ordering == '-latest_revision_created_at' %}teal {% endif %}">
{% trans 'Updated' %}
</a>
{% else %}
{% trans 'Updated' %}
{% endif %}
{% trans 'Updated' as updated_label %}
{% table_header_label label=updated_label sortable=sortable sort_field='latest_revision_created_at' %}
</th>
<th class="type">
{% if sortable and not not_sortable_by_type %}
<a href="{% if ordering == 'content_type' %}{% querystring ordering='-content_type' %}{% else %}{% querystring ordering='content_type' %}{% endif %}" class="icon icon-arrow-{% if ordering == '-content_type' %}up-after{% else %}down-after{% endif %} {% if ordering == 'content_type' or ordering == '-content_type' %}teal {% endif %}">
{% trans 'Type' %}
</a>
{% trans 'Type' as type_label %}
{% if sortable and sortable_by_type %}
{% table_header_label label=type_label sortable=1 sort_field='content_type' %}
{% else %}
{% trans 'Type' %}
{% table_header_label label=type_label sortable=0 %}
{% endif %}
</th>
<th class="status">
{% if sortable %}
<a href="{% if ordering == 'live' %}{% querystring ordering='-live' %}{% else %}{% querystring ordering='live' %}{% endif %}" class="icon icon-arrow-{% if ordering == '-live' %}up-after{% else %}down-after{% endif %} {% if ordering == 'live' or ordering == '-live' %}teal {% endif %}">
{% trans 'Status' %}
</a>
{% else %}
{% trans 'Status' %}
{% endif %}
{% trans 'Status' as status_label %}
{% table_header_label label=status_label sortable=sortable sort_field='live' %}
</th>
<th></th>
</tr>

Wyświetl plik

@ -32,7 +32,7 @@
</nav>
{% endif %}
{% include "wagtailadmin/pages/listing/_list_explore.html" with show_parent=1 sortable=1 not_sortable_by_type=1 %}
{% include "wagtailadmin/pages/listing/_list_explore.html" with show_parent=1 sortable=1 sortable_by_type=0 %}
{% url 'wagtailadmin_pages:search' as pagination_base_url %}
{% paginate pages base_url=pagination_base_url %}

Wyświetl plik

@ -8,7 +8,7 @@ from django.contrib.messages.constants import DEFAULT_TAGS as MESSAGE_TAGS
from django.template.defaultfilters import stringfilter
from django.template.loader import render_to_string
from django.templatetags.static import static
from django.utils.html import conditional_escape
from django.utils.html import conditional_escape, format_html
from django.utils.safestring import mark_safe
from wagtail.admin.menu import admin_menu
@ -289,6 +289,52 @@ def querystring(context, **kwargs):
return '?' + querydict.urlencode()
@register.simple_tag(takes_context=True)
def table_header_label(context, label=None, sortable=True, ordering=None, sort_context_var='ordering', sort_param='ordering', sort_field=None):
"""
A label to go in a table header cell, optionally with a 'sort' link that alternates between
forward and reverse sorting
label = label text
ordering = current active ordering. If not specified, we will fetch it from the template context variable
given by sort_context_var. (We don't fetch it from the URL because that wouldn't give the view method
the opportunity to set a default)
sort_param = URL parameter that indicates the current active ordering
sort_field = the value for sort_param that indicates that sorting is currently on this column.
For example, if sort_param='ordering' and sort_field='title', then a URL parameter of
ordering=title indicates that the listing is ordered forwards on this column, and a URL parameter
of ordering=-title indicated that the listing is ordered in reverse on this column
To disable sorting on this column, set sortable=False or leave sort_field unspecified.
"""
if not sortable or not sort_field:
# render label without a sort link
return label
if ordering is None:
ordering = context.get(sort_context_var)
reverse_sort_field = "-%s" % sort_field
if ordering == sort_field:
# currently ordering forwards on this column; link should change to reverse ordering
url = querystring(context, **{sort_param: reverse_sort_field})
classname = "icon icon-arrow-down-after teal"
elif ordering == reverse_sort_field:
# currently ordering backwards on this column; link should change to forward ordering
url = querystring(context, **{sort_param: sort_field})
classname = "icon icon-arrow-up-after teal"
else:
# not currently ordering on this column; link should change to forward ordering
url = querystring(context, **{sort_param: sort_field})
classname = "icon icon-arrow-down-after"
return format_html(
'<a href="{url}" class="{classname}">{label}</a>',
url=url, classname=classname, label=label
)
@register.simple_tag(takes_context=True)
def pagination_querystring(context, page_number, page_key=DEFAULT_PAGE_KEY):
"""

Wyświetl plik

@ -76,7 +76,7 @@ class TestAdminPageChooserWidget(TestCase):
)
html = widget.render_html('test', self.child_page, {})
self.assertIn(">Choose a page (Simple Page, Event Page)<", html)
self.assertIn(">Choose a page<", html)
def test_render_js_init_with_can_choose_root(self):
widget = widgets.AdminPageChooser(can_choose_root=True)

Wyświetl plik

@ -171,9 +171,9 @@ class AdminPageChooser(AdminChooser):
super().__init__(**kwargs)
if target_models:
models = ', '.join([model._meta.verbose_name.title() for model in target_models if model is not Page])
if models:
self.choose_one_text += ' (' + models + ')'
model_names = [model._meta.verbose_name.title() for model in target_models if model is not Page]
if len(model_names) == 1:
self.choose_one_text += ' (' + model_names[0] + ')'
self.user_perms = user_perms
self.target_models = list(target_models or [Page])

Wyświetl plik

@ -1,4 +1,5 @@
from django import template
from django.shortcuts import reverse
from django.template.defaulttags import token_kwargs
from django.utils.encoding import force_text
from django.utils.safestring import mark_safe
@ -12,11 +13,15 @@ register = template.Library()
@register.simple_tag(takes_context=True)
def pageurl(context, page):
def pageurl(context, page, fallback=None):
"""
Outputs a page's URL as relative (/foo/bar/) if it's within the same site as the
current page, or absolute (http://example.com/foo/bar/) if not.
If kwargs contains a fallback view name and page is None, the fallback view url will be returned.
"""
if page is None and fallback:
return reverse(fallback)
if not hasattr(page, 'relative_url'):
raise ValueError("pageurl tag expected a Page object, got %r" % page)

Wyświetl plik

@ -2,6 +2,7 @@ from django import template
from django.core.cache import cache
from django.http import HttpRequest
from django.test import TestCase
from django.urls.exceptions import NoReverseMatch
from django.utils.safestring import SafeText
from wagtail.core.models import Page, Site
@ -19,6 +20,16 @@ class TestPageUrlTags(TestCase):
self.assertContains(response,
'<a href="/events/christmas/">Christmas</a>')
def test_pageurl_fallback(self):
tpl = template.Template('''{% load wagtailcore_tags %}<a href="{% pageurl page fallback='fallback' %}">Fallback</a>''')
result = tpl.render(template.Context({'page': None}))
self.assertIn('<a href="/fallback/">Fallback</a>', result)
def test_pageurl_fallback_without_valid_fallback(self):
tpl = template.Template('''{% load wagtailcore_tags %}<a href="{% pageurl page fallback='not-existing-endpoint' %}">Fallback</a>''')
with self.assertRaises(NoReverseMatch):
tpl.render(template.Context({'page': None}))
def test_slugurl_tag(self):
response = self.client.get('/events/christmas/')
self.assertEqual(response.status_code, 200)

Wyświetl plik

@ -1,4 +1,5 @@
from django.conf.urls import include, url
from django.http import HttpResponse
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.api.v2.endpoints import PagesAPIEndpoint
@ -37,6 +38,8 @@ urlpatterns = [
url(r'^testapp/', include(testapp_urls)),
url(r'^fallback/', lambda: HttpResponse('ok'), name='fallback'),
# For anything not caught by a more specific rule above, hand over to
# Wagtail's serving mechanism
url(r'', include(wagtail_urls)),