Skip to content

Commit

Permalink
fix click-preventing, again
Browse files Browse the repository at this point in the history
click prevention now cancelled by ANY *down/*start event
(previously it was limited to elements with `taphold` listeners)

refactor to use dynamically attached listeners instead of permanent
  • Loading branch information
johndoe committed Dec 23, 2019
1 parent 2d67a5f commit 5f06945
Showing 1 changed file with 50 additions and 48 deletions.
98 changes: 50 additions & 48 deletions taphold.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
(function ($) {
var preventClick = false;
function namespaced (name, ns) {
return name.replace(/\w+/g, '$&'+ns);
}

var startevent = namespaced(window.PointerEvent ? 'pointerdown' : 'touchstart mousedown', '.taphold');

var preventClick = {
isActive: false,

handler: function (event) {
preventClick.off();
event.stopPropagation();
event.preventDefault();
},

off: function () {
document.removeEventListener('click', preventClick.handler, {capture: true});
$(document).off('.enableclick');
preventClick.isActive = false;
},

on: function () {
if (!preventClick.isActive) {
preventClick.isActive = true;
$(document).on(namespaced(startevent,'.enableclick'), preventClick.off);
// https://stackoverflow.com/a/20290312/2520247
// Note: listeners directly attached to element may skip capture phase
// that's why we add add our click-preventing handler to `document`
document.addEventListener('click', preventClick.handler, {capture: true});
// https://github.com/jquery/jquery/issues/1735
}
}
};

var _cancel = '.taphold.cancel';
var cancelevent = {
pointerdown: namespaced('pointerup pointercancel pointerout', _cancel),
touchstart: namespaced('touchend touchmove touchcancel', _cancel),
mousedown: namespaced('mouseup mouseout dragstart', _cancel)
};

function startHandler (event) {
var data = event.data;
if (event.originalEvent.isPrimary === false) { return; }
Expand All @@ -8,73 +48,35 @@
} else if (event.touches) {
if (event.touches.length !== 1) { return; }
}
preventClick = false;
var $elem = $(this);
data._timer = setTimeout(function () {
data._timer = null;
var _timer = setTimeout(function () {
$elem.off(_cancel);
$elem.triggerHandler($.Event('taphold', {target: event.target}), data);
if (event.type === 'touchstart' || event.pointerType === 'touch') {
// prevent simulated mouse events https://w3c.github.io/touch-events/#mouse-events
$(elem).one('touchend', data, function (e) { e.preventDefault(); });
$elem.one('touchend', data, function (e) { e.preventDefault(); });
} else {
preventClick = true;
preventClick.on();
}
}, data.delay);
$elem.on(cancelevent[event.type], data, function () {
$elem.off(_cancel);
clearTimeout(_timer); // cancel taphold
});
}

function cancelHandler (event) {
var data = event.data;
if (data._timer) {
clearTimeout(data._timer);
data._timer = null;
}
}

function preventClickHandler (event) {
if (preventClick) {
preventClick = false;
event.stopPropagation();
event.preventDefault();
}
}

function namespaced (name) {
return name.replace(/\w+/g, '$&.taphold');
}
var startevent, cancelevent;
if (window.PointerEvent) {
startevent = namespaced('pointerdown');
cancelevent = namespaced('pointerup pointercancel pointerout');
} else {
startevent = namespaced('touchstart mousedown');
cancelevent = namespaced('touchend touchmove touchcancel mouseup mouseout dragstart');
}

var counter = 0;
$.event.special.taphold = {
defaults: {
delay: 500
},

setup: function (data) {
data = $.extend({}, $.event.special.taphold.defaults, data);
$(this)
.on(startevent, data, startHandler)
.on(cancelevent, data, cancelHandler);
if (counter++ === 0) {
// https://stackoverflow.com/a/20290312/2520247
// Note: listeners directly attached to element may skip capture phase
// that's why we add our click-preventing handler to `document`
document.addEventListener('click', preventClickHandler, {capture: true});
// https://github.com/jquery/jquery/issues/1735
}
$(this).on(startevent, data, startHandler);
},

teardown: function () {
$(this).off('.taphold');
if (counter-- === 1) {
document.removeEventListener('click', preventClickHandler, {capture: true});
}
}
};
})(jQuery);

0 comments on commit 5f06945

Please sign in to comment.