Skip to content

Commit b86f88b

Browse files
committed
V 0.0.3 Changes:
* More types fixes - event options must be optional, package.json needs a reference to the `index.d.ts` * changed the file structure * the script needed more checks when removing listeners * minor demo improvements
1 parent af62520 commit b86f88b

14 files changed

+166
-154
lines changed

demo/demo-component.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@ class DemoComponent {
1212
compMap.set(this.element, this);
1313
}
1414
handleResize({ type }){
15-
this.element.innerText = this.constructor.name + ' div#' + this.id + ', triggered: "' + type+ '", new Window size:' + window.innerWidth;
15+
this.element.innerText = this.constructor.name + ' div#' + this.id + ',\ntriggered: "' + type + '",\nwindow.innerWidth:' + window.innerWidth;
1616
}
1717
/** @param {Event} e */
1818
handleClick(e){
19-
const { target, type, pageX } = e;
19+
const { target, type, pageX, pageY } = e;
2020
if (target && target.closest('button') !== null ) {
2121
e.preventDefault();
2222
e.stopImmediatePropagation();
2323
}
2424
console.log('"click" on `handleClick` should be `propagationStopped` if the target is a button, otherwise is only executes once and removes itself');
2525

26-
this.element.innerText = this.constructor.name + ' div#' + this.id + ', triggered: "' + type + '", pageX: ' + pageX;
26+
this.element.innerText = this.constructor.name + ' div#' + this.id + ',\ntriggered: "' + type + '",\npageX: ' + pageX + ', pageY: ' + pageY;
2727
}
2828
handleScroll({ type }){
29-
this.element.innerText = this.constructor.name + ' div#' + this.id + ', triggered: "' + type + '", scrollY: ' + window.scrollY;
29+
this.element.innerText = this.constructor.name + ' div#' + this.id + ',\ntriggered: "' + type + '",\nscrollY: ' + window.scrollY;
3030
}
3131
_addListeners() {
3232
EventListener.on(document, 'click', this.handleClick, { once: true });

dist/event-listener-es5.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*!
2-
* EventListener v0.0.2 (https://github.com/thednp/event-listener.js)
2+
* EventListener v0.0.3 (https://github.com/thednp/event-listener.js)
33
* Modern event listener for efficient applications.
44
* Copyright 2022 © thednp
55
* Licensed under MIT (https://github.com/thednp/event-listener.js/blob/master/LICENSE)
@@ -49,7 +49,7 @@
4949
* @param {Element | HTMLElement | Window | Document} element
5050
* @param {string} eventType
5151
* @param {EventListenerObject['handleEvent']} listener
52-
* @param {AddEventListenerOptions} options
52+
* @param {AddEventListenerOptions=} options
5353
*/
5454
var addListener = function (element, eventType, listener, options) {
5555
// get element listeners first
@@ -84,21 +84,22 @@
8484
* @param {Element | HTMLElement | Window | Document} element
8585
* @param {string} eventType
8686
* @param {EventListenerObject['handleEvent']} listener
87-
* @param {AddEventListenerOptions} options
87+
* @param {AddEventListenerOptions=} options
8888
*/
8989
var removeListener = function (element, eventType, listener, options) {
9090
// get listener first
9191
var oneEventMap = EventRegistry[eventType];
9292
var oneElementMap = oneEventMap && oneEventMap.get(element);
93+
var savedOptions = oneElementMap && oneElementMap.get(listener);
9394
// also recover initial options
94-
var ref = oneElementMap
95-
? oneElementMap.get(listener)
95+
var ref = savedOptions !== undefined
96+
? savedOptions
9697
: { options: options };
9798
var eventOptions = ref.options;
9899

99100
// unsubscribe second, remove from registry
100101
if (oneElementMap && oneElementMap.has(listener)) { oneElementMap.delete(listener); }
101-
if (!oneElementMap || !oneElementMap.size) { oneEventMap.delete(element); }
102+
if (oneEventMap && (!oneElementMap || !oneElementMap.size)) { oneEventMap.delete(element); }
102103
if (!oneEventMap || !oneEventMap.size) { delete EventRegistry[eventType]; }
103104

104105
// remove listener last

dist/event-listener-es5.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/event-listener.esm.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*!
2-
* EventListener v0.0.2 (https://github.com/thednp/event-listener.js)
2+
* EventListener v0.0.3 (https://github.com/thednp/event-listener.js)
33
* Modern event listener for efficient applications.
44
* Copyright 2022 © thednp
55
* Licensed under MIT (https://github.com/thednp/event-listener.js/blob/master/LICENSE)
@@ -41,7 +41,7 @@ function globalListener(e) {
4141
* @param {Element | HTMLElement | Window | Document} element
4242
* @param {string} eventType
4343
* @param {EventListenerObject['handleEvent']} listener
44-
* @param {AddEventListenerOptions} options
44+
* @param {AddEventListenerOptions=} options
4545
*/
4646
const addListener = (element, eventType, listener, options) => {
4747
// get element listeners first
@@ -76,20 +76,21 @@ const addListener = (element, eventType, listener, options) => {
7676
* @param {Element | HTMLElement | Window | Document} element
7777
* @param {string} eventType
7878
* @param {EventListenerObject['handleEvent']} listener
79-
* @param {AddEventListenerOptions} options
79+
* @param {AddEventListenerOptions=} options
8080
*/
8181
const removeListener = (element, eventType, listener, options) => {
8282
// get listener first
8383
const oneEventMap = EventRegistry[eventType];
8484
const oneElementMap = oneEventMap && oneEventMap.get(element);
85+
const savedOptions = oneElementMap && oneElementMap.get(listener);
8586
// also recover initial options
86-
const { options: eventOptions } = oneElementMap
87-
? oneElementMap.get(listener)
87+
const { options: eventOptions } = savedOptions !== undefined
88+
? savedOptions
8889
: { options };
8990

9091
// unsubscribe second, remove from registry
9192
if (oneElementMap && oneElementMap.has(listener)) oneElementMap.delete(listener);
92-
if (!oneElementMap || !oneElementMap.size) oneEventMap.delete(element);
93+
if (oneEventMap && (!oneElementMap || !oneElementMap.size)) oneEventMap.delete(element);
9394
if (!oneEventMap || !oneEventMap.size) delete EventRegistry[eventType];
9495

9596
// remove listener last

dist/event-listener.esm.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/event-listener.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*!
2-
* EventListener v0.0.2 (https://github.com/thednp/event-listener.js)
2+
* EventListener v0.0.3 (https://github.com/thednp/event-listener.js)
33
* Modern event listener for efficient applications.
44
* Copyright 2022 © thednp
55
* Licensed under MIT (https://github.com/thednp/event-listener.js/blob/master/LICENSE)
@@ -47,7 +47,7 @@
4747
* @param {Element | HTMLElement | Window | Document} element
4848
* @param {string} eventType
4949
* @param {EventListenerObject['handleEvent']} listener
50-
* @param {AddEventListenerOptions} options
50+
* @param {AddEventListenerOptions=} options
5151
*/
5252
const addListener = (element, eventType, listener, options) => {
5353
// get element listeners first
@@ -82,20 +82,21 @@
8282
* @param {Element | HTMLElement | Window | Document} element
8383
* @param {string} eventType
8484
* @param {EventListenerObject['handleEvent']} listener
85-
* @param {AddEventListenerOptions} options
85+
* @param {AddEventListenerOptions=} options
8686
*/
8787
const removeListener = (element, eventType, listener, options) => {
8888
// get listener first
8989
const oneEventMap = EventRegistry[eventType];
9090
const oneElementMap = oneEventMap && oneEventMap.get(element);
91+
const savedOptions = oneElementMap && oneElementMap.get(listener);
9192
// also recover initial options
92-
const { options: eventOptions } = oneElementMap
93-
? oneElementMap.get(listener)
93+
const { options: eventOptions } = savedOptions !== undefined
94+
? savedOptions
9495
: { options };
9596

9697
// unsubscribe second, remove from registry
9798
if (oneElementMap && oneElementMap.has(listener)) oneElementMap.delete(listener);
98-
if (!oneElementMap || !oneElementMap.size) oneEventMap.delete(element);
99+
if (oneEventMap && (!oneElementMap || !oneElementMap.size)) oneEventMap.delete(element);
99100
if (!oneEventMap || !oneEventMap.size) delete EventRegistry[eventType];
100101

101102
// remove listener last

dist/event-listener.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
{
22
"name": "event-listener.js",
33
"author": "thednp",
4-
"version": "0.0.2",
4+
"version": "0.0.3",
55
"description": "Modern event listener for efficient applications.",
66
"license": "MIT",
77
"homepage": "https://github.com/thednp/event-listener.js",
88
"main": "dist/event-listener.min.js",
99
"module": "dist/event-listener.esm.js",
1010
"jsnext": "src/index.js",
11+
"types": "types/index.d.ts",
1112
"repository": {
1213
"type": "git",
1314
"url": "git+https://github.com/thednp/event-listener.js.git"

src/event-listener.js

Lines changed: 2 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,5 @@
1-
/** @type {Record<string, any>} */
2-
const EventRegistry = {};
3-
4-
/**
5-
* The global event listener.
6-
*
7-
* @this {Element | HTMLElement | Window | Document}
8-
* @param {Event} e
9-
* @returns {void}
10-
*/
11-
function globalListener(e) {
12-
const that = this;
13-
const { type } = e;
14-
const oneEvMap = EventRegistry[type] ? [...EventRegistry[type]] : [];
15-
16-
oneEvMap.forEach((elementsMap) => {
17-
const [element, listenersMap] = elementsMap;
18-
[...listenersMap].forEach((listenerMap) => {
19-
if (element === that) {
20-
const [listener, options] = listenerMap;
21-
listener.apply(element, [e]);
22-
23-
if (options && options.once) {
24-
removeListener(element, type, listener, options);
25-
}
26-
}
27-
});
28-
});
29-
}
30-
31-
/**
32-
* Register a new listener with its options and attach the `globalListener`
33-
* to the target if this is the first listener.
34-
*
35-
* @param {Element | HTMLElement | Window | Document} element
36-
* @param {string} eventType
37-
* @param {EventListenerObject['handleEvent']} listener
38-
* @param {AddEventListenerOptions} options
39-
*/
40-
const addListener = (element, eventType, listener, options) => {
41-
// get element listeners first
42-
if (!EventRegistry[eventType]) {
43-
EventRegistry[eventType] = new Map();
44-
}
45-
const oneEventMap = EventRegistry[eventType];
46-
47-
if (!oneEventMap.has(element)) {
48-
oneEventMap.set(element, new Map());
49-
}
50-
const oneElementMap = oneEventMap.get(element);
51-
52-
// get listeners size
53-
const { size } = oneElementMap;
54-
55-
// register listener with its options
56-
if (oneElementMap) {
57-
oneElementMap.set(listener, options);
58-
}
59-
60-
// add listener last
61-
if (!size) {
62-
element.addEventListener(eventType, globalListener, options);
63-
}
64-
};
65-
66-
/**
67-
* Remove a listener from registry and detach the `globalListener`
68-
* if no listeners are found in the registry.
69-
*
70-
* @param {Element | HTMLElement | Window | Document} element
71-
* @param {string} eventType
72-
* @param {EventListenerObject['handleEvent']} listener
73-
* @param {AddEventListenerOptions} options
74-
*/
75-
const removeListener = (element, eventType, listener, options) => {
76-
// get listener first
77-
const oneEventMap = EventRegistry[eventType];
78-
const oneElementMap = oneEventMap && oneEventMap.get(element);
79-
// also recover initial options
80-
const { options: eventOptions } = oneElementMap
81-
? oneElementMap.get(listener)
82-
: { options };
83-
84-
// unsubscribe second, remove from registry
85-
if (oneElementMap && oneElementMap.has(listener)) oneElementMap.delete(listener);
86-
if (!oneElementMap || !oneElementMap.size) oneEventMap.delete(element);
87-
if (!oneEventMap || !oneEventMap.size) delete EventRegistry[eventType];
88-
89-
// remove listener last
90-
if (!oneElementMap || !oneElementMap.size) {
91-
element.removeEventListener(eventType, globalListener, eventOptions);
92-
}
93-
};
1+
import EventRegistry from './registry';
2+
import globalListener, { addListener, removeListener } from './globalListener';
943

954
/**
965
* Advanced event listener based on subscribe / publish pattern.

src/globalListener.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import EventRegistry from './registry';
2+
3+
/**
4+
* The global event listener.
5+
*
6+
* @this {Element | HTMLElement | Window | Document}
7+
* @param {Event} e
8+
* @returns {void}
9+
*/
10+
export default function globalListener(e) {
11+
const that = this;
12+
const { type } = e;
13+
const oneEvMap = EventRegistry[type] ? [...EventRegistry[type]] : [];
14+
15+
oneEvMap.forEach((elementsMap) => {
16+
const [element, listenersMap] = elementsMap;
17+
[...listenersMap].forEach((listenerMap) => {
18+
if (element === that) {
19+
const [listener, options] = listenerMap;
20+
listener.apply(element, [e]);
21+
22+
if (options && options.once) {
23+
removeListener(element, type, listener, options);
24+
}
25+
}
26+
});
27+
});
28+
}
29+
30+
/**
31+
* Register a new listener with its options and attach the `globalListener`
32+
* to the target if this is the first listener.
33+
*
34+
* @param {Element | HTMLElement | Window | Document} element
35+
* @param {string} eventType
36+
* @param {EventListenerObject['handleEvent']} listener
37+
* @param {AddEventListenerOptions=} options
38+
*/
39+
export const addListener = (element, eventType, listener, options) => {
40+
// get element listeners first
41+
if (!EventRegistry[eventType]) {
42+
EventRegistry[eventType] = new Map();
43+
}
44+
const oneEventMap = EventRegistry[eventType];
45+
46+
if (!oneEventMap.has(element)) {
47+
oneEventMap.set(element, new Map());
48+
}
49+
const oneElementMap = oneEventMap.get(element);
50+
51+
// get listeners size
52+
const { size } = oneElementMap;
53+
54+
// register listener with its options
55+
if (oneElementMap) {
56+
oneElementMap.set(listener, options);
57+
}
58+
59+
// add listener last
60+
if (!size) {
61+
element.addEventListener(eventType, globalListener, options);
62+
}
63+
};
64+
65+
/**
66+
* Remove a listener from registry and detach the `globalListener`
67+
* if no listeners are found in the registry.
68+
*
69+
* @param {Element | HTMLElement | Window | Document} element
70+
* @param {string} eventType
71+
* @param {EventListenerObject['handleEvent']} listener
72+
* @param {AddEventListenerOptions=} options
73+
*/
74+
export const removeListener = (element, eventType, listener, options) => {
75+
// get listener first
76+
const oneEventMap = EventRegistry[eventType];
77+
const oneElementMap = oneEventMap && oneEventMap.get(element);
78+
const savedOptions = oneElementMap && oneElementMap.get(listener);
79+
// also recover initial options
80+
const { options: eventOptions } = savedOptions !== undefined
81+
? savedOptions
82+
: { options };
83+
84+
// unsubscribe second, remove from registry
85+
if (oneElementMap && oneElementMap.has(listener)) oneElementMap.delete(listener);
86+
if (oneEventMap && (!oneElementMap || !oneElementMap.size)) oneEventMap.delete(element);
87+
if (!oneEventMap || !oneEventMap.size) delete EventRegistry[eventType];
88+
89+
// remove listener last
90+
if (!oneElementMap || !oneElementMap.size) {
91+
element.removeEventListener(eventType, globalListener, eventOptions);
92+
}
93+
};

0 commit comments

Comments
 (0)