Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support overriding default item in page action menu #5612

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 17 additions & 1 deletion docs/reference/hooks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ Hooks for customising the way users are directed through the process of creating

Add an item to the popup menu of actions on the page creation and edit views. The callable passed to this hook must return an instance of ``wagtail.admin.action_menu.ActionMenuItem``. The following attributes and methods are available to be overridden on subclasses of ``ActionMenuItem``:

:order: an integer (default 100) which determines the item's position in the menu. Can also be passed as a keyword argument to the object constructor
:order: an integer (default 100) which determines the item's position in the menu. Can also be passed as a keyword argument to the object constructor. The lowest-numbered item in this sequence will be selected as the default menu item; as standard, this is "Save draft" (which has an ``order`` of 0).
:label: the displayed text of the menu item
:get_url: a method which returns a URL for the menu item to link to; by default, returns ``None`` which causes the menu item to behave as a form submit button instead
:name: value of the ``name`` attribute of the submit button, if no URL is specified
Expand Down Expand Up @@ -566,12 +566,28 @@ Hooks for customising the way users are directed through the process of creating

Modify the final list of action menu items on the page creation and edit views. The callable passed to this hook receives a list of ``ActionMenuItem`` objects, a request object and a context dictionary as per ``register_page_action_menu_item``, and should modify the list of menu items in-place.


.. code-block:: python

@hooks.register('construct_page_action_menu')
def remove_submit_to_moderator_option(menu_items, request, context):
menu_items[:] = [item for item in menu_items if item.name != 'action-submit']


The order of items in this list determines the menu ordering, and the first item in the list will be selected as the default action. For example, to change the default action to Publish:

.. code-block:: python

@hooks.register('construct_page_action_menu')
def make_publish_default_action(menu_items, request, context):
for (index, item) in enumerate(menu_items):
if item.name == 'action-publish':
# move to top of list
menu_items.pop(index)
menu_items.insert(0, item)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably needs a note to say that this will ignore the order field on the menu items?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I'll update the text to:

The construct_page_action_menu hook is called after the menu items have been sorted by their order attributes, and so setting a menu item's order will have no effect at this point. Instead, items can be reordered by changing their position in the list, with the first item being selected as the default action. For example, to change the default action to Publish:

break


.. construct_page_listing_buttons:

