295
domEventName: DOMEventName,
296
targetElement: Element,
297
): void {
298
+ if (__DEV__) {
299
+ if (!nonDelegatedEvents.has(domEventName)) {
300
+ console.error(
301
+ 'Did not expect a listenToNonDelegatedEvent() call for "%s". ' +
302
+ 'This is a bug in React. Please file an issue.',
303
+ domEventName,
304
+ );
305
+ }
306
+ }
307
const isCapturePhaseListener = false;
308
const listenerSet = getEventListenerSet(targetElement);
309
const listenerSetKey = getListenerSetKey(
321
}
322
}
323
315
-const listeningMarker =
316
- '_reactListening' +
317
- Math.random()
318
- .toString(36)
319
- .slice(2);
320
-
321
-export function listenToAllSupportedEvents(rootContainerElement: EventTarget) {
322
- if ((rootContainerElement: any)[listeningMarker]) {
323
- // Performance optimization: don't iterate through events
324
- // for the same portal container or root node more than once.
325
- // TODO: once we remove the flag, we may be able to also
326
- // remove some of the bookkeeping maps used for laziness.
327
- return;
328
- }
329
- (rootContainerElement: any)[listeningMarker] = true;
330
- allNativeEvents.forEach(domEventName => {
331
- if (!nonDelegatedEvents.has(domEventName)) {
332
- listenToNativeEvent(
324
+export function listenToNativeEvent(
325
+ domEventName: DOMEventName,
326
+ isCapturePhaseListener: boolean,
327
+ target: EventTarget,
328
+): void {
329
+ if (__DEV__) {
330
+ if (nonDelegatedEvents.has(domEventName) && !isCapturePhaseListener) {
331
+ console.error(
332
+ 'Did not expect a listenToNativeEvent() call for "%s" in the bubble phase. ' +
333
+ 'This is a bug in React. Please file an issue.',
334
domEventName,
334
- false,
335
- ((rootContainerElement: any): Element),
336
- null,
335
);
336
}
339
- listenToNativeEvent(
340
- domEventName,
341
- true,
342
- ((rootContainerElement: any): Element),
343
- null,
344
- );
345
- });
337
+ }
338
+
339
+ let eventSystemFlags = 0;
340
+ if (isCapturePhaseListener) {
341
+ eventSystemFlags |= IS_CAPTURE_PHASE;
342
+ }
343
+ addTrappedEventListener(
344
+ target,
345
+ domEventName,
346
+ eventSystemFlags,
347
+ isCapturePhaseListener,
348
+ );
349
}
350
348
-export function listenToNativeEvent(
351
+// This is only used by createEventHandle when the
352
+// target is not a DOM element. E.g. window.
353
+export function listenToNativeEventForNonManagedEventTarget(
354
domEventName: DOMEventName,
355
isCapturePhaseListener: boolean,
351
- rootContainerElement: EventTarget,
352
- targetElement: Element | null,
353
- eventSystemFlags?: EventSystemFlags = 0,
356
+ target: EventTarget,
357
): void {
355
- let target = rootContainerElement;
356
-
357
- // selectionchange needs to be attached to the document
358
- // otherwise it won't capture incoming events that are only
359
- // triggered on the document directly.
360
- if (
361
- domEventName === 'selectionchange' &&
362
- (rootContainerElement: any).nodeType !== DOCUMENT_NODE
363
- ) {
364
- target = (rootContainerElement: any).ownerDocument;
365
- }
366
- // If the event can be delegated (or is capture phase), we can
367
- // register it to the root container. Otherwise, we should
368
- // register the event to the target element and mark it as
369
- // a non-delegated event.
370
- if (
371
- targetElement !== null &&
372
- !isCapturePhaseListener &&
373
- nonDelegatedEvents.has(domEventName)
374
- ) {
375
- // For all non-delegated events, apart from scroll, we attach
376
- // their event listeners to the respective elements that their
377
- // events fire on. That means we can skip this step, as event
378
- // listener has already been added previously. However, we
379
- // special case the scroll event because the reality is that any
380
- // element can scroll.
381
- // TODO: ideally, we'd eventually apply the same logic to all
382
- // events from the nonDelegatedEvents list. Then we can remove
383
- // this special case and use the same logic for all events.
384
- if (domEventName !== 'scroll') {
385
- return;
386
- }
387
- eventSystemFlags |= IS_NON_DELEGATED;
388
- target = targetElement;
389
- }
358
+ let eventSystemFlags = IS_EVENT_HANDLE_NON_MANAGED_NODE;
359
const listenerSet = getEventListenerSet(target);
360
const listenerSetKey = getListenerSetKey(
361
domEventName,
362
isCapturePhaseListener,
363
);
395
- // If the listener entry is empty or we should upgrade, then
396
- // we need to trap an event listener onto the target.
364
if (!listenerSet.has(listenerSetKey)) {
365
if (isCapturePhaseListener) {
366
eventSystemFlags |= IS_CAPTURE_PHASE;
375
}
376
}
377
378
+const listeningMarker =
379
+ '_reactListening' +
380
+ Math.random()
381
+ .toString(36)
382
+ .slice(2);
383
+
384
+export function listenToAllSupportedEvents(rootContainerElement: EventTarget) {
385
+ if (!(rootContainerElement: any)[listeningMarker]) {
386
+ (rootContainerElement: any)[listeningMarker] = true;
387
+ allNativeEvents.forEach(domEventName => {
388
+ // We handle selectionchange separately because it
389
+ // doesn't bubble and needs to be on the document.
390
+ if (domEventName !== 'selectionchange') {
391
+ if (!nonDelegatedEvents.has(domEventName)) {
392
+ listenToNativeEvent(domEventName, false, rootContainerElement);
393
+ }
394
+ listenToNativeEvent(domEventName, true, rootContainerElement);
395
+ }
396
+ });
397
+ const ownerDocument =
398
+ (rootContainerElement: any).nodeType === DOCUMENT_NODE
399
+ ? rootContainerElement
400
+ : (rootContainerElement: any).ownerDocument;
401
+ if (ownerDocument !== null) {
402
+ // The selectionchange event also needs deduplication
403
+ // but it is attached to the document.
404
+ if (!(ownerDocument: any)[listeningMarker]) {
405
+ (ownerDocument: any)[listeningMarker] = true;
406
+ listenToNativeEvent('selectionchange', false, ownerDocument);
407
+ }
408
+ }
409
+ }
410
+}
411
+
412
function addTrappedEventListener(
413
targetContainer: EventTarget,
414
domEventName: DOMEventName,