@virtualstate/app-history
Version:
Native JavaScript [app-history](https://github.com/WICG/app-history) implementation
54 lines (45 loc) • 2.07 kB
text/typescript
import { Event } from "./event"
import { isSignalEvent, isSignalHandled } from "./signal-event"
import { AbortError } from "../app-history-errors"
import {EventTargetListenersMatch, EventTargetListenersThis} from "./event-target-options"
import { EventTargetListeners } from "./event-target-listeners"
export interface SyncEventTarget extends EventTargetListeners {
new (thisValue?: unknown): SyncEventTarget;
dispatchEvent(event: Event): void | Promise<void>
}
export class SyncEventTarget extends EventTargetListeners implements SyncEventTarget {
readonly [EventTargetListenersThis]: unknown
constructor(thisValue: unknown = undefined) {
super();
this[EventTargetListenersThis] = thisValue
}
dispatchEvent(event: Event) {
const listeners = this[EventTargetListenersMatch]?.(event.type) ?? [];
// Don't even dispatch an aborted event
if (isSignalEvent(event) && event.signal.aborted) {
throw new AbortError();
}
for (let index = 0; index < listeners.length; index += 1) {
const descriptor = listeners[index];
// Remove the listener before invoking the callback
// This ensures that inside of the callback causes no more additional event triggers to this
// listener
if (descriptor.once) {
// by passing the descriptor as the options, we get an internal redirect
// that forces an instance level object equals, meaning
// we will only remove _this_ descriptor!
this.removeEventListener(descriptor.type, descriptor.callback, descriptor);
}
try {
descriptor.callback.call(this[EventTargetListenersThis] ?? this, event);
} catch (error) {
if (!isSignalHandled(event, error)) {
throw error;
}
}
if (isSignalEvent(event) && event.signal.aborted) {
throw new AbortError();
}
}
}
}