@samitouri / QOS-React-2 / commits / f470cb88f8

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 );