Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

premature event firing

Status
Not open for further replies.

hessodreamy

Programmer
Feb 28, 2005
59
GB
I have a menu system which pops up a submenu when the mouse hovers over a menu item. It dynamically creates a div for the submenu, and removes it when the mouse the submenu, or the main menu item which spawned it. All good so far.

Nearly there. But what I'm finding now is that the submenu closes when the mouse leaves one of the hyperlinks in the submenu, instead of closing only when the mouse leaves the enclosing div. Why is it doing this? I think I'm going to cry...

The code is below. You can see it in action at
(btw I've got my reasons for not doing this with css so please no suggestions along those lines :) )
Code:
<script>
var inSubMenu = new Array();
function openMenu(oMenu)
{
    var mainMenu = oMenu;
    var subMenu = document.createElement("div");mainMenu.appendChild(subMenu);
    subMenu.className='subMenu';
    subMenu.id='submenu'+oMenu.id;
    var mouseoutfunction = function() {oMenu.removeChild(this);};
    subMenu.onmouseout=mouseoutfunction;
    var sublist = cats[oMenu.id];
    //for each subcat
    //create link
    //set href
    //set inner text
    //add to sub
    for(var catid in sublist)
    {
          var link = document.createElement('a');
          link.href= '/products/category.php?catid='+oMenu.id;
          link.appendChild(document.createTextNode(sublist[catid]));
          subMenu.appendChild(link);
    }
}
function leaveMenu (oMenu)
{
  var timeoutFunc = function () { oMenu.removeChild(oMenu.lastChild);};
  window.setTimeout(timeoutFunc, 10);
}
</script>
<div id="menuItem" style="position:relative; right:-50%" >
<strong>Categories A-Z</strong>
<script>
var cats = new Array();
cats[195] = new Array('Chemical Absorbents','General Purpose Absorbents','Oil Only Absorbents','Spill Kits');
inSubMenu[195] = false
cats[223] = new Array('Analysis ruled pad','Analysis ruled paper','General Trader/VAT book','Halfbound account book','Postage & Delivery book','Standard account book','Standard Analysis Book','Wage & S.S.P book');
inSubMenu[223] = false
cats[224] = new Array('Adhesives & Coverings','All Purpose adhesive','Dry adhesive','Glue Roller/Refill','Glue Stick/Gluepen','Paste/Smooth');
inSubMenu[224] = false
cats[183] = new Array(' Air Purifiers',' Air Purifiers Mounted');
inSubMenu[183] = false
</script>
<div id="223" style="position:relative" onmouseover="openMenu(this)" onmouseout="leaveMenu(this)">
    <a name="Accounting Book/Pa..." href="../products/category.php?catid=223">&nbsp;<&nbsp;Accounting Book/Pa...</a>
</div>
<div id="224" style="position:relative" onmouseover="openMenu(this)" onmouseout="leaveMenu(this)">
    <a name="Adhesives" href="../products/category.php?catid=224">&nbsp;<&nbsp;Adhesives</a></div>
<div id="183" style="position:relative" onmouseover="openMenu(this)" onmouseout="leaveMenu(this)">
    <a name="Air Conditioners" href="../products/category.php?catid=183">&nbsp;<&nbsp;Air Conditioners</a>
</div>
</div><style>
#menuItem {
	width:150px;
	color: black;
	text-align:center;
	background-color:White;
	border: solid 1px #3B5263;
	padding:0px;
	position: relative;
}
#menuItem a {
	width: 150px;
	font: normal 8pt Verdana;
	color: black;
	text-decoration: none;
	text-align:left;
	display:block;
	border: solid 1px #547A98;
	background-color: #DEE6EC;
    padding:0px;
}
#menuItem a:hover {
	color: orange;
	text-decoration: none;
	display:block;
	border-top: solid 1px #547A98;
	background-color: WHITE;
}
.subMenu {
	width:150px;
	color: black;
	overflow:auto;
	text-align:center;
	background-color:White;
	border: solid 1px #3B5263;
	padding:0px;
 position: absolute;
	right:100%;
	top:0%;
	overflow: hidden;
}
</style>
 
I don't think that that is your problem. I think it's that way the timers are working to clear the menu items, combined with the immediate clearing of the submenu when moving from one submenu item to another.

If you replace your first script section with this one, you should find that it no longer an issue. I've also tidied up the timer code for the main menu.

