CSS Navigation Menu - horizontal and keep submenu opened

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Nyris
    New Member
    • Nov 2008
    • 22

    CSS Navigation Menu - horizontal and keep submenu opened

    I have this code used for the navigation on an HTML page. It's an accordion style dropdown menu. Everything works fine I just need to change it so that the submenuheader class allows it to be a clickable link. Right now all that happens with for example Home has two submenus of About Us and Quality. When you click home it expands the dropdown. But I want it to expand and also direct to a Home page. thanks in advance!


    Code:
    var ddaccordion={
    	
    	contentclassname:{}, //object to store corresponding contentclass name based on headerclass
    
    	expandone:function(headerclass, selected){ //PUBLIC function to expand a particular header
    		this.toggleone(headerclass, selected, "expand")
    	},
    
    	collapseone:function(headerclass, selected){ //PUBLIC function to collapse a particular header
    		this.toggleone(headerclass, selected, "collapse")
    	},
    
    	expandall:function(headerclass){ //PUBLIC function to expand all headers based on their shared CSS classname
    		var $=jQuery
    		var $headers=$('.'+headerclass)
    		$('.'+this.contentclassname[headerclass]+':hidden').each(function(){
    			$headers.eq(parseInt($(this).attr('contentindex'))).trigger("evt_accordion")
    		})
    	},
    
    	collapseall:function(headerclass){ //PUBLIC function to collapse all headers based on their shared CSS classname
    		var $=jQuery
    		var $headers=$('.'+headerclass)
    		$('.'+this.contentclassname[headerclass]+':visible').each(function(){
    			$headers.eq(parseInt($(this).attr('contentindex'))).trigger("evt_accordion")
    		})
    	},
    
    	toggleone:function(headerclass, selected, optstate){ //PUBLIC function to expand/ collapse a particular header
    		var $=jQuery
    		var $targetHeader=$('.'+headerclass).eq(selected)
    		var $subcontent=$('.'+this.contentclassname[headerclass]).eq(selected)
    		if (typeof optstate=="undefined" || optstate=="expand" && $subcontent.is(":hidden") || optstate=="collapse" && $subcontent.is(":visible"))
    			$targetHeader.trigger("evt_accordion")
    	},
    
    	expandit:function($targetHeader, $targetContent, config, useractivated){
    		$targetContent.slideDown(config.animatespeed, function(){config.onopenclose($targetHeader.get(0), parseInt($targetHeader.attr('headerindex')), $targetContent.css('display'), useractivated)})
    		this.transformHeader($targetHeader, config, "expand")
    	},
    
    	collapseit:function($targetHeader, $targetContent, config, isuseractivated){
    		$targetContent.slideUp(config.animatespeed, function(){config.onopenclose($targetHeader.get(0), parseInt($targetHeader.attr('headerindex')), $targetContent.css('display'), isuseractivated)})
    		this.transformHeader($targetHeader, config, "collapse")
    	},
    
    	transformHeader:function($targetHeader, config, state){
    		$targetHeader.addClass((state=="expand")? config.cssclass.expand : config.cssclass.collapse) //alternate btw "expand" and "collapse" CSS classes
    		.removeClass((state=="expand")? config.cssclass.collapse : config.cssclass.expand)
    		if (config.htmlsetting.location=='src'){ //Change header image (assuming header is an image)?
    			$targetHeader=($targetHeader.is("img"))? $targetHeader : $targetHeader.find('img').eq(0) //Set target to either header itself, or first image within header
    			$targetHeader.attr('src', (state=="expand")? config.htmlsetting.expand : config.htmlsetting.collapse) //change header image
    		}
    		else if (config.htmlsetting.location=="prefix") //if change "prefix" HTML, locate dynamically added ".accordprefix" span tag and change it
    			$targetHeader.find('.accordprefix').html((state=="expand")? config.htmlsetting.expand : config.htmlsetting.collapse)
    		else if (config.htmlsetting.location=="suffix")
    			$targetHeader.find('.accordsuffix').html((state=="expand")? config.htmlsetting.expand : config.htmlsetting.collapse)
    	},
    
    	urlparamselect:function(headerclass){
    		var result=window.location.search.match(new RegExp(headerclass+"=((\\d+)(,(\\d+))*)", "i")) //check for "?headerclass=2,3,4" in URL
    		if (result!=null)
    			result=RegExp.$1.split(',')
    		return result //returns null, [index], or [index1,index2,etc], where index are the desired selected header indices
    	},
    
    	getCookie:function(Name){ 
    		var re=new RegExp(Name+"=[^;]+", "i") //construct RE to search for target name/value pair
    		if (document.cookie.match(re)) //if cookie found
    			return document.cookie.match(re)[0].split("=")[1] //return its value
    		return null
    	},
    
    	setCookie:function(name, value){
    		document.cookie = name + "=" + value + "; path=/"
    	},
    
    	init:function(config){
    	document.write('<style type="text/css">\n')
    	document.write('.'+config.contentclass+'{display: none}\n') //generate CSS to hide contents
    	document.write('<\/style>')
    	jQuery(document).ready(function($){
    		ddaccordion.urlparamselect(config.headerclass)
    		var persistedheaders=ddaccordion.getCookie(config.headerclass)
    		ddaccordion.contentclassname[config.headerclass]=config.contentclass //remember contentclass name based on headerclass
    		config.cssclass={collapse: config.toggleclass[0], expand: config.toggleclass[1]} //store expand and contract CSS classes as object properties
    		config.revealtype=/^(click)|(mouseover)$/i.test(config.revealtype)? config.revealtype.replace(/mouseover/i, "mouseenter") : "click"
    		config.htmlsetting={location: config.togglehtml[0], collapse: config.togglehtml[1], expand: config.togglehtml[2]} //store HTML settings as object properties
    		config.oninit=(typeof config.oninit=="undefined")? function(){} : config.oninit //attach custom "oninit" event handler
    		config.onopenclose=(typeof config.onopenclose=="undefined")? function(){} : config.onopenclose //attach custom "onopenclose" event handler
    		var lastexpanded={} //object to hold reference to last expanded header and content (jquery objects)
    		var expandedindices=ddaccordion.urlparamselect(config.headerclass) || ((config.persiststate && persistedheaders!=null)? persistedheaders : config.defaultexpanded)
    		if (typeof expandedindices=='string') //test for string value (exception is config.defaultexpanded, which is an array)
    			expandedindices=expandedindices.replace(/c/ig, '').split(',') //transform string value to an array (ie: "c1,c2,c3" becomes [1,2,3]
    		var $subcontents=$('.'+config["contentclass"])
    		if (expandedindices.length==1 && expandedindices[0]=="-1") //check for expandedindices value of [-1], indicating persistence is on and no content expanded
    			expandedindices=[]
    		if (config["collapseprev"] && expandedindices.length>1) //only allow one content open?
    			expandedindices=[expandedindices.pop()] //return last array element as an array (for sake of jQuery.inArray())
    		if (config["onemustopen"] && expandedindices.length==0) //if at least one content should be open at all times and none are, open 1st header
    			expandedindices=[0]
    		$('.'+config["headerclass"]).each(function(index){ //loop through all headers
    			if (/(prefix)|(suffix)/i.test(config.htmlsetting.location) && $(this).html()!=""){ //add a SPAN element to header depending on user setting and if header is a container tag
    				$('<span class="accordprefix"></span>').prependTo(this)
    				$('<span class="accordsuffix"></span>').appendTo(this)
    			}
    			$(this).attr('headerindex', index+'h') //store position of this header relative to its peers
    			$subcontents.eq(index).attr('contentindex', index+'c') //store position of this content relative to its peers
    			var $subcontent=$subcontents.eq(index)
    			var needle=(typeof expandedindices[0]=="number")? index : index+'' //check for data type within expandedindices array- index should match that type
    			if (jQuery.inArray(needle, expandedindices)!=-1){ //check for headers that should be expanded automatically (convert index to string first)
    				if (config.animatedefault==false)
    					$subcontent.show()
    				ddaccordion.expandit($(this), $subcontent, config, false) //Last Boolean value sets 'isuseractivated' parameter
    				lastexpanded={$header:$(this), $content:$subcontent}
    			}  //end check
    			else{
    				$subcontent.hide()
    				config.onopenclose($(this).get(0), parseInt($(this).attr('headerindex')), $subcontent.css('display'), false) //Last Boolean value sets 'isuseractivated' parameter
    				ddaccordion.transformHeader($(this), config, "collapse")
    			}
    		})
    		$('.'+config["headerclass"]).bind("evt_accordion", function(){ //assign custom event handler that expands/ contacts a header
    				var $subcontent=$subcontents.eq(parseInt($(this).attr('headerindex'))) //get subcontent that should be expanded/collapsed
    				if ($subcontent.css('display')=="none"){
    					ddaccordion.expandit($(this), $subcontent, config, true) //Last Boolean value sets 'isuseractivated' parameter
    					if (config["collapseprev"] && lastexpanded.$header && $(this).get(0)!=lastexpanded.$header.get(0)){ //collapse previous content?
    						ddaccordion.collapseit(lastexpanded.$header, lastexpanded.$content, config, true) //Last Boolean value sets 'isuseractivated' parameter
    					}
    					lastexpanded={$header:$(this), $content:$subcontent}
    				}
    				else{
    					ddaccordion.collapseit($(this), $subcontent, config, true) //Last Boolean value sets 'isuseractivated' parameter
    				}
     		})
    		$('.'+config["headerclass"]).bind(config.revealtype, function(){
    			if (config.revealtype=="mouseenter"){
    				ddaccordion.expandone(config["headerclass"], parseInt($(this).attr("headerindex")))
    			}
    			else{
    				$(this).trigger("evt_accordion")
    				return false //cancel default click behavior
    			}
    		})
    		config.oninit($('.'+config["headerclass"]).get(), expandedindices)
    		$(window).bind('unload', function(){ //clean up and persist on page unload
    			$('.'+config["headerclass"]).unbind()
    			var expandedindices=[]
    			$('.'+config["contentclass"]+":visible").each(function(index){ //get indices of expanded headers
    				expandedindices.push($(this).attr('contentindex'))
    			})
    			if (config.persiststate==true){ //persist state?
    				expandedindices=(expandedindices.length==0)? '-1c' : expandedindices //No contents expanded, indicate that with dummy '-1c' value?
    				ddaccordion.setCookie(config.headerclass, expandedindices)
    			}
    		})
    	})
    	}
    }
  • Dormilich
    Recognized Expert Expert
    • Aug 2008
    • 8694

    #2
    Originally posted by Nyris
    Right now all that happens with for example Home has two submenus of About Us and Quality. When you click home it expands the dropdown. But I want it to expand and also direct to a Home page.
    but why should it expand when it instantly leads the user to the "home" site without the chance to go to"About Us" or "Quality"? or asked the other way round, how is the user supposed to get to "quality" (despite the fact that he probably couldn't read, that the site is named so).

    regards

    Comment

    • Nyris
      New Member
      • Nov 2008
      • 22

      #3
      The home page has announcments and what not that are important. So once the user directs him/herself to a different page right now there's no way to get back to the homepage unless you hit the back button however many times you need to.

      Comment

      • Dormilich
        Recognized Expert Expert
        • Aug 2008
        • 8694

        #4
        there are some ways out
        - define the top level links unclickable (removing the href attribute), so the onclick will show up the menu. along with this event add the href attribute, so that the element becomes a full working link element.
        - use 2 onclick events. the first one to show up the submenu and adding the second event to the top level element (the second event must not be present from the start)
        - use a CSS dropdown menu. there you don't need javascript at all (except for the IE hacks)

        I recommend the last option.

        regards

        Comment

        • Nyris
          New Member
          • Nov 2008
          • 22

          #5
          Sorry for the delay! Thanks for the suggestions so far. However, I didn't write this. It was something that was premade and put into the website. Unfortuntely I have absolutely no javascript experience and I'm trying to decipher all this with little sucess. Could you point out the areas where I need to change to add the second onclick event?

          Comment

          • Dormilich
            Recognized Expert Expert
            • Aug 2008
            • 8694

            #6
            If I had a say, I'd switch to CSS dropdown menu. this minimizes javascript to a minimum (it's only needed for IE hacks).

            CSS dropdowns are pretty standard nowadays, see Son of Suckerfish Dropdowns | HTML Dog.

            regards

            Comment

            • Nyris
              New Member
              • Nov 2008
              • 22

              #7
              Thanks for the link. I see how this works and how it's a lot better than the javascript version. However, I need it to be horizontal and when a certain submenu is opened it stays opened. Is that possible? This was the reason to why I was leaning towards fixing the javascript code.

              Comment

              • Dormilich
                Recognized Expert Expert
                • Aug 2008
                • 8694

                #8
                Originally posted by Nyris
                However, I need it to be horizontal
                that's just a matter of the used CSS. see Pure CSS Menus.
                Originally posted by Nyris
                and when a certain submenu is opened it stays opened.
                what do you mean? the dropdown stays open as long as the mouse hovers over either the submenu or the submenu's parent link.

                Originally posted by Nyris
                I see how this works and how it's a lot better than the javascript version.
                that's why I recommended it in the first place.

                regards
                Last edited by Dormilich; Dec 19 '08, 06:58 PM. Reason: added personal note

                Comment

                • Nyris
                  New Member
                  • Nov 2008
                  • 22

                  #9
                  The website is FSIP. Take a look at that and you can see what the navigation looks like now.

                  Comment

                  • Dormilich
                    Recognized Expert Expert
                    • Aug 2008
                    • 8694

                    #10
                    so you didn't want to go for the nested lists? well, everything is fine, as long as you're satisfied. I'm glad I could help you solve the issue.

                    regards

                    Comment

                    • Nyris
                      New Member
                      • Nov 2008
                      • 22

                      #11
                      No no! This is what the navigation looks like now. What I need it to do is when you click on the header menu's I want it to go to that page as well as open up the submenus. I haven't changed anything yet. ^_^b

                      Comment

                      • Dormilich
                        Recognized Expert Expert
                        • Aug 2008
                        • 8694

                        #12
                        in the CSS dropdown the submenu will open if the mouse pointer touches the appropriate link (the last link had a working sample, as I recall). so boldly speaking CSS dropdown doesn't depend on click events.

                        by speaking of opening the submenus—where do you want the submenus to show up (there's a whole lot of possibilities, only limited by you imagination)?

                        Comment

                        • Nyris
                          New Member
                          • Nov 2008
                          • 22

                          #13
                          I would like to expand beneath the header like it does now. That's what the boss wants! haha

                          Comment

                          • Dormilich
                            Recognized Expert Expert
                            • Aug 2008
                            • 8694

                            #14
                            should be possible, you have to play around with the CSS a bit, though.

                            Comment

                            • acoder
                              Recognized Expert MVP
                              • Nov 2006
                              • 16032

                              #15
                              Nyris, are you going the CSS route or are you sticking to JavaScript? If you're changing to CSS, I'll move this thread over to the HTML/CSS forum.

                              Comment

                              Working...