.. index:: z3c.menu, menu, viewlets Navigation Menus with z3c.menu and Viewlets ******************************************* 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. Setting up a Viewlet Manager ============================ 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: .. code-block:: python 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: .. code-block:: xml 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. .. code-block:: xml
Navigation Menu
Adding Viewlets =============== 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: .. code-block:: xml 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: .. image:: images/menuScreenShot.png