History

Update FastClick

Thibaut committed 12 years ago

Commit 791de071 parent 97c101b1 file · +62 −14Browse files

Unified · Split

assets/javascripts/vendor/fastclick.js+62−14
@@ -1,7 +1,7 @@
11 /**
22 * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
33 *
4− * @version 0.6.9
4+ * @version 0.6.11
55 * @codingstandard ftlabs-jsv2
66 * @copyright The Financial Times Limited [All Rights Reserved]
77 * @license MIT License (see LICENSE.txt)
@@ -98,6 +98,9 @@ function FastClick(layer) { · 90 unmodified lines
9898 /** @type function() */
9999 this.onTouchStart = function() { return FastClick.prototype.onTouchStart.apply(self, arguments); };
100100
101+ /** @type function() */
102+ this.onTouchMove = function() { return FastClick.prototype.onTouchMove.apply(self, arguments); };
103+
101104 /** @type function() */
102105 this.onTouchEnd = function() { return FastClick.prototype.onTouchEnd.apply(self, arguments); };
103106
@@ -117,6 +120,7 @@ function FastClick(layer) { · 13 unmodified lines
117120
118121 layer.addEventListener('click', this.onClick, true);
119122 layer.addEventListener('touchstart', this.onTouchStart, false);
123+ layer.addEventListener('touchmove', this.onTouchMove, false);
120124 layer.addEventListener('touchend', this.onTouchEnd, false);
121125 layer.addEventListener('touchcancel', this.onTouchCancel, false);
122126
@@ -241,8 +245,9 @@ FastClick.prototype.needsFocus = function(target) { · 118 unmodified lines
241245 'use strict';
242246 switch (target.nodeName.toLowerCase()) {
243247 case 'textarea':
244− case 'select':
245248 return true;
249+ case 'select':
250+ return !this.deviceIsAndroid;
246251 case 'input':
247252 switch (target.type) {
248253 case 'button':
@@ -281,11 +286,22 @@ FastClick.prototype.sendClick = function(targetElement, event) { · 32 unmodified lines
281286
282287 // Synthesise a click event, with an extra attribute so it can be tracked
283288 clickEvent = document.createEvent('MouseEvents');
284− clickEvent.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
289+ clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
285290 clickEvent.forwardedTouchEvent = true;
286291 targetElement.dispatchEvent(clickEvent);
287292 };
288293
294+FastClick.prototype.determineEventType = function(targetElement) {
295+ 'use strict';
296+
297+ //Issue #159: Android Chrome Select Box does not open with a synthetic click event
298+ if (this.deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {
299+ return 'mousedown';
300+ }
301+
302+ return 'click';
303+};
304+
289305
290306 /**
291307 * @param {EventTarget|Element} targetElement
@@ -294,7 +310,8 @@ FastClick.prototype.focus = function(targetElement) { · 2 unmodified lines
294310 'use strict';
295311 var length;
296312
297− if (this.deviceIsIOS && targetElement.setSelectionRange) {
313+ // 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.
314+ if (this.deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time') {
298315 length = targetElement.value.length;
299316 targetElement.setSelectionRange(length, length);
300317 } else {
@@ -436,6 +453,28 @@ FastClick.prototype.touchHasMoved = function(event) { · 135 unmodified lines
436453 };
437454
438455
456+/**
457+ * Update the last position.
458+ *
459+ * @param {Event} event
460+ * @returns {boolean}
461+ */
462+FastClick.prototype.onTouchMove = function(event) {
463+ 'use strict';
464+ if (!this.trackingClick) {
465+ return true;
466+ }
467+
468+ // If the touch has moved, cancel the click tracking
469+ if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {
470+ this.trackingClick = false;
471+ this.targetElement = null;
472+ }
473+
474+ return true;
475+};
476+
477+
439478 /**
440479 * Attempt to find the labelled control for the given label element.
441480 *
@@ -471,12 +510,6 @@ FastClick.prototype.onTouchEnd = function(event) { · 29 unmodified lines
471510 'use strict';
472511 var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
473512
474− // If the touch has moved, cancel the click tracking
475− if (this.touchHasMoved(event)) {
476− this.trackingClick = false;
477− this.targetElement = null;
478− }
479−
480513 if (!this.trackingClick) {
481514 return true;
482515 }
@@ -487,6 +520,9 @@ FastClick.prototype.onTouchEnd = function(event) { · 4 unmodified lines
487520 return true;
488521 }
489522
523+ // Reset to prevent wrong click cancel on input (issue #156).
524+ this.cancelNextClick = false;
525+
490526 this.lastClickTime = event.timeStamp;
491527
492528 trackingClickStart = this.trackingClickStart;
@@ -671,6 +707,7 @@ FastClick.prototype.destroy = function() { · 178 unmodified lines
671707
672708 layer.removeEventListener('click', this.onClick, true);
673709 layer.removeEventListener('touchstart', this.onTouchStart, false);
710+ layer.removeEventListener('touchmove', this.onTouchMove, false);
674711 layer.removeEventListener('touchend', this.onTouchEnd, false);
675712 layer.removeEventListener('touchcancel', this.onTouchCancel, false);
676713 };
@@ -684,19 +721,30 @@ FastClick.prototype.destroy = function() { · 7 unmodified lines
684721 FastClick.notNeeded = function(layer) {
685722 'use strict';
686723 var metaViewport;
724+ var chromeVersion;
687725
688726 // Devices that don't support touch don't need FastClick
689727 if (typeof window.ontouchstart === 'undefined') {
690728 return true;
691729 }
692730
693− if ((/Chrome\/[0-9]+/).test(navigator.userAgent)) {
731+ // Chrome version - zero for other browsers
732+ chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
733+
734+ if (chromeVersion) {
694735
695− // Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
696736 if (FastClick.prototype.deviceIsAndroid) {
697737 metaViewport = document.querySelector('meta[name=viewport]');
698− if (metaViewport && metaViewport.content.indexOf('user-scalable=no') !== -1) {
699− return true;
738+
739+ if (metaViewport) {
740+ // Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
741+ if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
742+ return true;
743+ }
744+ // Chrome 32 and above with width=device-width or less don't need FastClick
745+ if (chromeVersion > 31 && window.innerWidth <= window.screen.width) {
746+ return true;
747+ }
700748 }
701749
702750 // Chrome desktop doesn't need FastClick (issue #15)