|Version 18 (modified by 10 years ago) ( diff ),|
Table of Contents
S3Navigation is an S3 module providing a generic framework for the implementation of navigation elements in the web UI.
S3NavigationItem is a base class for the implementation of navigation items, and provides the common logic for all types of navigation items as well as an API for renderers.
Navigation items are UI elements to navigate the application, and can appear as menus, breadcrumb rows, tab rows, and various other types of links. They all have in common that they are linked to request URLs and usually get activated by clicking them.
The S3NavigationItem class is not meant to be used directly for the implementation of navigation items. Instead, it should be subclassed for each type of navigation items the user interface needs. Subclasses of S3NavigationItem are supposed to implement the layout of the respective item type, and are therefore referred to as Layouts.
To implement a Layout, create a new subclass of S3NavigationItem and implement a (static) method layout:
class MyMenuLayout(S3NavigationItem): @staticmethod def layout(item): # Layout implementation goes here
The layout method takes an instance of the layout class as parameter, and returns an instance of a web2py HTML helper class (DIV or a subclass of it). This HTML instance is what eventually gets written into the view.
The layout method can make use of the renderer API to retrieve the item's attributes and flags.
Defining Navigation Items
Once you have implemented the Layout, you can create instances of it to define the particular navigation elements. The elements can be nested using the call-method:
my_menu = MyMenuLayout("Home")( MyMenuLayout("First Item"), MyMenuLayout("Second Item"), MyMenuLayout("Submenu")( MyMenuLayout("First SubmenuItem"), MyMenuLayout("Second SubmenuItem") ) )
Each navigation item can receive any number of keyword parameters.
The following keyword parameters are used by the base-class:
|label||string||The label for the item (if any)||always the first parameter, so the keyword can be omitted; labels which are not already |
|r||Request||The request object||if passed, then the item inherits |
|a||string||The application name in the target URL||inherited from parent item|
|c||string||The controller name in the target URL||inherited from parent item|
|f||string||The function name in the target URL||inherited from parent item|
|args||list of strings, or string||the arguments in the target URL||if passed as single string, the arguments must be separated by slashes|
|vars||dict of strings||the query variables in the target URL|
|extension||string||the URL extension (data format extension) in the target URL||defaults to |
|p||string||the permission required to access this item||defaults to m|
|m||string||the URL method for the request||defaults to "", will be appended to |
|t||string||the name of the table the permission is required for||defaults to |
|tags||list of strings||a list of tags for this item||tags can later be used to address this item in the menu tree, e.g. to update flags|
|parent||the parent item||set the parent item explicitly||special purpose, defaults to |
|translate||boolean||False will prevent automatic localization of the item label|
|layout||function||use this function to render this item instead of the layout of the class|
|check||boolean, function or mixed list of these types||conditions to check before rendering||functions will be called with the item as parameter and are expected to return a boolean|
|restrict||list of role IDs or UIDs||restrict access to this item to these roles|
|link||boolean||whether to link this item to the specified target URL or not||defaults to |
|mandatory||boolean||override active check - item is always active||not implemented yet|
All other keyword parameters will be stored in the item instance as they are and get passed on to the
layout method. Keywords starting with an "_" underscore will be stored in the
item.attributes dict, all other keywords in the
item.options dict. It is up to the layout method to deal with those keyword parameters then.
During the status check cascade, each navigation item receives a set of status flags which then are available to the layout method. It is up to the layout method whether and how each combination of flags influences the rendering of the item.
|item.enabled||The item shall be rendered as enabled (accessible)||renderers would usually skip items with enabled=False, but could also render them greyed-out or otherwise visible but inaccessible; this flag will be altered by the return value of the check-hooks, and can be overridden by the check_enabled method of the class|
|item.selected||The target URL of the item or any of its sub-items matches the current request||this can be used for menu highlighting; if more than one subtree can be matched, only items in the first matching subtree will be marked selected|
|item.authorized||The user is permitted to access the target URL of this item||renderers would usually skip items the user is not permitted to access, but could also render the item greyed-out or otherwise visible but inaccessible|
|item.visible||Custom flag to show/hide items||will always be True unless explicitly changed by a check-hook method|
Status Check Cascade
All S3Navigation items are run through a cascade of status checks before they get handed over to the layout method.
The default behavior of these methods is meant for menu items, which may though not fit for all types of navigation items. Where needed, the subclass should overwrite them accordingly. These methods won't take any parameter beyond
self and are expected to return a boolean value. The methods are called in the order they appear in the following table:
|Method||Meaning||Effect||Flag set||Standard Behavior|
|check_active||Check whether the item is relevant for the current request||if this returns False, the item will be deactivated and no further checks nor the renderer ever be invoked (abort)||check_active returns False if a target controller is defined, but disabled in deployment settings, or if neither the item nor any of the items in the same subtree anyhow matches the request|
|check_permission||Check whether the user is permitted to access the target URL of the item||sets flag||authorized||returns True if an auth.accessible_url can be created from the target URL|
|check_selected||Check whether the item matches the current request||sets flag upward in the whole subtree||selected||returns True if this item or any of its children, out of all items in the tree, reaches the highest match-level for the current request|
|check_hook||Runs the check-hook methods defined for this item||if this returns False, neither check_enabled nor the renderer will be run||returns True only if all check-hooks return True, otherwise False|
|check_enabled||Check whether the item is enabled||Overrides the enabled flag if (and only if) it returns False, if it returns True, the flag remains unchanged||enabled||by default, check_enabled returns always True|
Invoking the Renderer
To render a navigation element (i.e. to run the layout method), just put it into the view like:
This will call the layout method of the element, provided that the element is active (i.e. relevant for the current request).