Ignore event listener extraction on numeric text components (#9194)

In ReactDOM we don't dispatch events in the synthetic event system on to
text nodes. We back up one to the element before dispatching.

In React Native we don't do that. The iOS native side doesn't dispatch on
the text nodes but only the parent. The Android native side however does
dispatch on text nodes.

We already covered this for strings, but current element in Stack can be
a number if it is numeric text content.
This commit is contained in:
Sebastian Markbåge
2017-03-16 15:29:06 -07:00
committed by GitHub
parent 9549ebfae5
commit 9c7cf20dd5
2 changed files with 93 additions and 7 deletions
@@ -87,6 +87,93 @@ it('handles events', () => {
]);
});
it('handles events on text nodes', () => {
expect(RCTEventEmitter.register.mock.calls.length).toBe(1);
var EventEmitter = RCTEventEmitter.register.mock.calls[0][0];
var Text = createReactNativeComponentClass({
validAttributes: {foo: true},
uiViewClassName: 'Text',
});
class ContextHack extends React.Component {
static childContextTypes = {isInAParentText: React.PropTypes.bool};
getChildContext() {
return {isInAParentText: true};
}
render() {
return this.props.children;
}
}
var log = [];
ReactNative.render(
<ContextHack>
<Text>
<Text
onTouchEnd={() => log.push('string touchend')}
onTouchEndCapture={() => log.push('string touchend capture')}
onTouchStart={() => log.push('string touchstart')}
onTouchStartCapture={() => log.push('string touchstart capture')}>
Text Content
</Text>
<Text
onTouchEnd={() => log.push('number touchend')}
onTouchEndCapture={() => log.push('number touchend capture')}
onTouchStart={() => log.push('number touchstart')}
onTouchStartCapture={() => log.push('number touchstart capture')}>
{123}
</Text>
</Text>
</ContextHack>,
1,
);
expect(UIManager.createView.mock.calls.length).toBe(5);
// Don't depend on the order of createView() calls.
// Stack creates views outside-in; fiber creates them inside-out.
var innerTagString = UIManager.createView.mock.calls.find(
args => args[3] && args[3].text === 'Text Content',
)[0];
var innerTagNumber = UIManager.createView.mock.calls.find(
args => args[3] && args[3].text === '123',
)[0];
EventEmitter.receiveTouches(
'topTouchStart',
[{target: innerTagString, identifier: 17}],
[0],
);
EventEmitter.receiveTouches(
'topTouchEnd',
[{target: innerTagString, identifier: 17}],
[0],
);
EventEmitter.receiveTouches(
'topTouchStart',
[{target: innerTagNumber, identifier: 18}],
[0],
);
EventEmitter.receiveTouches(
'topTouchEnd',
[{target: innerTagNumber, identifier: 18}],
[0],
);
expect(log).toEqual([
'string touchstart capture',
'string touchstart',
'string touchend capture',
'string touchend',
'number touchstart capture',
'number touchstart',
'number touchend capture',
'number touchend',
]);
});
it('handles when a responder is unmounted while a touch sequence is in progress', () => {
var EventEmitter = RCTEventEmitter.register.mock.calls[0][0];
var View = createReactNativeComponentClass({
@@ -138,7 +138,10 @@ var EventPluginHub = {
return null;
}
} else {
if (typeof inst._currentElement === 'string') {
const currentElement = inst._currentElement;
if (
typeof currentElement === 'string' || typeof currentElement === 'number'
) {
// Text node, let it bubble through.
return null;
}
@@ -146,14 +149,10 @@ var EventPluginHub = {
// If the instance is already unmounted, we have no listeners.
return null;
}
const props = inst._currentElement.props;
const props = currentElement.props;
listener = props[registrationName];
if (
shouldPreventMouseEvent(
registrationName,
inst._currentElement.type,
props,
)
shouldPreventMouseEvent(registrationName, currentElement.type, props)
) {
return null;
}