Set currentTarget on synthetic events
Fixes #658, fixes #659.
Ben Alpert committed
Dec 30, 2013 at 11:52 UTC
33dcf8a0b57ed05ef675a714ab8762e9ae7471ed
6 files changed
+91
-10
src/core/ReactDefaultInjection.js
+3
-1
@@ -29,6 +29,7 @@ var ReactDOMSelect = require('ReactDOMSelect');
29
var ReactDOMTextarea = require('ReactDOMTextarea');
30
var ReactEventEmitter = require('ReactEventEmitter');
31
var ReactEventTopLevelCallback = require('ReactEventTopLevelCallback');
32
+var ReactMount = require('ReactMount');
33
var ReactPerf = require('ReactPerf');
34
var ReactRootIndex = require('ReactRootIndex');
35
@@ -53,10 +54,11 @@ var ReactUpdates = require('ReactUpdates');
54
function inject() {
55
ReactEventEmitter.TopLevelCallbackCreator = ReactEventTopLevelCallback;
56
/**
56
- * Inject module for resolving DOM hierarchy and plugin ordering.
57
+ * Inject modules for resolving DOM hierarchy and plugin ordering.
58
*/
59
EventPluginHub.injection.injectEventPluginOrder(DefaultEventPluginOrder);
60
EventPluginHub.injection.injectInstanceHandle(ReactInstanceHandles);
61
+ EventPluginHub.injection.injectMount(ReactMount);
62
63
/**
64
* Some important event plugins included by default (without having to require
src/core/__tests__/ReactEventEmitter-test.js
+47
-4
@@ -34,10 +34,16 @@ require('mock-modules')
34
var keyOf = require('keyOf');
35
var mocks = require('mocks');
36
37
-var EventPluginHub;
37
var ReactMount = require('ReactMount');
38
+var idToNode = {};
39
var getID = ReactMount.getID;
40
-var setID = ReactMount.setID;
40
+var setID = function(el, id) {
41
+ ReactMount.setID(el, id);
42
+ idToNode[id] = el;
43
+};
44
+var oldGetNode = ReactMount.getNode;
45
+
46
+var EventPluginHub;
47
var ReactEventEmitter;
48
var ReactTestUtils;
49
var TapEventPlugin;
@@ -93,10 +99,11 @@ describe('ReactEventEmitter', function() {
99
TapEventPlugin = require('TapEventPlugin');
100
ReactMount = require('ReactMount');
101
EventListener = require('EventListener');
96
- getID = ReactMount.getID;
97
- setID = ReactMount.setID;
102
ReactEventEmitter = require('ReactEventEmitter');
103
ReactTestUtils = require('ReactTestUtils');
104
+ ReactMount.getNode = function(id) {
105
+ return idToNode[id];
106
+ };
107
idCallOrder = [];
108
tapMoveThreshold = TapEventPlugin.tapMoveThreshold;
109
EventPluginHub.injection.injectEventPluginsByName({
@@ -104,6 +111,10 @@ describe('ReactEventEmitter', function() {
111
});
112
});
113
114
+ afterEach(function() {
115
+ ReactMount.getNode = oldGetNode;
116
+ });
117
+
118
it('should store a listener correctly', function() {
119
registerSimpleTestHandler();
120
var listener = ReactEventEmitter.getListener(getID(CHILD), ON_CLICK_KEY);
@@ -162,6 +173,38 @@ describe('ReactEventEmitter', function() {
173
expect(idCallOrder[2]).toBe(getID(GRANDPARENT));
174
});
175
176
+ it('should set currentTarget', function() {
177
+ ReactEventEmitter.putListener(
178
+ getID(CHILD),
179
+ ON_CLICK_KEY,
180
+ function(event) {
181
+ recordID(getID(CHILD));
182
+ expect(event.currentTarget).toBe(CHILD);
183
+ }
184
+ );
185
+ ReactEventEmitter.putListener(
186
+ getID(PARENT),
187
+ ON_CLICK_KEY,
188
+ function(event) {
189
+ recordID(getID(PARENT));
190
+ expect(event.currentTarget).toBe(PARENT);
191
+ }
192
+ );
193
+ ReactEventEmitter.putListener(
194
+ getID(GRANDPARENT),
195
+ ON_CLICK_KEY,
196
+ function(event) {
197
+ recordID(getID(GRANDPARENT));
198
+ expect(event.currentTarget).toBe(GRANDPARENT);
199
+ }
200
+ );
201
+ ReactTestUtils.Simulate.click(CHILD);
202
+ expect(idCallOrder.length).toBe(3);
203
+ expect(idCallOrder[0]).toBe(getID(CHILD));
204
+ expect(idCallOrder[1]).toBe(getID(PARENT));
205
+ expect(idCallOrder[2]).toBe(getID(GRANDPARENT));
206
+ });
207
+
208
it('should support stopPropagation()', function() {
209
ReactEventEmitter.putListener(
210
getID(CHILD),
src/event/EventPluginHub.js
+6
@@ -85,6 +85,12 @@ var EventPluginHub = {
85
*/
86
injection: {
87
88
+ /**
89
+ * @param {object} InjectedMount
90
+ * @public
91
+ */
92
+ injectMount: EventPluginUtils.injection.injectMount,
93
+
94
/**
95
* @param {object} InjectedInstanceHandle
96
* @public
src/event/EventPluginUtils.js
+31
-3
@@ -22,6 +22,28 @@ var EventConstants = require('EventConstants');
22
23
var invariant = require('invariant');
24
25
+/**
26
+ * Injected dependencies:
27
+ */
28
+
29
+/**
30
+ * - `Mount`: [required] Module that can convert between React dom IDs and
31
+ * actual node references.
32
+ */
33
+var injection = {
34
+ Mount: null,
35
+ injectMount: function(InjectedMount) {
36
+ injection.Mount = InjectedMount;
37
+ if (__DEV__) {
38
+ invariant(
39
+ InjectedMount && InjectedMount.getNode,
40
+ 'EventPluginUtils.injection.injectMount(...): Injected Mount module ' +
41
+ 'is missing getNode.'
42
+ );
43
+ }
44
+ }
45
+};
46
+
47
var topLevelTypes = EventConstants.topLevelTypes;
48
49
function isEndish(topLevelType) {
@@ -39,6 +61,7 @@ function isStartish(topLevelType) {
61
topLevelType === topLevelTypes.topTouchStart;
62
}
63
64
+
65
var validateEventDispatches;
66
if (__DEV__) {
67
validateEventDispatches = function(event) {
@@ -90,7 +113,10 @@ function forEachEventDispatch(event, cb) {
113
* @param {string} domID DOM id to pass to the callback.
114
*/
115
function executeDispatch(event, listener, domID) {
93
- listener(event, domID);
116
+ event.currentTarget = injection.Mount.getNode(domID);
117
+ var returnValue = listener(event, domID);
118
+ event.currentTarget = null;
119
+ return returnValue;
120
}
121
122
/**
@@ -175,11 +201,13 @@ var EventPluginUtils = {
201
isEndish: isEndish,
202
isMoveish: isMoveish,
203
isStartish: isStartish,
204
+
205
+ executeDirectDispatch: executeDirectDispatch,
206
+ executeDispatch: executeDispatch,
207
executeDispatchesInOrder: executeDispatchesInOrder,
208
executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
180
- executeDirectDispatch: executeDirectDispatch,
209
hasDispatches: hasDispatches,
182
- executeDispatch: executeDispatch,
210
+ injection: injection,
211
useTouchEvents: false
212
};
213
src/event/synthetic/SyntheticEvent.js
+2
-1
@@ -33,7 +33,8 @@ var mergeInto = require('mergeInto');
33
var EventInterface = {
34
type: null,
35
target: getEventTarget,
36
- currentTarget: null,
36
+ // currentTarget is set when dispatching; no use in copying it here
37
+ currentTarget: emptyFunction.thatReturnsNull,
38
eventPhase: null,
39
bubbles: null,
40
cancelable: null,
src/eventPlugins/SimpleEventPlugin.js
+2
-1
@@ -19,6 +19,7 @@
19
"use strict";
20
21
var EventConstants = require('EventConstants');
22
+var EventPluginUtils = require('EventPluginUtils');
23
var EventPropagators = require('EventPropagators');
24
var SyntheticClipboardEvent = require('SyntheticClipboardEvent');
25
var SyntheticEvent = require('SyntheticEvent');
@@ -270,7 +271,7 @@ var SimpleEventPlugin = {
271
* @param {string} domID DOM ID to pass to the callback.
272
*/
273
executeDispatch: function(event, listener, domID) {
273
- var returnValue = listener(event, domID);
274
+ var returnValue = EventPluginUtils.executeDispatch(event, listener, domID);
275
if (returnValue === false) {
276
event.stopPropagation();
277
event.preventDefault();