Code:
<script type="text/javascript">
<!--
	var inSubMenu = new Array();
	var menuTimer = null;
	var previousMenu = null;

	function openMenu(oMenu) {

		if (menuTimer != null) {
			document.title = 'Clearing timer';
			clearTimeout(menuTimer);
			menuTimer = null;
		}
		if (previousMenu != null && previousMenu != oMenu) closeMenu();

		if (previousMenu != oMenu) {
			var mainMenu = oMenu;
			var subMenu = document.createElement("div");
			mainMenu.appendChild(subMenu);
			subMenu.className='subMenu';
			subMenu.id='submenu'+oMenu.id;

			var sublist = cats[oMenu.id];
			for(var catid in sublist) {
				var link = document.createElement('a');
				link.href= '/products/category.php?catid='+oMenu.id;
				link.appendChild(document.createTextNode(sublist[catid]));
				subMenu.appendChild(link);
			}
		}
	}

	function closeMenu() {
		if (previousMenu != null) {
			previousMenu.removeChild(previousMenu.lastChild);
			previousMenu = null;
		}
	}

	function leaveMenu(oMenu) {
		if (previousMenu != null && previousMenu != oMenu) closeMenu();
		previousMenu = oMenu;
		menuTimer = setTimeout('closeMenu();', 250);
	}
//-->
</script>

Hope this helps,
Dan


[tt]Dan's Page [blue]@[/blue] Code Couch
[/tt]
 
P.P.S. I'm not entirely sure the code I gave above would work correctly if you added a third level to the menu.

If you need a flexible and extensible menu system that will comfortably handle 3..n levels, you'll probably want to either pick one that is already available, or design one from the ground up, thinking through all your requirements.

Dan



[tt]Dan's Page [blue]@[/blue] Code Couch
[/tt]
 
self said:
I don't think that that is your problem.

Hmmm... of course, now that I re-read your original code, I can see what you mean. I had assumed that the submenu item anchors were each contained within their own div... but I see now you were referring to the outer div.

Anyway - you were right with your original description of the problem ;o)

Dan


[tt]Dan's Page [blue]@[/blue] Code Couch
[/tt]
 
Well, hey. Your code works brilliant. Thanks a lot. I've been trying to sort this menu thing out for ages. Today is a happy day for me!

Cheers
 
I think the original realization is unncessarily complicated by conflicting event, mouseout some element and "at the same time" meaning mouseover some other element.

Here is a realization with minimal change with respect to the main body as shown by the op, using only mouseover and it works cross browser. This is the main functional part. The stylistic part is unchanged. inSubMenu now is taken out and not used.
[tt]
<script language="javascript">
window.onload=setup;
var subMenu=null; //becoming global here
function setup() {
if (document.all) {
document.attachEvent("onmouseover",openMenuA);
} else {
document.addEventListener("mouseover",openMenuA,false);
}
}

function openMenuA(event) {
var evt=(event)?event:window.event;
var oelem=(evt.srcElement)?evt.srcElement:evt.target;
switch (oelem.name) {
case "Accounting Book/Pa..." :
case "Adhesives" :
case "Air Conditioners" :
if (subMenu) {
subMenu.parentNode.removeChild(subMenu);
subMenu=null;
}
var mainMenu=oelem.parentNode;
subMenu = document.createElement("div");
mainMenu.appendChild(subMenu);
subMenu.className='subMenu';
subMenu.id='submenu'+mainMenu.id;
var sublist = cats[mainMenu.id];
//for each subcat
//create link
//set href
//set inner text
//add to sub
for(var catid in sublist)
{
var link = document.createElement('a');
link.href= '/products/category.php?catid='+mainMenu.id;
link.appendChild(document.createTextNode(sublist[catid]));
subMenu.appendChild(link);
}
break;
default :
if (subMenu) {
if ((!oelem.href)||(oelem.href.indexOf("catid")==-1)) {
subMenu.parentNode.removeChild(subMenu);
subMenu=null;
}
}
break;
}
}
</script>
<div id="menuItem" style="position:relative; right:-50%" >
<strong>Categories A-Z</strong>
<script>
var cats = new Array();
cats[195] = new Array('Chemical Absorbents','General Purpose Absorbents','Oil Only Absorbents','Spill Kits');
cats[223] = new Array('Analysis ruled pad','Analysis ruled paper','General Trader/VAT book','Halfbound account book','Postage & Delivery book','Standard account book','Standard Analysis Book','Wage & S.S.P book');
cats[224] = new Array('Adhesives & Coverings','All Purpose adhesive','Dry adhesive','Glue Roller/Refill','Glue Stick/Gluepen','Paste/Smooth');
cats[183] = new Array(' Air Purifiers',' Air Purifiers Mounted');
</script>
<div id="223" style="position:relative">
<a name="Accounting Book/Pa..." href="../products/category.php?catid=223">&nbsp;&lt;&nbsp;Accounting Book/Pa...</a>
</div>
<div id="224" style="position:relative">
<a name="Adhesives" href="../products/category.php?catid=224">&nbsp;&lt;&nbsp;Adhesives</a></div>
<div id="183" style="position:relative">
<a name="Air Conditioners" href="../products/category.php?catid=183">&nbsp;&lt;&nbsp;Air Conditioners</a>
</div>
[/tt]
(Due to the design on <a>, specific listing of name is used in the distinguishing process of srcElement/target. It may be possible to make it more concise by some common criteria.)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top