Created
August 2, 2010 15:35
-
-
Save unruthless/504814 to your computer and use it in GitHub Desktop.
jQuery snippet to handle global navigation behavior
Thanks for the suggestions, Michael! I've implemented (1) and (3), started implementing (4), and am studying how best to implement (2). That function's a tricky one -- how to close the menu when something is moused over, where that something is neither the active menu nor the active menu's dropdown anchor.
Not so tricky. In that case, just bind it when you need it, and unbind it when you don't. Something like this:
(function() {
var activeDropdown,
activeMenu,
activeMenuClass = 'droppeddown',
activeParent,
// Deactivates the current menu
deactivateMenu = function() {
if (activeDropdown) {
activeDropdown.removeClass(activeMenuClass);
activeMenu.hide();
}
},
activeExpander,
activeSubmenu,
activeSubmenuClass = 'expanded',
// Deactivates the current submenu
deactivateSubmenu = function() {
if (activeMenu) {
activeMenu.find('.expander').removeClass(activeSubmenuClass);
activeMenu.find('.submenu').hide();
}
},
// Deactivates menu when outside element is moused over
deactivateAll = function(e) {
if (typeof e !== 'object' || !activeParent) {
return;
}
var parentElement = activeParent[0];
if ( !$.contains(parentElement,e.target) || !parentElement == e.target ) {
deactivateSubmenu();
deactivateMenu();
// we don't need this function anymore. Unbind it.
$(document.body).unbind('mouseover', deactivateAll);
}
};
// Iterate through each dropdown
$('.dropdown').each(function() {
var dropdown = $(this),
menu = dropdown.next('.menu'),
parent = dropdown.parent();
// Activates this dropdown's menu
var activate = function() {
deactivateMenu();
activeDropdown = dropdown.addClass(activeMenuClass);
activeMenu = menu.show();
activeParent = parent;
// Deactivates menu when outside element is moused over
$(document.body).bind('mouseover', deactivateAll);
};
// Activates menu when mouseovered
dropdown.bind('mouseover',function(e) {
if (e) {
e.stopPropagation();
}
activate();
});
// Activates menu when focused
dropdown.bind('focus',function() {
activate();
});
});
// Iterate through each expander
$('.expander').each(function() {
var expander = $(this),
submenu = expander.next('.submenu');
// Toggles this expander's submenu
var toggle = function() {
activeExpander = expander.toggleClass(activeSubmenuClass);
activeSubmenu = submenu.slideToggle();
}
// Toggles submenu when clicked
expander.bind('click',function(e) {
if (e) {
e.stopPropagation();
e.preventDefault();
}
toggle();
});
});
})();
Michael, that's brilliant. Beers on me at the next Build Guild. Thank you so much.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Ruth -
Looks good overall. A few suggestions, though:
you can try this:
It's good that you're using one function to bind a single event which triggers the menu behavior, but using a mouseover event on the document.body is going to fire that function every time the cursor enters the bounds of any element anywhere on the page - in other words, constantly. Not very efficient. In most cases, it'd be best to bind the event to the parent element of the menus and that's it.
You probably don't need e.preventDefault() on mouseover events, as there is no default action for that event.
Any string that you've used more than once ('droppeddown', 'expander', 'expanded') should probably be set to a variable that's global to the closure, so the string is only set once. This helps with keeping file size down when minimizing. If you want to be really consistent, set all your strings to closure-global variables, and just refer to the variable names throughout the code.
Cheers,
M