/*  Dynamically generates a nested UL navigation list from  an XML file. Adds CSS class names to the LI elements.  leafes get the menu_leaf_class  open nodes get the menu_open_class  closed nodes get the menu_closed_class  the current node gets the menu_active_class*///configvar menu_active_class = "active";var menu_leaf_class = "leaf";var menu_open_class = "open";var menu_closed_class = "closed";//the default page that is displayed if URL ends in /var menu_default_page = "../index.htm";//statevar menu_current; // XML menu node of the current locationvar menu_totop;   // path to top folder from current location// main function// navfile : the URL to the navigation XML// menu_id : id of the element into which to insert the navigationfunction menu_main(navfile, menu_id) {  var xml = menu_loadXml(navfile);  if (!xml) return;  menu_create(xml, menu_id);}  // navfile : the URL to the navigation XMLfunction menu_loadXml(navfile) {    var xmlHttp = false;    // Mozilla, Opera, Safari, IE7    if (typeof XMLHttpRequest != 'undefined') {        xmlHttp = new XMLHttpRequest();    }    if (!xmlHttp) {        // before IE 6        try {            xmlHttp  = new ActiveXObject("Msxml2.XMLHTTP");        } catch(e) {            try {                xmlHttp  = new ActiveXObject("Microsoft.XMLHTTP");            } catch(e) {                xmlHttp  = false;            }        }    }    if (!xmlHttp) {      alert("Sorry, your browser does not support AJAX!");      return false;    }    xmlHttp.open("GET", navfile, false);    xmlHttp.send(null);    if ((xmlHttp.status>=200) && (xmlHttp.status < 400)) {      return xmlHttp.responseXML.getElementsByTagName("navigation")[0];    } else {      alert("AJAX error: "+ xmlHttp.status +" "+ xmlHttp.statusText);      return false;    }}// xml : the XML root node of the navigation XML// menu_id : id of the element into which to insert the navigationfunction menu_create(xml, menu_id) {     var url = location.href;     if (url.lastIndexOf("/") == (url.length-1)) {       url = url+menu_default_page;     }     if (url.lastIndexOf("?") >= 0) {       url = url.substring(0, url.lastIndexOf("?"));     }     if (url.lastIndexOf("#") >= 0) {       url = url.substring(0, url.lastIndexOf("#"));     }     menu_current = menu_getCurrentMenu(xml, url);     menu_totop = menu_getPathToTop(menu_current);          var main = document.getElementById(menu_id);     if (!main) {       alert("No element with id '"+ menu_id +"' found");       return;     }          var root = document.createElement("ul");     menu_traverse(xml, root);     main.appendChild(root);}/* Walks down the subtree and on the way back   sets properties.   element : the parent XML node   root    : the DOM node of the enclosing UL   returns bit set           1: set = element is a node, unset = element is a leaf           2: set = element contains the active node*/ function menu_traverse(element, root) {  var props = 0;  var ihavechildren = false;  var icontainactive = false; for (var i=0; i<element.childNodes.length; i++) {    var child = element.childNodes[i];    if (child.nodeType != 1) continue;    if (child.nodeName != "menu") continue;    ihavechildren = true;    // create DOM    var li = document.createElement("li");    li.className = "";    var a = document.createElement("a");    var url = child.getAttribute("url");    if (!url) {      var submenus = child.getElementsByTagName("menu");      for (var j=0; j < submenus.length; j++) {        url = submenus[j].getAttribute("url");        if (url) break;      }    }    if (!url) url="#"; // we are desperate now    var iamactive = (child == menu_current);    if (iamactive) {      li.className = menu_active_class;      icontainactive = true;    }      a.setAttribute("href", menu_totop + url);    var text = document.createTextNode(child.getAttribute("title"));    a.appendChild(text);    li.appendChild(a);    root.appendChild(li);    // recurse    var ul = document.createElement("ul");    var subprops = menu_traverse(child, ul); // aggregate bits        if (subprops & 1) {      li.className += " "+ (iamactive || (subprops & 2) ? menu_open_class : menu_closed_class);      li.appendChild(ul);    } else {      li.className += " "+menu_leaf_class;    }    props |= subprops;  }  if (ihavechildren) props |= 1;  if (icontainactive) props |= 2;  return props;}function menu_getPathToTop(menu) {  var path = "";  if (menu == null) return path;  var url = menu.getAttribute("url");  var a = url.split(/[\/]/);  if (a.length == 1) return path;  for (var i=0; i < a.length - 1; i++) {    path += "../";  }  return path;}// determines the current location in the nav tree.// its the longest URL that matches the location.// xml : the XML root node of the navigation XML// loc : the current URL locationfunction menu_getCurrentMenu(xml, loc) {  var current = null;  var maxlen = 0;  var menus = xml.getElementsByTagName("menu");  for (var i=0; i < menus.length; i++) {    var menu = menus[i];    var url = menu.getAttribute("url");    if (!url) continue;    if (url.length < maxlen) continue;        if (!menu_isSameUrl(loc, url)) continue;    current = menu;    maxlen = url.length;  }  return current;}//matches two URIs when href is the last part of url//.. and . are correctly resolvedfunction menu_isSameUrl(url, href) {  var a = url.split(/[?\/]/i);  var b = href.split(/[?\/]/i);  var i = a.length - 1;  var j = b.length - 1;  while ((i >= 0) && (j >= 0)) {    if (b[j] == "..") { j-=2; continue; }    if (a[i] == "..") { i-=2; continue; }    if ((b[j] == ".") || (b[j] == "")) { j--; continue; }    if ((a[i] == ".") || (a[i] == "")) { i--; continue; }    if (! (a[i] == b[j])) return false;    i--;    j--;  }  return true;}