UNPKG

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