mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge pull request #8096 from sebmarkbage/fiberdom
Merge React[DOM/Native]TreeTraversal
This commit is contained in:
@@ -22,7 +22,6 @@ var EventPluginUtils = require('EventPluginUtils');
|
||||
var HTMLDOMPropertyConfig = require('HTMLDOMPropertyConfig');
|
||||
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var ReactDOMTreeTraversal = require('ReactDOMTreeTraversal');
|
||||
var ReactEventListener = require('ReactEventListener');
|
||||
var SVGDOMPropertyConfig = require('SVGDOMPropertyConfig');
|
||||
var SelectEventPlugin = require('SelectEventPlugin');
|
||||
@@ -48,7 +47,6 @@ function inject() {
|
||||
*/
|
||||
EventPluginHub.injection.injectEventPluginOrder(DOMEventPluginOrder);
|
||||
EventPluginUtils.injection.injectComponentTree(ReactDOMComponentTree);
|
||||
EventPluginUtils.injection.injectTreeTraversal(ReactDOMTreeTraversal);
|
||||
|
||||
/**
|
||||
* Some important event plugins included by default (without having to require
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
/**
|
||||
* Copyright 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactDOMTreeTraversal
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var invariant = require('invariant');
|
||||
|
||||
/**
|
||||
* Return the lowest common ancestor of A and B, or null if they are in
|
||||
* different trees.
|
||||
*/
|
||||
function getLowestCommonAncestor(instA, instB) {
|
||||
invariant('_hostNode' in instA, 'getNodeFromInstance: Invalid argument.');
|
||||
invariant('_hostNode' in instB, 'getNodeFromInstance: Invalid argument.');
|
||||
|
||||
var depthA = 0;
|
||||
for (var tempA = instA; tempA; tempA = tempA._hostParent) {
|
||||
depthA++;
|
||||
}
|
||||
var depthB = 0;
|
||||
for (var tempB = instB; tempB; tempB = tempB._hostParent) {
|
||||
depthB++;
|
||||
}
|
||||
|
||||
// If A is deeper, crawl up.
|
||||
while (depthA - depthB > 0) {
|
||||
instA = instA._hostParent;
|
||||
depthA--;
|
||||
}
|
||||
|
||||
// If B is deeper, crawl up.
|
||||
while (depthB - depthA > 0) {
|
||||
instB = instB._hostParent;
|
||||
depthB--;
|
||||
}
|
||||
|
||||
// Walk in lockstep until we find a match.
|
||||
var depth = depthA;
|
||||
while (depth--) {
|
||||
if (instA === instB) {
|
||||
return instA;
|
||||
}
|
||||
instA = instA._hostParent;
|
||||
instB = instB._hostParent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if A is an ancestor of B.
|
||||
*/
|
||||
function isAncestor(instA, instB) {
|
||||
invariant('_hostNode' in instA, 'isAncestor: Invalid argument.');
|
||||
invariant('_hostNode' in instB, 'isAncestor: Invalid argument.');
|
||||
|
||||
while (instB) {
|
||||
if (instB === instA) {
|
||||
return true;
|
||||
}
|
||||
instB = instB._hostParent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent instance of the passed-in instance.
|
||||
*/
|
||||
function getParentInstance(inst) {
|
||||
invariant('_hostNode' in inst, 'getParentInstance: Invalid argument.');
|
||||
|
||||
return inst._hostParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates the traversal of a two-phase, capture/bubble event dispatch.
|
||||
*/
|
||||
function traverseTwoPhase(inst, fn, arg) {
|
||||
var path = [];
|
||||
while (inst) {
|
||||
path.push(inst);
|
||||
inst = inst._hostParent;
|
||||
}
|
||||
var i;
|
||||
for (i = path.length; i-- > 0;) {
|
||||
fn(path[i], 'captured', arg);
|
||||
}
|
||||
for (i = 0; i < path.length; i++) {
|
||||
fn(path[i], 'bubbled', arg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
|
||||
* should would receive a `mouseEnter` or `mouseLeave` event.
|
||||
*
|
||||
* Does not invoke the callback on the nearest common ancestor because nothing
|
||||
* "entered" or "left" that element.
|
||||
*/
|
||||
function traverseEnterLeave(from, to, fn, argFrom, argTo) {
|
||||
var common = from && to ? getLowestCommonAncestor(from, to) : null;
|
||||
var pathFrom = [];
|
||||
while (from && from !== common) {
|
||||
pathFrom.push(from);
|
||||
from = from._hostParent;
|
||||
}
|
||||
var pathTo = [];
|
||||
while (to && to !== common) {
|
||||
pathTo.push(to);
|
||||
to = to._hostParent;
|
||||
}
|
||||
var i;
|
||||
for (i = 0; i < pathFrom.length; i++) {
|
||||
fn(pathFrom[i], 'bubbled', argFrom);
|
||||
}
|
||||
for (i = pathTo.length; i-- > 0;) {
|
||||
fn(pathTo[i], 'captured', argTo);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isAncestor: isAncestor,
|
||||
getLowestCommonAncestor: getLowestCommonAncestor,
|
||||
getParentInstance: getParentInstance,
|
||||
traverseTwoPhase: traverseTwoPhase,
|
||||
traverseEnterLeave: traverseEnterLeave,
|
||||
};
|
||||
@@ -27,7 +27,6 @@ var ReactNativeComponentTree = require('ReactNativeComponentTree');
|
||||
var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
|
||||
var ReactNativeEventPluginOrder = require('ReactNativeEventPluginOrder');
|
||||
var ReactNativeGlobalResponderHandler = require('ReactNativeGlobalResponderHandler');
|
||||
var ReactNativeTreeTraversal = require('ReactNativeTreeTraversal');
|
||||
var ResponderEventPlugin = require('ResponderEventPlugin');
|
||||
|
||||
function inject() {
|
||||
@@ -41,7 +40,6 @@ function inject() {
|
||||
*/
|
||||
EventPluginHub.injection.injectEventPluginOrder(ReactNativeEventPluginOrder);
|
||||
EventPluginUtils.injection.injectComponentTree(ReactNativeComponentTree);
|
||||
EventPluginUtils.injection.injectTreeTraversal(ReactNativeTreeTraversal);
|
||||
|
||||
ResponderEventPlugin.injection.injectGlobalResponderHandler(
|
||||
ReactNativeGlobalResponderHandler
|
||||
|
||||
+1
-3
@@ -6,13 +6,11 @@
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeTreeTraversal
|
||||
* @providesModule ReactTreeTraversal
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Same as ReactDOMTreeTraversal without the invariants.
|
||||
|
||||
/**
|
||||
* Return the lowest common ancestor of A and B, or null if they are in
|
||||
* different trees.
|
||||
+15
-15
@@ -50,8 +50,8 @@ function renderParentIntoDocument() {
|
||||
return ReactTestUtils.renderIntoDocument(<ParentComponent />);
|
||||
}
|
||||
|
||||
describe('ReactDOMTreeTraversal', () => {
|
||||
var ReactDOMTreeTraversal;
|
||||
describe('ReactTreeTraversal', () => {
|
||||
var ReactTreeTraversal;
|
||||
|
||||
var aggregatedArgs;
|
||||
function argAggregator(inst, phase, arg) {
|
||||
@@ -67,14 +67,14 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
ReactDOMTreeTraversal = require('ReactDOMTreeTraversal');
|
||||
ReactTreeTraversal = require('ReactTreeTraversal');
|
||||
aggregatedArgs = [];
|
||||
});
|
||||
|
||||
describe('traverseTwoPhase', () => {
|
||||
it('should not traverse when traversing outside DOM', () => {
|
||||
var expectedAggregation = [];
|
||||
ReactDOMTreeTraversal.traverseTwoPhase(null, argAggregator, ARG);
|
||||
ReactTreeTraversal.traverseTwoPhase(null, argAggregator, ARG);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
});
|
||||
|
||||
@@ -92,7 +92,7 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
{node: parent.refs.P_P1, phase: 'bubbled', arg: ARG},
|
||||
{node: parent.refs.P, phase: 'bubbled', arg: ARG},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseTwoPhase(target, argAggregator, ARG);
|
||||
ReactTreeTraversal.traverseTwoPhase(target, argAggregator, ARG);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
});
|
||||
|
||||
@@ -103,7 +103,7 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
{node: parent.refs.P, phase: 'captured', arg: ARG},
|
||||
{node: parent.refs.P, phase: 'bubbled', arg: ARG},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseTwoPhase(target, argAggregator, ARG);
|
||||
ReactTreeTraversal.traverseTwoPhase(target, argAggregator, ARG);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
});
|
||||
});
|
||||
@@ -112,7 +112,7 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
it('should not traverse when enter/leaving outside DOM', () => {
|
||||
var target = null;
|
||||
var expectedAggregation = [];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
target, target, argAggregator, ARG, ARG2
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
@@ -123,7 +123,7 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
var leave = getInst(parent.refs.P_P1_C1.refs.DIV_1);
|
||||
var enter = getInst(parent.refs.P_P1_C1.refs.DIV_1);
|
||||
var expectedAggregation = [];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
@@ -138,7 +138,7 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
// enter/leave shouldn't fire anything on the parent
|
||||
{node: parent.refs.P_P1_C1.refs.DIV_2, phase: 'captured', arg: ARG2},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
@@ -151,7 +151,7 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
var expectedAggregation = [
|
||||
{node: parent.refs.P_P1_C1.refs.DIV_1, phase: 'bubbled', arg: ARG},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
@@ -166,7 +166,7 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
{node: parent.refs.P_P1, phase: 'captured', arg: ARG2},
|
||||
{node: parent.refs.P_P1_C1.refs.DIV, phase: 'captured', arg: ARG2},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
@@ -179,7 +179,7 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
var expectedAggregation = [
|
||||
{node: parent.refs.P, phase: 'captured', arg: ARG2},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
@@ -194,7 +194,7 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
{node: parent.refs.P_P1, phase: 'bubbled', arg: ARG},
|
||||
{node: parent.refs.P, phase: 'bubbled', arg: ARG},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
@@ -209,7 +209,7 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
{node: parent.refs.P_P1, phase: 'bubbled', arg: ARG},
|
||||
{node: parent.refs.P, phase: 'bubbled', arg: ARG},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
@@ -261,7 +261,7 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
var i;
|
||||
for (i = 0; i < ancestors.length; i++) {
|
||||
var plan = ancestors[i];
|
||||
var firstCommon = ReactDOMTreeTraversal.getLowestCommonAncestor(
|
||||
var firstCommon = ReactTreeTraversal.getLowestCommonAncestor(
|
||||
getInst(plan.one),
|
||||
getInst(plan.two)
|
||||
);
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var ReactTreeTraversal = require('ReactTreeTraversal');
|
||||
var ReactErrorUtils = require('ReactErrorUtils');
|
||||
|
||||
var invariant = require('invariant');
|
||||
@@ -25,7 +26,6 @@ var warning = require('warning');
|
||||
* and actual node references.
|
||||
*/
|
||||
var ComponentTree;
|
||||
var TreeTraversal;
|
||||
var injection = {
|
||||
injectComponentTree: function(Injected) {
|
||||
ComponentTree = Injected;
|
||||
@@ -39,16 +39,6 @@ var injection = {
|
||||
);
|
||||
}
|
||||
},
|
||||
injectTreeTraversal: function(Injected) {
|
||||
TreeTraversal = Injected;
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
Injected && Injected.isAncestor && Injected.getLowestCommonAncestor,
|
||||
'EventPluginUtils.injection.injectTreeTraversal(...): Injected ' +
|
||||
'module is missing isAncestor or getLowestCommonAncestor.'
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function isEndish(topLevelType) {
|
||||
@@ -237,19 +227,19 @@ var EventPluginUtils = {
|
||||
return ComponentTree.getNodeFromInstance(node);
|
||||
},
|
||||
isAncestor: function(a, b) {
|
||||
return TreeTraversal.isAncestor(a, b);
|
||||
return ReactTreeTraversal.isAncestor(a, b);
|
||||
},
|
||||
getLowestCommonAncestor: function(a, b) {
|
||||
return TreeTraversal.getLowestCommonAncestor(a, b);
|
||||
return ReactTreeTraversal.getLowestCommonAncestor(a, b);
|
||||
},
|
||||
getParentInstance: function(inst) {
|
||||
return TreeTraversal.getParentInstance(inst);
|
||||
return ReactTreeTraversal.getParentInstance(inst);
|
||||
},
|
||||
traverseTwoPhase: function(target, fn, arg) {
|
||||
return TreeTraversal.traverseTwoPhase(target, fn, arg);
|
||||
return ReactTreeTraversal.traverseTwoPhase(target, fn, arg);
|
||||
},
|
||||
traverseEnterLeave: function(from, to, fn, argFrom, argTo) {
|
||||
return TreeTraversal.traverseEnterLeave(from, to, fn, argFrom, argTo);
|
||||
return ReactTreeTraversal.traverseEnterLeave(from, to, fn, argFrom, argTo);
|
||||
},
|
||||
|
||||
injection: injection,
|
||||
|
||||
+16
-14
@@ -408,20 +408,9 @@ describe('ResponderEventPlugin', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModuleRegistry();
|
||||
|
||||
EventPluginHub = require('EventPluginHub');
|
||||
EventPluginUtils = require('EventPluginUtils');
|
||||
ResponderEventPlugin = require('ResponderEventPlugin');
|
||||
|
||||
EventPluginUtils.injection.injectComponentTree({
|
||||
getInstanceFromNode: function(id) {
|
||||
return idToInstance[id];
|
||||
},
|
||||
getNodeFromInstance: function(inst) {
|
||||
return inst._rootNodeID;
|
||||
},
|
||||
});
|
||||
|
||||
EventPluginUtils.injection.injectTreeTraversal({
|
||||
// Inline mock
|
||||
const ReactTreeTraversal = require('ReactTreeTraversal');
|
||||
Object.assign(ReactTreeTraversal, {
|
||||
isAncestor: function(a, b) {
|
||||
return isAncestorIDOf(a._rootNodeID, b._rootNodeID);
|
||||
},
|
||||
@@ -443,6 +432,19 @@ describe('ResponderEventPlugin', () => {
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
EventPluginHub = require('EventPluginHub');
|
||||
EventPluginUtils = require('EventPluginUtils');
|
||||
ResponderEventPlugin = require('ResponderEventPlugin');
|
||||
|
||||
EventPluginUtils.injection.injectComponentTree({
|
||||
getInstanceFromNode: function(id) {
|
||||
return idToInstance[id];
|
||||
},
|
||||
getNodeFromInstance: function(inst) {
|
||||
return inst._rootNodeID;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should do nothing when no one wants to respond', () => {
|
||||
|
||||
Reference in New Issue
Block a user