Monday, February 7, 2011

Create a Dynamic Menu in HTML

Recently I was asked by a co worker to assist in creating a navigation menu for a web site.  The requirement was that it needed to be able to read from an XML file (specifically a sitemap file from Visual Studio).  You may be wondering why we did not use the menu object within Visual Studio.  Visual Studio has a lot of useful objects for creating fast and robust web pages though there are times where it is better to use other methodologies.  One of those is when it comes to speed and simplicity.  Using the menu object can at times slow down the rendering of a page and the transitions can at times be slow.  There is a lot of over-head involved and if all of those features are not needed it is better to just use HTML, javascript and CSS.

Since I am not one for recreating the wheel, I looked into my “bag of tricks” and found a link to a solution that I came across previously that could help to fulfill this need, or at least partially with some modifications.  There is a great article provided by “Dynamic Drive” for a “Smooth Navigation Menu.”  This a very good set of code that is very flexible in allowing a person to present a menu in a lot of different ways.  I am not going to go into all the code that is used to create this solution, just the options that are there to configure it.  This is a very light weight and fast solution.  Now you may be thinking if this article is so good then why continue reading this one.  And the reason is that I added some enhancements to this.  The solution does not have the ability to read in an XML file.  It is based upon the use of a prebuilt un-order list html block.

First off, I changed some of the names in the solution to better fit our naming conventions (smoothddmenu to dynamicmenu in the js file and the name of the div to menu-ajax).  If you are not strong in javascript then I do not recommend doing this, though if you are like me and want to have all naming conventions through out your environment to be consistent and are comfortable with javascript then have at it.

After cleaning up some of the names in the file it was time to add some new functions to the script file to handle the xml reading and parsing.  At the end of the script file add the variable below to define the xml activeobject object.
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
Next we need to create a function that will return the readystate for the xmldoc read.
function verify() {
        if(xmlDoc.readyState!=4)
                return false;
}
This will provide the libraries needed to work with a XML file.  Next you will need a function to load a XML file using a file name into the variable.  This function makes sure that async is turned off, sets the readystatechange value to verify and then loads the file with the path provided in the function call.
function loadXML(xmlFile) {
        xmlDoc.async="false";
        xmlDoc.onreadystatechange=verify;
        xmlDoc.load(xmlFile);
}
Next we need to create the function that will parse the XML document.  The smooth menu needs an un-ordered list HTML block so we need to take the XML document and render it as an un-ordered HTML block.  Also there are three key attributes in the xml elements that we will be using, url, title and description.  These will be put into “a” HTML tag within the “li” elements in the un-ordered HTML block.  The url element value will be used as the href, the title will be used as the value displayed and the description will be the title (html not XML – used as a hover over description for the item) attributes for the tags.  I am going to use a VC style sitemap file for a source though it is not important what you use to make the file or ever what the names of the tags are as long as the elements are the same.
function readXML(xdoc) {
        if(xdoc.hasChildNodes()) {
        if(xdoc.getAttribute("title") != null)
        {
                    document.write("<li>");
                    document.write("<a href='");
            document.write(xdoc.getAttribute("url"));
                    document.write("' title='");
            document.write(xdoc.getAttribute("description"));
            document.write("' >");
                    document.write(xdoc.getAttribute("title"));
                    document.write("</a>");
        }
            document.write("<ul>");
                var nodes=xdoc.childNodes.length;
                for(var i=0; i<xdoc.childNodes.length; i++)
        {
                        readXML(xdoc.childNodes(i));
        }
            document.write("</ul>");
        if(xdoc.getAttribute("title") != null)
        {
                    document.write("</li>");
        }
        }
        else
    {
        if(xdoc.getAttribute("title") != null)
        {
                    document.write("<li>");
                    document.write("<a href='");
            document.write(xdoc.getAttribute("url"));
                    document.write("' title='");
            document.write(xdoc.getAttribute("description"));
            document.write("' >");
                    document.write(xdoc.getAttribute("title"));
                    document.write("</a>");
                    document.write("</li>");
        }
    }
}
Lastly, we need a function that will initialize the functions we just created that the HTML document can call and pass the file name.  This will pass the file name, call the function to load that file to the variable, and then pass a XMLDocumentElement to the parsing function.
function initXML(file) {
        loadXML(file);
        var xdoc=xmlDoc.documentElement;
        readXML(xdoc);
}
Now that the additions to the js script have been added it is time to create the HTML file for your web page.  First you need to add your document type declaration (this is not required though it is best practice and helps browsers to more easily render your page which will increase speed to load the page).  Then create the “HEAD” tags with the links to the CSS and java script files.  If you read the smooth menu article there are three files to download and it would be good to download a copy of the jquery script.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd%22>
<html xmlns="http://www.w3.org/1999/xhtml%22 lang="en" xml:lang="en">
<head>
<title>menu sample</title>
<link rel="stylesheet" type="text/css" href="menu.css" />
<link rel="stylesheet" type="text/css" href="menu-v.css" />
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="menu.js">
</head>
<body>
</body>
</html>
As you can see from the below code there is not much to this page so far, in fact you will not see anything.  Next we need to create the XML file so that we have something to parse.  I created a file called SiteMap.xml which has the following in it.  This file is stored in the same folder at the HTML that I will render it on.
<?xml version="1.0" encoding="utf-8"?>
<siteMap>
  <siteMapNode url="#" title="Home" description="" />
  <siteMapNode url="#" title="Links" description="">
    <siteMapNode url="http://www.dynamicdrive.com/dynamicindex1/ddsmoothmenu.htm%22 title="Dynamic Drive" description="" />
    <siteMapNode url="http://w3schools.com%22/ title="w3schools" description="" />
  </siteMapNode>
  <siteMapNode url="#" title="List 1" description="">
    <siteMapNode url="#" title="List Item 1" description="" />
    <siteMapNode url="#" title="List Item 2" description="" />
    <siteMapNode url="#" title="List 2" description="" >
       <siteMapNode url="#" title="List Item 3" description="" />
       <siteMapNode url="#" title="List Item 4" description="" />
       <siteMapNode url="#" title="List Item 5" description="" />
       <siteMapNode url="#" title="List Item 6" description="" />
    </siteMapNode>
  </siteMapNode>
</siteMap>
Back to our HTML file, between the “BODY” tags you will need to add a division block (identified by “DIV” tags).  Within the division you will need a script block that will call the initXML function and pass the name of the sitemap.xml file.
<div id="menu-ajax">
<script language="JavaScript">
    initXML("SiteMap.xml");
</script>
<noscript>
<a href="link to site map for search engines and user with JS disabled">Site map</a>
</noscript>
</div>
If you were to run the HTML file now it will not have the menu but will display an un-order list HTML block (see below).
image
We now need to add a script block in the “HEAD” block that will change our un-ordered list to the menu object that we want.  Within the smooth menu code there is a variable called ddsmoothmenu (if you made changes like I did then you may need to change some of these values).  The variable has a function called “init” which is what we want to call.  We are also passing some values to the function that would control the behavior of how this is displayed.  I will not go into all the parameters and what they mean.  The descriptions should be sufficient enough.
<script type="text/javascript">
smoothmenu.init({
mainmenuid: "menu-ajax", //menu DIV id
orientation: 'h', //Horizontal or vertical menu: Set to "h" or "v"
classname: 'ddsmoothmenu', //class added to menu's outer DIV
contentsource: "markup" //"markup" or ["container_id", "path_to_menu_file"]
})
</script>
Once this has been added, if you run the HTML file it should look similar to the following.
image

No comments:

Post a Comment