DHTML Lab: Hierarchical Menus, III; Frames - Positioning | WebReference

DHTML Lab: Hierarchical Menus, III; Frames - Positioning

home / experts / dhtml / column18

Hierarchical Menus in Frames
menu positioning

Initial Display

The function that displays the menu originally is popUp(), called by the onMouseOver handler in our HTML page.

In our original version, the menu was placed exactly at the point of the mouseover. In the frames version, we have to correctly position it in the main frame so that it seems to be connected to the navigation frame link.

If the navigation frame is on the left, the menu must appear at the left edge of the main frame (main.pageXOffset, for NS4, and main.document.body.scrollLeft, for IE4). Notice that we place the menu at whatever position in the main frame's page corresponds to the left-most visible coordinate in the frame window, and not at the left-most cordinate of the page. This is to compensate for the possibility that a user has scrolled the page horizontally. We still must have the menu appear at the frame's left edge.

For the vertical coordinate of the menu's position, we must calculate the browser window position of the mouseover event, then position the menu at that same position. We must always compensate for probable vertical scrolling of the main frame and a possible scrolling of the navigation frame. In Navigator, we do not have properties for the event coordinates in the client (browser) window. Instead, we must subtract the page part that is scrolled off-window (pageYOffset) from the page position of the event (e.pageY). This gives us the client window vertical position. We then take this value and add it to the pageYOffset of the main frame. The result is the vertical page position in the main frame that the menu should be placed at to be next to the navigation frame link.

The above calculations are the same for a top navigation frame, substituting horizontal coordinate properties for the vertical ones and vice-versa.

function popUp(menuName,e){
    if (!areCreated) return;
    hideAll();
    currentMenu = eval(menuName);
    if (isLeftNav) {    
        xPos = (NS4) ? main.pageXOffset : main.document.body.scrollLeft;
        yPos = (NS4) ? (e.pageY-pageYOffset) + main.pageYOffset : event.clientY + main.document.body.scrollTop;
    }
    else {
        xPos = (NS4) ? (e.pageX-pageXOffset) + main.pageXOffset : event.clientX + main.document.body.scrollLeft;                                                                        
        yPos = (NS4) ? main.pageYOffset : main.document.body.scrollTop;
    }
    currentMenu.moveTo(xPos,yPos);
    currentMenu.keepInWindow()
    currentMenu.isOn = true;
    currentMenu.showIt(true);
}

The Explorer version has the same logic, but is a two-step process instead of three. We use the built-in event.clientX and event.clientY properties to determine the client window coordinates of the mouseover event and add this value to either main.document.body.scrollLeft or main.document.body.scrollTop.

Note: The present frame has both vertical and horizontal scrollbars. Scroll the frame to different positions and mouseover the links in the left frame.

Keep in Window

The other function that deals with initial menu positioning is keepInWindow(), which assures that the menus are not rendered off-screen. All coordinate properties in this function have been changed to properties of the main frame:

function keepInWindow() {
    scrBars = 20;
    if (NS4) {
        winRight = (main.pageXOffset + main.innerWidth) - scrBars;
        rightPos = this.left + menuWidth;
   
        if (rightPos > winRight) {
            if (this.hasParent) {
                parentLeft = this.parentMenu.left;
                newLeft = ((parentLeft-menuWidth) + childOverlap);
                this.left = newLeft;
            }
            else {
                dif = rightPos - winRight;
                this.left -= dif;
            }
        }
        winBot = (main.pageYOffset + main.innerHeight) - scrBars;
        botPos = this.top + this.fullHeight;
        if (botPos > winBot) {
            dif = botPos - winBot;
            this.top -= dif;
        }
    }
    else {
           winRight = (main.document.body.scrollLeft + main.document.body.clientWidth) - scrBars;
        rightPos = this.style.pixelLeft + menuWidth;
    
        if (rightPos > winRight) {
            if (this.hasParent) {
                parentLeft = this.parentMenu.style.pixelLeft;
                newLeft = ((parentLeft - menuWidth) + childOverlap);
                this.style.pixelLeft = newLeft;
            }
            else {
                dif = rightPos - winRight;
                this.style.pixelLeft -= dif;
            }
        }
        winBot = (main.document.body.scrollTop + main.document.body.clientHeight) - scrBars;
        botPos = this.style.pixelTop + this.fullHeight;
        if (botPos > winBot) {
            dif = botPos - winBot;
            this.style.pixelTop -= dif;
        }
    }
}

Methods

Menu visibility and actual movement into position are controlled by the functions, showIt() for both browsers, and moveTo(), for Explorer. Navigator has a built-in moveTo() method. These functions remain unchanged from the original version.

function showIt(on) {
	if (NS4) {this.visibility = (on) ? "show" : "hide"}
		else {this.style.visibility = (on) ? "visible" : "hidden"}
}
function moveTo(xPos,yPos) {
	this.style.pixelLeft = xPos;
	this.style.pixelTop = yPos;
}

With our menus now positioned and visible, we must make a couple of changes to the functions that handle the mouseover and mouseout events for the menu and the menu items.


Produced by Peter Belesis and

All Rights Reserved. Legal Notices.
Created: Apr. 08, 1998
Revised: Apr. 08, 1998

URL: http://www.webreference.com/dhtml/column18/menuFrPos.html