Pop-Up Menus | |||||||
The item layers are taken in order and as each is positioned it's resulting
height is found and used to update a running total so that the next can be
positioned just below it. When the last item has been built, the full height of
the menu can be determined and the layers making up the base and bevel can
be properly clipped.
Automatically Building Submenus Once a menu has been built and added to a page, the last step is to check each item to see if a submenu was assigned to it. If so, the create() method is called for that submenu. This recursively builds all submenus so you only need to call create() for your top-level menus. Each menu has a created property that is set to true once the create() method has been called for it. This prevents errors if you should inadvertently attempt to create a menu that has already been built along with it's parent or ancestor. Setting the Item Text Appearance As each item layer is built, HTML code is generated by wrapping the given item text with <SPAN></SPAN> tags to specify a CSS style for the text font based on the menu definition. This code is then wrapped by <TABLE></TABLE> tags to set up the proper spacing around the text. If the menu has no submenus assigned to any of it's items, a single table cell is used for the text. But if one or more items does have a submenu, two table columns are used. The left contains the text and the right contains an image, either the menu's arrow gif or a transparent gif used as a spacer. This allows the text of each item to be properly aligned with the others. Tracking Mouse Position The script captures the onmouseover event for the page to keep track of the current mouse position. The coordinates are stored in the global variables mouseX and mouseY. These coordinates are used in positioning menus and to help in the opening and closing of menus and submenus (see details below). Positioning Menus When the open() method is called for a window it's position is set depending on several factors. Submenus are always positioned relative to their parent menu item. If the resulting position would place part of the submenu past the viewable area of the window, it is adjusted so that the entire menu is visible. Top-level menus are handled differently. If the isStatic flag is true the menu's current coordinates will be used. These default to (0,0) but can be changed by the moveMenuTo() and moveMenuBy() methods. If not static, the menu is positioned according to the current mouse position, just like a submenu. The open() method optionally takes x and y arguments. If these are given for a top-level menu, they take precedence and will be used even it they place the menu outside of the viewable page area. Once positioned, the menu is made visible and it's current position is saved within the menu object itself. Event Capturing In all, four event handlers are used to control menu behavior. For each item in a menu the onmouseover, onmouseout and onclick (IE) or onmouseup (NS) events are captured. For the menu's base layer the onmouseout event is captured. The event handlers assigned to these control the actions of the menu and submenus. Event handlers are given an implied reference to the object that fired them. With the above events that will be the layer itself, not the menu or item object to which it belongs. So when the event capturing is defined for any layer a new targetMenu and/or targetItem property is added to it and assigned a pointer to the owning menu or item object. This allows the event handler functions to easily reference the menu or item itself. Creating the Item Highlight Effect As illustrated above, each item consists of three layers. The top, transparent layer is set up to capture mouse over, mouse out and mouse click events. The highlight layer is initially made invisible, allowing the normal layer to be seen. When a mouseover occurs, the highlight layer is made visible. On a mouseout it is hidden again, restoring the normal appearance. Controlling Menus and Submenus In addition to highlighting items there is also the need to control the opening and closing of menus and submenus. This can get complicated because the event models in Netscape and IE differ greatly and different actions are required depending on the circumstances. Here's an example. In the case illustrated below, the mouse starts on an item with a submenu which has been opened. When the mouse moves off this item, it may have gone onto the submenu, in which case both menus need to be kept open.
But, if the mouse has moved to the second item, the first submenu must be closed and a new one opened.
Finally, if the mouse has moved completely off both menus, both should be closed (unless the main menu has been made static, then only the submenu should be closed). To help keep track of each menu's state and their relationships to each other some additional properties are defined for menu.
With these set the event handlers can properly control how and when the submenus should appear. Here is a brief overview of the logic in each. Item onmouseover
Item onmouseout
Menu onmouseout
*This is necessary because in IE events bubble up from child elements, including the bevel and item layers, the HTML tags surrounding the item text and the item text itself. When the mouse moves onto these, an onmouseout is first fired for the menu. Also note that in IE, the current mouse coordinates are updated using the values in the global event object. This is necessary because the onmousemove handler for the page may not fire before the onmouseout for the menu. So this function will update the global mouseX and mouseY values to use the most current values. Window Resizing Netscape browsers will lose track of DHTML elements when the browser window is resized. In order to ensure that the menu appears correctly, the window resize event is captured for both Netscape and IE. When a resize occurs, the entire page is reloaded by the popUpMenuReload() function, causing the menus to be rebuilt. Note that some early releases of Netscape 4 have a bug that can cause a resize event to fire even when the window has not be resized. To correct this, the width and height of the window is saved at load time. On a resize, these are checked against the current width and height and a reload occurs only if the size has indeed changed. To keep the behavior consistent with IE, resizes are handled the same way. However, when resizing an IE browser by dragging the window border, the 'Show window contents while dragging' display option on Windows platforms will cause the event to fire before the window can be resized, canceling the drag. This means the user would be unable to resize the browser via dragging. To prevent this, a setTimeout() is used to reload the page. This allows the user a couple of seconds to resize the browser before the page gets refreshed and cancels the user drag action.
The script is fairly large, so if you are concerned about download time use the condensed popcond.js version which can be used in place of the dhtmllib.js and popupmenu.js files (21K vs. 37K). It contains all the code in the other two files but has been stripped of most comments and formatting. You can also download popupmenu.zip (52K) which contains all the JavaScript code files, documentation, examples and graphics.
|
|||||||
Home |