joeldbirch / superfish

Superfish is a jQuery plugin that adds usability enhancements to existing multi-level drop-down menus.
Other
912 stars 315 forks source link

hoverIntent required for touch in IE10 and certain Android browsers #46

Open joeldbirch opened 11 years ago

joeldbirch commented 11 years ago

Rolling #29 and #24 into one issue.

Looking for an elegant fix for this issue. It will likely hang around for a while. Feel free to have a go at solving it for me!

joeldbirch commented 11 years ago

Tagged "wontfix" for now, in lieu of a "toohardbasket" tag.

ghost commented 10 years ago

Hi joeldbirch,

i think I'm experiencing the same problem as described in #29 but I was wondering how I can go about implementing the "hoverIntent work around", can you provide any instructions? The URL to my page: www.quaaoutlodge.com/drupal-7.30/ Oh, this page is based on the Skeleton theme on Drupal 7.x and also, I have "Enable hoverIntent detection." under "SUPERFISH PLUGINS" selected - is there anything else I should do? Seems like I was able to figure it out and resolve the issue by selecting "Enable jQuery sf-Touchscreen plugin for this menu." under "SUPERFISH PLUGINS - SF-TOUCHSCREEN" in "Home » Administration » Structure » Blocks" - just in case any one else finds this issue...

IanLunn commented 10 years ago

What is the reason for this being difficult to implement please? I may look in to it. Can't the script preventDefault() on first click, then allow navigation on the second? Is it not as simple as that?

IanLunn commented 10 years ago

I see the problem with this now. It seems there is no way to distinguish between what is a touch and click in IE10/11.

If you disable hoverIntent, a link is immediately navigated to in IE10/11 when the device has touch and click capabilities, as described in #24. A nasty work-around for this is to apply a timer to the following in the over() function:

setTimeout(function() {
    clearTimeout(o.sfTimer);
    $this.siblings().superfish('hide').end().superfish('show');
}, 100);

I believe the timer gives the events a chance to execute in an order that prevents navigation on the link prior to opening the menu. I guess this is replicating what hoverIntent is doing with its own delay.

Of course, if you disable hoverIntent, with the above workaround you're adding a delay back in so it's catch 22. You may also want to wrap the above code in some logic that only applies to IE10/11 on devices that have touch and click capabilities, that way you at least remove the delay from browsers other than IE10/11.

joeldbirch commented 10 years ago

Hey, sorry for the delayed reply, and I can't go into detail at the moment. Anyway, yes it's not as simple as it seems, as you know. I have tried all sorts of techniques, including the timer you mentioned as well as setting a "nofollow" flag on touch and removing it after the opening animation ends. I also tried using .one('click') handlers to then allow links to be followed. All of these efforts ran into one or more issues with differences in event models between various devices and browsers. The only glimmer of light I found was using hand.js to polyfill PointerEvents, but alas, Chrome has decided to back out of implementing that, so exploring further down that path feels like a deadend. :-1:

RohitSethia commented 9 years ago

Hey,

Actually I have managed to get this working on Android Devices seemlessly. Just wanted to provide the fix I have used.

Firstly, I have made the check only for a Android Device and then checked whether the Menu Item which we are clicking has the class sfHover . If it has the Class, then the default action will continue on clicking, else it will first open the sub-menu and then on the 2nd click it will perform the default action.

var $ = jQuery.noConflict();

var YOURAPPLICATION = YOURAPPLICATION || {};

(function($){

    // USE STRICT
    "use strict";

    YOURAPPLICATION.header = {

        init: function(){

            YOURAPPLICATION.header.superfish();
            YOURAPPLICATION.header.menufunctions();

        },

        superfish: function(){

            if ( $().superfish ) {

                $('#primary-menu > ul').superfish({
                    popUpSelector: 'ul,.mega-menu-content',
                    delay: 250,
                    speed: 350,
                    animation: {opacity:'show'},
                    animationOut:  {opacity:'hide'},
                    cssArrows: false
                });

            }

        },

        menufunctions: function(){

            $( '#primary-menu ul li:has(ul)' ).addClass('sub-menu');

            if( YOURAPPLICATION.isMobile.Android() ) {
                $( '#primary-menu ul li.sub-menu' ).children('a').on('touchstart', function(e){
                    if( !$(this).parent('li.sub-menu').hasClass('sfHover') ) {
                        e.preventDefault();
                    }
                });
            }

        }

    };

    YOURAPPLICATION.isMobile = {
        Android: function() {
            return navigator.userAgent.match(/Android/i);
        },
        BlackBerry: function() {
            return navigator.userAgent.match(/BlackBerry/i);
        },
        iOS: function() {
            return navigator.userAgent.match(/iPhone|iPad|iPod/i);
        },
        Opera: function() {
            return navigator.userAgent.match(/Opera Mini/i);
        },
        Windows: function() {
            return navigator.userAgent.match(/IEMobile/i);
        },
        any: function() {
            return (YOURAPPLICATION.isMobile.Android() || YOURAPPLICATION.isMobile.BlackBerry() || YOURAPPLICATION.isMobile.iOS() || YOURAPPLICATION.isMobile.Opera() || YOURAPPLICATION.isMobile.Windows());
        }
    };

    YOURAPPLICATION.documentOnReady = {

        init: function(){
            YOURAPPLICATION.header.init();
        }

    };

    $(document).ready( YOURAPPLICATION.documentOnReady.init );

})(jQuery);

Here is the Gist: https://gist.github.com/RohitSethia/0d45fe0ab06721e96fff .

Hope this Help. :+1: