All files / sportident/src/utils events.ts

100% Statements 25/25
100% Branches 12/12
100% Functions 7/7
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 9337x               37x   110x       110x                                                     37x             84x 84x 84x       84x             23x 23x 23x 22x   23x       1x             110x 110x 110x 110x 53x 53x   1x 1x 1x     110x      
import * as errorUtils from './errors';
 
export interface IEvent<T extends string> {
    type?: T;
    target: unknown;
    defaultPrevented: boolean;
}
 
export class Event<T extends string> implements IEvent<T> {
    target: unknown;
    defaultPrevented = false;
 
    // eslint-disable-next-line no-useless-constructor
    constructor(
                public type?: T,
    // eslint-disable-next-line no-empty-function
    ) {}
}
 
export type EventCallback<T extends Event<string>> = (event: T) => void;
 
interface EventTypeDict {
    [type: string]: Event<string>;
}
 
export interface IEventTarget<T extends EventTypeDict> {
    addEventListener: <K extends keyof T>(
        type: K,
        callback: EventCallback<T[K]>,
    ) => void;
    removeEventListener: <K extends keyof T>(
        type: K,
        callback: EventCallback<T[K]>,
    ) => void;
    removeAllEventListeners: () => void;
    dispatchEvent: <K extends keyof T>(
        type: K,
        event: T[K],
    ) => void;
}
 
export class EventTarget<T extends EventTypeDict> implements IEventTarget<T> {
    private eventRegistry?: {[type: string]: EventCallback<Event<string>>[]};
 
    addEventListener<K extends keyof T>(
        type: K,
        callback: EventCallback<T[K]>,
    ): void {
        const eventRegistry = this.eventRegistry || {};
        const listeners = eventRegistry[type as string] || [];
        eventRegistry[type as string] = [
            ...listeners,
            callback as EventCallback<Event<string>>,
        ];
        this.eventRegistry = eventRegistry;
    }
 
    removeEventListener<K extends keyof T>(
        type: K,
        callback: EventCallback<T[K]>,
    ): void {
        const eventRegistry = this.eventRegistry || {};
        const listeners = eventRegistry[type as string] || [];
        eventRegistry[type as string] = listeners.filter(
            (listener: EventCallback<T[K]>) => listener !== callback,
        );
        this.eventRegistry = eventRegistry;
    }
 
    removeAllEventListeners(): void {
        this.eventRegistry = {};
    }
 
    dispatchEvent<K extends keyof T>(
        type: K,
        event: T[K],
    ): boolean {
        event.type = type as string;
        const eventRegistry = this.eventRegistry || {};
        const listeners = eventRegistry[type as string] || [];
        listeners.forEach((listener: EventCallback<T[K]>) => {
            try {
                listener(event);
            } catch (exc) {
                const err = errorUtils.getErrorOrThrow(exc);
                console.error(`Event Listener failed (${String(type)}): ${err.message}`);
                console.info(err.stack);
            }
        });
        return !event.defaultPrevented;
    }
}