mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Further cleanup of plugin event system (#18056)
This commit is contained in:
@@ -14,7 +14,8 @@ let EventPluginRegistry;
|
||||
let React;
|
||||
let ReactDOM;
|
||||
let ReactDOMComponentTree;
|
||||
let ReactBrowserEventEmitter;
|
||||
let DOMEventPluginSystem;
|
||||
let ReactDOMEventListener;
|
||||
let ReactTestUtils;
|
||||
|
||||
let idCallOrder;
|
||||
@@ -52,18 +53,21 @@ function registerSimpleTestHandler() {
|
||||
return getListener(CHILD, ON_CLICK_KEY);
|
||||
}
|
||||
|
||||
// We should probably remove this file at some point, it's just full of
|
||||
// internal API usage. ReactBrowserEventEmitter was refactored out in
|
||||
// #18056 too. The majority of this code lives in DOMEventPluginSystem.
|
||||
describe('ReactBrowserEventEmitter', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
LISTENER.mockClear();
|
||||
|
||||
// TODO: can we express this test with only public API?
|
||||
EventPluginGetListener = require('legacy-events/getListener').default;
|
||||
EventPluginRegistry = require('legacy-events/EventPluginRegistry');
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
ReactDOMComponentTree = require('../client/ReactDOMComponentTree');
|
||||
ReactBrowserEventEmitter = require('../events/ReactBrowserEventEmitter');
|
||||
DOMEventPluginSystem = require('../events/DOMEventPluginSystem');
|
||||
ReactDOMEventListener = require('../events/ReactDOMEventListener');
|
||||
ReactTestUtils = require('react-dom/test-utils');
|
||||
|
||||
container = document.createElement('div');
|
||||
@@ -177,12 +181,12 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
expect(LISTENER).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should not invoke handlers if ReactBrowserEventEmitter is disabled', () => {
|
||||
it('should not invoke handlers if ReactDOMEventListener is disabled', () => {
|
||||
registerSimpleTestHandler();
|
||||
ReactBrowserEventEmitter.setEnabled(false);
|
||||
ReactDOMEventListener.setEnabled(false);
|
||||
CHILD.click();
|
||||
expect(LISTENER).toHaveBeenCalledTimes(0);
|
||||
ReactBrowserEventEmitter.setEnabled(true);
|
||||
ReactDOMEventListener.setEnabled(true);
|
||||
CHILD.click();
|
||||
expect(LISTENER).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
@@ -346,15 +350,15 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
|
||||
it('should listen to events only once', () => {
|
||||
spyOnDevAndProd(EventTarget.prototype, 'addEventListener');
|
||||
ReactBrowserEventEmitter.listenTo(ON_CLICK_KEY, document);
|
||||
ReactBrowserEventEmitter.listenTo(ON_CLICK_KEY, document);
|
||||
DOMEventPluginSystem.listenToEvent(ON_CLICK_KEY, document);
|
||||
DOMEventPluginSystem.listenToEvent(ON_CLICK_KEY, document);
|
||||
expect(EventTarget.prototype.addEventListener).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should work with event plugins without dependencies', () => {
|
||||
spyOnDevAndProd(EventTarget.prototype, 'addEventListener');
|
||||
|
||||
ReactBrowserEventEmitter.listenTo(ON_CLICK_KEY, document);
|
||||
DOMEventPluginSystem.listenToEvent(ON_CLICK_KEY, document);
|
||||
|
||||
expect(EventTarget.prototype.addEventListener.calls.argsFor(0)[0]).toBe(
|
||||
'click',
|
||||
@@ -364,7 +368,7 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
it('should work with event plugins with dependencies', () => {
|
||||
spyOnDevAndProd(EventTarget.prototype, 'addEventListener');
|
||||
|
||||
ReactBrowserEventEmitter.listenTo(ON_CHANGE_KEY, document);
|
||||
DOMEventPluginSystem.listenToEvent(ON_CHANGE_KEY, document);
|
||||
|
||||
const setEventListeners = [];
|
||||
const listenCalls = EventTarget.prototype.addEventListener.calls.allArgs();
|
||||
|
||||
+4
-6
@@ -57,14 +57,11 @@ import {
|
||||
TOP_SUBMIT,
|
||||
TOP_TOGGLE,
|
||||
} from '../events/DOMTopLevelEventTypes';
|
||||
import {
|
||||
listenTo,
|
||||
trapBubbledEvent,
|
||||
getListenerMapForElement,
|
||||
} from '../events/ReactBrowserEventEmitter';
|
||||
import {getListenerMapForElement} from '../events/DOMEventListenerMap';
|
||||
import {
|
||||
addResponderEventSystemEvent,
|
||||
removeActiveResponderEventSystemEvent,
|
||||
trapBubbledEvent,
|
||||
} from '../events/ReactDOMEventListener.js';
|
||||
import {mediaEventTypes} from '../events/DOMTopLevelEventTypes';
|
||||
import {
|
||||
@@ -90,6 +87,7 @@ import {
|
||||
enableDeprecatedFlareAPI,
|
||||
enableTrustedTypesIntegration,
|
||||
} from 'shared/ReactFeatureFlags';
|
||||
import {listenToEvent} from '../events/DOMEventPluginSystem';
|
||||
|
||||
let didWarnInvalidHydration = false;
|
||||
let didWarnShadyDOM = false;
|
||||
@@ -274,7 +272,7 @@ function ensureListeningTo(
|
||||
const doc = isDocumentOrFragment
|
||||
? rootContainerElement
|
||||
: rootContainerElement.ownerDocument;
|
||||
listenTo(registrationName, doc);
|
||||
listenToEvent(registrationName, doc);
|
||||
}
|
||||
|
||||
function getOwnerDocumentFromRootContainer(
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
import {addUserTimingListener} from 'shared/ReactFeatureFlags';
|
||||
|
||||
import ReactDOM from './ReactDOM';
|
||||
import {isEnabled} from '../events/ReactBrowserEventEmitter';
|
||||
import {isEnabled} from '../events/ReactDOMEventListener';
|
||||
import {getClosestInstanceFromNode} from './ReactDOMComponentTree';
|
||||
|
||||
if (__EXPERIMENTAL__) {
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import {validateDOMNesting, updatedAncestorInfo} from './validateDOMNesting';
|
||||
import {
|
||||
isEnabled as ReactBrowserEventEmitterIsEnabled,
|
||||
setEnabled as ReactBrowserEventEmitterSetEnabled,
|
||||
} from '../events/ReactBrowserEventEmitter';
|
||||
} from '../events/ReactDOMEventListener';
|
||||
import {getChildNamespace} from '../shared/DOMNamespaces';
|
||||
import {
|
||||
ELEMENT_NODE,
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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 'legacy-events/TopLevelEventTypes';
|
||||
|
||||
const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
|
||||
// prettier-ignore
|
||||
const elementListenerMap:
|
||||
// $FlowFixMe Work around Flow bug
|
||||
| WeakMap
|
||||
| Map<
|
||||
Document | Element | Node,
|
||||
Map<DOMTopLevelEventType | string, null | (any => void)>,
|
||||
> = new PossiblyWeakMap();
|
||||
|
||||
export function getListenerMapForElement(
|
||||
element: Document | Element | Node,
|
||||
): Map<DOMTopLevelEventType | string, null | (any => void)> {
|
||||
let listenerMap = elementListenerMap.get(element);
|
||||
if (listenerMap === undefined) {
|
||||
listenerMap = new Map();
|
||||
elementListenerMap.set(element, listenerMap);
|
||||
}
|
||||
return listenerMap;
|
||||
}
|
||||
@@ -21,9 +21,81 @@ import {batchedEventUpdates} from 'legacy-events/ReactGenericBatching';
|
||||
import {runEventsInBatch} from 'legacy-events/EventBatching';
|
||||
import {plugins} from 'legacy-events/EventPluginRegistry';
|
||||
import accumulateInto from 'legacy-events/accumulateInto';
|
||||
import {registrationNameDependencies} from 'legacy-events/EventPluginRegistry';
|
||||
|
||||
import getEventTarget from './getEventTarget';
|
||||
import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
|
||||
import {trapCapturedEvent, trapBubbledEvent} from './ReactDOMEventListener';
|
||||
import {getListenerMapForElement} from './DOMEventListenerMap';
|
||||
import isEventSupported from './isEventSupported';
|
||||
import {
|
||||
TOP_BLUR,
|
||||
TOP_CANCEL,
|
||||
TOP_CLOSE,
|
||||
TOP_FOCUS,
|
||||
TOP_INVALID,
|
||||
TOP_RESET,
|
||||
TOP_SCROLL,
|
||||
TOP_SUBMIT,
|
||||
getRawEventName,
|
||||
mediaEventTypes,
|
||||
} from './DOMTopLevelEventTypes';
|
||||
|
||||
/**
|
||||
* Summary of `DOMEventPluginSystem` event handling:
|
||||
*
|
||||
* - Top-level delegation is used to trap most native browser events. This
|
||||
* may only occur in the main thread and is the responsibility of
|
||||
* ReactDOMEventListener, which is injected and can therefore support
|
||||
* pluggable event sources. This is the only work that occurs in the main
|
||||
* thread.
|
||||
*
|
||||
* - We normalize and de-duplicate events to account for browser quirks. This
|
||||
* may be done in the worker thread.
|
||||
*
|
||||
* - Forward these native events (with the associated top-level type used to
|
||||
* trap it) to `EventPluginRegistry`, which in turn will ask plugins if they want
|
||||
* to extract any synthetic events.
|
||||
*
|
||||
* - The `EventPluginRegistry` will then process each event by annotating them with
|
||||
* "dispatches", a sequence of listeners and IDs that care about that event.
|
||||
*
|
||||
* - The `EventPluginRegistry` then dispatches the events.
|
||||
*
|
||||
* Overview of React and the event system:
|
||||
*
|
||||
* +------------+ .
|
||||
* | DOM | .
|
||||
* +------------+ .
|
||||
* | .
|
||||
* v .
|
||||
* +------------+ .
|
||||
* | ReactEvent | .
|
||||
* | Listener | .
|
||||
* +------------+ . +-----------+
|
||||
* | . +--------+|SimpleEvent|
|
||||
* | . | |Plugin |
|
||||
* +-----|------+ . v +-----------+
|
||||
* | | | . +--------------+ +------------+
|
||||
* | +-----------.--->|PluginRegistry| | Event |
|
||||
* | | . | | +-----------+ | Propagators|
|
||||
* | ReactEvent | . | | |TapEvent | |------------|
|
||||
* | Emitter | . | |<---+|Plugin | |other plugin|
|
||||
* | | . | | +-----------+ | utilities |
|
||||
* | +-----------.--->| | +------------+
|
||||
* | | | . +--------------+
|
||||
* +-----|------+ . ^ +-----------+
|
||||
* | . | |Enter/Leave|
|
||||
* + . +-------+|Plugin |
|
||||
* +-------------+ . +-----------+
|
||||
* | application | .
|
||||
* |-------------| .
|
||||
* | | .
|
||||
* | | .
|
||||
* +-------------+ .
|
||||
* .
|
||||
* React Core . General Purpose Event Plugin System
|
||||
*/
|
||||
|
||||
const CALLBACK_BOOKKEEPING_POOL_SIZE = 10;
|
||||
const callbackBookkeepingPool = [];
|
||||
@@ -213,3 +285,97 @@ export function dispatchEventForPluginEventSystem(
|
||||
releaseTopLevelCallbackBookKeeping(bookKeeping);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We listen for bubbled touch events on the document object.
|
||||
*
|
||||
* Firefox v8.01 (and possibly others) exhibited strange behavior when
|
||||
* mounting `onmousemove` events at some node that was not the document
|
||||
* element. The symptoms were that if your mouse is not moving over something
|
||||
* contained within that mount point (for example on the background) the
|
||||
* top-level listeners for `onmousemove` won't be called. However, if you
|
||||
* register the `mousemove` on the document object, then it will of course
|
||||
* catch all `mousemove`s. This along with iOS quirks, justifies restricting
|
||||
* top-level listeners to the document object only, at least for these
|
||||
* movement types of events and possibly all events.
|
||||
*
|
||||
* @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
|
||||
*
|
||||
* Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
|
||||
* they bubble to document.
|
||||
*
|
||||
* @param {string} registrationName Name of listener (e.g. `onClick`).
|
||||
* @param {object} mountAt Container where to mount the listener
|
||||
*/
|
||||
export function listenToEvent(
|
||||
registrationName: string,
|
||||
mountAt: Document | Element | Node,
|
||||
): void {
|
||||
const listeningSet = getListenerMapForElement(mountAt);
|
||||
const dependencies = registrationNameDependencies[registrationName];
|
||||
|
||||
for (let i = 0; i < dependencies.length; i++) {
|
||||
const dependency = dependencies[i];
|
||||
listenToTopLevelEvent(dependency, mountAt, listeningSet);
|
||||
}
|
||||
}
|
||||
|
||||
export function listenToTopLevelEvent(
|
||||
topLevelType: DOMTopLevelEventType,
|
||||
mountAt: Document | Element | Node,
|
||||
listenerMap: Map<DOMTopLevelEventType | string, null | (any => void)>,
|
||||
): void {
|
||||
if (!listenerMap.has(topLevelType)) {
|
||||
switch (topLevelType) {
|
||||
case TOP_SCROLL:
|
||||
trapCapturedEvent(TOP_SCROLL, mountAt);
|
||||
break;
|
||||
case TOP_FOCUS:
|
||||
case TOP_BLUR:
|
||||
trapCapturedEvent(TOP_FOCUS, mountAt);
|
||||
trapCapturedEvent(TOP_BLUR, mountAt);
|
||||
// We set the flag for a single dependency later in this function,
|
||||
// but this ensures we mark both as attached rather than just one.
|
||||
listenerMap.set(TOP_BLUR, null);
|
||||
listenerMap.set(TOP_FOCUS, null);
|
||||
break;
|
||||
case TOP_CANCEL:
|
||||
case TOP_CLOSE:
|
||||
if (isEventSupported(getRawEventName(topLevelType))) {
|
||||
trapCapturedEvent(topLevelType, mountAt);
|
||||
}
|
||||
break;
|
||||
case TOP_INVALID:
|
||||
case TOP_SUBMIT:
|
||||
case TOP_RESET:
|
||||
// We listen to them on the target DOM elements.
|
||||
// Some of them bubble so we don't want them to fire twice.
|
||||
break;
|
||||
default:
|
||||
// By default, listen on the top level to all non-media events.
|
||||
// Media events don't bubble so adding the listener wouldn't do anything.
|
||||
const isMediaEvent = mediaEventTypes.indexOf(topLevelType) !== -1;
|
||||
if (!isMediaEvent) {
|
||||
trapBubbledEvent(topLevelType, mountAt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
listenerMap.set(topLevelType, null);
|
||||
}
|
||||
}
|
||||
|
||||
export function isListeningToAllDependencies(
|
||||
registrationName: string,
|
||||
mountAt: Document | Element,
|
||||
): boolean {
|
||||
const listenerMap = getListenerMapForElement(mountAt);
|
||||
const dependencies = registrationNameDependencies[registrationName];
|
||||
|
||||
for (let i = 0; i < dependencies.length; i++) {
|
||||
const dependency = dependencies[i];
|
||||
if (!listenerMap.has(dependency)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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 'legacy-events/EventPluginRegistry';
|
||||
import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
|
||||
import {
|
||||
TOP_BLUR,
|
||||
TOP_CANCEL,
|
||||
TOP_CLOSE,
|
||||
TOP_FOCUS,
|
||||
TOP_INVALID,
|
||||
TOP_RESET,
|
||||
TOP_SCROLL,
|
||||
TOP_SUBMIT,
|
||||
getRawEventName,
|
||||
mediaEventTypes,
|
||||
} from './DOMTopLevelEventTypes';
|
||||
import {
|
||||
setEnabled,
|
||||
isEnabled,
|
||||
trapBubbledEvent,
|
||||
trapCapturedEvent,
|
||||
} from './ReactDOMEventListener';
|
||||
import isEventSupported from './isEventSupported';
|
||||
|
||||
/**
|
||||
* Summary of `ReactBrowserEventEmitter` event handling:
|
||||
*
|
||||
* - Top-level delegation is used to trap most native browser events. This
|
||||
* may only occur in the main thread and is the responsibility of
|
||||
* ReactDOMEventListener, which is injected and can therefore support
|
||||
* pluggable event sources. This is the only work that occurs in the main
|
||||
* thread.
|
||||
*
|
||||
* - We normalize and de-duplicate events to account for browser quirks. This
|
||||
* may be done in the worker thread.
|
||||
*
|
||||
* - Forward these native events (with the associated top-level type used to
|
||||
* trap it) to `EventPluginRegistry`, which in turn will ask plugins if they want
|
||||
* to extract any synthetic events.
|
||||
*
|
||||
* - The `EventPluginRegistry` will then process each event by annotating them with
|
||||
* "dispatches", a sequence of listeners and IDs that care about that event.
|
||||
*
|
||||
* - The `EventPluginRegistry` then dispatches the events.
|
||||
*
|
||||
* Overview of React and the event system:
|
||||
*
|
||||
* +------------+ .
|
||||
* | DOM | .
|
||||
* +------------+ .
|
||||
* | .
|
||||
* v .
|
||||
* +------------+ .
|
||||
* | ReactEvent | .
|
||||
* | Listener | .
|
||||
* +------------+ . +-----------+
|
||||
* | . +--------+|SimpleEvent|
|
||||
* | . | |Plugin |
|
||||
* +-----|------+ . v +-----------+
|
||||
* | | | . +--------------+ +------------+
|
||||
* | +-----------.--->|PluginRegistry| | Event |
|
||||
* | | . | | +-----------+ | Propagators|
|
||||
* | ReactEvent | . | | |TapEvent | |------------|
|
||||
* | Emitter | . | |<---+|Plugin | |other plugin|
|
||||
* | | . | | +-----------+ | utilities |
|
||||
* | +-----------.--->| | +------------+
|
||||
* | | | . +--------------+
|
||||
* +-----|------+ . ^ +-----------+
|
||||
* | . | |Enter/Leave|
|
||||
* + . +-------+|Plugin |
|
||||
* +-------------+ . +-----------+
|
||||
* | application | .
|
||||
* |-------------| .
|
||||
* | | .
|
||||
* | | .
|
||||
* +-------------+ .
|
||||
* .
|
||||
* React Core . General Purpose Event Plugin System
|
||||
*/
|
||||
|
||||
const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
|
||||
// prettier-ignore
|
||||
const elementListenerMap:
|
||||
// $FlowFixMe Work around Flow bug
|
||||
| WeakMap
|
||||
| Map<
|
||||
Document | Element | Node,
|
||||
Map<DOMTopLevelEventType | string, null | (any => void)>,
|
||||
> = new PossiblyWeakMap();
|
||||
|
||||
export function getListenerMapForElement(
|
||||
element: Document | Element | Node,
|
||||
): Map<DOMTopLevelEventType | string, null | (any => void)> {
|
||||
let listenerMap = elementListenerMap.get(element);
|
||||
if (listenerMap === undefined) {
|
||||
listenerMap = new Map();
|
||||
elementListenerMap.set(element, listenerMap);
|
||||
}
|
||||
return listenerMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* We listen for bubbled touch events on the document object.
|
||||
*
|
||||
* Firefox v8.01 (and possibly others) exhibited strange behavior when
|
||||
* mounting `onmousemove` events at some node that was not the document
|
||||
* element. The symptoms were that if your mouse is not moving over something
|
||||
* contained within that mount point (for example on the background) the
|
||||
* top-level listeners for `onmousemove` won't be called. However, if you
|
||||
* register the `mousemove` on the document object, then it will of course
|
||||
* catch all `mousemove`s. This along with iOS quirks, justifies restricting
|
||||
* top-level listeners to the document object only, at least for these
|
||||
* movement types of events and possibly all events.
|
||||
*
|
||||
* @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
|
||||
*
|
||||
* Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
|
||||
* they bubble to document.
|
||||
*
|
||||
* @param {string} registrationName Name of listener (e.g. `onClick`).
|
||||
* @param {object} mountAt Container where to mount the listener
|
||||
*/
|
||||
export function listenTo(
|
||||
registrationName: string,
|
||||
mountAt: Document | Element | Node,
|
||||
): void {
|
||||
const listeningSet = getListenerMapForElement(mountAt);
|
||||
const dependencies = registrationNameDependencies[registrationName];
|
||||
|
||||
for (let i = 0; i < dependencies.length; i++) {
|
||||
const dependency = dependencies[i];
|
||||
listenToTopLevel(dependency, mountAt, listeningSet);
|
||||
}
|
||||
}
|
||||
|
||||
export function listenToTopLevel(
|
||||
topLevelType: DOMTopLevelEventType,
|
||||
mountAt: Document | Element | Node,
|
||||
listenerMap: Map<DOMTopLevelEventType | string, null | (any => void)>,
|
||||
): void {
|
||||
if (!listenerMap.has(topLevelType)) {
|
||||
switch (topLevelType) {
|
||||
case TOP_SCROLL:
|
||||
trapCapturedEvent(TOP_SCROLL, mountAt);
|
||||
break;
|
||||
case TOP_FOCUS:
|
||||
case TOP_BLUR:
|
||||
trapCapturedEvent(TOP_FOCUS, mountAt);
|
||||
trapCapturedEvent(TOP_BLUR, mountAt);
|
||||
// We set the flag for a single dependency later in this function,
|
||||
// but this ensures we mark both as attached rather than just one.
|
||||
listenerMap.set(TOP_BLUR, null);
|
||||
listenerMap.set(TOP_FOCUS, null);
|
||||
break;
|
||||
case TOP_CANCEL:
|
||||
case TOP_CLOSE:
|
||||
if (isEventSupported(getRawEventName(topLevelType))) {
|
||||
trapCapturedEvent(topLevelType, mountAt);
|
||||
}
|
||||
break;
|
||||
case TOP_INVALID:
|
||||
case TOP_SUBMIT:
|
||||
case TOP_RESET:
|
||||
// We listen to them on the target DOM elements.
|
||||
// Some of them bubble so we don't want them to fire twice.
|
||||
break;
|
||||
default:
|
||||
// By default, listen on the top level to all non-media events.
|
||||
// Media events don't bubble so adding the listener wouldn't do anything.
|
||||
const isMediaEvent = mediaEventTypes.indexOf(topLevelType) !== -1;
|
||||
if (!isMediaEvent) {
|
||||
trapBubbledEvent(topLevelType, mountAt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
listenerMap.set(topLevelType, null);
|
||||
}
|
||||
}
|
||||
|
||||
export function isListeningToAllDependencies(
|
||||
registrationName: string,
|
||||
mountAt: Document | Element,
|
||||
): boolean {
|
||||
const listenerMap = getListenerMapForElement(mountAt);
|
||||
const dependencies = registrationNameDependencies[registrationName];
|
||||
|
||||
for (let i = 0; i < dependencies.length; i++) {
|
||||
const dependency = dependencies[i];
|
||||
if (!listenerMap.has(dependency)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export {setEnabled, isEnabled, trapBubbledEvent, trapCapturedEvent};
|
||||
+3
-5
@@ -32,10 +32,7 @@ import {
|
||||
attemptToDispatchEvent,
|
||||
addResponderEventSystemEvent,
|
||||
} from './ReactDOMEventListener';
|
||||
import {
|
||||
getListenerMapForElement,
|
||||
listenToTopLevel,
|
||||
} from './ReactBrowserEventEmitter';
|
||||
import {getListenerMapForElement} from './DOMEventListenerMap';
|
||||
import {
|
||||
getInstanceFromNode,
|
||||
getClosestInstanceFromNode,
|
||||
@@ -120,6 +117,7 @@ import {
|
||||
TOP_BLUR,
|
||||
} from './DOMTopLevelEventTypes';
|
||||
import {IS_REPLAYED} from 'legacy-events/EventSystemFlags';
|
||||
import {listenToTopLevelEvent} from './DOMEventPluginSystem';
|
||||
|
||||
type QueuedReplayableEvent = {|
|
||||
blockedOn: null | Container | SuspenseInstance,
|
||||
@@ -217,7 +215,7 @@ function trapReplayableEvent(
|
||||
document: Document,
|
||||
listenerMap: Map<DOMTopLevelEventType | string, null | (any => void)>,
|
||||
) {
|
||||
listenToTopLevel(topLevelType, document, listenerMap);
|
||||
listenToTopLevelEvent(topLevelType, document, listenerMap);
|
||||
if (enableDeprecatedFlareAPI) {
|
||||
// Trap events for the responder system.
|
||||
const topLevelTypeString = unsafeCastDOMTopLevelTypeToString(topLevelType);
|
||||
|
||||
+1
-1
@@ -22,11 +22,11 @@ import {
|
||||
TOP_MOUSE_UP,
|
||||
TOP_SELECTION_CHANGE,
|
||||
} from './DOMTopLevelEventTypes';
|
||||
import {isListeningToAllDependencies} from './ReactBrowserEventEmitter';
|
||||
import getActiveElement from '../client/getActiveElement';
|
||||
import {getNodeFromInstance} from '../client/ReactDOMComponentTree';
|
||||
import {hasSelectionCapabilities} from '../client/ReactInputSelection';
|
||||
import {DOCUMENT_NODE} from '../shared/HTMLNodeType';
|
||||
import {isListeningToAllDependencies} from './DOMEventPluginSystem';
|
||||
|
||||
const skipSelectionChangeEvent =
|
||||
canUseDOM && 'documentMode' in document && document.documentMode <= 11;
|
||||
|
||||
Reference in New Issue
Block a user