SitePoint Sponsor

User Tag List

Results 1 to 4 of 4
  1. #1
    ☆★☆★ silver trophy vgarcia's Avatar
    Join Date
    Jan 2002
    Location
    in transition
    Posts
    21,235
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)

    Making flyout menus from a <dl>

    Hey everyone,

    I've been working on a script to make flyout menus from a definition list (<dl>), which the menu portion of a site I'm working on. So far I have this, which has been made easier by Skunk and Peter-Paul Koch. So far the script works perfectly in Mozilla, but that's it. In Opera 7.22/Windows it doesn't activate for some reason, and in IE6/Windows it activates but doesn't go away! Here is my code so far:

    JS:
    Code:
    function addEvent(obj, evType, fn){
     if (obj.addEventListener){
       obj.addEventListener(evType, fn, true);
       return true;
     } else if (obj.attachEvent){
       var r = obj.attachEvent("on"+evType, fn);
       return r;
     } else {
       return false;
     }
    }
    
    addEvent(window, 'load', menuconfig);
    
    function makeMenuGoBoom(e) {
    		/* Adapted from http://www.quirksmode.org/js/events_properties.html */
        if (typeof e == 'undefined') {
            var e = window.event;
        }
        var source;
        if (typeof e.target != 'undefined') {
            source = e.target;
        } else if (typeof e.srcElement != 'undefined') {
            source = e.srcElement;
        } else {
            return true;
        }
        /* For most browsers, targ would now be a link element; Safari however
           returns a text node so we need to check the node type to make sure */
        if (source.nodeType == 3) {
            source = source.parentNode;
        }
    	
    	if ("dt" == source.parentNode.nodeName.toLowerCase()) {
    		source.parentNode.nextSibling.style.visibility = 'visible';
    	} else {
    		source.style.visibility = 'visible';
    	}
    	return false;
    }
    
    function makeMenuGoAway(e) {
    	setTimeout(function() { makeMenuGoForGood(e) }, 300);
    }
    
    function makeMenuGoForGood(e) {
    	/* Adapted from http://www.quirksmode.org/js/events_properties.html */
        if (typeof e == 'undefined') {
            var e = window.event;
        }
        var source;
        if (typeof e.target != 'undefined') {
            source = e.target;
        } else if (typeof e.srcElement != 'undefined') {
            source = e.srcElement;
        } else {
            return true;
        }
        /* For most browsers, targ would now be a link element; Safari however
           returns a text node so we need to check the node type to make sure */
        if (source.nodeType == 3) {
            source = source.parentNode;
        }
    	if ("dt" == source.parentNode.nodeName.toLowerCase()) {
    		source.parentNode.nextSibling.style.visibility = '';
    	} else {
    		source.style.visibility = '';
    	}
    	return false;
    }
    
    function menuconfig() {
    	var dts = document.getElementById("navlist").childNodes;
    	var dItem, activeLink, activeDef;
    	for (var x = 0; x < dts.length; x++) {
    		dItem = dts[x];
    		
    		if (dItem.nextSibling && 'dd' == dItem.nextSibling.nodeName.toLowerCase()) {
    			activeLink = dItem.getElementsByTagName("a")[0];
    			activeLink.onmouseover = makeMenuGoBoom;
    			activeLink.onmouseout = makeMenuGoAway;
    			dItem.nextSibling.onmouseover = makeMenuGoBoom;
    			dItem.nextSibling.onmouseout = makeMenuGoAway;
    			
    		}
    		
    	}
    }
    Sample HTML:
    HTML Code:
    <dl id="navlist">
    				<dt class="skip"><a href="#content" title="Back to Content">Back to Content</a></dt>
    				<dt id="home"><a href="/" title="Home" class="current">home</a></dt>
    				<dt id="about"><a href="/about/" title="About Me">about me</a></dt>
    				<dd id="aboutlist">
    					<ul>
    						<li><a href="/about/background/" title="My Background">background</a></li><li><a href="/about/resume/" title="My R&eacute;sum&eacute;">my r&eacute;sum&eacute;</a></li><li><a href="/about/portfolio/" title="My Portfolio">my portfolio</a></li><li><a href="/contact/" title="Contact Me">contact me</a></li>
    					</ul>
    				</dd>
    </dl>
    CSS:
    Code:
    #mainnav dl {
    	position: absolute;
    	top: 81px;
    	left: 1px;
    	height: 20px;
    	line-height: 20px;
    	margin: 0;
    	padding: 0;
    	width: 716px;
    	border: 1px solid #666;
    	background: #ccc;
    	font-size: x-small;
    }
    #mainnav dt {
    	float: left;
    	width: 125px;
    	border-right: 1px solid #666;
    	/*position: relative;*/
    }
    #mainnav dt a {
    	display: block;
    	text-align: center;
    	color: #666;
    	font-weight: bold;
    	text-decoration:none;
    	font-family: "Bitstream Vera Sans", Geneva, Verdana, sans-serif;
    }
    #mainnav dt a:hover {
    	background: #708dab;
    	color: white;
    }
    #mainnav dd  {
    	position: absolute;
    	top: 20px;
    	width: 150px;
    	z-index: 30;
    	margin: 0;
    	padding: 0 0 10px;
    	background: transparent url(/images/bottom-flyout-new.gif) bottom no-repeat;
    	visibility: hidden;
    }
    #mainnav dd:hover {
    	/*redundant rule to help with the scripting for the menus*/
    	visibility: visible;
    }
    #aboutlist {
    	left: 126px;
    }
    Basically, the <dt>s form a horizontal navigation bar, and the <dd>s are supposed to go underneath their respective "terms". Does anyone see anything out of place, redundant, or that will just make IE and Opera choke? Any help would be greatly appreciated.

  2. #2
    Web-coding NINJA! silver trophy beetle's Avatar
    Join Date
    Jul 2002
    Location
    Dallas, TX
    Posts
    2,900
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Tell me if you like this any better. The target/srcElement method is okay, but this is much more robust - since you never have to worry about textNodes fouling it up. I tested it successfully in Mozilla 1.4 (Gecko 20030624), IE 6.0.2600 (No SP1), and Opera 7.11 (Build 2887).

    Code:
    /*
    	The _Event, _Utils, and _DOM objects I store in a separate file, normally called global.objects.js
    */
     
    var _Event = {
    	add: function( elem, evt, fp, useCapture )
    	{
    		if ( typeof elem.attachEvent != "undefined" )
    		{
    			elem.attachEvent( "on" + evt, fp );
    			return true;
    		}
    		else if ( typeof elem.addEventListener != "undefined" )
    		{
    			elem.addEventListener( evt, fp, useCapture );
    			return true;
    		}
    		return false;
    	},
    	getSrcElement: function( e )
    	{
    		var source = null;
    		switch( true )
    		{
    			case ( typeof e.target != 'undefined' ) :
    				source = e.target;
    				break;
    			case ( typeof e.srcElement != 'undefined' ) :
    				source = e.srcElement;
    				break;
    		}
    		if ( source.nodeType == 3 )
    		{
    			source = _DOM.nextSibling( source );
    		}
    		return source;
    	}
    }
    
     
    var _Utils = {
    	getNode: function( id )
    	{
    		return ( typeof document.getElementById != "undefined" ) ?
    			document.getElementById( id ) :
    			( typeof document.all != "undefined" ) ?
    				document.all( id ) :			
    				document.layers[id];
    	}
    }
     
    var _DOM = {
    	addChild: function( elem, parentId )
    	{
    		return _Utils.getNode( parentId ).appendChild( elem );
    	},
    	nextSibling: function( elem )
    	{
    		if ( !elem.nextSibling )
    		{
    			return null;
    		}
    		var ns = elem.nextSibling;
    		while ( ns.nodeType != 1 )
    		{
    			ns = ns.nextSibling;
    		}
    		return ns;
    	}
    }
     
    function DLMenu( menuId )
    {
    	this.menu = _Utils.getNode( menuId );
     
    	this.hide = function( elem )
    	{
    		elem.style.visibility = "hidden";
    	}
     
    	this.show = function( elem )
    	{
    		elem.style.visibility = "visible";
    	}
     
    	this.init = function()
    	{
    		var dts = this.menu.getElementsByTagName( "dt" ),
    			dt, dd, i = 0, self = this;
    		
    		while ( dt = dts[i++] )
    		{
    			dd = _DOM.nextSibling( dt );
    			if ( dd != null && 'dd' == dd.nodeName.toLowerCase() )
    			{
    				this.hide( dd );
    				_Event.add( dt, "mouseover", function() { self.show( dd ) }, false );
    				_Event.add( dt, "mouseout", function() { self.hide( dd ) }, false );
    			}
    		}
    	}
    	this.init();
    }
     
    _Event.add( window, "load", function()
    {
    	var a = new DLMenu( "navlist" );
    }, false );
    Another possible hang-up point in your script is that you had a handy addEvent() function, but used it only to add the initializing function to the window, and not for all your other event handling.
    beetle a.k.a. Peter Bailey
    blogs: php | prophp | security | design | zen | software
    refs: dhtml | gecko | prototype | phpdocs | unicode | charsets
    tools: ide | ftp | regex | ffdev




  3. #3
    Web-coding NINJA! silver trophy beetle's Avatar
    Join Date
    Jul 2002
    Location
    Dallas, TX
    Posts
    2,900
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hey Vinnie, change the content of the IF statement inside the WHILE loop to this
    Code:
    this.hide( dd );
    dt.onmouseover = function( e )
    {
    	self.show( _DOM.nextSibling( this ) );
    }
    dt.onmouseout = function( e )
    {
    	self.hide( _DOM.nextSibling( this ) );
    }
    I know this is contradictory to things I've said previously, but here's why I changed it.

    Inside an event-triggered function, normally the this keyword directly refers to the element that the event is attached to, which is not necessarily the element that fired the event (such as srcElement and target).

    However, in IE, when the function is attached via attachEvent, then the this keyword refers to window. Since the object we're referring to needs local scope, all other traditional methods fail.

    I'm currently testing a couple other possibilities, such as cancelling the event bubbling.
    beetle a.k.a. Peter Bailey
    blogs: php | prophp | security | design | zen | software
    refs: dhtml | gecko | prototype | phpdocs | unicode | charsets
    tools: ide | ftp | regex | ffdev




  4. #4
    ☆★☆★ silver trophy vgarcia's Avatar
    Join Date
    Jan 2002
    Location
    in transition
    Posts
    21,235
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)
    It's working beautifully now! One more question though; any way to keep the <dd>s up, so people can click on the links rather than having the whole list disappear when you mouse off the <dt>?


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •