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

No delay between adjacent menu items #6

Open
Grimmrobe opened this issue Mar 26, 2013 · 18 comments
Open

No delay between adjacent menu items #6

Grimmrobe opened this issue Mar 26, 2013 · 18 comments

Comments

@Grimmrobe
Copy link

Just an idea.. when moving sideways across a horizontal navigation with many large submenus, It would be less jarring visually to have no delay between the over and out of each submenu.

In other words: hoverintent is useful on the first hover but once the cursor is in the menu there could be a setting to remove the delay ( and act like a normal hover ) between over and out based on if target has same class etc...

@briancherne
Copy link
Owner

I cringe when someone references a specific implementation / use case. But I think it was appropriate to illustrate your point and overall I think this is a brilliant idea.

I can see a new configuration property (called "sharedIntent") with the default value set to false. A value of false would result in identical functionality to current/previous releases, thus not breaking any existing implementation.

When sharedIntent is set to true, a short timeout would be used to determine adjacency. That timeout would be triggered on mouse leave, and cleared on mouse enter. While the timeout is running, the intent-determining mouse move logic would be bypassed. Once the timeout's time is up, it'll reset the intent logic.

@usmonster
Copy link
Collaborator

You can also use event.relatedTarget to determine adjacency for free. (jQuery docs mention mouseover/mouseout, but should work with mouseenter/mouseleave as well--see also MDN docs)

@inquiztr
Copy link

Is there any chance of getting this feature in soon? I have been trying to modify it and use event.relatedTarget but am struggling with it.

@frankie-loves-jesus
Copy link

👍 brilliant

@usmonster
Copy link
Collaborator

@inquiztr Can you provide a jsfiddle or jsbin that simply demonstrates your issue when using event.relatedTarget?

@inquiztr
Copy link

Here is my attempt at it. It seems to work but the more i test it i see sometimes it misses triggering hovers sometimes:
http://jsfiddle.net/inquiztr/sk6L3dp4/

@usmonster
Copy link
Collaborator

usmonster commented Aug 31, 2014

