The hover delay solution: hoverIntent
To prevent the unwanted triggering of menus, and the irritating queuing of a whole sequence of show and hide events, we need to implement a short delay in the aORliEnter function. To accomplish this I personally prefer Brian Cherne's jQuery plugin hoverIntent. It's a more sophisticated algorithm than a simple delay. To quote Brian's web site:
hoverIntent is a plug-in that attempts to determine the user's intent... like a crystal ball, only with mouse movement! It works like (and was derived from) jQuery's built-in hover. However, instead of immediately calling the onMouseOver function, it waits until the user's mouse slows down enough before making the call.
That said, to complete this tutorial we'll go ahead and implement a simple delay functionality, then show how to autodetect hoverIntent and override that with Brian's more sophisticated algorithm.
Delaying the "show" function on aORliEnter
When the cursor enters an element and triggers an "enter" event, a timer is set up to provide a short delay before responding. If a "leave" event is triggered before the delay is finished, the delay and the response to the "enter" event are both cancelled.
To implement this, the first lines of the main function object are modified to the following:
- var duration = 500;
- var effect = "slide";
- var sliverW = 5;
- var hDelay = 200;
- var toTimer = undefined;
- var toLI = undefined;
- if (opts.duration) duration = opts.duration;
- if (opts.effect) effect = opts.effect;
- if (opts.sliverW) sliverW = opts.sliverW;
- if (opts.hDelay) hDelay = opts.hDelay;
Lines 5, 6, 7 and 12 were added to provide some main function variables to manage the timer event.
- hDelay is the delay period in ms
- toTimer is the handle for the time-out timer
- toLI temporarily stores the target hover <li> element that triggered the hover event
aORliEnter
Next, all but the first line of the aORliEnter function is moved to a callback function declared as follows:
- function doEnter(newLI) {
This function will now handle showing and hiding of submenus, and will be called only after the appropriate delay. The main aORliEnter event function is next modified as follows:
- function aORliEnter(eo) {
- var newLI = GetHoverLI(eo.target);
- if (toTimer) {
- if (toLI.is(newLI ))
- return;
- else {
- clearTimeout(toTimer);
- toTimer = undefined;
- toLI = undefined;
- }
- }
- if (hDelay > 5) {
- toLI = newLI;
- toTimer = setTimeout(doEnter, hDelay);
- } else
- doEnter(newLI);
- }
If "toTimer" is defined, then test to see if this is a redundant call by comparing the previously stored, and not yet used, <li> hover element with the target <li> hover element of this event. If they're the same, return and do nothing. If not, clear the timeout and reset "toTimer" and "toLI".
Next, if the delay is not greater than 5 ms, then don't schedule a delay and just call the doEnter function directly. Otherwise, set up a delay timer to call doEnter after the delay.
Note that all the browsers but IE support setting up parameters for the callback by adding them as the 3rd, 4th, etc. parameters of the setTimeout function. This could be done by changing line 14 above to:
- 14. toTimer = setTimeout(doHoverEnter, hDelay, newLI);
Unfortunately, since IE doesn't support these callback parameters, "toLI" is required to store the new hover <li> element for the callback. Doing it this way allows the code to work for all browsers, including IE.
aORliLeave and ulLeave
Finally, aORliLeave and ulLeave are modified to test "toTimer", and if it is defined, then the timeout is cleared and "toTimer" and "toLI" are reset. After that, they proceeds as before.
Conclusion
Here is the previous example page, but now with the delay added. The irritating problem of waiting for many queued events to clear can still occur, but only if the duration is much greater than the delay. For example, if you set up a delay of 100 ms and a duration of 1000 ms, you can trigger up to ten enter events while the first animation is running its course. So some care must be taken regarding the choice of duration and delay. You can download the final javascript here.
One might also wish to prevent the immediate closure of all menus if the cursor momentarily leaves the menu tree. It might be nice to provide a short delay before allowing the ulLeave event to take action. But to do so, you would have to code a second time out. And why bother when hoverIntent handles the situation so nicely. Note that the final version of the javascript code autodetects hoverIntent and makes use of its capabilities rather than the internal delay. But if hoverIntent is not available, then the coded delay handles the situation nicely.
Also note that with a properly implemented delay, the 'portal' effect operates nicely. Try it out here.
Animation: A-1 A-2 [A-3] Touch-Screen Tablets