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