``construct_page_listing_buttons``
Expand Down
24 changes: 24 additions & 0 deletions docs/releases/2.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,30 @@ This release introduces a new setting :ref:`WAGTAILDOCS_SERVE_METHOD <wagtaildoc
In Wagtail 2.7, the default behaviour on remote storage backends is to redirect to the storage's underlying URL after performing the permission check. If this is unsuitable for your project (for example, your storage provider is configured to block public access, or revealing its URL would be a security risk) you can revert to the previous behaviour by setting ``WAGTAILDOCS_SERVE_METHOD`` to ``'serve_view'``.


Template change for page action menu hooks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When customising the action menu on the page edit view through the :ref:`register_page_action_menu_item <register_page_action_menu_item>` or :ref:`construct_page_action_menu <construct_page_action_menu>` hook, the ``ActionMenuItem`` object's ``template`` attribute or ``render_html`` method can be overridden to customise the menu item's HTML. As of Wagtail 2.7, the HTML returned from these should *not* include the enclosing ``<li>`` element.

Any add-on library that uses this feature and needs to preserve backward compatibility with previous Wagtail versions can conditionally reinsert the ``<li>`` wrapper through its ``render_html`` method - for example:

.. code-block:: python

from django.utils.html import format_html
from wagtail import VERSION as WAGTAIL_VERSION
from wagtail.admin.action_menu import ActionMenuItem

class CustomMenuItem(ActionMenuItem):
template = 'myapp/my_menu_item.html'

def render_html(self, request, parent_context):
html = super().render_html(request, parent_context)
if WAGTAIL_VERSION < (2, 7):
html = format_html('<li>{}</li>', html)
return html



``wagtail.admin.utils`` and ``wagtail.admin.decorators`` modules deprecated
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
36 changes: 35 additions & 1 deletion wagtail/admin/action_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def render_html(self, request, parent_context):


class PublishMenuItem(ActionMenuItem):
label = _("Publish")
name = 'action-publish'
template = 'wagtailadmin/pages/action_menu/publish.html'

Expand Down Expand Up @@ -121,6 +122,31 @@ def get_url(self, request, context):
return reverse('wagtailadmin_pages:delete', args=(context['page'].id,))


class SaveDraftMenuItem(ActionMenuItem):
name = 'action-save-draft'
label = _("Save Draft")
template = 'wagtailadmin/pages/action_menu/save_draft.html'

def get_context(self, request, parent_context):
context = super().get_context(request, parent_context)
context['is_revision'] = (context['view'] == 'revisions_revert')
return context


class PageLockedMenuItem(ActionMenuItem):
name = 'action-page-locked'
label = _("Page locked")
template = 'wagtailadmin/pages/action_menu/page_locked.html'

def is_shown(self, request, context):
return ('page' in context) and (context['page'].locked)

def get_context(self, request, parent_context):
context = super().get_context(request, parent_context)
context['is_revision'] = (context['view'] == 'revisions_revert')
return context


BASE_PAGE_ACTION_MENU_ITEMS = None


Expand All @@ -133,6 +159,8 @@ def _get_base_page_action_menu_items():

if BASE_PAGE_ACTION_MENU_ITEMS is None:
BASE_PAGE_ACTION_MENU_ITEMS = [
PageLockedMenuItem(order=-10000),
SaveDraftMenuItem(order=0),
UnpublishMenuItem(order=10),
DeleteMenuItem(order=20),
PublishMenuItem(order=30),
Expand Down Expand Up @@ -163,13 +191,19 @@ def __init__(self, request, **kwargs):
for hook in hooks.get_hooks('construct_page_action_menu'):
hook(self.menu_items, self.request, self.context)

try:
self.default_item = self.menu_items.pop(0)
except IndexError:
self.default_item = None

def render_html(self):
return render_to_string(self.template, {
'default_menu_item': self.default_item.render_html(self.request, self.context),
'show_menu': bool(self.menu_items),
'rendered_menu_items': [
menu_item.render_html(self.request, self.context)
for menu_item in self.menu_items
]
],
}, request=self.request)

@cached_property
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
{% if default_menu_item %}
{{ default_menu_item }}
{% endif %}
{% if show_menu %}
<div class="dropdown-toggle icon icon-arrow-up"></div>
<ul>
{% for item in rendered_menu_items %}{{ item }}{% endfor %}
{% for item in rendered_menu_items %}
<li>
{{ item }}
</li>
{% endfor %}
</ul>
{% endif %}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<li>
{% if url %}
<a href="{{ url }}">{{ label }}</a>
{% else %}
<input type="submit" name="{{ name }}" value="{{ label }}" class="button" />
{% endif %}
</li>
{% if url %}
<a class="button" href="{{ url }}">{{ label }}</a>
{% else %}
<input type="submit" name="{{ name }}" value="{{ label }}" class="button" />
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% load i18n %}
<button type="submit" class="button action-save {% if is_revision %}warning{% endif %}" disabled>{% trans 'Page locked' %}</button>
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
{% load i18n %}
<li>
<button type="submit" name="action-publish" value="action-publish" class="button button-longrunning {% if is_revision %}warning{% endif %}" data-clicked-text="{% trans 'Publishing…' %}"><span class="icon icon-spinner"></span><em>{% if is_revision %}{% trans 'Publish this revision' %}{% else %}{% trans 'Publish' %}{% endif %}</em></button>
</li>
<button type="submit" name="action-publish" value="action-publish" class="button button-longrunning {% if is_revision %}warning{% endif %}" data-clicked-text="{% trans 'Publishing…' %}"><span class="icon icon-spinner"></span><em>{% if is_revision %}{% trans 'Publish this revision' %}{% else %}{% trans 'Publish' %}{% endif %}</em></button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% load i18n %}
<button type="submit" class="button action-save button-longrunning {% if is_revision %}warning{% endif %}" data-clicked-text="{% trans 'Saving…' %}"><span class="icon icon-spinner"></span><em>{% if is_revision %}{% trans 'Replace current draft' %}{% else %}{% trans 'Save draft' %}{% endif %}</em></button>
11 changes: 5 additions & 6 deletions wagtail/admin/templates/wagtailadmin/pages/create.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@ <h1 class="icon icon-doc-empty-inverse">
<footer role="contentinfo">
<nav aria-label="{% trans 'Actions' %}">
<ul>
<li class="actions">
<div class="dropdown dropup dropdown-button match-width">
<button type="submit" class="button action-save button-longrunning" data-clicked-text="{% trans 'Saving…' %}"><span class="icon icon-spinner"></span><em>{% trans 'Save draft' %}</em></button>
{{ action_menu.render_html }}
</div>
</li>
<li class="actions">
<div class="dropdown dropup dropdown-button match-width {% if is_revision %}warning{% endif %}">
{{ action_menu.render_html }}
</div>
</li>

<li class="preview">
{% trans 'Preview' as preview_label %}
Expand Down
2 changes: 0 additions & 2 deletions wagtail/admin/templates/wagtailadmin/pages/edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ <h1 class="icon icon-doc-empty-inverse">
<ul>
<li class="actions">
<div class="dropdown dropup dropdown-button match-width {% if is_revision %}warning{% endif %}">
<button type="submit" class="button action-save button-longrunning {% if is_revision %}warning{% endif %}" data-clicked-text="{% trans 'Saving…' %}" {% if page.locked %}disabled {% endif %}><span class="icon icon-spinner"></span><em>{% if page.locked %}{% trans 'Page locked' %}{% else %}{% if is_revision %}{% trans 'Replace current draft' %}{% else %}{% trans 'Save draft' %}{% endif %}{% endif %}</em></button>

{{ action_menu.render_html }}
</div>
</li>
Expand Down
30 changes: 30 additions & 0 deletions wagtail/admin/tests/pages/test_edit_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,36 @@ def hook_func(request, page):
# page should be edited
self.assertEqual(Page.objects.get(id=self.child_page.id).title, "I've been edited!")

def test_override_default_action_menu_item(self):
def hook_func(menu_items, request, context):
for (index, item) in enumerate(menu_items):
if item.name == 'action-publish':
# move to top of list
menu_items.pop(index)
menu_items.insert(0, item)
break

with self.register_hook('construct_page_action_menu', hook_func):
response = self.client.get(reverse('wagtailadmin_pages:edit', args=(self.single_event_page.id, )))

publish_button = '''
<button type="submit" name="action-publish" value="action-publish" class="button button-longrunning " data-clicked-text="Publishing…">
<span class="icon icon-spinner"></span><em>Publish</em>
</button>
'''
save_button = '''
<button type="submit" class="button action-save button-longrunning " data-clicked-text="Saving…" >
<span class="icon icon-spinner"></span><em>Save draft</em>
</button>
'''

# save button should be in a <li>
self.assertContains(response, "<li>%s</li>" % save_button, html=True)

# publish button should be present, but not in a <li>
self.assertContains(response, publish_button, html=True)
self.assertNotContains(response, "<li>%s</li>" % publish_button, html=True)


class TestPageEditReordering(TestCase, WagtailTestUtils):
def setUp(self):
Expand Down