Update FastClick

pull/15/head
Thibaut 11 years ago
parent 97c101b259
commit 791de07d0a

@ -1,7 +1,7 @@
/** /**
* @preserve FastClick: polyfill to remove click delays on browsers with touch UIs. * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
* *
* @version 0.6.9 * @version 0.6.11
* @codingstandard ftlabs-jsv2 * @codingstandard ftlabs-jsv2
* @copyright The Financial Times Limited [All Rights Reserved] * @copyright The Financial Times Limited [All Rights Reserved]
* @license MIT License (see LICENSE.txt) * @license MIT License (see LICENSE.txt)
@ -98,6 +98,9 @@ function FastClick(layer) {
/** @type function() */ /** @type function() */
this.onTouchStart = function() { return FastClick.prototype.onTouchStart.apply(self, arguments); }; this.onTouchStart = function() { return FastClick.prototype.onTouchStart.apply(self, arguments); };
/** @type function() */
this.onTouchMove = function() { return FastClick.prototype.onTouchMove.apply(self, arguments); };
/** @type function() */ /** @type function() */
this.onTouchEnd = function() { return FastClick.prototype.onTouchEnd.apply(self, arguments); }; this.onTouchEnd = function() { return FastClick.prototype.onTouchEnd.apply(self, arguments); };
@ -117,6 +120,7 @@ function FastClick(layer) {
layer.addEventListener('click', this.onClick, true); layer.addEventListener('click', this.onClick, true);
layer.addEventListener('touchstart', this.onTouchStart, false); layer.addEventListener('touchstart', this.onTouchStart, false);
layer.addEventListener('touchmove', this.onTouchMove, false);
layer.addEventListener('touchend', this.onTouchEnd, false); layer.addEventListener('touchend', this.onTouchEnd, false);
layer.addEventListener('touchcancel', this.onTouchCancel, false); layer.addEventListener('touchcancel', this.onTouchCancel, false);
@ -241,8 +245,9 @@ FastClick.prototype.needsFocus = function(target) {
'use strict'; 'use strict';
switch (target.nodeName.toLowerCase()) { switch (target.nodeName.toLowerCase()) {
case 'textarea': case 'textarea':
case 'select':
return true; return true;
case 'select':
return !this.deviceIsAndroid;
case 'input': case 'input':
switch (target.type) { switch (target.type) {
case 'button': case 'button':
@ -281,11 +286,22 @@ FastClick.prototype.sendClick = function(targetElement, event) {
// Synthesise a click event, with an extra attribute so it can be tracked // Synthesise a click event, with an extra attribute so it can be tracked
clickEvent = document.createEvent('MouseEvents'); clickEvent = document.createEvent('MouseEvents');
clickEvent.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
clickEvent.forwardedTouchEvent = true; clickEvent.forwardedTouchEvent = true;
targetElement.dispatchEvent(clickEvent); targetElement.dispatchEvent(clickEvent);
}; };
FastClick.prototype.determineEventType = function(targetElement) {
'use strict';
//Issue #159: Android Chrome Select Box does not open with a synthetic click event
if (this.deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {
return 'mousedown';
}
return 'click';
};
/** /**
* @param {EventTarget|Element} targetElement * @param {EventTarget|Element} targetElement
@ -294,7 +310,8 @@ FastClick.prototype.focus = function(targetElement) {
'use strict'; 'use strict';
var length; var length;
if (this.deviceIsIOS && targetElement.setSelectionRange) { // 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 (this.deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time') {
length = targetElement.value.length; length = targetElement.value.length;
targetElement.setSelectionRange(length, length); targetElement.setSelectionRange(length, length);
} else { } else {
@ -436,6 +453,28 @@ FastClick.prototype.touchHasMoved = function(event) {
}; };
/**
* Update the last position.
*
* @param {Event} event
* @returns {boolean}
*/
FastClick.prototype.onTouchMove = function(event) {
'use strict';
if (!this.trackingClick) {
return true;
}
// If the touch has moved, cancel the click tracking
if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {
this.trackingClick = false;
this.targetElement = null;
}
return true;
};
/** /**
* Attempt to find the labelled control for the given label element. * Attempt to find the labelled control for the given label element.
* *
@ -471,12 +510,6 @@ FastClick.prototype.onTouchEnd = function(event) {
'use strict'; 'use strict';
var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement; var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
// If the touch has moved, cancel the click tracking
if (this.touchHasMoved(event)) {
this.trackingClick = false;
this.targetElement = null;
}
if (!this.trackingClick) { if (!this.trackingClick) {
return true; return true;
} }
@ -487,6 +520,9 @@ FastClick.prototype.onTouchEnd = function(event) {
return true; return true;
} }
// Reset to prevent wrong click cancel on input (issue #156).
this.cancelNextClick = false;
this.lastClickTime = event.timeStamp; this.lastClickTime = event.timeStamp;
trackingClickStart = this.trackingClickStart; trackingClickStart = this.trackingClickStart;
@ -671,6 +707,7 @@ FastClick.prototype.destroy = function() {
layer.removeEventListener('click', this.onClick, true); layer.removeEventListener('click', this.onClick, true);
layer.removeEventListener('touchstart', this.onTouchStart, false); layer.removeEventListener('touchstart', this.onTouchStart, false);
layer.removeEventListener('touchmove', this.onTouchMove, false);
layer.removeEventListener('touchend', this.onTouchEnd, false); layer.removeEventListener('touchend', this.onTouchEnd, false);
layer.removeEventListener('touchcancel', this.onTouchCancel, false); layer.removeEventListener('touchcancel', this.onTouchCancel, false);
}; };
@ -684,19 +721,30 @@ FastClick.prototype.destroy = function() {
FastClick.notNeeded = function(layer) { FastClick.notNeeded = function(layer) {
'use strict'; 'use strict';
var metaViewport; var metaViewport;
var chromeVersion;
// Devices that don't support touch don't need FastClick // Devices that don't support touch don't need FastClick
if (typeof window.ontouchstart === 'undefined') { if (typeof window.ontouchstart === 'undefined') {
return true; return true;
} }
if ((/Chrome\/[0-9]+/).test(navigator.userAgent)) { // Chrome version - zero for other browsers
chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
if (chromeVersion) {
// Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
if (FastClick.prototype.deviceIsAndroid) { if (FastClick.prototype.deviceIsAndroid) {
metaViewport = document.querySelector('meta[name=viewport]'); metaViewport = document.querySelector('meta[name=viewport]');
if (metaViewport && metaViewport.content.indexOf('user-scalable=no') !== -1) {
return true; if (metaViewport) {
// Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
return true;
}
// Chrome 32 and above with width=device-width or less don't need FastClick
if (chromeVersion > 31 && window.innerWidth <= window.screen.width) {
return true;
}
} }
// Chrome desktop doesn't need FastClick (issue #15) // Chrome desktop doesn't need FastClick (issue #15)

Loading…
Cancel
Save