Web Services Wiki
Welcome Guest: Login
The rendering of BethelMenus (edited by visiting the "template" tab of a container in the ZMI) is very flexible. Three ways have currently been developed to transform a BethelMenu to html (render the menu):
All are rendered as a lists with various additional attributes (id, class, style, etc). The names denote their original usages, but certainly these adapters can be used in other templates, in other ways as the design of the template requires. Or new adapters can be written easily.
A common way of implementing these is to embed this functionality directly within the model, or have some predefined helper class. The former method isn't ideal, as it is results in "code bloat" with presentation logic embedded in the model. The latter is much nicer, and Zope 3 has a nice mechanism called adapters to achieve this. Adapters are pluggable interfaces which provide additional functionality / apis for content objects. Content objects are "adapted to" an adapter interface, and the Zope 3 framework looks up the appropriate adapter for the adapter interface and content model.
BethelMenu renderers have been implemented using Zope 3 adapters. Adapters have an interface, and a implementing class for each content interface (e.g. ISilvaObject) that uses the adapter. The interfaces are defined in BethelTemplates.interfaces, the adapters are implemented in BethelTemplates.adapters.menu_renderers, and all are tied together in BethelTemplates/configure.zcml
ISidebarMenuRenderer
IHorizontalBarMenuRenderer
IContentMenuRenderer
Each of the three adapter implementations extends BaseMenuRenderer. All output unordered lists with additional markup. The base class includes defaults for the components of the list:
The generateMenu method of the base class calls the menu's generateMenu4 to generate a flat list of menu items. It returns a 2-tuple containing:
The render_items method takes the menu_list and renders it using the 5 default components listed above, and returns the html as a list of string-chunks. This renders just the list items, and not the root's <ul>, the implementing classes do that part.
Each adapter has a __call__ method which does the actual transforming of the menu into html.
Generates the menu, and outputs it within the following html:
<ul id="<<ul_id>>" class="adxm menu menu-htb"> <![[ output from BaseMenuRenderer.render_items ]]> </ul>
Generates the menu, and outputs it within the following html:
<ul class="adxm menu menu-vlr"> <![[ output from BaseMenuRenderer.render_items ]]> </ul>
NOTE: see this document to learn how content menus are used in the BU template.
Generates the menu by:
The menu is rendered and output within the following html:
<ul id="<<ul_id>>" class="adxm menu menu-<<direction>>"> <![[ output from BaseMenuRenderer.render_items ]]> </ul>
The calling template code will likely place this output within a div which can be used for styling the menu via css.
Each adapter is configured very similarly to the ISidebarMenuRenderer (just replace the names):
<adapter for="Products.BethelTemplates.interfaces.IBethelMenu" provides=".interfaces.ISidebarMenuRenderer" factory=".adapters.menu_renderers.SidebarMenuRenderer" />
The adapters are difficult to call directly from template code, so the view class (BaseViewMixin) has helper functions to call and render the adapters. BaseViewMixin has the following methods: renderSidebarMenu, renderTopMenu, renderSubMenu which render the respective menus. These methods take the site_config object and the menu name/id (string) as parameters.
The view code for one of these looks like:
def renderContentMenu(self, site_config, menu, bar_id, direction):
menu = site_config.menus[menu]
return interfaces.ISubMenuRenderer(menu)(site_config.aq_parent.id, bar_id, direction)