This commit is contained in:
94
node_modules/consolidated-events/src/TargetEventHandlers.js
generated
vendored
Normal file
94
node_modules/consolidated-events/src/TargetEventHandlers.js
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
import eventOptionsKey from './eventOptionsKey';
|
||||
|
||||
function ensureCanMutateNextEventHandlers(eventHandlers) {
|
||||
if (eventHandlers.handlers === eventHandlers.nextHandlers) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
eventHandlers.nextHandlers = eventHandlers.handlers.slice();
|
||||
}
|
||||
}
|
||||
|
||||
export default function TargetEventHandlers(target) {
|
||||
this.target = target;
|
||||
this.events = {};
|
||||
}
|
||||
|
||||
TargetEventHandlers.prototype.getEventHandlers = function getEventHandlers(eventName, options) {
|
||||
const key = `${eventName} ${eventOptionsKey(options)}`;
|
||||
|
||||
if (!this.events[key]) {
|
||||
this.events[key] = {
|
||||
handlers: [],
|
||||
handleEvent: undefined,
|
||||
};
|
||||
this.events[key].nextHandlers = this.events[key].handlers;
|
||||
}
|
||||
|
||||
return this.events[key];
|
||||
};
|
||||
|
||||
TargetEventHandlers.prototype.handleEvent = function handleEvent(eventName, options, event) {
|
||||
const eventHandlers = this.getEventHandlers(eventName, options);
|
||||
eventHandlers.handlers = eventHandlers.nextHandlers;
|
||||
eventHandlers.handlers.forEach((handler) => {
|
||||
if (handler) {
|
||||
// We need to check for presence here because a handler function may
|
||||
// cause later handlers to get removed. This can happen if you for
|
||||
// instance have a waypoint that unmounts another waypoint as part of an
|
||||
// onEnter/onLeave handler.
|
||||
handler(event);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
TargetEventHandlers.prototype.add = function add(eventName, listener, options) {
|
||||
// options has already been normalized at this point.
|
||||
const eventHandlers = this.getEventHandlers(eventName, options);
|
||||
|
||||
ensureCanMutateNextEventHandlers(eventHandlers);
|
||||
|
||||
if (eventHandlers.nextHandlers.length === 0) {
|
||||
eventHandlers.handleEvent = this.handleEvent.bind(this, eventName, options);
|
||||
|
||||
this.target.addEventListener(
|
||||
eventName,
|
||||
eventHandlers.handleEvent,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
eventHandlers.nextHandlers.push(listener);
|
||||
|
||||
let isSubscribed = true;
|
||||
const unsubscribe = () => {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
|
||||
isSubscribed = false;
|
||||
|
||||
ensureCanMutateNextEventHandlers(eventHandlers);
|
||||
const index = eventHandlers.nextHandlers.indexOf(listener);
|
||||
eventHandlers.nextHandlers.splice(index, 1);
|
||||
|
||||
if (eventHandlers.nextHandlers.length === 0) {
|
||||
// All event handlers have been removed, so we want to remove the event
|
||||
// listener from the target node.
|
||||
|
||||
if (this.target) {
|
||||
// There can be a race condition where the target may no longer exist
|
||||
// when this function is called, e.g. when a React component is
|
||||
// unmounting. Guarding against this prevents the following error:
|
||||
//
|
||||
// Cannot read property 'removeEventListener' of undefined
|
||||
this.target.removeEventListener(
|
||||
eventName,
|
||||
eventHandlers.handleEvent,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
eventHandlers.handleEvent = undefined;
|
||||
}
|
||||
};
|
||||
return unsubscribe;
|
||||
};
|
||||
6
node_modules/consolidated-events/src/canUseDOM.js
generated
vendored
Normal file
6
node_modules/consolidated-events/src/canUseDOM.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
const CAN_USE_DOM = !!(
|
||||
(typeof window !== 'undefined' &&
|
||||
window.document && window.document.createElement)
|
||||
);
|
||||
|
||||
export default CAN_USE_DOM;
|
||||
39
node_modules/consolidated-events/src/canUsePassiveEventListeners.js
generated
vendored
Normal file
39
node_modules/consolidated-events/src/canUsePassiveEventListeners.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import canUseDOM from './canUseDOM';
|
||||
|
||||
// Adapted from Modernizr
|
||||
// https://github.com/Modernizr/Modernizr/blob/acb3f0d9/feature-detects/dom/passiveeventlisteners.js#L26-L37
|
||||
function testPassiveEventListeners() {
|
||||
if (!canUseDOM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!window.addEventListener || !window.removeEventListener || !Object.defineProperty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let supportsPassiveOption = false;
|
||||
try {
|
||||
const opts = Object.defineProperty({}, 'passive', {
|
||||
// eslint-disable-next-line getter-return
|
||||
get() {
|
||||
supportsPassiveOption = true;
|
||||
},
|
||||
});
|
||||
const noop = () => {};
|
||||
window.addEventListener('testPassiveEventSupport', noop, opts);
|
||||
window.removeEventListener('testPassiveEventSupport', noop, opts);
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
return supportsPassiveOption;
|
||||
}
|
||||
|
||||
let memoized;
|
||||
|
||||
export default function canUsePassiveEventListeners() {
|
||||
if (memoized === undefined) {
|
||||
memoized = testPassiveEventListeners();
|
||||
}
|
||||
return memoized;
|
||||
}
|
||||
30
node_modules/consolidated-events/src/eventOptionsKey.js
generated
vendored
Normal file
30
node_modules/consolidated-events/src/eventOptionsKey.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/* eslint-disable no-bitwise */
|
||||
|
||||
/**
|
||||
* Generate a unique key for any set of event options
|
||||
*/
|
||||
export default function eventOptionsKey(normalizedEventOptions) {
|
||||
if (!normalizedEventOptions) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the browser does not support passive event listeners, the normalized
|
||||
// event options will be a boolean.
|
||||
if (normalizedEventOptions === true) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
// At this point, the browser supports passive event listeners, so we expect
|
||||
// the event options to be an object with possible properties of capture,
|
||||
// passive, and once.
|
||||
//
|
||||
// We want to consistently return the same value, regardless of the order of
|
||||
// these properties, so let's use binary maths to assign each property to a
|
||||
// bit, and then add those together (with an offset to account for the
|
||||
// booleans at the beginning of this function).
|
||||
const capture = normalizedEventOptions.capture << 0;
|
||||
const passive = normalizedEventOptions.passive << 1;
|
||||
const once = normalizedEventOptions.once << 2;
|
||||
return capture + passive + once;
|
||||
}
|
||||
|
||||
14
node_modules/consolidated-events/src/index.js
generated
vendored
Normal file
14
node_modules/consolidated-events/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import normalizeEventOptions from './normalizeEventOptions';
|
||||
import TargetEventHandlers from './TargetEventHandlers';
|
||||
|
||||
const EVENT_HANDLERS_KEY = '__consolidated_events_handlers__';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export function addEventListener(target, eventName, listener, options) {
|
||||
if (!target[EVENT_HANDLERS_KEY]) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
target[EVENT_HANDLERS_KEY] = new TargetEventHandlers(target);
|
||||
}
|
||||
const normalizedEventOptions = normalizeEventOptions(options);
|
||||
return target[EVENT_HANDLERS_KEY].add(eventName, listener, normalizedEventOptions);
|
||||
}
|
||||
17
node_modules/consolidated-events/src/normalizeEventOptions.js
generated
vendored
Normal file
17
node_modules/consolidated-events/src/normalizeEventOptions.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import canUsePassiveEventListeners from './canUsePassiveEventListeners';
|
||||
|
||||
export default function normalizeEventOptions(eventOptions) {
|
||||
if (!eventOptions) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!canUsePassiveEventListeners()) {
|
||||
// If the browser does not support the passive option, then it is expecting
|
||||
// a boolean for the options argument to specify whether it should use
|
||||
// capture or not. In more modern browsers, this is passed via the `capture`
|
||||
// option, so let's just hoist that value up.
|
||||
return !!eventOptions.capture;
|
||||
}
|
||||
|
||||
return eventOptions;
|
||||
}
|
||||
Reference in New Issue
Block a user