Use browser event names for top-level event types in React DOM (#12629)
* Add TopLevelEventTypes * Fix `ReactBrowserEventEmitter` * Fix EventPluginUtils * Fix TapEventPlugin * Fix ResponderEventPlugin * Update ReactDOMFiberComponent * Fix BeforeInputEventPlugin * Fix ChangeEventPlugin * Fix EnterLeaveEventPlugin * Add missing non top event type used in ChangeEventPlugin * Fix SelectEventPlugin * Fix SimpleEventPlugin * Fix outstanding Flow issues and move TopLevelEventTypes * Inline a list of all events in `ReactTestUtils` * Fix tests * Make it pretty * Fix completly unrelated typo * Don’t use map constructor because of IE11 * Update typings, revert changes to native code * Make topLevelTypes in ResponderEventPlugin injectable and create DOM and ReactNative variant * Set proper dependencies for DOMResponderEventPlugin * Prettify * Make some react dom tests no longer depend on internal API * Use factories to create top level speific generic event modules * Remove unused dependency * Revert exposed module renaming, hide store creation, and inline dependency decleration * Add Flow types to createResponderEventPlugin and its consumers * Remove unused dependency * Use opaque flow type for TopLevelType * Add missing semis * Use raw event names as top level identifer * Upgrade baylon This is required for parsing opaque flow types in our CI tests. * Clean up flow types * Revert Map changes of ReactBrowserEventEmitter * Upgrade babel-* packages Apparently local unit tests also have issues with parsing JavaScript modules that contain opaque types (not sure why I didn't notice earlier!?). * Revert Map changes of SimpleEventPlugin * Clean up ReactTestUtils * Add missing semi * Fix Flow issue * Make TopLevelType clearer * Favor for loops * Explain the new DOMTopLevelEventTypes concept * Use static injection for Responder plugin types * Remove null check and rely on flow checks * Add missing ResponderEventPlugin dependencies
This commit is contained in:
parent
1047980dca
commit
e96dc14059
|
@ -15,7 +15,7 @@ function NumberInputs() {
|
|||
`}
|
||||
affectedBrowsers="IE Edge, IE 11">
|
||||
<TestCase.Steps>
|
||||
<li>Type any string (not an actual password</li>
|
||||
<li>Type any string (not an actual password)</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
"babel-plugin-transform-regenerator": "^6.26.0",
|
||||
"babel-preset-react": "^6.5.0",
|
||||
"babel-traverse": "^6.9.0",
|
||||
"babylon": "6.15.0",
|
||||
"babylon": "6.18.0",
|
||||
"bundle-collapser": "^1.1.1",
|
||||
"chalk": "^1.1.3",
|
||||
"cli-table": "^0.3.1",
|
||||
|
|
|
@ -25,6 +25,7 @@ import type {PluginModule} from './PluginModuleType';
|
|||
import type {ReactSyntheticEvent} from './ReactSyntheticEventType';
|
||||
import type {Fiber} from 'react-reconciler/src/ReactFiber';
|
||||
import type {AnyNativeEvent} from './PluginModuleType';
|
||||
import type {TopLevelType} from './TopLevelEventTypes';
|
||||
|
||||
/**
|
||||
* Internal queue of events that have accumulated their dispatches and are
|
||||
|
@ -165,7 +166,7 @@ export function getListener(inst: Fiber, registrationName: string) {
|
|||
* @internal
|
||||
*/
|
||||
function extractEvents(
|
||||
topLevelType: string,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: Fiber,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
nativeEventTarget: EventTarget,
|
||||
|
@ -227,7 +228,7 @@ export function runEventsInBatch(
|
|||
}
|
||||
|
||||
export function runExtractedEventsInBatch(
|
||||
topLevelType: string,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: Fiber,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
nativeEventTarget: EventTarget,
|
||||
|
|
|
@ -30,21 +30,6 @@ export const injection = {
|
|||
},
|
||||
};
|
||||
|
||||
export function isEndish(topLevelType) {
|
||||
return (
|
||||
topLevelType === 'topMouseUp' ||
|
||||
topLevelType === 'topTouchEnd' ||
|
||||
topLevelType === 'topTouchCancel'
|
||||
);
|
||||
}
|
||||
|
||||
export function isMoveish(topLevelType) {
|
||||
return topLevelType === 'topMouseMove' || topLevelType === 'topTouchMove';
|
||||
}
|
||||
export function isStartish(topLevelType) {
|
||||
return topLevelType === 'topMouseDown' || topLevelType === 'topTouchStart';
|
||||
}
|
||||
|
||||
let validateEventDispatches;
|
||||
if (__DEV__) {
|
||||
validateEventDispatches = function(event) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import type {
|
|||
DispatchConfig,
|
||||
ReactSyntheticEvent,
|
||||
} from './ReactSyntheticEventType';
|
||||
import type {TopLevelType} from './TopLevelEventTypes';
|
||||
|
||||
export type EventTypes = {[key: string]: DispatchConfig};
|
||||
|
||||
|
@ -22,7 +23,7 @@ export type PluginName = string;
|
|||
export type PluginModule<NativeEvent> = {
|
||||
eventTypes: EventTypes,
|
||||
extractEvents: (
|
||||
topLevelType: string,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: Fiber,
|
||||
nativeTarget: NativeEvent,
|
||||
nativeEventTarget: EventTarget,
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
*/
|
||||
|
||||
import type {Fiber} from 'react-reconciler/src/ReactFiber';
|
||||
import type {TopLevelType} from './TopLevelEventTypes';
|
||||
|
||||
export type DispatchConfig = {
|
||||
dependencies: Array<string>,
|
||||
dependencies: Array<TopLevelType>,
|
||||
phasedRegistrationNames?: {
|
||||
bubbled: string,
|
||||
captured: string,
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
import {getLowestCommonAncestor, isAncestor} from 'shared/ReactTreeTraversal';
|
||||
|
||||
import {
|
||||
isStartish,
|
||||
isMoveish,
|
||||
isEndish,
|
||||
executeDirectDispatch,
|
||||
hasDispatches,
|
||||
executeDispatchesInOrderStopAtTrue,
|
||||
|
@ -24,6 +21,17 @@ import {
|
|||
import ResponderSyntheticEvent from './ResponderSyntheticEvent';
|
||||
import ResponderTouchHistoryStore from './ResponderTouchHistoryStore';
|
||||
import accumulate from './accumulate';
|
||||
import {
|
||||
TOP_SCROLL,
|
||||
TOP_SELECTION_CHANGE,
|
||||
TOP_TOUCH_CANCEL,
|
||||
isStartish,
|
||||
isMoveish,
|
||||
isEndish,
|
||||
startDependencies,
|
||||
moveDependencies,
|
||||
endDependencies,
|
||||
} from './ResponderTopLevelEventTypes';
|
||||
|
||||
/**
|
||||
* Instance of element that should respond to touch/move types of interactions,
|
||||
|
@ -37,11 +45,6 @@ let responderInst = null;
|
|||
*/
|
||||
let trackedTouchCount = 0;
|
||||
|
||||
/**
|
||||
* Last reported number of active touches.
|
||||
*/
|
||||
let previousActiveTouches = 0;
|
||||
|
||||
const changeResponder = function(nextResponderInst, blockHostResponder) {
|
||||
const oldResponderInst = responderInst;
|
||||
responderInst = nextResponderInst;
|
||||
|
@ -64,6 +67,7 @@ const eventTypes = {
|
|||
bubbled: 'onStartShouldSetResponder',
|
||||
captured: 'onStartShouldSetResponderCapture',
|
||||
},
|
||||
dependencies: startDependencies,
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -80,6 +84,7 @@ const eventTypes = {
|
|||
bubbled: 'onScrollShouldSetResponder',
|
||||
captured: 'onScrollShouldSetResponderCapture',
|
||||
},
|
||||
dependencies: [TOP_SCROLL],
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -94,6 +99,7 @@ const eventTypes = {
|
|||
bubbled: 'onSelectionChangeShouldSetResponder',
|
||||
captured: 'onSelectionChangeShouldSetResponderCapture',
|
||||
},
|
||||
dependencies: [TOP_SELECTION_CHANGE],
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -105,21 +111,44 @@ const eventTypes = {
|
|||
bubbled: 'onMoveShouldSetResponder',
|
||||
captured: 'onMoveShouldSetResponderCapture',
|
||||
},
|
||||
dependencies: moveDependencies,
|
||||
},
|
||||
|
||||
/**
|
||||
* Direct responder events dispatched directly to responder. Do not bubble.
|
||||
*/
|
||||
responderStart: {registrationName: 'onResponderStart'},
|
||||
responderMove: {registrationName: 'onResponderMove'},
|
||||
responderEnd: {registrationName: 'onResponderEnd'},
|
||||
responderRelease: {registrationName: 'onResponderRelease'},
|
||||
responderStart: {
|
||||
registrationName: 'onResponderStart',
|
||||
dependencies: startDependencies,
|
||||
},
|
||||
responderMove: {
|
||||
registrationName: 'onResponderMove',
|
||||
dependencies: moveDependencies,
|
||||
},
|
||||
responderEnd: {
|
||||
registrationName: 'onResponderEnd',
|
||||
dependencies: endDependencies,
|
||||
},
|
||||
responderRelease: {
|
||||
registrationName: 'onResponderRelease',
|
||||
dependencies: endDependencies,
|
||||
},
|
||||
responderTerminationRequest: {
|
||||
registrationName: 'onResponderTerminationRequest',
|
||||
dependencies: [],
|
||||
},
|
||||
responderGrant: {
|
||||
registrationName: 'onResponderGrant',
|
||||
dependencies: [],
|
||||
},
|
||||
responderReject: {
|
||||
registrationName: 'onResponderReject',
|
||||
dependencies: [],
|
||||
},
|
||||
responderTerminate: {
|
||||
registrationName: 'onResponderTerminate',
|
||||
dependencies: [],
|
||||
},
|
||||
responderGrant: {registrationName: 'onResponderGrant'},
|
||||
responderReject: {registrationName: 'onResponderReject'},
|
||||
responderTerminate: {registrationName: 'onResponderTerminate'},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -322,7 +351,7 @@ function setResponderAndExtractTransfer(
|
|||
? eventTypes.startShouldSetResponder
|
||||
: isMoveish(topLevelType)
|
||||
? eventTypes.moveShouldSetResponder
|
||||
: topLevelType === 'topSelectionChange'
|
||||
: topLevelType === TOP_SELECTION_CHANGE
|
||||
? eventTypes.selectionChangeShouldSetResponder
|
||||
: eventTypes.scrollShouldSetResponder;
|
||||
|
||||
|
@ -427,8 +456,8 @@ function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) {
|
|||
// responderIgnoreScroll: We are trying to migrate away from specifically
|
||||
// tracking native scroll events here and responderIgnoreScroll indicates we
|
||||
// will send topTouchCancel to handle canceling touch events instead
|
||||
((topLevelType === 'topScroll' && !nativeEvent.responderIgnoreScroll) ||
|
||||
(trackedTouchCount > 0 && topLevelType === 'topSelectionChange') ||
|
||||
((topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll) ||
|
||||
(trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE) ||
|
||||
isStartish(topLevelType) ||
|
||||
isMoveish(topLevelType))
|
||||
);
|
||||
|
@ -534,7 +563,7 @@ const ResponderEventPlugin = {
|
|||
}
|
||||
|
||||
const isResponderTerminate =
|
||||
responderInst && topLevelType === 'topTouchCancel';
|
||||
responderInst && topLevelType === TOP_TOUCH_CANCEL;
|
||||
const isResponderRelease =
|
||||
responderInst &&
|
||||
!isResponderTerminate &&
|
||||
|
@ -556,23 +585,10 @@ const ResponderEventPlugin = {
|
|||
changeResponder(null);
|
||||
}
|
||||
|
||||
const numberActiveTouches =
|
||||
ResponderTouchHistoryStore.touchHistory.numberActiveTouches;
|
||||
if (
|
||||
ResponderEventPlugin.GlobalInteractionHandler &&
|
||||
numberActiveTouches !== previousActiveTouches
|
||||
) {
|
||||
ResponderEventPlugin.GlobalInteractionHandler.onChange(
|
||||
numberActiveTouches,
|
||||
);
|
||||
}
|
||||
previousActiveTouches = numberActiveTouches;
|
||||
|
||||
return extracted;
|
||||
},
|
||||
|
||||
GlobalResponderHandler: null,
|
||||
GlobalInteractionHandler: null,
|
||||
|
||||
injection: {
|
||||
/**
|
||||
|
@ -580,17 +596,9 @@ const ResponderEventPlugin = {
|
|||
* Object that handles any change in responder. Use this to inject
|
||||
* integration with an existing touch handling system etc.
|
||||
*/
|
||||
injectGlobalResponderHandler: function(GlobalResponderHandler) {
|
||||
injectGlobalResponderHandler(GlobalResponderHandler) {
|
||||
ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {{onChange: (numberActiveTouches) => void} GlobalInteractionHandler
|
||||
* Object that handles any change in the number of active touches.
|
||||
*/
|
||||
injectGlobalInteractionHandler: function(GlobalInteractionHandler) {
|
||||
ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
export const TOP_TOUCH_START = 'topTouchStart';
|
||||
export const TOP_TOUCH_MOVE = 'topTouchMove';
|
||||
export const TOP_TOUCH_END = 'topTouchEnd';
|
||||
export const TOP_TOUCH_CANCEL = 'topTouchCancel';
|
||||
export const TOP_SCROLL = 'topScroll';
|
||||
export const TOP_SELECTION_CHANGE = 'topSelectionChange';
|
||||
|
||||
export function isStartish(topLevelType: mixed): boolean {
|
||||
return topLevelType === TOP_TOUCH_START;
|
||||
}
|
||||
|
||||
export function isMoveish(topLevelType: mixed): boolean {
|
||||
return topLevelType === TOP_TOUCH_MOVE;
|
||||
}
|
||||
|
||||
export function isEndish(topLevelType: mixed): boolean {
|
||||
return topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL;
|
||||
}
|
||||
|
||||
export const startDependencies = [TOP_TOUCH_START];
|
||||
export const moveDependencies = [TOP_TOUCH_MOVE];
|
||||
export const endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END];
|
|
@ -10,7 +10,7 @@
|
|||
import invariant from 'fbjs/lib/invariant';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
import {isEndish, isMoveish, isStartish} from './EventPluginUtils';
|
||||
import {isStartish, isMoveish, isEndish} from './ResponderTopLevelEventTypes';
|
||||
|
||||
/**
|
||||
* Tracks the position and time of each active touch by `touch.identifier`. We
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {DOMTopLevelEventType} from 'react-dom/src/events/DOMTopLevelEventTypes';
|
||||
|
||||
type RNTopLevelEventType =
|
||||
| 'topMouseDown'
|
||||
| 'topMouseMove'
|
||||
| 'topMouseUp'
|
||||
| 'topScroll'
|
||||
| 'topSelectionChange'
|
||||
| 'topTouchCancel'
|
||||
| 'topTouchEnd'
|
||||
| 'topTouchMove'
|
||||
| 'topTouchStart';
|
||||
|
||||
export type TopLevelType = DOMTopLevelEventType | RNTopLevelEventType;
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
// Note: ideally these would be imported from DOMTopLevelEventTypes,
|
||||
// but our build system currently doesn't let us do that from a fork.
|
||||
|
||||
export const TOP_TOUCH_START = 'touchstart';
|
||||
export const TOP_TOUCH_MOVE = 'touchmove';
|
||||
export const TOP_TOUCH_END = 'touchend';
|
||||
export const TOP_TOUCH_CANCEL = 'touchcancel';
|
||||
export const TOP_SCROLL = 'scroll';
|
||||
export const TOP_SELECTION_CHANGE = 'selectionchange';
|
||||
export const TOP_MOUSE_DOWN = 'mousedown';
|
||||
export const TOP_MOUSE_MOVE = 'mousemove';
|
||||
export const TOP_MOUSE_UP = 'mouseup';
|
||||
|
||||
export function isStartish(topLevelType: mixed): boolean {
|
||||
return topLevelType === TOP_TOUCH_START || topLevelType === TOP_MOUSE_DOWN;
|
||||
}
|
||||
|
||||
export function isMoveish(topLevelType: mixed): boolean {
|
||||
return topLevelType === TOP_TOUCH_MOVE || topLevelType === TOP_MOUSE_MOVE;
|
||||
}
|
||||
|
||||
export function isEndish(topLevelType: mixed): boolean {
|
||||
return (
|
||||
topLevelType === TOP_TOUCH_END ||
|
||||
topLevelType === TOP_TOUCH_CANCEL ||
|
||||
topLevelType === TOP_MOUSE_UP
|
||||
);
|
||||
}
|
||||
|
||||
export const startDependencies = [TOP_TOUCH_START, TOP_MOUSE_DOWN];
|
||||
export const moveDependencies = [TOP_TOUCH_MOVE, TOP_MOUSE_MOVE];
|
||||
export const endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END, TOP_MOUSE_UP];
|
|
@ -309,14 +309,9 @@ describe('ReactDOM', () => {
|
|||
const actual = [];
|
||||
|
||||
function click(node) {
|
||||
const fakeNativeEvent = function() {};
|
||||
fakeNativeEvent.target = node;
|
||||
fakeNativeEvent.path = [node, container];
|
||||
ReactTestUtils.simulateNativeEventOnNode(
|
||||
'topClick',
|
||||
node,
|
||||
fakeNativeEvent,
|
||||
);
|
||||
ReactTestUtils.Simulate.click(node, {
|
||||
path: [node, container],
|
||||
});
|
||||
}
|
||||
|
||||
class Wrapper extends React.Component {
|
||||
|
|
|
@ -838,12 +838,7 @@ describe('ReactDOMFiber', () => {
|
|||
|
||||
expect(portal.tagName).toBe('DIV');
|
||||
|
||||
const fakeNativeEvent = {};
|
||||
ReactTestUtils.simulateNativeEventOnNode(
|
||||
'topClick',
|
||||
portal,
|
||||
fakeNativeEvent,
|
||||
);
|
||||
ReactTestUtils.Simulate.click(portal);
|
||||
|
||||
expect(ops).toEqual(['portal clicked', 'parent clicked']);
|
||||
});
|
||||
|
@ -858,14 +853,12 @@ describe('ReactDOMFiber', () => {
|
|||
|
||||
function simulateMouseMove(from, to) {
|
||||
if (from) {
|
||||
ReactTestUtils.simulateNativeEventOnNode('topMouseOut', from, {
|
||||
target: from,
|
||||
ReactTestUtils.SimulateNative.mouseOut(from, {
|
||||
relatedTarget: to,
|
||||
});
|
||||
}
|
||||
if (to) {
|
||||
ReactTestUtils.simulateNativeEventOnNode('topMouseOver', to, {
|
||||
target: to,
|
||||
ReactTestUtils.SimulateNative.mouseOver(to, {
|
||||
relatedTarget: from,
|
||||
});
|
||||
}
|
||||
|
@ -983,12 +976,7 @@ describe('ReactDOMFiber', () => {
|
|||
expect(node.tagName).toEqual('DIV');
|
||||
|
||||
function click(target) {
|
||||
const fakeNativeEvent = {};
|
||||
ReactTestUtils.simulateNativeEventOnNode(
|
||||
'topClick',
|
||||
target,
|
||||
fakeNativeEvent,
|
||||
);
|
||||
ReactTestUtils.Simulate.click(target);
|
||||
}
|
||||
|
||||
click(node);
|
||||
|
|
|
@ -694,10 +694,9 @@ describe('ReactDOMInput', () => {
|
|||
|
||||
setUntrackedValue.call(node, 'giraffe');
|
||||
|
||||
const fakeNativeEvent = function() {};
|
||||
fakeNativeEvent.target = node;
|
||||
fakeNativeEvent.path = [node, container];
|
||||
ReactTestUtils.simulateNativeEventOnNode('topInput', node, fakeNativeEvent);
|
||||
ReactTestUtils.SimulateNative.input(node, {
|
||||
path: [node, container],
|
||||
});
|
||||
|
||||
expect(handled).toBe(true);
|
||||
});
|
||||
|
|
|
@ -21,8 +21,16 @@ import * as ReactDOMFiberTextarea from './ReactDOMFiberTextarea';
|
|||
import * as inputValueTracking from './inputValueTracking';
|
||||
import setInnerHTML from './setInnerHTML';
|
||||
import setTextContent from './setTextContent';
|
||||
import {
|
||||
TOP_ERROR,
|
||||
TOP_INVALID,
|
||||
TOP_LOAD,
|
||||
TOP_RESET,
|
||||
TOP_SUBMIT,
|
||||
TOP_TOGGLE,
|
||||
} from '../events/DOMTopLevelEventTypes';
|
||||
import {listenTo, trapBubbledEvent} from '../events/ReactBrowserEventEmitter';
|
||||
import {mediaEventTypes} from '../events/BrowserEventConstants';
|
||||
import {mediaEventTypes} from '../events/DOMTopLevelEventTypes';
|
||||
import * as CSSPropertyOperations from '../shared/CSSPropertyOperations';
|
||||
import {Namespaces, getIntrinsicNamespace} from '../shared/DOMNamespaces';
|
||||
import {
|
||||
|
@ -440,43 +448,41 @@ export function setInitialProperties(
|
|||
switch (tag) {
|
||||
case 'iframe':
|
||||
case 'object':
|
||||
trapBubbledEvent('topLoad', 'load', domElement);
|
||||
trapBubbledEvent(TOP_LOAD, domElement);
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'video':
|
||||
case 'audio':
|
||||
// Create listener for each media event
|
||||
for (const event in mediaEventTypes) {
|
||||
if (mediaEventTypes.hasOwnProperty(event)) {
|
||||
trapBubbledEvent(event, mediaEventTypes[event], domElement);
|
||||
}
|
||||
for (let i = 0; i < mediaEventTypes.length; i++) {
|
||||
trapBubbledEvent(mediaEventTypes[i], domElement);
|
||||
}
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'source':
|
||||
trapBubbledEvent('topError', 'error', domElement);
|
||||
trapBubbledEvent(TOP_ERROR, domElement);
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'img':
|
||||
case 'image':
|
||||
case 'link':
|
||||
trapBubbledEvent('topError', 'error', domElement);
|
||||
trapBubbledEvent('topLoad', 'load', domElement);
|
||||
trapBubbledEvent(TOP_ERROR, domElement);
|
||||
trapBubbledEvent(TOP_LOAD, domElement);
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'form':
|
||||
trapBubbledEvent('topReset', 'reset', domElement);
|
||||
trapBubbledEvent('topSubmit', 'submit', domElement);
|
||||
trapBubbledEvent(TOP_RESET, domElement);
|
||||
trapBubbledEvent(TOP_SUBMIT, domElement);
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'details':
|
||||
trapBubbledEvent('topToggle', 'toggle', domElement);
|
||||
trapBubbledEvent(TOP_TOGGLE, domElement);
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'input':
|
||||
ReactDOMFiberInput.initWrapperState(domElement, rawProps);
|
||||
props = ReactDOMFiberInput.getHostProps(domElement, rawProps);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
trapBubbledEvent(TOP_INVALID, domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
|
@ -488,7 +494,7 @@ export function setInitialProperties(
|
|||
case 'select':
|
||||
ReactDOMFiberSelect.initWrapperState(domElement, rawProps);
|
||||
props = ReactDOMFiberSelect.getHostProps(domElement, rawProps);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
trapBubbledEvent(TOP_INVALID, domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
|
@ -496,7 +502,7 @@ export function setInitialProperties(
|
|||
case 'textarea':
|
||||
ReactDOMFiberTextarea.initWrapperState(domElement, rawProps);
|
||||
props = ReactDOMFiberTextarea.getHostProps(domElement, rawProps);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
trapBubbledEvent(TOP_INVALID, domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
|
@ -829,36 +835,34 @@ export function diffHydratedProperties(
|
|||
switch (tag) {
|
||||
case 'iframe':
|
||||
case 'object':
|
||||
trapBubbledEvent('topLoad', 'load', domElement);
|
||||
trapBubbledEvent(TOP_LOAD, domElement);
|
||||
break;
|
||||
case 'video':
|
||||
case 'audio':
|
||||
// Create listener for each media event
|
||||
for (const event in mediaEventTypes) {
|
||||
if (mediaEventTypes.hasOwnProperty(event)) {
|
||||
trapBubbledEvent(event, mediaEventTypes[event], domElement);
|
||||
}
|
||||
for (let i = 0; i < mediaEventTypes.length; i++) {
|
||||
trapBubbledEvent(mediaEventTypes[i], domElement);
|
||||
}
|
||||
break;
|
||||
case 'source':
|
||||
trapBubbledEvent('topError', 'error', domElement);
|
||||
trapBubbledEvent(TOP_ERROR, domElement);
|
||||
break;
|
||||
case 'img':
|
||||
case 'image':
|
||||
case 'link':
|
||||
trapBubbledEvent('topError', 'error', domElement);
|
||||
trapBubbledEvent('topLoad', 'load', domElement);
|
||||
trapBubbledEvent(TOP_ERROR, domElement);
|
||||
trapBubbledEvent(TOP_LOAD, domElement);
|
||||
break;
|
||||
case 'form':
|
||||
trapBubbledEvent('topReset', 'reset', domElement);
|
||||
trapBubbledEvent('topSubmit', 'submit', domElement);
|
||||
trapBubbledEvent(TOP_RESET, domElement);
|
||||
trapBubbledEvent(TOP_SUBMIT, domElement);
|
||||
break;
|
||||
case 'details':
|
||||
trapBubbledEvent('topToggle', 'toggle', domElement);
|
||||
trapBubbledEvent(TOP_TOGGLE, domElement);
|
||||
break;
|
||||
case 'input':
|
||||
ReactDOMFiberInput.initWrapperState(domElement, rawProps);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
trapBubbledEvent(TOP_INVALID, domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
|
@ -868,14 +872,14 @@ export function diffHydratedProperties(
|
|||
break;
|
||||
case 'select':
|
||||
ReactDOMFiberSelect.initWrapperState(domElement, rawProps);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
trapBubbledEvent(TOP_INVALID, domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
break;
|
||||
case 'textarea':
|
||||
ReactDOMFiberTextarea.initWrapperState(domElement, rawProps);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
trapBubbledEvent(TOP_INVALID, domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
|
|
|
@ -5,11 +5,23 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {TopLevelTypes} from './BrowserEventConstants';
|
||||
import type {TopLevelType} from 'events/TopLevelEventTypes';
|
||||
|
||||
import {accumulateTwoPhaseDispatches} from 'events/EventPropagators';
|
||||
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
|
||||
|
||||
import {
|
||||
TOP_BLUR,
|
||||
TOP_COMPOSITION_START,
|
||||
TOP_COMPOSITION_END,
|
||||
TOP_COMPOSITION_UPDATE,
|
||||
TOP_KEY_DOWN,
|
||||
TOP_KEY_PRESS,
|
||||
TOP_KEY_UP,
|
||||
TOP_MOUSE_DOWN,
|
||||
TOP_TEXT_INPUT,
|
||||
TOP_PASTE,
|
||||
} from './DOMTopLevelEventTypes';
|
||||
import * as FallbackCompositionState from './FallbackCompositionState';
|
||||
import SyntheticCompositionEvent from './SyntheticCompositionEvent';
|
||||
import SyntheticInputEvent from './SyntheticInputEvent';
|
||||
|
@ -50,10 +62,10 @@ const eventTypes = {
|
|||
captured: 'onBeforeInputCapture',
|
||||
},
|
||||
dependencies: [
|
||||
'topCompositionEnd',
|
||||
'topKeyPress',
|
||||
'topTextInput',
|
||||
'topPaste',
|
||||
TOP_COMPOSITION_END,
|
||||
TOP_KEY_PRESS,
|
||||
TOP_TEXT_INPUT,
|
||||
TOP_PASTE,
|
||||
],
|
||||
},
|
||||
compositionEnd: {
|
||||
|
@ -62,12 +74,12 @@ const eventTypes = {
|
|||
captured: 'onCompositionEndCapture',
|
||||
},
|
||||
dependencies: [
|
||||
'topBlur',
|
||||
'topCompositionEnd',
|
||||
'topKeyDown',
|
||||
'topKeyPress',
|
||||
'topKeyUp',
|
||||
'topMouseDown',
|
||||
TOP_BLUR,
|
||||
TOP_COMPOSITION_END,
|
||||
TOP_KEY_DOWN,
|
||||
TOP_KEY_PRESS,
|
||||
TOP_KEY_UP,
|
||||
TOP_MOUSE_DOWN,
|
||||
],
|
||||
},
|
||||
compositionStart: {
|
||||
|
@ -76,12 +88,12 @@ const eventTypes = {
|
|||
captured: 'onCompositionStartCapture',
|
||||
},
|
||||
dependencies: [
|
||||
'topBlur',
|
||||
'topCompositionStart',
|
||||
'topKeyDown',
|
||||
'topKeyPress',
|
||||
'topKeyUp',
|
||||
'topMouseDown',
|
||||
TOP_BLUR,
|
||||
TOP_COMPOSITION_START,
|
||||
TOP_KEY_DOWN,
|
||||
TOP_KEY_PRESS,
|
||||
TOP_KEY_UP,
|
||||
TOP_MOUSE_DOWN,
|
||||
],
|
||||
},
|
||||
compositionUpdate: {
|
||||
|
@ -90,12 +102,12 @@ const eventTypes = {
|
|||
captured: 'onCompositionUpdateCapture',
|
||||
},
|
||||
dependencies: [
|
||||
'topBlur',
|
||||
'topCompositionUpdate',
|
||||
'topKeyDown',
|
||||
'topKeyPress',
|
||||
'topKeyUp',
|
||||
'topMouseDown',
|
||||
TOP_BLUR,
|
||||
TOP_COMPOSITION_UPDATE,
|
||||
TOP_KEY_DOWN,
|
||||
TOP_KEY_PRESS,
|
||||
TOP_KEY_UP,
|
||||
TOP_MOUSE_DOWN,
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -124,11 +136,11 @@ function isKeypressCommand(nativeEvent) {
|
|||
*/
|
||||
function getCompositionEventType(topLevelType) {
|
||||
switch (topLevelType) {
|
||||
case 'topCompositionStart':
|
||||
case TOP_COMPOSITION_START:
|
||||
return eventTypes.compositionStart;
|
||||
case 'topCompositionEnd':
|
||||
case TOP_COMPOSITION_END:
|
||||
return eventTypes.compositionEnd;
|
||||
case 'topCompositionUpdate':
|
||||
case TOP_COMPOSITION_UPDATE:
|
||||
return eventTypes.compositionUpdate;
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +154,7 @@ function getCompositionEventType(topLevelType) {
|
|||
* @return {boolean}
|
||||
*/
|
||||
function isFallbackCompositionStart(topLevelType, nativeEvent) {
|
||||
return topLevelType === 'topKeyDown' && nativeEvent.keyCode === START_KEYCODE;
|
||||
return topLevelType === TOP_KEY_DOWN && nativeEvent.keyCode === START_KEYCODE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,16 +166,16 @@ function isFallbackCompositionStart(topLevelType, nativeEvent) {
|
|||
*/
|
||||
function isFallbackCompositionEnd(topLevelType, nativeEvent) {
|
||||
switch (topLevelType) {
|
||||
case 'topKeyUp':
|
||||
case TOP_KEY_UP:
|
||||
// Command keys insert or clear IME input.
|
||||
return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1;
|
||||
case 'topKeyDown':
|
||||
case TOP_KEY_DOWN:
|
||||
// Expect IME keyCode on each keydown. If we get any other
|
||||
// code we must have exited earlier.
|
||||
return nativeEvent.keyCode !== START_KEYCODE;
|
||||
case 'topKeyPress':
|
||||
case 'topMouseDown':
|
||||
case 'topBlur':
|
||||
case TOP_KEY_PRESS:
|
||||
case TOP_MOUSE_DOWN:
|
||||
case TOP_BLUR:
|
||||
// Events are not possible without cancelling IME.
|
||||
return true;
|
||||
default:
|
||||
|
@ -252,15 +264,15 @@ function extractCompositionEvent(
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {TopLevelTypes} topLevelType Record from `BrowserEventConstants`.
|
||||
* @param {TopLevelType} topLevelType Number from `TopLevelType`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {?string} The string corresponding to this `beforeInput` event.
|
||||
*/
|
||||
function getNativeBeforeInputChars(topLevelType: TopLevelTypes, nativeEvent) {
|
||||
function getNativeBeforeInputChars(topLevelType: TopLevelType, nativeEvent) {
|
||||
switch (topLevelType) {
|
||||
case 'topCompositionEnd':
|
||||
case TOP_COMPOSITION_END:
|
||||
return getDataFromCustomEvent(nativeEvent);
|
||||
case 'topKeyPress':
|
||||
case TOP_KEY_PRESS:
|
||||
/**
|
||||
* If native `textInput` events are available, our goal is to make
|
||||
* use of them. However, there is a special case: the spacebar key.
|
||||
|
@ -283,7 +295,7 @@ function getNativeBeforeInputChars(topLevelType: TopLevelTypes, nativeEvent) {
|
|||
hasSpaceKeypress = true;
|
||||
return SPACEBAR_CHAR;
|
||||
|
||||
case 'topTextInput':
|
||||
case TOP_TEXT_INPUT:
|
||||
// Record the characters to be added to the DOM.
|
||||
const chars = nativeEvent.data;
|
||||
|
||||
|
@ -306,18 +318,18 @@ function getNativeBeforeInputChars(topLevelType: TopLevelTypes, nativeEvent) {
|
|||
* For browsers that do not provide the `textInput` event, extract the
|
||||
* appropriate string to use for SyntheticInputEvent.
|
||||
*
|
||||
* @param {string} topLevelType Record from `BrowserEventConstants`.
|
||||
* @param {number} topLevelType Number from `TopLevelEventTypes`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {?string} The fallback string for this `beforeInput` event.
|
||||
*/
|
||||
function getFallbackBeforeInputChars(topLevelType: TopLevelTypes, nativeEvent) {
|
||||
function getFallbackBeforeInputChars(topLevelType: TopLevelType, nativeEvent) {
|
||||
// If we are currently composing (IME) and using a fallback to do so,
|
||||
// try to extract the composed characters from the fallback object.
|
||||
// If composition event is available, we extract a string only at
|
||||
// compositionevent, otherwise extract it at fallback events.
|
||||
if (isComposing) {
|
||||
if (
|
||||
topLevelType === 'topCompositionEnd' ||
|
||||
topLevelType === TOP_COMPOSITION_END ||
|
||||
(!canUseCompositionEvent &&
|
||||
isFallbackCompositionEnd(topLevelType, nativeEvent))
|
||||
) {
|
||||
|
@ -330,11 +342,11 @@ function getFallbackBeforeInputChars(topLevelType: TopLevelTypes, nativeEvent) {
|
|||
}
|
||||
|
||||
switch (topLevelType) {
|
||||
case 'topPaste':
|
||||
case TOP_PASTE:
|
||||
// If a paste event occurs after a keypress, throw out the input
|
||||
// chars. Paste events should not lead to BeforeInput events.
|
||||
return null;
|
||||
case 'topKeyPress':
|
||||
case TOP_KEY_PRESS:
|
||||
/**
|
||||
* As of v27, Firefox may fire keypress events even when no character
|
||||
* will be inserted. A few possibilities:
|
||||
|
@ -365,7 +377,7 @@ function getFallbackBeforeInputChars(topLevelType: TopLevelTypes, nativeEvent) {
|
|||
}
|
||||
}
|
||||
return null;
|
||||
case 'topCompositionEnd':
|
||||
case TOP_COMPOSITION_END:
|
||||
return useFallbackCompositionData ? null : nativeEvent.data;
|
||||
default:
|
||||
return null;
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import getVendorPrefixedEventName from './getVendorPrefixedEventName';
|
||||
|
||||
/**
|
||||
* Types of raw signals from the browser caught at the top level.
|
||||
*
|
||||
* For events like 'submit' or audio/video events which don't consistently
|
||||
* bubble (which we trap at a lower node than `document`), binding
|
||||
* at `document` would cause duplicate events so we don't include them here.
|
||||
*/
|
||||
export const topLevelTypes = {
|
||||
topAnimationEnd: getVendorPrefixedEventName('animationend'),
|
||||
topAnimationIteration: getVendorPrefixedEventName('animationiteration'),
|
||||
topAnimationStart: getVendorPrefixedEventName('animationstart'),
|
||||
topBlur: 'blur',
|
||||
topCancel: 'cancel',
|
||||
topChange: 'change',
|
||||
topClick: 'click',
|
||||
topClose: 'close',
|
||||
topCompositionEnd: 'compositionend',
|
||||
topCompositionStart: 'compositionstart',
|
||||
topCompositionUpdate: 'compositionupdate',
|
||||
topContextMenu: 'contextmenu',
|
||||
topCopy: 'copy',
|
||||
topCut: 'cut',
|
||||
topDoubleClick: 'dblclick',
|
||||
topDrag: 'drag',
|
||||
topDragEnd: 'dragend',
|
||||
topDragEnter: 'dragenter',
|
||||
topDragExit: 'dragexit',
|
||||
topDragLeave: 'dragleave',
|
||||
topDragOver: 'dragover',
|
||||
topDragStart: 'dragstart',
|
||||
topDrop: 'drop',
|
||||
topFocus: 'focus',
|
||||
topInput: 'input',
|
||||
topKeyDown: 'keydown',
|
||||
topKeyPress: 'keypress',
|
||||
topKeyUp: 'keyup',
|
||||
topLoad: 'load',
|
||||
topLoadStart: 'loadstart',
|
||||
topMouseDown: 'mousedown',
|
||||
topMouseMove: 'mousemove',
|
||||
topMouseOut: 'mouseout',
|
||||
topMouseOver: 'mouseover',
|
||||
topMouseUp: 'mouseup',
|
||||
topPaste: 'paste',
|
||||
topScroll: 'scroll',
|
||||
topSelectionChange: 'selectionchange',
|
||||
topTextInput: 'textInput',
|
||||
topToggle: 'toggle',
|
||||
topTouchCancel: 'touchcancel',
|
||||
topTouchEnd: 'touchend',
|
||||
topTouchMove: 'touchmove',
|
||||
topTouchStart: 'touchstart',
|
||||
topTransitionEnd: getVendorPrefixedEventName('transitionend'),
|
||||
topWheel: 'wheel',
|
||||
};
|
||||
|
||||
// There are so many media events, it makes sense to just
|
||||
// maintain a list of them. Note these aren't technically
|
||||
// "top-level" since they don't bubble. We should come up
|
||||
// with a better naming convention if we come to refactoring
|
||||
// the event system.
|
||||
export const mediaEventTypes = {
|
||||
topAbort: 'abort',
|
||||
topCanPlay: 'canplay',
|
||||
topCanPlayThrough: 'canplaythrough',
|
||||
topDurationChange: 'durationchange',
|
||||
topEmptied: 'emptied',
|
||||
topEncrypted: 'encrypted',
|
||||
topEnded: 'ended',
|
||||
topError: 'error',
|
||||
topLoadedData: 'loadeddata',
|
||||
topLoadedMetadata: 'loadedmetadata',
|
||||
topLoadStart: 'loadstart',
|
||||
topPause: 'pause',
|
||||
topPlay: 'play',
|
||||
topPlaying: 'playing',
|
||||
topProgress: 'progress',
|
||||
topRateChange: 'ratechange',
|
||||
topSeeked: 'seeked',
|
||||
topSeeking: 'seeking',
|
||||
topStalled: 'stalled',
|
||||
topSuspend: 'suspend',
|
||||
topTimeUpdate: 'timeupdate',
|
||||
topVolumeChange: 'volumechange',
|
||||
topWaiting: 'waiting',
|
||||
};
|
||||
|
||||
export type TopLevelTypes = $Enum<typeof topLevelTypes>;
|
|
@ -13,6 +13,16 @@ import SyntheticEvent from 'events/SyntheticEvent';
|
|||
import isTextInputElement from 'shared/isTextInputElement';
|
||||
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
|
||||
|
||||
import {
|
||||
TOP_BLUR,
|
||||
TOP_CHANGE,
|
||||
TOP_CLICK,
|
||||
TOP_FOCUS,
|
||||
TOP_INPUT,
|
||||
TOP_KEY_DOWN,
|
||||
TOP_KEY_UP,
|
||||
TOP_SELECTION_CHANGE,
|
||||
} from './DOMTopLevelEventTypes';
|
||||
import getEventTarget from './getEventTarget';
|
||||
import isEventSupported from './isEventSupported';
|
||||
import {getNodeFromInstance} from '../client/ReactDOMComponentTree';
|
||||
|
@ -26,14 +36,14 @@ const eventTypes = {
|
|||
captured: 'onChangeCapture',
|
||||
},
|
||||
dependencies: [
|
||||
'topBlur',
|
||||
'topChange',
|
||||
'topClick',
|
||||
'topFocus',
|
||||
'topInput',
|
||||
'topKeyDown',
|
||||
'topKeyUp',
|
||||
'topSelectionChange',
|
||||
TOP_BLUR,
|
||||
TOP_CHANGE,
|
||||
TOP_CLICK,
|
||||
TOP_FOCUS,
|
||||
TOP_INPUT,
|
||||
TOP_KEY_DOWN,
|
||||
TOP_KEY_UP,
|
||||
TOP_SELECTION_CHANGE,
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -100,7 +110,7 @@ function getInstIfValueChanged(targetInst) {
|
|||
}
|
||||
|
||||
function getTargetInstForChangeEvent(topLevelType, targetInst) {
|
||||
if (topLevelType === 'topChange') {
|
||||
if (topLevelType === TOP_CHANGE) {
|
||||
return targetInst;
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +165,7 @@ function handlePropertyChange(nativeEvent) {
|
|||
}
|
||||
|
||||
function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) {
|
||||
if (topLevelType === 'topFocus') {
|
||||
if (topLevelType === TOP_FOCUS) {
|
||||
// In IE9, propertychange fires for most input events but is buggy and
|
||||
// doesn't fire when text is deleted, but conveniently, selectionchange
|
||||
// appears to fire in all of the remaining cases so we catch those and
|
||||
|
@ -168,7 +178,7 @@ function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) {
|
|||
// missed a blur event somehow.
|
||||
stopWatchingForValueChange();
|
||||
startWatchingForValueChange(target, targetInst);
|
||||
} else if (topLevelType === 'topBlur') {
|
||||
} else if (topLevelType === TOP_BLUR) {
|
||||
stopWatchingForValueChange();
|
||||
}
|
||||
}
|
||||
|
@ -176,9 +186,9 @@ function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) {
|
|||
// For IE8 and IE9.
|
||||
function getTargetInstForInputEventPolyfill(topLevelType, targetInst) {
|
||||
if (
|
||||
topLevelType === 'topSelectionChange' ||
|
||||
topLevelType === 'topKeyUp' ||
|
||||
topLevelType === 'topKeyDown'
|
||||
topLevelType === TOP_SELECTION_CHANGE ||
|
||||
topLevelType === TOP_KEY_UP ||
|
||||
topLevelType === TOP_KEY_DOWN
|
||||
) {
|
||||
// On the selectionchange event, the target is just document which isn't
|
||||
// helpful for us so just check activeElement instead.
|
||||
|
@ -210,13 +220,13 @@ function shouldUseClickEvent(elem) {
|
|||
}
|
||||
|
||||
function getTargetInstForClickEvent(topLevelType, targetInst) {
|
||||
if (topLevelType === 'topClick') {
|
||||
if (topLevelType === TOP_CLICK) {
|
||||
return getInstIfValueChanged(targetInst);
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetInstForInputOrChangeEvent(topLevelType, targetInst) {
|
||||
if (topLevelType === 'topInput' || topLevelType === 'topChange') {
|
||||
if (topLevelType === TOP_INPUT || topLevelType === TOP_CHANGE) {
|
||||
return getInstIfValueChanged(targetInst);
|
||||
}
|
||||
}
|
||||
|
@ -292,7 +302,7 @@ const ChangeEventPlugin = {
|
|||
}
|
||||
|
||||
// When blurring, set the value attribute for number inputs
|
||||
if (topLevelType === 'topBlur') {
|
||||
if (topLevelType === TOP_BLUR) {
|
||||
handleControlledInputBlur(targetInst, targetNode);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {TopLevelType} from 'events/TopLevelEventTypes';
|
||||
import getVendorPrefixedEventName from './getVendorPrefixedEventName';
|
||||
|
||||
/**
|
||||
* To identify top level events in react-dom, we use constants defined by this
|
||||
* module. Those are completely opaque to every other module but we rely on them
|
||||
* being the raw DOM event names inside this module. This allows us to build a
|
||||
* very efficient mapping from top level identifiers to the raw event type.
|
||||
*
|
||||
* The use of an `opaque` flow type makes sure that we can only access the value
|
||||
* of a constant in this module.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
export opaque type DOMTopLevelEventType =
|
||||
| 'abort'
|
||||
| 'animationend'
|
||||
| 'animationiteration'
|
||||
| 'animationstart'
|
||||
| 'blur'
|
||||
| 'canplay'
|
||||
| 'canplaythrough'
|
||||
| 'cancel'
|
||||
| 'change'
|
||||
| 'click'
|
||||
| 'close'
|
||||
| 'compositionend'
|
||||
| 'compositionstart'
|
||||
| 'compositionupdate'
|
||||
| 'contextmenu'
|
||||
| 'copy'
|
||||
| 'cut'
|
||||
| 'dblclick'
|
||||
| 'drag'
|
||||
| 'dragend'
|
||||
| 'dragenter'
|
||||
| 'dragexit'
|
||||
| 'dragleave'
|
||||
| 'dragover'
|
||||
| 'dragstart'
|
||||
| 'drop'
|
||||
| 'durationchange'
|
||||
| 'emptied'
|
||||
| 'encrypted'
|
||||
| 'ended'
|
||||
| 'error'
|
||||
| 'focus'
|
||||
| 'input'
|
||||
| 'invalid'
|
||||
| 'keydown'
|
||||
| 'keypress'
|
||||
| 'keyup'
|
||||
| 'load'
|
||||
| 'loadstart'
|
||||
| 'loadeddata'
|
||||
| 'loadedmetadata'
|
||||
| 'mousedown'
|
||||
| 'mousemove'
|
||||
| 'mouseout'
|
||||
| 'mouseover'
|
||||
| 'mouseup'
|
||||
| 'paste'
|
||||
| 'pause'
|
||||
| 'play'
|
||||
| 'playing'
|
||||
| 'progress'
|
||||
| 'ratechange'
|
||||
| 'reset'
|
||||
| 'scroll'
|
||||
| 'seeked'
|
||||
| 'seeking'
|
||||
| 'selectionchange'
|
||||
| 'stalled'
|
||||
| 'submit'
|
||||
| 'suspend'
|
||||
| 'textInput'
|
||||
| 'timeupdate'
|
||||
| 'toggle'
|
||||
| 'touchcancel'
|
||||
| 'touchend'
|
||||
| 'touchmove'
|
||||
| 'touchstart'
|
||||
| 'transitionend'
|
||||
| 'volumechange'
|
||||
| 'waiting'
|
||||
| 'wheel';
|
||||
|
||||
export const TOP_ABORT: TopLevelType = 'abort';
|
||||
export const TOP_ANIMATION_END: TopLevelType = getVendorPrefixedEventName(
|
||||
'animationend',
|
||||
);
|
||||
export const TOP_ANIMATION_ITERATION: TopLevelType = getVendorPrefixedEventName(
|
||||
'animationiteration',
|
||||
);
|
||||
export const TOP_ANIMATION_START: TopLevelType = getVendorPrefixedEventName(
|
||||
'animationstart',
|
||||
);
|
||||
export const TOP_BLUR: TopLevelType = 'blur';
|
||||
export const TOP_CAN_PLAY: TopLevelType = 'canplay';
|
||||
export const TOP_CAN_PLAY_THROUGH: TopLevelType = 'canplaythrough';
|
||||
export const TOP_CANCEL: TopLevelType = 'cancel';
|
||||
export const TOP_CHANGE: TopLevelType = 'change';
|
||||
export const TOP_CLICK: TopLevelType = 'click';
|
||||
export const TOP_CLOSE: TopLevelType = 'close';
|
||||
export const TOP_COMPOSITION_END: TopLevelType = 'compositionend';
|
||||
export const TOP_COMPOSITION_START: TopLevelType = 'compositionstart';
|
||||
export const TOP_COMPOSITION_UPDATE: TopLevelType = 'compositionupdate';
|
||||
export const TOP_CONTEXT_MENU: TopLevelType = 'contextmenu';
|
||||
export const TOP_COPY: TopLevelType = 'copy';
|
||||
export const TOP_CUT: TopLevelType = 'cut';
|
||||
export const TOP_DOUBLE_CLICK: TopLevelType = 'dblclick';
|
||||
export const TOP_DRAG: TopLevelType = 'drag';
|
||||
export const TOP_DRAG_END: TopLevelType = 'dragend';
|
||||
export const TOP_DRAG_ENTER: TopLevelType = 'dragenter';
|
||||
export const TOP_DRAG_EXIT: TopLevelType = 'dragexit';
|
||||
export const TOP_DRAG_LEAVE: TopLevelType = 'dragleave';
|
||||
export const TOP_DRAG_OVER: TopLevelType = 'dragover';
|
||||
export const TOP_DRAG_START: TopLevelType = 'dragstart';
|
||||
export const TOP_DROP: TopLevelType = 'drop';
|
||||
export const TOP_DURATION_CHANGE: TopLevelType = 'durationchange';
|
||||
export const TOP_EMPTIED: TopLevelType = 'emptied';
|
||||
export const TOP_ENCRYPTED: TopLevelType = 'encrypted';
|
||||
export const TOP_ENDED: TopLevelType = 'ended';
|
||||
export const TOP_ERROR: TopLevelType = 'error';
|
||||
export const TOP_FOCUS: TopLevelType = 'focus';
|
||||
export const TOP_INPUT: TopLevelType = 'input';
|
||||
export const TOP_INVALID: TopLevelType = 'invalid';
|
||||
export const TOP_KEY_DOWN: TopLevelType = 'keydown';
|
||||
export const TOP_KEY_PRESS: TopLevelType = 'keypress';
|
||||
export const TOP_KEY_UP: TopLevelType = 'keyup';
|
||||
export const TOP_LOAD: TopLevelType = 'load';
|
||||
export const TOP_LOAD_START: TopLevelType = 'loadstart';
|
||||
export const TOP_LOADED_DATA: TopLevelType = 'loadeddata';
|
||||
export const TOP_LOADED_METADATA: TopLevelType = 'loadedmetadata';
|
||||
export const TOP_MOUSE_DOWN: TopLevelType = 'mousedown';
|
||||
export const TOP_MOUSE_MOVE: TopLevelType = 'mousemove';
|
||||
export const TOP_MOUSE_OUT: TopLevelType = 'mouseout';
|
||||
export const TOP_MOUSE_OVER: TopLevelType = 'mouseover';
|
||||
export const TOP_MOUSE_UP: TopLevelType = 'mouseup';
|
||||
export const TOP_PASTE: TopLevelType = 'paste';
|
||||
export const TOP_PAUSE: TopLevelType = 'pause';
|
||||
export const TOP_PLAY: TopLevelType = 'play';
|
||||
export const TOP_PLAYING: TopLevelType = 'playing';
|
||||
export const TOP_PROGRESS: TopLevelType = 'progress';
|
||||
export const TOP_RATE_CHANGE: TopLevelType = 'ratechange';
|
||||
export const TOP_RESET: TopLevelType = 'reset';
|
||||
export const TOP_SCROLL: TopLevelType = 'scroll';
|
||||
export const TOP_SEEKED: TopLevelType = 'seeked';
|
||||
export const TOP_SEEKING: TopLevelType = 'seeking';
|
||||
export const TOP_SELECTION_CHANGE: TopLevelType = 'selectionchange';
|
||||
export const TOP_STALLED: TopLevelType = 'stalled';
|
||||
export const TOP_SUBMIT: TopLevelType = 'submit';
|
||||
export const TOP_SUSPEND: TopLevelType = 'suspend';
|
||||
export const TOP_TEXT_INPUT: TopLevelType = 'textInput';
|
||||
export const TOP_TIME_UPDATE: TopLevelType = 'timeupdate';
|
||||
export const TOP_TOGGLE: TopLevelType = 'toggle';
|
||||
export const TOP_TOUCH_CANCEL: TopLevelType = 'touchcancel';
|
||||
export const TOP_TOUCH_END: TopLevelType = 'touchend';
|
||||
export const TOP_TOUCH_MOVE: TopLevelType = 'touchmove';
|
||||
export const TOP_TOUCH_START: TopLevelType = 'touchstart';
|
||||
export const TOP_TRANSITION_END: TopLevelType = getVendorPrefixedEventName(
|
||||
'transitionend',
|
||||
);
|
||||
export const TOP_VOLUME_CHANGE: TopLevelType = 'volumechange';
|
||||
export const TOP_WAITING: TopLevelType = 'waiting';
|
||||
export const TOP_WHEEL: TopLevelType = 'wheel';
|
||||
|
||||
export const mediaEventTypes: Array<TopLevelType> = [
|
||||
TOP_ABORT,
|
||||
TOP_CAN_PLAY,
|
||||
TOP_CAN_PLAY_THROUGH,
|
||||
TOP_DURATION_CHANGE,
|
||||
TOP_EMPTIED,
|
||||
TOP_ENCRYPTED,
|
||||
TOP_ENDED,
|
||||
TOP_ERROR,
|
||||
TOP_LOADED_DATA,
|
||||
TOP_LOADED_METADATA,
|
||||
TOP_LOAD_START,
|
||||
TOP_PAUSE,
|
||||
TOP_PLAY,
|
||||
TOP_PLAYING,
|
||||
TOP_PROGRESS,
|
||||
TOP_RATE_CHANGE,
|
||||
TOP_SEEKED,
|
||||
TOP_SEEKING,
|
||||
TOP_STALLED,
|
||||
TOP_SUSPEND,
|
||||
TOP_TIME_UPDATE,
|
||||
TOP_VOLUME_CHANGE,
|
||||
TOP_WAITING,
|
||||
];
|
||||
|
||||
export function getRawEventName(topLevelType: TopLevelType): string {
|
||||
return topLevelType;
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import {accumulateEnterLeaveDispatches} from 'events/EventPropagators';
|
||||
|
||||
import {TOP_MOUSE_OUT, TOP_MOUSE_OVER} from './DOMTopLevelEventTypes';
|
||||
import SyntheticMouseEvent from './SyntheticMouseEvent';
|
||||
import {
|
||||
getClosestInstanceFromNode,
|
||||
|
@ -16,11 +17,11 @@ import {
|
|||
const eventTypes = {
|
||||
mouseEnter: {
|
||||
registrationName: 'onMouseEnter',
|
||||
dependencies: ['topMouseOut', 'topMouseOver'],
|
||||
dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER],
|
||||
},
|
||||
mouseLeave: {
|
||||
registrationName: 'onMouseLeave',
|
||||
dependencies: ['topMouseOut', 'topMouseOver'],
|
||||
dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER],
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -41,12 +42,12 @@ const EnterLeaveEventPlugin = {
|
|||
nativeEventTarget,
|
||||
) {
|
||||
if (
|
||||
topLevelType === 'topMouseOver' &&
|
||||
topLevelType === TOP_MOUSE_OVER &&
|
||||
(nativeEvent.relatedTarget || nativeEvent.fromElement)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
if (topLevelType !== 'topMouseOut' && topLevelType !== 'topMouseOver') {
|
||||
if (topLevelType !== TOP_MOUSE_OUT && topLevelType !== TOP_MOUSE_OVER) {
|
||||
// Must not be a mouse in or mouse out - ignoring.
|
||||
return null;
|
||||
}
|
||||
|
@ -67,7 +68,7 @@ const EnterLeaveEventPlugin = {
|
|||
|
||||
let from;
|
||||
let to;
|
||||
if (topLevelType === 'topMouseOut') {
|
||||
if (topLevelType === TOP_MOUSE_OUT) {
|
||||
from = targetInst;
|
||||
const related = nativeEvent.relatedTarget || nativeEvent.toElement;
|
||||
to = related ? getClosestInstanceFromNode(related) : null;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
export function addEventBubbleListener(
|
||||
element: Element,
|
||||
element: Document | Element,
|
||||
eventType: string,
|
||||
listener: Function,
|
||||
): void {
|
||||
|
@ -16,7 +16,7 @@ export function addEventBubbleListener(
|
|||
}
|
||||
|
||||
export function addEventCaptureListener(
|
||||
element: Element,
|
||||
element: Document | Element,
|
||||
eventType: string,
|
||||
listener: Function,
|
||||
): void {
|
||||
|
|
|
@ -3,9 +3,18 @@
|
|||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import {registrationNameDependencies} from 'events/EventPluginRegistry';
|
||||
import {
|
||||
TOP_BLUR,
|
||||
TOP_CANCEL,
|
||||
TOP_CLOSE,
|
||||
TOP_FOCUS,
|
||||
TOP_SCROLL,
|
||||
} from './DOMTopLevelEventTypes';
|
||||
import {
|
||||
setEnabled,
|
||||
isEnabled,
|
||||
|
@ -13,7 +22,6 @@ import {
|
|||
trapCapturedEvent,
|
||||
} from './ReactDOMEventListener';
|
||||
import isEventSupported from './isEventSupported';
|
||||
import {topLevelTypes} from './BrowserEventConstants';
|
||||
|
||||
/**
|
||||
* Summary of `ReactBrowserEventEmitter` event handling:
|
||||
|
@ -79,7 +87,7 @@ let reactTopListenersCounter = 0;
|
|||
*/
|
||||
const topListenersIDKey = '_reactListenersID' + ('' + Math.random()).slice(2);
|
||||
|
||||
function getListeningForDocument(mountAt) {
|
||||
function getListeningForDocument(mountAt: any) {
|
||||
// In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty`
|
||||
// directly.
|
||||
if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) {
|
||||
|
@ -108,37 +116,39 @@ function getListeningForDocument(mountAt) {
|
|||
* they bubble to document.
|
||||
*
|
||||
* @param {string} registrationName Name of listener (e.g. `onClick`).
|
||||
* @param {object} contentDocumentHandle Document which owns the container
|
||||
* @param {object} mountAt Container where to mount the listener
|
||||
*/
|
||||
export function listenTo(registrationName, contentDocumentHandle) {
|
||||
const mountAt = contentDocumentHandle;
|
||||
export function listenTo(
|
||||
registrationName: string,
|
||||
mountAt: Document | Element,
|
||||
) {
|
||||
const isListening = getListeningForDocument(mountAt);
|
||||
const dependencies = registrationNameDependencies[registrationName];
|
||||
|
||||
for (let i = 0; i < dependencies.length; i++) {
|
||||
const dependency = dependencies[i];
|
||||
if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) {
|
||||
if (dependency === 'topScroll') {
|
||||
trapCapturedEvent('topScroll', 'scroll', mountAt);
|
||||
} else if (dependency === 'topFocus' || dependency === 'topBlur') {
|
||||
trapCapturedEvent('topFocus', 'focus', mountAt);
|
||||
trapCapturedEvent('topBlur', 'blur', mountAt);
|
||||
if (dependency === TOP_SCROLL) {
|
||||
trapCapturedEvent(TOP_SCROLL, mountAt);
|
||||
} else if (dependency === TOP_FOCUS || dependency === TOP_BLUR) {
|
||||
trapCapturedEvent(TOP_FOCUS, mountAt);
|
||||
trapCapturedEvent(TOP_BLUR, mountAt);
|
||||
|
||||
// to make sure blur and focus event listeners are only attached once
|
||||
isListening.topBlur = true;
|
||||
isListening.topFocus = true;
|
||||
} else if (dependency === 'topCancel') {
|
||||
isListening[TOP_BLUR] = true;
|
||||
isListening[TOP_FOCUS] = true;
|
||||
} else if (dependency === TOP_CANCEL) {
|
||||
if (isEventSupported('cancel', true)) {
|
||||
trapCapturedEvent('topCancel', 'cancel', mountAt);
|
||||
trapCapturedEvent(TOP_CANCEL, mountAt);
|
||||
}
|
||||
isListening.topCancel = true;
|
||||
} else if (dependency === 'topClose') {
|
||||
isListening[TOP_CANCEL] = true;
|
||||
} else if (dependency === TOP_CLOSE) {
|
||||
if (isEventSupported('close', true)) {
|
||||
trapCapturedEvent('topClose', 'close', mountAt);
|
||||
trapCapturedEvent(TOP_CLOSE, mountAt);
|
||||
}
|
||||
isListening.topClose = true;
|
||||
} else if (topLevelTypes.hasOwnProperty(dependency)) {
|
||||
trapBubbledEvent(dependency, topLevelTypes[dependency], mountAt);
|
||||
isListening[TOP_CLOSE] = true;
|
||||
} else {
|
||||
trapBubbledEvent(dependency, mountAt);
|
||||
}
|
||||
|
||||
isListening[dependency] = true;
|
||||
|
@ -146,7 +156,10 @@ export function listenTo(registrationName, contentDocumentHandle) {
|
|||
}
|
||||
}
|
||||
|
||||
export function isListeningToAllDependencies(registrationName, mountAt) {
|
||||
export function isListeningToAllDependencies(
|
||||
registrationName: string,
|
||||
mountAt: Document | Element,
|
||||
) {
|
||||
const isListening = getListeningForDocument(mountAt);
|
||||
const dependencies = registrationNameDependencies[registrationName];
|
||||
for (let i = 0; i < dependencies.length; i++) {
|
||||
|
|
|
@ -3,17 +3,23 @@
|
|||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import {batchedUpdates, interactiveUpdates} from 'events/ReactGenericBatching';
|
||||
import {runExtractedEventsInBatch} from 'events/EventPluginHub';
|
||||
import {isFiberMounted} from 'react-reconciler/reflection';
|
||||
import {HostRoot} from 'shared/ReactTypeOfWork';
|
||||
import type {AnyNativeEvent} from 'events/PluginModuleType';
|
||||
import type {TopLevelType} from 'events/TopLevelEventTypes';
|
||||
import type {Fiber} from 'react-reconciler/src/ReactFiber';
|
||||
|
||||
import {addEventBubbleListener, addEventCaptureListener} from './EventListener';
|
||||
import getEventTarget from './getEventTarget';
|
||||
import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
|
||||
import SimpleEventPlugin from './SimpleEventPlugin';
|
||||
import {getRawEventName} from './DOMTopLevelEventTypes';
|
||||
|
||||
const {isInteractiveTopLevelEventType} = SimpleEventPlugin;
|
||||
|
||||
|
@ -40,7 +46,16 @@ function findRootContainerNode(inst) {
|
|||
}
|
||||
|
||||
// Used to store ancestor hierarchy in top level callback
|
||||
function getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst) {
|
||||
function getTopLevelCallbackBookKeeping(
|
||||
topLevelType,
|
||||
nativeEvent,
|
||||
targetInst,
|
||||
): {
|
||||
topLevelType: ?TopLevelType,
|
||||
nativeEvent: ?AnyNativeEvent,
|
||||
targetInst: Fiber,
|
||||
ancestors: Array<Fiber>,
|
||||
} {
|
||||
if (callbackBookkeepingPool.length) {
|
||||
const instance = callbackBookkeepingPool.pop();
|
||||
instance.topLevelType = topLevelType;
|
||||
|
@ -101,7 +116,7 @@ function handleTopLevel(bookKeeping) {
|
|||
// TODO: can we stop exporting these?
|
||||
export let _enabled = true;
|
||||
|
||||
export function setEnabled(enabled) {
|
||||
export function setEnabled(enabled: ?boolean) {
|
||||
_enabled = !!enabled;
|
||||
}
|
||||
|
||||
|
@ -112,14 +127,16 @@ export function isEnabled() {
|
|||
/**
|
||||
* Traps top-level events by using event bubbling.
|
||||
*
|
||||
* @param {string} topLevelType Record from `BrowserEventConstants`.
|
||||
* @param {string} handlerBaseName Event name (e.g. "click").
|
||||
* @param {number} topLevelType Number from `TopLevelEventTypes`.
|
||||
* @param {object} element Element on which to attach listener.
|
||||
* @return {?object} An object with a remove function which will forcefully
|
||||
* remove the listener.
|
||||
* @internal
|
||||
*/
|
||||
export function trapBubbledEvent(topLevelType, handlerBaseName, element) {
|
||||
export function trapBubbledEvent(
|
||||
topLevelType: TopLevelType,
|
||||
element: Document | Element,
|
||||
) {
|
||||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
|
@ -129,7 +146,7 @@ export function trapBubbledEvent(topLevelType, handlerBaseName, element) {
|
|||
|
||||
addEventBubbleListener(
|
||||
element,
|
||||
handlerBaseName,
|
||||
getRawEventName(topLevelType),
|
||||
// Check if interactive and wrap in interactiveUpdates
|
||||
dispatch.bind(null, topLevelType),
|
||||
);
|
||||
|
@ -138,14 +155,16 @@ export function trapBubbledEvent(topLevelType, handlerBaseName, element) {
|
|||
/**
|
||||
* Traps a top-level event by using event capturing.
|
||||
*
|
||||
* @param {string} topLevelType Record from `BrowserEventConstants`.
|
||||
* @param {string} handlerBaseName Event name (e.g. "click").
|
||||
* @param {number} topLevelType Number from `TopLevelEventTypes`.
|
||||
* @param {object} element Element on which to attach listener.
|
||||
* @return {?object} An object with a remove function which will forcefully
|
||||
* remove the listener.
|
||||
* @internal
|
||||
*/
|
||||
export function trapCapturedEvent(topLevelType, handlerBaseName, element) {
|
||||
export function trapCapturedEvent(
|
||||
topLevelType: TopLevelType,
|
||||
element: Document | Element,
|
||||
) {
|
||||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
|
@ -155,7 +174,7 @@ export function trapCapturedEvent(topLevelType, handlerBaseName, element) {
|
|||
|
||||
addEventCaptureListener(
|
||||
element,
|
||||
handlerBaseName,
|
||||
getRawEventName(topLevelType),
|
||||
// Check if interactive and wrap in interactiveUpdates
|
||||
dispatch.bind(null, topLevelType),
|
||||
);
|
||||
|
@ -165,7 +184,10 @@ function dispatchInteractiveEvent(topLevelType, nativeEvent) {
|
|||
interactiveUpdates(dispatchEvent, topLevelType, nativeEvent);
|
||||
}
|
||||
|
||||
export function dispatchEvent(topLevelType, nativeEvent) {
|
||||
export function dispatchEvent(
|
||||
topLevelType: TopLevelType,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
) {
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,16 @@ import isTextInputElement from 'shared/isTextInputElement';
|
|||
import getActiveElement from 'fbjs/lib/getActiveElement';
|
||||
import shallowEqual from 'fbjs/lib/shallowEqual';
|
||||
|
||||
import {
|
||||
TOP_BLUR,
|
||||
TOP_CONTEXT_MENU,
|
||||
TOP_FOCUS,
|
||||
TOP_KEY_DOWN,
|
||||
TOP_KEY_UP,
|
||||
TOP_MOUSE_DOWN,
|
||||
TOP_MOUSE_UP,
|
||||
TOP_SELECTION_CHANGE,
|
||||
} from './DOMTopLevelEventTypes';
|
||||
import {isListeningToAllDependencies} from './ReactBrowserEventEmitter';
|
||||
import {getNodeFromInstance} from '../client/ReactDOMComponentTree';
|
||||
import * as ReactInputSelection from '../client/ReactInputSelection';
|
||||
|
@ -29,14 +39,14 @@ const eventTypes = {
|
|||
captured: 'onSelectCapture',
|
||||
},
|
||||
dependencies: [
|
||||
'topBlur',
|
||||
'topContextMenu',
|
||||
'topFocus',
|
||||
'topKeyDown',
|
||||
'topKeyUp',
|
||||
'topMouseDown',
|
||||
'topMouseUp',
|
||||
'topSelectionChange',
|
||||
TOP_BLUR,
|
||||
TOP_CONTEXT_MENU,
|
||||
TOP_FOCUS,
|
||||
TOP_KEY_DOWN,
|
||||
TOP_KEY_UP,
|
||||
TOP_MOUSE_DOWN,
|
||||
TOP_MOUSE_UP,
|
||||
TOP_SELECTION_CHANGE,
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -156,7 +166,7 @@ const SelectEventPlugin = {
|
|||
|
||||
switch (topLevelType) {
|
||||
// Track the input node that has focus.
|
||||
case 'topFocus':
|
||||
case TOP_FOCUS:
|
||||
if (
|
||||
isTextInputElement(targetNode) ||
|
||||
targetNode.contentEditable === 'true'
|
||||
|
@ -166,18 +176,18 @@ const SelectEventPlugin = {
|
|||
lastSelection = null;
|
||||
}
|
||||
break;
|
||||
case 'topBlur':
|
||||
case TOP_BLUR:
|
||||
activeElement = null;
|
||||
activeElementInst = null;
|
||||
lastSelection = null;
|
||||
break;
|
||||
// Don't fire the event while the user is dragging. This matches the
|
||||
// semantics of the native select event.
|
||||
case 'topMouseDown':
|
||||
case TOP_MOUSE_DOWN:
|
||||
mouseDown = true;
|
||||
break;
|
||||
case 'topContextMenu':
|
||||
case 'topMouseUp':
|
||||
case TOP_CONTEXT_MENU:
|
||||
case TOP_MOUSE_UP:
|
||||
mouseDown = false;
|
||||
return constructSelectEvent(nativeEvent, nativeEventTarget);
|
||||
// Chrome and IE fire non-standard event when selection is changed (and
|
||||
|
@ -189,13 +199,13 @@ const SelectEventPlugin = {
|
|||
// keyup, but we check on keydown as well in the case of holding down a
|
||||
// key, when multiple keydown events are fired but only one keyup is.
|
||||
// This is also our approach for IE handling, for the reason above.
|
||||
case 'topSelectionChange':
|
||||
case TOP_SELECTION_CHANGE:
|
||||
if (skipSelectionChangeEvent) {
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
case 'topKeyDown':
|
||||
case 'topKeyUp':
|
||||
case TOP_KEY_DOWN:
|
||||
case TOP_KEY_UP:
|
||||
return constructSelectEvent(nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {TopLevelTypes} from './BrowserEventConstants';
|
||||
import type {TopLevelType} from 'events/TopLevelEventTypes';
|
||||
import type {
|
||||
DispatchConfig,
|
||||
ReactSyntheticEvent,
|
||||
|
@ -17,6 +17,8 @@ import type {EventTypes, PluginModule} from 'events/PluginModuleType';
|
|||
|
||||
import {accumulateTwoPhaseDispatches} from 'events/EventPropagators';
|
||||
import SyntheticEvent from 'events/SyntheticEvent';
|
||||
|
||||
import * as DOMTopLevelEventTypes from './DOMTopLevelEventTypes';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
import SyntheticAnimationEvent from './SyntheticAnimationEvent';
|
||||
|
@ -41,93 +43,96 @@ import getEventCharCode from './getEventCharCode';
|
|||
* bubbled: 'onAbort',
|
||||
* captured: 'onAbortCapture',
|
||||
* },
|
||||
* dependencies: ['topAbort'],
|
||||
* dependencies: [TOP_ABORT],
|
||||
* },
|
||||
* ...
|
||||
* };
|
||||
* topLevelEventsToDispatchConfig = {
|
||||
* 'topAbort': { sameConfig }
|
||||
* };
|
||||
* topLevelEventsToDispatchConfig = new Map([
|
||||
* [TOP_ABORT, { sameConfig }],
|
||||
* ]);
|
||||
*/
|
||||
const interactiveEventTypeNames: Array<string> = [
|
||||
'blur',
|
||||
'cancel',
|
||||
'click',
|
||||
'close',
|
||||
'contextMenu',
|
||||
'copy',
|
||||
'cut',
|
||||
'doubleClick',
|
||||
'dragEnd',
|
||||
'dragStart',
|
||||
'drop',
|
||||
'focus',
|
||||
'input',
|
||||
'invalid',
|
||||
'keyDown',
|
||||
'keyPress',
|
||||
'keyUp',
|
||||
'mouseDown',
|
||||
'mouseUp',
|
||||
'paste',
|
||||
'pause',
|
||||
'play',
|
||||
'rateChange',
|
||||
'reset',
|
||||
'seeked',
|
||||
'submit',
|
||||
'touchCancel',
|
||||
'touchEnd',
|
||||
'touchStart',
|
||||
'volumeChange',
|
||||
type EventTuple = [TopLevelType, string];
|
||||
const interactiveEventTypeNames: Array<EventTuple> = [
|
||||
[DOMTopLevelEventTypes.TOP_BLUR, 'blur'],
|
||||
[DOMTopLevelEventTypes.TOP_CANCEL, 'cancel'],
|
||||
[DOMTopLevelEventTypes.TOP_CLICK, 'click'],
|
||||
[DOMTopLevelEventTypes.TOP_CLOSE, 'close'],
|
||||
[DOMTopLevelEventTypes.TOP_CONTEXT_MENU, 'contextMenu'],
|
||||
[DOMTopLevelEventTypes.TOP_COPY, 'copy'],
|
||||
[DOMTopLevelEventTypes.TOP_CUT, 'cut'],
|
||||
[DOMTopLevelEventTypes.TOP_DOUBLE_CLICK, 'doubleClick'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_END, 'dragEnd'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_START, 'dragStart'],
|
||||
[DOMTopLevelEventTypes.TOP_DROP, 'drop'],
|
||||
[DOMTopLevelEventTypes.TOP_FOCUS, 'focus'],
|
||||
[DOMTopLevelEventTypes.TOP_INPUT, 'input'],
|
||||
[DOMTopLevelEventTypes.TOP_INVALID, 'invalid'],
|
||||
[DOMTopLevelEventTypes.TOP_KEY_DOWN, 'keyDown'],
|
||||
[DOMTopLevelEventTypes.TOP_KEY_PRESS, 'keyPress'],
|
||||
[DOMTopLevelEventTypes.TOP_KEY_UP, 'keyUp'],
|
||||
[DOMTopLevelEventTypes.TOP_MOUSE_DOWN, 'mouseDown'],
|
||||
[DOMTopLevelEventTypes.TOP_MOUSE_UP, 'mouseUp'],
|
||||
[DOMTopLevelEventTypes.TOP_PASTE, 'paste'],
|
||||
[DOMTopLevelEventTypes.TOP_PAUSE, 'pause'],
|
||||
[DOMTopLevelEventTypes.TOP_PLAY, 'play'],
|
||||
[DOMTopLevelEventTypes.TOP_RATE_CHANGE, 'rateChange'],
|
||||
[DOMTopLevelEventTypes.TOP_RESET, 'reset'],
|
||||
[DOMTopLevelEventTypes.TOP_SEEKED, 'seeked'],
|
||||
[DOMTopLevelEventTypes.TOP_SUBMIT, 'submit'],
|
||||
[DOMTopLevelEventTypes.TOP_TOUCH_CANCEL, 'touchCancel'],
|
||||
[DOMTopLevelEventTypes.TOP_TOUCH_END, 'touchEnd'],
|
||||
[DOMTopLevelEventTypes.TOP_TOUCH_START, 'touchStart'],
|
||||
[DOMTopLevelEventTypes.TOP_VOLUME_CHANGE, 'volumeChange'],
|
||||
];
|
||||
const nonInteractiveEventTypeNames: Array<string> = [
|
||||
'abort',
|
||||
'animationEnd',
|
||||
'animationIteration',
|
||||
'animationStart',
|
||||
'canPlay',
|
||||
'canPlayThrough',
|
||||
'drag',
|
||||
'dragEnter',
|
||||
'dragExit',
|
||||
'dragLeave',
|
||||
'dragOver',
|
||||
'durationChange',
|
||||
'emptied',
|
||||
'encrypted',
|
||||
'ended',
|
||||
'error',
|
||||
'load',
|
||||
'loadedData',
|
||||
'loadedMetadata',
|
||||
'loadStart',
|
||||
'mouseMove',
|
||||
'mouseOut',
|
||||
'mouseOver',
|
||||
'playing',
|
||||
'progress',
|
||||
'scroll',
|
||||
'seeking',
|
||||
'stalled',
|
||||
'suspend',
|
||||
'timeUpdate',
|
||||
'toggle',
|
||||
'touchMove',
|
||||
'transitionEnd',
|
||||
'waiting',
|
||||
'wheel',
|
||||
const nonInteractiveEventTypeNames: Array<EventTuple> = [
|
||||
[DOMTopLevelEventTypes.TOP_ABORT, 'abort'],
|
||||
[DOMTopLevelEventTypes.TOP_ANIMATION_END, 'animationEnd'],
|
||||
[DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION, 'animationIteration'],
|
||||
[DOMTopLevelEventTypes.TOP_ANIMATION_START, 'animationStart'],
|
||||
[DOMTopLevelEventTypes.TOP_CAN_PLAY, 'canPlay'],
|
||||
[DOMTopLevelEventTypes.TOP_CAN_PLAY_THROUGH, 'canPlayThrough'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG, 'drag'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_ENTER, 'dragEnter'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_EXIT, 'dragExit'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_LEAVE, 'dragLeave'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_OVER, 'dragOver'],
|
||||
[DOMTopLevelEventTypes.TOP_DURATION_CHANGE, 'durationChange'],
|
||||
[DOMTopLevelEventTypes.TOP_EMPTIED, 'emptied'],
|
||||
[DOMTopLevelEventTypes.TOP_ENCRYPTED, 'encrypted'],
|
||||
[DOMTopLevelEventTypes.TOP_ENDED, 'ended'],
|
||||
[DOMTopLevelEventTypes.TOP_ERROR, 'error'],
|
||||
[DOMTopLevelEventTypes.TOP_LOAD, 'load'],
|
||||
[DOMTopLevelEventTypes.TOP_LOADED_DATA, 'loadedData'],
|
||||
[DOMTopLevelEventTypes.TOP_LOADED_METADATA, 'loadedMetadata'],
|
||||
[DOMTopLevelEventTypes.TOP_LOAD_START, 'loadStart'],
|
||||
[DOMTopLevelEventTypes.TOP_MOUSE_MOVE, 'mouseMove'],
|
||||
[DOMTopLevelEventTypes.TOP_MOUSE_OUT, 'mouseOut'],
|
||||
[DOMTopLevelEventTypes.TOP_MOUSE_OVER, 'mouseOver'],
|
||||
[DOMTopLevelEventTypes.TOP_PLAYING, 'playing'],
|
||||
[DOMTopLevelEventTypes.TOP_PROGRESS, 'progress'],
|
||||
[DOMTopLevelEventTypes.TOP_SCROLL, 'scroll'],
|
||||
[DOMTopLevelEventTypes.TOP_SEEKING, 'seeking'],
|
||||
[DOMTopLevelEventTypes.TOP_STALLED, 'stalled'],
|
||||
[DOMTopLevelEventTypes.TOP_SUSPEND, 'suspend'],
|
||||
[DOMTopLevelEventTypes.TOP_TIME_UPDATE, 'timeUpdate'],
|
||||
[DOMTopLevelEventTypes.TOP_TOGGLE, 'toggle'],
|
||||
[DOMTopLevelEventTypes.TOP_TOUCH_MOVE, 'touchMove'],
|
||||
[DOMTopLevelEventTypes.TOP_TRANSITION_END, 'transitionEnd'],
|
||||
[DOMTopLevelEventTypes.TOP_WAITING, 'waiting'],
|
||||
[DOMTopLevelEventTypes.TOP_WHEEL, 'wheel'],
|
||||
];
|
||||
|
||||
const eventTypes: EventTypes = {};
|
||||
const topLevelEventsToDispatchConfig: {
|
||||
[key: TopLevelTypes]: DispatchConfig,
|
||||
[key: TopLevelType]: DispatchConfig,
|
||||
} = {};
|
||||
|
||||
function addEventTypeNameToConfig(event: string, isInteractive: boolean) {
|
||||
function addEventTypeNameToConfig(
|
||||
[topEvent, event]: EventTuple,
|
||||
isInteractive: boolean,
|
||||
) {
|
||||
const capitalizedEvent = event[0].toUpperCase() + event.slice(1);
|
||||
const onEvent = 'on' + capitalizedEvent;
|
||||
const topEvent = 'top' + capitalizedEvent;
|
||||
|
||||
const type = {
|
||||
phasedRegistrationNames: {
|
||||
|
@ -141,58 +146,60 @@ function addEventTypeNameToConfig(event: string, isInteractive: boolean) {
|
|||
topLevelEventsToDispatchConfig[topEvent] = type;
|
||||
}
|
||||
|
||||
interactiveEventTypeNames.forEach(eventTypeName => {
|
||||
addEventTypeNameToConfig(eventTypeName, true);
|
||||
interactiveEventTypeNames.forEach(eventTuple => {
|
||||
addEventTypeNameToConfig(eventTuple, true);
|
||||
});
|
||||
nonInteractiveEventTypeNames.forEach(eventTypeName => {
|
||||
addEventTypeNameToConfig(eventTypeName, false);
|
||||
nonInteractiveEventTypeNames.forEach(eventTuple => {
|
||||
addEventTypeNameToConfig(eventTuple, false);
|
||||
});
|
||||
|
||||
// Only used in DEV for exhaustiveness validation.
|
||||
const knownHTMLTopLevelTypes = [
|
||||
'topAbort',
|
||||
'topCancel',
|
||||
'topCanPlay',
|
||||
'topCanPlayThrough',
|
||||
'topClose',
|
||||
'topDurationChange',
|
||||
'topEmptied',
|
||||
'topEncrypted',
|
||||
'topEnded',
|
||||
'topError',
|
||||
'topInput',
|
||||
'topInvalid',
|
||||
'topLoad',
|
||||
'topLoadedData',
|
||||
'topLoadedMetadata',
|
||||
'topLoadStart',
|
||||
'topPause',
|
||||
'topPlay',
|
||||
'topPlaying',
|
||||
'topProgress',
|
||||
'topRateChange',
|
||||
'topReset',
|
||||
'topSeeked',
|
||||
'topSeeking',
|
||||
'topStalled',
|
||||
'topSubmit',
|
||||
'topSuspend',
|
||||
'topTimeUpdate',
|
||||
'topToggle',
|
||||
'topVolumeChange',
|
||||
'topWaiting',
|
||||
const knownHTMLTopLevelTypes: Array<TopLevelType> = [
|
||||
DOMTopLevelEventTypes.TOP_ABORT,
|
||||
DOMTopLevelEventTypes.TOP_CANCEL,
|
||||
DOMTopLevelEventTypes.TOP_CAN_PLAY,
|
||||
DOMTopLevelEventTypes.TOP_CAN_PLAY_THROUGH,
|
||||
DOMTopLevelEventTypes.TOP_CLOSE,
|
||||
DOMTopLevelEventTypes.TOP_DURATION_CHANGE,
|
||||
DOMTopLevelEventTypes.TOP_EMPTIED,
|
||||
DOMTopLevelEventTypes.TOP_ENCRYPTED,
|
||||
DOMTopLevelEventTypes.TOP_ENDED,
|
||||
DOMTopLevelEventTypes.TOP_ERROR,
|
||||
DOMTopLevelEventTypes.TOP_INPUT,
|
||||
DOMTopLevelEventTypes.TOP_INVALID,
|
||||
DOMTopLevelEventTypes.TOP_LOAD,
|
||||
DOMTopLevelEventTypes.TOP_LOADED_DATA,
|
||||
DOMTopLevelEventTypes.TOP_LOADED_METADATA,
|
||||
DOMTopLevelEventTypes.TOP_LOAD_START,
|
||||
DOMTopLevelEventTypes.TOP_PAUSE,
|
||||
DOMTopLevelEventTypes.TOP_PLAY,
|
||||
DOMTopLevelEventTypes.TOP_PLAYING,
|
||||
DOMTopLevelEventTypes.TOP_PROGRESS,
|
||||
DOMTopLevelEventTypes.TOP_RATE_CHANGE,
|
||||
DOMTopLevelEventTypes.TOP_RESET,
|
||||
DOMTopLevelEventTypes.TOP_SEEKED,
|
||||
DOMTopLevelEventTypes.TOP_SEEKING,
|
||||
DOMTopLevelEventTypes.TOP_STALLED,
|
||||
DOMTopLevelEventTypes.TOP_SUBMIT,
|
||||
DOMTopLevelEventTypes.TOP_SUSPEND,
|
||||
DOMTopLevelEventTypes.TOP_TIME_UPDATE,
|
||||
DOMTopLevelEventTypes.TOP_TOGGLE,
|
||||
DOMTopLevelEventTypes.TOP_VOLUME_CHANGE,
|
||||
DOMTopLevelEventTypes.TOP_WAITING,
|
||||
];
|
||||
|
||||
const SimpleEventPlugin: PluginModule<MouseEvent> = {
|
||||
const SimpleEventPlugin: PluginModule<MouseEvent> & {
|
||||
isInteractiveTopLevelEventType: (topLevelType: TopLevelType) => boolean,
|
||||
} = {
|
||||
eventTypes: eventTypes,
|
||||
|
||||
isInteractiveTopLevelEventType(topLevelType: TopLevelTypes): boolean {
|
||||
isInteractiveTopLevelEventType(topLevelType: TopLevelType): boolean {
|
||||
const config = topLevelEventsToDispatchConfig[topLevelType];
|
||||
return config !== undefined && config.isInteractive === true;
|
||||
},
|
||||
|
||||
extractEvents: function(
|
||||
topLevelType: TopLevelTypes,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: Fiber,
|
||||
nativeEvent: MouseEvent,
|
||||
nativeEventTarget: EventTarget,
|
||||
|
@ -203,7 +210,7 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
|
|||
}
|
||||
let EventConstructor;
|
||||
switch (topLevelType) {
|
||||
case 'topKeyPress':
|
||||
case DOMTopLevelEventTypes.TOP_KEY_PRESS:
|
||||
// Firefox creates a keypress event for function keys too. This removes
|
||||
// the unwanted keypress events. Enter is however both printable and
|
||||
// non-printable. One would expect Tab to be as well (but it isn't).
|
||||
|
@ -211,65 +218,65 @@ const SimpleEventPlugin: PluginModule<MouseEvent> = {
|
|||
return null;
|
||||
}
|
||||
/* falls through */
|
||||
case 'topKeyDown':
|
||||
case 'topKeyUp':
|
||||
case DOMTopLevelEventTypes.TOP_KEY_DOWN:
|
||||
case DOMTopLevelEventTypes.TOP_KEY_UP:
|
||||
EventConstructor = SyntheticKeyboardEvent;
|
||||
break;
|
||||
case 'topBlur':
|
||||
case 'topFocus':
|
||||
case DOMTopLevelEventTypes.TOP_BLUR:
|
||||
case DOMTopLevelEventTypes.TOP_FOCUS:
|
||||
EventConstructor = SyntheticFocusEvent;
|
||||
break;
|
||||
case 'topClick':
|
||||
case DOMTopLevelEventTypes.TOP_CLICK:
|
||||
// Firefox creates a click event on right mouse clicks. This removes the
|
||||
// unwanted click events.
|
||||
if (nativeEvent.button === 2) {
|
||||
return null;
|
||||
}
|
||||
/* falls through */
|
||||
case 'topDoubleClick':
|
||||
case 'topMouseDown':
|
||||
case 'topMouseMove':
|
||||
case 'topMouseUp':
|
||||
case DOMTopLevelEventTypes.TOP_DOUBLE_CLICK:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_DOWN:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_MOVE:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_UP:
|
||||
// TODO: Disabled elements should not respond to mouse events
|
||||
/* falls through */
|
||||
case 'topMouseOut':
|
||||
case 'topMouseOver':
|
||||
case 'topContextMenu':
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_OUT:
|
||||
case DOMTopLevelEventTypes.TOP_MOUSE_OVER:
|
||||
case DOMTopLevelEventTypes.TOP_CONTEXT_MENU:
|
||||
EventConstructor = SyntheticMouseEvent;
|
||||
break;
|
||||
case 'topDrag':
|
||||
case 'topDragEnd':
|
||||
case 'topDragEnter':
|
||||
case 'topDragExit':
|
||||
case 'topDragLeave':
|
||||
case 'topDragOver':
|
||||
case 'topDragStart':
|
||||
case 'topDrop':
|
||||
case DOMTopLevelEventTypes.TOP_DRAG:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_END:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_ENTER:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_EXIT:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_LEAVE:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_OVER:
|
||||
case DOMTopLevelEventTypes.TOP_DRAG_START:
|
||||
case DOMTopLevelEventTypes.TOP_DROP:
|
||||
EventConstructor = SyntheticDragEvent;
|
||||
break;
|
||||
case 'topTouchCancel':
|
||||
case 'topTouchEnd':
|
||||
case 'topTouchMove':
|
||||
case 'topTouchStart':
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_CANCEL:
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_END:
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_MOVE:
|
||||
case DOMTopLevelEventTypes.TOP_TOUCH_START:
|
||||
EventConstructor = SyntheticTouchEvent;
|
||||
break;
|
||||
case 'topAnimationEnd':
|
||||
case 'topAnimationIteration':
|
||||
case 'topAnimationStart':
|
||||
case DOMTopLevelEventTypes.TOP_ANIMATION_END:
|
||||
case DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION:
|
||||
case DOMTopLevelEventTypes.TOP_ANIMATION_START:
|
||||
EventConstructor = SyntheticAnimationEvent;
|
||||
break;
|
||||
case 'topTransitionEnd':
|
||||
case DOMTopLevelEventTypes.TOP_TRANSITION_END:
|
||||
EventConstructor = SyntheticTransitionEvent;
|
||||
break;
|
||||
case 'topScroll':
|
||||
case DOMTopLevelEventTypes.TOP_SCROLL:
|
||||
EventConstructor = SyntheticUIEvent;
|
||||
break;
|
||||
case 'topWheel':
|
||||
case DOMTopLevelEventTypes.TOP_WHEEL:
|
||||
EventConstructor = SyntheticWheelEvent;
|
||||
break;
|
||||
case 'topCopy':
|
||||
case 'topCut':
|
||||
case 'topPaste':
|
||||
case DOMTopLevelEventTypes.TOP_COPY:
|
||||
case DOMTopLevelEventTypes.TOP_CUT:
|
||||
case DOMTopLevelEventTypes.TOP_PASTE:
|
||||
EventConstructor = SyntheticClipboardEvent;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -7,12 +7,33 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import {isStartish, isEndish} from 'events/EventPluginUtils';
|
||||
import {accumulateTwoPhaseDispatches} from 'events/EventPropagators';
|
||||
import TouchEventUtils from 'fbjs/lib/TouchEventUtils';
|
||||
import type {TopLevelType} from 'events/TopLevelEventTypes';
|
||||
|
||||
import {
|
||||
TOP_MOUSE_DOWN,
|
||||
TOP_MOUSE_MOVE,
|
||||
TOP_MOUSE_UP,
|
||||
TOP_TOUCH_CANCEL,
|
||||
TOP_TOUCH_END,
|
||||
TOP_TOUCH_MOVE,
|
||||
TOP_TOUCH_START,
|
||||
} from './DOMTopLevelEventTypes';
|
||||
import SyntheticUIEvent from './SyntheticUIEvent';
|
||||
|
||||
function isStartish(topLevelType) {
|
||||
return topLevelType === TOP_MOUSE_DOWN || topLevelType === TOP_TOUCH_START;
|
||||
}
|
||||
|
||||
function isEndish(topLevelType) {
|
||||
return (
|
||||
topLevelType === TOP_MOUSE_UP ||
|
||||
topLevelType === TOP_TOUCH_END ||
|
||||
topLevelType === TOP_TOUCH_CANCEL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* We are extending the Flow 'Touch' declaration to enable using bracket
|
||||
* notation to access properties.
|
||||
|
@ -75,13 +96,13 @@ function getDistance(coords: CoordinatesType, nativeEvent: _Touch): number {
|
|||
}
|
||||
|
||||
const touchEvents = [
|
||||
'topTouchStart',
|
||||
'topTouchCancel',
|
||||
'topTouchEnd',
|
||||
'topTouchMove',
|
||||
TOP_TOUCH_START,
|
||||
TOP_TOUCH_CANCEL,
|
||||
TOP_TOUCH_END,
|
||||
TOP_TOUCH_MOVE,
|
||||
];
|
||||
|
||||
const dependencies = ['topMouseDown', 'topMouseMove', 'topMouseUp'].concat(
|
||||
const dependencies = [TOP_MOUSE_DOWN, TOP_MOUSE_MOVE, TOP_MOUSE_UP].concat(
|
||||
touchEvents,
|
||||
);
|
||||
|
||||
|
@ -105,7 +126,7 @@ const TapEventPlugin = {
|
|||
eventTypes: eventTypes,
|
||||
|
||||
extractEvents: function(
|
||||
topLevelType: mixed,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: mixed,
|
||||
nativeEvent: _Touch,
|
||||
nativeEventTarget: EventTarget,
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
import SyntheticEvent from 'events/SyntheticEvent';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
import {topLevelTypes, mediaEventTypes} from '../events/BrowserEventConstants';
|
||||
import * as DOMTopLevelEventTypes from '../events/DOMTopLevelEventTypes';
|
||||
|
||||
const {findDOMNode} = ReactDOM;
|
||||
const {
|
||||
|
@ -36,6 +36,33 @@ function Event(suffix) {}
|
|||
* @class ReactTestUtils
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simulates a top level event being dispatched from a raw event that occurred
|
||||
* on an `Element` node.
|
||||
* @param {number} topLevelType A number from `TopLevelEventTypes`
|
||||
* @param {!Element} node The dom to simulate an event occurring on.
|
||||
* @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
|
||||
*/
|
||||
function simulateNativeEventOnNode(topLevelType, node, fakeNativeEvent) {
|
||||
fakeNativeEvent.target = node;
|
||||
ReactDOMEventListener.dispatchEvent(topLevelType, fakeNativeEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates a top level event being dispatched from a raw event that occurred
|
||||
* on the `ReactDOMComponent` `comp`.
|
||||
* @param {Object} topLevelType A type from `BrowserEventConstants.topLevelTypes`.
|
||||
* @param {!ReactDOMComponent} comp
|
||||
* @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
|
||||
*/
|
||||
function simulateNativeEventOnDOMComponent(
|
||||
topLevelType,
|
||||
comp,
|
||||
fakeNativeEvent,
|
||||
) {
|
||||
simulateNativeEventOnNode(topLevelType, findDOMNode(comp), fakeNativeEvent);
|
||||
}
|
||||
|
||||
function findAllInRenderedFiberTreeInternal(fiber, test) {
|
||||
if (!fiber) {
|
||||
return [];
|
||||
|
@ -291,37 +318,6 @@ const ReactTestUtils = {
|
|||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Simulates a top level event being dispatched from a raw event that occurred
|
||||
* on an `Element` node.
|
||||
* @param {Object} topLevelType A type from `BrowserEventConstants.topLevelTypes`
|
||||
* @param {!Element} node The dom to simulate an event occurring on.
|
||||
* @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
|
||||
*/
|
||||
simulateNativeEventOnNode: function(topLevelType, node, fakeNativeEvent) {
|
||||
fakeNativeEvent.target = node;
|
||||
ReactDOMEventListener.dispatchEvent(topLevelType, fakeNativeEvent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Simulates a top level event being dispatched from a raw event that occurred
|
||||
* on the `ReactDOMComponent` `comp`.
|
||||
* @param {Object} topLevelType A type from `BrowserEventConstants.topLevelTypes`.
|
||||
* @param {!ReactDOMComponent} comp
|
||||
* @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
|
||||
*/
|
||||
simulateNativeEventOnDOMComponent: function(
|
||||
topLevelType,
|
||||
comp,
|
||||
fakeNativeEvent,
|
||||
) {
|
||||
ReactTestUtils.simulateNativeEventOnNode(
|
||||
topLevelType,
|
||||
findDOMNode(comp),
|
||||
fakeNativeEvent,
|
||||
);
|
||||
},
|
||||
|
||||
nativeTouchData: function(x, y) {
|
||||
return {
|
||||
touches: [{pageX: x, pageY: y}],
|
||||
|
@ -436,20 +432,20 @@ buildSimulators();
|
|||
* to dispatch synthetic events.
|
||||
*/
|
||||
|
||||
function makeNativeSimulator(eventType) {
|
||||
function makeNativeSimulator(eventType, topLevelType) {
|
||||
return function(domComponentOrNode, nativeEventData) {
|
||||
const fakeNativeEvent = new Event(eventType);
|
||||
Object.assign(fakeNativeEvent, nativeEventData);
|
||||
if (ReactTestUtils.isDOMComponent(domComponentOrNode)) {
|
||||
ReactTestUtils.simulateNativeEventOnDOMComponent(
|
||||
eventType,
|
||||
simulateNativeEventOnDOMComponent(
|
||||
topLevelType,
|
||||
domComponentOrNode,
|
||||
fakeNativeEvent,
|
||||
);
|
||||
} else if (domComponentOrNode.tagName) {
|
||||
// Will allow on actual dom nodes.
|
||||
ReactTestUtils.simulateNativeEventOnNode(
|
||||
eventType,
|
||||
simulateNativeEventOnNode(
|
||||
topLevelType,
|
||||
domComponentOrNode,
|
||||
fakeNativeEvent,
|
||||
);
|
||||
|
@ -457,23 +453,84 @@ function makeNativeSimulator(eventType) {
|
|||
};
|
||||
}
|
||||
|
||||
const eventKeys = [].concat(
|
||||
Object.keys(topLevelTypes),
|
||||
Object.keys(mediaEventTypes),
|
||||
);
|
||||
|
||||
eventKeys.forEach(function(eventType) {
|
||||
// Event type is stored as 'topClick' - we transform that to 'click'
|
||||
const convenienceName =
|
||||
eventType.indexOf('top') === 0
|
||||
? eventType.charAt(3).toLowerCase() + eventType.substr(4)
|
||||
: eventType;
|
||||
[
|
||||
[DOMTopLevelEventTypes.TOP_ABORT, 'abort'],
|
||||
[DOMTopLevelEventTypes.TOP_ANIMATION_END, 'animationEnd'],
|
||||
[DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION, 'animationIteration'],
|
||||
[DOMTopLevelEventTypes.TOP_ANIMATION_START, 'animationStart'],
|
||||
[DOMTopLevelEventTypes.TOP_BLUR, 'blur'],
|
||||
[DOMTopLevelEventTypes.TOP_CAN_PLAY_THROUGH, 'canPlayThrough'],
|
||||
[DOMTopLevelEventTypes.TOP_CAN_PLAY, 'canPlay'],
|
||||
[DOMTopLevelEventTypes.TOP_CANCEL, 'cancel'],
|
||||
[DOMTopLevelEventTypes.TOP_CHANGE, 'change'],
|
||||
[DOMTopLevelEventTypes.TOP_CLICK, 'click'],
|
||||
[DOMTopLevelEventTypes.TOP_CLOSE, 'close'],
|
||||
[DOMTopLevelEventTypes.TOP_COMPOSITION_END, 'compositionEnd'],
|
||||
[DOMTopLevelEventTypes.TOP_COMPOSITION_START, 'compositionStart'],
|
||||
[DOMTopLevelEventTypes.TOP_COMPOSITION_UPDATE, 'compositionUpdate'],
|
||||
[DOMTopLevelEventTypes.TOP_CONTEXT_MENU, 'contextMenu'],
|
||||
[DOMTopLevelEventTypes.TOP_COPY, 'copy'],
|
||||
[DOMTopLevelEventTypes.TOP_CUT, 'cut'],
|
||||
[DOMTopLevelEventTypes.TOP_DOUBLE_CLICK, 'doubleClick'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_END, 'dragEnd'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_ENTER, 'dragEnter'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_EXIT, 'dragExit'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_LEAVE, 'dragLeave'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_OVER, 'dragOver'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG_START, 'dragStart'],
|
||||
[DOMTopLevelEventTypes.TOP_DRAG, 'drag'],
|
||||
[DOMTopLevelEventTypes.TOP_DROP, 'drop'],
|
||||
[DOMTopLevelEventTypes.TOP_DURATION_CHANGE, 'durationChange'],
|
||||
[DOMTopLevelEventTypes.TOP_EMPTIED, 'emptied'],
|
||||
[DOMTopLevelEventTypes.TOP_ENCRYPTED, 'encrypted'],
|
||||
[DOMTopLevelEventTypes.TOP_ENDED, 'ended'],
|
||||
[DOMTopLevelEventTypes.TOP_ERROR, 'error'],
|
||||
[DOMTopLevelEventTypes.TOP_FOCUS, 'focus'],
|
||||
[DOMTopLevelEventTypes.TOP_INPUT, 'input'],
|
||||
[DOMTopLevelEventTypes.TOP_KEY_DOWN, 'keyDown'],
|
||||
[DOMTopLevelEventTypes.TOP_KEY_PRESS, 'keyPress'],
|
||||
[DOMTopLevelEventTypes.TOP_KEY_UP, 'keyUp'],
|
||||
[DOMTopLevelEventTypes.TOP_LOAD_START, 'loadStart'],
|
||||
[DOMTopLevelEventTypes.TOP_LOAD_START, 'loadStart'],
|
||||
[DOMTopLevelEventTypes.TOP_LOAD, 'load'],
|
||||
[DOMTopLevelEventTypes.TOP_LOADED_DATA, 'loadedData'],
|
||||
[DOMTopLevelEventTypes.TOP_LOADED_METADATA, 'loadedMetadata'],
|
||||
[DOMTopLevelEventTypes.TOP_MOUSE_DOWN, 'mouseDown'],
|
||||
[DOMTopLevelEventTypes.TOP_MOUSE_MOVE, 'mouseMove'],
|
||||
[DOMTopLevelEventTypes.TOP_MOUSE_OUT, 'mouseOut'],
|
||||
[DOMTopLevelEventTypes.TOP_MOUSE_OVER, 'mouseOver'],
|
||||
[DOMTopLevelEventTypes.TOP_MOUSE_UP, 'mouseUp'],
|
||||
[DOMTopLevelEventTypes.TOP_PASTE, 'paste'],
|
||||
[DOMTopLevelEventTypes.TOP_PAUSE, 'pause'],
|
||||
[DOMTopLevelEventTypes.TOP_PLAY, 'play'],
|
||||
[DOMTopLevelEventTypes.TOP_PLAYING, 'playing'],
|
||||
[DOMTopLevelEventTypes.TOP_PROGRESS, 'progress'],
|
||||
[DOMTopLevelEventTypes.TOP_RATE_CHANGE, 'rateChange'],
|
||||
[DOMTopLevelEventTypes.TOP_SCROLL, 'scroll'],
|
||||
[DOMTopLevelEventTypes.TOP_SEEKED, 'seeked'],
|
||||
[DOMTopLevelEventTypes.TOP_SEEKING, 'seeking'],
|
||||
[DOMTopLevelEventTypes.TOP_SELECTION_CHANGE, 'selectionChange'],
|
||||
[DOMTopLevelEventTypes.TOP_STALLED, 'stalled'],
|
||||
[DOMTopLevelEventTypes.TOP_SUSPEND, 'suspend'],
|
||||
[DOMTopLevelEventTypes.TOP_TEXT_INPUT, 'textInput'],
|
||||
[DOMTopLevelEventTypes.TOP_TIME_UPDATE, 'timeUpdate'],
|
||||
[DOMTopLevelEventTypes.TOP_TOGGLE, 'toggle'],
|
||||
[DOMTopLevelEventTypes.TOP_TOUCH_CANCEL, 'touchCancel'],
|
||||
[DOMTopLevelEventTypes.TOP_TOUCH_END, 'touchEnd'],
|
||||
[DOMTopLevelEventTypes.TOP_TOUCH_MOVE, 'touchMove'],
|
||||
[DOMTopLevelEventTypes.TOP_TOUCH_START, 'touchStart'],
|
||||
[DOMTopLevelEventTypes.TOP_TRANSITION_END, 'transitionEnd'],
|
||||
[DOMTopLevelEventTypes.TOP_VOLUME_CHANGE, 'volumeChange'],
|
||||
[DOMTopLevelEventTypes.TOP_WAITING, 'waiting'],
|
||||
[DOMTopLevelEventTypes.TOP_WHEEL, 'wheel'],
|
||||
].forEach(([topLevelType, eventType]) => {
|
||||
/**
|
||||
* @param {!Element|ReactDOMComponent} domComponentOrNode
|
||||
* @param {?Event} nativeEventData Fake native event to use in SyntheticEvent.
|
||||
*/
|
||||
ReactTestUtils.SimulateNative[convenienceName] = makeNativeSimulator(
|
||||
ReactTestUtils.SimulateNative[eventType] = makeNativeSimulator(
|
||||
eventType,
|
||||
topLevelType,
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
accumulateTwoPhaseDispatches,
|
||||
accumulateDirectDispatches,
|
||||
} from 'events/EventPropagators';
|
||||
import type {TopLevelType} from 'events/TopLevelEventTypes';
|
||||
import * as ReactNativeViewConfigRegistry from 'ReactNativeViewConfigRegistry';
|
||||
import SyntheticEvent from 'events/SyntheticEvent';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
@ -29,7 +30,7 @@ const ReactNativeBridgeEventPlugin = {
|
|||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
extractEvents: function(
|
||||
topLevelType: string,
|
||||
topLevelType: TopLevelType,
|
||||
targetInst: Object,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
nativeEventTarget: Object,
|
||||
|
|
|
@ -15,6 +15,7 @@ import warning from 'fbjs/lib/warning';
|
|||
import {getInstanceFromNode} from './ReactNativeComponentTree';
|
||||
|
||||
import type {AnyNativeEvent} from 'events/PluginModuleType';
|
||||
import type {TopLevelType} from 'events/TopLevelEventTypes';
|
||||
|
||||
export {getListener, registrationNameModules as registrationNames};
|
||||
|
||||
|
@ -88,7 +89,7 @@ const removeTouchesAtIndices = function(
|
|||
*/
|
||||
export function _receiveRootNodeIDEvent(
|
||||
rootNodeID: number,
|
||||
topLevelType: string,
|
||||
topLevelType: TopLevelType,
|
||||
nativeEventParam: ?AnyNativeEvent,
|
||||
) {
|
||||
const nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT;
|
||||
|
@ -114,7 +115,7 @@ export function _receiveRootNodeIDEvent(
|
|||
*/
|
||||
export function receiveEvent(
|
||||
rootNodeID: number,
|
||||
topLevelType: string,
|
||||
topLevelType: TopLevelType,
|
||||
nativeEventParam: AnyNativeEvent,
|
||||
) {
|
||||
_receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam);
|
||||
|
@ -145,7 +146,7 @@ export function receiveEvent(
|
|||
* identifier 0, also abandoning traditional click handlers.
|
||||
*/
|
||||
export function receiveTouches(
|
||||
eventTopLevelType: string,
|
||||
eventTopLevelType: TopLevelType,
|
||||
touches: Array<Object>,
|
||||
changedIndices: Array<number>,
|
||||
) {
|
||||
|
|
|
@ -143,6 +143,14 @@ const forks = Object.freeze({
|
|||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
// React DOM uses different top level event names and supports mouse events.
|
||||
'events/ResponderTopLevelEventTypes': (bundleType, entry) => {
|
||||
if (entry === 'react-dom' || entry.startsWith('react-dom/')) {
|
||||
return 'events/forks/ResponderTopLevelEventTypes.dom.js';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = forks;
|
||||
|
|
Loading…
Reference in New Issue