@samitouri / QOS-React-2 / commits / 88e90d5601
Fork 0

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 }