Part 5: Custom Navigation in Lenya

26 February 05

OK, so you have the basics: you know how to install Lenya, you understand it's approach to content management, you understand the pipeline bit, and you know how to edit existing documents. Through playing around, you probably now know how to make new pages, and create the content hierarchy for your site. Now the question becomes, how do I customize the navigation to be marked up the way you want.

Customizing Lenya navigation items

In order to understand customizing navigation items in Lenya, you'll need to understand where that's possible. In the default publication's root directory, you'll see a directory called 'lenya'. It's here where you can add folders and files that override the global defaults set aside for all of Lenya.

One of the directories is 'navigation'. In there, you'll most likely see a file called tabs.xsl. This is a customized version of the tabs just for the default publication. But you can do others. Here's the list of the file names you can add in the 'navigation' folder that will override the global files:

breadcrumb.xsl The breadcrumb trails at the top of the page (e.g. Home > Products > Furniture)
menu.xsl The menu at the left of the pages (in the default publication, for example)
tabs.xsl The tabs at the top of the page (in the default publication, they are the highest levels of nav on the site)
search.xsl The search box on the site

There are others, but these will do for now. You can check out what the originals are in /usr/local/tomcat/webapps/lenya/lenya/xslt/navigation/. It requires some understanding XSLT, which is again beyond the scope of this article. W3Schools has a nice place to learn XSLT quickly.

We're going to take a look at the sitetree structure to find out what you're capable of knowing about an item in the navigation of the site, then do a quick example of how to create your own menu.

Understanding the site tree

The site tree is the place where all the "nodes", or pages in your publication are stored, preserving the hierarchy. The XML file can be found by going to the content/authoring/ directory in the default publication and viewing the sitetree.xml file. Let's take a look at a chunk:

<site>
<node id="index">
<label xml:lang="en">Home</label>
<label xml:lang="de">Home</label>
</node>

<node id="tutorial">
<label xml:lang="en">Tutorial</label>
<label xml:lang="de">Tutorial</label>

<node id="new_doctype">
<label xml:lang="en">Create new doctype</label>
</node>
</node>
</site>

The above tells us that each page is characterized by a <node> tag. Each <node> tag has an "id" attribute, which is the name of the document. So, if this publication's address were http://www.someplace.com/, then the ID for the second node would make the address to page http://www.someplace.com/tutorial.html.

Each node has an inner element called <label>. The label tag's contents are the navigation title for the page. It's the link to the page that you see in menu of the site. The xml:lang attribute signifies the language for this label, and as you can see, this site has multiple supported languages: "en" for English, and "de" for German.

Nodes can be inside other nodes. In the example above, the "new_doctype" node is inside the "tutorial" node. This means that the "tutorial" page is a parent of the "new_doctype" page, so they fall underneath each other like so:

1. Home
2. Tutorial
a. Create new doctype

Order is also important - the order of the nodes in the sitetree file is the order in which the pages are displayed in the hierarchy of the site.

The nav: namespace

An XML namespace was created for users to grab these nodes with the appropriate information. So, for example, you can reference a node in your XSL using nav:node. Once you reference the node, you can reference it's label too: nav:label. There's some other items you can reference when you are pointing at a specific node:

@href The location of the page relative to where you are currently in the site
@current A true or false value is possible to determine whether or not the page you are on is the node you are referencing
@visibleinnav Another true/false value given if the page had been labeled as visible in the navigation

Hiding navigation items can be helpful for situations like form submission/confirmation pages. You don't want the user to go to that page right away from within the site's menu, so you hide it, letting the programming of the form's input redirect the user to that page instead. Other examples abound.

Using your new-found knowledge

Let's try putting together a simple menu.xsl file that creates our own simple markup. The contents are below:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:nav="http://apache.org/cocoon/lenya/navigation/1.0"
xmlns="http://www.w3.org/1999/xhtml"
exclude-result-prefixes="nav">

<xsl:template match="nav:site">
<ul>

