Forum Moderators: open
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>SELECT BOX</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style type="text/css">
<!--
body,td,th {
font-family: verdana;
font-size: small;
color: #009999;
}
body {
background-color: #FFFFFF;
margin-left: 2em;
margin-top: 2em;
}
-->
br{
line-height:0;}
#innermenu a{
text-decoration:none;
}
#innermenu a:hover{
background-color:#00FFFF;
}
div{
padding:0;
margin:0;
}
#search{
width:150px;
height:auto;
border:1px solid white;
}
a.drop{
display:block;
font-size:0.9em;
font-weight:normal;
color:#666;
text-decoration:none;
width:146px;
height:12px;
padding:1px;
background-image:url(arrow_out.gif);
background-repeat:no-repeat;
background-position:right;
text-align:left;
cursor:hand;
border:1px solid #006699;
}
a.drop:hover{
font-size:0.9em;
font-weight:normal;
color:#666;
text-decoration:none;
display:block;
width:146px;
height:12px;
padding:1px;
background-image:url(arrow_over.gif);
background-repeat:no-repeat;
background-position:right;
text-align:left;
cursor:hand;
border:1px solid #006699;
}
#dropdown{
font-size:0.9em;
z-index:10;
width:148px;
height:auto;
background-color:#FFFFFF;
border:1px solid #006699;
border-top:0;
visibility:hidden;
}
#dropdown ul{
padding:0;
margin:0;
list-style-type:none;}
#dropdown li{
padding:0;
margin:0;}
#dropdown a{
display:block;
background-color:#fff;
padding:2px 4px;
margin:0;
text-decoration:none;
color:#666;
}
#dropdown a:hover{
display:block;
background-color:#0099FF;
padding:2px 4px;
margin:0;
text-decoration:none;
color:#fff;
}
</style>
<script type="text/javascript">
function showhide(whichLayer)
{
if (document.getElementById)
{
// this is the way the standards work
var style2 = document.getElementById(whichLayer).style;
style2.visibility = style2.visibility? "":"visible";
}
}
</script>
</head>
<body>
<div id="search">
<a href="javascript:showhide('dropdown');" on class="drop">Show all links</a>
<div id="dropdown" onmouseout="showhide('dropdown');">
<a href="#"> Link 1</a><br />
<a href="#">Link 2</a><br />
<a href="#">Link 3</a><br />
<a href="#">Link 4</a><br />
<a href="#">Link 5</a><br />
<a href="#">Link 6</a><br />
<a href="#">Link 7</a><br />
<a href="#">Link 8</a><br />
</div>
</div>
</body>
</html>
The functionality works fine until the mouseout event is triggered by the dropdown box. Somehow the browser considers the mouse to be out of the dropdown div as soon as you hover over any of the links contained within that div. This obviously what causes that annoying blinking effect and I was wondering if there was anyway to stop this from happening.
Would anyone here know how to stop the browser from considering child elements of the dropdown divs to be outside of the div?
Thanks a lot in advance!
In fact, that's not what happening. Events like clicks and mouseouts bubble. There is a cacophony of mouseouts bubbling up from the child elements. If there is any gap between the child elements, then there are also mouseouts as the mouse moves to each child.
There are ways around this. These usually involve querying the event trapped at the event handler. It always involves some kind of cross-browser fiddles.
Personally, I think the widget would be more use-friendly if the dropdown didn't hide until the mouse moves off the top link. I mention this because I have a feeling it would also be a little easier to code for.
I have changed the CSS property to 'display'.
If the function call sends an event argument, showMenu function tests the event for the element that caused it. If it is not the container then the function returns.
#dropdown{
....
display:none;
}....
<script type="text/javascript">
getEventSrc = window.Event
? function(e){var targ=e.target;return targ.nodeType==1?targ:targ.parentNode}
: function() {return event.srcElement}function showMenu(container,Bshow, e)
{
if (
!document.getElementById ¦¦
(e && getEventSrc(e)!=container)
) return;
container.getElementsByTagName('div')[0].style.display
= Bshow? 'block':'';
}</script>
</head>
<body>
<div id="search" onmouseout="showMenu(this,0,event);" style="padding:5px;">
<a href="#" onclick="showMenu(this.parentNode,1);" class="drop">Show all links</a>
<div id="dropdown" >
<a href="#"> Link 1</a><br />
<a href="#">Link 2</a><br />
<a href="#">Link 3</a><br />
<a href="#">Link 4</a><br />
<a href="#">Link 5</a><br />
<a href="#">Link 6</a><br />
<a href="#">Link 7</a><br />
<a href="#">Link 8</a><br />
</div>
</div>
[edited by: jatar_k at 3:47 pm (utc) on Oct. 5, 2005]
getEventSrc = window.Event? function(e){var targ=e.target;return targ.nodeType==1?targ:targ.parentNode}
: function() {return event.srcElement} I can see that you are capturing the event + finding the target but as a result of my limited of knowledge of of JavaScript & its syntax I can’t see how it would fit in the equation above. And I would like to understand it better as I’d probably be using something along these lines quite a lot in the future.
Regards,
BB
I don't think so. Notice that it's all arranged so that id's aren't actually required. The only specifics of any kind are
a) the tagName, DIV, for the dropdown part.
b) the dropdown, and header are direct children of the main container.
This is just the best I could come up with yesterday afternoon. There are certainly better overall approaches.
This is essentially a simple dropdown menu, so it's likely that this could be acheived using just CSS - in standards browsers, maybe with scripted enhancement for IE. A pure CSS approach would give a slightly different behaviour that acts on mouseover, not click.
This one comes to mind for a click-activated menu:
[brainjar.com...]
..but that ceases to operate without script.
Search "CSS dropdown menu" for other options, if you wouldn't mind having something that may "degrade gracefully" without javascript.
----------------------------------
The originating element of an event isn't necessarily the element that has the event handler. The event could have bubbled up from a descendant element.
Finding the originating element, across browsers, is a slightly messy business. That code hopes to clean it up, but is messy itself, partly in the hope of making it more efficient.
STANDARDS
There is a global function,
[b]E[/b]vent, which is the constructor for event objects. To pass the event in an HTML event handler, you use the keyword(?)
event. The originating node is held in the property, target. However, text nodes can originate events, so we need to check the nodeType, and return the parentNode (the actual element) if the nodeType!= 1.
IE
There is a global object,
[b]e[/b]vent. This holds a reference to the event object of the current, event-driven thread. Otherwise it is null. Event handlers assigned via script are passed no arguments.
There is no need to pass the event in an HTML event handler, because event is in the global namespace. However, because of this, and the use of the same 'name', the code to pass the event in standards browsers also passes the event in IE.
The originating element is held in the property, srcElement.
--------------
A single function could be used to sort this out. One that has 'branches' in it. At one time, when I was using this approach, I found that my Moz was being a bit sluggish, so the question, "what event model do you use?" is only asked once at load time, so as to cut out that step when the function is used. Javascript functions are objects, so they can be juggled in this way. Some call it "function pointing".
// Does global, Event, exist?
// (as property of window to avoid undeclared variable error)
if(window.Event)
getSrcElement = function(e){standards code}
else
getSrcElement = function(){IE code}
Finally, this
if..else structure, and the one in the standards function, is turned into a shortcut expression, using the conditional operator [developer-test.mozilla.org]