From f972579844196c802dc830024213535d8abfc4d0 Mon Sep 17 00:00:00 2001 From: Tim Heap Date: Thu, 19 Nov 2015 17:04:03 +1100 Subject: [PATCH] Add hook to allow adding buttons to page listing The 'register_page_listing_buttons' hook allows plugin developers to add buttons to the actions list on the page listing in the admin. --- .../wagtailadmin/pages/listing/_buttons.html | 3 ++ .../pages/listing/_page_title_explore.html | 29 ++---------- .../listing/_parent_page_title_explore.html | 25 +--------- .../templatetags/wagtailadmin_tags.py | 13 ++++++ wagtail/wagtailadmin/wagtail_hooks.py | 37 +++++++++++++-- wagtail/wagtailadmin/widgets.py | 46 +++++++++++++++++++ 6 files changed, 99 insertions(+), 54 deletions(-) create mode 100644 wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_buttons.html diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_buttons.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_buttons.html new file mode 100644 index 0000000000..3887ced9cf --- /dev/null +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_buttons.html @@ -0,0 +1,3 @@ +{% for button in buttons %} +
  • {{ button|safe }}
  • +{% endfor %} diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_page_title_explore.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_page_title_explore.html index fb8386ae9a..2846fad9ff 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_page_title_explore.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_page_title_explore.html @@ -1,4 +1,4 @@ -{% load i18n %} +{% load i18n wagtailadmin_tags %} {# The title field for a page in the page listing, when in 'explore' mode #} @@ -14,28 +14,5 @@ \ No newline at end of file + {% page_listing_buttons page page_perms %} + diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_parent_page_title_explore.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_parent_page_title_explore.html index 014933922b..9173c99e7d 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_parent_page_title_explore.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/listing/_parent_page_title_explore.html @@ -16,26 +16,5 @@ {% include "wagtailadmin/pages/_privacy_switch.html" with page=parent_page %} \ No newline at end of file + {% page_listing_buttons parent_page parent_page_perms is_parent=True %} + diff --git a/wagtail/wagtailadmin/templatetags/wagtailadmin_tags.py b/wagtail/wagtailadmin/templatetags/wagtailadmin_tags.py index aee4843e54..a4eda44005 100644 --- a/wagtail/wagtailadmin/templatetags/wagtailadmin_tags.py +++ b/wagtail/wagtailadmin/templatetags/wagtailadmin_tags.py @@ -1,5 +1,7 @@ from __future__ import unicode_literals +import itertools + from django import template from django.conf import settings from django.contrib.humanize.templatetags.humanize import intcomma @@ -280,3 +282,14 @@ def paginate(context, page, base_url='', page_key=DEFAULT_PAGE_KEY, 'page_key': page_key, 'paginator': page.paginator, } + + +@register.inclusion_tag("wagtailadmin/pages/listing/_buttons.html", + takes_context=True) +def page_listing_buttons(context, page, page_perms, is_parent=False): + button_hooks = hooks.get_hooks('register_page_listing_buttons') + buttons = sorted(itertools.chain.from_iterable( + hook(page, page_perms, is_parent) + for hook in button_hooks)) + print(buttons) + return {'page': page, 'buttons': buttons} diff --git a/wagtail/wagtailadmin/wagtail_hooks.py b/wagtail/wagtailadmin/wagtail_hooks.py index 9dc1cdb54e..65f134335c 100644 --- a/wagtail/wagtailadmin/wagtail_hooks.py +++ b/wagtail/wagtailadmin/wagtail_hooks.py @@ -1,10 +1,11 @@ from django.contrib.auth.models import Permission from django.contrib.staticfiles.templatetags.staticfiles import static -from django.core import urlresolvers +from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ from wagtail.wagtailadmin.menu import MenuItem, SubmenuMenuItem, settings_menu from wagtail.wagtailadmin.search import SearchArea +from wagtail.wagtailadmin.widgets import Button, PageListingButton from wagtail.wagtailcore import hooks from wagtail.wagtailcore.permissions import collection_permission_policy @@ -17,10 +18,10 @@ class ExplorerMenuItem(MenuItem): @hooks.register('register_admin_menu_item') def register_explorer_menu_item(): return ExplorerMenuItem( - _('Explorer'), urlresolvers.reverse('wagtailadmin_explore_root'), + _('Explorer'), reverse('wagtailadmin_explore_root'), name='explorer', classnames='icon icon-folder-open-inverse dl-trigger', - attrs={'data-explorer-menu-url': urlresolvers.reverse('wagtailadmin_explorer_nav')}, + attrs={'data-explorer-menu-url': reverse('wagtailadmin_explorer_nav')}, order=100) @@ -38,7 +39,7 @@ def register_permissions(): @hooks.register('register_admin_search_area') def register_pages_search_area(): return SearchArea( - _('Pages'), urlresolvers.reverse('wagtailadmin_pages:search'), + _('Pages'), reverse('wagtailadmin_pages:search'), name='pages', classnames='icon icon-folder-open-inverse', order=100) @@ -53,4 +54,30 @@ class CollectionsMenuItem(MenuItem): @hooks.register('register_settings_menu_item') def register_collections_menu_item(): - return CollectionsMenuItem(_('Collections'), urlresolvers.reverse('wagtailadmin_collections:index'), classnames='icon icon-folder-open-1', order=700) + return CollectionsMenuItem(_('Collections'), reverse('wagtailadmin_collections:index'), classnames='icon icon-folder-open-1', order=700) + + +@hooks.register('register_page_listing_buttons') +def page_listing_buttons(page, page_perms, is_parent=False): + if page_perms.can_edit(): + yield PageListingButton(_('Edit'), reverse('wagtailadmin_pages:edit', args=[page.id]), + attrs={'title': _('Edit this page')}, priority=10) + if page.has_unpublished_changes: + yield PageListingButton(_('Draft'), reverse('wagtailadmin_pages:view_draft', args=[page.id]), + attrs={'target': '_blank'}, priority=20) + if page.live and page.url: + yield PageListingButton(_('Live'), page.url, attrs={'target': "_blank"}, priority=30) + if page_perms.can_move(): + yield PageListingButton(_('Move'), reverse('wagtailadmin_pages:move', args=[page.id]), priority=40) + if not page.is_root(): + yield PageListingButton(_('Copy'), reverse('wagtailadmin_pages:copy', args=[page.id]), priority=50) + if page_perms.can_delete(): + yield PageListingButton(_('Delete'), reverse('wagtailadmin_pages:delete', args=[page.id]), priority=60) + if page_perms.can_unpublish(): + yield PageListingButton(_('Unpublish'), reverse('wagtailadmin_pages:unpublish', args=[page.id]), priority=70) + if page_perms.can_add_subpage(): + if is_parent: + yield Button(_('Add child page'), reverse('wagtailadmin_pages:add_subpage', args=[page.id]), + classes={'button', 'button-small', 'bicolor', 'icon', 'white', 'icon-plus'}, priority=80) + else: + yield PageListingButton(_('Add child page'), reverse('wagtailadmin_pages:add_subpage', args=[page.id]), priority=80) diff --git a/wagtail/wagtailadmin/widgets.py b/wagtail/wagtailadmin/widgets.py index 65e4913c0d..a998f06ded 100644 --- a/wagtail/wagtailadmin/widgets.py +++ b/wagtail/wagtailadmin/widgets.py @@ -1,13 +1,17 @@ from __future__ import absolute_import, unicode_literals import json +from functools import total_ordering from django.contrib.contenttypes.models import ContentType from django.core.urlresolvers import reverse from django.forms import widgets +from django.forms.utils import flatatt from django.template.loader import render_to_string +from django.utils.encoding import python_2_unicode_compatible from django.utils.formats import get_format from django.utils.functional import cached_property +from django.utils.html import format_html from django.utils.translation import ugettext_lazy as _ from taggit.forms import TagWidget @@ -185,3 +189,45 @@ class AdminPageChooser(AdminChooser): parent=json.dumps(parent.id if parent else None), can_choose_root=('true' if self.can_choose_root else 'false') ) + + +@python_2_unicode_compatible +@total_ordering +class Button(object): + def __init__(self, label, url, classes=set(), attrs={}, priority=1000): + self.label = label + self.url = url + self.classes = classes + self.attrs = attrs.copy() + self.priority = priority + + def render(self): + attrs = {'href': self.url, 'class': ' '.join(sorted(self.classes))} + attrs.update(self.attrs) + return format_html('{}', flatatt(attrs), self.label) + + def __str__(self): + return self.render() + + def __repr__(self): + return ''.format(self.label) + + def __lt__(self, other): + if not isinstance(other, Button): + return NotImplemented + return (self.priority, self.label) < (other.priority, other.label) + + def __eq__(self, other): + if not isinstance(other, Button): + return NotImplemented + return (self.label == other.label and + self.url == other.url and + self.classes == other.classes and + self.attrs == other.attrs and + self.priority == other.priority) + + +class PageListingButton(Button): + def __init__(self, label, url, classes=set(), **kwargs): + classes = {'button', 'button-small', 'button-secondary'} | set(classes) + super(PageListingButton, self).__init__(label, url, classes=classes, **kwargs)