156 lines
4.3 KiB
JavaScript
156 lines
4.3 KiB
JavaScript
|
|
/**
|
||
|
|
* Universal Events implementation
|
||
|
|
* Browser: Uses EventTarget API
|
||
|
|
* Node.js: Uses built-in events module
|
||
|
|
*/
|
||
|
|
import { isBrowser, isNode } from '../utils/environment.js';
|
||
|
|
let nodeEvents = null;
|
||
|
|
// Dynamic import for Node.js events (only in Node.js environment)
|
||
|
|
if (isNode()) {
|
||
|
|
try {
|
||
|
|
nodeEvents = await import('events');
|
||
|
|
}
|
||
|
|
catch {
|
||
|
|
// Ignore import errors in non-Node environments
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Browser implementation using EventTarget
|
||
|
|
*/
|
||
|
|
class BrowserEventEmitter extends EventTarget {
|
||
|
|
constructor() {
|
||
|
|
super(...arguments);
|
||
|
|
this.listeners = new Map();
|
||
|
|
}
|
||
|
|
on(event, listener) {
|
||
|
|
if (!this.listeners.has(event)) {
|
||
|
|
this.listeners.set(event, new Set());
|
||
|
|
}
|
||
|
|
this.listeners.get(event).add(listener);
|
||
|
|
const handler = (e) => {
|
||
|
|
const customEvent = e;
|
||
|
|
listener(...(customEvent.detail || []));
|
||
|
|
};
|
||
|
|
listener.__handler = handler;
|
||
|
|
this.addEventListener(event, handler);
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
off(event, listener) {
|
||
|
|
const eventListeners = this.listeners.get(event);
|
||
|
|
if (eventListeners) {
|
||
|
|
eventListeners.delete(listener);
|
||
|
|
const handler = listener.__handler;
|
||
|
|
if (handler) {
|
||
|
|
this.removeEventListener(event, handler);
|
||
|
|
delete listener.__handler;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
emit(event, ...args) {
|
||
|
|
const customEvent = new CustomEvent(event, { detail: args });
|
||
|
|
this.dispatchEvent(customEvent);
|
||
|
|
const eventListeners = this.listeners.get(event);
|
||
|
|
return eventListeners ? eventListeners.size > 0 : false;
|
||
|
|
}
|
||
|
|
once(event, listener) {
|
||
|
|
const onceListener = (...args) => {
|
||
|
|
this.off(event, onceListener);
|
||
|
|
listener(...args);
|
||
|
|
};
|
||
|
|
return this.on(event, onceListener);
|
||
|
|
}
|
||
|
|
removeAllListeners(event) {
|
||
|
|
if (event) {
|
||
|
|
const eventListeners = this.listeners.get(event);
|
||
|
|
if (eventListeners) {
|
||
|
|
for (const listener of eventListeners) {
|
||
|
|
this.off(event, listener);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
for (const [eventName] of this.listeners) {
|
||
|
|
this.removeAllListeners(eventName);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
listenerCount(event) {
|
||
|
|
const eventListeners = this.listeners.get(event);
|
||
|
|
return eventListeners ? eventListeners.size : 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Node.js implementation using events.EventEmitter
|
||
|
|
*/
|
||
|
|
class NodeEventEmitter {
|
||
|
|
constructor() {
|
||
|
|
this.emitter = new nodeEvents.EventEmitter();
|
||
|
|
}
|
||
|
|
on(event, listener) {
|
||
|
|
this.emitter.on(event, listener);
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
off(event, listener) {
|
||
|
|
this.emitter.off(event, listener);
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
emit(event, ...args) {
|
||
|
|
return this.emitter.emit(event, ...args);
|
||
|
|
}
|
||
|
|
once(event, listener) {
|
||
|
|
this.emitter.once(event, listener);
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
removeAllListeners(event) {
|
||
|
|
this.emitter.removeAllListeners(event);
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
listenerCount(event) {
|
||
|
|
return this.emitter.listenerCount(event);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Universal EventEmitter class
|
||
|
|
*/
|
||
|
|
export class EventEmitter {
|
||
|
|
constructor() {
|
||
|
|
if (isBrowser()) {
|
||
|
|
this.emitter = new BrowserEventEmitter();
|
||
|
|
}
|
||
|
|
else if (isNode() && nodeEvents) {
|
||
|
|
this.emitter = new NodeEventEmitter();
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
this.emitter = new BrowserEventEmitter();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
on(event, listener) {
|
||
|
|
this.emitter.on(event, listener);
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
off(event, listener) {
|
||
|
|
this.emitter.off(event, listener);
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
emit(event, ...args) {
|
||
|
|
return this.emitter.emit(event, ...args);
|
||
|
|
}
|
||
|
|
once(event, listener) {
|
||
|
|
this.emitter.once(event, listener);
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
removeAllListeners(event) {
|
||
|
|
this.emitter.removeAllListeners(event);
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
listenerCount(event) {
|
||
|
|
return this.emitter.listenerCount(event);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Named export for compatibility
|
||
|
|
export { EventEmitter as default };
|
||
|
|
// Re-export Node.js EventEmitter class if available
|
||
|
|
export const NodeEventEmitterClass = nodeEvents?.EventEmitter || null;
|
||
|
|
//# sourceMappingURL=events.js.map
|