This commit is contained in:
3
node_modules/consolidated-events/.babelrc
generated
vendored
Normal file
3
node_modules/consolidated-events/.babelrc
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["airbnb"]
|
||||
}
|
||||
1
node_modules/consolidated-events/.eslintignore
generated
vendored
Normal file
1
node_modules/consolidated-events/.eslintignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
lib
|
||||
8
node_modules/consolidated-events/.eslintrc
generated
vendored
Normal file
8
node_modules/consolidated-events/.eslintrc
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "airbnb-base",
|
||||
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
}
|
||||
}
|
||||
7
node_modules/consolidated-events/.travis.yml
generated
vendored
Normal file
7
node_modules/consolidated-events/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- "6"
|
||||
- "7"
|
||||
- "8"
|
||||
- "10"
|
||||
27
node_modules/consolidated-events/CHANGELOG.md
generated
vendored
Normal file
27
node_modules/consolidated-events/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
## v2.0.1
|
||||
|
||||
- Move TargetEventHandlers methods to prototype ([#15](https://github.com/lencioni/consolidated-events/pull/15))
|
||||
|
||||
## v2.0.0
|
||||
|
||||
- Now built with rollup ([#8](https://github.com/lencioni/consolidated-events/pull/8))
|
||||
- Deprecated `removeEventListener` export removed ([#13](https://github.com/lencioni/consolidated-events/pull/13))
|
||||
- Passive event listener test is now removed after being added ([#11](https://github.com/lencioni/consolidated-events/pull/11))
|
||||
- Reduced bundle size impact by replacing a class with a function ([#12](https://github.com/lencioni/consolidated-events/pull/12))
|
||||
|
||||
## v1.1.1
|
||||
|
||||
- Prevent event handlers from being mutated during current iteration.
|
||||
|
||||
## v1.1.0
|
||||
|
||||
- Return an unsubscribe function from `addEventListener` and deprecate
|
||||
`removeEventListener`.
|
||||
|
||||
## v1.0.1
|
||||
|
||||
- Fix bug with `handleEvent()`.
|
||||
|
||||
## v1.0.0
|
||||
|
||||
- Initial release.
|
||||
21
node_modules/consolidated-events/LICENSE
generated
vendored
Normal file
21
node_modules/consolidated-events/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Joe Lencioni
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
43
node_modules/consolidated-events/README.md
generated
vendored
Normal file
43
node_modules/consolidated-events/README.md
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# consolidated-events <sup>[![Version Badge][npm-version-svg]][package-url]</sup>
|
||||
|
||||
[![Build Status][travis-svg]][travis-url]
|
||||
[![dependency status][deps-svg]][deps-url]
|
||||
[![dev dependency status][dev-deps-svg]][dev-deps-url]
|
||||
[![License][license-image]][license-url]
|
||||
[![Downloads][downloads-image]][downloads-url]
|
||||
|
||||
[![npm badge][npm-badge-png]][package-url]
|
||||
|
||||
|
||||
Manage multiple event handlers using few event listeners.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
import { addEventListener } from 'consolidated-events';
|
||||
|
||||
const removeEventListener = addEventListener(
|
||||
window,
|
||||
'scroll',
|
||||
() => { console.log('scrolling') },
|
||||
{ passive: true }
|
||||
);
|
||||
|
||||
...
|
||||
|
||||
removeEventListener();
|
||||
```
|
||||
|
||||
[npm-version-svg]: http://versionbadg.es/lencioni/consolidated-events.svg
|
||||
[package-url]: https://npmjs.org/package/consolidated-events
|
||||
[travis-svg]: https://travis-ci.org/lencioni/consolidated-events.svg
|
||||
[travis-url]: https://travis-ci.org/lencioni/consolidated-events
|
||||
[deps-svg]: https://david-dm.org/lencioni/consolidated-events.svg
|
||||
[deps-url]: https://david-dm.org/lencioni/consolidated-events
|
||||
[dev-deps-svg]: https://david-dm.org/lencioni/consolidated-events/dev-status.svg
|
||||
[dev-deps-url]: https://david-dm.org/lencioni/consolidated-events#info=devDependencies
|
||||
[license-image]: http://img.shields.io/npm/l/consolidated-events.svg
|
||||
[license-url]: LICENSE
|
||||
[downloads-image]: http://img.shields.io/npm/dm/consolidated-events.svg
|
||||
[downloads-url]: http://npm-stat.com/charts.html?package=consolidated-events
|
||||
[npm-badge-png]: https://nodei.co/npm/consolidated-events.png?downloads=true&stars=true
|
||||
6
node_modules/consolidated-events/__tests__/.eslintrc
generated
vendored
Normal file
6
node_modules/consolidated-events/__tests__/.eslintrc
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"env": {
|
||||
"jasmine": true,
|
||||
"jest": true
|
||||
}
|
||||
}
|
||||
196
node_modules/consolidated-events/__tests__/TargetEventHandlers-test.js
generated
vendored
Normal file
196
node_modules/consolidated-events/__tests__/TargetEventHandlers-test.js
generated
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
import TargetEventHandlers from '../src/TargetEventHandlers';
|
||||
|
||||
class MockTarget {
|
||||
constructor() {
|
||||
this.addEventListener = jest.fn();
|
||||
this.removeEventListener = jest.fn();
|
||||
}
|
||||
}
|
||||
|
||||
describe('#add()', () => {
|
||||
it('adds a single event listener to the target the first time', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const listener = () => {};
|
||||
eventHandlers.add('scroll', listener);
|
||||
|
||||
expect(target.addEventListener).toHaveBeenCalledTimes(1);
|
||||
expect(target.addEventListener)
|
||||
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
|
||||
});
|
||||
|
||||
it('does not add an event listener to the target the second time', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const listener = () => {};
|
||||
const listener2 = () => {};
|
||||
eventHandlers.add('scroll', listener);
|
||||
eventHandlers.add('scroll', listener2);
|
||||
|
||||
expect(target.addEventListener).toHaveBeenCalledTimes(1);
|
||||
expect(target.addEventListener)
|
||||
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
|
||||
});
|
||||
|
||||
it('adds an event listener for each set of options', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const listener = () => {};
|
||||
const listener2 = () => {};
|
||||
eventHandlers.add('scroll', listener);
|
||||
eventHandlers.add('scroll', listener2, { passive: true });
|
||||
|
||||
expect(target.addEventListener).toHaveBeenCalledTimes(2);
|
||||
expect(target.addEventListener)
|
||||
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
|
||||
expect(target.addEventListener)
|
||||
.toHaveBeenCalledWith('scroll', jasmine.any(Function), { passive: true });
|
||||
});
|
||||
|
||||
it('adds an event listener for each event type', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const listener = () => {};
|
||||
const listener2 = () => {};
|
||||
eventHandlers.add('scroll', listener);
|
||||
eventHandlers.add('resize', listener2);
|
||||
|
||||
expect(target.addEventListener).toHaveBeenCalledTimes(2);
|
||||
expect(target.addEventListener)
|
||||
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
|
||||
expect(target.addEventListener)
|
||||
.toHaveBeenCalledWith('resize', jasmine.any(Function), undefined);
|
||||
});
|
||||
|
||||
it('returns an unsubscribe function', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const remove = eventHandlers.add('scroll', () => {});
|
||||
|
||||
expect(typeof remove).toBe('function');
|
||||
});
|
||||
|
||||
it('unsubscribe deletes the event listener when the only handler is removed', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const remove = eventHandlers.add('scroll', () => {});
|
||||
remove();
|
||||
|
||||
expect(target.removeEventListener).toHaveBeenCalledTimes(1);
|
||||
expect(target.removeEventListener)
|
||||
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
|
||||
});
|
||||
|
||||
it('unsubscribe does not throw when called twice', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const remove = eventHandlers.add('scroll', () => {});
|
||||
remove();
|
||||
|
||||
expect(remove).not.toThrow();
|
||||
});
|
||||
|
||||
it('unsubscribe does not delete the event listener when there are more handlers left', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const remove = eventHandlers.add('scroll', () => {});
|
||||
eventHandlers.add('scroll', () => {});
|
||||
remove();
|
||||
|
||||
expect(target.removeEventListener).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('unsubscribe called multiple times does not delete the event listener when there are more handlers left', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const remove = eventHandlers.add('scroll', () => {});
|
||||
eventHandlers.add('scroll', () => {});
|
||||
remove();
|
||||
remove();
|
||||
|
||||
expect(target.removeEventListener).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('unsubscribe deletes the event listener when all handlers are removed', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const remove = eventHandlers.add('scroll', () => {});
|
||||
const remove2 = eventHandlers.add('scroll', () => {});
|
||||
remove();
|
||||
remove2();
|
||||
|
||||
expect(target.removeEventListener).toHaveBeenCalledTimes(1);
|
||||
expect(target.removeEventListener)
|
||||
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
|
||||
});
|
||||
|
||||
it('unsubscribe handles different options separately', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const remove = eventHandlers.add('scroll', () => {});
|
||||
const remove2 = eventHandlers.add('scroll', () => {}, { passive: true });
|
||||
remove();
|
||||
remove2();
|
||||
|
||||
expect(target.removeEventListener).toHaveBeenCalledTimes(2);
|
||||
expect(target.removeEventListener)
|
||||
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
|
||||
expect(target.removeEventListener)
|
||||
.toHaveBeenCalledWith('scroll', jasmine.any(Function), { passive: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('#handleEvent', () => {
|
||||
it('calls each handler', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const handlers = [jest.fn(), jest.fn(), jest.fn()];
|
||||
handlers.forEach((handler) => {
|
||||
eventHandlers.add('scroll', handler);
|
||||
});
|
||||
const event = {};
|
||||
eventHandlers.handleEvent('scroll', undefined, event);
|
||||
|
||||
handlers.forEach((handler) => {
|
||||
expect(handler).toHaveBeenCalledTimes(1);
|
||||
expect(handler).toHaveBeenCalledWith(event);
|
||||
});
|
||||
});
|
||||
|
||||
it('calls each handler even when one is removed when called', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
|
||||
let remove;
|
||||
const firstHandler = jest.fn(() => remove());
|
||||
remove = eventHandlers.add('scroll', firstHandler);
|
||||
|
||||
const secondHandler = jest.fn();
|
||||
eventHandlers.add('scroll', secondHandler);
|
||||
|
||||
const event = {};
|
||||
eventHandlers.handleEvent('scroll', undefined, event);
|
||||
|
||||
expect(firstHandler).toHaveBeenCalledTimes(1);
|
||||
expect(firstHandler).toHaveBeenCalledWith(event);
|
||||
|
||||
expect(secondHandler).toHaveBeenCalledTimes(1);
|
||||
expect(secondHandler).toHaveBeenCalledWith(event);
|
||||
});
|
||||
|
||||
it('calls each handler with options', () => {
|
||||
const target = new MockTarget();
|
||||
const eventHandlers = new TargetEventHandlers(target);
|
||||
const handlers = [jest.fn(), jest.fn(), jest.fn()];
|
||||
handlers.forEach((handler) => {
|
||||
eventHandlers.add('scroll', handler, { passive: true });
|
||||
});
|
||||
const event = {};
|
||||
eventHandlers.handleEvent('scroll', { passive: true }, event);
|
||||
|
||||
handlers.forEach((handler) => {
|
||||
expect(handler).toHaveBeenCalledTimes(1);
|
||||
expect(handler).toHaveBeenCalledWith(event);
|
||||
});
|
||||
});
|
||||
});
|
||||
97
node_modules/consolidated-events/__tests__/canUsePassiveEventListeners-test.js
generated
vendored
Normal file
97
node_modules/consolidated-events/__tests__/canUsePassiveEventListeners-test.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
import wrap from 'jest-wrap';
|
||||
|
||||
let canUsePassiveEventListeners;
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
canUsePassiveEventListeners = require('../src/canUsePassiveEventListeners').default; // eslint-disable-line global-require
|
||||
});
|
||||
|
||||
describe('when not canUseDOM', () => {
|
||||
beforeEach(() => {
|
||||
jest.mock('../src/canUseDOM', () => ({ default: false }));
|
||||
});
|
||||
|
||||
it('returns false', () => {
|
||||
expect(canUsePassiveEventListeners()).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns false multiple times', () => {
|
||||
expect(canUsePassiveEventListeners()).toEqual(false);
|
||||
expect(canUsePassiveEventListeners()).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
wrap()
|
||||
.withGlobal('window', () => ({
|
||||
addEventListener() {},
|
||||
removeEventListener() {},
|
||||
}))
|
||||
.describe('when canUseDOM', () => {
|
||||
beforeEach(() => {
|
||||
jest.mock('../src/canUseDOM', () => ({ default: true }));
|
||||
});
|
||||
|
||||
wrap()
|
||||
.withOverride(() => window, 'addEventListener', () => null)
|
||||
.describe('when addEventListener is not present', () => {
|
||||
it('returns false', () => {
|
||||
expect(canUsePassiveEventListeners()).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns false multiple times', () => {
|
||||
expect(canUsePassiveEventListeners()).toEqual(false);
|
||||
expect(canUsePassiveEventListeners()).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
wrap()
|
||||
.withOverrides(() => window, () => ({
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: null,
|
||||
}))
|
||||
.describe('when removeEventListener is not present', () => {
|
||||
it('returns false', () => {
|
||||
expect(canUsePassiveEventListeners()).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns false multiple times', () => {
|
||||
expect(canUsePassiveEventListeners()).toEqual(false);
|
||||
expect(canUsePassiveEventListeners()).toEqual(false);
|
||||
});
|
||||
|
||||
it('does not call addEventListener', () => {
|
||||
canUsePassiveEventListeners();
|
||||
expect(window.addEventListener).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
wrap()
|
||||
.withOverrides(() => window, () => ({
|
||||
addEventListener: jest.fn(),
|
||||
}))
|
||||
.describe('when addEventListener and removeEventListener are present', () => {
|
||||
it('calls addEventListener', () => {
|
||||
canUsePassiveEventListeners();
|
||||
expect(window.addEventListener).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
wrap()
|
||||
.withOverride(
|
||||
() => window,
|
||||
'addEventListener',
|
||||
() => jest.fn((event, listener, options) => options.passive /* invoke a getter */),
|
||||
)
|
||||
.describe('when "passive" property is accessed', () => {
|
||||
it('returns true', () => {
|
||||
expect(canUsePassiveEventListeners()).toEqual(true);
|
||||
expect(window.addEventListener).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('is memoized', () => {
|
||||
expect(canUsePassiveEventListeners()).toEqual(true);
|
||||
expect(canUsePassiveEventListeners()).toEqual(true);
|
||||
expect(window.addEventListener).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
71
node_modules/consolidated-events/__tests__/eventOptionsKey-test.js
generated
vendored
Normal file
71
node_modules/consolidated-events/__tests__/eventOptionsKey-test.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
import eventOptionsKey from '../src/eventOptionsKey';
|
||||
|
||||
it('treats undefined and false the same', () => {
|
||||
expect(eventOptionsKey(undefined))
|
||||
.toBe(eventOptionsKey(false));
|
||||
});
|
||||
|
||||
it('treats false and empty objects the same', () => {
|
||||
expect(eventOptionsKey(false))
|
||||
.toBe(eventOptionsKey({}));
|
||||
});
|
||||
|
||||
it('treats empty objects and true differently', () => {
|
||||
expect(eventOptionsKey({}))
|
||||
.not.toBe(eventOptionsKey(true));
|
||||
});
|
||||
|
||||
it('treats empty objects and a good option differently', () => {
|
||||
expect(eventOptionsKey({}))
|
||||
.not.toBe(eventOptionsKey({ capture: true }));
|
||||
});
|
||||
|
||||
it('treats true and a good option differently', () => {
|
||||
expect(eventOptionsKey(true))
|
||||
.not.toBe(eventOptionsKey({ capture: true }));
|
||||
});
|
||||
|
||||
it('treats capture and passive differently', () => {
|
||||
expect(eventOptionsKey({ capture: true }))
|
||||
.not.toBe(eventOptionsKey({ passive: true }));
|
||||
});
|
||||
|
||||
it('treats capture and only differently', () => {
|
||||
expect(eventOptionsKey({ capture: true }))
|
||||
.not.toBe(eventOptionsKey({ only: true }));
|
||||
});
|
||||
|
||||
it('treats passive and only differently', () => {
|
||||
expect(eventOptionsKey({ passive: true }))
|
||||
.not.toBe(eventOptionsKey({ only: true }));
|
||||
});
|
||||
|
||||
it('treats capture/passive differently from capture', () => {
|
||||
expect(eventOptionsKey({ capture: true, passive: true }))
|
||||
.not.toBe(eventOptionsKey({ capture: true }));
|
||||
});
|
||||
|
||||
it('treats capture/once differently from capture', () => {
|
||||
expect(eventOptionsKey({ capture: true, once: true }))
|
||||
.not.toBe(eventOptionsKey({ capture: true }));
|
||||
});
|
||||
|
||||
it('treats capture/once differently from capture/passive', () => {
|
||||
expect(eventOptionsKey({ capture: true, once: true }))
|
||||
.not.toBe(eventOptionsKey({ capture: true, passive: true }));
|
||||
});
|
||||
|
||||
it('treats capture/passive/once differently from capture/passive', () => {
|
||||
expect(eventOptionsKey({ capture: true, passive: true, once: true }))
|
||||
.not.toBe(eventOptionsKey({ capture: true, passive: true }));
|
||||
});
|
||||
|
||||
it('treats capture/passive/once differently from capture/once', () => {
|
||||
expect(eventOptionsKey({ capture: true, passive: true, once: true }))
|
||||
.not.toBe(eventOptionsKey({ capture: true, once: true }));
|
||||
});
|
||||
|
||||
it('does not care about the order of options', () => {
|
||||
expect(eventOptionsKey({ capture: true, passive: true, once: true }))
|
||||
.toBe(eventOptionsKey({ passive: true, once: true, capture: true }));
|
||||
});
|
||||
34
node_modules/consolidated-events/__tests__/index-test.js
generated
vendored
Normal file
34
node_modules/consolidated-events/__tests__/index-test.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
import { addEventListener } from '../src';
|
||||
import TargetEventHandlers from '../src/TargetEventHandlers';
|
||||
|
||||
class MockTarget {
|
||||
constructor() {
|
||||
this.addEventListener = jest.fn();
|
||||
}
|
||||
}
|
||||
|
||||
const EVENT_HANDLERS_KEY = '__consolidated_events_handlers__';
|
||||
|
||||
describe('addEventListener()', () => {
|
||||
it('initializes an instance of TargetEventHandlers on new targets', () => {
|
||||
const target = new MockTarget();
|
||||
addEventListener(target, 'scroll', () => {});
|
||||
expect(target[EVENT_HANDLERS_KEY]).toBeInstanceOf(TargetEventHandlers);
|
||||
expect(target[EVENT_HANDLERS_KEY].target).toBe(target);
|
||||
});
|
||||
|
||||
it('normalizes event options', () => {
|
||||
const target = new MockTarget();
|
||||
addEventListener(target, 'scroll', () => {}, { capture: true });
|
||||
|
||||
expect(target.addEventListener)
|
||||
.toHaveBeenCalledWith('scroll', jasmine.any(Function), true);
|
||||
});
|
||||
|
||||
it('returns an unsubscribe function', () => {
|
||||
const target = new MockTarget();
|
||||
const remove = addEventListener(target, 'scroll', () => {}, { capture: true });
|
||||
|
||||
expect(typeof remove).toBe('function');
|
||||
});
|
||||
});
|
||||
52
node_modules/consolidated-events/__tests__/normalizeEventOptions-test.js
generated
vendored
Normal file
52
node_modules/consolidated-events/__tests__/normalizeEventOptions-test.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/* eslint-disable import/first */
|
||||
jest.mock('../src/canUsePassiveEventListeners');
|
||||
|
||||
import canUsePassiveEventListeners from '../src/canUsePassiveEventListeners';
|
||||
import normalizeEventOptions from '../src/normalizeEventOptions';
|
||||
|
||||
it('is undefined when event options are undefined', () => {
|
||||
expect(normalizeEventOptions(undefined)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('is undefined when event options are null', () => {
|
||||
expect(normalizeEventOptions(null)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('is undefined when event options are false', () => {
|
||||
expect(normalizeEventOptions(false)).toBe(undefined);
|
||||
});
|
||||
|
||||
describe('when able to use passive event listeners', () => {
|
||||
beforeEach(() => {
|
||||
canUsePassiveEventListeners.mockImplementation(() => true);
|
||||
});
|
||||
|
||||
it('passes the eventOptions object through', () => {
|
||||
expect(normalizeEventOptions({ passive: true }))
|
||||
.toEqual({ passive: true });
|
||||
|
||||
expect(normalizeEventOptions({ capture: true }))
|
||||
.toEqual({ capture: true });
|
||||
|
||||
expect(normalizeEventOptions({ capture: true, passive: true }))
|
||||
.toEqual({ capture: true, passive: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('when not able to use passive event listeners', () => {
|
||||
beforeEach(() => {
|
||||
canUsePassiveEventListeners.mockImplementation(() => false);
|
||||
});
|
||||
|
||||
it('is true when the capture option is on', () => {
|
||||
expect(normalizeEventOptions({ capture: true })).toBe(true);
|
||||
});
|
||||
|
||||
it('is false when the capture option is off', () => {
|
||||
expect(normalizeEventOptions({ capture: false })).toBe(false);
|
||||
});
|
||||
|
||||
it('is false when the capture option is missing', () => {
|
||||
expect(normalizeEventOptions({ passive: true })).toBe(false);
|
||||
});
|
||||
});
|
||||
206
node_modules/consolidated-events/lib/index.esm.js
generated
vendored
Normal file
206
node_modules/consolidated-events/lib/index.esm.js
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
var CAN_USE_DOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
|
||||
|
||||
// Adapted from Modernizr
|
||||
// https://github.com/Modernizr/Modernizr/blob/acb3f0d9/feature-detects/dom/passiveeventlisteners.js#L26-L37
|
||||
function testPassiveEventListeners() {
|
||||
if (!CAN_USE_DOM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!window.addEventListener || !window.removeEventListener || !Object.defineProperty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var supportsPassiveOption = false;
|
||||
try {
|
||||
var opts = Object.defineProperty({}, 'passive', {
|
||||
// eslint-disable-next-line getter-return
|
||||
get: function () {
|
||||
function get() {
|
||||
supportsPassiveOption = true;
|
||||
}
|
||||
|
||||
return get;
|
||||
}()
|
||||
});
|
||||
var noop = function noop() {};
|
||||
window.addEventListener('testPassiveEventSupport', noop, opts);
|
||||
window.removeEventListener('testPassiveEventSupport', noop, opts);
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
return supportsPassiveOption;
|
||||
}
|
||||
|
||||
var memoized = void 0;
|
||||
|
||||
function canUsePassiveEventListeners() {
|
||||
if (memoized === undefined) {
|
||||
memoized = testPassiveEventListeners();
|
||||
}
|
||||
return memoized;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* eslint-disable no-bitwise */
|
||||
|
||||
/**
|
||||
* Generate a unique key for any set of event options
|
||||
*/
|
||||
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).
|
||||
var capture = normalizedEventOptions.capture << 0;
|
||||
var passive = normalizedEventOptions.passive << 1;
|
||||
var once = normalizedEventOptions.once << 2;
|
||||
return capture + passive + once;
|
||||
}
|
||||
|
||||
function ensureCanMutateNextEventHandlers(eventHandlers) {
|
||||
if (eventHandlers.handlers === eventHandlers.nextHandlers) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
eventHandlers.nextHandlers = eventHandlers.handlers.slice();
|
||||
}
|
||||
}
|
||||
|
||||
function TargetEventHandlers(target) {
|
||||
this.target = target;
|
||||
this.events = {};
|
||||
}
|
||||
|
||||
TargetEventHandlers.prototype.getEventHandlers = function () {
|
||||
function getEventHandlers(eventName, options) {
|
||||
var key = String(eventName) + ' ' + String(eventOptionsKey(options));
|
||||
|
||||
if (!this.events[key]) {
|
||||
this.events[key] = {
|
||||
handlers: [],
|
||||
handleEvent: undefined
|
||||
};
|
||||
this.events[key].nextHandlers = this.events[key].handlers;
|
||||
}
|
||||
|
||||
return this.events[key];
|
||||
}
|
||||
|
||||
return getEventHandlers;
|
||||
}();
|
||||
|
||||
TargetEventHandlers.prototype.handleEvent = function () {
|
||||
function handleEvent(eventName, options, event) {
|
||||
var eventHandlers = this.getEventHandlers(eventName, options);
|
||||
eventHandlers.handlers = eventHandlers.nextHandlers;
|
||||
eventHandlers.handlers.forEach(function (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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return handleEvent;
|
||||
}();
|
||||
|
||||
TargetEventHandlers.prototype.add = function () {
|
||||
function add(eventName, listener, options) {
|
||||
var _this = this;
|
||||
|
||||
// options has already been normalized at this point.
|
||||
var 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);
|
||||
|
||||
var isSubscribed = true;
|
||||
var unsubscribe = function () {
|
||||
function unsubscribe() {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
|
||||
isSubscribed = false;
|
||||
|
||||
ensureCanMutateNextEventHandlers(eventHandlers);
|
||||
var 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;
|
||||
}();
|
||||
return unsubscribe;
|
||||
}
|
||||
|
||||
return add;
|
||||
}();
|
||||
|
||||
var EVENT_HANDLERS_KEY = '__consolidated_events_handlers__';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-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);
|
||||
}
|
||||
var normalizedEventOptions = normalizeEventOptions(options);
|
||||
return target[EVENT_HANDLERS_KEY].add(eventName, listener, normalizedEventOptions);
|
||||
}
|
||||
|
||||
export { addEventListener };
|
||||
210
node_modules/consolidated-events/lib/index.js
generated
vendored
Normal file
210
node_modules/consolidated-events/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
var CAN_USE_DOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
|
||||
|
||||
// Adapted from Modernizr
|
||||
// https://github.com/Modernizr/Modernizr/blob/acb3f0d9/feature-detects/dom/passiveeventlisteners.js#L26-L37
|
||||
function testPassiveEventListeners() {
|
||||
if (!CAN_USE_DOM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!window.addEventListener || !window.removeEventListener || !Object.defineProperty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var supportsPassiveOption = false;
|
||||
try {
|
||||
var opts = Object.defineProperty({}, 'passive', {
|
||||
// eslint-disable-next-line getter-return
|
||||
get: function () {
|
||||
function get() {
|
||||
supportsPassiveOption = true;
|
||||
}
|
||||
|
||||
return get;
|
||||
}()
|
||||
});
|
||||
var noop = function noop() {};
|
||||
window.addEventListener('testPassiveEventSupport', noop, opts);
|
||||
window.removeEventListener('testPassiveEventSupport', noop, opts);
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
return supportsPassiveOption;
|
||||
}
|
||||
|
||||
var memoized = void 0;
|
||||
|
||||
function canUsePassiveEventListeners() {
|
||||
if (memoized === undefined) {
|
||||
memoized = testPassiveEventListeners();
|
||||
}
|
||||
return memoized;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* eslint-disable no-bitwise */
|
||||
|
||||
/**
|
||||
* Generate a unique key for any set of event options
|
||||
*/
|
||||
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).
|
||||
var capture = normalizedEventOptions.capture << 0;
|
||||
var passive = normalizedEventOptions.passive << 1;
|
||||
var once = normalizedEventOptions.once << 2;
|
||||
return capture + passive + once;
|
||||
}
|
||||
|
||||
function ensureCanMutateNextEventHandlers(eventHandlers) {
|
||||
if (eventHandlers.handlers === eventHandlers.nextHandlers) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
eventHandlers.nextHandlers = eventHandlers.handlers.slice();
|
||||
}
|
||||
}
|
||||
|
||||
function TargetEventHandlers(target) {
|
||||
this.target = target;
|
||||
this.events = {};
|
||||
}
|
||||
|
||||
TargetEventHandlers.prototype.getEventHandlers = function () {
|
||||
function getEventHandlers(eventName, options) {
|
||||
var key = String(eventName) + ' ' + String(eventOptionsKey(options));
|
||||
|
||||
if (!this.events[key]) {
|
||||
this.events[key] = {
|
||||
handlers: [],
|
||||
handleEvent: undefined
|
||||
};
|
||||
this.events[key].nextHandlers = this.events[key].handlers;
|
||||
}
|
||||
|
||||
return this.events[key];
|
||||
}
|
||||
|
||||
return getEventHandlers;
|
||||
}();
|
||||
|
||||
TargetEventHandlers.prototype.handleEvent = function () {
|
||||
function handleEvent(eventName, options, event) {
|
||||
var eventHandlers = this.getEventHandlers(eventName, options);
|
||||
eventHandlers.handlers = eventHandlers.nextHandlers;
|
||||
eventHandlers.handlers.forEach(function (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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return handleEvent;
|
||||
}();
|
||||
|
||||
TargetEventHandlers.prototype.add = function () {
|
||||
function add(eventName, listener, options) {
|
||||
var _this = this;
|
||||
|
||||
// options has already been normalized at this point.
|
||||
var 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);
|
||||
|
||||
var isSubscribed = true;
|
||||
var unsubscribe = function () {
|
||||
function unsubscribe() {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
|
||||
isSubscribed = false;
|
||||
|
||||
ensureCanMutateNextEventHandlers(eventHandlers);
|
||||
var 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;
|
||||
}();
|
||||
return unsubscribe;
|
||||
}
|
||||
|
||||
return add;
|
||||
}();
|
||||
|
||||
var EVENT_HANDLERS_KEY = '__consolidated_events_handlers__';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-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);
|
||||
}
|
||||
var normalizedEventOptions = normalizeEventOptions(options);
|
||||
return target[EVENT_HANDLERS_KEY].add(eventName, listener, normalizedEventOptions);
|
||||
}
|
||||
|
||||
exports.addEventListener = addEventListener;
|
||||
54
node_modules/consolidated-events/package.json
generated
vendored
Normal file
54
node_modules/consolidated-events/package.json
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"name": "consolidated-events",
|
||||
"version": "2.0.2",
|
||||
"description": "Manage multiple event handlers using few event listeners",
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.esm.js",
|
||||
"scripts": {
|
||||
"build": "npm run clean && npm run build:js",
|
||||
"build:js": "rollup -c",
|
||||
"check-changelog": "expr $(git status --porcelain 2>/dev/null| grep \"^\\s*M.*CHANGELOG.md\" | wc -l) >/dev/null || (echo 'Please edit CHANGELOG.md' && exit 1)",
|
||||
"check-only-changelog-changed": "(expr $(git status --porcelain 2>/dev/null| grep -v \"CHANGELOG.md\" | wc -l) >/dev/null && echo 'Only CHANGELOG.md may have uncommitted changes' && exit 1) || exit 0",
|
||||
"clean": "rimraf lib",
|
||||
"lint": "eslint .",
|
||||
"postversion": "git commit package.json CHANGELOG.md -m \"Version $npm_package_version\" && npm run tag && git push && git push --tags && npm publish",
|
||||
"prepublish": "in-publish && safe-publish-latest && npm run build || not-in-publish",
|
||||
"pretest": "npm run --silent lint",
|
||||
"tag": "git tag v$npm_package_version",
|
||||
"test": "npm run --silent test:js",
|
||||
"test:js": "jest",
|
||||
"test:js:watch": "jest --watch",
|
||||
"version:major": "npm --no-git-tag-version version major",
|
||||
"version:minor": "npm --no-git-tag-version version minor",
|
||||
"version:patch": "npm --no-git-tag-version version patch"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/lencioni/consolidated-events.git"
|
||||
},
|
||||
"keywords": [
|
||||
"events",
|
||||
"performance"
|
||||
],
|
||||
"author": "Joe Lencioni <joe.lencioni@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/lencioni/consolidated-events/issues"
|
||||
},
|
||||
"homepage": "https://github.com/lencioni/consolidated-events#readme",
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-jest": "^23.0.1",
|
||||
"babel-preset-airbnb": "^2.5.1",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-airbnb-base": "^12.1.0",
|
||||
"eslint-plugin-import": "^2.12.0",
|
||||
"in-publish": "^2.0.0",
|
||||
"jest": "^23.1.0",
|
||||
"jest-wrap": "^1.4.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"rollup": "^0.60.7",
|
||||
"rollup-plugin-babel": "^3.0.4",
|
||||
"safe-publish-latest": "^1.1.1"
|
||||
}
|
||||
}
|
||||
22
node_modules/consolidated-events/rollup.config.js
generated
vendored
Normal file
22
node_modules/consolidated-events/rollup.config.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import babel from 'rollup-plugin-babel';
|
||||
import pkg from './package.json';
|
||||
|
||||
export default {
|
||||
input: 'src/index.js',
|
||||
output: [
|
||||
{
|
||||
file: pkg.main,
|
||||
format: 'cjs',
|
||||
},
|
||||
{
|
||||
file: pkg.module,
|
||||
format: 'esm',
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
babel({
|
||||
babelrc: false,
|
||||
presets: [['airbnb', { modules: false }]],
|
||||
}),
|
||||
],
|
||||
};
|
||||
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