From 2db52d6962f0cbb705399222a8b1558a9c97d027 Mon Sep 17 00:00:00 2001 From: Lasse Laakkonen Date: Tue, 10 Apr 2018 17:03:06 +0300 Subject: [PATCH 1/4] Use Date.getTime() instead of event.timeStamp for tracking clicks. --- lib/fastclick.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/fastclick.js b/lib/fastclick.js index 86bf83e0..ae11e529 100644 --- a/lib/fastclick.js +++ b/lib/fastclick.js @@ -389,7 +389,12 @@ * @returns {boolean} */ FastClick.prototype.onTouchStart = function(event) { - var targetElement, touch, selection; + var targetElement, touch, selection, touchStartTime; + + // Do not use event.timeStamp + // iOS 11.3 returns negative values for event.timeStamp after pausing/resuming a Cordova application + // and supposedly for mobile Safari as well + touchStartTime = (new Date()).getTime(); // Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111). if (event.targetTouches.length > 1) { @@ -435,14 +440,14 @@ } this.trackingClick = true; - this.trackingClickStart = event.timeStamp; + this.trackingClickStart = touchStartTime; this.targetElement = targetElement; this.touchStartX = touch.pageX; this.touchStartY = touch.pageY; // Prevent phantom clicks on fast double-tap (issue #36) - if ((event.timeStamp - this.lastClickTime) < this.tapDelay) { + if ((touchStartTime - this.lastClickTime) < this.tapDelay) { event.preventDefault(); } @@ -519,26 +524,31 @@ * @returns {boolean} */ FastClick.prototype.onTouchEnd = function(event) { - var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement; + var forElement, trackingClickStart, targetTagName, scrollParent, touch, touchEndTime, targetElement = this.targetElement; + + // Do not use event.timeStamp + // iOS 11.3 returns negative values for event.timeStamp after pausing/resuming a Cordova application + // and supposedly for mobile Safari as well + touchEndTime = (new Date()).getTime(); if (!this.trackingClick) { return true; } // Prevent phantom clicks on fast double-tap (issue #36) - if ((event.timeStamp - this.lastClickTime) < this.tapDelay) { + if ((touchEndTime - this.lastClickTime) < this.tapDelay) { this.cancelNextClick = true; return true; } - if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) { + if ((touchEndTime - this.trackingClickStart) > this.tapTimeout) { return true; } // Reset to prevent wrong click cancel on input (issue #156). this.cancelNextClick = false; - this.lastClickTime = event.timeStamp; + this.lastClickTime = touchEndTime; trackingClickStart = this.trackingClickStart; this.trackingClick = false; @@ -571,7 +581,7 @@ // Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through. // Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37). - if ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) { + if ((touchEndTime - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) { this.targetElement = null; return false; } From da25396cde3802d355bb0dbd1c608f149298e9e0 Mon Sep 17 00:00:00 2001 From: Lasse Laakkonen Date: Tue, 10 Apr 2018 21:39:33 +0300 Subject: [PATCH 2/4] Change touch start time and end time to be set as the current time only for iOS 11.3, so that other platforms will not be affected. --- lib/fastclick.js | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/lib/fastclick.js b/lib/fastclick.js index ae11e529..0ee0dfdc 100644 --- a/lib/fastclick.js +++ b/lib/fastclick.js @@ -204,6 +204,13 @@ var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent); + /** + * iOS 11.3 has a bug that returns negative event.timeStamp values + * + * @type boolean + */ + var deviceIsIOS11_3 = deviceIsIOS && (/OS 11_3(_\d)?/).test(navigator.userAgent); + /** * iOS 6.0-7.* requires the target element to be manually derived * @@ -391,10 +398,14 @@ FastClick.prototype.onTouchStart = function(event) { var targetElement, touch, selection, touchStartTime; - // Do not use event.timeStamp - // iOS 11.3 returns negative values for event.timeStamp after pausing/resuming a Cordova application - // and supposedly for mobile Safari as well - touchStartTime = (new Date()).getTime(); + if (deviceIsIOS11_3) { + // Do not use event.timeStamp + // iOS 11.3 returns negative values for event.timeStamp after pausing/resuming a Cordova application + // and supposedly for mobile Safari as well + touchStartTime = (new Date()).getTime(); + } else { + touchStartTime = event.timeStamp; + } // Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111). if (event.targetTouches.length > 1) { @@ -526,10 +537,14 @@ FastClick.prototype.onTouchEnd = function(event) { var forElement, trackingClickStart, targetTagName, scrollParent, touch, touchEndTime, targetElement = this.targetElement; - // Do not use event.timeStamp - // iOS 11.3 returns negative values for event.timeStamp after pausing/resuming a Cordova application - // and supposedly for mobile Safari as well - touchEndTime = (new Date()).getTime(); + if (deviceIsIOS11_3) { + // Do not use event.timeStamp + // iOS 11.3 returns negative values for event.timeStamp after pausing/resuming a Cordova application + // and supposedly for mobile Safari as well + touchEndTime = (new Date()).getTime(); + } else { + touchEndTime = event.timeStamp; + } if (!this.trackingClick) { return true; From ad338ea4560dbcac8115fc62af08e08fac8dadab Mon Sep 17 00:00:00 2001 From: Lasse Laakkonen Date: Thu, 26 Apr 2018 22:53:56 +0300 Subject: [PATCH 3/4] Remove detection of iOS 11.3 for handling negative event.timeStamp values. Use onTouchEnd timestamp source based on onTouchStart timestamp source. --- lib/fastclick.js | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/lib/fastclick.js b/lib/fastclick.js index 0ee0dfdc..a01625b4 100644 --- a/lib/fastclick.js +++ b/lib/fastclick.js @@ -204,13 +204,6 @@ var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent); - /** - * iOS 11.3 has a bug that returns negative event.timeStamp values - * - * @type boolean - */ - var deviceIsIOS11_3 = deviceIsIOS && (/OS 11_3(_\d)?/).test(navigator.userAgent); - /** * iOS 6.0-7.* requires the target element to be manually derived * @@ -397,16 +390,18 @@ */ FastClick.prototype.onTouchStart = function(event) { var targetElement, touch, selection, touchStartTime; - - if (deviceIsIOS11_3) { - // Do not use event.timeStamp - // iOS 11.3 returns negative values for event.timeStamp after pausing/resuming a Cordova application - // and supposedly for mobile Safari as well + + // iOS (at least 11.3 and 11.4 beta) returns negative values for event.timeStamp after pausing/resuming a Cordova application + // and supposedly for mobile Safari as well + // https://github.com/ftlabs/fastclick/issues/549 + if (event.timeStamp < 0) { touchStartTime = (new Date()).getTime(); + this.isTrackingClickStartFromEvent = false; } else { touchStartTime = event.timeStamp; + this.isTrackingClickStartFromEvent = true; } - + // Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111). if (event.targetTouches.length > 1) { return true; @@ -536,14 +531,14 @@ */ FastClick.prototype.onTouchEnd = function(event) { var forElement, trackingClickStart, targetTagName, scrollParent, touch, touchEndTime, targetElement = this.targetElement; - - if (deviceIsIOS11_3) { - // Do not use event.timeStamp - // iOS 11.3 returns negative values for event.timeStamp after pausing/resuming a Cordova application + + if (this.isTrackingClickStartFromEvent) { + touchEndTime = event.timeStamp; + } else { + // iOS (at least 11.3 and 11.4 beta) returns negative values for event.timeStamp after pausing/resuming a Cordova application // and supposedly for mobile Safari as well + // https://github.com/ftlabs/fastclick/issues/549 touchEndTime = (new Date()).getTime(); - } else { - touchEndTime = event.timeStamp; } if (!this.trackingClick) { From e85ed9e302817f0c5e6caa32523c428e00df0268 Mon Sep 17 00:00:00 2001 From: Lasse Laakkonen Date: Sat, 28 Apr 2018 12:44:27 +0300 Subject: [PATCH 4/4] Update comments. --- lib/fastclick.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/fastclick.js b/lib/fastclick.js index a01625b4..bceb070c 100644 --- a/lib/fastclick.js +++ b/lib/fastclick.js @@ -391,8 +391,9 @@ FastClick.prototype.onTouchStart = function(event) { var targetElement, touch, selection, touchStartTime; - // iOS (at least 11.3 and 11.4 beta) returns negative values for event.timeStamp after pausing/resuming a Cordova application - // and supposedly for mobile Safari as well + // iOS (at least 11.4 and 11.4 beta) can return smaller event.timeStamp values after resuming with + // Cordova using UIWebView (and possibly also with mobile Safari?), the timeStamp values can also + // be negative // https://github.com/ftlabs/fastclick/issues/549 if (event.timeStamp < 0) { touchStartTime = (new Date()).getTime(); @@ -535,8 +536,9 @@ if (this.isTrackingClickStartFromEvent) { touchEndTime = event.timeStamp; } else { - // iOS (at least 11.3 and 11.4 beta) returns negative values for event.timeStamp after pausing/resuming a Cordova application - // and supposedly for mobile Safari as well + // iOS (at least 11.4 and 11.4 beta) can return smaller event.timeStamp values after resuming with + // Cordova using UIWebView (and possibly also with mobile Safari?), the timeStamp values can also + // be negative // https://github.com/ftlabs/fastclick/issues/549 touchEndTime = (new Date()).getTime(); }