123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- from django.forms import Media, MediaDefiningClass
- from django.forms.utils import flatatt
- from django.template.loader import render_to_string
- from django.utils.safestring import mark_safe
- from wagtail import hooks
- from wagtail.admin.ui.sidebar import LinkMenuItem as LinkMenuItemComponent
- from wagtail.admin.ui.sidebar import SubMenuItem as SubMenuItemComponent
- from wagtail.coreutils import cautious_slugify
- class MenuItem(metaclass=MediaDefiningClass):
- def __init__(
- self, label, url, name=None, classnames="", icon_name="", attrs=None, order=1000
- ):
- self.label = label
- self.url = url
- self.classnames = classnames
- self.icon_name = icon_name
- self.name = name or cautious_slugify(str(label))
- self.order = order
- if attrs:
- self.attr_string = flatatt(attrs)
- else:
- self.attr_string = ""
- def is_shown(self, request):
- """
- Whether this menu item should be shown for the given request; permission
- checks etc should go here. By default, menu items are shown all the time
- """
- return True
- def is_active(self, request):
- return request.path.startswith(str(self.url))
- def get_context(self, request):
- """Defines context for the template, overridable to use more data"""
- return {
- "name": self.name,
- "url": self.url,
- "classnames": self.classnames,
- "icon_name": self.icon_name,
- "attr_string": self.attr_string,
- "label": self.label,
- "active": self.is_active(request),
- }
- def render_html(self, request):
- context = self.get_context(request)
- return render_to_string(self.template, context, request=request)
- def render_component(self, request):
- return LinkMenuItemComponent(
- self.name,
- self.label,
- self.url,
- icon_name=self.icon_name,
- classnames=self.classnames,
- )
- class Menu:
- def __init__(self, register_hook_name, construct_hook_name=None):
- self.register_hook_name = register_hook_name
- self.construct_hook_name = construct_hook_name
- # _registered_menu_items will be populated on first access to the
- # registered_menu_items property. We can't populate it in __init__ because
- # we can't rely on all hooks modules to have been imported at the point that
- # we create the admin_menu and settings_menu instances
- self._registered_menu_items = None
- @property
- def registered_menu_items(self):
- if self._registered_menu_items is None:
- self._registered_menu_items = [
- fn() for fn in hooks.get_hooks(self.register_hook_name)
- ]
- return self._registered_menu_items
- def menu_items_for_request(self, request):
- items = [item for item in self.registered_menu_items if item.is_shown(request)]
- # provide a hook for modifying the menu, if construct_hook_name has been set
- if self.construct_hook_name:
- for fn in hooks.get_hooks(self.construct_hook_name):
- fn(request, items)
- return items
- def active_menu_items(self, request):
- return [
- item
- for item in self.menu_items_for_request(request)
- if item.is_active(request)
- ]
- @property
- def media(self):
- media = Media()
- for item in self.registered_menu_items:
- media += item.media
- return media
- def render_html(self, request):
- menu_items = self.menu_items_for_request(request)
- rendered_menu_items = []
- for item in sorted(menu_items, key=lambda i: i.order):
- rendered_menu_items.append(item.render_html(request))
- return mark_safe("".join(rendered_menu_items))
- def render_component(self, request):
- menu_items = self.menu_items_for_request(request)
- rendered_menu_items = []
- for item in sorted(menu_items, key=lambda i: i.order):
- rendered_menu_items.append(item.render_component(request))
- return rendered_menu_items
- class SubmenuMenuItem(MenuItem):
- """A MenuItem which wraps an inner Menu object"""
- def __init__(self, label, menu, **kwargs):
- self.menu = menu
- super().__init__(label, "#", **kwargs)
- def is_shown(self, request):
- # show the submenu if one or more of its children is shown
- return bool(self.menu.menu_items_for_request(request))
- def is_active(self, request):
- return bool(self.menu.active_menu_items(request))
- def render_component(self, request):
- return SubMenuItemComponent(
- self.name,
- self.label,
- self.menu.render_component(request),
- icon_name=self.icon_name,
- classnames=self.classnames,
- )
- class AdminOnlyMenuItem(MenuItem):
- """A MenuItem which is only shown to superusers"""
- def is_shown(self, request):
- return request.user.is_superuser
- admin_menu = Menu(
- register_hook_name="register_admin_menu_item",
- construct_hook_name="construct_main_menu",
- )
- settings_menu = Menu(
- register_hook_name="register_settings_menu_item",
- construct_hook_name="construct_settings_menu",
- )
- reports_menu = Menu(
- register_hook_name="register_reports_menu_item",
- construct_hook_name="construct_reports_menu",
- )
|