fastclick.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. !function() {
  2. function t(e, o) {
  3. function i(t, e) {
  4. return function() {
  5. return t.apply(e, arguments)
  6. }
  7. }
  8. var r;
  9. if (o = o || {},
  10. this.trackingClick = !1, this.trackingClickStart = 0, this.targetElement = null, this.touchStartX = 0, this.touchStartY = 0, this.lastTouchIdentifier = 0, this.touchBoundary = o.touchBoundary || 10, this.layer = e, this.tapDelay = o.tapDelay || 200, this.tapTimeout = o.tapTimeout || 700, !t.notNeeded(e)) {
  11. for (var a = ["onMouse", "onClick", "onTouchStart", "onTouchMove", "onTouchEnd", "onTouchCancel"], c = this, s = 0, u = a.length; s < u; s++) c[a[s]] = i(c[a[s]], c);
  12. n && (e.addEventListener("mouseover", this.onMouse, !0), e.addEventListener("mousedown", this.onMouse, !0), e.addEventListener("mouseup", this.onMouse, !0)),
  13. e.addEventListener("click", this.onClick, !0),
  14. e.addEventListener("touchstart", this.onTouchStart, !1),
  15. e.addEventListener("touchmove", this.onTouchMove, !1),
  16. e.addEventListener("touchend", this.onTouchEnd, !1),
  17. e.addEventListener("touchcancel", this.onTouchCancel, !1),
  18. Event.prototype.stopImmediatePropagation || (e.removeEventListener = function(t, n, o) {
  19. var i = Node.prototype.removeEventListener;
  20. "click" === t ? i.call(e, t, n.hijacked || n, o) : i.call(e, t, n, o)
  21. },
  22. e.addEventListener = function(t, n, o) {
  23. var i = Node.prototype.addEventListener;
  24. "click" === t ? i.call(e, t, n.hijacked || (n.hijacked = function(t) {
  25. t.propagationStopped || n(t)
  26. }), o) : i.call(e, t, n, o)
  27. }),
  28. "function" == typeof e.onclick && (r = e.onclick, e.addEventListener("click",
  29. function(t) {
  30. r(t)
  31. },
  32. !1), e.onclick = null)
  33. }
  34. }
  35. var e = navigator.userAgent.indexOf("Windows Phone") >= 0,
  36. n = navigator.userAgent.indexOf("Android") > 0 && !e,
  37. o = /iP(ad|hone|od)/.test(navigator.userAgent) && !e,
  38. i = o && /OS 4_\d(_\d)?/.test(navigator.userAgent),
  39. r = o && /OS [6-7]_\d/.test(navigator.userAgent),
  40. a = navigator.userAgent.indexOf("BB10") > 0;
  41. t.prototype.needsClick = function(t) {
  42. switch (t.nodeName.toLowerCase()) {
  43. case "button":
  44. case "select":
  45. case "textarea":
  46. if (t.disabled) return ! 0;
  47. break;
  48. case "input":
  49. if (o && "file" === t.type || t.disabled) return ! 0;
  50. break;
  51. case "label":
  52. case "iframe":
  53. case "video":
  54. return ! 0
  55. }
  56. return /\bneedsclick\b/.test(t.className)
  57. },
  58. t.prototype.needsFocus = function(t) {
  59. switch (t.nodeName.toLowerCase()) {
  60. case "textarea":
  61. return ! 0;
  62. case "select":
  63. return ! n;
  64. case "input":
  65. switch (t.type) {
  66. case "button":
  67. case "checkbox":
  68. case "file":
  69. case "image":
  70. case "radio":
  71. case "submit":
  72. return ! 1
  73. }
  74. return ! t.disabled && !t.readOnly;
  75. default:
  76. return /\bneedsfocus\b/.test(t.className)
  77. }
  78. },
  79. t.prototype.sendClick = function(t, e) {
  80. var n, o;
  81. document.activeElement && document.activeElement !== t && document.activeElement.blur(),
  82. o = e.changedTouches[0],
  83. n = document.createEvent("MouseEvents"),
  84. n.initMouseEvent(this.determineEventType(t), !0, !0, window, 1, o.screenX, o.screenY, o.clientX, o.clientY, !1, !1, !1, !1, 0, null),
  85. n.forwardedTouchEvent = !0,
  86. t.dispatchEvent(n)
  87. },
  88. t.prototype.determineEventType = function(t) {
  89. return n && "select" === t.tagName.toLowerCase() ? "mousedown": "click"
  90. },
  91. t.prototype.focus = function(t) {
  92. var e;
  93. o && t.setSelectionRange && 0 !== t.type.indexOf("date") && "time" !== t.type && "month" !== t.type ? (e = t.value.length, t.setSelectionRange(e, e)) : t.focus()
  94. },
  95. t.prototype.updateScrollParent = function(t) {
  96. var e, n;
  97. if (e = t.fastClickScrollParent, !e || !e.contains(t)) {
  98. n = t;
  99. do {
  100. if (n.scrollHeight > n.offsetHeight) {
  101. e = n,
  102. t.fastClickScrollParent = n;
  103. break
  104. }
  105. n = n.parentElement
  106. } while ( n )
  107. }
  108. e && (e.fastClickLastScrollTop = e.scrollTop)
  109. },
  110. t.prototype.getTargetElementFromEventTarget = function(t) {
  111. return t.nodeType === Node.TEXT_NODE ? t.parentNode: t
  112. },
  113. t.prototype.onTouchStart = function(t) {
  114. var e, n, r;
  115. if (t.targetTouches.length > 1) return ! 0;
  116. if (e = this.getTargetElementFromEventTarget(t.target), n = t.targetTouches[0], o) {
  117. if (r = window.getSelection(), r.rangeCount && !r.isCollapsed) return ! 0;
  118. if (!i) {
  119. if (n.identifier && n.identifier === this.lastTouchIdentifier) return t.preventDefault(),
  120. !1;
  121. this.lastTouchIdentifier = n.identifier,
  122. this.updateScrollParent(e)
  123. }
  124. }
  125. return this.trackingClick = !0,
  126. this.trackingClickStart = t.timeStamp,
  127. this.targetElement = e,
  128. this.touchStartX = n.pageX,
  129. this.touchStartY = n.pageY,
  130. t.timeStamp - this.lastClickTime < this.tapDelay && t.preventDefault(),
  131. !0
  132. },
  133. t.prototype.touchHasMoved = function(t) {
  134. var e = t.changedTouches[0],
  135. n = this.touchBoundary;
  136. return Math.abs(e.pageX - this.touchStartX) > n || Math.abs(e.pageY - this.touchStartY) > n
  137. },
  138. t.prototype.onTouchMove = function(t) {
  139. return ! this.trackingClick || ((this.targetElement !== this.getTargetElementFromEventTarget(t.target) || this.touchHasMoved(t)) && (this.trackingClick = !1, this.targetElement = null), !0)
  140. },
  141. t.prototype.findControl = function(t) {
  142. return void 0 !== t.control ? t.control: t.htmlFor ? document.getElementById(t.htmlFor) : t.querySelector("button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea")
  143. },
  144. t.prototype.onTouchEnd = function(t) {
  145. var e, a, c, s, u, l = this.targetElement;
  146. if (!this.trackingClick) return ! 0;
  147. if (t.timeStamp - this.lastClickTime < this.tapDelay) return this.cancelNextClick = !0,
  148. !0;
  149. if (t.timeStamp - this.trackingClickStart > this.tapTimeout) return ! 0;
  150. if (this.cancelNextClick = !1, this.lastClickTime = t.timeStamp, a = this.trackingClickStart, this.trackingClick = !1, this.trackingClickStart = 0, r && (u = t.changedTouches[0], l = document.elementFromPoint(u.pageX - window.pageXOffset, u.pageY - window.pageYOffset) || l, l.fastClickScrollParent = this.targetElement.fastClickScrollParent), c = l.tagName.toLowerCase(), "label" === c) {
  151. if (e = this.findControl(l)) {
  152. if (this.focus(l), n) return ! 1;
  153. l = e
  154. }
  155. } else if (this.needsFocus(l)) return t.timeStamp - a > 100 || o && window.top !== window && "input" === c ? (this.targetElement = null, !1) : (this.focus(l), this.sendClick(l, t), o && "select" === c || (this.targetElement = null, t.preventDefault()), !1);
  156. return ! (!o || i || (s = l.fastClickScrollParent, !s || s.fastClickLastScrollTop === s.scrollTop)) || (this.needsClick(l) || (t.preventDefault(), this.sendClick(l, t)), !1)
  157. },
  158. t.prototype.onTouchCancel = function() {
  159. this.trackingClick = !1,
  160. this.targetElement = null
  161. },
  162. t.prototype.onMouse = function(t) {
  163. return ! this.targetElement || ( !! t.forwardedTouchEvent || (!t.cancelable || (!(!this.needsClick(this.targetElement) || this.cancelNextClick) || (t.stopImmediatePropagation ? t.stopImmediatePropagation() : t.propagationStopped = !0, t.stopPropagation(), t.preventDefault(), !1))))
  164. },
  165. t.prototype.onClick = function(t) {
  166. var e;
  167. return this.trackingClick ? (this.targetElement = null, this.trackingClick = !1, !0) : "submit" === t.target.type && 0 === t.detail || (e = this.onMouse(t), e || (this.targetElement = null), e)
  168. },
  169. t.prototype.destroy = function() {
  170. var t = this.layer;
  171. n && (t.removeEventListener("mouseover", this.onMouse, !0), t.removeEventListener("mousedown", this.onMouse, !0), t.removeEventListener("mouseup", this.onMouse, !0)),
  172. t.removeEventListener("click", this.onClick, !0),
  173. t.removeEventListener("touchstart", this.onTouchStart, !1),
  174. t.removeEventListener("touchmove", this.onTouchMove, !1),
  175. t.removeEventListener("touchend", this.onTouchEnd, !1),
  176. t.removeEventListener("touchcancel", this.onTouchCancel, !1)
  177. },
  178. t.notNeeded = function(t) {
  179. var e, o, i, r;
  180. if ("undefined" == typeof window.ontouchstart) return ! 0;
  181. if (o = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [, 0])[1]) {
  182. if (!n) return ! 0;
  183. if (e = document.querySelector("meta[name=viewport]")) {
  184. if (e.content.indexOf("user-scalable=no") !== -1) return ! 0;
  185. if (o > 31 && document.documentElement.scrollWidth <= window.outerWidth) return ! 0
  186. }
  187. }
  188. if (a && (i = navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/), i[1] >= 10 && i[2] >= 3 && (e = document.querySelector("meta[name=viewport]")))) {
  189. if (e.content.indexOf("user-scalable=no") !== -1) return ! 0;
  190. if (document.documentElement.scrollWidth <= window.outerWidth) return ! 0
  191. }
  192. return "none" === t.style.msTouchAction || "manipulation" === t.style.touchAction || (r = +(/Firefox\/([0-9]+)/.exec(navigator.userAgent) || [, 0])[1], !!(r >= 27 && (e = document.querySelector("meta[name=viewport]"), e && (e.content.indexOf("user-scalable=no") !== -1 || document.documentElement.scrollWidth <= window.outerWidth))) || ("none" === t.style.touchAction || "manipulation" === t.style.touchAction))
  193. },
  194. t.attach = function(e, n) {
  195. return new t(e, n)
  196. },
  197. "function" == typeof define && "object" == typeof define.amd && define.amd ? define(function() {
  198. return t
  199. }) : "undefined" != typeof module && module.exports ? (module.exports = t.attach, module.exports.FastClick = t) : window.FastClick = t
  200. } ();