Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deactivate submenu on menu mouse leave #67

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 91 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,85 +1,116 @@
jQuery-menu-aim
===============

menu-aim is a jQuery plugin for dropdown menus that can differentiate
Menu-aim is a jQuery plugin for dropdown menus that can differentiate
between a user trying hover over a dropdown item vs trying to navigate into
a submenu's contents.
a submenu's contents. It's originally developed by [kamens](//github.com/kamens/).
You can check out original [project](https://github.com/kamens/jQuery-menu-aim) for reference
and creation history.

[Try a demo.](https://rawgithub.com/kamens/jQuery-menu-aim/master/example/example.html)
[Try a demo.](https://rawgit.com/banesto/jQuery-menu-aim/master/advanced_example/index.html)

![Amazon screenshot](https://raw.github.com/kamens/jQuery-menu-aim/master/amazon.png)
Menu-aim tries to solve accidental sibling submenu openings by detecting the direction of
the user's mouse movement. In the image blue triangle represents a possible movement area
for mouse cursor towards submenu edges when submenu will stay open until `defaultDelay` will end.
If mouse cursor moves out of this triange, then sibling submenu will pop up. This can make
for quicker transitions when navigating up and down the menu. The experience is similar to
Amazon's "Shop by Department" dropdown.

This problem is normally solved using timeouts and delays. menu-aim tries to
solve this by detecting the direction of the user's mouse movement. This can
make for quicker transitions when navigating up and down the menu. The
experience is hopefully similar to amazon.com/'s "Shop by Department"
dropdown.
![Amazon screenshot](https://raw.github.com/banesto/jQuery-menu-aim/master/amazon.png)

## Use like so:

$("#menu").menuAim({
activate: $.noop, // fired on row activation
deactivate: $.noop // fired on row deactivation
activateCallback: $.noop, // fired on row activation
deactivateCallback: $.noop // fired on row deactivation
});

...to receive events when a menu's row has been purposefully (de)activated.
You have to create activation and deactivation functions in you own page that could simply
add 'open' class to active submenu like that:

function activate(row) {
$(row).addClass('open');
}

function deactivate(row) {
$(row).removeClass('open');
}

The following options can be passed to menuAim. All functions execute with
the relevant row's HTML element as the execution context ('this'):

.menuAim({
// Function to call when a row is purposefully activated. Use this
// to show a submenu's content for the activated row.
activate: function() {},

// Function to call when a row is deactivated.
deactivate: function() {},

// Function to call when mouse enters a menu row. Entering a row
// does not mean the row has been activated, as the user may be
// mousing over to a submenu.
enter: function() {},

// Function to call when mouse exits a menu row.
exit: function() {},

// Function to call when mouse exits the entire menu. If this returns
// true, the current row's deactivation event and callback function
// will be fired. Otherwise, if this isn't supplied or it returns
// false, the currently activated row will stay activated when the
// mouse leaves the menu entirely.
exitMenu: function() {},

// Selector for identifying which elements in the menu are rows
// that can trigger the above events. Defaults to "> li".
rowSelector: "> li",

// You may have some menu rows that aren't submenus and therefore
// shouldn't ever need to "activate." If so, filter submenu rows w/
// this selector. Defaults to "*" (all elements).
submenuSelector: "*",

// Direction the submenu opens relative to the main menu. This
// controls which direction is "forgiving" as the user moves their
// cursor from the main menu into the submenu. Can be one of "right",
// "left", "above", or "below". Defaults to "right".
submenuDirection: "right"
});

menu-aim assumes that you are using a menu with submenus that expand
$("#menu").menuAim({
triggerEvent: "hover", // A means of activating submenu.
// It's either 'hover' or 'click' or 'both
rowSelector: "> li", // Selector for identifying which elements
// in the menu are rows
handle: "> a", // Handle for triggering mouse clicks on menu item
submenuSelector: "*", // You may have some menu rows that aren't submenus
// and thereforeshouldn't ever need to "activate."
// If so, filter submenu rows w/
// this selector. Defaults to "*" (all elements).
submenuDirection: "right", // Direction the submenu opens relative to the
// main menu. Can be left, right, above, or below.
// Defaults to "right".
openClassName: "open", // Class that will be applied to menu item
// when activated

tolerance: 75, // Bigger = more tolerant for mouse movement
// precision when entering submenu
activationDelay: 300, // Delay (ms) for first submenu opening
mouseLocsTracked: 3, // Number of past mouse locations to track direction
defaultDelay: 300, // Delay (ms) when user appears to be entering
// submenu and mouse movement is being tracked

enterCallback: $.noop, // Function to call when mouse enters a menu row.
// Entering a row does not mean the row has been
// activated, as the user may be
// mousing over to a submenu.
activateCallback: $.noop, // Function to call when a row is purposefully
// activated. Use this to show a submenu's
// content for the activated row.
deactivateCallback: $.noop, // Function to call when a row is deactivated.
exitCallback: $.noop, // Function to call when mouse exits a menu row.
exitMenuCallback: $.noop // Function to call when mouse exits whole menu.
// This is needed for autoclosing submenu
});

Submenus can be placed in multiple positions relatively to main menu - `left`, `right`, `above` or `below`.
By default menu-aim assumes that you are using a menu with submenus that expand
to the menu's right. It will fire events when the user's mouse enters a new
dropdown item *and* when that item is being intentionally hovered over.
menu item *and* when that item is being intentionally hovered over.

### Changing submenu open trigger

You can change submenu opening trigger from `hover` to `click`:

$("#menu").('switchToClick');

And from `click` to `hover`:

$("#menu").('switchToHover');

## Want an example to learn from?

Check out example/example.html -- it has [a working dropdown for you to play with](https://rawgithub.com/kamens/jQuery-menu-aim/master/example/example.html):
[Advanced Example](https://rawgit.com/banesto/jQuery-menu-aim/master/advanced_example/index.html) of submenus opening below main menu with ability to switch opening trigger on the fly:

![Advanced example screenshot](https://raw.github.com/banesto/jQuery-menu-aim/master/advanced_example.png)

[Bootstrap example](https://rawgithub.com/banesto/jQuery-menu-aim/master/example/example.html) with menu-aim applied to secondary menu which opens to right:

![Example screenshot](https://raw.github.com/kamens/jQuery-menu-aim/master/example.png)<br>
![Example screenshot](https://raw.github.com/banesto/jQuery-menu-aim/master/example.png)<br>
_Play with the above example full of fun monkey pictures by opening example/example.html after downloading the repo._

## FAQ
## Features

* UX enhancement for drop-down menus to achieve behavior when moving mouse cursor towards submenu through sibling menu item, current submenu stays open and sibling submenu does not open
* Ability to set first submenu activation delay - in case menu opening is optional and not crutial and is potentially annoying to users
* When mouse cursor leaves menu submenu autocloses (if set in 'hover' mode)
* When in 'click' mode, user can close submenu by clicking outside menu
* Ability to set whether submenu opens on 'hover' (default) or 'click'
* Ability to change submenu opening trigger on-the-fly

## Licence

Project lincensed under [MIT](http://en.wikipedia.org/wiki/MIT_License) license.

1. What's the license? [MIT](http://en.wikipedia.org/wiki/MIT_License).
2. Does it support horizontal menus or submenus that open to the left? Yup. Check out the submenuDirection option above.
3. I work at a big company that requires a version number on this third party code before I can use it. Do you have a version number? Sure, current version: 1.1
4. I'm not nearly bored enough. Got anything else? [Read about this plugin's creation](http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown).
Binary file added advanced_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
143 changes: 143 additions & 0 deletions advanced_example/css/component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
.cbp-hrmenu {
width: 100%;
border-bottom: 4px solid #47a3da;
}

/* general ul style */
.cbp-hrmenu ul {
margin: 0;
padding: 0;
list-style-type: none;
}

/* first level ul style */
.cbp-hrmenu > ul,
.cbp-hrmenu .cbp-hrsub-inner {
width: 90%;
max-width: 70em;
margin: 0 auto;
padding: 0 1.5em;
}

.cbp-hrmenu > ul > li {
display: inline-block;
background-color: #efefef;
}

.cbp-hrmenu > ul > li > a {
font-weight: 700;
padding: 1em 2em;
color: #999;
display: inline-block;
}

.cbp-hrmenu > ul > li > a:hover {
color: #47a3da;
}

.cbp-hrmenu > ul > li.cbp-hropen a,
.cbp-hrmenu > ul > li.cbp-hropen > a:hover {
color: #fff;
background: #47a3da;
}

/* sub-menu */
.cbp-hrmenu .cbp-hrsub {
display: none;
position: absolute;
background: #47a3da;
width: 100%;
left: 0;
}

.cbp-hropen .cbp-hrsub {
display: block;
padding-bottom: 2em;
}

.cbp-hrmenu .cbp-hrsub-inner > div {
width: 33%;
float: left;
padding: 0 2em 0;
}

.cbp-hrmenu .cbp-hrsub-inner:before,
.cbp-hrmenu .cbp-hrsub-inner:after {
content: " ";
display: table;
}

.cbp-hrmenu .cbp-hrsub-inner:after {
clear: both;
}

.cbp-hrmenu .cbp-hrsub-inner > div a {
line-height: 1.5em;
}

.cbp-hrsub h4 {
color: #afdefa;
padding: 1em 0 0.6em;
margin: 0;
font-size: 130%;
font-weight: 300;
}

/* Examples for media queries */

@media screen and (max-width: 52.75em) {

.cbp-hrmenu {
font-size: 80%;
}

}

@media screen and (max-width: 43em) {

.cbp-hrmenu {
font-size: 120%;
border: none;
}

.cbp-hrmenu > ul,
.cbp-hrmenu .cbp-hrsub-inner {
width: 100%;
padding: 0;
}

.cbp-hrmenu .cbp-hrsub-inner {
padding: 0 2em;
font-size: 75%;
}

.cbp-hrmenu > ul > li {
display: block;
border-bottom: 4px solid #47a3da;
}

.cbp-hrmenu > ul > li > a {
display: block;
padding: 1em 3em;
}

.cbp-hrmenu .cbp-hrsub {
position: relative;
}

.cbp-hrsub h4 {
padding-top: 0.6em;
}

}

@media screen and (max-width: 36em) {
.cbp-hrmenu .cbp-hrsub-inner > div {
width: 100%;
float: none;
padding: 0 2em;
}
}



Loading