- HTML Refactoring
- Menu Support Functions with the jQuery Library
- Summary
Menu Support Functions with the jQuery Library
The old JavaScript code supporting the drop-down menu is pretty complex due to the ID-based object selection. Its underlying principles are quite simple, as it only has to support two different event types:
- Click on a top-row item.
- Click on an item in a drop-down box.
Clicking on a drop-down box is very simple to implement: The drop-down box should be hidden and the corresponding top-row item "unpressed." The default click-on-link action takes care of the rest (the browser follows the link to the destination).
Clicking on a top-row item is slightly more complex. Whenever a top-row item is clicked, any already opened drop-down box has to be hidden first (to implement the familiar[md]and thus expected[md]drop-down menu behavior), and then the selected drop-down box must be displayed or hidden. The class of the clicked item should also be changed to indicate that it has been pressed.
We could implement the code as I've just described, but there's another optimization opportunity. Assuming that we have a function that hides all drop-down boxes, we can use it as follows:
- For a click in the drop-down box: We can safely hide all drop-down boxes, as we know all of them except the current one are hidden anyway.
- For a click on a top-row button: We have to hide all other drop-down boxes anyway, so we might as well hide all of them and show the selected one if it hasn't been opened before the click.
With this optimization, the click-on-link event handler becomes pretty simple. We have to find the parent element of the current link and figure out whether it's a top-row item (checking whether it has sibling DD elements), hiding all drop-down boxes otherwise:
function menuClick() { var parent = $(this).parent('P,DT'); var dropdown = parent.siblings('DD'); if (dropdown.length) { /** click on a top-row item with drop-down menu **/ } else { hideDropDown(parent); } }
The code that handles the click on a top-row item has to remember its state, hide all drop-down boxes, and show the current one if it hasn't been opened previously.
We use the is jQuery function to check whether the down class has been applied to the parent element and (if needed) apply the down class to the parent and display the drop-down part of the menu:
var isDown = parent.is('.down'); hideDropDown(parent); if (!isDown) { parent.addClass('down') dropdown.show(); }
The hideDropDown function could use the ID of the menu DIV element or its class to find it and act on all its children. However, it's better to find the top-level DIV element as an ancestor of the clicked link; this approach allows us to use the same code for multiple menus on the same page (and even repurpose it other uses[md]for example, the left sidebar menu). We'll use the parents jQuery method find the ancestor DIV element and then use the find method on its results to find the DT and DD descendants of the DIV:
function hideDropDown(objSet) { objSet.parents('DIV:first') .find('DT').removeClass('down').end() .find('DD').hide(); }
Finally, we have to bind the onclick event handler to the links within the menu. The following lines of code declare an anonymous function that is used as a document ready callback:
$(function(){ $("#topRowMenu").addClass("topRowMenu") .find("a").click(menuClick); })
The function finds the top-row menu using its ID, sets a class that converts the DIV into a full-blown drop-down menu, and binds the menuClick function to the onclick events of all links within the menu.