浏览代码

Update FastClick

Thibaut 12 年之前
父节点
当前提交
791de07d0a
共有 1 个文件被更改,包括 62 次插入14 次删除
  1. 62 14
      assets/javascripts/vendor/fastclick.js

+ 62 - 14
assets/javascripts/vendor/fastclick.js

@@ -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)