The library for web and native user interfaces.
Use Synthetic Events
Swaps out usage of `AbstractEvent` with `SyntheticEvent` (and subclasses).
CommitSyncScript committed
Jun 14, 2013 at 16:45 UTC
88e90d5601aa29e606ed2c2e248f34df46ecad6f
15 files changed
+699
-935
src/core/__tests__/ReactEventEmitter-test.js
renamed
+2
-2
@@ -229,7 +229,7 @@ describe('ReactEventEmitter', function() {
229
230
it('should invoke handlers that were removed while bubbling', function() {
231
var handleParentClick = mocks.getMockFunction();
232
- var handleChildClick = function(abstractEvent) {
232
+ var handleChildClick = function(event) {
233
ReactEventEmitter.deleteAllListeners(PARENT.id);
234
};
235
ReactEventEmitter.putListener(CHILD.id, ON_CLICK_KEY, handleChildClick);
@@ -240,7 +240,7 @@ describe('ReactEventEmitter', function() {
240
241
it('should not invoke newly inserted handlers while bubbling', function() {
242
var handleParentClick = mocks.getMockFunction();
243
- var handleChildClick = function(abstractEvent) {
243
+ var handleChildClick = function(event) {
244
ReactEventEmitter.putListener(PARENT.id, ON_CLICK_KEY, handleParentClick);
245
};
246
ReactEventEmitter.putListener(CHILD.id, ON_CLICK_KEY, handleChildClick);
src/event/AbstractEvent.js
deleted
-253
@@ -1,253 +0,0 @@
1
-/**
2
- * Copyright 2013 Facebook, Inc.
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- *
16
- * @providesModule AbstractEvent
17
- */
18
-
19
-"use strict";
20
-
21
-var BrowserEnv = require('BrowserEnv');
22
-var PooledClass = require('PooledClass');
23
-var TouchEventUtils = require('TouchEventUtils');
24
-
25
-var emptyFunction = require('emptyFunction');
26
-
27
-var MAX_POOL_SIZE = 20;
28
-
29
-/**
30
- * AbstractEvent copy constructor. @see `PooledClass`. Provides a single place
31
- * to define all cross browser normalization of DOM events. Does not attempt to
32
- * extend a native event, rather creates a completely new object that has a
33
- * reference to the nativeEvent through .nativeEvent member. The property .data
34
- * should hold all data that is extracted from the event in a cross browser
35
- * manner. Application code should use the data field when possible, not the
36
- * unreliable native event.
37
- */
38
-function AbstractEvent(
39
- reactEventType,
40
- reactTargetID, // Allows the abstract target to differ from native.
41
- nativeEvent,
42
- data) {
43
- this.reactEventType = reactEventType;
44
- this.reactTargetID = reactTargetID || '';
45
- this.nativeEvent = nativeEvent;
46
- this.data = data;
47
- // TODO: Deprecate storing target - doesn't always make sense for some types
48
- this.target = nativeEvent && nativeEvent.target;
49
-
50
- /**
51
- * As a performance optimization, we tag the existing event with the listeners
52
- * (or listener [singular] if only one). This avoids having to package up an
53
- * abstract event along with the set of listeners into a wrapping "dispatch"
54
- * object. No one should ever read this property except event system and
55
- * plugin/dispatcher code. We also tag the abstract event with a parallel
56
- * ID array. _dispatchListeners[i] is being dispatched to a DOM node at ID
57
- * _dispatchIDs[i]. The lengths should never, ever, ever be different.
58
- */
59
- this._dispatchListeners = null;
60
- this._dispatchIDs = null;
61
-
62
- this.isPropagationStopped = false;
63
- this.isPersistent = emptyFunction.thatReturnsFalse;
64
-}
65
-
66
-/** `PooledClass` looks for this. */
67
-AbstractEvent.poolSize = MAX_POOL_SIZE;
68
-
69
-/**
70
- * `PooledClass` looks for `destructor` on each instance it releases. We need to
71
- * ensure that we remove all references to listeners which could trap large
72
- * amounts of memory in their closures.
73
- */
74
-AbstractEvent.prototype.destructor = function() {
75
- this.target = null;
76
- this._dispatchListeners = null;
77
- this._dispatchIDs = null;
78
-};
79
-
80
-/**
81
- * Enhance the `AbstractEvent` class to have pooling abilities. We instruct
82
- * `PooledClass` that our copy constructor accepts five arguments (this is just
83
- * a performance optimization). These objects are instantiated frequently.
84
- */
85
-PooledClass.addPoolingTo(AbstractEvent, PooledClass.fiveArgumentPooler);
86
-
87
-AbstractEvent.prototype.stopPropagation = function() {
88
- this.isPropagationStopped = true;
89
- if (this.nativeEvent.stopPropagation) {
90
- this.nativeEvent.stopPropagation();
91
- }
92
- // IE8 only understands cancelBubble, not stopPropagation().
93
- this.nativeEvent.cancelBubble = true;
94
-};
95
-
96
-AbstractEvent.prototype.preventDefault = function() {
97
- AbstractEvent.preventDefaultOnNativeEvent(this.nativeEvent);
98
-};
99
-
100
-/**
101
- * We clear out all dispatched `AbstractEvent`s after each event loop, adding
102
- * them back into the pool. This allows a way to hold onto a reference that
103
- * won't be added back into the pool.
104
- */
105
-AbstractEvent.prototype.persist = function() {
106
- this.isPersistent = emptyFunction.thatReturnsTrue;
107
-};
108
-
109
-/**
110
- * Utility function for preventing default in cross browser manner.
111
- */
112
-AbstractEvent.preventDefaultOnNativeEvent = function(nativeEvent) {
113
- if (nativeEvent.preventDefault) {
114
- nativeEvent.preventDefault();
115
- } else {
116
- nativeEvent.returnValue = false;
117
- }
118
-};
119
-
120
-/**
121
- * @param {Element} target The target element.
122
- */
123
-AbstractEvent.normalizeScrollDataFromTarget = function(target) {
124
- return {
125
- scrollTop: target.scrollTop,
126
- scrollLeft: target.scrollLeft,
127
- clientWidth: target.clientWidth,
128
- clientHeight: target.clientHeight,
129
- scrollHeight: target.scrollHeight,
130
- scrollWidth: target.scrollWidth
131
- };
132
-};
133
-
134
-/*
135
- * There are some normalizations that need to happen for various browsers. In
136
- * addition to replacing the general event fixing with a framework such as
137
- * jquery, we need to normalize mouse events here. Code below is mostly borrowed
138
- * from: jScrollPane/script/jquery.mousewheel.js
139
- */
140
-AbstractEvent.normalizeMouseWheelData = function(nativeEvent) {
141
- var delta = 0;
142
- var deltaX = 0;
143
- var deltaY = 0;
144
-
145
- /* traditional scroll wheel data */
146
- if ( nativeEvent.wheelDelta ) { delta = nativeEvent.wheelDelta/120; }
147
- if ( nativeEvent.detail ) { delta = -nativeEvent.detail/3; }
148
-
149
- /* Multidimensional scroll (touchpads) with deltas */
150
- deltaY = delta;
151
-
152
- /* Gecko based browsers */
153
- if (nativeEvent.axis !== undefined &&
154
- nativeEvent.axis === nativeEvent.HORIZONTAL_AXIS ) {
155
- deltaY = 0;
156
- deltaX = -delta;
157
- }
158
-
159
- /* Webkit based browsers */
160
- if (nativeEvent.wheelDeltaY !== undefined ) {
161
- deltaY = nativeEvent.wheelDeltaY/120;
162
- }
163
- if (nativeEvent.wheelDeltaX !== undefined ) {
164
- deltaX = -nativeEvent.wheelDeltaX/120;
165
- }
166
-
167
- return { delta: delta, deltaX: deltaX, deltaY: deltaY };
168
-};
169
-
170
-/**
171
- * I <3 Quirksmode.org:
172
- * http://www.quirksmode.org/js/events_properties.html
173
- */
174
-AbstractEvent.isNativeClickEventRightClick = function(nativeEvent) {
175
- return nativeEvent.which ? nativeEvent.which === 3 :
176
- nativeEvent.button ? nativeEvent.button === 2 :
177
- false;
178
-};
179
-
180
-AbstractEvent.normalizePointerData = function(nativeEvent) {
181
- return {
182
- globalX: AbstractEvent.eventPageX(nativeEvent),
183
- globalY: AbstractEvent.eventPageY(nativeEvent),
184
- rightMouseButton:
185
- AbstractEvent.isNativeClickEventRightClick(nativeEvent)
186
- };
187
-};
188
-
189
-AbstractEvent.normalizeDragEventData =
190
- function(nativeEvent, globalX, globalY, startX, startY) {
191
- return {
192
- globalX: globalX,
193
- globalY: globalY,
194
- startX: startX,
195
- startY: startY
196
- };
197
- };
198
-
199
-/**
200
- * Warning: It is possible to move your finger on a touch surface, yet not
201
- * effect the `eventPageX/Y` because the touch had caused a scroll that
202
- * compensated for your movement. To track movements across the page, prevent
203
- * default to avoid scrolling, and control scrolling in javascript.
204
- */
205
-
206
-/**
207
- * Gets the exact position of a touch/mouse event on the page with respect to
208
- * the document body. The only reason why this method is needed instead of using
209
- * `TouchEventUtils.extractSingleTouch` is to support IE8-. Mouse events in all
210
- * browsers except IE8- contain a pageY. IE8 and below require clientY
211
- * computation:
212
- *
213
- * @param {Event} nativeEvent Native event, possibly touch or mouse.
214
- * @return {number} Coordinate with respect to document body.
215
- */
216
-AbstractEvent.eventPageY = function(nativeEvent) {
217
- var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent);
218
- if (singleTouch) {
219
- return singleTouch.pageY;
220
- } else if (typeof nativeEvent.pageY !== 'undefined') {
221
- return nativeEvent.pageY;
222
- } else {
223
- return nativeEvent.clientY + BrowserEnv.currentPageScrollTop;
224
- }
225
-};
226
-
227
-/**
228
- * @see `AbstractEvent.eventPageY`.
229
- *
230
- * @param {Event} nativeEvent Native event, possibly touch or mouse.
231
- * @return {number} Coordinate with respect to document body.
232
- */
233
-AbstractEvent.eventPageX = function(nativeEvent) {
234
- var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent);
235
- if (singleTouch) {
236
- return singleTouch.pageX;
237
- } else if (typeof nativeEvent.pageX !== 'undefined') {
238
- return nativeEvent.pageX;
239
- } else {
240
- return nativeEvent.clientX + BrowserEnv.currentPageScrollLeft;
241
- }
242
-};
243
-
244
-/**
245
- * @deprecated
246
- */
247
-AbstractEvent.persistentCloneOf = function(abstractEvent) {
248
- abstractEvent.persist();
249
- return abstractEvent;
250
-};
251
-
252
-module.exports = AbstractEvent;
253
-
src/event/EventPluginHub.js
+1
-1
@@ -65,7 +65,7 @@ var executeDispatchesAndRelease = function(event) {
65
* Required. When a top-level event is fired, this method is expected to
66
* extract synthetic events that will in turn be queued and dispatched.
67
*
68
- * `abstractEventTypes` {object}
68
+ * `eventTypes` {object}
69
* Optional, plugins that fire events must publish a mapping of registration
70
* names that are used to register listeners. Values of this mapping must
71
* be objects that contain `registrationName` or `phasedRegistrationNames`.
src/event/EventPluginRegistry.js
+2
-2
@@ -60,7 +60,7 @@ function recomputePluginOrdering() {
60
pluginName
61
);
62
EventPluginRegistry.plugins[pluginIndex] = PluginModule;
63
- var publishedEvents = PluginModule.abstractEventTypes;
63
+ var publishedEvents = PluginModule.eventTypes;
64
for (var eventName in publishedEvents) {
65
invariant(
66
publishEventForPlugin(publishedEvents[eventName], PluginModule),
@@ -198,7 +198,7 @@ var EventPluginRegistry = {
198
* @internal
199
*/
200
getPluginModuleForEvent: function(event) {
201
- var dispatchConfig = event.reactEventType;
201
+ var dispatchConfig = event.dispatchConfig;
202
if (dispatchConfig.registrationName) {
203
return EventPluginRegistry.registrationNames[
204
dispatchConfig.registrationName
src/event/EventPluginUtils.js
+43
-64
@@ -19,7 +19,6 @@
19
"use strict";
20
21
var EventConstants = require('EventConstants');
22
-var AbstractEvent = require('AbstractEvent');
22
23
var invariant = require('invariant');
24
@@ -40,27 +39,11 @@ function isStartish(topLevelType) {
39
topLevelType === topLevelTypes.topTouchStart;
40
}
41
43
-function storePageCoordsIn(obj, nativeEvent) {
44
- var pageX = AbstractEvent.eventPageX(nativeEvent);
45
- var pageY = AbstractEvent.eventPageY(nativeEvent);
46
- obj.pageX = pageX;
47
- obj.pageY = pageY;
48
-}
49
-
50
-function eventDistance(coords, nativeEvent) {
51
- var pageX = AbstractEvent.eventPageX(nativeEvent);
52
- var pageY = AbstractEvent.eventPageY(nativeEvent);
53
- return Math.pow(
54
- Math.pow(pageX - coords.pageX, 2) + Math.pow(pageY - coords.pageY, 2),
55
- 0.5
56
- );
57
-}
58
-
42
var validateEventDispatches;
43
if (__DEV__) {
61
- validateEventDispatches = function(abstractEvent) {
62
- var dispatchListeners = abstractEvent._dispatchListeners;
63
- var dispatchIDs = abstractEvent._dispatchIDs;
44
+ validateEventDispatches = function(event) {
45
+ var dispatchListeners = event._dispatchListeners;
46
+ var dispatchIDs = event._dispatchIDs;
47
48
var listenersIsArr = Array.isArray(dispatchListeners);
49
var idsIsArr = Array.isArray(dispatchIDs);
@@ -71,53 +54,52 @@ if (__DEV__) {
54
55
invariant(
56
idsIsArr === listenersIsArr && IDsLen === listenersLen,
74
- 'EventPluginUtils: Invalid `abstractEvent`.'
57
+ 'EventPluginUtils: Invalid `event`.'
58
);
59
};
60
}
61
62
/**
80
- * Invokes `cb(abstractEvent, listener, id)`. Avoids using call if no scope is
63
+ * Invokes `cb(event, listener, id)`. Avoids using call if no scope is
64
* provided. The `(listener,id)` pair effectively forms the "dispatch" but are
65
* kept separate to conserve memory.
66
*/
84
-function forEachEventDispatch(abstractEvent, cb) {
85
- var dispatchListeners = abstractEvent._dispatchListeners;
86
- var dispatchIDs = abstractEvent._dispatchIDs;
67
+function forEachEventDispatch(event, cb) {
68
+ var dispatchListeners = event._dispatchListeners;
69
+ var dispatchIDs = event._dispatchIDs;
70
if (__DEV__) {
88
- validateEventDispatches(abstractEvent);
71
+ validateEventDispatches(event);
72
}
73
if (Array.isArray(dispatchListeners)) {
91
- var i;
92
- for (
93
- i = 0;
94
- i < dispatchListeners.length && !abstractEvent.isPropagationStopped;
95
- i++) {
74
+ for (var i = 0; i < dispatchListeners.length; i++) {
75
+ if (event.isPropagationStopped()) {
76
+ break;
77
+ }
78
// Listeners and IDs are two parallel arrays that are always in sync.
97
- cb(abstractEvent, dispatchListeners[i], dispatchIDs[i]);
79
+ cb(event, dispatchListeners[i], dispatchIDs[i]);
80
}
81
} else if (dispatchListeners) {
100
- cb(abstractEvent, dispatchListeners, dispatchIDs);
82
+ cb(event, dispatchListeners, dispatchIDs);
83
}
84
}
85
86
/**
87
* Default implementation of PluginModule.executeDispatch().
106
- * @param {AbstractEvent} AbstractEvent to handle
88
+ * @param {SyntheticEvent} SyntheticEvent to handle
89
* @param {function} Application-level callback
90
* @param {string} domID DOM id to pass to the callback.
91
*/
110
-function executeDispatch(abstractEvent, listener, domID) {
111
- listener(abstractEvent, domID);
92
+function executeDispatch(event, listener, domID) {
93
+ listener(event, domID);
94
}
95
96
/**
97
* Standard/simple iteration through an event's collected dispatches.
98
*/
117
-function executeDispatchesInOrder(abstractEvent, executeDispatch) {
118
- forEachEventDispatch(abstractEvent, executeDispatch);
119
- abstractEvent._dispatchListeners = null;
120
- abstractEvent._dispatchIDs = null;
99
+function executeDispatchesInOrder(event, executeDispatch) {
100
+ forEachEventDispatch(event, executeDispatch);
101
+ event._dispatchListeners = null;
102
+ event._dispatchIDs = null;
103
}
104
105
/**
@@ -127,25 +109,24 @@ function executeDispatchesInOrder(abstractEvent, executeDispatch) {
109
* @returns id of the first dispatch execution who's listener returns true, or
110
* null if no listener returned true.
111
*/
130
-function executeDispatchesInOrderStopAtTrue(abstractEvent) {
131
- var dispatchListeners = abstractEvent._dispatchListeners;
132
- var dispatchIDs = abstractEvent._dispatchIDs;
112
+function executeDispatchesInOrderStopAtTrue(event) {
113
+ var dispatchListeners = event._dispatchListeners;
114
+ var dispatchIDs = event._dispatchIDs;
115
if (__DEV__) {
134
- validateEventDispatches(abstractEvent);
116
+ validateEventDispatches(event);
117
}
118
if (Array.isArray(dispatchListeners)) {
137
- var i;
138
- for (
139
- i = 0;
140
- i < dispatchListeners.length && !abstractEvent.isPropagationStopped;
141
- i++) {
119
+ for (var i = 0; i < dispatchListeners.length; i++) {
120
+ if (event.isPropagationStopped()) {
121
+ break;
122
+ }
123
// Listeners and IDs are two parallel arrays that are always in sync.
143
- if (dispatchListeners[i](abstractEvent, dispatchIDs[i])) {
124
+ if (dispatchListeners[i](event, dispatchIDs[i])) {
125
return dispatchIDs[i];
126
}
127
}
128
} else if (dispatchListeners) {
148
- if (dispatchListeners(abstractEvent, dispatchIDs)) {
129
+ if (dispatchListeners(event, dispatchIDs)) {
130
return dispatchIDs;
131
}
132
}
@@ -161,30 +142,30 @@ function executeDispatchesInOrderStopAtTrue(abstractEvent) {
142
*
143
* @returns The return value of executing the single dispatch.
144
*/
164
-function executeDirectDispatch(abstractEvent) {
145
+function executeDirectDispatch(event) {
146
if (__DEV__) {
166
- validateEventDispatches(abstractEvent);
147
+ validateEventDispatches(event);
148
}
168
- var dispatchListener = abstractEvent._dispatchListeners;
169
- var dispatchID = abstractEvent._dispatchIDs;
149
+ var dispatchListener = event._dispatchListeners;
150
+ var dispatchID = event._dispatchIDs;
151
invariant(
152
!Array.isArray(dispatchListener),
172
- 'executeDirectDispatch(...): Invalid `abstractEvent`.'
153
+ 'executeDirectDispatch(...): Invalid `event`.'
154
);
155
var res = dispatchListener ?
175
- dispatchListener(abstractEvent, dispatchID) :
156
+ dispatchListener(event, dispatchID) :
157
null;
177
- abstractEvent._dispatchListeners = null;
178
- abstractEvent._dispatchIDs = null;
158
+ event._dispatchListeners = null;
159
+ event._dispatchIDs = null;
160
return res;
161
}
162
163
/**
183
- * @param {AbstractEvent} abstractEvent
164
+ * @param {SyntheticEvent} event
165
* @returns {bool} True iff number of dispatches accumulated is greater than 0.
166
*/
186
-function hasDispatches(abstractEvent) {
187
- return !!abstractEvent._dispatchListeners;
167
+function hasDispatches(event) {
168
+ return !!event._dispatchListeners;
169
}
170
171
/**
@@ -194,8 +175,6 @@ var EventPluginUtils = {
175
isEndish: isEndish,
176
isMoveish: isMoveish,
177
isStartish: isStartish,
197
- storePageCoordsIn: storePageCoordsIn,
198
- eventDistance: eventDistance,
178
executeDispatchesInOrder: executeDispatchesInOrder,
179
executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
180
executeDirectDispatch: executeDirectDispatch,
src/event/EventPropagators.js
+27
-29
@@ -56,19 +56,19 @@ var injection = {
56
* Some event types have a notion of different registration names for different
57
* "phases" of propagation. This finds listeners by a given phase.
58
*/
59
-function listenerAtPhase(id, abstractEvent, propagationPhase) {
59
+function listenerAtPhase(id, event, propagationPhase) {
60
var registrationName =
61
- abstractEvent.reactEventType.phasedRegistrationNames[propagationPhase];
61
+ event.dispatchConfig.phasedRegistrationNames[propagationPhase];
62
return getListener(id, registrationName);
63
}
64
65
/**
66
- * Tags an `AbstractEvent` with dispatched listeners. Creating this function
66
+ * Tags a `SyntheticEvent` with dispatched listeners. Creating this function
67
* here, allows us to not have to bind or create functions for each event.
68
* Mutating the event's members allows us to not have to create a wrapping
69
* "dispatch" object that pairs the event with the listener.
70
*/
71
-function accumulateDirectionalDispatches(domID, upwards, abstractEvent) {
71
+function accumulateDirectionalDispatches(domID, upwards, event) {
72
if (__DEV__) {
73
if (!domID) {
74
throw new Error('Dispatching id must not be null');
@@ -76,11 +76,10 @@ function accumulateDirectionalDispatches(domID, upwards, abstractEvent) {
76
injection.validate();
77
}
78
var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;
79
- var listener = listenerAtPhase(domID, abstractEvent, phase);
79
+ var listener = listenerAtPhase(domID, event, phase);
80
if (listener) {
81
- abstractEvent._dispatchListeners =
82
- accumulate(abstractEvent._dispatchListeners, listener);
83
- abstractEvent._dispatchIDs = accumulate(abstractEvent._dispatchIDs, domID);
81
+ event._dispatchListeners = accumulate(event._dispatchListeners, listener);
82
+ event._dispatchIDs = accumulate(event._dispatchIDs, domID);
83
}
84
}
85
@@ -91,12 +90,12 @@ function accumulateDirectionalDispatches(domID, upwards, abstractEvent) {
90
* single traversal for the entire collection of events because each event may
91
* have a different target.
92
*/
94
-function accumulateTwoPhaseDispatchesSingle(abstractEvent) {
95
- if (abstractEvent && abstractEvent.reactEventType.phasedRegistrationNames) {
93
+function accumulateTwoPhaseDispatchesSingle(event) {
94
+ if (event && event.dispatchConfig.phasedRegistrationNames) {
95
injection.InstanceHandle.traverseTwoPhase(
97
- abstractEvent.reactTargetID,
96
+ event.dispatchMarker,
97
accumulateDirectionalDispatches,
99
- abstractEvent
98
+ event
99
);
100
}
101
}
@@ -105,36 +104,35 @@ function accumulateTwoPhaseDispatchesSingle(abstractEvent) {
104
/**
105
* Accumulates without regard to direction, does not look for phased
106
* registration names. Same as `accumulateDirectDispatchesSingle` but without
108
- * requiring that the `reactTargetID` be the same as the dispatched ID.
107
+ * requiring that the `dispatchMarker` be the same as the dispatched ID.
108
*/
110
-function accumulateDispatches(id, ignoredDirection, abstractEvent) {
111
- if (abstractEvent && abstractEvent.reactEventType.registrationName) {
112
- var registrationName = abstractEvent.reactEventType.registrationName;
109
+function accumulateDispatches(id, ignoredDirection, event) {
110
+ if (event && event.dispatchConfig.registrationName) {
111
+ var registrationName = event.dispatchConfig.registrationName;
112
var listener = getListener(id, registrationName);
113
if (listener) {
115
- abstractEvent._dispatchListeners =
116
- accumulate(abstractEvent._dispatchListeners, listener);
117
- abstractEvent._dispatchIDs = accumulate(abstractEvent._dispatchIDs, id);
114
+ event._dispatchListeners = accumulate(event._dispatchListeners, listener);
115
+ event._dispatchIDs = accumulate(event._dispatchIDs, id);
116
}
117
}
118
}
119
120
/**
123
- * Accumulates dispatches on an `AbstractEvent`, but only for the
124
- * `reactTargetID`.
125
- * @param {AbstractEvent} abstractEvent
121
+ * Accumulates dispatches on an `SyntheticEvent`, but only for the
122
+ * `dispatchMarker`.
123
+ * @param {SyntheticEvent} event
124
*/
127
-function accumulateDirectDispatchesSingle(abstractEvent) {
128
- if (abstractEvent && abstractEvent.reactEventType.registrationName) {
129
- accumulateDispatches(abstractEvent.reactTargetID, null, abstractEvent);
125
+function accumulateDirectDispatchesSingle(event) {
126
+ if (event && event.dispatchConfig.registrationName) {
127
+ accumulateDispatches(event.dispatchMarker, null, event);
128
}
129
}
130
133
-function accumulateTwoPhaseDispatches(abstractEvents) {
131
+function accumulateTwoPhaseDispatches(events) {
132
if (__DEV__) {
133
injection.validate();
134
}
137
- forEachAccumulated(abstractEvents, accumulateTwoPhaseDispatchesSingle);
135
+ forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
136
}
137
138
function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
@@ -151,11 +149,11 @@ function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
149
}
150
151
154
-function accumulateDirectDispatches(abstractEvents) {
152
+function accumulateDirectDispatches(events) {
153
if (__DEV__) {
154
injection.validate();
155
}
158
- forEachAccumulated(abstractEvents, accumulateDirectDispatchesSingle);
156
+ forEachAccumulated(events, accumulateDirectDispatchesSingle);
157
}
158
159
src/event/__tests__/EventPluginRegistry-test.js
+8
-8
@@ -155,13 +155,13 @@ describe('EventPluginRegistry', function() {
155
156
it('should publish registration names of injected plugins', function() {
157
var OnePlugin = createPlugin({
158
- abstractEventTypes: {
158
+ eventTypes: {
159
click: {registrationName: 'onClick'},
160
focus: {registrationName: 'onFocus'}
161
}
162
});
163
var TwoPlugin = createPlugin({
164
- abstractEventTypes: {
164
+ eventTypes: {
165
magic: {
166
phasedRegistrationNames: {
167
bubbled: 'onMagicBubble',
@@ -189,12 +189,12 @@ describe('EventPluginRegistry', function() {
189
190
it('should throw if multiple registration names collide', function() {
191
var OnePlugin = createPlugin({
192
- abstractEventTypes: {
192
+ eventTypes: {
193
photoCapture: {registrationName: 'onPhotoCapture'}
194
}
195
});
196
var TwoPlugin = createPlugin({
197
- abstractEventTypes: {
197
+ eventTypes: {
198
photo: {
199
phasedRegistrationNames: {
200
bubbled: 'onPhotoBubble',
@@ -219,7 +219,7 @@ describe('EventPluginRegistry', function() {
219
220
it('should throw if an invalid event is published', function() {
221
var OnePlugin = createPlugin({
222
- abstractEventTypes: {
222
+ eventTypes: {
223
badEvent: {/* missing configuration */}
224
}
225
});
@@ -246,14 +246,14 @@ describe('EventPluginRegistry', function() {
246
};
247
248
var OnePlugin = createPlugin({
249
- abstractEventTypes: {
249
+ eventTypes: {
250
click: clickDispatchConfig,
251
magic: magicDispatchConfig
252
}
253
});
254
255
- var clickEvent = {reactEventType: clickDispatchConfig};
256
- var magicEvent = {reactEventType: magicDispatchConfig};
255
+ var clickEvent = {dispatchConfig: clickDispatchConfig};
256
+ var magicEvent = {dispatchConfig: magicDispatchConfig};
257
258
expect(EventPluginRegistry.getPluginModuleForEvent(clickEvent)).toBe(null);
259
expect(EventPluginRegistry.getPluginModuleForEvent(magicEvent)).toBe(null);
src/eventPlugins/AnalyticsEventPluginFactory.js
+3
-3
@@ -133,14 +133,14 @@ if (__DEV__) {
133
}
134
135
/**
136
- * This plugin does not really extract any abstract events. Rather it just looks
137
- * at the top level event and bumps up counters as appropriate
136
+ * This plugin does not really extract any synthetic events. Rather it just
137
+ * looks at the top-level event and bumps up counters as appropriate
138
*
139
* @param {string} topLevelType Record from `EventConstants`.
140
* @param {DOMEventTarget} topLevelTarget The listening component root node.
141
* @param {string} topLevelTargetID ID of `topLevelTarget`.
142
* @param {object} nativeEvent Native browser event.
143
- * @return {*} An accumulation of `AbstractEvent`s.
143
+ * @return {*} An accumulation of synthetic events.
144
* @see {EventPluginHub.extractEvents}
145
*/
146
function extractEvents(
src/eventPlugins/EnterLeaveEventPlugin.js
+62
-63
@@ -19,11 +19,11 @@
19
20
"use strict";
21
22
+var EventConstants = require('EventConstants');
23
var EventPropagators = require('EventPropagators');
24
var ExecutionEnvironment = require('ExecutionEnvironment');
24
-var AbstractEvent = require('AbstractEvent');
25
-var EventConstants = require('EventConstants');
25
var ReactInstanceHandles = require('ReactInstanceHandles');
26
+var SyntheticMouseEvent = require('SyntheticMouseEvent');
27
28
var getDOMNodeID = require('getDOMNodeID');
29
var keyOf = require('keyOf');
@@ -31,78 +31,77 @@ var keyOf = require('keyOf');
31
var topLevelTypes = EventConstants.topLevelTypes;
32
var getFirstReactDOM = ReactInstanceHandles.getFirstReactDOM;
33
34
-var abstractEventTypes = {
34
+var eventTypes = {
35
mouseEnter: {registrationName: keyOf({onMouseEnter: null})},
36
mouseLeave: {registrationName: keyOf({onMouseLeave: null})}
37
};
38
39
-/**
40
- * For almost every interaction we care about, there will be a top-level
41
- * `mouseover` and `mouseout` event that occurs so only pay attention to one of
42
- * the two (to avoid duplicate events). We use the `mouseout` event.
43
- *
44
- * However, there's one interaction where there will be no `mouseout` event to
45
- * rely on - mousing from outside the browser *into* the chrome. We detect this
46
- * scenario and only in that case, we use the `mouseover` event.
47
- *
48
- * @param {string} topLevelType Record from `EventConstants`.
49
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
50
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
51
- * @param {object} nativeEvent Native browser event.
52
- * @return {*} An accumulation of `AbstractEvent`s.
53
- * @see {EventPluginHub.extractEvents}
54
- */
55
-var extractEvents = function(
56
- topLevelType,
57
- topLevelTarget,
58
- topLevelTargetID,
59
- nativeEvent) {
60
- if (topLevelType === topLevelTypes.topMouseOver &&
61
- (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
62
- return null;
63
- }
64
- if (topLevelType !== topLevelTypes.topMouseOut &&
65
- topLevelType !== topLevelTypes.topMouseOver) {
66
- return null; // Must not be a mouse in or mouse out - ignoring.
67
- }
39
+var EnterLeaveEventPlugin = {
40
69
- var to, from;
70
- if (topLevelType === topLevelTypes.topMouseOut) {
71
- to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) ||
72
- ExecutionEnvironment.global;
73
- from = topLevelTarget;
74
- } else {
75
- to = topLevelTarget;
76
- from = ExecutionEnvironment.global;
77
- }
41
+ eventTypes: eventTypes,
42
79
- // Nothing pertains to our managed components.
80
- if (from === to) {
81
- return null;
82
- }
43
+ /**
44
+ * For almost every interaction we care about, there will be both a top-level
45
+ * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
46
+ * we do not extract duplicate events. However, moving the mouse into the
47
+ * browser from outside will not fire a `mouseout` event. In this case, we use
48
+ * the `mouseover` top-level event.
49
+ *
50
+ * @param {string} topLevelType Record from `EventConstants`.
51
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
52
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
53
+ * @param {object} nativeEvent Native browser event.
54
+ * @return {*} An accumulation of synthetic events.
55
+ * @see {EventPluginHub.extractEvents}
56
+ */
57
+ extractEvents: function(
58
+ topLevelType,
59
+ topLevelTarget,
60
+ topLevelTargetID,
61
+ nativeEvent) {
62
+ if (topLevelType === topLevelTypes.topMouseOver &&
63
+ (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
64
+ return null;
65
+ }
66
+ if (topLevelType !== topLevelTypes.topMouseOut &&
67
+ topLevelType !== topLevelTypes.topMouseOver) {
68
+ // Must not be a mouse in or mouse out - ignoring.
69
+ return null;
70
+ }
71
84
- var fromID = from ? getDOMNodeID(from) : '';
85
- var toID = to ? getDOMNodeID(to) : '';
72
+ var from, to;
73
+ if (topLevelType === topLevelTypes.topMouseOut) {
74
+ from = topLevelTarget;
75
+ to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement)
76
+ || ExecutionEnvironment.global;
77
+ } else {
78
+ from = ExecutionEnvironment.global;
79
+ to = topLevelTarget;
80
+ }
81
87
- var leave = AbstractEvent.getPooled(
88
- abstractEventTypes.mouseLeave,
89
- fromID,
90
- nativeEvent
91
- );
92
- var enter = AbstractEvent.getPooled(
93
- abstractEventTypes.mouseEnter,
94
- toID,
95
- nativeEvent
96
- );
82
+ if (from === to) {
83
+ // Nothing pertains to our managed components.
84
+ return null;
85
+ }
86
98
- EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
87
+ var fromID = from ? getDOMNodeID(from) : '';
88
+ var toID = to ? getDOMNodeID(to) : '';
89
100
- return [leave, enter];
101
-};
90
+ var leave = SyntheticMouseEvent.getPooled(
91
+ eventTypes.mouseLeave,
92
+ fromID,
93
+ nativeEvent
94
+ );
95
+ var enter = SyntheticMouseEvent.getPooled(
96
+ eventTypes.mouseEnter,
97
+ toID,
98
+ nativeEvent
99
+ );
100
+
101
+ EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
102
+ return [leave, enter];
103
+ }
104
103
-var EnterLeaveEventPlugin = {
104
- abstractEventTypes: abstractEventTypes,
105
- extractEvents: extractEvents
105
};
106
107
module.exports = EnterLeaveEventPlugin;
src/eventPlugins/ResponderEventPlugin.js
+138
-141
@@ -18,10 +18,10 @@
18
19
"use strict";
20
21
-var AbstractEvent = require('AbstractEvent');
21
var EventConstants = require('EventConstants');
22
var EventPluginUtils = require('EventPluginUtils');
23
var EventPropagators = require('EventPropagators');
24
+var SyntheticEvent = require('SyntheticEvent');
25
26
var accumulate = require('accumulate');
27
var keyOf = require('keyOf');
@@ -41,11 +41,7 @@ var executeDispatchesInOrderStopAtTrue =
41
var responderID = null;
42
var isPressing = false;
43
44
-var getResponderID = function() {
45
- return responderID;
46
-};
47
-
48
-var abstractEventTypes = {
44
+var eventTypes = {
45
/**
46
* On a `touchStart`/`mouseDown`, is it desired that this element become the
47
* responder?
@@ -116,22 +112,22 @@ var abstractEventTypes = {
112
* `extractEvents()`.
113
* - These events that are returned from `extractEvents` are "deferred
114
* dispatched events".
119
- * - When returned from `extractEvents`, deferred dispatched events
120
- * contain an "accumulation" of deferred dispatches.
121
- * -- These deferred dispatches are accumulated/collected before they are
122
- * returned, but processed at a later time by the `EventPluginHub` (hence the
123
- * name deferred).
115
+ * - When returned from `extractEvents`, deferred-dispatched events contain an
116
+ * "accumulation" of deferred dispatches.
117
+ * - These deferred dispatches are accumulated/collected before they are
118
+ * returned, but processed at a later time by the `EventPluginHub` (hence the
119
+ * name deferred).
120
*
125
- * In the process of returning their deferred dispatched events, event plugins
121
+ * In the process of returning their deferred-dispatched events, event plugins
122
* themselves can dispatch events on-demand without returning them from
127
- * `extractEvents`. Plugins might want to do this, so that they can use
128
- * event dispatching as a tool that helps them decide which events should be
129
- * extracted in the first place.
123
+ * `extractEvents`. Plugins might want to do this, so that they can use event
124
+ * dispatching as a tool that helps them decide which events should be extracted
125
+ * in the first place.
126
*
127
* "On-Demand-Dispatched Events":
128
*
133
- * - On-demand dispatched are not returned from `extractEvents`.
134
- * - On-demand dispatched events are dispatched during the process of returning
129
+ * - On-demand-dispatched events are not returned from `extractEvents`.
130
+ * - On-demand-dispatched events are dispatched during the process of returning
131
* the deferred-dispatched events.
132
* - They should not have side effects.
133
* - They should be avoided, and/or eventually be replaced with another
@@ -158,81 +154,81 @@ var abstractEventTypes = {
154
* - `touchStart` (`EventPluginHub` dispatches as usual)
155
* - `responderGrant/Reject` (`EventPluginHub` dispatches as usual)
156
*
161
- * @returns {Accumulation<AbstractEvent>}
162
- */
163
-
164
-/**
157
* @param {string} topLevelType Record from `EventConstants`.
166
- * @param {string} renderedTargetID ID of deepest React rendered element.
158
+ * @param {string} topLevelTargetID ID of deepest React rendered element.
159
* @param {object} nativeEvent Native browser event.
168
- * @return {*} An accumulation of extracted `AbstractEvent`s.
160
+ * @return {*} An accumulation of synthetic events.
161
*/
170
-var setResponderAndExtractTransfer =
171
- function(topLevelType, renderedTargetID, nativeEvent) {
172
- var type;
173
- var shouldSetEventType =
174
- isStartish(topLevelType) ? abstractEventTypes.startShouldSetResponder :
175
- isMoveish(topLevelType) ? abstractEventTypes.moveShouldSetResponder :
176
- abstractEventTypes.scrollShouldSetResponder;
162
+function setResponderAndExtractTransfer(
163
+ topLevelType,
164
+ topLevelTargetID,
165
+ nativeEvent) {
166
+ var shouldSetEventType =
167
+ isStartish(topLevelType) ? eventTypes.startShouldSetResponder :
168
+ isMoveish(topLevelType) ? eventTypes.moveShouldSetResponder :
169
+ eventTypes.scrollShouldSetResponder;
170
178
- var bubbleShouldSetFrom = responderID || renderedTargetID;
179
- var shouldSetEvent = AbstractEvent.getPooled(
180
- shouldSetEventType,
181
- bubbleShouldSetFrom,
182
- topLevelType,
183
- nativeEvent,
184
- AbstractEvent.normalizePointerData(nativeEvent)
185
- );
186
- EventPropagators.accumulateTwoPhaseDispatches(shouldSetEvent);
187
- var wantsResponderID = executeDispatchesInOrderStopAtTrue(shouldSetEvent);
188
- AbstractEvent.release(shouldSetEvent);
171
+ var bubbleShouldSetFrom = responderID || topLevelTargetID;
172
+ var shouldSetEvent = SyntheticEvent.getPooled(
173
+ shouldSetEventType,
174
+ bubbleShouldSetFrom,
175
+ nativeEvent
176
+ );
177
+ EventPropagators.accumulateTwoPhaseDispatches(shouldSetEvent);
178
+ var wantsResponderID = executeDispatchesInOrderStopAtTrue(shouldSetEvent);
179
+ if (!shouldSetEvent.isPersistent()) {
180
+ shouldSetEvent.constructor.release(shouldSetEvent);
181
+ }
182
190
- if (!wantsResponderID || wantsResponderID === responderID) {
191
- return null;
192
- }
193
- var extracted;
194
- var grantEvent = AbstractEvent.getPooled(
195
- abstractEventTypes.responderGrant,
196
- wantsResponderID,
197
- topLevelType,
183
+ if (!wantsResponderID || wantsResponderID === responderID) {
184
+ return null;
185
+ }
186
+ var extracted;
187
+ var grantEvent = SyntheticEvent.getPooled(
188
+ eventTypes.responderGrant,
189
+ wantsResponderID,
190
+ nativeEvent
191
+ );
192
+
193
+ EventPropagators.accumulateDirectDispatches(grantEvent);
194
+ if (responderID) {
195
+ var terminationRequestEvent = SyntheticEvent.getPooled(
196
+ eventTypes.responderTerminationRequest,
197
+ responderID,
198
nativeEvent
199
);
200
+ EventPropagators.accumulateDirectDispatches(terminationRequestEvent);
201
+ var shouldSwitch = !hasDispatches(terminationRequestEvent) ||
202
+ executeDirectDispatch(terminationRequestEvent);
203
+ if (!terminationRequestEvent.isPersistent()) {
204
+ terminationRequestEvent.constructor.release(terminationRequestEvent);
205
+ }
206
201
- EventPropagators.accumulateDirectDispatches(grantEvent);
202
- if (responderID) {
203
- type = abstractEventTypes.responderTerminationRequest;
204
- var terminationRequestEvent = AbstractEvent.getPooled(type, responderID);
205
- EventPropagators.accumulateDirectDispatches(terminationRequestEvent);
206
- var shouldSwitch = !hasDispatches(terminationRequestEvent) ||
207
- executeDirectDispatch(terminationRequestEvent);
208
- AbstractEvent.release(terminationRequestEvent);
209
- if (shouldSwitch) {
210
- var terminateType = abstractEventTypes.responderTerminate;
211
- var terminateEvent = AbstractEvent.getPooled(
212
- terminateType,
213
- responderID,
214
- topLevelType,
215
- nativeEvent
216
- );
217
- EventPropagators.accumulateDirectDispatches(terminateEvent);
218
- extracted = accumulate(extracted, [grantEvent, terminateEvent]);
219
- responderID = wantsResponderID;
220
- } else {
221
- var rejectEvent = AbstractEvent.getPooled(
222
- abstractEventTypes.responderReject,
223
- wantsResponderID,
224
- topLevelType,
225
- nativeEvent
226
- );
227
- EventPropagators.accumulateDirectDispatches(rejectEvent);
228
- extracted = accumulate(extracted, rejectEvent);
229
- }
230
- } else {
231
- extracted = accumulate(extracted, grantEvent);
207
+ if (shouldSwitch) {
208
+ var terminateType = eventTypes.responderTerminate;
209
+ var terminateEvent = SyntheticEvent.getPooled(
210
+ terminateType,
211
+ responderID,
212
+ nativeEvent
213
+ );
214
+ EventPropagators.accumulateDirectDispatches(terminateEvent);
215
+ extracted = accumulate(extracted, [grantEvent, terminateEvent]);
216
responderID = wantsResponderID;
217
+ } else {
218
+ var rejectEvent = SyntheticEvent.getPooled(
219
+ eventTypes.responderReject,
220
+ wantsResponderID,
221
+ nativeEvent
222
+ );
223
+ EventPropagators.accumulateDirectDispatches(rejectEvent);
224
+ extracted = accumulate(extracted, rejectEvent);
225
}
234
- return extracted;
235
- };
226
+ } else {
227
+ extracted = accumulate(extracted, grantEvent);
228
+ responderID = wantsResponderID;
229
+ }
230
+ return extracted;
231
+}
232
233
/**
234
* A transfer is a negotiation between a currently set responder and the next
@@ -241,9 +237,8 @@ var setResponderAndExtractTransfer =
237
* currently a responder set (in other words as long as the user is pressing
238
* down).
239
*
244
- * @param {EventConstants.topLevelTypes} topLevelType
245
- * @return {boolean} Whether or not a transfer of responder could possibly
246
- * occur.
240
+ * @param {string} topLevelType Record from `EventConstants`.
241
+ * @return {boolean} True if a transfer of responder could possibly occur.
242
*/
243
function canTriggerTransfer(topLevelType) {
244
return topLevelType === EventConstants.topLevelTypes.topScroll ||
@@ -252,68 +247,70 @@ function canTriggerTransfer(topLevelType) {
247
}
248
249
/**
255
- * @param {string} topLevelType Record from `EventConstants`.
256
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
257
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
258
- * @param {object} nativeEvent Native browser event.
259
- * @return {*} An accumulation of `AbstractEvent`s.
260
- * @see {EventPluginHub.extractEvents}
250
+ * Event plugin for formalizing the negotiation between claiming locks on
251
+ * receiving touches.
252
*/
262
-var extractEvents = function(
263
- topLevelType,
264
- topLevelTarget,
265
- topLevelTargetID,
266
- nativeEvent) {
267
- var extracted;
268
- // Must have missed an end event - reset the state here.
269
- if (responderID && isStartish(topLevelType)) {
270
- responderID = null;
271
- }
272
- if (isStartish(topLevelType)) {
273
- isPressing = true;
274
- } else if (isEndish(topLevelType)) {
275
- isPressing = false;
276
- }
277
- if (canTriggerTransfer(topLevelType)) {
278
- var transfer = setResponderAndExtractTransfer(
253
+var ResponderEventPlugin = {
254
+
255
+ getResponderID: function() {
256
+ return responderID;
257
+ },
258
+
259
+ eventTypes: eventTypes,
260
+
261
+ /**
262
+ * @param {string} topLevelType Record from `EventConstants`.
263
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
264
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
265
+ * @param {object} nativeEvent Native browser event.
266
+ * @return {*} An accumulation of synthetic events.
267
+ * @see {EventPluginHub.extractEvents}
268
+ */
269
+ extractEvents: function(
270
topLevelType,
271
+ topLevelTarget,
272
topLevelTargetID,
281
- nativeEvent
282
- );
283
- if (transfer) {
284
- extracted = accumulate(extracted, transfer);
273
+ nativeEvent) {
274
+ var extracted;
275
+ // Must have missed an end event - reset the state here.
276
+ if (responderID && isStartish(topLevelType)) {
277
+ responderID = null;
278
}
279
+ if (isStartish(topLevelType)) {
280
+ isPressing = true;
281
+ } else if (isEndish(topLevelType)) {
282
+ isPressing = false;
283
+ }
284
+ if (canTriggerTransfer(topLevelType)) {
285
+ var transfer = setResponderAndExtractTransfer(
286
+ topLevelType,
287
+ topLevelTargetID,
288
+ nativeEvent
289
+ );
290
+ if (transfer) {
291
+ extracted = accumulate(extracted, transfer);
292
+ }
293
+ }
294
+ // Now that we know the responder is set correctly, we can dispatch
295
+ // responder type events (directly to the responder).
296
+ var type = isMoveish(topLevelType) ? eventTypes.responderMove :
297
+ isEndish(topLevelType) ? eventTypes.responderRelease :
298
+ isStartish(topLevelType) ? eventTypes.responderStart : null;
299
+ if (type) {
300
+ var gesture = SyntheticEvent.getPooled(
301
+ type,
302
+ responderID || '',
303
+ nativeEvent
304
+ );
305
+ EventPropagators.accumulateDirectDispatches(gesture);
306
+ extracted = accumulate(extracted, gesture);
307
+ }
308
+ if (type === eventTypes.responderRelease) {
309
+ responderID = null;
310
+ }
311
+ return extracted;
312
}
287
- // Now that we know the responder is set correctly, we can dispatch
288
- // responder type events (directly to the responder).
289
- var type = isMoveish(topLevelType) ? abstractEventTypes.responderMove :
290
- isEndish(topLevelType) ? abstractEventTypes.responderRelease :
291
- isStartish(topLevelType) ? abstractEventTypes.responderStart : null;
292
- if (type) {
293
- var data = AbstractEvent.normalizePointerData(nativeEvent);
294
- var gesture = AbstractEvent.getPooled(
295
- type,
296
- responderID,
297
- nativeEvent,
298
- data
299
- );
300
- EventPropagators.accumulateDirectDispatches(gesture);
301
- extracted = accumulate(extracted, gesture);
302
- }
303
- if (type === abstractEventTypes.responderRelease) {
304
- responderID = null;
305
- }
306
- return extracted;
307
-};
313
309
-/**
310
- * Event plugin for formalizing the negotiation between claiming locks on
311
- * receiving touches.
312
- */
313
-var ResponderEventPlugin = {
314
- abstractEventTypes: abstractEventTypes,
315
- extractEvents: extractEvents,
316
- getResponderID: getResponderID
314
};
315
316
module.exports = ResponderEventPlugin;
src/eventPlugins/SimpleEventPlugin.js
+262
-237
@@ -18,201 +18,237 @@
18
19
"use strict";
20
21
-var AbstractEvent = require('AbstractEvent');
21
var EventConstants = require('EventConstants');
22
var EventPropagators = require('EventPropagators');
23
+var SyntheticEvent = require('SyntheticEvent');
24
+var SyntheticFocusEvent = require('SyntheticFocusEvent');
25
+var SyntheticKeyboardEvent = require('SyntheticKeyboardEvent');
26
+var SyntheticMouseEvent = require('SyntheticMouseEvent');
27
+var SyntheticMutationEvent = require('SyntheticMutationEvent');
28
+var SyntheticTouchEvent = require('SyntheticTouchEvent');
29
+var SyntheticUIEvent = require('SyntheticUIEvent');
30
+var SyntheticWheelEvent = require('SyntheticWheelEvent');
31
32
+var invariant = require('invariant');
33
var keyOf = require('keyOf');
34
35
var topLevelTypes = EventConstants.topLevelTypes;
36
29
-var SimpleEventPlugin = {
30
- abstractEventTypes: {
31
- // Note: We do not allow listening to mouseOver events. Instead, use the
32
- // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.
33
- mouseDown: {
34
- phasedRegistrationNames: {
35
- bubbled: keyOf({onMouseDown: true}),
36
- captured: keyOf({onMouseDownCapture: true})
37
- }
38
- },
39
- mouseUp: {
40
- phasedRegistrationNames: {
41
- bubbled: keyOf({onMouseUp: true}),
42
- captured: keyOf({onMouseUpCapture: true})
43
- }
44
- },
45
- mouseMove: {
46
- phasedRegistrationNames: {
47
- bubbled: keyOf({onMouseMove: true}),
48
- captured: keyOf({onMouseMoveCapture: true})
49
- }
50
- },
51
- doubleClick: {
52
- phasedRegistrationNames: {
53
- bubbled: keyOf({onDoubleClick: true}),
54
- captured: keyOf({onDoubleClickCapture: true})
55
- }
56
- },
57
- click: {
58
- phasedRegistrationNames: {
59
- bubbled: keyOf({onClick: true}),
60
- captured: keyOf({onClickCapture: true})
61
- }
62
- },
63
- wheel: {
64
- phasedRegistrationNames: {
65
- bubbled: keyOf({onWheel: true}),
66
- captured: keyOf({onWheelCapture: true})
67
- }
68
- },
69
- touchStart: {
70
- phasedRegistrationNames: {
71
- bubbled: keyOf({onTouchStart: true}),
72
- captured: keyOf({onTouchStartCapture: true})
73
- }
74
- },
75
- touchEnd: {
76
- phasedRegistrationNames: {
77
- bubbled: keyOf({onTouchEnd: true}),
78
- captured: keyOf({onTouchEndCapture: true})
79
- }
80
- },
81
- touchCancel: {
82
- phasedRegistrationNames: {
83
- bubbled: keyOf({onTouchCancel: true}),
84
- captured: keyOf({onTouchCancelCapture: true})
85
- }
86
- },
87
- touchMove: {
88
- phasedRegistrationNames: {
89
- bubbled: keyOf({onTouchMove: true}),
90
- captured: keyOf({onTouchMoveCapture: true})
91
- }
92
- },
93
- keyUp: {
94
- phasedRegistrationNames: {
95
- bubbled: keyOf({onKeyUp: true}),
96
- captured: keyOf({onKeyUpCapture: true})
97
- }
98
- },
99
- keyPress: {
100
- phasedRegistrationNames: {
101
- bubbled: keyOf({onKeyPress: true}),
102
- captured: keyOf({onKeyPressCapture: true})
103
- }
104
- },
105
- keyDown: {
106
- phasedRegistrationNames: {
107
- bubbled: keyOf({onKeyDown: true}),
108
- captured: keyOf({onKeyDownCapture: true})
109
- }
110
- },
111
- input: {
112
- phasedRegistrationNames: {
113
- bubbled: keyOf({onInput: true}),
114
- captured: keyOf({onInputCapture: true})
115
- }
116
- },
117
- focus: {
118
- phasedRegistrationNames: {
119
- bubbled: keyOf({onFocus: true}),
120
- captured: keyOf({onFocusCapture: true})
121
- }
122
- },
123
- blur: {
124
- phasedRegistrationNames: {
125
- bubbled: keyOf({onBlur: true}),
126
- captured: keyOf({onBlurCapture: true})
127
- }
128
- },
129
- scroll: {
130
- phasedRegistrationNames: {
131
- bubbled: keyOf({onScroll: true}),
132
- captured: keyOf({onScrollCapture: true})
133
- }
134
- },
135
- change: {
136
- phasedRegistrationNames: {
137
- bubbled: keyOf({onChange: true}),
138
- captured: keyOf({onChangeCapture: true})
139
- }
140
- },
141
- submit: {
142
- phasedRegistrationNames: {
143
- bubbled: keyOf({onSubmit: true}),
144
- captured: keyOf({onSubmitCapture: true})
145
- }
146
- },
147
- DOMCharacterDataModified: {
148
- phasedRegistrationNames: {
149
- bubbled: keyOf({onDOMCharacterDataModified: true}),
150
- captured: keyOf({onDOMCharacterDataModifiedCapture: true})
151
- }
152
- },
153
- drag: {
154
- phasedRegistrationNames: {
155
- bubbled: keyOf({onDrag: true}),
156
- captured: keyOf({onDragCapture: true})
157
- }
158
- },
159
- dragEnd: {
160
- phasedRegistrationNames: {
161
- bubbled: keyOf({onDragEnd: true}),
162
- captured: keyOf({onDragEndCapture: true})
163
- }
164
- },
165
- dragEnter: {
166
- phasedRegistrationNames: {
167
- bubbled: keyOf({onDragEnter: true}),
168
- captured: keyOf({onDragEnterCapture: true})
169
- }
170
- },
171
- dragExit: {
172
- phasedRegistrationNames: {
173
- bubbled: keyOf({onDragExit: true}),
174
- captured: keyOf({onDragExitCapture: true})
175
- }
176
- },
177
- dragLeave: {
178
- phasedRegistrationNames: {
179
- bubbled: keyOf({onDragLeave: true}),
180
- captured: keyOf({onDragLeaveCapture: true})
181
- }
182
- },
183
- dragOver: {
184
- phasedRegistrationNames: {
185
- bubbled: keyOf({onDragOver: true}),
186
- captured: keyOf({onDragOverCapture: true})
187
- }
188
- },
189
- dragStart: {
190
- phasedRegistrationNames: {
191
- bubbled: keyOf({onDragStart: true}),
192
- captured: keyOf({onDragStartCapture: true})
193
- }
194
- },
195
- drop: {
196
- phasedRegistrationNames: {
197
- bubbled: keyOf({onDrop: true}),
198
- captured: keyOf({onDropCapture: true})
199
- }
37
+var eventTypes = {
38
+ blur: {
39
+ phasedRegistrationNames: {
40
+ bubbled: keyOf({onBlur: true}),
41
+ captured: keyOf({onBlurCapture: true})
42
+ }
43
+ },
44
+ change: {
45
+ phasedRegistrationNames: {
46
+ bubbled: keyOf({onChange: true}),
47
+ captured: keyOf({onChangeCapture: true})
48
+ }
49
+ },
50
+ click: {
51
+ phasedRegistrationNames: {
52
+ bubbled: keyOf({onClick: true}),
53
+ captured: keyOf({onClickCapture: true})
54
+ }
55
+ },
56
+ doubleClick: {
57
+ phasedRegistrationNames: {
58
+ bubbled: keyOf({onDoubleClick: true}),
59
+ captured: keyOf({onDoubleClickCapture: true})
60
+ }
61
+ },
62
+ drag: {
63
+ phasedRegistrationNames: {
64
+ bubbled: keyOf({onDrag: true}),
65
+ captured: keyOf({onDragCapture: true})
66
+ }
67
+ },
68
+ dragEnd: {
69
+ phasedRegistrationNames: {
70
+ bubbled: keyOf({onDragEnd: true}),
71
+ captured: keyOf({onDragEndCapture: true})
72
+ }
73
+ },
74
+ dragEnter: {
75
+ phasedRegistrationNames: {
76
+ bubbled: keyOf({onDragEnter: true}),
77
+ captured: keyOf({onDragEnterCapture: true})
78
+ }
79
+ },
80
+ dragExit: {
81
+ phasedRegistrationNames: {
82
+ bubbled: keyOf({onDragExit: true}),
83
+ captured: keyOf({onDragExitCapture: true})
84
+ }
85
+ },
86
+ dragLeave: {
87
+ phasedRegistrationNames: {
88
+ bubbled: keyOf({onDragLeave: true}),
89
+ captured: keyOf({onDragLeaveCapture: true})
90
+ }
91
+ },
92
+ dragOver: {
93
+ phasedRegistrationNames: {
94
+ bubbled: keyOf({onDragOver: true}),
95
+ captured: keyOf({onDragOverCapture: true})
96
+ }
97
+ },
98
+ dragStart: {
99
+ phasedRegistrationNames: {
100
+ bubbled: keyOf({onDragStart: true}),
101
+ captured: keyOf({onDragStartCapture: true})
102
+ }
103
+ },
104
+ drop: {
105
+ phasedRegistrationNames: {
106
+ bubbled: keyOf({onDrop: true}),
107
+ captured: keyOf({onDropCapture: true})
108
+ }
109
+ },
110
+ focus: {
111
+ phasedRegistrationNames: {
112
+ bubbled: keyOf({onFocus: true}),
113
+ captured: keyOf({onFocusCapture: true})
114
+ }
115
+ },
116
+ input: {
117
+ phasedRegistrationNames: {
118
+ bubbled: keyOf({onInput: true}),
119
+ captured: keyOf({onInputCapture: true})
120
+ }
121
+ },
122
+ keyDown: {
123
+ phasedRegistrationNames: {
124
+ bubbled: keyOf({onKeyDown: true}),
125
+ captured: keyOf({onKeyDownCapture: true})
126
+ }
127
+ },
128
+ keyPress: {
129
+ phasedRegistrationNames: {
130
+ bubbled: keyOf({onKeyPress: true}),
131
+ captured: keyOf({onKeyPressCapture: true})
132
+ }
133
+ },
134
+ keyUp: {
135
+ phasedRegistrationNames: {
136
+ bubbled: keyOf({onKeyUp: true}),
137
+ captured: keyOf({onKeyUpCapture: true})
138
+ }
139
+ },
140
+ // Note: We do not allow listening to mouseOver events. Instead, use the
141
+ // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.
142
+ mouseDown: {
143
+ phasedRegistrationNames: {
144
+ bubbled: keyOf({onMouseDown: true}),
145
+ captured: keyOf({onMouseDownCapture: true})
146
+ }
147
+ },
148
+ mouseMove: {
149
+ phasedRegistrationNames: {
150
+ bubbled: keyOf({onMouseMove: true}),
151
+ captured: keyOf({onMouseMoveCapture: true})
152
+ }
153
+ },
154
+ mouseUp: {
155
+ phasedRegistrationNames: {
156
+ bubbled: keyOf({onMouseUp: true}),
157
+ captured: keyOf({onMouseUpCapture: true})
158
+ }
159
+ },
160
+ scroll: {
161
+ phasedRegistrationNames: {
162
+ bubbled: keyOf({onScroll: true}),
163
+ captured: keyOf({onScrollCapture: true})
164
+ }
165
+ },
166
+ submit: {
167
+ phasedRegistrationNames: {
168
+ bubbled: keyOf({onSubmit: true}),
169
+ captured: keyOf({onSubmitCapture: true})
170
}
171
},
172
+ touchCancel: {
173
+ phasedRegistrationNames: {
174
+ bubbled: keyOf({onTouchCancel: true}),
175
+ captured: keyOf({onTouchCancelCapture: true})
176
+ }
177
+ },
178
+ touchEnd: {
179
+ phasedRegistrationNames: {
180
+ bubbled: keyOf({onTouchEnd: true}),
181
+ captured: keyOf({onTouchEndCapture: true})
182
+ }
183
+ },
184
+ touchMove: {
185
+ phasedRegistrationNames: {
186
+ bubbled: keyOf({onTouchMove: true}),
187
+ captured: keyOf({onTouchMoveCapture: true})
188
+ }
189
+ },
190
+ touchStart: {
191
+ phasedRegistrationNames: {
192
+ bubbled: keyOf({onTouchStart: true}),
193
+ captured: keyOf({onTouchStartCapture: true})
194
+ }
195
+ },
196
+ wheel: {
197
+ phasedRegistrationNames: {
198
+ bubbled: keyOf({onWheel: true}),
199
+ captured: keyOf({onWheelCapture: true})
200
+ }
201
+ }
202
+};
203
+
204
+var topLevelEventsToDispatchConfig = {
205
+ topBlur: eventTypes.blur,
206
+ topChange: eventTypes.change,
207
+ topClick: eventTypes.click,
208
+ topDoubleClick: eventTypes.doubleClick,
209
+ topDOMCharacterDataModified: eventTypes.DOMCharacterDataModified,
210
+ topDrag: eventTypes.drag,
211
+ topDragEnd: eventTypes.dragEnd,
212
+ topDragEnter: eventTypes.dragEnter,
213
+ topDragExit: eventTypes.dragExit,
214
+ topDragLeave: eventTypes.dragLeave,
215
+ topDragOver: eventTypes.dragOver,
216
+ topDragStart: eventTypes.dragStart,
217
+ topDrop: eventTypes.drop,
218
+ topFocus: eventTypes.focus,
219
+ topInput: eventTypes.input,
220
+ topKeyDown: eventTypes.keyDown,
221
+ topKeyPress: eventTypes.keyPress,
222
+ topKeyUp: eventTypes.keyUp,
223
+ topMouseDown: eventTypes.mouseDown,
224
+ topMouseMove: eventTypes.mouseMove,
225
+ topMouseUp: eventTypes.mouseUp,
226
+ topScroll: eventTypes.scroll,
227
+ topSubmit: eventTypes.submit,
228
+ topTouchCancel: eventTypes.touchCancel,
229
+ topTouchEnd: eventTypes.touchEnd,
230
+ topTouchMove: eventTypes.touchMove,
231
+ topTouchStart: eventTypes.touchStart,
232
+ topWheel: eventTypes.wheel
233
+};
234
+
235
+var SimpleEventPlugin = {
236
+
237
+ eventTypes: eventTypes,
238
239
/**
240
* Same as the default implementation, except cancels the event when return
241
* value is false.
242
*
207
- * @param {AbstractEvent} AbstractEvent to handle
208
- * @param {function} Application-level callback
209
- * @param {string} domID DOM id to pass to the callback.
243
+ * @param {object} Event to be dispatched.
244
+ * @param {function} Application-level callback.
245
+ * @param {string} domID DOM ID to pass to the callback.
246
*/
211
- executeDispatch: function(abstractEvent, listener, domID) {
212
- var returnValue = listener(abstractEvent, domID);
247
+ executeDispatch: function(event, listener, domID) {
248
+ var returnValue = listener(event, domID);
249
if (returnValue === false) {
214
- abstractEvent.stopPropagation();
215
- abstractEvent.preventDefault();
250
+ event.stopPropagation();
251
+ event.preventDefault();
252
}
253
},
254
@@ -221,7 +257,7 @@ var SimpleEventPlugin = {
257
* @param {DOMEventTarget} topLevelTarget The listening component root node.
258
* @param {string} topLevelTargetID ID of `topLevelTarget`.
259
* @param {object} nativeEvent Native browser event.
224
- * @return {*} An accumulation of `AbstractEvent`s.
260
+ * @return {*} An accumulation of synthetic events.
261
* @see {EventPluginHub.extractEvents}
262
*/
263
extractEvents: function(
@@ -229,29 +265,30 @@ var SimpleEventPlugin = {
265
topLevelTarget,
266
topLevelTargetID,
267
nativeEvent) {
232
- var data;
233
- var abstractEventType =
234
- SimpleEventPlugin.topLevelTypesToAbstract[topLevelType];
235
- if (!abstractEventType) {
268
+ var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
269
+ if (!dispatchConfig) {
270
return null;
271
}
272
+ var EventConstructor;
273
switch(topLevelType) {
239
- case topLevelTypes.topWheel:
240
- data = AbstractEvent.normalizeMouseWheelData(nativeEvent);
274
+ case topLevelTypes.topChange:
275
+ case topLevelTypes.topInput:
276
+ case topLevelTypes.topSubmit:
277
+ // HTML Events
278
+ // @see http://www.w3.org/TR/html5/index.html#events-0
279
+ EventConstructor = SyntheticEvent;
280
break;
242
- case topLevelTypes.topScroll:
243
- data = AbstractEvent.normalizeScrollDataFromTarget(topLevelTarget);
281
+ case topLevelTypes.topKeyDown:
282
+ case topLevelTypes.topKeyPress:
283
+ case topLevelTypes.topKeyUp:
284
+ EventConstructor = SyntheticKeyboardEvent;
285
+ break;
286
+ case topLevelTypes.topBlur:
287
+ case topLevelTypes.topFocus:
288
+ EventConstructor = SyntheticFocusEvent;
289
break;
290
case topLevelTypes.topClick:
291
case topLevelTypes.topDoubleClick:
247
- case topLevelTypes.topChange:
248
- case topLevelTypes.topDOMCharacterDataModified:
249
- case topLevelTypes.topMouseDown:
250
- case topLevelTypes.topMouseUp:
251
- case topLevelTypes.topMouseMove:
252
- case topLevelTypes.topTouchMove:
253
- case topLevelTypes.topTouchStart:
254
- case topLevelTypes.topTouchEnd:
292
case topLevelTypes.topDrag:
293
case topLevelTypes.topDragEnd:
294
case topLevelTypes.topDragEnter:
@@ -260,53 +297,41 @@ var SimpleEventPlugin = {
297
case topLevelTypes.topDragOver:
298
case topLevelTypes.topDragStart:
299
case topLevelTypes.topDrop:
263
- data = AbstractEvent.normalizePointerData(nativeEvent);
264
- // todo: Use AbstractEvent.normalizeDragEventData for drag/drop?
300
+ case topLevelTypes.topMouseDown:
301
+ case topLevelTypes.topMouseMove:
302
+ case topLevelTypes.topMouseUp:
303
+ EventConstructor = SyntheticMouseEvent;
304
+ break;
305
+ case topLevelTypes.topDOMCharacterDataModified:
306
+ EventConstructor = SyntheticMutationEvent;
307
+ break;
308
+ case topLevelTypes.topTouchCancel:
309
+ case topLevelTypes.topTouchEnd:
310
+ case topLevelTypes.topTouchMove:
311
+ case topLevelTypes.topTouchStart:
312
+ EventConstructor = SyntheticTouchEvent;
313
+ break;
314
+ case topLevelTypes.topScroll:
315
+ EventConstructor = SyntheticUIEvent;
316
+ break;
317
+ case topLevelTypes.topWheel:
318
+ EventConstructor = SyntheticWheelEvent;
319
break;
266
- default:
267
- data = null;
320
}
269
- var abstractEvent = AbstractEvent.getPooled(
270
- abstractEventType,
321
+ invariant(
322
+ EventConstructor,
323
+ 'SimpleEventPlugin: Unhandled event type, `%s`.',
324
+ topLevelType
325
+ );
326
+ var event = EventConstructor.getPooled(
327
+ dispatchConfig,
328
topLevelTargetID,
272
- nativeEvent,
273
- data
329
+ nativeEvent
330
);
275
- EventPropagators.accumulateTwoPhaseDispatches(abstractEvent);
276
- return abstractEvent;
331
+ EventPropagators.accumulateTwoPhaseDispatches(event);
332
+ return event;
333
}
278
-};
334
280
-SimpleEventPlugin.topLevelTypesToAbstract = {
281
- topMouseDown: SimpleEventPlugin.abstractEventTypes.mouseDown,
282
- topMouseUp: SimpleEventPlugin.abstractEventTypes.mouseUp,
283
- topMouseMove: SimpleEventPlugin.abstractEventTypes.mouseMove,
284
- topClick: SimpleEventPlugin.abstractEventTypes.click,
285
- topDoubleClick: SimpleEventPlugin.abstractEventTypes.doubleClick,
286
- topWheel: SimpleEventPlugin.abstractEventTypes.wheel,
287
- topTouchStart: SimpleEventPlugin.abstractEventTypes.touchStart,
288
- topTouchEnd: SimpleEventPlugin.abstractEventTypes.touchEnd,
289
- topTouchMove: SimpleEventPlugin.abstractEventTypes.touchMove,
290
- topTouchCancel: SimpleEventPlugin.abstractEventTypes.touchCancel,
291
- topKeyUp: SimpleEventPlugin.abstractEventTypes.keyUp,
292
- topKeyPress: SimpleEventPlugin.abstractEventTypes.keyPress,
293
- topKeyDown: SimpleEventPlugin.abstractEventTypes.keyDown,
294
- topInput: SimpleEventPlugin.abstractEventTypes.input,
295
- topFocus: SimpleEventPlugin.abstractEventTypes.focus,
296
- topBlur: SimpleEventPlugin.abstractEventTypes.blur,
297
- topScroll: SimpleEventPlugin.abstractEventTypes.scroll,
298
- topChange: SimpleEventPlugin.abstractEventTypes.change,
299
- topSubmit: SimpleEventPlugin.abstractEventTypes.submit,
300
- topDOMCharacterDataModified:
301
- SimpleEventPlugin.abstractEventTypes.DOMCharacterDataModified,
302
- topDrag: SimpleEventPlugin.abstractEventTypes.drag,
303
- topDragEnd: SimpleEventPlugin.abstractEventTypes.dragEnd,
304
- topDragEnter: SimpleEventPlugin.abstractEventTypes.dragEnter,
305
- topDragExit: SimpleEventPlugin.abstractEventTypes.dragExit,
306
- topDragLeave: SimpleEventPlugin.abstractEventTypes.dragLeave,
307
- topDragOver: SimpleEventPlugin.abstractEventTypes.dragOver,
308
- topDragStart: SimpleEventPlugin.abstractEventTypes.dragStart,
309
- topDrop: SimpleEventPlugin.abstractEventTypes.drop
335
};
336
337
module.exports = SimpleEventPlugin;
src/eventPlugins/TapEventPlugin.js
+69
-43
@@ -19,25 +19,49 @@
19
20
"use strict";
21
22
-var AbstractEvent = require('AbstractEvent');
22
+var BrowserEnv = require('BrowserEnv');
23
var EventPluginUtils = require('EventPluginUtils');
24
var EventPropagators = require('EventPropagators');
25
+var SyntheticUIEvent = require('SyntheticUIEvent');
26
+var TouchEventUtils = require('TouchEventUtils');
27
28
var keyOf = require('keyOf');
29
30
var isStartish = EventPluginUtils.isStartish;
31
var isEndish = EventPluginUtils.isEndish;
30
-var storePageCoordsIn = EventPluginUtils.storePageCoordsIn;
31
-var eventDistance = EventPluginUtils.eventDistance;
32
33
/**
34
- * The number of pixels that are tolerated in between a touchStart and
35
- * touchEnd in order to still be considered a 'tap' event.
34
+ * Number of pixels that are tolerated in between a `touchStart` and `touchEnd`
35
+ * in order to still be considered a 'tap' event.
36
*/
37
var tapMoveThreshold = 10;
38
var startCoords = {x: null, y: null};
39
40
-var abstractEventTypes = {
40
+var Axis = {
41
+ x: {page: 'pageX', client: 'clientX', envScroll: 'currentPageScrollLeft'},
42
+ y: {page: 'pageY', client: 'clientY', envScroll: 'currentPageScrollTop'}
43
+};
44
+
45
+function getAxisCoordOfEvent(axis, nativeEvent) {
46
+ var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent);
47
+ if (singleTouch) {
48
+ return singleTouch[axis.page];
49
+ }
50
+ return axis.page in nativeEvent ?
51
+ nativeEvent[axis.page] :
52
+ nativeEvent[axis.client] + BrowserEnv[axis.envScroll];
53
+}
54
+
55
+function getDistance(coords, nativeEvent) {
56
+ var pageX = getAxisCoordOfEvent(Axis.x, nativeEvent);
57
+ var pageY = getAxisCoordOfEvent(Axis.y, nativeEvent);
58
+ return Math.pow(
59
+ Math.pow(pageX - coords.x, 2) + Math.pow(pageY - coords.y, 2),
60
+ 0.5
61
+ );
62
+}
63
+
64
+var eventTypes = {
65
touchTap: {
66
phasedRegistrationNames: {
67
bubbled: keyOf({onTouchTap: null}),
@@ -46,46 +70,48 @@ var abstractEventTypes = {
70
}
71
};
72
49
-/**
50
- * @param {string} topLevelType Record from `EventConstants`.
51
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
52
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
53
- * @param {object} nativeEvent Native browser event.
54
- * @return {*} An accumulation of `AbstractEvent`s.
55
- * @see {EventPluginHub.extractEvents}
56
- */
57
-var extractEvents = function(
58
- topLevelType,
59
- topLevelTarget,
60
- topLevelTargetID,
61
- nativeEvent) {
62
- if (!isStartish(topLevelType) && !isEndish(topLevelType)) {
63
- return;
64
- }
65
- var abstractEvent;
66
- var dist = eventDistance(startCoords, nativeEvent);
67
- if (isEndish(topLevelType) && dist < tapMoveThreshold) {
68
- abstractEvent = AbstractEvent.getPooled(
69
- abstractEventTypes.touchTap,
73
+var TapEventPlugin = {
74
+
75
+ tapMoveThreshold: tapMoveThreshold,
76
+
77
+ eventTypes: eventTypes,
78
+
79
+ /**
80
+ * @param {string} topLevelType Record from `EventConstants`.
81
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
82
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
83
+ * @param {object} nativeEvent Native browser event.
84
+ * @return {*} An accumulation of synthetic events.
85
+ * @see {EventPluginHub.extractEvents}
86
+ */
87
+ extractEvents: function(
88
+ topLevelType,
89
+ topLevelTarget,
90
topLevelTargetID,
71
- nativeEvent
72
- );
73
- }
74
- if (isStartish(topLevelType)) {
75
- storePageCoordsIn(startCoords, nativeEvent);
76
- } else if (isEndish(topLevelType)) {
77
- startCoords.x = 0;
78
- startCoords.y = 0;
91
+ nativeEvent) {
92
+ if (!isStartish(topLevelType) && !isEndish(topLevelType)) {
93
+ return null;
94
+ }
95
+ var event = null;
96
+ var distance = getDistance(startCoords, nativeEvent);
97
+ if (isEndish(topLevelType) && distance < tapMoveThreshold) {
98
+ event = SyntheticUIEvent.getPooled(
99
+ eventTypes.touchTap,
100
+ topLevelTargetID,
101
+ nativeEvent
102
+ );
103
+ }
104
+ if (isStartish(topLevelType)) {
105
+ startCoords.x = getAxisCoordOfEvent(Axis.x, nativeEvent);
106
+ startCoords.y = getAxisCoordOfEvent(Axis.y, nativeEvent);
107
+ } else if (isEndish(topLevelType)) {
108
+ startCoords.x = 0;
109
+ startCoords.y = 0;
110
+ }
111
+ EventPropagators.accumulateTwoPhaseDispatches(event);
112
+ return event;
113
}
80
- EventPropagators.accumulateTwoPhaseDispatches(abstractEvent);
81
- return abstractEvent;
82
-};
114
84
-var TapEventPlugin = {
85
- tapMoveThreshold: tapMoveThreshold,
86
- startCoords: startCoords,
87
- abstractEventTypes: abstractEventTypes,
88
- extractEvents: extractEvents
115
};
116
117
module.exports = TapEventPlugin;
src/eventPlugins/TextChangeEventPlugin.js
+55
-58
@@ -18,18 +18,18 @@
18
19
"use strict";
20
21
-var AbstractEvent = require('AbstractEvent');
21
var EventConstants = require('EventConstants');
22
var EventPluginHub = require('EventPluginHub');
23
var EventPropagators = require('EventPropagators');
24
var ExecutionEnvironment = require('ExecutionEnvironment');
25
+var SyntheticEvent = require('SyntheticEvent');
26
27
var isEventSupported = require('isEventSupported');
28
var keyOf = require('keyOf');
29
30
var topLevelTypes = EventConstants.topLevelTypes;
31
32
-var abstractEventTypes = {
32
+var eventTypes = {
33
textChange: {
34
phasedRegistrationNames: {
35
bubbled: keyOf({onTextChange: null}),
@@ -121,29 +121,28 @@ var stopWatching = function() {
121
* the value of the active element has changed.
122
*/
123
var handlePropertyChange = function(nativeEvent) {
124
- var value;
125
- var abstractEvent;
126
-
127
- if (nativeEvent.propertyName === "value") {
128
- value = nativeEvent.srcElement.value;
129
- if (value !== activeElementValue) {
130
- activeElementValue = value;
131
-
132
- abstractEvent = AbstractEvent.getPooled(
133
- abstractEventTypes.textChange,
134
- activeElementID,
135
- nativeEvent
136
- );
137
- EventPropagators.accumulateTwoPhaseDispatches(abstractEvent);
138
-
139
- // If propertychange bubbled, we'd just bind to it like all the other
140
- // events and have it go through ReactEventTopLevelCallback. Since it
141
- // doesn't, we manually listen for the propertychange event and so we
142
- // have to enqueue and process the abstract event manually.
143
- EventPluginHub.enqueueEvents(abstractEvent);
144
- EventPluginHub.processEventQueue();
145
- }
124
+ if (nativeEvent.propertyName !== "value") {
125
+ return;
126
+ }
127
+ var value = nativeEvent.srcElement.value;
128
+ if (value === activeElementValue) {
129
+ return;
130
}
131
+ activeElementValue = value;
132
+
133
+ var event = SyntheticEvent.getPooled(
134
+ eventTypes.textChange,
135
+ activeElementID,
136
+ nativeEvent
137
+ );
138
+ EventPropagators.accumulateTwoPhaseDispatches(event);
139
+
140
+ // If propertychange bubbled, we'd just bind to it like all the other events
141
+ // and have it go through ReactEventTopLevelCallback. Since it doesn't, we
142
+ // manually listen for the propertychange event and so we have to enqueue and
143
+ // process the abstract event manually.
144
+ EventPluginHub.enqueueEvents(event);
145
+ EventPluginHub.processEventQueue();
146
};
147
148
/**
@@ -154,8 +153,7 @@ if (isInputSupported) {
153
targetIDForTextChangeEvent = function(
154
topLevelType,
155
topLevelTarget,
157
- topLevelTargetID,
158
- nativeEvent) {
156
+ topLevelTargetID) {
157
if (topLevelType === topLevelTypes.topInput) {
158
// In modern browsers (i.e., not IE8 or IE9), the input event is exactly
159
// what we want so fall through here and trigger an abstract event...
@@ -171,8 +169,7 @@ if (isInputSupported) {
169
targetIDForTextChangeEvent = function(
170
topLevelType,
171
topLevelTarget,
174
- topLevelTargetID,
175
- nativeEvent) {
172
+ topLevelTargetID) {
173
if (topLevelType === topLevelTypes.topFocus) {
174
// In IE8, we can capture almost all .value changes by adding a
175
// propertychange handler and looking for events with propertyName
@@ -214,40 +211,40 @@ if (isInputSupported) {
211
};
212
}
213
217
-/**
218
- * @param {string} topLevelType Record from `EventConstants`.
219
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
220
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
221
- * @param {object} nativeEvent Native browser event.
222
- * @return {*} An accumulation of `AbstractEvent`s.
223
- * @see {EventPluginHub.extractEvents}
224
- */
225
-var extractEvents = function(
226
- topLevelType,
227
- topLevelTarget,
228
- topLevelTargetID,
229
- nativeEvent) {
230
- var targetID = targetIDForTextChangeEvent(
231
- topLevelType,
232
- topLevelTarget,
233
- topLevelTargetID,
234
- nativeEvent
235
- );
214
+var TextChangeEventPlugin = {
215
237
- if (targetID) {
238
- var abstractEvent = AbstractEvent.getPooled(
239
- abstractEventTypes.textChange,
240
- targetID,
241
- nativeEvent
216
+ eventTypes: eventTypes,
217
+
218
+ /**
219
+ * @param {string} topLevelType Record from `EventConstants`.
220
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
221
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
222
+ * @param {object} nativeEvent Native browser event.
223
+ * @return {*} An accumulation of synthetic events.
224
+ * @see {EventPluginHub.extractEvents}
225
+ */
226
+ extractEvents: function(
227
+ topLevelType,
228
+ topLevelTarget,
229
+ topLevelTargetID,
230
+ nativeEvent) {
231
+ var targetID = targetIDForTextChangeEvent(
232
+ topLevelType,
233
+ topLevelTarget,
234
+ topLevelTargetID
235
);
243
- EventPropagators.accumulateTwoPhaseDispatches(abstractEvent);
244
- return abstractEvent;
236
+
237
+ if (targetID) {
238
+ var event = SyntheticEvent.getPooled(
239
+ eventTypes.textChange,
240
+ targetID,
241
+ nativeEvent
242
+ );
243
+ EventPropagators.accumulateTwoPhaseDispatches(event);
244
+ return event;
245
+ }
246
}
246
-};
247
248
-var TextChangeEventPlugin = {
249
- abstractEventTypes: abstractEventTypes,
250
- extractEvents: extractEvents
248
};
249
250
module.exports = TextChangeEventPlugin;
src/eventPlugins/__tests__/ResponderEventPlugin-test.js
+24
-28
@@ -23,21 +23,21 @@ var EventConstants;
23
var EventPropagators;
24
var ReactInstanceHandles;
25
var ResponderEventPlugin;
26
-var AbstractEvent;
26
+var SyntheticEvent;
27
28
var GRANDPARENT_ID = '.reactRoot[0]';
29
var PARENT_ID = '.reactRoot[0].0';
30
var CHILD_ID = '.reactRoot[0].0.0';
31
32
var topLevelTypes;
33
-var responderAbstractEventTypes;
33
+var responderEventTypes;
34
var spies;
35
36
var DUMMY_NATIVE_EVENT = {};
37
var DUMMY_RENDERED_TARGET = {};
38
39
var onStartShouldSetResponder = function(id, cb, capture) {
40
- var registrationNames = responderAbstractEventTypes
40
+ var registrationNames = responderEventTypes
41
.startShouldSetResponder
42
.phasedRegistrationNames;
43
CallbackRegistry.putListener(
@@ -48,7 +48,7 @@ var onStartShouldSetResponder = function(id, cb, capture) {
48
};
49
50
var onScrollShouldSetResponder = function(id, cb, capture) {
51
- var registrationNames = responderAbstractEventTypes
51
+ var registrationNames = responderEventTypes
52
.scrollShouldSetResponder
53
.phasedRegistrationNames;
54
CallbackRegistry.putListener(
@@ -59,7 +59,7 @@ var onScrollShouldSetResponder = function(id, cb, capture) {
59
};
60
61
var onMoveShouldSetResponder = function(id, cb, capture) {
62
- var registrationNames = responderAbstractEventTypes
62
+ var registrationNames = responderEventTypes
63
.moveShouldSetResponder
64
.phasedRegistrationNames;
65
CallbackRegistry.putListener(
@@ -73,7 +73,7 @@ var onMoveShouldSetResponder = function(id, cb, capture) {
73
var onResponderGrant = function(id, cb) {
74
CallbackRegistry.putListener(
75
id,
76
- responderAbstractEventTypes.responderGrant.registrationName,
76
+ responderEventTypes.responderGrant.registrationName,
77
cb
78
);
79
};
@@ -165,44 +165,40 @@ var existsInExtraction = function(extracted, test) {
165
* Helper validators.
166
*/
167
function assertGrantEvent(id, extracted) {
168
- var test = function(abstractEvent) {
169
- return abstractEvent instanceof AbstractEvent &&
170
- abstractEvent.reactEventType ===
171
- responderAbstractEventTypes.responderGrant &&
172
- abstractEvent.reactTargetID === id;
168
+ var test = function(event) {
169
+ return event instanceof SyntheticEvent &&
170
+ event.dispatchConfig === responderEventTypes.responderGrant &&
171
+ event.dispatchMarker === id;
172
};
173
expect(ResponderEventPlugin.getResponderID()).toBe(id);
174
expect(existsInExtraction(extracted, test)).toBe(true);
175
}
176
177
function assertResponderMoveEvent(id, extracted) {
179
- var test = function(abstractEvent) {
180
- return abstractEvent instanceof AbstractEvent &&
181
- abstractEvent.reactEventType ===
182
- responderAbstractEventTypes.responderMove &&
183
- abstractEvent.reactTargetID === id;
178
+ var test = function(event) {
179
+ return event instanceof SyntheticEvent &&
180
+ event.dispatchConfig === responderEventTypes.responderMove &&
181
+ event.dispatchMarker === id;
182
};
183
expect(ResponderEventPlugin.getResponderID()).toBe(id);
184
expect(existsInExtraction(extracted, test)).toBe(true);
185
}
186
187
function assertTerminateEvent(id, extracted) {
190
- var test = function(abstractEvent) {
191
- return abstractEvent instanceof AbstractEvent &&
192
- abstractEvent.reactEventType ===
193
- responderAbstractEventTypes.responderTerminate &&
194
- abstractEvent.reactTargetID === id;
188
+ var test = function(event) {
189
+ return event instanceof SyntheticEvent &&
190
+ event.dispatchConfig === responderEventTypes.responderTerminate &&
191
+ event.dispatchMarker === id;
192
};
193
expect(ResponderEventPlugin.getResponderID()).not.toBe(id);
194
expect(existsInExtraction(extracted, test)).toBe(true);
195
}
196
197
function assertRelease(id, extracted) {
201
- var test = function(abstractEvent) {
202
- return abstractEvent instanceof AbstractEvent &&
203
- abstractEvent.reactEventType ===
204
- responderAbstractEventTypes.responderRelease &&
205
- abstractEvent.reactTargetID === id;
198
+ var test = function(event) {
199
+ return event instanceof SyntheticEvent &&
200
+ event.dispatchConfig === responderEventTypes.responderRelease &&
201
+ event.dispatchMarker === id;
202
};
203
expect(ResponderEventPlugin.getResponderID()).toBe(null);
204
expect(existsInExtraction(extracted, test)).toBe(true);
@@ -226,12 +222,12 @@ describe('ResponderEventPlugin', function() {
222
beforeEach(function() {
223
require('mock-modules').dumpCache();
224
229
- AbstractEvent = require('AbstractEvent');
225
CallbackRegistry = require('CallbackRegistry');
226
EventConstants = require('EventConstants');
227
EventPropagators = require('EventPropagators');
228
ReactInstanceHandles = require('ReactInstanceHandles');
229
ResponderEventPlugin = require('ResponderEventPlugin');
230
+ SyntheticEvent = require('SyntheticEvent');
231
EventPropagators.injection.injectInstanceHandle(ReactInstanceHandles);
232
233
// dumpCache, in open-source tests, only resets existing mocks. It does not
@@ -240,7 +236,7 @@ describe('ResponderEventPlugin', function() {
236
CallbackRegistry.__purge();
237
238
topLevelTypes = EventConstants.topLevelTypes;
243
- responderAbstractEventTypes = ResponderEventPlugin.abstractEventTypes;
239
+ responderEventTypes = ResponderEventPlugin.eventTypes;
240
241
spies = {
242
onStartShouldSetResponderChild: function() {},
src/test/ReactTestUtils.js
+3
-3
@@ -187,7 +187,7 @@ var ReactTestUtils = {
187
* on and `Element` node.
188
* @param topLevelType {Object} A type from `EventConstants.topLevelTypes`
189
* @param {!Element} node The dom to simulate an event occurring on.
190
- * @param {?Event} fakeNativeEvent Fake native event to pass to ReactEvent.
190
+ * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
191
*/
192
simulateEventOnNode: function(topLevelType, node, fakeNativeEvent) {
193
var virtualHandler =
@@ -203,7 +203,7 @@ var ReactTestUtils = {
203
* on the `ReactNativeComponent` `comp`.
204
* @param topLevelType {Object} A type from `EventConstants.topLevelTypes`.
205
* @param comp {!ReactNativeComponent}
206
- * @param {?Event} fakeNativeEvent Fake native event to pass to ReactEvent.
206
+ * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
207
*/
208
simulateEventOnDOMComponent: function(topLevelType, comp, fakeNativeEvent) {
209
var reactRootID = comp._rootNodeID || comp._rootDomId;
@@ -280,7 +280,7 @@ for (eventType in topLevelTypes) {
280
eventType.charAt(3).toLowerCase() + eventType.substr(4) : eventType;
281
/**
282
* @param {!Element || ReactNativeComponent} domComponentOrNode
283
- * @param {?Event} nativeEventData Fake native event to pass to ReactEvent.
283
+ * @param {?Event} nativeEventData Fake native event to use in SyntheticEvent.
284
*/
285
ReactTestUtils.Simulate[convenienceName] = makeSimulator(eventType);
286
}