Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/renderers/dom/client/ReactBrowserEventEmitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ var topEventMapping = {
topLoadedMetadata: 'loadedmetadata',
topLoadStart: 'loadstart',
topMouseDown: 'mousedown',
topMouseEnter: 'mousenter',
topMouseLeave: 'mouseleave',
topMouseMove: 'mousemove',
topMouseOut: 'mouseout',
topMouseOver: 'mouseover',
Expand Down Expand Up @@ -280,6 +282,24 @@ var ReactBrowserEventEmitter = assign({}, ReactEventEmitterMixin, {
ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE
);
}
} else if (dependency === topLevelTypes.topMouseEnter ||
dependency === topLevelTypes.topMouseLeave) {

if (isEventSupported('mouseenter', true)) {
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
topLevelTypes.topMouseEnter,
'mouseenter',
mountAt
);
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
topLevelTypes.topMouseLeave,
'mouseleave',
mountAt
);
}

isListening[topLevelTypes.topMouseEnter] = true;
isListening[topLevelTypes.topMouseLeave] = true;
} else if (dependency === topLevelTypes.topFocus ||
dependency === topLevelTypes.topBlur) {

Expand Down
40 changes: 12 additions & 28 deletions src/renderers/dom/client/ReactDOMTreeTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ function getParentInstance(inst) {
return inst._nativeParent;
}

/**
*
*/
function traverseUntil(inst, fn) {
while (inst && !fn(inst)) {
inst = inst._nativeParent;
}

return inst;
}

/**
* Simulates the traversal of a two-phase, capture/bubble event dispatch.
*/
Expand All @@ -97,38 +108,11 @@ function traverseTwoPhase(inst, fn, 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._nativeParent;
}
var pathTo = [];
while (to && to !== common) {
pathTo.push(to);
to = to._nativeParent;
}
var i;
for (i = 0; i < pathFrom.length; i++) {
fn(pathFrom[i], true, argFrom);
}
for (i = pathTo.length; i-- > 0;) {
fn(pathTo[i], false, argTo);
}
}

module.exports = {
isAncestor: isAncestor,
getLowestCommonAncestor: getLowestCommonAncestor,
getParentInstance: getParentInstance,
traverseUntil: traverseUntil,
traverseTwoPhase: traverseTwoPhase,
traverseEnterLeave: traverseEnterLeave,
};
109 changes: 0 additions & 109 deletions src/renderers/dom/client/__tests__/ReactDOMTreeTraversal-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ var ReactTestUtils = require('ReactTestUtils');
* Ensure that all callbacks are invoked, passing this unique argument.
*/
var ARG = {arg: true};
var ARG2 = {arg2: true};

var ChildComponent = React.createClass({
render: function() {
Expand Down Expand Up @@ -108,114 +107,6 @@ describe('ReactDOMTreeTraversal', function() {
});
});

describe('traverseEnterLeave', function() {
it('should not traverse when enter/leaving outside DOM', function() {
var target = null;
var expectedAggregation = [];
ReactDOMTreeTraversal.traverseEnterLeave(
target, target, argAggregator, ARG, ARG2
);
expect(aggregatedArgs).toEqual(expectedAggregation);
});

it('should not traverse if enter/leave the same node', function() {
var parent = renderParentIntoDocument();
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(
leave, enter, argAggregator, ARG, ARG2
);
expect(aggregatedArgs).toEqual(expectedAggregation);
});

it('should traverse enter/leave to sibling - avoids parent', function() {
var parent = renderParentIntoDocument();
var leave = getInst(parent.refs.P_P1_C1.refs.DIV_1);
var enter = getInst(parent.refs.P_P1_C1.refs.DIV_2);
var expectedAggregation = [
{node: parent.refs.P_P1_C1.refs.DIV_1, isUp: true, arg: ARG},
// enter/leave shouldn't fire anything on the parent
{node: parent.refs.P_P1_C1.refs.DIV_2, isUp: false, arg: ARG2},
];
ReactDOMTreeTraversal.traverseEnterLeave(
leave, enter, argAggregator, ARG, ARG2
);
expect(aggregatedArgs).toEqual(expectedAggregation);
});

it('should traverse enter/leave to parent - avoids parent', function() {
var parent = renderParentIntoDocument();
var leave = getInst(parent.refs.P_P1_C1.refs.DIV_1);
var enter = getInst(parent.refs.P_P1_C1.refs.DIV);
var expectedAggregation = [
{node: parent.refs.P_P1_C1.refs.DIV_1, isUp: true, arg: ARG},
];
ReactDOMTreeTraversal.traverseEnterLeave(
leave, enter, argAggregator, ARG, ARG2
);
expect(aggregatedArgs).toEqual(expectedAggregation);
});

it('should enter from the window', function() {
var parent = renderParentIntoDocument();
var leave = null; // From the window or outside of the React sandbox.
var enter = getInst(parent.refs.P_P1_C1.refs.DIV);
var expectedAggregation = [
{node: parent.refs.P, isUp: false, arg: ARG2},
{node: parent.refs.P_P1, isUp: false, arg: ARG2},
{node: parent.refs.P_P1_C1.refs.DIV, isUp: false, arg: ARG2},
];
ReactDOMTreeTraversal.traverseEnterLeave(
leave, enter, argAggregator, ARG, ARG2
);
expect(aggregatedArgs).toEqual(expectedAggregation);
});

it('should enter from the window to the shallowest', function() {
var parent = renderParentIntoDocument();
var leave = null; // From the window or outside of the React sandbox.
var enter = getInst(parent.refs.P);
var expectedAggregation = [
{node: parent.refs.P, isUp: false, arg: ARG2},
];
ReactDOMTreeTraversal.traverseEnterLeave(
leave, enter, argAggregator, ARG, ARG2
);
expect(aggregatedArgs).toEqual(expectedAggregation);
});

it('should leave to the window', function() {
var parent = renderParentIntoDocument();
var enter = null; // From the window or outside of the React sandbox.
var leave = getInst(parent.refs.P_P1_C1.refs.DIV);
var expectedAggregation = [
{node: parent.refs.P_P1_C1.refs.DIV, isUp: true, arg: ARG},
{node: parent.refs.P_P1, isUp: true, arg: ARG},
{node: parent.refs.P, isUp: true, arg: ARG},
];
ReactDOMTreeTraversal.traverseEnterLeave(
leave, enter, argAggregator, ARG, ARG2
);
expect(aggregatedArgs).toEqual(expectedAggregation);
});

it('should leave to the window from the shallowest', function() {
var parent = renderParentIntoDocument();
var enter = null; // From the window or outside of the React sandbox.
var leave = getInst(parent.refs.P_P1_C1.refs.DIV);
var expectedAggregation = [
{node: parent.refs.P_P1_C1.refs.DIV, isUp: true, arg: ARG},
{node: parent.refs.P_P1, isUp: true, arg: ARG},
{node: parent.refs.P, isUp: true, arg: ARG},
];
ReactDOMTreeTraversal.traverseEnterLeave(
leave, enter, argAggregator, ARG, ARG2
);
expect(aggregatedArgs).toEqual(expectedAggregation);
});
});

describe('getFirstCommonAncestor', function() {
it('should determine the first common ancestor correctly', function() {
var parent = renderParentIntoDocument();
Expand Down
Loading