How to allow for a default submenu on a jQuery hover menu
Asked Answered
L

1

1

This started from a related question. After getting a brilliant answer I ran into an unforeseen gap in functionality: how can I show a menu open by default?

More specifically if a user lands on a page that exists in my sub-nav I want to have that sub-nav open with the current page highlighted. If they use the menu to browse around it will change accordingly, but always go back to the default state if they don't make a selection.

The code I'm basing this off can be found in this jsfiddle.

The menu structure is like:

<div id="mnav">
    <ul id="buttons">
        <li class="one"><a href="#">Main 1</a></li>
        <li class="two"><a href="#">Main 2</a></li>
        <li class="three"><a href="#">Main 3</a></li>
        <li class="four nav-dark"><a href="#">Main 4</a></li>
    </ul>
</div><!-- /mnav -->
<div id="snav">
    <ul class="snav-one">
        <li><a href="#">Sub 1.1</a></li>
        <li><a href="#">Sub 1.2</a></li>
        <li><a href="#">Sub 1.3</a></li>
    </ul>
    <ul class="snav-two">
        <li><a href="#">Sub 2.1</a></li>
        <li><a href="#">Sub 2.2</a></li>
    </ul>
</div><!-- /snav -->


It was suggested that the basic idea is on hover-out to set things back to the way they were and that makes perfect sense, but how do you save the initial state the menu is in?

Long answered 27/5, 2011 at 15:43 Comment(2)
Linking to jsFiddle is good, but Questions will get more votes and answers if the relevant code is also included in the question body. :)Claviform
Thanks for the heads up Brock.Long
C
2

Based on that jsFiddle code, one approach would be:

  1. The server sets a global variable in the page GBL_bNoDefaultMenu to true or false depending on whether that page has a default sub-menu. (JS could set the variable in ajaxified pages.)

  2. The server also marks the default sub-menu with the class defaultMenu.
    EG: <ul class="snav-two defaultMenu">

  3. Be sure the page has a style like:

    #snav ul.defaultMenu {
        display: block;  /* Or the correct visible display mode.*/
    }
    
  4. Then code like the following should work.
    Notice that all of the main-nav buttons need a hover now. Also, Everything's been consolidated into one hover() call. And depending on the production page, further simplification may be possible.

See the demo at jsFiddle.

$("#buttons li, #snav ul").hover (function (zEvent) {MenuOpenCloseErgoTimer (zEvent); } );

function MenuOpenCloseErgoTimer (zEvent)
{
    var dDelay;
    var ActionFunction = null;

    if (zEvent.type == 'mouseenter')
    {
        if (zEvent.currentTarget.nodeName  == 'LI')        //-- Main nav.
        {
            dDelay          = 300;
            ActionFunction  = function (node) {
                //--- The first class is a special tie to a submenu, if it exists
                var subnav = 'ul.snav-' + $(node).attr ('class').split (' ')[0];
                $("#snav ul").hide ();
                $("#snav").find (subnav).show ();

                //--- Not sure what's going on with the "open" class.  It's irrelevant to this demo.
                if (GBL_bNoDefaultMenu)
                    $("#snav").stop (true, true).slideDown ('fast').addClass ("open");
            };
        }
        else //-- zEvent.currentTarget.nodeName  == 'UL'   //-- Sub nav.
        {
            dDelay          = 0;
            ActionFunction  = function (node) {
                $(node).show ();

                if (GBL_bNoDefaultMenu)
                    $("#snav").stop (true, true).slideDown ('fast').addClass ("open");
            };
        }
    }
    else //-- zEvent.type == 'mouseleave'
    {
        //--- Actions for main nav and sub nav are the same.
        dDelay          = 200;
        ActionFunction  = function (node) {
            if (GBL_bNoDefaultMenu)
                $("#snav").stop (true, true).slideUp ('fast').removeClass ("open");
            $("#snav ul").hide ();
            $("#snav ul.defaultMenu").show ();
        }
    }

    if (typeof this.delayTimer == "number")
    {
        clearTimeout (this.delayTimer);
    }
    this.delayTimer     = setTimeout (function() { ActionFunction (zEvent.currentTarget); }, dDelay);
}
Claviform answered 29/5, 2011 at 4:23 Comment(1)
I added a conditional to set the global var and show #snav if needed. I also added a conditional inside the GBL_bNoDefaultMenu 'LI' block of code that checks to see if the snav it's trying to open even exists. Check out my jsFiddle.Long

© 2022 - 2024 — McMap. All rights reserved.