Skip to content

Commit 0bf0a9e

Browse files
committed
Update 1.0.0-Dev.10
1 parent 732c5e7 commit 0bf0a9e

File tree

8 files changed

+184
-41
lines changed

8 files changed

+184
-41
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ yarn.lock
5959
*.env.test.local
6060
*.env.production.local
6161
src/copyright.js
62+
jest.config.js
63+
jest.setup.js
6264

6365
# Developer-specific folder
6466
dev/

README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,23 @@
1-
# Event Engine
1+
<h1 align="center">
2+
<picture>
3+
<source media="(prefers-color-scheme: dark)" srcset="./docs/media/jamesgober-logo-dark.png">
4+
<img width="72" height="72" alt="Official brand mark and logo of James Gober. Image shows JG stylish initials encased in a hexagon outline." src="./docs/media/jamesgober-logo.png">
5+
</picture>
6+
<br>
7+
<b>EventEngine</b>
8+
<br>
9+
<sup>
10+
<small>JavaScript Library</small>
11+
</sup>
12+
<br>
13+
</h1>
14+
15+
&nbsp;
16+
17+
18+
## Licence & copyright
19+
The **EventEngine** JavaScript library is an open-source project licensed under the **MIT** license.
20+
21+
All rights not explicitly granted in the MIT license are reserved. View the [LICENSE](https://github.com/jamesgober/EventEngine/blob/main/LICENSE) file that was provided with this source code for more information.
22+
23+
Copyright &copy; 2024 James Gober (https://jamesgober.com).

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.0-Dev.9
1+
1.0.0-Dev.10

package.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "eventengine",
33
"version": "1.0.0",
44
"description": "EventEngine: A lightweight, extensible JavaScript library for managing DOM events with features like namespacing, throttling, debouncing, observables, debugging tools, and a focus on performance and flexibility.",
5-
"main": "dist/eventengine.min.js",
5+
"main": "dist/events.min.js",
66
"scripts": {
77
"test": "jest",
88
"build": "rollup -c",
@@ -35,7 +35,18 @@
3535
"devDependencies": {
3636
"@rollup/plugin-terser": "^0.4.4",
3737
"eslint": "^8.0.0",
38-
"jest": "^29.0.0",
38+
"jest": "^29.7.0",
39+
"jest-environment-jsdom": "^29.7.0",
40+
"jsdom": "^25.0.1",
3941
"rollup": "^3.20.0"
42+
},
43+
"jest": {
44+
"testEnvironment": "jest-environment-jsdom",
45+
"setupFilesAfterEnv": [
46+
"<rootDir>/jest.setup.js"
47+
]
48+
},
49+
"dependencies": {
50+
"util": "^0.12.5"
4051
}
4152
}

src/EventUtils.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* EventUtils - Utility methods for throttling, debouncing, and other event-related operations.
3+
*/
4+
const EventUtils = {
5+
/**
6+
* Creates a throttled version of the given function.
7+
*
8+
* @param {Function} func - The function to throttle.
9+
* @param {number} limit - The time limit in milliseconds.
10+
* @returns {Function} - The throttled function.
11+
*/
12+
throttle: function (func, limit) {
13+
let lastCall = 0;
14+
return function (...args) {
15+
const now = Date.now();
16+
if (now - lastCall >= limit) {
17+
lastCall = now;
18+
func.apply(this, args);
19+
}
20+
};
21+
},
22+
23+
/**
24+
* Creates a debounced version of the given function.
25+
*
26+
* @param {Function} func - The function to debounce.
27+
* @param {number} delay - The delay in milliseconds.
28+
* @returns {Function} - The debounced function.
29+
*/
30+
debounce: function (func, delay) {
31+
let timeoutId;
32+
return function (...args) {
33+
clearTimeout(timeoutId);
34+
timeoutId = setTimeout(() => func.apply(this, args), delay);
35+
};
36+
},
37+
38+
/**
39+
* Executes an event callback with additional safety and debugging.
40+
*
41+
* @param {Event} event - The event object.
42+
* @param {Function} callback - The callback function.
43+
*/
44+
doEvent: function (event, callback) {
45+
try {
46+
callback(event);
47+
} catch (error) {
48+
console.error('Error executing event callback:', error);
49+
}
50+
},
51+
};
52+
// Export the entire EventUtils object
53+
module.exports = EventUtils;
Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
/* _ _
1+
/*
2+
_ _
23
| | (_)
34
_____ _____ _ __ | |_ ___ _ __ __ _ _ _ __ ___
45
/ _ \ \ / / _ \ '_ \| __/ / _ \ '_ \ / _` | | '_ \ / _ \
@@ -7,6 +8,7 @@
78
__/ | JS LIBRARY
89
|___/
910
*/
11+
1012
/*!
1113
* Event Engine - A High-Performance JavaScript DOM Events Library
1214
*
@@ -25,6 +27,16 @@
2527
* Roles: Developer, Architect, Maintainer, Designer, Project Lead, Author
2628
*/
2729

30+
31+
32+
const isNode = typeof window === 'undefined';
33+
const context = isNode ? {} : window; // Fallback to an empty object in Node.js
34+
35+
// Mock addEventListener in Node.js environment
36+
if (isNode) {
37+
context.addEventListener = () => {}; // No-op
38+
}
39+
2840
/**
2941
* Events Module
3042
* Provides an API for handling browser events with features like namespacing,
@@ -49,10 +61,18 @@
4961
global.Events = factory(global);
5062
}
5163

52-
}(typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : this, function (window) {
64+
}(typeof window !== 'undefined' ? window : global, function (window) {
5365
'use strict';
5466

55-
const { throttle, debounce, doEvent } = EventUtils; // Import utility methods
67+
// import { throttle, debounce, doEvent } from './EventUtils';
68+
const EventUtils = require('./EventUtils'); // Adjust the path as needed
69+
70+
// Destructure the utilities
71+
const { throttle, debounce, doEvent } = EventUtils;
72+
73+
if (isNode) {
74+
console.warn('Events library is running in a Node.js environment. DOM operations are disabled.');
75+
}
5676

5777
/**
5878
* Container for all event handling functionalities.
@@ -64,6 +84,7 @@
6484
* @private
6585
*/
6686
const liveEvents = new Map();
87+
6788
/**
6889
* Stores debugging and analytics data.
6990
* @private
@@ -84,6 +105,12 @@
84105
*/
85106
const groups = new Map();
86107

108+
// Refactor selector validation
109+
const isValidSelector = selector =>
110+
selector instanceof HTMLElement ||
111+
selector === window ||
112+
selector === document;
113+
87114
/**
88115
* Enables debugging mode for event tracking.
89116
*/
@@ -147,56 +174,47 @@
147174
* @param {boolean} [once=false] - If true, the listener is removed after the first execution.
148175
* @param {string} [group=''] - Optional group to organize listeners.
149176
*/
150-
Events.add = function (types, selector, callback, options = {}, namespace = '', once = false, group = '') {
177+
Events.add = function (types, target, callback, options = {}, namespace = '', once = false, group = '') {
178+
if (!(target instanceof context.HTMLElement || target === context || target === context.document)) {
179+
throw new Error('Invalid target. Must be an instance of HTMLElement, Window, or Document.');
180+
}
181+
151182
types.split(',').forEach(type => {
152183
type = type.trim();
153-
let handler = callback;
154-
155-
if (options.throttle) handler = throttle(callback, options.throttle);
156-
if (options.debounce) handler = debounce(callback, options.debounce);
157184

158-
const listener = {
159-
selector,
160-
callback: handler,
161-
originalCallback: callback,
162-
namespace,
163-
options,
164-
once,
165-
priority: options.priority || 0,
166-
};
185+
const handler = options.throttle
186+
? throttle(callback, options.throttle)
187+
: options.debounce
188+
? debounce(callback, options.debounce)
189+
: callback;
167190

168191
if (!liveEvents.has(type)) liveEvents.set(type, []);
169-
liveEvents.get(type).push(listener);
192+
liveEvents.get(type).push({ target, callback: handler });
193+
194+
target.addEventListener(type, handler, { capture: options.capture || false });
170195

171196
if (group) {
172197
if (!groups.has(group)) groups.set(group, []);
173-
groups.get(group).push({ type, listener });
198+
groups.get(group).push({ type, target, handler });
174199
}
175-
176-
window.addEventListener(type, function eventHandlerWrapper(event) {
177-
handler.call(selector, event);
178-
if (once) {
179-
Events.remove(type, selector, callback, namespace);
180-
window.removeEventListener(type, eventHandlerWrapper, options.capture || false);
181-
}
182-
}, { capture: options.capture || false, passive: options.passive || false });
183200
});
184201
};
185202

186203
/**
187204
* Removes an event listener or all listeners for a type/namespace.
188205
*/
189-
Events.remove = function (types, selector, callback, namespace = '') {
206+
/**
207+
* Removes an event listener.
208+
*/
209+
Events.remove = function (types, target, callback) {
190210
types.split(',').forEach(type => {
191-
const listeners = liveEvents.get(type) || [];
192-
const updatedListeners = listeners.filter(listener =>
193-
!(listener.selector === selector && listener.originalCallback === callback && (!namespace || listener.namespace === namespace))
194-
);
195-
196-
if (updatedListeners.length) liveEvents.set(type, updatedListeners);
197-
else {
198-
liveEvents.delete(type);
199-
window.removeEventListener(type, eventHandler, true);
211+
target.removeEventListener(type.trim(), callback);
212+
213+
if (liveEvents.has(type)) {
214+
liveEvents.set(
215+
type,
216+
liveEvents.get(type).filter(e => e.target !== target || e.callback !== callback)
217+
);
200218
}
201219
});
202220
};

tests/events.test.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const Events = require('../src/events');
2+
3+
describe('Events Module', () => {
4+
beforeEach(() => {
5+
document.body.innerHTML = ''; // Reset DOM
6+
});
7+
8+
test('should add and trigger an event', () => {
9+
const div = document.createElement('div');
10+
document.body.appendChild(div);
11+
12+
const mockCallback = jest.fn();
13+
Events.add('click', div, mockCallback);
14+
15+
const event = new CustomEvent('click');
16+
div.dispatchEvent(event);
17+
18+
expect(mockCallback).toHaveBeenCalledTimes(1);
19+
});
20+
21+
test('should remove an event listener', () => {
22+
const div = document.createElement('div');
23+
document.body.appendChild(div);
24+
25+
const mockCallback = jest.fn();
26+
Events.add('click', div, mockCallback);
27+
Events.remove('click', div, mockCallback);
28+
29+
const event = new CustomEvent('click');
30+
div.dispatchEvent(event);
31+
32+
expect(mockCallback).not.toHaveBeenCalled();
33+
});
34+
});

tests/sample.test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
test('adds 1 + 2 to equal 3', () => {
2+
expect(1 + 2).toBe(3);
3+
});

0 commit comments

Comments
 (0)