<!-- loop through all top-level items and return as list items -->
<xsl:for-each select="/*/nav:node[@visibleinnav = 'true']">
<xsl:when test="@current = 'true'">
<li class="current"><a href="{@href}"><xsl:apply-templates select="nav:label"/></a></li>
</xsl:when>
<xsl:otherwise>
<li><a href="{@href}"><xsl:apply-templates select="nav:label"/></a></li>
</xsl:otherwise>
</xsl:for-each>

</ul>
</xsl:template>

<xsl:template match="nav:label">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>

OK, so let's dissect this one. You always start with your XML prologue and stylesheet tags (notice how the root stylesheet tag references the nav namespace?). Then, one template is created to match the <site> tag - that's the root tag that wraps around all the <node> tags in our sitetree.xml file.

We open up the unordered list, and then we'll just loop through the top-level navigation items on the site. The '/*/nav:node' part of the for-each loop steps down into the site tag that you just matched (/*), and then through the nodes underneath the site tag (/nav:node). Note that this is only the top level nodes, not all the parents and children! Read up on XSLT and XPath to better understand how this notation works.

For each top-level item, we test to see that node happens to be the page we are looking at right now (@current = 'true'). If it is, then we open up our list tag and assign it the class of "current". Your CSS can then be created to give some special styling to that list item.

Once the list item is created, we need the link. The address for the link tag is gathered from our handy @href. The text for the link will be the label of the node. So, we call out another template shown at the bottom of our example menu.xsl file where it basically just grabs the value of the contents inside the <label> tags in the sitetree.xml file. We close the the link and the list items.

Of course, if this isn't the page we are on, then we do the same thing but don't add in our special class. Simple, no?

Give it a try

You now pretty much have the basics for putting together your own custom navigation. There are those that feel my methods for generating the menus are incorrect and that I should grab the nodes that I need in one fell swoop instead of looping through each one, but this was the only method I could find where I would achieve the coding standards I wanted. Go experiment and have fun!

Comments?

Keith - Mar 4, 4:19pm

Jon,

Great work so far! I’m preparing to test-drive Lenya, but have been intimidated by the learning curve and lack of basic documentation. These articles are a huge help.

Keep up the great work!

Jon Linczak - Mar 5, 11:04am

Thanks Keith, glad these articles are helping. Incidentally, at about the same time that I was putting up this article, one of the Lenya developers put together a similar Wiki doc on the subject. For those interested, you can view it here.

As far as I know, it’s a work in progress, so keep an eye on this space.

Amna & Kiran - Apr 12, 3:49am

Hi..
Thnx for all the help u’ve been providing to all of us interested-in/concerned-with Lenya. Ur a great help :)
Here’s our latest query
Can u tell us if there is a way of uploading a page to lenya publication other than the “File-> New Document” in the UI???

Sean Fulton - Apr 13, 11:56am

This is great. Your documentation is shades better than the official docs or wiki.

Jon Linczak - Apr 23, 6:44pm

Sean: Thanks for the kind words and glad it’s helped you out.

Amna & Kiran: Glad I could be of service! As far as your question on another way of uploading a page to Lenya, that’s a tough question. Do you mean, is there a way to take an existing document that you have and make it part of the publication? If so, I believe there is something that allows you to import HTML files, but I’ve not used it myself.

A tibit located here talks about using the One Form Editor if they are XML files, and using WebDAV for others, but it’s not very helpful. Here’s a document that has a linked Perl script that imports existing content, but I’ve never really used it before.

If you still can’t find what you need, feel free to post your question at the Lenya user’s mailing list. Hope this helps!

Amna & Kiran - Apr 25, 2:46am

Welllllll, thanx Jon.
Yup we mean that.
We’ve been trying that perl code but facing some difficulty..Figuring out how to put in the missing parameters__ if & when we succeed we’ll post the modified code… And yes, we put the question on Lenya user mailing list on 21st and still have fingers crossed for the reply… :)
Thanx a bunch

Richard - Apr 26, 10:17am

Jon,

Thanks for the great resource on Lenya. I wanted to point out a few things. Firefox doesn’t wrap the text in the code boxes, whereas Opera 8 does. And neither (I don’t use IE, so I didn’t check that) indent the example code, which makes it easier to read, of course. Maybe you want to use pre tags instead, but maybe not. :) It looks like you put spaces in the code, it just doesn’t indent.

Just some curiousities. Don’t know if you’d already seen this.

R

Richard - Apr 26, 10:55am

Let me clarify: I’m not being nitpicky. ;)

Jon Linczak - Apr 27, 8:38pm

Amna & Kiran: I’m sorry that I couldn’t give you a better response, and that stinks that you haven’t had a response to your questions about the Perl code. Hopefully someone will fess up. Please do post your experiences here should you come up with a solution.

Richard: By no means do I think you’re being nitpicky! :) Actually, I’ve always been annoyed with my site design, and how lazy I have been in the CSS and structure all-together. When you pour your heart into one site (Hiram’s in my case), I find it hard to use the extra time at the end of the day to come up with something amazing for your site. In the end, I just wanted to put up something so I had an avenue to get the word out on Lenya.

The goal is to hire someone to put together a knock-out design, which always motivates me to put together some good CSS, but when that will be is still up in the air. In the mean time, with a little “vacation” time coming up in mid-May, perhaps I can work on fixing up some of the issues you mentioned. Thanks again for reading the site!

Suresh - Oct 24, 1:30am

Hi jon,
I started working on Lenya for one of our Content Management System Project.I got an idea abt lenya by Going through the online help available.But iam getting confused in understanding the control flow in Xmaps,Xsls,Xsps(which are heavily present in the Lenya project).In my project i have to customize lenya according to the Project Requirements(Like i need a Login Page, etc ..),So for this i feel that understanding the control flow in the Xmaps ,XSL,Xsps,So could u please help me in
in understanding this.

Thanks in Advance
suresh

Jon Linczak - Nov 21, 1:33am

Hi Suresh, my sincerest apologies for taking so long to respond. My queue of things to do have grown so long and it is only now that I have an opportunity to get back to some Lenya items.

Control flow comes in two varieties, as far as I know. One is the usecase and the other is via XSP and/or CForms.

Usecases allow you to control the flow of Lenya itself. Like, what happens after you choose an item in the menu.

XSP is becoming a deprectated programming language as far as I understand, and is slowly being replaced with CForms. CForms gives you the opportunity to create your own administrative screens within Lenya to update databases, etc. I’ve never used CForms myself, so I can’t really help with personal experience.

For topics on usecases, XSP and CForms, you might want to visit the Lenya site. Here are some examples:

1. Lenya doc on usecases
2. Cocoon doc on XSP
3. Lots of Cocoon documentation on CForms

While I don’t know much about CForms, it appears the documentation has grown considerably and if you have questions, perhaps we can work them out together.

All the best on your web project!

sean - Apr 11, 6:48pm

Hi – Thanks for the great Lenya tips. Is it possible to modify this XSLT to generate nested list navigation? I’m new to XSL and not sure where to modify the control structure to loop through the second level nodes and output them as nested ul’s also.

Thanks

Jon Linczak - Apr 16, 11:01pm

Hi Sean – it certainly is possible to modify the above for nested navigation. Before you end the list tag, throw in another for-each tag that selects on the nav:node only (no /*/ blah. blah, blah) and that should loop through the nodes underneath the node you are currently on in the outer loop. You have to do it twice for each when tag, or just once on the current branch if you want to just output subnavigation for the current section the user is on. Hope this helps somewhat…

John - Jul 6, 8:18am

i think u r providing nothing special , u r just copying the material from lenya.apache.org and put it in ur website,
give us something special that lenya.apache.org does not contain

Jon Linczak - Jul 6, 5:05pm

Hey John, actually, much of the articles on the Lenya website were written right here on this site originally, and were later transferred to the main Lenya website as documentation. You can view the reference here and there is somewhere in the archived mailing list the email from Gregor asking the other developers if moving the articles to the site was ok with everyone. I even mentioned it on my website.

Sorry this wasn’t clearer.

John - Jul 7, 6:28am

Hi Ok i apolozige b-coz i had no idea abt it ,
so that was the only reaoson well its really very good job that u are doing ’ i’ll deffiinately appreciate you for this
Thank you
John

commenting closed for this article

in this site