I am making a DHTML menu using css and javascript.
my CSS looks like this. Basically the submenu is conained in a wrapper span that is initially set to display none and onmouseover it changes the class of the parent div to n2 so the span is displayed and likewise onmouseout changes div back to n1 to re-hide the span.
So when I build the html for a sample of the menu it looks like this.
Changing the class works fine and the menu functions just great except I have the issue of any submenu potentially overflowing the bottom of the window so the user would need to scroll down to see all the options when the menu expands. So I am working on functions to reposition the submenus when they become visible only If they would cause overflow. My javascript looks like this.
This works in both firefox and IE and moves the 1st level submenus up when needed. Now after all this... here is the problem... 2nd level submenus still overflow the bottom of the page and I have done some testing and this is what I found out:
The cnodes[1].offsetHeight is returning the height is zero for all 2nd level submenus during execution. It appears its trying to calculate the height of the hidden span before it's display is set to block. Because it always returns zero the overflow check will always fail and submenus 2 deep will never be moved up. I made sure that I called the changeClass() function so the span would be set to display 'block' prior to calling the offsetHeight but it still returns zero. If i manually set cnodes[1].dispay = block before getting the offsetHeight it correctly gets the height of the submenu but it completely breaks the dhtml effects of the menu.
What doesn't make any sense is, The function works for 1st level deep but nothing deeper than that. And the HTML format for both 1st and 2nd level menus are the same.
Any ideas?
my CSS looks like this. Basically the submenu is conained in a wrapper span that is initially set to display none and onmouseover it changes the class of the parent div to n2 so the span is displayed and likewise onmouseout changes div back to n1 to re-hide the span.
Code:
.navbar {
float:left;
position: relative;
width: 173px;
background-color:white;
border: solid 1px black;
top:200px;
}
.n1 {
position:relative;
background-color: 1b2f3b;
color: white;
display:block;
border-color:black;
border-width:1px;
border-style:solid;
padding: 2px 0px 2px 5px;
}
.n1 span {display:none;}
.n2 {
position:relative;
background-color: 095c8e;
color: white;
display:block;
border-style:solid;
border-width:1px;
padding: 2px 0px 2px 5px;
}
.n2 span {
position: absolute;
top:0px;
left:150px;
background-color: 1b2f3b;
color: white;
z-index:1000;
border-style:solid;
border-width:2px;
width:180px;
}
So when I build the html for a sample of the menu it looks like this.
Code:
<div class="navbar">
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
DIV 1-1
<span class="sub">
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
Link 1
<span class="sub">
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 1</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 4</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 7</div>
</span>
</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
Link 4
<span class="sub">
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 1</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 4</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 7</div>
</span>
</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
</span>
</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
DIV 1-2
<span class="sub">
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
Link 1
<span class="sub">
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 1</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 4</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 7</div>
</span>
</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
Link 4
<span class="sub">
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 1</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 4</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 7</div>
</span>
</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
<div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
</span>
</div>
</div>
</div>
Changing the class works fine and the menu functions just great except I have the issue of any submenu potentially overflowing the bottom of the window so the user would need to scroll down to see all the options when the menu expands. So I am working on functions to reposition the submenus when they become visible only If they would cause overflow. My javascript looks like this.
Code:
function changeClass(item)
{
if(item.className == "n1")
item.className = "n2";
else if (item.className == "n2")
item.className = "n1";
}
function getYpos(element)
{
var y;
y = element.offsetTop;
if (element.offsetParent != null)
y += getYpos(element.offsetParent);
//alert(y);
return y;
}
function pos(element)
{
var y, ch, eh = 0;
changeClass(element);
// get verical position of element in relation to page
y = getYpos(element);
//element height
eh = element.offsetHeight;
var cnodes = element.childNodes;
// check to see if element has a submenu (child[1] is the span)
if (cnodes[1] && cnodes[1].nodeType == 1)
{
// get height of submenu
ch =cnodes[1].offsetHeight;
}
// checks for submenu overflow and if so, moves submenu up
if ((y + ch) > document.body.clientHeight)
{
ch = ch - eh;
cnodes[1].style.top = "-" + ch + "px";
}
}
function closeMenu(element)
{
var cnodes = element.childNodes;
// reset submenu position to original position
if (cnodes[1] && cnodes[1].nodeType == 1)
{
cnodes[1].style.top = "0px";
}
changeClass(element);
}
This works in both firefox and IE and moves the 1st level submenus up when needed. Now after all this... here is the problem... 2nd level submenus still overflow the bottom of the page and I have done some testing and this is what I found out:
The cnodes[1].offsetHeight is returning the height is zero for all 2nd level submenus during execution. It appears its trying to calculate the height of the hidden span before it's display is set to block. Because it always returns zero the overflow check will always fail and submenus 2 deep will never be moved up. I made sure that I called the changeClass() function so the span would be set to display 'block' prior to calling the offsetHeight but it still returns zero. If i manually set cnodes[1].dispay = block before getting the offsetHeight it correctly gets the height of the submenu but it completely breaks the dhtml effects of the menu.
What doesn't make any sense is, The function works for 1st level deep but nothing deeper than that. And the HTML format for both 1st and 2nd level menus are the same.
Any ideas?