-
Notifications
You must be signed in to change notification settings - Fork 14
/
jquery.noclickdelay.js
103 lines (87 loc) · 3.5 KB
/
jquery.noclickdelay.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
(function ($, window, document) {
"use strict";
// This code is only for iOS
if (!window.navigator.userAgent.match(/(iPhone|iPad|iPod)/)) {
return;
}
var CONFIG = {
TOUCH_MOVE_THRESHHOLD: 10,
PRESSED_CLASS: "pressed",
GHOST_CLICK_TIMEOUT: 500,
GHOST_CLICK_THRESHOLD: 10
}, clicks = [];
function withinDistance(x1, y1, x2, y2, distance) {
return Math.abs(x1 - x2) < distance && Math.abs(y1 - y2) < distance;
}
// Use a native event listener so we can set useCapture
document.addEventListener('click', function (e) {
for (var i = 0; i < clicks.length; i++) {
// For some reason, the ghost click events don't always appear where the touchend event was
if (withinDistance(clicks[i][0], clicks[i][1], e.clientX, e.clientY,
CONFIG.GHOST_CLICK_THRESHOLD)) {
e.preventDefault();
e.stopPropagation();
return;
}
}
}, true);
$(document).on('touchstart', '.button', function (e) {
var elem = $(this);
// Disable the webkit tap highlight, since it is no longer accurate
elem.css('webkitTapHighlightColor', 'rgba(0,0,0,0)');
elem.addClass(CONFIG.PRESSED_CLASS);
var touch = e.originalEvent.touches[0];
var location = [touch.clientX, touch.clientY];
this.__eventLocation = location;
this.__onTouchMove = function (e) {
var touch = e.originalEvent.touches[0];
if (withinDistance(touch.clientX, touch.clientY, location[0], location[1],
CONFIG.TOUCH_MOVE_THRESHHOLD)) {
elem.addClass(CONFIG.PRESSED_CLASS);
} else {
elem.removeClass(CONFIG.PRESSED_CLASS);
}
};
$(document.body).on('touchmove', this.__onTouchMove);
});
$(document).on('touchcancel', '.button', function () {
var elem = $(this);
elem.removeClass(CONFIG.PRESSED_CLASS);
$(document.body).off('touchmove', this.__onTouchMove);
});
$(document).on('touchend', '.button', function (e) {
var elem = $(this);
if (elem.hasClass(CONFIG.PRESSED_CLASS)) {
elem.removeClass(CONFIG.PRESSED_CLASS);
var location = this.__eventLocation;
if (location) {
var touch = e.originalEvent.changedTouches[0];
if (!withinDistance(touch.clientX, touch.clientY, location[0], location[1],
CONFIG.TOUCH_MOVE_THRESHHOLD)) {
return;
}
// Dispatch a fake click event within a setTimeout. If we don't do this, there's a strange bug where
// the next view can't correctly bring the keyboard up
setTimeout(function() {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
elem.get(0).dispatchEvent(evt);
}, 1);
// Don't process the default action for this event to avoid WebKit stealing focus from a
// view we might be loading, and from dispatching a click event
e.preventDefault();
// Eat further "ghost" click events at this location that appear if the user holds the link down
// longer than the double-tap cancel threshold (these are not cancelled when preventing default)
var clickLocation = [touch.clientX, touch.clientY];
clicks.push(clickLocation);
window.setTimeout(function() {
var i = clicks.indexOf(clickLocation);
if (i >= 0) {
clicks.splice(i, 1);
}
}, CONFIG.GHOST_CLICK_TIMEOUT);
}
}
$(document.body).off('touchmove', this.__onTouchMove);
});
})(jQuery, window, document);