Update FastClick

pull/168/head
Thibaut 10 years ago
parent 8448461beb
commit 6f260637fa

@ -1,7 +1,9 @@
;(function () {
'use strict';
/**
* @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
*
* @version 1.0.3
* @codingstandard ftlabs-jsv2
* @copyright The Financial Times Limited [All Rights Reserved]
* @license MIT License (see LICENSE.txt)
@ -16,10 +18,9 @@
*
* @constructor
* @param {Element} layer The layer to listen on
* @param {Object} options The options to override the defaults
* @param {Object} [options={}] The options to override the defaults
*/
function FastClick(layer, options) {
'use strict';
var oldOnClick;
options = options || {};
@ -94,6 +95,13 @@ function FastClick(layer, options) {
*/
this.tapDelay = options.tapDelay || 200;
/**
* The maximum time for a tap
*
* @type number
*/
this.tapTimeout = options.tapTimeout || 700;
if (FastClick.notNeeded(layer)) {
return;
}
@ -165,13 +173,19 @@ function FastClick(layer, options) {
}
}
/**
* Windows Phone 8.1 fakes user agent string to look like Android and iPhone.
*
* @type boolean
*/
var deviceIsWindowsPhone = navigator.userAgent.indexOf("Windows Phone") >= 0;
/**
* Android requires exceptions.
*
* @type boolean
*/
var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0;
var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0 && !deviceIsWindowsPhone;
/**
@ -179,7 +193,7 @@ var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0;
*
* @type boolean
*/
var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent);
var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent) && !deviceIsWindowsPhone;
/**
@ -191,11 +205,11 @@ var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);
/**
* iOS 6.0(+?) requires the target element to be manually derived
* iOS 6.0-7.* requires the target element to be manually derived
*
* @type boolean
*/
var deviceIsIOSWithBadTarget = deviceIsIOS && (/OS ([6-9]|\d{2})_\d/).test(navigator.userAgent);
var deviceIsIOSWithBadTarget = deviceIsIOS && (/OS [6-7]_\d/).test(navigator.userAgent);
/**
* BlackBerry requires exceptions.
@ -211,7 +225,6 @@ var deviceIsBlackBerry10 = navigator.userAgent.indexOf('BB10') > 0;
* @returns {boolean} Returns true if the element needs a native click
*/
FastClick.prototype.needsClick = function(target) {
'use strict';
switch (target.nodeName.toLowerCase()) {
// Don't send a synthetic click to disabled inputs (issue #62)
@ -232,6 +245,7 @@ FastClick.prototype.needsClick = function(target) {
break;
case 'label':
case 'iframe': // iOS8 homescreen apps can prevent events bubbling into frames
case 'video':
return true;
}
@ -247,7 +261,6 @@ FastClick.prototype.needsClick = function(target) {
* @returns {boolean} Returns true if the element requires a call to focus to simulate native click.
*/
FastClick.prototype.needsFocus = function(target) {
'use strict';
switch (target.nodeName.toLowerCase()) {
case 'textarea':
return true;
@ -279,7 +292,6 @@ FastClick.prototype.needsFocus = function(target) {
* @param {Event} event
*/
FastClick.prototype.sendClick = function(targetElement, event) {
'use strict';
var clickEvent, touch;
// On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
@ -297,7 +309,6 @@ FastClick.prototype.sendClick = function(targetElement, event) {
};
FastClick.prototype.determineEventType = function(targetElement) {
'use strict';
//Issue #159: Android Chrome Select Box does not open with a synthetic click event
if (deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {
@ -312,11 +323,10 @@ FastClick.prototype.determineEventType = function(targetElement) {
* @param {EventTarget|Element} targetElement
*/
FastClick.prototype.focus = function(targetElement) {
'use strict';
var length;
// Issue #160: on iOS 7, some input elements (e.g. date datetime) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time') {
// Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month') {
length = targetElement.value.length;
targetElement.setSelectionRange(length, length);
} else {
@ -331,7 +341,6 @@ FastClick.prototype.focus = function(targetElement) {
* @param {EventTarget|Element} targetElement
*/
FastClick.prototype.updateScrollParent = function(targetElement) {
'use strict';
var scrollParent, parentElement;
scrollParent = targetElement.fastClickScrollParent;
@ -363,7 +372,6 @@ FastClick.prototype.updateScrollParent = function(targetElement) {
* @returns {Element|EventTarget}
*/
FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {
'use strict';
// On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
if (eventTarget.nodeType === Node.TEXT_NODE) {
@ -381,7 +389,6 @@ FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {
* @returns {boolean}
*/
FastClick.prototype.onTouchStart = function(event) {
'use strict';
var targetElement, touch, selection;
// Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
@ -450,7 +457,6 @@ FastClick.prototype.onTouchStart = function(event) {
* @returns {boolean}
*/
FastClick.prototype.touchHasMoved = function(event) {
'use strict';
var touch = event.changedTouches[0], boundary = this.touchBoundary;
if (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) {
@ -468,7 +474,6 @@ FastClick.prototype.touchHasMoved = function(event) {
* @returns {boolean}
*/
FastClick.prototype.onTouchMove = function(event) {
'use strict';
if (!this.trackingClick) {
return true;
}
@ -490,7 +495,6 @@ FastClick.prototype.onTouchMove = function(event) {
* @returns {Element|null}
*/
FastClick.prototype.findControl = function(labelElement) {
'use strict';
// Fast path for newer browsers supporting the HTML5 control attribute
if (labelElement.control !== undefined) {
@ -515,7 +519,6 @@ FastClick.prototype.findControl = function(labelElement) {
* @returns {boolean}
*/
FastClick.prototype.onTouchEnd = function(event) {
'use strict';
var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
if (!this.trackingClick) {
@ -528,6 +531,10 @@ FastClick.prototype.onTouchEnd = function(event) {
return true;
}
if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) {
return true;
}
// Reset to prevent wrong click cancel on input (issue #156).
this.cancelNextClick = false;
@ -609,7 +616,6 @@ FastClick.prototype.onTouchEnd = function(event) {
* @returns {void}
*/
FastClick.prototype.onTouchCancel = function() {
'use strict';
this.trackingClick = false;
this.targetElement = null;
};
@ -622,7 +628,6 @@ FastClick.prototype.onTouchCancel = function() {
* @returns {boolean}
*/
FastClick.prototype.onMouse = function(event) {
'use strict';
// If a target element was never set (because a touch event was never fired) allow the event
if (!this.targetElement) {
@ -673,7 +678,6 @@ FastClick.prototype.onMouse = function(event) {
* @returns {boolean}
*/
FastClick.prototype.onClick = function(event) {
'use strict';
var permitted;
// It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
@ -706,7 +710,6 @@ FastClick.prototype.onClick = function(event) {
* @returns {void}
*/
FastClick.prototype.destroy = function() {
'use strict';
var layer = this.layer;
if (deviceIsAndroid) {
@ -729,10 +732,10 @@ FastClick.prototype.destroy = function() {
* @param {Element} layer The layer to listen on
*/
FastClick.notNeeded = function(layer) {
'use strict';
var metaViewport;
var chromeVersion;
var blackberryVersion;
var firefoxVersion;
// Devices that don't support touch don't need FastClick
if (typeof window.ontouchstart === 'undefined') {
@ -785,8 +788,26 @@ FastClick.notNeeded = function(layer) {
}
}
// IE10 with -ms-touch-action: none, which disables double-tap-to-zoom (issue #97)
if (layer.style.msTouchAction === 'none') {
// IE10 with -ms-touch-action: none or manipulation, which disables double-tap-to-zoom (issue #97)
if (layer.style.msTouchAction === 'none' || layer.style.touchAction === 'manipulation') {
return true;
}
// Firefox version - zero for other browsers
firefoxVersion = +(/Firefox\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
if (firefoxVersion >= 27) {
// Firefox 27+ does not have tap delay if the content is not zoomable - https://bugzilla.mozilla.org/show_bug.cgi?id=922896
metaViewport = document.querySelector('meta[name=viewport]');
if (metaViewport && (metaViewport.content.indexOf('user-scalable=no') !== -1 || document.documentElement.scrollWidth <= window.outerWidth)) {
return true;
}
}
// IE11: prefixed -ms-touch-action is no longer supported and it's recomended to use non-prefixed version
// http://msdn.microsoft.com/en-us/library/windows/apps/Hh767313.aspx
if (layer.style.touchAction === 'none' || layer.style.touchAction === 'manipulation') {
return true;
}
@ -798,19 +819,17 @@ FastClick.notNeeded = function(layer) {
* Factory method for creating a FastClick object
*
* @param {Element} layer The layer to listen on
* @param {Object} options The options to override the defaults
* @param {Object} [options={}] The options to override the defaults
*/
FastClick.attach = function(layer, options) {
'use strict';
return new FastClick(layer, options);
};
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
// AMD. Register as an anonymous module.
define(function() {
'use strict';
return FastClick;
});
} else if (typeof module !== 'undefined' && module.exports) {
@ -819,3 +838,4 @@ if (typeof define == 'function' && typeof define.amd == 'object' && define.amd)
} else {
window.FastClick = FastClick;
}
}());

Loading…
Cancel
Save