//This class implements the logic for a menu system. //Each object is initialized with a menu element, its parent menu //element, and its child menu element. There is no limit on the //number of submenu level. function dhtmlMenu(topElement, subDiv, parentMenu) { this.oElement = topElement; //top menu this.oDiv = subDiv; //sub menu container associated with top menu this.oParent = parentMenu; //parent container of top menu this.externalMainMenuEvent; this.externalSubMenuEvent; this.displayRight; //display the 1st sub-menu to right (default is bottom) this.clickToActivate = false; this.xadj = 0; this.yadj = 0; this.delayOpen = 50; this.delayClose = 100; } //function properties - static variables //the current active top level menu dhtmlMenu.currentMenu = null; dhtmlMenu.changeTopMenuEvent = null; //next top level menu dhtmlMenu.nextMenu = null; //the timer to hide the current top level menu //and all its submenu dhtmlMenu.timeoutId = null; //delay event for parent menu; dhtmlMenu.parentMenu = null; dhtmlMenu.timeoutId2 = null; dhtmlMenu._collection = new Object(); //object methods inherited through the //prototype object dhtmlMenu.prototype.init = function() { var eventFunction = function(e) {dhtmlMenu._collection[this.id].onMainMenuEvent(e);}; dhtmlMenu._collection[this.oElement.id] = this; this.oElement.onmouseover = eventFunction; this.oElement.onmouseout = eventFunction; this.oElement.onclick = eventFunction; eventFunction = function(e) {dhtmlMenu._collection[this.id].onSubMenuEvent(e);}; this.oDiv.style.visibility = 'hidden'; dhtmlMenu._collection[this.oDiv.id] = this; this.oDiv.onmouseover = eventFunction; this.oDiv.onmouseout = eventFunction; } dhtmlMenu.prototype.init2 = function _dhtmlMenu_init2() { this.oDiv.style.visibility = 'hidden'; } //event handler of the parent menu dhtmlMenu.prototype.onMainMenuEvent = function(evt, type) { if (evt && !window.event) {type = evt.type;} if (!type) type = window.event.type; switch (type) { case 'mouseover': if (!this.clickToActivate && !dhtmlMenu.currentMenu && !this.oParent) { dhtmlMenu.currentMenu = this.oElement; } else if (!dhtmlMenu.currentMenu) break; this._disableTimer(); //disable timer to close top level menu //check if mouse is over a top level menu //or a submenu if (!this.oParent) { //delay opening the top menu dhtmlMenu.nextMenu = this.oElement; dhtmlMenu.timeoutId = window.setTimeout('dhtmlMenu._collection[\'' + dhtmlMenu.nextMenu.id + '\']._changeTopMenu(); dhtmlMenu.timeoutId = null; dhtmlMenu.nextMenu = null;', this.delayOpen); } else { //delay opening the child menu this._disableTimer2(); dhtmlMenu.parentMenu = this.oElement; dhtmlMenu.timeoutId2 = window.setTimeout('dhtmlMenu._collection[\'' + dhtmlMenu.parentMenu.id + '\']._displayChildMenu(); dhtmlMenu.parentMenu = null; dhtmlMenu.timeoutId2 = null', 350); } break; case 'mouseout': if (!dhtmlMenu.currentMenu) break; this._disableTimer(); //disable timer to close top level menu this._disableTimer2(); //disable timer to open child menu //reset timer to switch off the top level menu and its child menu if (!this.clickToActivate && !this.oParent && this.oDiv.style.visibility == 'hidden' && dhtmlMenu.currentMenu == this.oElement) dhtmlMenu.currentMenu = null; else dhtmlMenu.timeoutId = window.setTimeout('dhtmlMenu._collection[\'' + dhtmlMenu.currentMenu.id + '\']._switchDiv(false); if (dhtmlMenu.changeTopMenuEvent) dhtmlMenu.changeTopMenuEvent(dhtmlMenu.currentMenu, null); dhtmlMenu.currentMenu = null; dhtmlMenu.timeoutId = null', this.delayClose); break; case 'click': //initiate automatic mouseover and mouseout responses //to the entire menu system. The click event is applied //only to the top level menu. if (!dhtmlMenu.currentMenu && !this.oParent) { dhtmlMenu.currentMenu = this.oElement; this._changeTopMenu(); } break; } if (this.externalMainMenuEvent) this.externalMainMenuEvent(evt, type); } //event handler of the child menu dhtmlMenu.prototype.onSubMenuEvent = function(evt, type) { if (evt && !window.event) {type = evt.type;} if (!type) type = window.event.type; switch (type) { case 'mouseover': this._disableTimer(); break; case 'mouseout': this._disableTimer(); //set timer to switch off the top level menu dhtmlMenu.timeoutId = window.setTimeout('dhtmlMenu._collection[\'' + dhtmlMenu.currentMenu.id + '\']._switchDiv(false); if (dhtmlMenu.changeTopMenuEvent) dhtmlMenu.changeTopMenuEvent(dhtmlMenu.currentMenu, null); dhtmlMenu.currentMenu = null; dhtmlMenu.timeoutId = null', this.delayClose); break; } if (this.externalSubMenuEvent) this.externalSubMenuEvent(evt, type); //if (window.event) event.cancelBubble = true; //else evt.stopPropagation(); } //toggle the child menu on-off dhtmlMenu.prototype._switchDiv = function(active) { if (active) { //the top level menu is active var pos = this._calcPos(this.oElement); if (!this.oParent) { //parent menu is the top level menu //calculate the display position of the child menu if (this.displayRight) pos.x += this.oElement.offsetWidth; else pos = {x:pos.x, y:pos.y + this.oElement.offsetHeight}; this.oDiv.style.left = pos.x + this.xadj; this.oDiv.style.top = pos.y + this.yadj; } else { //parent menu is not a top level menu //calculate the display position of the child menu this.oDiv.style.left = pos.x + this.oParent.offsetWidth + this.xadj; this.oDiv.style.top = pos.y + this.yadj; } //display child menu this.oDiv.style.visibility = 'visible'; } else { //the top level menu is no longer active if (this.oDiv.childMenu) { //switch off all child's child-menu this.oDiv.childMenu._switchDiv(active); this.oDiv.childMenu = null; } //switch off the child menu of the top level menu this.oDiv.style.visibility = 'hidden'; this.oDiv.style.top = '0'; this.oDiv.style.left = '0'; } } //disable the timer to switch off the top level menu dhtmlMenu.prototype._disableTimer = function() { if (dhtmlMenu.timeoutId) { window.clearTimeout(dhtmlMenu.timeoutId); dhtmlMenu.timeoutId = null; } } //disable the timer to switch off the top level menu dhtmlMenu.prototype._disableTimer2 = function() { if (dhtmlMenu.timeoutId2) { window.clearTimeout(dhtmlMenu.timeoutId2); dhtmlMenu.timeoutId2 = null; } } dhtmlMenu.prototype._changeTopMenu = function() { //switch off previous active top level menu var prevMenu = dhtmlMenu.currentMenu; if (prevMenu && (prevMenu != this.oElement)) { dhtmlMenu._collection[prevMenu.id]._disableTimer(); dhtmlMenu._collection[prevMenu.id]._switchDiv(false); } //set current menu and switch it on dhtmlMenu.currentMenu = this.oElement; this._switchDiv(true); if (dhtmlMenu.changeTopMenuEvent) dhtmlMenu.changeTopMenuEvent(prevMenu, this.oElement); } dhtmlMenu.prototype._displayChildMenu = function() { var prevChild = this.oParent.childMenu; if (prevChild) prevChild._switchDiv(false); this.oParent.childMenu = this; this._switchDiv(true); } //calculate the position relative to the client screen dhtmlMenu.prototype._calcPos = function(thisElement) { var oParent = thisElement.offsetParent; var i = 50; //limit to 50 iteration var oBody = document.body; var pos = {x:thisElement.offsetLeft, y:thisElement.offsetTop}; while (i-- > 0 && oParent != oBody) { pos.x += oParent.offsetLeft - 0; //position correction for padding pos.y += oParent.offsetTop - 0; //position correction for padding oParent = oParent.offsetParent; } return pos; }