UNPKG

3.61 kBJavaScriptView Raw
1/**
2 * Copyright 2013-present, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 *
10 */
11
12'use strict';
13
14var EventPluginUtils = require('./EventPluginUtils');
15var EventPropagators = require('./EventPropagators');
16var SyntheticUIEvent = require('./SyntheticUIEvent');
17var TouchEventUtils = require('fbjs/lib/TouchEventUtils');
18var ViewportMetrics = require('./ViewportMetrics');
19
20var isStartish = EventPluginUtils.isStartish;
21var isEndish = EventPluginUtils.isEndish;
22
23/**
24 * We are extending the Flow 'Touch' declaration to enable using bracket
25 * notation to access properties.
26 * Without this adjustment Flow throws
27 * "Indexable signature not found in Touch".
28 * See https://github.com/facebook/flow/issues/1323
29 */
30
31
32/**
33 * Number of pixels that are tolerated in between a `touchStart` and `touchEnd`
34 * in order to still be considered a 'tap' event.
35 */
36var tapMoveThreshold = 10;
37var startCoords = { x: 0, y: 0 };
38
39var Axis = {
40 x: { page: 'pageX', client: 'clientX', envScroll: 'currentPageScrollLeft' },
41 y: { page: 'pageY', client: 'clientY', envScroll: 'currentPageScrollTop' }
42};
43
44function getAxisCoordOfEvent(axis, nativeEvent) {
45 var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent);
46 if (singleTouch) {
47 return singleTouch[axis.page];
48 }
49 return axis.page in nativeEvent ? nativeEvent[axis.page] : nativeEvent[axis.client] + ViewportMetrics[axis.envScroll];
50}
51
52function getDistance(coords, nativeEvent) {
53 var pageX = getAxisCoordOfEvent(Axis.x, nativeEvent);
54 var pageY = getAxisCoordOfEvent(Axis.y, nativeEvent);
55 return Math.pow(Math.pow(pageX - coords.x, 2) + Math.pow(pageY - coords.y, 2), 0.5);
56}
57
58var touchEvents = ['topTouchStart', 'topTouchCancel', 'topTouchEnd', 'topTouchMove'];
59
60var dependencies = ['topMouseDown', 'topMouseMove', 'topMouseUp'].concat(touchEvents);
61
62var eventTypes = {
63 touchTap: {
64 phasedRegistrationNames: {
65 bubbled: 'onTouchTap',
66 captured: 'onTouchTapCapture'
67 },
68 dependencies: dependencies
69 }
70};
71
72var usedTouch = false;
73var usedTouchTime = 0;
74var TOUCH_DELAY = 1000;
75
76var TapEventPlugin = {
77 tapMoveThreshold: tapMoveThreshold,
78
79 eventTypes: eventTypes,
80
81 extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
82 if (!isStartish(topLevelType) && !isEndish(topLevelType)) {
83 return null;
84 }
85 // on ios, there is a delay after touch event and synthetic
86 // mouse events, so that user can perform double tap
87 // solution: ignore mouse events following touchevent within small timeframe
88 if (touchEvents.indexOf(topLevelType) !== -1) {
89 usedTouch = true;
90 usedTouchTime = Date.now();
91 } else {
92 if (usedTouch && Date.now() - usedTouchTime < TOUCH_DELAY) {
93 return null;
94 }
95 }
96 var event = null;
97 var distance = getDistance(startCoords, nativeEvent);
98 if (isEndish(topLevelType) && distance < tapMoveThreshold) {
99 event = SyntheticUIEvent.getPooled(eventTypes.touchTap, targetInst, nativeEvent, nativeEventTarget);
100 }
101 if (isStartish(topLevelType)) {
102 startCoords.x = getAxisCoordOfEvent(Axis.x, nativeEvent);
103 startCoords.y = getAxisCoordOfEvent(Axis.y, nativeEvent);
104 } else if (isEndish(topLevelType)) {
105 startCoords.x = 0;
106 startCoords.y = 0;
107 }
108 EventPropagators.accumulateTwoPhaseDispatches(event);
109 return event;
110 }
111};
112
113module.exports = TapEventPlugin;
\No newline at end of file