At this point, it is pretty difficult to navigate between pages in our application. It would be really nice to have a set of links that appear on each page for navigating between the front page and the contact add form. We can’t just put hard links into the layout template because we don’t know what url the server will be running under, and the relative paths change depending on which page you are looking at. Thus we need something like z3c.menu.
z3c.menu is a very minimal package providing just a few helper classes for making menus. The real power comes from a zope core package, zope.viewlet. Here is the idea. Instead of working with the old zope menus, which are rather inflexible, we want to use viewlets to more easily define how and when menu items are displayed. Our navigation menu will be a viewlet manager, and each link in the menu will be a viewlet. In case you have not worked with viewlets before, I’ll try to explain what they are all about.
What is a viewlet manager? In one sense, a viewlet manager is meant to represent a certain region of a web page where you want to contain any number of dynamicly generated pieces of content. One easy example is the region on most blogs that contains a picture of the blogger, a short description of the blog, a list of recent posts, a small calendar and maybe a set of tags. In Zope terms, we would consider each one of these pieces of content as a viewlet (think miniature view), which are all collected together in a viewlet manager.
Getting to the point, let’s create a viewlet manager. Start by opening up src/zcontact/skin.py and adding the following code:
from zope.viewlet.interfaces import IViewletManager from zope.viewlet.manager import WeightOrderedViewletManager class INavigationMenu(IViewletManager): """Navigation Menu Viewlet Manager.""" class NavigationMenu(WeightOrderedViewletManager): zope.interface.implements(INavigationMenu)
When you create viewlets, they are registered to a particular viewlet manager according to an interface. Thus we start by creating our own interface called INavigationMenu just for the navigation menu, which inherits from IViewletManager (lines 4-5). Next we create an implementation of the INavigationMenu interface (lines 7-8). The WeightOrderedViewletManager class can sort viewlets according to a given weight, which could come in handy for a navigation menu.
Next we want to register our ViewletManager instance in zcml, so that it can be rendered from a page template. Open up src/zcontact/skin.zcml and add the following registration:
<browser:viewletManager name="INavigationMenu" provides="zcontact.skin.INavigationMenu" class="zcontact.skin.NavigationMenu" layer="zcontact.layer.IZContactBrowserLayer" permission="zope.Public" />
You’ll need to add xmlns:browser="http://namespaces.zope.org/browser" to the configure tab for the browser namespace.
Now we have a viewlet manager which represents the region where our navigation links will go. But we still have to render the viewlet manager in our skin by editing src/zcontact/layout.pt. You can put the following snippet anywhere in the template where you would like the menu to appear. I chose to put it right under the “ZContact” header.
<div tal:content="structure provider:INavigationMenu">Navigation Menu</div>
Now that we have our navigation menu viewlet manager set up, we need to add some viewlets (menu items). All we have to do for viewlets is some zcml registration in the same place where we registered the pagelets that our navigation menu links will point to. So open up zcontact/browser/configure.zcml and add the following two zcml configurations:
<viewlet name="Add Contact" viewURL="@@addContact.html" for="*" manager="zcontact.skin.INavigationMenu" class="z3c.menu.simple.menu.GlobalMenuItem" permission="zope.Public" layer="zcontact.layer.IZContactBrowserLayer" weight="2" /> <viewlet name="Contact List" viewURL="@@index.html" for="*" manager="zcontact.skin.INavigationMenu" class="z3c.menu.simple.menu.GlobalMenuItem" permission="zope.Public" layer="zcontact.layer.IZContactBrowserLayer" weight="1" />
The name attribute specifies what the link will say and the viewURL specifies the relative url from the site root to the view in question. Then we set the manager to the INavigationMenu interface we created in the previous section. Finally, we see our first bit of z3c.menu by using the GlobalMenuItem class for the viewlet. This class figures out what the base url should be and attaches the viewURL attribute to the end.
With that finished, you can restart your server and checkout a slick new navigation menu that works flawlessly on every page of your application.
As always, here is a screen shot:
Enter search terms or a module, class or function name.