Merge pull request #8096 from sebmarkbage/fiberdom

Merge React[DOM/Native]TreeTraversal
This commit is contained in:
Sebastian Markbåge
2016-10-25 17:52:16 -04:00
committed by GitHub
7 changed files with 38 additions and 186 deletions
@@ -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
@@ -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.
@@ -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,
@@ -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', () => {