diff --git a/lib/fastclick.js b/lib/fastclick.js index 86bf83e0..bceb070c 100644 --- a/lib/fastclick.js +++ b/lib/fastclick.js @@ -389,8 +389,20 @@ * @returns {boolean} */ FastClick.prototype.onTouchStart = function(event) { - var targetElement, touch, selection; - + var targetElement, touch, selection, touchStartTime; + + // 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(); + 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; @@ -435,14 +447,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 +531,36 @@ * @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; + + if (this.isTrackingClickStartFromEvent) { + touchEndTime = event.timeStamp; + } else { + // 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(); + } 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 +593,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; }