dbushell/Responsive-Off-Canvas-Menu

Allow menu to be dismissed on touching the partial off-screen content (iOS)

paulrobertlloyd opened this issue · 3 comments

From my limited to reading on the matter, for elements that are not links or buttons, iOS doesn’t translate click events to ontouchstart; therefore touching outside the menu doesn’t work in iOS.

The click event listener line for reference.

Looks like I was trying to be too clever for my own good :) This needs more thought/testing obviously, but maybe something along the lines of:

var close_event = ('ontouchstart' in window) ? 'touchstart' : 'mousedown';

document.addEventListener(close_event, function(e)
{
    if (nav_open && !hasParent(e.target, 'nav')) {
        e.preventDefault();
        app.closeNav();
    }
},
true);

Problem is that it will probably cancel any attempts to scroll vertically if the user touches the right-hand side (i.e. not the nav element). You'd want a slight delay to ensure the touchend, touchcancel or mouseup happen within 200–300ms.

Cheers, I’ll give that a go. Meanwhile, I used some CSS:

.touch #inner-wrap {
    cursor: pointer;
}

In the past when working with dropdown-type interface elements I've implemented this functionality (modified to make sense here) to best-guess whether or not a user is scrolling:

$(document).on('click touchstart touchend', function(e) {

    var touch;
    var sensitivity = 20;
    var closeThis  = function() {...};

    // Distinguish scroll from a 'tap'
    if ( e.type === 'touchstart' && e.originalEvent.touches.length === 1 ) {
        touch = {
            x: e.originalEvent.touches[0].pageX,
            y: e.originalEvent.touches[0].pageY
        };

        return;
    }

    if ( e.type === 'touchend' ) {
        var difX = Math.abs(touch.x - e.originalEvent.changedTouches[0].pageX);
        var difY = Math.abs(touch.y - e.originalEvent.changedTouches[0].pageY);

        touch = undefined;

        if ( difX > sensitivity || difY > sensitivity ) {
            return;
        }
    }

    closeThis();

});

EDIT: I guess this is actually simpler but I seem to remember changedTouches is/was a bitch:

$(document).on('click touchend', function(e) {

    var closeThis  = function() {...};

    if ( e.type === 'touchend' && e.originalEvent.changedTouches.length ) {
        return;
    }

    closeThis();

});