forked from ungleich-public/dynamicweb
183 lines
5.5 KiB
Python
183 lines
5.5 KiB
Python
from typing import Any, Optional
|
|
|
|
from django.utils.encoding import smart_str
|
|
|
|
|
|
class Menu:
|
|
"""The base class for all menu-generating classes."""
|
|
namespace = None
|
|
|
|
def __init__(self, renderer):
|
|
"""
|
|
Initialize the Menu class.
|
|
|
|
Args:
|
|
renderer: The renderer associated with the menu.
|
|
"""
|
|
self.renderer = renderer
|
|
|
|
if not self.namespace:
|
|
self.namespace = self.__class__.__name__
|
|
|
|
def get_nodes(self, request) -> list['NavigationNode']:
|
|
"""
|
|
Get a list of NavigationNode instances for the menu.
|
|
|
|
Args:
|
|
request: The request object.
|
|
|
|
Returns:
|
|
A list of NavigationNode instances.
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
|
|
class Modifier:
|
|
"""The base class for all menu-modifying classes. A modifier add, removes or changes
|
|
:class:`menus.base.NavigationNode` in the list."""
|
|
def __init__(self, renderer):
|
|
"""
|
|
Initialize the Modifier class.
|
|
|
|
Args:
|
|
renderer: The renderer associated with the modifier.
|
|
"""
|
|
self.renderer = renderer
|
|
|
|
def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
|
|
"""
|
|
Modify the list of nodes.
|
|
|
|
Args:
|
|
request: The request object.
|
|
nodes: List of NavigationNode instances.
|
|
namespace: The namespace for the menu.
|
|
root_id: ID of the root node.
|
|
post_cut: Boolean indicating post-cut status.
|
|
breadcrumb: Boolean indicating breadcrumb status.
|
|
"""
|
|
pass
|
|
|
|
|
|
class NavigationNode:
|
|
"""
|
|
Represents each node in a menu tree.
|
|
|
|
Attributes:
|
|
title: The title of the menu item.
|
|
url: The URL associated with the menu item.
|
|
id: The unique ID of this item.
|
|
parent_id: The ID of the parent item (optional).
|
|
parent_namespace: The namespace of the parent (optional).
|
|
attr: Additional information to store on this node (optional).
|
|
visible: Indicates whether this item is visible (default is True).
|
|
"""
|
|
|
|
selected: bool = False
|
|
ancestor: bool = False
|
|
descendant: bool = False
|
|
sibling: bool = False
|
|
level: int | None = None
|
|
|
|
def __init__(
|
|
self,
|
|
title: str,
|
|
url: str,
|
|
id: Any,
|
|
parent_id: Any | None = None,
|
|
parent_namespace: str | None = None,
|
|
attr: dict[str, Any] | None = None,
|
|
visible: bool = True,
|
|
):
|
|
"""
|
|
Initialize a NavigationNode instance.
|
|
|
|
Args:
|
|
title: The title of the menu item.
|
|
url: The URL associated with the menu item.
|
|
id: The unique ID of this item.
|
|
parent_id: The ID of the parent item (optional).
|
|
parent_namespace: The namespace of the parent (optional).
|
|
attr: Additional information to store on this node (optional).
|
|
visible: Indicates whether this item is visible (default is True).
|
|
"""
|
|
self.children: list[NavigationNode] = [] # Do not modify
|
|
self.parent: NavigationNode | None = None # Do not modify, code depends on this
|
|
self.namespace: str | None = None # TODO: Clarify the necessity of this and the line above
|
|
self.title = title
|
|
self.url = url
|
|
self.id = id
|
|
self.parent_id = parent_id
|
|
self.parent_namespace = parent_namespace
|
|
self.visible = visible
|
|
self.attr = attr or {}
|
|
"""
|
|
A dictionary to add arbitrary attributes to the node. An important key is 'is_page':
|
|
* If True, the node represents a django CMS 'Page' object.
|
|
* Nodes representing CMS pages have specific keys in 'attr'.
|
|
"""
|
|
|
|
def __repr__(self):
|
|
"""
|
|
Returns a string representation of the NavigationNode.
|
|
"""
|
|
return f"<Navigation Node: {smart_str(self.title)}>"
|
|
|
|
def get_menu_title(self) -> str:
|
|
"""
|
|
Returns the associated title using the naming convention of 'cms.models.pagemodel.Page'.
|
|
"""
|
|
return self.title
|
|
|
|
def get_absolute_url(self) -> str:
|
|
"""
|
|
Returns the URL associated with this menu item.
|
|
"""
|
|
return self.url
|
|
|
|
def get_attribute(self, name: str) -> Any:
|
|
"""
|
|
Retrieves a dictionary item from 'attr'. Returns None if it does not exist.
|
|
|
|
Args:
|
|
name: The name of the attribute.
|
|
|
|
Returns:
|
|
The value associated with the attribute name or None if not found.
|
|
"""
|
|
return self.attr.get(name, None)
|
|
|
|
def get_descendants(self) -> list['NavigationNode']:
|
|
"""
|
|
Returns a list of all children beneath the current menu item.
|
|
"""
|
|
return sum(([node] + node.get_descendants() for node in self.children), [])
|
|
|
|
def get_ancestors(self) -> list['NavigationNode']:
|
|
"""
|
|
Returns a list of all parent items, excluding the current menu item.
|
|
"""
|
|
if getattr(self, 'parent', None):
|
|
return [self.parent] + self.parent.get_ancestors()
|
|
else:
|
|
return []
|
|
|
|
def is_selected(self, request) -> bool:
|
|
"""
|
|
Checks if the node is selected based on the request path.
|
|
|
|
Args:
|
|
request: The request object.
|
|
|
|
Returns:
|
|
True if the node is selected, False otherwise.
|
|
"""
|
|
node_abs_url = self.get_absolute_url()
|
|
return node_abs_url == request.path
|
|
|
|
@property
|
|
def is_leaf_node(self) -> bool:
|
|
"""
|
|
Indicates whether the node is a leaf node.
|
|
"""
|
|
return not self.children
|