Add support for "nested" menu items
some menus were just getting too long, so this gives us a way to collapse certain items, which user can expand as needed
This commit is contained in:
parent
329e75ee82
commit
fe80028c07
3 changed files with 139 additions and 38 deletions
|
@ -2,7 +2,7 @@
|
|||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2018 Lance Edgar
|
||||
# Copyright © 2010-2021 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -33,6 +33,7 @@ from rattail.util import import_module_path
|
|||
class MenuGroup(Object):
|
||||
title = None
|
||||
items = None
|
||||
is_menu = True
|
||||
is_link = False
|
||||
|
||||
|
||||
|
@ -41,10 +42,19 @@ class MenuItem(Object):
|
|||
url = None
|
||||
target = None
|
||||
is_link = True
|
||||
is_menu = False
|
||||
is_sep = False
|
||||
|
||||
|
||||
class MenuItemMenu(Object):
|
||||
title = None
|
||||
items = None
|
||||
is_menu = True
|
||||
is_sep = False
|
||||
|
||||
|
||||
class MenuSeparator(object):
|
||||
is_menu = False
|
||||
is_sep = True
|
||||
|
||||
|
||||
|
@ -61,55 +71,108 @@ def make_simple_menus(request):
|
|||
# collect "simple" menus definition, but must refine that somewhat to
|
||||
# produce our final menus
|
||||
raw_menus = menus_module.simple_menus(request)
|
||||
mark_allowed(request, raw_menus)
|
||||
final_menus = []
|
||||
for topitem in raw_menus:
|
||||
|
||||
if topitem.get('type') == 'link':
|
||||
final_menus.append(
|
||||
MenuItem(title=topitem['title'],
|
||||
url=topitem['url'],
|
||||
target=topitem.get('target')))
|
||||
if topitem['allowed']:
|
||||
|
||||
else: # assuming 'menu' type
|
||||
if topitem.get('type') == 'link':
|
||||
final_menus.append(make_menu_entry(topitem))
|
||||
|
||||
# figure out which ones the user has permission to access
|
||||
allowed = []
|
||||
for item in topitem['items']:
|
||||
else: # assuming 'menu' type
|
||||
|
||||
if item.get('type') == 'sep':
|
||||
allowed.append(item)
|
||||
|
||||
if item.get('perm'):
|
||||
if request.has_perm(item['perm']):
|
||||
allowed.append(item)
|
||||
else:
|
||||
allowed.append(item)
|
||||
|
||||
if allowed:
|
||||
|
||||
# user must have access to something; construct items for the menu
|
||||
menu_items = []
|
||||
for item in allowed:
|
||||
for item in topitem['items']:
|
||||
if not item['allowed']:
|
||||
continue
|
||||
|
||||
# separator
|
||||
if item.get('type') == 'sep':
|
||||
# nested submenu
|
||||
if item.get('type') == 'menu':
|
||||
submenu_items = []
|
||||
for subitem in item['items']:
|
||||
if subitem['allowed']:
|
||||
submenu_items.append(make_menu_entry(subitem))
|
||||
menu_items.append(MenuItemMenu(
|
||||
title=item['title'],
|
||||
items=submenu_items))
|
||||
|
||||
elif item.get('type') == 'sep':
|
||||
# we only want to add a sep, *if* we already have some
|
||||
# menu items (i.e. there is something to separate)
|
||||
# *and* the last menu item is not a sep (avoid doubles)
|
||||
if menu_items and not menu_items[-1].is_sep:
|
||||
menu_items.append(MenuSeparator())
|
||||
menu_items.append(make_menu_entry(item))
|
||||
|
||||
# menu item
|
||||
else:
|
||||
menu_items.append(
|
||||
MenuItem(title=item['title'],
|
||||
url=item['url'],
|
||||
target=item.get('target')))
|
||||
else: # standard menu item
|
||||
menu_items.append(make_menu_entry(item))
|
||||
|
||||
# remove final separator if present
|
||||
if menu_items and menu_items[-1].is_sep:
|
||||
menu_items.pop()
|
||||
|
||||
# only add if we wound up with something
|
||||
assert menu_items
|
||||
if menu_items:
|
||||
final_menus.append(
|
||||
MenuGroup(title=topitem['title'], items=menu_items))
|
||||
final_menus.append(MenuGroup(
|
||||
title=topitem['title'],
|
||||
items=menu_items))
|
||||
|
||||
return final_menus
|
||||
|
||||
|
||||
def make_menu_entry(item):
|
||||
"""
|
||||
Convert a simple menu entry dict, into a proper menu-related object, for
|
||||
use in constructing final menu.
|
||||
"""
|
||||
# separator
|
||||
if item.get('type') == 'sep':
|
||||
return MenuSeparator()
|
||||
|
||||
# standard menu item
|
||||
return MenuItem(
|
||||
title=item['title'],
|
||||
url=item['url'],
|
||||
target=item.get('target'))
|
||||
|
||||
|
||||
def is_allowed(request, item):
|
||||
"""
|
||||
Logic to determine if a given menu item is "allowed" for current user.
|
||||
"""
|
||||
perm = item.get('perm')
|
||||
if perm:
|
||||
return request.has_perm(perm)
|
||||
return True
|
||||
|
||||
|
||||
def mark_allowed(request, menus):
|
||||
"""
|
||||
Traverse the menu set, and mark each item as "allowed" (or not) based on
|
||||
current user permissions.
|
||||
"""
|
||||
for topitem in menus:
|
||||
|
||||
if topitem.get('type', 'menu') == 'menu':
|
||||
topitem['allowed'] = False
|
||||
|
||||
for item in topitem['items']:
|
||||
|
||||
if item.get('type') == 'menu':
|
||||
for subitem in item['items']:
|
||||
subitem['allowed'] = is_allowed(request, subitem)
|
||||
|
||||
item['allowed'] = False
|
||||
for subitem in item['items']:
|
||||
if subitem['allowed'] and subitem.get('type') != 'sep':
|
||||
item['allowed'] = True
|
||||
break
|
||||
|
||||
else:
|
||||
item['allowed'] = is_allowed(request, item)
|
||||
|
||||
for item in topitem['items']:
|
||||
if item['allowed'] and item.get('type') != 'sep':
|
||||
topitem['allowed'] = True
|
||||
break
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue