Events: Pass native instances up until propagation
Next step: take advantage of having the native instances in EventPropagators instead of converting right back to IDs.
Ben Alpert committed
Oct 16, 2015 at 23:42 UTC
f470cb88f88b4667419f170fcc7971dad4298494
23 files changed
+522
-531
src/renderers/dom/client/ReactDOMComponentTree.js
+7
@@ -148,6 +148,13 @@ function getInstanceFromNode(node) {
148
* DOM node.
149
*/
150
function getNodeFromInstance(inst) {
151
+ // Without this first invariant, passing a non-DOM-component triggers the next
152
+ // invariant for a missing parent, which is super confusing.
153
+ invariant(
154
+ inst._nativeNode !== undefined,
155
+ 'getNodeFromInstance: Invalid argument.'
156
+ );
157
+
158
if (inst._nativeNode) {
159
return inst._nativeNode;
160
}
src/renderers/dom/client/ReactDOMTreeTraversal.js
new
+83
@@ -0,0 +1,83 @@
1
+/**
2
+ * Copyright 2015, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule ReactDOMTreeTraversal
10
+ */
11
+
12
+'use strict';
13
+
14
+var invariant = require('invariant');
15
+
16
+/**
17
+ * Return the lowest common ancestor of A and B, or null if they are in
18
+ * different trees.
19
+ */
20
+function getLowestCommonAncestor(instA, instB) {
21
+ invariant('_nativeNode' in instA, 'getNodeFromInstance: Invalid argument.');
22
+ invariant('_nativeNode' in instB, 'getNodeFromInstance: Invalid argument.');
23
+
24
+ var depthA = 0;
25
+ for (var tempA = instA; tempA; tempA = tempA._nativeParent) {
26
+ depthA++;
27
+ }
28
+ var depthB = 0;
29
+ for (var tempB = instB; tempB; tempB = tempB._nativeParent) {
30
+ depthB++;
31
+ }
32
+
33
+ // If A is deeper, crawl up.
34
+ while (depthA - depthB > 0) {
35
+ instA = instA._nativeParent;
36
+ depthA--;
37
+ }
38
+
39
+ // If B is deeper, crawl up.
40
+ while (depthB - depthA > 0) {
41
+ instB = instB._nativeParent;
42
+ depthB--;
43
+ }
44
+
45
+ // Walk in lockstep until we find a match.
46
+ var depth = depthA;
47
+ while (depth--) {
48
+ if (instA === instB) {
49
+ return instA;
50
+ }
51
+ instA = instA._nativeParent;
52
+ instB = instB._nativeParent;
53
+ }
54
+ return null;
55
+}
56
+
57
+/**
58
+ * Return if A is an ancestor of B.
59
+ */
60
+function isAncestor(instA, instB) {
61
+ invariant('_nativeNode' in instA, 'isAncestor: Invalid argument.');
62
+ invariant('_nativeNode' in instB, 'isAncestor: Invalid argument.');
63
+
64
+ while (instB) {
65
+ if (instB === instA) {
66
+ return true;
67
+ }
68
+ instB = instB._nativeParent;
69
+ }
70
+ return false;
71
+}
72
+
73
+function getParentInstance(inst) {
74
+ invariant('_nativeNode' in inst, 'getParentInstance: Invalid argument.');
75
+
76
+ return inst._nativeParent;
77
+}
78
+
79
+module.exports = {
80
+ isAncestor: isAncestor,
81
+ getLowestCommonAncestor: getLowestCommonAncestor,
82
+ getParentInstance: getParentInstance,
83
+};
src/renderers/dom/client/ReactEventListener.js
+21
-90
@@ -15,32 +15,28 @@
15
var EventListener = require('EventListener');
16
var ExecutionEnvironment = require('ExecutionEnvironment');
17
var PooledClass = require('PooledClass');
18
-var ReactInstanceHandles = require('ReactInstanceHandles');
19
-var ReactMount = require('ReactMount');
18
+var ReactDOMComponentTree = require('ReactDOMComponentTree');
19
var ReactUpdates = require('ReactUpdates');
20
21
var assign = require('Object.assign');
22
var getEventTarget = require('getEventTarget');
23
var getUnboundedScrollPosition = require('getUnboundedScrollPosition');
24
26
-var DOCUMENT_FRAGMENT_NODE_TYPE = 11;
27
-
25
/**
29
- * Finds the parent React component of `node`.
30
- *
31
- * @param {*} node
32
- * @return {?DOMEventTarget} Parent container, or `null` if the specified node
33
- * is not nested.
26
+ * Find the deepest React component completely containing the root of the
27
+ * passed-in instance (for use when entire React trees are nested within each
28
+ * other). If React trees are not nested, returns null.
29
*/
35
-function findParent(node) {
30
+function findParent(inst) {
31
// TODO: It may be a good idea to cache this to prevent unnecessary DOM
32
// traversal, but caching is difficult to do correctly without using a
33
// mutation observer to listen for all DOM changes.
39
- var nodeID = ReactMount.getID(node);
40
- var rootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
41
- var container = ReactMount.findReactContainerForID(rootID);
42
- var parent = ReactMount.getFirstReactDOM(container);
43
- return parent;
34
+ while (inst._nativeParent) {
35
+ inst = inst._nativeParent;
36
+ }
37
+ var rootNode = ReactDOMComponentTree.getNodeFromInstance(inst);
38
+ var container = rootNode.parentNode;
39
+ return ReactDOMComponentTree.getClosestInstanceFromNode(container);
40
}
41
42
// Used to store ancestor hierarchy in top level callback
@@ -62,91 +58,26 @@ PooledClass.addPoolingTo(
58
);
59
60
function handleTopLevelImpl(bookKeeping) {
65
- // TODO: Re-enable event.path handling
66
- //
67
- // if (bookKeeping.nativeEvent.path && bookKeeping.nativeEvent.path.length > 1) {
68
- // // New browsers have a path attribute on native events
69
- // handleTopLevelWithPath(bookKeeping);
70
- // } else {
71
- // // Legacy browsers don't have a path attribute on native events
72
- // handleTopLevelWithoutPath(bookKeeping);
73
- // }
74
-
75
- void handleTopLevelWithPath; // temporarily unused
76
- handleTopLevelWithoutPath(bookKeeping);
77
-}
78
-
79
-// Legacy browsers don't have a path attribute on native events
80
-function handleTopLevelWithoutPath(bookKeeping) {
81
- var topLevelTarget = ReactMount.getFirstReactDOM(
82
- getEventTarget(bookKeeping.nativeEvent)
83
- ) || window;
61
+ var nativeEventTarget = getEventTarget(bookKeeping.nativeEvent);
62
+ var targetInst = ReactDOMComponentTree.getClosestInstanceFromNode(
63
+ nativeEventTarget
64
+ );
65
66
// Loop through the hierarchy, in case there's any nested components.
67
// It's important that we build the array of ancestors before calling any
68
// event handlers, because event handlers can modify the DOM, leading to
69
// inconsistencies with ReactMount's node cache. See #1105.
89
- var ancestor = topLevelTarget;
90
- while (ancestor) {
70
+ var ancestor = targetInst;
71
+ do {
72
bookKeeping.ancestors.push(ancestor);
92
- ancestor = findParent(ancestor);
93
- }
73
+ ancestor = ancestor && findParent(ancestor);
74
+ } while (ancestor);
75
76
for (var i = 0; i < bookKeeping.ancestors.length; i++) {
96
- topLevelTarget = bookKeeping.ancestors[i];
97
- var topLevelTargetID = ReactMount.getID(topLevelTarget) || '';
98
- ReactEventListener._handleTopLevel(
99
- bookKeeping.topLevelType,
100
- topLevelTarget,
101
- topLevelTargetID,
102
- bookKeeping.nativeEvent,
103
- getEventTarget(bookKeeping.nativeEvent)
104
- );
105
- }
106
-}
107
-
108
-// New browsers have a path attribute on native events
109
-function handleTopLevelWithPath(bookKeeping) {
110
- var path = bookKeeping.nativeEvent.path;
111
- var currentNativeTarget = path[0];
112
- var eventsFired = 0;
113
- for (var i = 0; i < path.length; i++) {
114
- var currentPathElement = path[i];
115
- if (currentPathElement.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE) {
116
- currentNativeTarget = path[i + 1];
117
- }
118
- // TODO: slow
119
- var reactParent = ReactMount.getFirstReactDOM(currentPathElement);
120
- if (reactParent === currentPathElement) {
121
- var currentPathElementID = ReactMount.getID(currentPathElement);
122
- var newRootID = ReactInstanceHandles.getReactRootIDFromNodeID(
123
- currentPathElementID
124
- );
125
- bookKeeping.ancestors.push(currentPathElement);
126
-
127
- var topLevelTargetID = ReactMount.getID(currentPathElement) || '';
128
- eventsFired++;
129
- ReactEventListener._handleTopLevel(
130
- bookKeeping.topLevelType,
131
- currentPathElement,
132
- topLevelTargetID,
133
- bookKeeping.nativeEvent,
134
- currentNativeTarget
135
- );
136
-
137
- // Jump to the root of this React render tree
138
- while (currentPathElementID !== newRootID) {
139
- i++;
140
- currentPathElement = path[i];
141
- currentPathElementID = ReactMount.getID(currentPathElement);
142
- }
143
- }
144
- }
145
- if (eventsFired === 0) {
77
+ targetInst = bookKeeping.ancestors[i];
78
ReactEventListener._handleTopLevel(
79
bookKeeping.topLevelType,
148
- window,
149
- '',
80
+ targetInst,
81
bookKeeping.nativeEvent,
82
getEventTarget(bookKeeping.nativeEvent)
83
);
src/renderers/dom/client/__tests__/ReactBrowserEventEmitter-test.js
+22
-43
@@ -13,25 +13,17 @@
13
14
var keyOf = require('keyOf');
15
16
-var ReactMount = require('ReactMount');
17
-var idToNode = {};
18
-var getID = ReactMount.getID;
19
-var setID = function(el, id) {
20
- ReactMount.setID(el, id);
21
- idToNode[id] = el;
22
-};
23
-var oldGetNode;
24
-var oldGetFirstReactDOM;
25
-
16
+var EventListener;
17
var EventPluginHub;
18
var EventPluginRegistry;
19
+var React;
20
var ReactBrowserEventEmitter;
21
+var ReactDOMComponentTree;
22
var ReactTestUtils;
23
var TapEventPlugin;
31
-var EventListener;
24
25
var tapMoveThreshold;
34
-var idCallOrder = [];
26
+var idCallOrder;
27
var recordID = function(id) {
28
idCallOrder.push(id);
29
};
@@ -49,21 +41,9 @@ var ON_TOUCH_TAP_KEY = keyOf({onTouchTap: null});
41
var ON_CHANGE_KEY = keyOf({onChange: null});
42
var ON_MOUSE_ENTER_KEY = keyOf({onMouseEnter: null});
43
52
-
53
-/**
54
- * Since `ReactBrowserEventEmitter` is fairly well separated from the DOM, we
55
- * can test almost all of `ReactBrowserEventEmitter` without ever rendering
56
- * anything in the DOM. As long as we provide IDs that follow `React's`
57
- * conventional id namespace hierarchy. The only reason why we create these DOM
58
- * nodes is so that when we feed them into `ReactBrowserEventEmitter` (through
59
- * `ReactTestUtils`), the event handlers may receive a DOM node to inspect.
60
- */
61
-var CHILD = document.createElement('div');
62
-var PARENT = document.createElement('div');
63
-var GRANDPARENT = document.createElement('div');
64
-setID(CHILD, '.0.0.0.0');
65
-setID(PARENT, '.0.0.0');
66
-setID(GRANDPARENT, '.0.0');
44
+var GRANDPARENT;
45
+var PARENT;
46
+var CHILD;
47
48
function registerSimpleTestHandler() {
49
EventPluginHub.putListener(getID(CHILD), ON_CLICK_KEY, LISTENER);
@@ -72,27 +52,31 @@ function registerSimpleTestHandler() {
52
return EventPluginHub.getListener(getID(CHILD), ON_CLICK_KEY);
53
}
54
55
+function getID(node) {
56
+ return ReactDOMComponentTree.getInstanceFromNode(node)._rootNodeID;
57
+}
58
+
59
60
describe('ReactBrowserEventEmitter', function() {
61
beforeEach(function() {
62
jest.resetModuleRegistry();
63
LISTENER.mockClear();
64
+ EventListener = require('EventListener');
65
EventPluginHub = require('EventPluginHub');
66
EventPluginRegistry = require('EventPluginRegistry');
82
- TapEventPlugin = require('TapEventPlugin');
83
- ReactMount = require('ReactMount');
84
- EventListener = require('EventListener');
67
+ React = require('React');
68
ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
69
+ ReactDOMComponentTree = require('ReactDOMComponentTree');
70
ReactTestUtils = require('ReactTestUtils');
71
+ TapEventPlugin = require('TapEventPlugin');
72
88
- oldGetNode = ReactMount.getNode;
89
- oldGetFirstReactDOM = ReactMount.oldGetFirstReactDOM;
90
- ReactMount.getNode = function(id) {
91
- return idToNode[id];
92
- };
93
- ReactMount.getFirstReactDOM = function(node) {
94
- return node;
95
- };
73
+ ReactTestUtils.renderIntoDocument(
74
+ <div ref={(c) => GRANDPARENT = c}>
75
+ <div ref={(c) => PARENT = c}>
76
+ <div ref={(c) => CHILD = c} />
77
+ </div>
78
+ </div>
79
+ );
80
81
idCallOrder = [];
82
tapMoveThreshold = TapEventPlugin.tapMoveThreshold;
@@ -101,11 +85,6 @@ describe('ReactBrowserEventEmitter', function() {
85
});
86
});
87
104
- afterEach(function() {
105
- ReactMount.getNode = oldGetNode;
106
- ReactMount.getFirstReactDOM = oldGetFirstReactDOM;
107
- });
108
-
88
it('should store a listener correctly', function() {
89
registerSimpleTestHandler();
90
var listener = EventPluginHub.getListener(getID(CHILD), ON_CLICK_KEY);
src/renderers/dom/client/__tests__/ReactEventListener-test.js
+23
-26
@@ -16,10 +16,8 @@ var EVENT_TARGET_PARAM = 1;
16
17
describe('ReactEventListener', function() {
18
var React;
19
-
19
var ReactDOM;
21
-
22
- var ReactMount;
20
+ var ReactDOMComponentTree;
21
var ReactEventListener;
22
var ReactTestUtils;
23
var handleTopLevel;
@@ -27,10 +25,8 @@ describe('ReactEventListener', function() {
25
beforeEach(function() {
26
jest.resetModuleRegistry();
27
React = require('React');
30
-
28
ReactDOM = require('ReactDOM');
32
-
33
- ReactMount = require('ReactMount');
29
+ ReactDOMComponentTree = require('ReactDOMComponentTree');
30
ReactEventListener = require('ReactEventListener');
31
ReactTestUtils = require('ReactTestUtils');
32
@@ -40,7 +36,7 @@ describe('ReactEventListener', function() {
36
37
it('should dispatch events from outside React tree', function() {
38
var otherNode = document.createElement('h1');
43
- var component = ReactMount.render(<div />, document.createElement('div'));
39
+ var component = ReactDOM.render(<div />, document.createElement('div'));
40
expect(handleTopLevel.mock.calls.length).toBe(0);
41
ReactEventListener.dispatchEvent(
42
'topMouseOut',
@@ -64,9 +60,9 @@ describe('ReactEventListener', function() {
60
var childControl = <div>Child</div>;
61
var parentContainer = document.createElement('div');
62
var parentControl = <div>Parent</div>;
67
- childControl = ReactMount.render(childControl, childContainer);
63
+ childControl = ReactDOM.render(childControl, childContainer);
64
parentControl =
69
- ReactMount.render(parentControl, parentContainer);
65
+ ReactDOM.render(parentControl, parentContainer);
66
ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
67
68
var callback = ReactEventListener.dispatchEvent.bind(null, 'test');
@@ -77,9 +73,9 @@ describe('ReactEventListener', function() {
73
var calls = handleTopLevel.mock.calls;
74
expect(calls.length).toBe(2);
75
expect(calls[0][EVENT_TARGET_PARAM])
80
- .toBe(ReactDOM.findDOMNode(childControl));
76
+ .toBe(ReactDOMComponentTree.getInstanceFromNode(childControl));
77
expect(calls[1][EVENT_TARGET_PARAM])
82
- .toBe(ReactDOM.findDOMNode(parentControl));
78
+ .toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));
79
});
80
81
it('should propagate events two levels down', function() {
@@ -89,11 +85,11 @@ describe('ReactEventListener', function() {
85
var parentControl = <div>Parent</div>;
86
var grandParentContainer = document.createElement('div');
87
var grandParentControl = <div>Parent</div>;
92
- childControl = ReactMount.render(childControl, childContainer);
88
+ childControl = ReactDOM.render(childControl, childContainer);
89
parentControl =
94
- ReactMount.render(parentControl, parentContainer);
90
+ ReactDOM.render(parentControl, parentContainer);
91
grandParentControl =
96
- ReactMount.render(grandParentControl, grandParentContainer);
92
+ ReactDOM.render(grandParentControl, grandParentContainer);
93
ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
94
ReactDOM.findDOMNode(grandParentControl).appendChild(parentContainer);
95
@@ -105,11 +101,11 @@ describe('ReactEventListener', function() {
101
var calls = handleTopLevel.mock.calls;
102
expect(calls.length).toBe(3);
103
expect(calls[0][EVENT_TARGET_PARAM])
108
- .toBe(ReactDOM.findDOMNode(childControl));
104
+ .toBe(ReactDOMComponentTree.getInstanceFromNode(childControl));
105
expect(calls[1][EVENT_TARGET_PARAM])
110
- .toBe(ReactDOM.findDOMNode(parentControl));
106
+ .toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));
107
expect(calls[2][EVENT_TARGET_PARAM])
112
- .toBe(ReactDOM.findDOMNode(grandParentControl));
108
+ .toBe(ReactDOMComponentTree.getInstanceFromNode(grandParentControl));
109
});
110
111
it('should not get confused by disappearing elements', function() {
@@ -117,9 +113,9 @@ describe('ReactEventListener', function() {
113
var childControl = <div>Child</div>;
114
var parentContainer = document.createElement('div');
115
var parentControl = <div>Parent</div>;
120
- childControl = ReactMount.render(childControl, childContainer);
116
+ childControl = ReactDOM.render(childControl, childContainer);
117
parentControl =
122
- ReactMount.render(parentControl, parentContainer);
118
+ ReactDOM.render(parentControl, parentContainer);
119
ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
120
121
// ReactBrowserEventEmitter.handleTopLevel might remove the
@@ -130,7 +126,7 @@ describe('ReactEventListener', function() {
126
handleTopLevel.mockImplementation(
127
function(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent) {
128
if (topLevelTarget === childNode) {
133
- ReactMount.unmountComponentAtNode(childContainer);
129
+ ReactDOM.unmountComponentAtNode(childContainer);
130
}
131
}
132
);
@@ -142,19 +138,20 @@ describe('ReactEventListener', function() {
138
139
var calls = handleTopLevel.mock.calls;
140
expect(calls.length).toBe(2);
145
- expect(calls[0][EVENT_TARGET_PARAM]).toBe(childNode);
141
+ expect(calls[0][EVENT_TARGET_PARAM])
142
+ .toBe(ReactDOMComponentTree.getInstanceFromNode(childNode));
143
expect(calls[1][EVENT_TARGET_PARAM])
147
- .toBe(ReactDOM.findDOMNode(parentControl));
144
+ .toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));
145
});
146
147
it('should batch between handlers from different roots', function() {
148
var childContainer = document.createElement('div');
149
var parentContainer = document.createElement('div');
153
- var childControl = ReactMount.render(
150
+ var childControl = ReactDOM.render(
151
<div>Child</div>,
152
childContainer
153
);
157
- var parentControl = ReactMount.render(
154
+ var parentControl = ReactDOM.render(
155
<div>Parent</div>,
156
parentContainer
157
);
@@ -165,7 +162,7 @@ describe('ReactEventListener', function() {
162
var childNode = ReactDOM.findDOMNode(childControl);
163
handleTopLevel.mockImplementation(
164
function(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent) {
168
- ReactMount.render(
165
+ ReactDOM.render(
166
<div>{topLevelTarget === childNode ? '1' : '2'}</div>,
167
childContainer
168
);
@@ -210,6 +207,6 @@ describe('ReactEventListener', function() {
207
var calls = handleTopLevel.mock.calls;
208
expect(calls.length).toBe(1);
209
expect(calls[0][EVENT_TARGET_PARAM])
213
- .toBe(ReactDOM.findDOMNode(instance.getInner()));
210
+ .toBe(ReactDOMComponentTree.getInstanceFromNode(instance.getInner()));
211
});
212
});
src/renderers/dom/client/eventPlugins/BeforeInputEventPlugin.js
+9
-29
@@ -227,16 +227,11 @@ function getDataFromCustomEvent(nativeEvent) {
227
var currentComposition = null;
228
229
/**
230
- * @param {string} topLevelType Record from `EventConstants`.
231
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
232
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
233
- * @param {object} nativeEvent Native browser event.
230
* @return {?object} A SyntheticCompositionEvent.
231
*/
232
function extractCompositionEvent(
233
topLevelType,
238
- topLevelTarget,
239
- topLevelTargetID,
234
+ targetInst,
235
nativeEvent,
236
nativeEventTarget
237
) {
@@ -261,7 +256,8 @@ function extractCompositionEvent(
256
// The current composition is stored statically and must not be
257
// overwritten while composition continues.
258
if (!currentComposition && eventType === eventTypes.compositionStart) {
264
- currentComposition = FallbackCompositionState.getPooled(topLevelTarget);
259
+ currentComposition =
260
+ FallbackCompositionState.getPooled(nativeEventTarget);
261
} else if (eventType === eventTypes.compositionEnd) {
262
if (currentComposition) {
263
fallbackData = currentComposition.getData();
@@ -271,7 +267,7 @@ function extractCompositionEvent(
267
268
var event = SyntheticCompositionEvent.getPooled(
269
eventType,
274
- topLevelTargetID,
270
+ targetInst,
271
nativeEvent,
272
nativeEventTarget
273
);
@@ -403,16 +399,11 @@ function getFallbackBeforeInputChars(topLevelType, nativeEvent) {
399
* Extract a SyntheticInputEvent for `beforeInput`, based on either native
400
* `textInput` or fallback behavior.
401
*
406
- * @param {string} topLevelType Record from `EventConstants`.
407
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
408
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
409
- * @param {object} nativeEvent Native browser event.
402
* @return {?object} A SyntheticInputEvent.
403
*/
404
function extractBeforeInputEvent(
405
topLevelType,
414
- topLevelTarget,
415
- topLevelTargetID,
406
+ targetInst,
407
nativeEvent,
408
nativeEventTarget
409
) {
@@ -432,7 +423,7 @@ function extractBeforeInputEvent(
423
424
var event = SyntheticInputEvent.getPooled(
425
eventTypes.beforeInput,
435
- topLevelTargetID,
426
+ targetInst,
427
nativeEvent,
428
nativeEventTarget
429
);
@@ -464,33 +455,22 @@ var BeforeInputEventPlugin = {
455
456
eventTypes: eventTypes,
457
467
- /**
468
- * @param {string} topLevelType Record from `EventConstants`.
469
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
470
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
471
- * @param {object} nativeEvent Native browser event.
472
- * @return {*} An accumulation of synthetic events.
473
- * @see {EventPluginHub.extractEvents}
474
- */
458
extractEvents: function(
459
topLevelType,
477
- topLevelTarget,
478
- topLevelTargetID,
460
+ targetInst,
461
nativeEvent,
462
nativeEventTarget
463
) {
464
return [
465
extractCompositionEvent(
466
topLevelType,
485
- topLevelTarget,
486
- topLevelTargetID,
467
+ targetInst,
468
nativeEvent,
469
nativeEventTarget
470
),
471
extractBeforeInputEvent(
472
topLevelType,
492
- topLevelTarget,
493
- topLevelTargetID,
473
+ targetInst,
474
nativeEvent,
475
nativeEventTarget
476
),
src/renderers/dom/client/eventPlugins/ChangeEventPlugin.js
+49
-62
@@ -15,6 +15,7 @@ var EventConstants = require('EventConstants');
15
var EventPluginHub = require('EventPluginHub');
16
var EventPropagators = require('EventPropagators');
17
var ExecutionEnvironment = require('ExecutionEnvironment');
18
+var ReactDOMComponentTree = require('ReactDOMComponentTree');
19
var ReactUpdates = require('ReactUpdates');
20
var SyntheticEvent = require('SyntheticEvent');
21
@@ -48,7 +49,7 @@ var eventTypes = {
49
* For IE shims
50
*/
51
var activeElement = null;
51
-var activeElementID = null;
52
+var activeElementInst = null;
53
var activeElementValue = null;
54
var activeElementValueProp = null;
55
@@ -74,7 +75,7 @@ if (ExecutionEnvironment.canUseDOM) {
75
function manualDispatchChangeEvent(nativeEvent) {
76
var event = SyntheticEvent.getPooled(
77
eventTypes.change,
77
- activeElementID,
78
+ activeElementInst,
79
nativeEvent,
80
getEventTarget(nativeEvent)
81
);
@@ -99,9 +100,9 @@ function runEventInBatch(event) {
100
EventPluginHub.processEventQueue(false);
101
}
102
102
-function startWatchingForChangeEventIE8(target, targetID) {
103
+function startWatchingForChangeEventIE8(target, targetInst) {
104
activeElement = target;
104
- activeElementID = targetID;
105
+ activeElementInst = targetInst;
106
activeElement.attachEvent('onchange', manualDispatchChangeEvent);
107
}
108
@@ -111,28 +112,27 @@ function stopWatchingForChangeEventIE8() {
112
}
113
activeElement.detachEvent('onchange', manualDispatchChangeEvent);
114
activeElement = null;
114
- activeElementID = null;
115
+ activeElementInst = null;
116
}
117
117
-function getTargetIDForChangeEvent(
118
+function getTargetInstForChangeEvent(
119
topLevelType,
119
- topLevelTarget,
120
- topLevelTargetID
120
+ targetInst
121
) {
122
if (topLevelType === topLevelTypes.topChange) {
123
- return topLevelTargetID;
123
+ return targetInst;
124
}
125
}
126
function handleEventsForChangeEventIE8(
127
topLevelType,
128
- topLevelTarget,
129
- topLevelTargetID
128
+ target,
129
+ targetInst
130
) {
131
if (topLevelType === topLevelTypes.topFocus) {
132
// stopWatching() should be a noop here but we call it just in case we
133
// missed a blur event somehow.
134
stopWatchingForChangeEventIE8();
135
- startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID);
135
+ startWatchingForChangeEventIE8(target, targetInst);
136
} else if (topLevelType === topLevelTypes.topBlur) {
137
stopWatchingForChangeEventIE8();
138
}
@@ -173,9 +173,9 @@ var newValueProp = {
173
* and override the value property so that we can distinguish user events from
174
* value changes in JS.
175
*/
176
-function startWatchingForValueChange(target, targetID) {
176
+function startWatchingForValueChange(target, targetInst) {
177
activeElement = target;
178
- activeElementID = targetID;
178
+ activeElementInst = targetInst;
179
activeElementValue = target.value;
180
activeElementValueProp = Object.getOwnPropertyDescriptor(
181
target.constructor.prototype,
@@ -211,7 +211,7 @@ function stopWatchingForValueChange() {
211
}
212
213
activeElement = null;
214
- activeElementID = null;
214
+ activeElementInst = null;
215
activeElementValue = null;
216
activeElementValueProp = null;
217
}
@@ -236,22 +236,21 @@ function handlePropertyChange(nativeEvent) {
236
/**
237
* If a `change` event should be fired, returns the target's ID.
238
*/
239
-function getTargetIDForInputEvent(
239
+function getTargetInstForInputEvent(
240
topLevelType,
241
- topLevelTarget,
242
- topLevelTargetID
241
+ targetInst
242
) {
243
if (topLevelType === topLevelTypes.topInput) {
244
// In modern browsers (i.e., not IE8 or IE9), the input event is exactly
245
// what we want so fall through here and trigger an abstract event
247
- return topLevelTargetID;
246
+ return targetInst;
247
}
248
}
249
250
function handleEventsForInputEventIE(
251
topLevelType,
253
- topLevelTarget,
254
- topLevelTargetID
252
+ target,
253
+ targetInst
254
) {
255
if (topLevelType === topLevelTypes.topFocus) {
256
// In IE8, we can capture almost all .value changes by adding a
@@ -268,17 +267,16 @@ function handleEventsForInputEventIE(
267
// stopWatching() should be a noop here but we call it just in case we
268
// missed a blur event somehow.
269
stopWatchingForValueChange();
271
- startWatchingForValueChange(topLevelTarget, topLevelTargetID);
270
+ startWatchingForValueChange(target, targetInst);
271
} else if (topLevelType === topLevelTypes.topBlur) {
272
stopWatchingForValueChange();
273
}
274
}
275
276
// For IE8 and IE9.
278
-function getTargetIDForInputEventIE(
277
+function getTargetInstForInputEventIE(
278
topLevelType,
280
- topLevelTarget,
281
- topLevelTargetID
279
+ targetInst
280
) {
281
if (topLevelType === topLevelTypes.topSelectionChange ||
282
topLevelType === topLevelTypes.topKeyUp ||
@@ -295,7 +293,7 @@ function getTargetIDForInputEventIE(
293
// fire selectionchange normally.
294
if (activeElement && activeElement.value !== activeElementValue) {
295
activeElementValue = activeElement.value;
298
- return activeElementID;
296
+ return activeElementInst;
297
}
298
}
299
}
@@ -314,13 +312,12 @@ function shouldUseClickEvent(elem) {
312
);
313
}
314
317
-function getTargetIDForClickEvent(
315
+function getTargetInstForClickEvent(
316
topLevelType,
319
- topLevelTarget,
320
- topLevelTargetID
317
+ targetInst
318
) {
319
if (topLevelType === topLevelTypes.topClick) {
323
- return topLevelTargetID;
320
+ return targetInst;
321
}
322
}
323
@@ -338,49 +335,39 @@ var ChangeEventPlugin = {
335
336
eventTypes: eventTypes,
337
341
- /**
342
- * @param {string} topLevelType Record from `EventConstants`.
343
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
344
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
345
- * @param {object} nativeEvent Native browser event.
346
- * @return {*} An accumulation of synthetic events.
347
- * @see {EventPluginHub.extractEvents}
348
- */
338
extractEvents: function(
350
- topLevelType,
351
- topLevelTarget,
352
- topLevelTargetID,
353
- nativeEvent,
354
- nativeEventTarget) {
355
-
356
- var getTargetIDFunc, handleEventFunc;
357
- if (shouldUseChangeEvent(topLevelTarget)) {
339
+ topLevelType,
340
+ targetInst,
341
+ nativeEvent,
342
+ nativeEventTarget
343
+ ) {
344
+ var targetNode = targetInst ?
345
+ ReactDOMComponentTree.getNodeFromInstance(targetInst) : window;
346
+
347
+ var getTargetInstFunc, handleEventFunc;
348
+ if (shouldUseChangeEvent(targetNode)) {
349
if (doesChangeEventBubble) {
359
- getTargetIDFunc = getTargetIDForChangeEvent;
350
+ getTargetInstFunc = getTargetInstForChangeEvent;
351
} else {
352
handleEventFunc = handleEventsForChangeEventIE8;
353
}
363
- } else if (isTextInputElement(topLevelTarget)) {
354
+ } else if (isTextInputElement(targetNode)) {
355
if (isInputEventSupported) {
365
- getTargetIDFunc = getTargetIDForInputEvent;
356
+ getTargetInstFunc = getTargetInstForInputEvent;
357
} else {
367
- getTargetIDFunc = getTargetIDForInputEventIE;
358
+ getTargetInstFunc = getTargetInstForInputEventIE;
359
handleEventFunc = handleEventsForInputEventIE;
360
}
370
- } else if (shouldUseClickEvent(topLevelTarget)) {
371
- getTargetIDFunc = getTargetIDForClickEvent;
361
+ } else if (shouldUseClickEvent(targetNode)) {
362
+ getTargetInstFunc = getTargetInstForClickEvent;
363
}
364
374
- if (getTargetIDFunc) {
375
- var targetID = getTargetIDFunc(
376
- topLevelType,
377
- topLevelTarget,
378
- topLevelTargetID
379
- );
380
- if (targetID) {
365
+ if (getTargetInstFunc) {
366
+ var inst = getTargetInstFunc(topLevelType, targetInst);
367
+ if (inst) {
368
var event = SyntheticEvent.getPooled(
369
eventTypes.change,
383
- targetID,
370
+ inst,
371
nativeEvent,
372
nativeEventTarget
373
);
@@ -393,8 +380,8 @@ var ChangeEventPlugin = {
380
if (handleEventFunc) {
381
handleEventFunc(
382
topLevelType,
396
- topLevelTarget,
397
- topLevelTargetID
383
+ targetNode,
384
+ targetInst
385
);
386
}
387
},
src/renderers/dom/client/eventPlugins/EnterLeaveEventPlugin.js
+30
-45
@@ -14,13 +14,12 @@
14
15
var EventConstants = require('EventConstants');
16
var EventPropagators = require('EventPropagators');
17
+var ReactDOMComponentTree = require('ReactDOMComponentTree');
18
var SyntheticMouseEvent = require('SyntheticMouseEvent');
19
19
-var ReactMount = require('ReactMount');
20
var keyOf = require('keyOf');
21
22
var topLevelTypes = EventConstants.topLevelTypes;
23
-var getFirstReactDOM = ReactMount.getFirstReactDOM;
23
24
var eventTypes = {
25
mouseEnter: {
@@ -39,8 +38,6 @@ var eventTypes = {
38
},
39
};
40
42
-var extractedEvents = [null, null];
43
-
41
var EnterLeaveEventPlugin = {
42
43
eventTypes: eventTypes,
@@ -51,20 +48,13 @@ var EnterLeaveEventPlugin = {
48
* we do not extract duplicate events. However, moving the mouse into the
49
* browser from outside will not fire a `mouseout` event. In this case, we use
50
* the `mouseover` top-level event.
54
- *
55
- * @param {string} topLevelType Record from `EventConstants`.
56
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
57
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
58
- * @param {object} nativeEvent Native browser event.
59
- * @return {*} An accumulation of synthetic events.
60
- * @see {EventPluginHub.extractEvents}
51
*/
52
extractEvents: function(
63
- topLevelType,
64
- topLevelTarget,
65
- topLevelTargetID,
66
- nativeEvent,
67
- nativeEventTarget) {
53
+ topLevelType,
54
+ targetInst,
55
+ nativeEvent,
56
+ nativeEventTarget
57
+ ) {
58
if (topLevelType === topLevelTypes.topMouseOver &&
59
(nativeEvent.relatedTarget || nativeEvent.fromElement)) {
60
return null;
@@ -76,12 +66,12 @@ var EnterLeaveEventPlugin = {
66
}
67
68
var win;
79
- if (topLevelTarget.window === topLevelTarget) {
80
- // `topLevelTarget` is probably a window object.
81
- win = topLevelTarget;
69
+ if (nativeEventTarget.window === nativeEventTarget) {
70
+ // `nativeEventTarget` is probably a window object.
71
+ win = nativeEventTarget;
72
} else {
73
// TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
84
- var doc = topLevelTarget.ownerDocument;
74
+ var doc = nativeEventTarget.ownerDocument;
75
if (doc) {
76
win = doc.defaultView || doc.parentWindow;
77
} else {
@@ -91,22 +81,15 @@ var EnterLeaveEventPlugin = {
81
82
var from;
83
var to;
94
- var fromID = '';
95
- var toID = '';
84
if (topLevelType === topLevelTypes.topMouseOut) {
97
- from = topLevelTarget;
98
- fromID = topLevelTargetID;
99
- to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement);
100
- if (to) {
101
- toID = ReactMount.getID(to);
102
- } else {
103
- to = win;
104
- }
105
- to = to || win;
85
+ from = targetInst;
86
+ var related = nativeEvent.relatedTarget || nativeEvent.toElement;
87
+ to = related ?
88
+ ReactDOMComponentTree.getClosestInstanceFromNode(related) : null;
89
} else {
107
- from = win;
108
- to = topLevelTarget;
109
- toID = topLevelTargetID;
90
+ // Moving to a node from outside the window.
91
+ from = null;
92
+ to = targetInst;
93
}
94
95
if (from === to) {
@@ -114,32 +97,34 @@ var EnterLeaveEventPlugin = {
97
return null;
98
}
99
100
+ var fromNode =
101
+ from == null ? win : ReactDOMComponentTree.getNodeFromInstance(from);
102
+ var toNode =
103
+ to == null ? win : ReactDOMComponentTree.getNodeFromInstance(to);
104
+
105
var leave = SyntheticMouseEvent.getPooled(
106
eventTypes.mouseLeave,
119
- fromID,
107
+ from,
108
nativeEvent,
109
nativeEventTarget
110
);
111
leave.type = 'mouseleave';
124
- leave.target = from;
125
- leave.relatedTarget = to;
112
+ leave.target = fromNode;
113
+ leave.relatedTarget = toNode;
114
115
var enter = SyntheticMouseEvent.getPooled(
116
eventTypes.mouseEnter,
129
- toID,
117
+ to,
118
nativeEvent,
119
nativeEventTarget
120
);
121
enter.type = 'mouseenter';
134
- enter.target = to;
135
- enter.relatedTarget = from;
136
-
137
- EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
122
+ enter.target = toNode;
123
+ enter.relatedTarget = fromNode;
124
139
- extractedEvents[0] = leave;
140
- extractedEvents[1] = enter;
125
+ EventPropagators.accumulateEnterLeaveDispatches(leave, enter, from, to);
126
142
- return extractedEvents;
127
+ return [leave, enter];
128
},
129
130
};
src/renderers/dom/client/eventPlugins/SelectEventPlugin.js
+17
-21
@@ -14,6 +14,7 @@
14
var EventConstants = require('EventConstants');
15
var EventPropagators = require('EventPropagators');
16
var ExecutionEnvironment = require('ExecutionEnvironment');
17
+var ReactDOMComponentTree = require('ReactDOMComponentTree');
18
var ReactInputSelection = require('ReactInputSelection');
19
var SyntheticEvent = require('SyntheticEvent');
20
@@ -49,12 +50,12 @@ var eventTypes = {
50
};
51
52
var activeElement = null;
52
-var activeElementID = null;
53
+var activeElementInst = null;
54
var lastSelection = null;
55
var mouseDown = false;
56
57
// Track whether a listener exists for this plugin. If none exist, we do
57
-// not extract events.
58
+// not extract events. See #3639.
59
var hasListener = false;
60
var ON_SELECT_KEY = keyOf({onSelect: null});
61
@@ -117,7 +118,7 @@ function constructSelectEvent(nativeEvent, nativeEventTarget) {
118
119
var syntheticEvent = SyntheticEvent.getPooled(
120
eventTypes.select,
120
- activeElementID,
121
+ activeElementInst,
122
nativeEvent,
123
nativeEventTarget
124
);
@@ -151,37 +152,32 @@ var SelectEventPlugin = {
152
153
eventTypes: eventTypes,
154
154
- /**
155
- * @param {string} topLevelType Record from `EventConstants`.
156
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
157
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
158
- * @param {object} nativeEvent Native browser event.
159
- * @return {*} An accumulation of synthetic events.
160
- * @see {EventPluginHub.extractEvents}
161
- */
155
extractEvents: function(
163
- topLevelType,
164
- topLevelTarget,
165
- topLevelTargetID,
166
- nativeEvent,
167
- nativeEventTarget) {
156
+ topLevelType,
157
+ targetInst,
158
+ nativeEvent,
159
+ nativeEventTarget
160
+ ) {
161
if (!hasListener) {
162
return null;
163
}
164
165
+ var targetNode = targetInst ?
166
+ ReactDOMComponentTree.getNodeFromInstance(targetInst) : window;
167
+
168
switch (topLevelType) {
169
// Track the input node that has focus.
170
case topLevelTypes.topFocus:
175
- if (isTextInputElement(topLevelTarget) ||
176
- topLevelTarget.contentEditable === 'true') {
177
- activeElement = topLevelTarget;
178
- activeElementID = topLevelTargetID;
171
+ if (isTextInputElement(targetNode) ||
172
+ targetNode.contentEditable === 'true') {
173
+ activeElement = targetNode;
174
+ activeElementInst = targetInst;
175
lastSelection = null;
176
}
177
break;
178
case topLevelTypes.topBlur:
179
activeElement = null;
184
- activeElementID = null;
180
+ activeElementInst = null;
181
lastSelection = null;
182
break;
183
src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js
+6
-15
@@ -457,20 +457,11 @@ var SimpleEventPlugin = {
457
458
eventTypes: eventTypes,
459
460
- /**
461
- * @param {string} topLevelType Record from `EventConstants`.
462
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
463
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
464
- * @param {object} nativeEvent Native browser event.
465
- * @return {*} An accumulation of synthetic events.
466
- * @see {EventPluginHub.extractEvents}
467
- */
460
extractEvents: function(
469
- topLevelType,
470
- topLevelTarget,
471
- topLevelTargetID,
472
- nativeEvent,
473
- nativeEventTarget
461
+ topLevelType,
462
+ targetInst,
463
+ nativeEvent,
464
+ nativeEventTarget
465
) {
466
var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
467
if (!dispatchConfig) {
@@ -511,7 +502,7 @@ var SimpleEventPlugin = {
502
EventConstructor = SyntheticEvent;
503
break;
504
case topLevelTypes.topKeyPress:
514
- // FireFox creates a keypress event for function keys too. This removes
505
+ // Firefox creates a keypress event for function keys too. This removes
506
// the unwanted keypress events. Enter is however both printable and
507
// non-printable. One would expect Tab to be as well (but it isn't).
508
if (getEventCharCode(nativeEvent) === 0) {
@@ -577,7 +568,7 @@ var SimpleEventPlugin = {
568
);
569
var event = EventConstructor.getPooled(
570
dispatchConfig,
580
- topLevelTargetID,
571
+ targetInst,
572
nativeEvent,
573
nativeEventTarget
574
);
src/renderers/dom/client/eventPlugins/TapEventPlugin.js
+6
-14
@@ -89,20 +89,12 @@ var TapEventPlugin = {
89
90
eventTypes: eventTypes,
91
92
- /**
93
- * @param {string} topLevelType Record from `EventConstants`.
94
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
95
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
96
- * @param {object} nativeEvent Native browser event.
97
- * @return {*} An accumulation of synthetic events.
98
- * @see {EventPluginHub.extractEvents}
99
- */
92
extractEvents: function(
101
- topLevelType,
102
- topLevelTarget,
103
- topLevelTargetID,
104
- nativeEvent,
105
- nativeEventTarget) {
93
+ topLevelType,
94
+ targetInst,
95
+ nativeEvent,
96
+ nativeEventTarget
97
+ ) {
98
if (!isStartish(topLevelType) && !isEndish(topLevelType)) {
99
return null;
100
}
@@ -122,7 +114,7 @@ var TapEventPlugin = {
114
if (isEndish(topLevelType) && distance < tapMoveThreshold) {
115
event = SyntheticUIEvent.getPooled(
116
eventTypes.touchTap,
125
- topLevelTargetID,
117
+ targetInst,
118
nativeEvent,
119
nativeEventTarget
120
);
src/renderers/dom/client/eventPlugins/__tests__/EnterLeaveEventPlugin-test.js
+3
-4
@@ -15,7 +15,7 @@ var EnterLeaveEventPlugin;
15
var EventConstants;
16
var React;
17
var ReactDOM;
18
-var ReactMount;
18
+var ReactDOMComponentTree;
19
20
var topLevelTypes;
21
@@ -27,7 +27,7 @@ describe('EnterLeaveEventPlugin', function() {
27
EventConstants = require('EventConstants');
28
React = require('React');
29
ReactDOM = require('ReactDOM');
30
- ReactMount = require('ReactMount');
30
+ ReactDOMComponentTree = require('ReactDOMComponentTree');
31
32
topLevelTypes = EventConstants.topLevelTypes;
33
});
@@ -48,8 +48,7 @@ describe('EnterLeaveEventPlugin', function() {
48
49
var extracted = EnterLeaveEventPlugin.extractEvents(
50
topLevelTypes.topMouseOver,
51
- div,
52
- ReactMount.getID(div),
51
+ ReactDOMComponentTree.getInstanceFromNode(div),
52
{target: div},
53
div
54
);
src/renderers/dom/client/eventPlugins/__tests__/SelectEventPlugin-test.js
+3
-4
@@ -14,7 +14,7 @@
14
var EventConstants;
15
var React;
16
var ReactDOM;
17
-var ReactMount;
17
+var ReactDOMComponentTree;
18
var ReactTestUtils;
19
var SelectEventPlugin;
20
@@ -24,8 +24,7 @@ describe('SelectEventPlugin', function() {
24
function extract(node, topLevelEvent) {
25
return SelectEventPlugin.extractEvents(
26
topLevelEvent,
27
- node,
28
- ReactMount.getID(node),
27
+ ReactDOMComponentTree.getInstanceFromNode(node),
28
{target: node},
29
node
30
);
@@ -35,7 +34,7 @@ describe('SelectEventPlugin', function() {
34
EventConstants = require('EventConstants');
35
React = require('React');
36
ReactDOM = require('ReactDOM');
38
- ReactMount = require('ReactMount');
37
+ ReactDOMComponentTree = require('ReactDOMComponentTree');
38
ReactTestUtils = require('ReactTestUtils');
39
SelectEventPlugin = require('SelectEventPlugin');
40
src/renderers/dom/client/syntheticEvents/SyntheticEvent.js
+5
-4
@@ -50,12 +50,13 @@ var EventInterface = {
50
* DOM interface; custom application-specific events can also subclass this.
51
*
52
* @param {object} dispatchConfig Configuration used to dispatch this event.
53
- * @param {string} dispatchMarker Marker identifying the event target.
53
+ * @param {*} targetInst Marker identifying the event target.
54
* @param {object} nativeEvent Native browser event.
55
*/
56
-function SyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
56
+function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) {
57
this.dispatchConfig = dispatchConfig;
58
- this.dispatchMarker = dispatchMarker;
58
+ this._targetInst = targetInst;
59
+
60
this.nativeEvent = nativeEvent;
61
this.target = nativeEventTarget;
62
this.currentTarget = nativeEventTarget;
@@ -158,7 +159,7 @@ assign(SyntheticEvent.prototype, {
159
this[propName] = null;
160
}
161
this.dispatchConfig = null;
161
- this.dispatchMarker = null;
162
+ this._targetInst = null;
163
this.nativeEvent = null;
164
},
165
src/renderers/dom/shared/ReactDefaultInjection.js
+7
-3
@@ -20,17 +20,19 @@ var HTMLDOMPropertyConfig = require('HTMLDOMPropertyConfig');
20
var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
21
var ReactComponentBrowserEnvironment =
22
require('ReactComponentBrowserEnvironment');
23
-var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
23
var ReactDOMComponent = require('ReactDOMComponent');
24
+var ReactDOMComponentTree = require('ReactDOMComponentTree');
25
+var ReactDOMTreeTraversal = require('ReactDOMTreeTraversal');
26
var ReactDOMTextComponent = require('ReactDOMTextComponent');
27
+var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
28
var ReactEventListener = require('ReactEventListener');
29
var ReactInjection = require('ReactInjection');
30
var ReactInstanceHandles = require('ReactInstanceHandles');
31
var ReactMount = require('ReactMount');
32
var ReactReconcileTransaction = require('ReactReconcileTransaction');
33
+var SVGDOMPropertyConfig = require('SVGDOMPropertyConfig');
34
var SelectEventPlugin = require('SelectEventPlugin');
35
var SimpleEventPlugin = require('SimpleEventPlugin');
33
-var SVGDOMPropertyConfig = require('SVGDOMPropertyConfig');
36
37
var alreadyInjected = false;
38
@@ -52,7 +54,9 @@ function inject() {
54
*/
55
ReactInjection.EventPluginHub.injectEventPluginOrder(DefaultEventPluginOrder);
56
ReactInjection.EventPluginHub.injectInstanceHandle(ReactInstanceHandles);
55
- ReactInjection.EventPluginHub.injectMount(ReactMount);
57
+ ReactInjection.EventPluginUtils.injectComponentTree(ReactDOMComponentTree);
58
+ ReactInjection.EventPluginUtils.injectTreeTraversal(ReactDOMTreeTraversal);
59
+ ReactInjection.EventPluginUtils.injectMount(ReactMount);
60
61
/**
62
* Some important event plugins included by default (without having to require
src/renderers/dom/shared/ReactInjection.js
+2
@@ -13,6 +13,7 @@
13
14
var DOMProperty = require('DOMProperty');
15
var EventPluginHub = require('EventPluginHub');
16
+var EventPluginUtils = require('EventPluginUtils');
17
var ReactComponentEnvironment = require('ReactComponentEnvironment');
18
var ReactClass = require('ReactClass');
19
var ReactEmptyComponent = require('ReactEmptyComponent');
@@ -27,6 +28,7 @@ var ReactInjection = {
28
DOMProperty: DOMProperty.injection,
29
EmptyComponent: ReactEmptyComponent.injection,
30
EventPluginHub: EventPluginHub.injection,
31
+ EventPluginUtils: EventPluginUtils.injection,
32
EventEmitter: ReactBrowserEventEmitter.injection,
33
NativeComponent: ReactNativeComponent.injection,
34
Perf: ReactPerf.injection,
src/renderers/shared/event/EventPluginHub.js
+2
-14
@@ -100,12 +100,6 @@ var EventPluginHub = {
100
*/
101
injection: {
102
103
- /**
104
- * @param {object} InjectedMount
105
- * @public
106
- */
107
- injectMount: EventPluginUtils.injection.injectMount,
108
-
103
/**
104
* @param {object} InjectedInstanceHandle
105
* @public
@@ -217,17 +211,12 @@ var EventPluginHub = {
211
* Allows registered plugins an opportunity to extract events from top-level
212
* native browser events.
213
*
220
- * @param {string} topLevelType Record from `EventConstants`.
221
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
222
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
223
- * @param {object} nativeEvent Native browser event.
214
* @return {*} An accumulation of synthetic events.
215
* @internal
216
*/
217
extractEvents: function(
218
topLevelType,
229
- topLevelTarget,
230
- topLevelTargetID,
219
+ targetInst,
220
nativeEvent,
221
nativeEventTarget) {
222
var events;
@@ -238,8 +227,7 @@ var EventPluginHub = {
227
if (possiblePlugin) {
228
var extractedEvents = possiblePlugin.extractEvents(
229
topLevelType,
241
- topLevelTarget,
242
- topLevelTargetID,
230
+ targetInst,
231
nativeEvent,
232
nativeEventTarget
233
);
src/renderers/shared/event/EventPluginUtils.js
+43
-8
@@ -22,21 +22,47 @@ var warning = require('warning');
22
*/
23
24
/**
25
+ * - `ComponentTree`: [required] Module that can convert between React instances
26
+ * and actual node references.
27
* - `Mount`: [required] Module that can convert between React dom IDs and
28
* actual node references.
29
*/
30
+var ComponentTree;
31
+var Mount;
32
+var TreeTraversal;
33
var injection = {
29
- Mount: null,
30
- injectMount: function(InjectedMount) {
31
- injection.Mount = InjectedMount;
34
+ injectComponentTree: function(Injected) {
35
+ ComponentTree = Injected;
36
if (__DEV__) {
37
warning(
34
- InjectedMount && InjectedMount.getNode && InjectedMount.getID,
38
+ Injected &&
39
+ Injected.getNodeFromInstance &&
40
+ Injected.getInstanceFromNode,
41
+ 'EventPluginUtils.injection.injectComponentTree(...): Injected ' +
42
+ 'module is missing getNodeFromInstance or getInstanceFromNode.'
43
+ );
44
+ }
45
+ },
46
+ injectMount: function(Injected) {
47
+ Mount = Injected;
48
+ if (__DEV__) {
49
+ warning(
50
+ Injected && Injected.getNode && Injected.getID,
51
'EventPluginUtils.injection.injectMount(...): Injected Mount ' +
52
'module is missing getNode or getID.'
53
);
54
}
55
},
56
+ injectTreeTraversal: function(Injected) {
57
+ TreeTraversal = Injected;
58
+ if (__DEV__) {
59
+ warning(
60
+ Injected && Injected.isAncestor && Injected.getLowestCommonAncestor,
61
+ 'EventPluginUtils.injection.injectTreeTraversal(...): Injected ' +
62
+ 'module is missing isAncestor or getLowestCommonAncestor.'
63
+ );
64
+ }
65
+ },
66
};
67
68
var topLevelTypes = EventConstants.topLevelTypes;
@@ -86,7 +112,7 @@ if (__DEV__) {
112
*/
113
function executeDispatch(event, simulated, listener, domID) {
114
var type = event.type || 'unknown-event';
89
- event.currentTarget = injection.Mount.getNode(domID);
115
+ event.currentTarget = EventPluginUtils.getNode(domID);
116
if (simulated) {
117
ReactErrorUtils.invokeGuardedCallbackWithCatch(
118
type,
@@ -214,10 +240,19 @@ var EventPluginUtils = {
240
hasDispatches: hasDispatches,
241
242
getNode: function(id) {
217
- return injection.Mount.getNode(id);
243
+ return Mount.getNode(id);
244
+ },
245
+ getInstanceFromNode: function(node) {
246
+ return ComponentTree.getInstanceFromNode(node);
247
+ },
248
+ isAncestor: function(a, b) {
249
+ return TreeTraversal.isAncestor(a, b);
250
+ },
251
+ getLowestCommonAncestor: function(a, b) {
252
+ return TreeTraversal.getLowestCommonAncestor(a, b);
253
},
219
- getID: function(node) {
220
- return injection.Mount.getID(node);
254
+ getParentInstance: function(inst) {
255
+ return TreeTraversal.getParentInstance(inst);
256
},
257
258
injection: injection,
src/renderers/shared/event/EventPropagators.js
+10
-6
@@ -22,6 +22,10 @@ var forEachAccumulated = require('forEachAccumulated');
22
var PropagationPhases = EventConstants.PropagationPhases;
23
var getListener = EventPluginHub.getListener;
24
25
+function getID(inst) {
26
+ return inst ? inst._rootNodeID : '';
27
+}
28
+
29
/**
30
* Some event types have a notion of different registration names for different
31
* "phases" of propagation. This finds listeners by a given phase.
@@ -64,7 +68,7 @@ function accumulateDirectionalDispatches(domID, upwards, event) {
68
function accumulateTwoPhaseDispatchesSingle(event) {
69
if (event && event.dispatchConfig.phasedRegistrationNames) {
70
EventPluginHub.injection.getInstanceHandle().traverseTwoPhase(
67
- event.dispatchMarker,
71
+ getID(event._targetInst),
72
accumulateDirectionalDispatches,
73
event
74
);
@@ -77,7 +81,7 @@ function accumulateTwoPhaseDispatchesSingle(event) {
81
function accumulateTwoPhaseDispatchesSingleSkipTarget(event) {
82
if (event && event.dispatchConfig.phasedRegistrationNames) {
83
EventPluginHub.injection.getInstanceHandle().traverseTwoPhaseSkipTarget(
80
- event.dispatchMarker,
84
+ getID(event._targetInst),
85
accumulateDirectionalDispatches,
86
event
87
);
@@ -109,7 +113,7 @@ function accumulateDispatches(id, ignoredDirection, event) {
113
*/
114
function accumulateDirectDispatchesSingle(event) {
115
if (event && event.dispatchConfig.registrationName) {
112
- accumulateDispatches(event.dispatchMarker, null, event);
116
+ accumulateDispatches(getID(event._targetInst), null, event);
117
}
118
}
119
@@ -121,10 +125,10 @@ function accumulateTwoPhaseDispatchesSkipTarget(events) {
125
forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget);
126
}
127
124
-function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
128
+function accumulateEnterLeaveDispatches(leave, enter, from, to) {
129
EventPluginHub.injection.getInstanceHandle().traverseEnterLeave(
126
- fromID,
127
- toID,
130
+ getID(from),
131
+ getID(to),
132
accumulateDispatches,
133
leave,
134
enter
src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js
+71
-67
@@ -14,7 +14,6 @@
14
var EventConstants = require('EventConstants');
15
var EventPluginUtils = require('EventPluginUtils');
16
var EventPropagators = require('EventPropagators');
17
-var ReactInstanceHandles = require('ReactInstanceHandles');
17
var ResponderSyntheticEvent = require('ResponderSyntheticEvent');
18
var ResponderTouchHistoryStore = require('ResponderTouchHistoryStore');
19
@@ -31,10 +30,10 @@ var executeDispatchesInOrderStopAtTrue =
30
EventPluginUtils.executeDispatchesInOrderStopAtTrue;
31
32
/**
34
- * ID of element that should respond to touch/move types of interactions, as
33
+ * Instance of element that should respond to touch/move types of interactions, as
34
* indicated explicitly by relevant callbacks.
35
*/
37
-var responderID = null;
36
+var responderInst = null;
37
38
/**
39
* Count of current touches. A textInput should become responder iff the
@@ -47,13 +46,13 @@ var trackedTouchCount = 0;
46
*/
47
var previousActiveTouches = 0;
48
50
-var changeResponder = function(nextResponderID) {
51
- var oldResponderID = responderID;
52
- responderID = nextResponderID;
49
+var changeResponder = function(nextResponderInst) {
50
+ var oldResponderInst = responderInst;
51
+ responderInst = nextResponderInst;
52
if (ResponderEventPlugin.GlobalResponderHandler !== null) {
53
ResponderEventPlugin.GlobalResponderHandler.onChange(
55
- oldResponderID,
56
- nextResponderID
54
+ oldResponderInst,
55
+ nextResponderInst
56
);
57
}
58
};
@@ -149,7 +148,7 @@ var eventTypes = {
148
* - If nothing is currently the responder, the "appropriate place" is the
149
* initiating event's `targetID`.
150
* - If something *is* already the responder, the "appropriate place" is the
152
- * first common ancestor of the event target and the current `responderID`.
151
+ * first common ancestor of the event target and the current `responderInst`.
152
* - Some negotiation happens: See the timing diagram below.
153
* - Scrolled views automatically become responder. The reasoning is that a
154
* platform scroll view that isn't built on top of the responder system has
@@ -158,7 +157,7 @@ var eventTypes = {
157
*
158
* - Responder being released:
159
* As soon as no more touches that *started* inside of descendents of the
161
- * *current* responderID, an `onResponderRelease` event is dispatched to the
160
+ * *current* responderInst, an `onResponderRelease` event is dispatched to the
161
* current responder, and the responder lock is released.
162
*
163
* TODO:
@@ -316,15 +315,11 @@ to return true:wantsResponderID| |
315
* - `touchStartCapture` (`EventPluginHub` dispatches as usual)
316
* - `touchStart` (`EventPluginHub` dispatches as usual)
317
* - `responderGrant/Reject` (`EventPluginHub` dispatches as usual)
319
- *
320
- * @param {string} topLevelType Record from `EventConstants`.
321
- * @param {string} topLevelTargetID ID of deepest React rendered element.
322
- * @param {object} nativeEvent Native browser event.
323
- * @return {*} An accumulation of synthetic events.
318
*/
319
+
320
function setResponderAndExtractTransfer(
321
topLevelType,
327
- topLevelTargetID,
322
+ targetInst,
323
nativeEvent,
324
nativeEventTarget
325
) {
@@ -336,15 +331,15 @@ function setResponderAndExtractTransfer(
331
eventTypes.scrollShouldSetResponder;
332
333
// TODO: stop one short of the the current responder.
339
- var bubbleShouldSetFrom = !responderID ?
340
- topLevelTargetID :
341
- ReactInstanceHandles.getFirstCommonAncestorID(responderID, topLevelTargetID);
334
+ var bubbleShouldSetFrom = !responderInst ?
335
+ targetInst :
336
+ EventPluginUtils.getLowestCommonAncestor(responderInst, targetInst);
337
338
// When capturing/bubbling the "shouldSet" event, we want to skip the target
339
// (deepest ID) if it happens to be the current responder. The reasoning:
340
// It's strange to get an `onMoveShouldSetResponder` when you're *already*
341
// the responder.
347
- var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderID;
342
+ var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst;
343
var shouldSetEvent = ResponderSyntheticEvent.getPooled(
344
shouldSetEventType,
345
bubbleShouldSetFrom,
@@ -362,24 +357,43 @@ function setResponderAndExtractTransfer(
357
shouldSetEvent.constructor.release(shouldSetEvent);
358
}
359
365
- if (!wantsResponderID || wantsResponderID === responderID) {
360
+ if (!wantsResponderID) {
361
+ return null;
362
+ }
363
+
364
+ // HACK: Temporary tree-crawling until executeDispatchesInOrderStopAtTrue
365
+ // returns the instance instead of the ID.
366
+ var wantsResponderInst;
367
+ for (
368
+ var inst = bubbleShouldSetFrom;
369
+ inst;
370
+ inst = EventPluginUtils.getParentInstance(inst)
371
+ ) {
372
+ if (wantsResponderID === inst._rootNodeID) {
373
+ wantsResponderInst = inst;
374
+ break;
375
+ }
376
+ }
377
+ invariant(wantsResponderInst, 'Requested responder instance not found.');
378
+
379
+ if (wantsResponderInst === responderInst) {
380
return null;
381
}
382
var extracted;
383
var grantEvent = ResponderSyntheticEvent.getPooled(
384
eventTypes.responderGrant,
371
- wantsResponderID,
385
+ wantsResponderInst,
386
nativeEvent,
387
nativeEventTarget
388
);
389
grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
390
391
EventPropagators.accumulateDirectDispatches(grantEvent);
378
- if (responderID) {
392
+ if (responderInst) {
393
394
var terminationRequestEvent = ResponderSyntheticEvent.getPooled(
395
eventTypes.responderTerminationRequest,
382
- responderID,
396
+ responderInst,
397
nativeEvent,
398
nativeEventTarget
399
);
@@ -392,21 +406,20 @@ function setResponderAndExtractTransfer(
406
}
407
408
if (shouldSwitch) {
395
- var terminateType = eventTypes.responderTerminate;
409
var terminateEvent = ResponderSyntheticEvent.getPooled(
397
- terminateType,
398
- responderID,
410
+ eventTypes.responderTerminate,
411
+ responderInst,
412
nativeEvent,
413
nativeEventTarget
414
);
415
terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
416
EventPropagators.accumulateDirectDispatches(terminateEvent);
417
extracted = accumulate(extracted, [grantEvent, terminateEvent]);
405
- changeResponder(wantsResponderID);
418
+ changeResponder(wantsResponderInst);
419
} else {
420
var rejectEvent = ResponderSyntheticEvent.getPooled(
421
eventTypes.responderReject,
409
- wantsResponderID,
422
+ wantsResponderInst,
423
nativeEvent,
424
nativeEventTarget
425
);
@@ -416,7 +429,7 @@ function setResponderAndExtractTransfer(
429
}
430
} else {
431
extracted = accumulate(extracted, grantEvent);
419
- changeResponder(wantsResponderID);
432
+ changeResponder(wantsResponderInst);
433
}
434
return extracted;
435
}
@@ -424,13 +437,13 @@ function setResponderAndExtractTransfer(
437
/**
438
* A transfer is a negotiation between a currently set responder and the next
439
* element to claim responder status. Any start event could trigger a transfer
427
- * of responderID. Any move event could trigger a transfer.
440
+ * of responderInst. Any move event could trigger a transfer.
441
*
442
* @param {string} topLevelType Record from `EventConstants`.
443
* @return {boolean} True if a transfer of responder could possibly occur.
444
*/
432
-function canTriggerTransfer(topLevelType, topLevelTargetID) {
433
- return topLevelTargetID && (
445
+function canTriggerTransfer(topLevelType, targetInst) {
446
+ return !!targetInst && (
447
topLevelType === EventConstants.topLevelTypes.topScroll ||
448
(trackedTouchCount > 0 &&
449
topLevelType === EventConstants.topLevelTypes.topSelectionChange) ||
@@ -441,7 +454,7 @@ function canTriggerTransfer(topLevelType, topLevelTargetID) {
454
455
/**
456
* Returns whether or not this touch end event makes it such that there are no
444
- * longer any touches that started inside of the current `responderID`.
457
+ * longer any touches that started inside of the current `responderInst`.
458
*
459
* @param {NativeEvent} nativeEvent Native touch end event.
460
* @return {boolean} Whether or not this touch end event ends the responder.
@@ -456,12 +469,8 @@ function noResponderTouches(nativeEvent) {
469
var target = activeTouch.target;
470
if (target !== null && target !== undefined && target !== 0) {
471
// Is the original touch location inside of the current responder?
459
- var isAncestor =
460
- ReactInstanceHandles.isAncestorIDOf(
461
- responderID,
462
- EventPluginUtils.getID(target)
463
- );
464
- if (isAncestor) {
472
+ var targetInst = EventPluginUtils.getInstanceFromNode(target);
473
+ if (EventPluginUtils.isAncestor(responderInst, targetInst)) {
474
return false;
475
}
476
}
@@ -472,30 +481,24 @@ function noResponderTouches(nativeEvent) {
481
482
var ResponderEventPlugin = {
483
475
- getResponderID: function() {
476
- return responderID;
484
+ /* For unit testing only */
485
+ _getResponderID: function() {
486
+ return responderInst ? responderInst._rootNodeID : null;
487
},
488
489
eventTypes: eventTypes,
490
491
/**
482
- * We must be resilient to `topLevelTargetID` being `undefined` on
483
- * `touchMove`, or `touchEnd`. On certain platforms, this means that a native
484
- * scroll has assumed control and the original touch targets are destroyed.
485
- *
486
- * @param {string} topLevelType Record from `EventConstants`.
487
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
488
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
489
- * @param {object} nativeEvent Native browser event.
490
- * @return {*} An accumulation of synthetic events.
491
- * @see {EventPluginHub.extractEvents}
492
+ * We must be resilient to `targetInst` being `null` on `touchMove` or
493
+ * `touchEnd`. On certain platforms, this means that a native scroll has
494
+ * assumed control and the original touch targets are destroyed.
495
*/
496
extractEvents: function(
494
- topLevelType,
495
- topLevelTarget,
496
- topLevelTargetID,
497
- nativeEvent,
498
- nativeEventTarget) {
497
+ topLevelType,
498
+ targetInst,
499
+ nativeEvent,
500
+ nativeEventTarget
501
+ ) {
502
if (isStartish(topLevelType)) {
503
trackedTouchCount += 1;
504
} else if (isEndish(topLevelType)) {
@@ -508,10 +511,10 @@ var ResponderEventPlugin = {
511
512
ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent, nativeEventTarget);
513
511
- var extracted = canTriggerTransfer(topLevelType, topLevelTargetID) ?
514
+ var extracted = canTriggerTransfer(topLevelType, targetInst) ?
515
setResponderAndExtractTransfer(
516
topLevelType,
514
- topLevelTargetID,
517
+ targetInst,
518
nativeEvent,
519
nativeEventTarget) :
520
null;
@@ -525,9 +528,9 @@ var ResponderEventPlugin = {
528
// These multiple individual change touch events are are always bookended
529
// by `onResponderGrant`, and one of
530
// (`onResponderRelease/onResponderTerminate`).
528
- var isResponderTouchStart = responderID && isStartish(topLevelType);
529
- var isResponderTouchMove = responderID && isMoveish(topLevelType);
530
- var isResponderTouchEnd = responderID && isEndish(topLevelType);
531
+ var isResponderTouchStart = responderInst && isStartish(topLevelType);
532
+ var isResponderTouchMove = responderInst && isMoveish(topLevelType);
533
+ var isResponderTouchEnd = responderInst && isEndish(topLevelType);
534
var incrementalTouch =
535
isResponderTouchStart ? eventTypes.responderStart :
536
isResponderTouchMove ? eventTypes.responderMove :
@@ -538,7 +541,7 @@ var ResponderEventPlugin = {
541
var gesture =
542
ResponderSyntheticEvent.getPooled(
543
incrementalTouch,
541
- responderID,
544
+ responderInst,
545
nativeEvent,
546
nativeEventTarget
547
);
@@ -548,10 +551,10 @@ var ResponderEventPlugin = {
551
}
552
553
var isResponderTerminate =
551
- responderID &&
554
+ responderInst &&
555
topLevelType === EventConstants.topLevelTypes.topTouchCancel;
556
var isResponderRelease =
554
- responderID &&
557
+ responderInst &&
558
!isResponderTerminate &&
559
isEndish(topLevelType) &&
560
noResponderTouches(nativeEvent);
@@ -560,8 +563,9 @@ var ResponderEventPlugin = {
563
isResponderRelease ? eventTypes.responderRelease :
564
null;
565
if (finalTouch) {
563
- var finalEvent =
564
- ResponderSyntheticEvent.getPooled(finalTouch, responderID, nativeEvent, nativeEventTarget);
566
+ var finalEvent = ResponderSyntheticEvent.getPooled(
567
+ finalTouch, responderInst, nativeEvent, nativeEventTarget
568
+ );
569
finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
570
EventPropagators.accumulateDirectDispatches(finalEvent);
571
extracted = accumulate(extracted, finalEvent);
src/renderers/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js
+99
-65
@@ -17,11 +17,6 @@ var ReactInstanceHandles;
17
var ResponderEventPlugin;
18
var EventPluginUtils;
19
20
-var GRANDPARENT_ID = '.0';
21
-var PARENT_ID = '.0.0';
22
-var CHILD_ID = '.0.0.0';
23
-var CHILD_ID2 = '.0.0.1';
24
-
20
var topLevelTypes;
21
22
var touch = function(nodeHandle, i) {
@@ -89,8 +84,7 @@ var _touchConfig = function(
84
changedTouchObjects
85
),
86
topLevelType: topType,
92
- target: targetNodeHandle,
93
- targetID: targetNodeHandle,
87
+ targetInst: idToInstance[targetNodeHandle],
88
};
89
};
90
@@ -296,8 +290,7 @@ var run = function(config, hierarchyConfig, nativeEventConfig) {
290
// Trigger the event
291
var extractedEvents = ResponderEventPlugin.extractEvents(
292
nativeEventConfig.topLevelType,
299
- nativeEventConfig.target,
300
- nativeEventConfig.targetID,
293
+ nativeEventConfig.targetInst,
294
nativeEventConfig.nativeEvent,
295
nativeEventConfig.target
296
);
@@ -316,6 +309,16 @@ var run = function(config, hierarchyConfig, nativeEventConfig) {
309
); // +1 for extra ++
310
};
311
312
+var GRANDPARENT_ID = '.0';
313
+var PARENT_ID = '.0.0';
314
+var CHILD_ID = '.0.0.0';
315
+var CHILD_ID2 = '.0.0.1';
316
+
317
+var idToInstance = {};
318
+[GRANDPARENT_ID, PARENT_ID, CHILD_ID, CHILD_ID2].forEach(function(id) {
319
+ idToInstance[id] = {_rootNodeID: id};
320
+});
321
+
322
var three = {
323
grandParent: GRANDPARENT_ID,
324
parent: PARENT_ID,
@@ -351,6 +354,39 @@ describe('ResponderEventPlugin', function() {
354
},
355
});
356
357
+ EventPluginUtils.injection.injectComponentTree({
358
+ getInstanceFromNode: function(id) {
359
+ return idToInstance[id];
360
+ },
361
+ getNodeFromInstance: function(inst) {
362
+ return inst._rootNodeID;
363
+ },
364
+ });
365
+
366
+ EventPluginUtils.injection.injectTreeTraversal({
367
+ isAncestor: function(a, b) {
368
+ return ReactInstanceHandles.isAncestorIDOf(
369
+ a._rootNodeID,
370
+ b._rootNodeID
371
+ );
372
+ },
373
+ getLowestCommonAncestor: function(a, b) {
374
+ if (!a || !b) {
375
+ return null;
376
+ }
377
+ var commonID = ReactInstanceHandles.getFirstCommonAncestorID(
378
+ a._rootNodeID,
379
+ b._rootNodeID
380
+ );
381
+ return idToInstance[commonID] || null;
382
+ },
383
+ getParentInstance: function(inst) {
384
+ var id = inst._rootNodeID;
385
+ var parentID = id.substr(0, id.lastIndexOf('.'));
386
+ return idToInstance[parentID] || null;
387
+ },
388
+ });
389
+
390
topLevelTypes = EventConstants.topLevelTypes;
391
});
392
@@ -363,12 +399,12 @@ describe('ResponderEventPlugin', function() {
399
config.startShouldSetResponder.bubbled.parent = {order: 4, returnVal: false};
400
config.startShouldSetResponder.bubbled.grandParent = {order: 5, returnVal: false};
401
run(config, three, startConfig(three.child, [three.child], [0]));
366
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
402
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
403
404
// Now no handlers should be called on `touchEnd`.
405
config = oneEventLoopTestConfig(three);
406
run(config, three, endConfig(three.child, [three.child], [0]));
371
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
407
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
408
});
409
410
@@ -384,13 +420,13 @@ describe('ResponderEventPlugin', function() {
420
config.responderGrant.grandParent = {order: 1};
421
config.responderStart.grandParent = {order: 2};
422
run(config, three, startConfig(three.child, [three.child], [0]));
387
- expect(ResponderEventPlugin.getResponderID()).toBe(GRANDPARENT_ID);
423
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
424
425
config = oneEventLoopTestConfig(three);
426
config.responderEnd.grandParent = {order: 0};
427
config.responderRelease.grandParent = {order: 1};
428
run(config, three, endConfig(three.child, [three.child], [0]));
393
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
429
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
430
});
431
432
it('should grant responder parent while capturing', () => {
@@ -400,13 +436,13 @@ describe('ResponderEventPlugin', function() {
436
config.responderGrant.parent = {order: 2};
437
config.responderStart.parent = {order: 3};
438
run(config, three, startConfig(three.child, [three.child], [0]));
403
- expect(ResponderEventPlugin.getResponderID()).toBe(PARENT_ID);
439
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
440
441
config = oneEventLoopTestConfig(three);
442
config.responderEnd.parent = {order: 0};
443
config.responderRelease.parent = {order: 1};
444
run(config, three, endConfig(three.child, [three.child], [0]));
409
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
445
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
446
});
447
448
it('should grant responder child while capturing', () => {
@@ -417,13 +453,13 @@ describe('ResponderEventPlugin', function() {
453
config.responderGrant.child = {order: 3};
454
config.responderStart.child = {order: 4};
455
run(config, three, startConfig(three.child, [three.child], [0]));
420
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
456
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
457
458
config = oneEventLoopTestConfig(three);
459
config.responderEnd.child = {order: 0};
460
config.responderRelease.child = {order: 1};
461
run(config, three, endConfig(three.child, [three.child], [0]));
426
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
462
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
463
});
464
465
it('should grant responder child while bubbling', () => {
@@ -435,13 +471,13 @@ describe('ResponderEventPlugin', function() {
471
config.responderGrant.child = {order: 4};
472
config.responderStart.child = {order: 5};
473
run(config, three, startConfig(three.child, [three.child], [0]));
438
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
474
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
475
476
config = oneEventLoopTestConfig(three);
477
config.responderEnd.child = {order: 0};
478
config.responderRelease.child = {order: 1};
479
run(config, three, endConfig(three.child, [three.child], [0]));
444
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
480
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
481
});
482
483
it('should grant responder parent while bubbling', () => {
@@ -454,13 +490,13 @@ describe('ResponderEventPlugin', function() {
490
config.responderGrant.parent = {order: 5};
491
config.responderStart.parent = {order: 6};
492
run(config, three, startConfig(three.child, [three.child], [0]));
457
- expect(ResponderEventPlugin.getResponderID()).toBe(PARENT_ID);
493
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
494
495
config = oneEventLoopTestConfig(three);
496
config.responderEnd.parent = {order: 0};
497
config.responderRelease.parent = {order: 1};
498
run(config, three, endConfig(three.child, [three.child], [0]));
463
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
499
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
500
});
501
502
it('should grant responder grandParent while bubbling', () => {
@@ -474,13 +510,13 @@ describe('ResponderEventPlugin', function() {
510
config.responderGrant.grandParent = {order: 6};
511
config.responderStart.grandParent = {order: 7};
512
run(config, three, startConfig(three.child, [three.child], [0]));
477
- expect(ResponderEventPlugin.getResponderID()).toBe(GRANDPARENT_ID);
513
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
514
515
config = oneEventLoopTestConfig(three);
516
config.responderEnd.grandParent = {order: 0};
517
config.responderRelease.grandParent = {order: 1};
518
run(config, three, endConfig(three.child, [three.child], [0]));
483
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
519
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
520
});
521
522
@@ -506,13 +542,13 @@ describe('ResponderEventPlugin', function() {
542
config.responderGrant.grandParent = {order: 1};
543
config.responderMove.grandParent = {order: 2};
544
run(config, three, moveConfig(three.child, [three.child], [0]));
509
- expect(ResponderEventPlugin.getResponderID()).toBe(GRANDPARENT_ID);
545
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
546
547
config = oneEventLoopTestConfig(three);
548
config.responderEnd.grandParent = {order: 0};
549
config.responderRelease.grandParent = {order: 1};
550
run(config, three, endConfig(three.child, [three.child], [0]));
515
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
551
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
552
});
553
554
it('should grant responder parent while capturing move', () => {
@@ -532,13 +568,13 @@ describe('ResponderEventPlugin', function() {
568
config.responderGrant.parent = {order: 2};
569
config.responderMove.parent = {order: 3};
570
run(config, three, moveConfig(three.child, [three.child], [0]));
535
- expect(ResponderEventPlugin.getResponderID()).toBe(PARENT_ID);
571
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
572
573
config = oneEventLoopTestConfig(three);
574
config.responderEnd.parent = {order: 0};
575
config.responderRelease.parent = {order: 1};
576
run(config, three, endConfig(three.child, [three.child], [0]));
541
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
577
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
578
});
579
580
it('should grant responder child while capturing move', () => {
@@ -559,13 +595,13 @@ describe('ResponderEventPlugin', function() {
595
config.responderGrant.child = {order: 3};
596
config.responderMove.child = {order: 4};
597
run(config, three, moveConfig(three.child, [three.child], [0]));
562
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
598
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
599
600
config = oneEventLoopTestConfig(three);
601
config.responderEnd.child = {order: 0};
602
config.responderRelease.child = {order: 1};
603
run(config, three, endConfig(three.child, [three.child], [0]));
568
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
604
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
605
});
606
607
it('should grant responder child while bubbling move', () => {
@@ -587,13 +623,13 @@ describe('ResponderEventPlugin', function() {
623
config.responderGrant.child = {order: 4};
624
config.responderMove.child = {order: 5};
625
run(config, three, moveConfig(three.child, [three.child], [0]));
590
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
626
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
627
628
config = oneEventLoopTestConfig(three);
629
config.responderEnd.child = {order: 0};
630
config.responderRelease.child = {order: 1};
631
run(config, three, endConfig(three.child, [three.child], [0]));
596
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
632
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
633
});
634
635
it('should grant responder parent while bubbling move', () => {
@@ -616,13 +652,13 @@ describe('ResponderEventPlugin', function() {
652
config.responderGrant.parent = {order: 5};
653
config.responderMove.parent = {order: 6};
654
run(config, three, moveConfig(three.child, [three.child], [0]));
619
- expect(ResponderEventPlugin.getResponderID()).toBe(PARENT_ID);
655
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
656
657
config = oneEventLoopTestConfig(three);
658
config.responderEnd.parent = {order: 0};
659
config.responderRelease.parent = {order: 1};
660
run(config, three, endConfig(three.child, [three.child], [0]));
625
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
661
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
662
});
663
664
it('should grant responder grandParent while bubbling move', () => {
@@ -646,13 +682,13 @@ describe('ResponderEventPlugin', function() {
682
config.responderGrant.grandParent = {order: 6};
683
config.responderMove.grandParent = {order: 7};
684
run(config, three, moveConfig(three.child, [three.child], [0]));
649
- expect(ResponderEventPlugin.getResponderID()).toBe(GRANDPARENT_ID);
685
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
686
687
config = oneEventLoopTestConfig(three);
688
config.responderEnd.grandParent = {order: 0};
689
config.responderRelease.grandParent = {order: 1};
690
run(config, three, endConfig(three.child, [three.child], [0]));
655
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
691
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
692
});
693
694
@@ -668,9 +704,9 @@ describe('ResponderEventPlugin', function() {
704
config.responderGrant.parent = {order: 2};
705
config.responderStart.parent = {order: 3};
706
run(config, three, startConfig(three.child, [three.child], [0]));
671
- expect(ResponderEventPlugin.getResponderID()).toBe(PARENT_ID);
707
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
708
673
- // While `PARENT_ID` is still responder, we create new handlers that verify
709
+ // While `parent` is still responder, we create new handlers that verify
710
// the ordering of propagation, restarting the count at `0`.
711
config = oneEventLoopTestConfig(three);
712
config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
@@ -678,13 +714,13 @@ describe('ResponderEventPlugin', function() {
714
config.startShouldSetResponder.bubbled.grandParent = {order: 1, returnVal: false};
715
config.responderStart.parent = {order: 2};
716
run(config, three, startConfig(three.child, [three.child], [0]));
681
- expect(ResponderEventPlugin.getResponderID()).toBe(PARENT_ID);
717
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
718
719
config = oneEventLoopTestConfig(three);
720
config.responderEnd.parent = {order: 0};
721
config.responderRelease.parent = {order: 1};
722
run(config, three, endConfig(three.child, [three.child], [0]));
687
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
723
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
724
});
725
726
it('should bubble negotiation to first common ancestor of responder then transfer', () => {
@@ -694,7 +730,7 @@ describe('ResponderEventPlugin', function() {
730
config.responderGrant.parent = {order: 2};
731
config.responderStart.parent = {order: 3};
732
run(config, three, startConfig(three.child, [three.child], [0]));
697
- expect(ResponderEventPlugin.getResponderID()).toBe(PARENT_ID);
733
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
734
735
config = oneEventLoopTestConfig(three);
736
@@ -705,19 +741,19 @@ describe('ResponderEventPlugin', function() {
741
config.responderTerminate.parent = {order: 3};
742
config.responderStart.grandParent = {order: 4};
743
run(config, three, startConfig(three.child, [three.child, three.child], [1]));
708
- expect(ResponderEventPlugin.getResponderID()).toBe(GRANDPARENT_ID);
744
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
745
746
config = oneEventLoopTestConfig(three);
747
config.responderEnd.grandParent = {order: 0};
748
// one remains\ /one ended \
749
run(config, three, endConfig(three.child, [three.child, three.child], [1]));
714
- expect(ResponderEventPlugin.getResponderID()).toBe(GRANDPARENT_ID);
750
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
751
752
config = oneEventLoopTestConfig(three);
753
config.responderEnd.grandParent = {order: 0};
754
config.responderRelease.grandParent = {order: 1};
755
run(config, three, endConfig(three.child, [three.child], [0]));
720
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
756
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
757
});
758
759
/**
@@ -733,7 +769,7 @@ describe('ResponderEventPlugin', function() {
769
config.startShouldSetResponder.bubbled.grandParent = {order: 3, returnVal: false};
770
771
run(config, three, startConfig(three.parent, [three.parent], [0]));
736
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
772
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
773
774
config = oneEventLoopTestConfig(three);
775
@@ -749,7 +785,7 @@ describe('ResponderEventPlugin', function() {
785
config.responderStart.child = {order: 5};
786
// / Two active touches \ /one of them new\
787
run(config, three, startConfig(three.child, [three.parent, three.child], [1]));
752
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
788
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
789
790
791
// Now we remove the original first touch, keeping the second touch that
@@ -759,7 +795,7 @@ describe('ResponderEventPlugin', function() {
795
config.responderEnd.child = {order: 0};
796
// / one ended\ /one remains \
797
run(config, three, endConfig(three.child, [three.parent, three.child], [0]));
762
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
798
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
799
800
// Okay, now let's add back that first touch (nothing should change) and
801
// then we'll try peeling back the touches in the opposite order to make
@@ -775,7 +811,7 @@ describe('ResponderEventPlugin', function() {
811
config.responderStart.child = {order: 4};
812
// / Two active touches \ /one of them new\
813
run(config, three, startConfig(three.parent, [three.child, three.parent], [1]));
778
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
814
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
815
816
817
// Now, move that new touch that had no effect, and did not start within
@@ -790,7 +826,7 @@ describe('ResponderEventPlugin', function() {
826
config.responderMove.child = {order: 4};
827
// / Two active touches \ /one of them moved\
828
run(config, three, moveConfig(three.parent, [three.child, three.parent], [1]));
793
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
829
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
830
831
832
config = oneEventLoopTestConfig(three);
@@ -798,7 +834,7 @@ describe('ResponderEventPlugin', function() {
834
config.responderRelease.child = {order: 1};
835
// /child end \ /parent remain\
836
run(config, three, endConfig(three.child, [three.child, three.parent], [0]));
801
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
837
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
838
});
839
840
@@ -816,7 +852,7 @@ describe('ResponderEventPlugin', function() {
852
config.responderStart.childOne = {order: 4};
853
854
run(config, siblings, startConfig(siblings.childOne, [siblings.childOne], [0]));
819
- expect(ResponderEventPlugin.getResponderID()).toBe(siblings.childOne);
855
+ expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
856
857
// If the touch target is the sibling item, the negotiation should only
858
// propagate to first common ancestor of current responder and sibling (so
@@ -829,7 +865,7 @@ describe('ResponderEventPlugin', function() {
865
var touchConfig =
866
startConfig(siblings.childTwo, [siblings.childOne, siblings.childTwo], [1]);
867
run(config, siblings, touchConfig);
832
- expect(ResponderEventPlugin.getResponderID()).toBe(siblings.childOne);
868
+ expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
869
870
871
// move childOne
@@ -838,7 +874,7 @@ describe('ResponderEventPlugin', function() {
874
config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};
875
config.responderMove.childOne = {order: 2};
876
run(config, siblings, moveConfig(siblings.childOne, [siblings.childOne, siblings.childTwo], [0]));
841
- expect(ResponderEventPlugin.getResponderID()).toBe(siblings.childOne);
877
+ expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
878
879
// move childTwo: Only negotiates to `parent`.
880
config = oneEventLoopTestConfig(siblings);
@@ -846,7 +882,7 @@ describe('ResponderEventPlugin', function() {
882
config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};
883
config.responderMove.childOne = {order: 2};
884
run(config, siblings, moveConfig(siblings.childTwo, [siblings.childOne, siblings.childTwo], [1]));
849
- expect(ResponderEventPlugin.getResponderID()).toBe(siblings.childOne);
885
+ expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
886
887
});
888
@@ -862,7 +898,7 @@ describe('ResponderEventPlugin', function() {
898
config.responderStart.child = {order: 5};
899
900
run(config, three, startConfig(three.child, [three.child], [0]));
865
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
901
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
902
903
// Suppose parent wants to become responder on move, and is rejected
904
config = oneEventLoopTestConfig(three);
@@ -877,7 +913,7 @@ describe('ResponderEventPlugin', function() {
913
var touchConfig =
914
moveConfig(three.child, [three.child], [0]);
915
run(config, three, touchConfig);
880
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
916
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
917
918
config = oneEventLoopTestConfig(three);
919
config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
@@ -891,7 +927,7 @@ describe('ResponderEventPlugin', function() {
927
touchConfig =
928
startConfig(three.child, [three.child, three.child], [1]);
929
run(config, three, touchConfig);
894
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
930
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
931
932
});
933
@@ -907,7 +943,7 @@ describe('ResponderEventPlugin', function() {
943
config.responderStart.child = {order: 5};
944
945
run(config, three, startConfig(three.child, [three.child], [0]));
910
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
946
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
947
948
// If the touch target is the sibling item, the negotiation should only
949
// propagate to first common ancestor of current responder and sibling (so
@@ -921,11 +957,10 @@ describe('ResponderEventPlugin', function() {
957
958
run(config, three, {
959
topLevelType: topLevelTypes.topScroll,
924
- target: three.parent,
925
- targetID: three.parent,
960
+ targetInst: idToInstance[three.parent],
961
nativeEvent: {},
962
});
928
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
963
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
964
965
966
// Now lets let the scroll take control this time.
@@ -939,11 +974,10 @@ describe('ResponderEventPlugin', function() {
974
975
run(config, three, {
976
topLevelType: topLevelTypes.topScroll,
942
- target: three.parent,
943
- targetID: three.parent,
977
+ targetInst: idToInstance[three.parent],
978
nativeEvent: {},
979
});
946
- expect(ResponderEventPlugin.getResponderID()).toBe(three.parent);
980
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
981
982
983
});
@@ -959,7 +993,7 @@ describe('ResponderEventPlugin', function() {
993
config.responderStart.child = {order: 5};
994
995
run(config, three, startConfig(three.child, [three.child], [0]));
962
- expect(ResponderEventPlugin.getResponderID()).toBe(three.child);
996
+ expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
997
998
config = oneEventLoopTestConfig(three);
999
config.responderEnd.child = {order: 0};
@@ -972,6 +1006,6 @@ describe('ResponderEventPlugin', function() {
1006
[0]
1007
);
1008
run(config, three, nativeEvent);
975
- expect(ResponderEventPlugin.getResponderID()).toBe(null);
1009
+ expect(ResponderEventPlugin._getResponderID()).toBe(null);
1010
});
1011
});
src/renderers/shared/reconciler/ReactEventEmitterMixin.js
+2
-9
@@ -23,22 +23,15 @@ var ReactEventEmitterMixin = {
23
/**
24
* Streams a fired top-level event to `EventPluginHub` where plugins have the
25
* opportunity to create `ReactEvent`s to be dispatched.
26
- *
27
- * @param {string} topLevelType Record from `EventConstants`.
28
- * @param {object} topLevelTarget The listening component root node.
29
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
30
- * @param {object} nativeEvent Native environment event.
26
*/
27
handleTopLevel: function(
28
topLevelType,
34
- topLevelTarget,
35
- topLevelTargetID,
29
+ targetInst,
30
nativeEvent,
31
nativeEventTarget) {
32
var events = EventPluginHub.extractEvents(
33
topLevelType,
40
- topLevelTarget,
41
- topLevelTargetID,
34
+ targetInst,
35
nativeEvent,
36
nativeEventTarget
37
);
src/test/ReactTestUtils.js
+2
-2
@@ -18,12 +18,12 @@ var EventPluginRegistry = require('EventPluginRegistry');
18
var EventPropagators = require('EventPropagators');
19
var React = require('React');
20
var ReactDOM = require('ReactDOM');
21
+var ReactDOMComponentTree = require('ReactDOMComponentTree');
22
var ReactElement = require('ReactElement');
23
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
24
var ReactCompositeComponent = require('ReactCompositeComponent');
25
var ReactInstanceHandles = require('ReactInstanceHandles');
26
var ReactInstanceMap = require('ReactInstanceMap');
26
-var ReactMount = require('ReactMount');
27
var ReactUpdates = require('ReactUpdates');
28
var SyntheticEvent = require('SyntheticEvent');
29
@@ -490,7 +490,7 @@ function makeSimulator(eventType) {
490
// properly destroying any properties assigned from `eventData` upon release
491
var event = new SyntheticEvent(
492
dispatchConfig,
493
- ReactMount.getID(node),
493
+ ReactDOMComponentTree.getInstanceFromNode(node),
494
fakeNativeEvent,
495
node
496
);