﻿// The Generic Menu Object

var menu = {
    xml : '',
    location : [],
    // loads the xml document specified by 'source'. The XML file should be in the webroot
    // this function also sets the current location (the page the user is on) so that the slide menu can know which place to start from.
    load : function(source) {
        this.getLocation();

        var req = false;
        // branch for native XMLHttpRequest object
        if(window.XMLHttpRequest && !(window.ActiveXObject)) {
    	    try {
			    req = new XMLHttpRequest();
            } catch(e) {
			    req = false;
            }
        // branch for IE/Windows ActiveX version
        } else if(window.ActiveXObject) {
       	    try {
        	    req = new ActiveXObject("Msxml2.XMLHTTP");
      	    } catch(e) {
        	    try {
          		    req = new ActiveXObject("Microsoft.XMLHTTP");
        	    } catch(e){ 
          		    req = false;
        	    }
		    }
        }
	    if(req) {
		    // false prevents async processing
	        req.open("GET", source, true);
	        
	        // assign a function to the statechange event handler
	        req.onreadystatechange = function () {
	            // if the state is complete, and the status is OK, assign the response to the xml var.
		        if (req.readyState == 4 && req.status == 200) {
		            menu.xml = req.responseXML;
		            
		            if(menu.drop.load) {
		                menu.drop.render();
		            }
		            if(menu.slide.load) {
		                menu.slide.render();
		                menu.slide.setStartMenu();
		            }
                }
		    }
	        req.send("");
	    }
    },
    getLocation : function() {
        var url = window.location
        var pat = new RegExp("^(.*:\/\/[^/]*)(/[^?#]*)(.*)$");
        var results = pat.exec(url);
        this.location = results;
    },
    
    
    
    
    
    
    
    
    
    
    // The Slide Menu Object
    slide : {
        // load:        whether or not to display this menu, default is false, change this value from the page
        // steps:       higher values = smoother slide
        // speed:       the lower the number, the faster it will be
        // distance:    shift distance
        // currentMenu: the root level menu id
        load : false,
        
        steps : 5,
        speed : 10,
        distance : 200,
        rootTitle : '<span style="font-style: italic;">my<span style="color: #AF1007;">Sabre</span></span>',
        
        disp : 0,
        location : 'root',
        startMenu : '',
        html : '',
        
        weirdOffset : 75,
        
        render : function() {
            this.location = menu.location[2];
            this.html += '<div id="slideTitle">'+this.rootTitle+'</div>\n';
            this.html += '<a id="slideBack" onclick="menu.slide.close();">Back</a>\n';
            this.html += '<div id="slideMenu">\n';
            
            this.html += '<div id="slide:root" style="display: block;">\n';
            if (menu.xml.documentElement != null) {
                this.traverse(menu.xml.documentElement);
            }
            this.html += '</div>\n';
            this.html += '</div>\n';
            
            var s = document.getElementById('slide');
		    s.innerHTML = this.html;
		    
		    s.style.height = (document.getElementById('slide:root').offsetHeight + this.weirdOffset) + "px";
        },
        traverse : function(tree) {
            if(tree.hasChildNodes()) {
                if (tree.nodeName == 'category') {
                
                    id = tree.getAttribute('id');
                    url = tree.getAttribute('href');
                    target = tree.getAttribute('target');

                    if (url != null && url != '') {
                        // if the url is this one, we want to have this menu load instead of the root level menu
                        // NOTE: This is ONLY for categories, because for categories we want to display their children,
                        //       For any other items (whether found, or not found) we want to display the parent's children.
                        if (url.toUpperCase() == this.location.toUpperCase()) {
                            //this.setStartMenu(id);
                            this.startMenu = "slide:" + id;
                        }
                        
                        // if there is a url for the category give the <a> an href property
                        url = 'href="' + url + '"';
                    } else {
                        url = '';
                    }
                    if (target == null || target == '') {
                        target = '_self';
                    }
                    this.html += '<a '+url+' target="'+target+'" class="parent" onclick="menu.slide.open(\'slide:'+id+'\');">'+id+'</a>\n';
                    this.html += '<div id="slide:'+id+'">\n';
                }
                for(var i=0; i<tree.childNodes.length; i++)
                {
                    this.traverse(tree.childNodes[i]);
                }
                
                if (tree.nodeName == 'category') {
                    this.html += '</div>\n\n';
                } else if (tree.nodeName != 'menu') {
                    if (tree.childNodes[0].nodeValue != null) {
                        url = tree.getAttribute('href');
                        hidden = tree.getAttribute('hidden');
                        target = tree.getAttribute('target');
                        if (target == null || target == '') {
                            target = '_self';
                        }
                        if(hidden == false || hidden == null) {
                            this.html += '<a href="'+url+'" target="'+target+'">'+tree.childNodes[0].nodeValue+'</a>\n';
                        }
                        
                        if (url.toUpperCase() == this.location.toUpperCase()) {
                            // if the url of this item is the same as this location
                            // we want to display the parent menu it is in
                            // NOTE: this differs from the category method, since the
                            //      category display its own menu, and not its parent menu
                            //this.setStartMenu(tree.parentNode.getAttribute('id'));
                            this.startMenu = "slide:" + tree.parentNode.getAttribute('id');
                        }
                    }
                }
            }
        },
        open : function(openid, sender) {
            this.topic(openid);
            var openMenu = document.getElementById(openid);
            var rootMenu = document.getElementById('slide:root');
            
            

            //document.getElementById('title').firstChild.data = openid;
            
            
            openMenu.style.display = "block";
            
            
            
            rootMenu.stepsLeft = this.steps;
            if (!rootMenu.style.left) {
                rootMenu.style.left = "0px";
            }
            openMenu.style.left = this.distance + "px";
            openMenu.style.top = "0px";

            
            // this makes sure that the menu is the right size
            document.getElementById('slide').style.height = (openMenu.offsetHeight + this.weirdOffset) + "px";

            // make this negative since we're moving to the left
            this.disp = Math.round(this.distance / this.steps) * -1;

            this.oldMenu = this.currentMenu
            this.currentMenu = openMenu;
            this.move();
        },
        close : function() {
            if (this.currentMenu && this.currentMenu.id != 'slide:root') {
                rootMenu = document.getElementById('slide:root');
                rootMenu.stepsLeft = this.steps;
                this.disp = Math.round(this.distance / this.steps);

                var parent = this.currentMenu.parentNode;
                parent.style.display = "block";


                // this makes sure that the menu is the right size
                document.getElementById('slide').style.height = (parent.offsetHeight + this.weirdOffset)+ "px";

                this.oldMenu = this.currentMenu;
                this.currentMenu = parent;
                this.move();
                
                // hide the old menu, so any new submenus don't show up over it, do this AFTER the menu is done sliding (hence the timeout)
                setTimeout('menu.slide.oldMenu.style.display = "none";', this.speed*this.steps);
                this.topic(this.currentMenu.id);
             }
        },
        setStartMenu : function(id) {
            if (this.startMenu != '' && this.startMenu != null) {
                var m = document.getElementById(this.startMenu);
                var r = document.getElementById("slide:root");
                var offset = 0;
                this.currentMenu = m;
                
                while (m.id != "slide:root") {
                    m.style.display = 'block';
                    m.style.left = "200px";
                    m.style.top = "0px";
                    offset = offset - this.distance;
                    r.style.left = offset + "px";
                    m = m.parentNode;
                }
                this.topic(this.currentMenu.id);
                
                // this makes sure that the menu is the right size
                document.getElementById('slide').style.height = (this.currentMenu.offsetHeight + this.weirdOffset) + "px";
            }
        },
        move : function() {
            var m = document.getElementById('slide:root');
            
            if (m.stepsLeft > 0) {
                m.style.left = parseInt(m.style.left) + this.disp + "px";
                m.stepsLeft--;
                setTimeout("menu.slide.move('"+id+"')", this.speed);
            }
        },
        topic : function(id) {
            var topic = document.getElementById('slideTitle');
            if (id == 'slide:root') {
                topic.innerHTML = this.rootTitle;
            } else {
                topic.innerHTML = id.substring(6);
            }
        }
    },
    
    
    
    
    drop : {
        // load:        whether or not to display this menu, default is false, change this value from the page
        load : false,
        html : '',
        
        render : function() {        
            if (menu.xml.documentElement != null) {
                this.traverse(menu.xml.documentElement);
            }
            var d = document.getElementById('drop');
		    d.innerHTML = this.html;

		    this.stuHover();
        },
        getOffset : function(obj){
            var curleft = 0;
            var wrapper = document.getElementById('drop');
            
            // offsetParent in IE6 doesn't work right, this is why we do parentNode until we hit the wrapper.
            while (obj != wrapper) {
                if (obj.offsetLeft != -9999) {
                    curleft += obj.offsetLeft;
                    
                }
                obj = obj.parentNode;
            }

            return curleft;
        },
        getWindowWidth : function () {
        // NOTE: Since this is the only place where it is easy to differentiate between which browser is doing the rendering,
        //       I fake the window width here so that the comparison between this and the offset of the element is more accurate.
            var myWidth = 0;
            if( typeof( window.innerWidth ) == 'number' ) {
                //Non-IE
                myWidth = window.innerWidth - 100;
            } else if( document.documentElement && document.documentElement.clientWidth ) {
                //IE 6+ in 'standards compliant mode'
                myWidth = document.documentElement.clientWidth -100 ;
            } else if( document.body && document.body.clientWidth ) {
                //IE 4 compatible
                myWidth = document.body.clientWidth;
          }
          
          // Little cheat to make sure that if the window is smaller than the actual minimum width of the menu we use the the greater value
          // Essentially this prevents awkward behavior when someone is running a window smaller than the minimum width of the design.
          if (myWidth < document.getElementById('drop').offsetWidth) {
                myWidth = document.getElementById('drop').offsetWidth;
          }
          return myWidth;
        },
        
        open : function(sender) {
            var sub = sender.childNodes[2];
            sub.style.left = "120px";
            
            // the number we add to the sender offset is from trial and error... javascript is NOT a precise science
            if ((this.getOffset(sender)+340) > this.getWindowWidth()) {
                sub.style.left = "-143px";
            }

            //IE 6 and below fix for no hover
            sender.className+=" iehover";
        },
        openTop : function(sender) {
            var sub = sender.childNodes[2];
            sub.style.left = "0px";
            
            if ((this.getOffset(sender) + 175) > this.getWindowWidth()) {
                sub.style.left = "-85px";
            }
            
            //IE 6 and below fix for no hover
            sender.className+=" iehover";
        },
        
        close : function(sender) {
            //IE 6 and below fix for no hover
            sender.className=sender.className.replace(new RegExp(" iehover\\b"), "");
        },
        
        traverse : function(tree) {
            // Get all categories
            if (tree.nodeName == 'category') {
                id = tree.getAttribute('id');
                url = tree.getAttribute('href');
                target = tree.getAttribute('target');
                if (url != null && url != '') {
                    url = 'href="' + url + '"';
                } else {
                    url = '';
                }
                if (target == null || target == '') {
                    target = '_self';
                }
                // if it is a root level category, give it a css class of "top",
                // and give the subsequent ul a class of "sub"
                if (tree.parentNode.nodeName == 'menu') {
                    if (tree.hasChildNodes()) {
			this.html += '\n<li class="top" onmouseover="menu.drop.openTop(this)" onmouseout="menu.drop.close(this)"><a '+url+' target="'+target+'" class="top_link">'+id+'</a>\n';
                        this.html += '<ul class="sub">\n';
                    } else {
			this.html += '\n<li class="top"><a '+url+' target="'+target+'" class="top_link">'+id+'</a>\n';
		    }
                } else {
                    this.html += '<li onmouseover="menu.drop.open(this)" onmouseout="menu.drop.close(this)"><a '+url+' target="'+target+'" class="fly">'+ id +'</a>\n';
                    this.html += '<ul>\n';
                }
            }
            if(tree.hasChildNodes()) {
                // Repeat this function for all the children
                for(var i=0; i<tree.childNodes.length; i++)
                {
                    this.traverse(tree.childNodes[i]);
                }
            }

            // once the children are parsed, we can close the category, or output a link
            if (tree.nodeName == 'category') {
                this.html += '</ul>\n</li>\n';
            } else if (tree.nodeName != 'menu') {
                if (tree.hasChildNodes()) {
                    if (tree.childNodes[0].nodeValue != null) {
                        hidden = tree.getAttribute('hidden');
                        target = tree.getAttribute('target');
                        if (target == null || target == '') {
                            target = '_self';
                        }
                        if (hidden == false || hidden == null){
                            this.html += '<li><a href="' + tree.getAttribute('href') + '" target="'+target+'">' + tree.childNodes[0].nodeValue + '</a></li>\n';
                        }
                    }
                }
            }
        },
        /* ================================================================ 
        This copyright notice must be kept untouched in the stylesheet at 
        all times.

        The original version of this script and the associated (x)html
        is available at http://www.stunicholls.com/menu/pro_drop_1.html
        Copyright (c) 2005-2007 Stu Nicholls. All rights reserved.
        This script and the associated (x)html may be modified in any 
        way to fit your requirements.
        =================================================================== */
        stuHover : function() {
	        var cssRule;
	        var newSelector;
	        if (document.styleSheets[0].rules) {
	            for (var i = 0; i < document.styleSheets.length; i++) {
		            for (var x = 0; x < document.styleSheets[i].rules.length ; x++) {
			            cssRule = document.styleSheets[i].rules[x];
			            if (cssRule.selectorText.indexOf("LI:hover") != -1)
			            {
				            newSelector = cssRule.selectorText.replace(/LI:hover/gi, "LI.iehover");
				            document.styleSheets[i].addRule(newSelector , cssRule.style.cssText);
			            }
		            }
		        }
		    }
        }
    }
};