I took a look, and I think this is the behavior @Grimmrobe wants: http://jsfiddle.net/sk6L3dp4/3/
(should probably instead use lastLeft = ob; or e.currentTarget in the mouseleave case to properly handle event delegation, but it's just a demo)

Though I'm not yet convinced the best way to do this is to build it into the plugin.

Similarly to #9, I would recommend simply using .hoverIntent once on the parent ul and again on the submenus (with interval: 0--this is important). The handler for the ul could simply toggle a class on it, and the one for lis could conditionally fire based on whether or not said class is present on the parent.

In more concrete terms, here's a general pattern that could potentially be used for such cases:

<elt>
    <child />
    <child />
    <child />
</elt>

And the JS:

$('elt').hoverIntent(function(){ $(this).toggleClass('hoverActive'); });
function doThing(e){
    if ( ! $(this).parent().hasClass('hoverActive') ) { console.log('nope!'); return; }
    if ( e.type === 'mouseenter' ) { console.log('hovering on and doing a thing!'); }
    else /* e.type === 'mouseleave' */ { console.log('hovering off and doing a different thing!'); }
}
$('elt child').hoverIntent({ interval: 0, over: doThing, out: doThing });
// or, using delegation:
//$('elt').hoverIntent({ interval: 0, over: doThing, out: doThing, selector: 'child' });

It's untested but probably produces the same desired effect, and without the need to add that specific new functionality to the plugin itself.

Thoughts @briancherne, @inquiztr, et al.?

@inquiztr
Copy link

inquiztr commented Sep 2, 2014

Thanks @usmonster. I am a javascript novice and going through your jsfiddle you provided: http://jsfiddle.net/sk6L3dp4/3/ Could you explain your condition here, specifically I am not familiar with the !! in the condition:
(cfg.sharedIntent && !! lastLeft && e.relatedTarget == lastLeft && lastLeft.hoverIntent_s)

But it seems to be working great, and I am thinking of using it in my project.

As for your other suggestion about adding hoverIntent to both the parent and children separately with different intervals is a pretty cool and elegant idea that I will try as well. But I am wondering, how would the initial "500ms"delay" happen. I would imagine as your mouse moves onto a child for the first time, the parent UL hover would be still in the delay, while the child hover triggers doThing right away.. but as the parent hasnt triggered yet, nothing would happen.

@usmonster
Copy link
Collaborator

Hi @inquiztr. Of course I'll explain. :]

The !! is basically just one way of casting something to a boolean. Intuition: A single ! before something will evaluate false if the object is "truthy" or true if it is "falsey." The second ! negates again and gives back the proper boolean value that represents the truthiness/falsiness of the original object. I could have just as easily left them out in the condition and had the same result, since the evaluated object will already either be "truthy" (the last element that triggered a hoverIntent mouseleave event) or "falsey" (null/undefined), which is good enough for any condition expression.

As for how my double-hoverintent suggestion works, well.. it actually probably doesn't work. I haven't tested, but your concern is justified, as that's exactly what would happen. There's a missing part, and I haven't had a chance to think it through to the point where it's not messy. I will try to get back to you on that.

@frankie-loves-jesus
Copy link

@usmonster hi there! Is your fiddle ready for a PR by any chance? Many thanks!

@usmonster
Copy link
Collaborator

@frankie-loves-jesus No, I haven't worked towards that yet. I think there's still some discussion and reflection to be done, and I also haven't had time to think about the alternative approach. I'll update here when I have something, but I'm pretty certain there's a general pattern that could be used to achieve this same behavior with the current version of the plugin.

@ghost
Copy link

ghost commented Oct 14, 2014

+1

@ghost
Copy link

ghost commented Oct 16, 2014

https://github.com/digital-chemist/dropdownMenus
here is what i have used to get the plugin to achieve no delay between siblings using event.relatedTarget;

index2 uses css3 animation to open and close the menu and a callback of some sorts needs to be added so the menu "text" doesnt appear until the menu is fully open...but you get the point

cheers, hope it helps

@usmonster
Copy link
Collaborator

Just had a chance to think about this again, and I came up with something a bit simpler but not far off from what I'd previously proposed above.

The principle is exactly the same, but instead of using .hoverIntent twice--once for the parent, once for the children--it's only used once for the parent, along with a regular hover (mousenter/mouseleave) handler for the children. Here's the modified jsFiddle in action:

http://jsfiddle.net/sk6L3dp4/5/
(Note that this uses the current, unmodified version of the plugin.)

As before, hoverIntent is used to toggle the active state of the parent, but it also re-triggers a mouseenter on the currently-hovered child. The normal hover handler(s) on the children will track said hovered child for the hoverIntent handler, but will only trigger the menu if the parent has been "activated" (i.e., hoverIntent's over has been triggered).

Here's an even simpler version that doesn't need to explicitly track the currently-hovered child element, and which would work perfectly if only issue #11 were resolved (@briancherne, let me know if I can/should make a PR for that):
http://jsfiddle.net/sk6L3dp4/7/

Again, these are general patterns that nicely and simply handle the "shared intent" use case without the need to add any new functionality to hoverIntent. I'm still not convinced the whole sharedIntent/event.relatedTarget business needs to be a feature of the plugin, but it's definitely a good thing to discuss. In any case, it's ultimately up to @briancherne to decide.

Hope this helps! (Also, please let me know if I've missed anything..)

@frankie-loves-jesus
Copy link

This is mighty fine work @usmonster! I just wish @briancherne was around to enjoy it.

@usmonster
Copy link
Collaborator

Thanks, @frankie-loves-jesus. Brian's away from computers for a bit, he should be back online in a few weeks.

@briancherne
Copy link
Owner

A few weeks... more like a few months... 😕

@frankie-loves-jesus - Does resolving issue #11 resolve this issue using @usmonster's workaround above? Or do you still feel the need for an adjacency check?

Re-reading my initial comment, I think the reason I was leaning towards sharedIntent (while slightly more convoluted, code-wise) is that it would allow for non-adjacent/related blocks to share intent.

@frankie-loves-jesus
Copy link

There he is -- welcome back @briancherne!

About the adjacency check, I think you meant to hit @Grimmrobe with that one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants