eventtarget

js/globals/eventtarget.ts

Event, CustomEvent, and EventTarget globals.

Pure JS implementation of the WHATWG EventTarget interface: https://dom.spec.whatwg.org/#interface-eventtarget

Scope: flat dispatch only (no DOM tree). All events fire at AT_TARGET. The bubbles and composed flags are stored but have no propagation effect — Fino has no parent node traversal.

Spec conformance: - addEventListener is idempotent for the same (callback, capture) pair - once: true auto-removes the listener after first invocation - signal option auto-removes the listener when the AbortSignal aborts - passive listeners cannot cancel the event via preventDefault() - dispatchEvent throws if the event is currently being dispatched - Listener errors are swallowed and do not prevent later listeners from firing. Fino does not currently report these through a browser-style global error event.

Example

const target = new EventTarget();
target.addEventListener('ready', () => console.log('ready'), { once: true });

target.dispatchEvent(new Event('ready'));
target.dispatchEvent(new Event('ready'));

Types

type EventCallback = ((event: Event) => void) | { handleEvent(event: Event): void; }

Event listener callback accepted by EventTarget.addEventListener().

A listener can be a function or an object with a handleEvent() method. Both forms receive the dispatched Event instance.

const listener: EventCallback = (event) => console.log(event.type);
target.addEventListener('ready', listener);

Interfaces

interface AddEventListenerOptions {

Options accepted by EventTarget.addEventListener().

capture participates in listener identity for compatibility, but Fino has no DOM tree and dispatches every event at the target. once removes the listener after the first call. passive prevents preventDefault() from canceling the event while that listener runs. signal removes the listener when the supplied AbortSignal aborts.

target.addEventListener('message', onMessage, {
  once: true,
  signal: controller.signal,
});

Properties

capture?: boolean

Participates in listener identity (a listener is uniquely keyed by callback plus capture flag) but has no traversal effect in Fino's flat dispatch.

once?: boolean

When true, the listener is removed automatically after its first invocation.

passive?: boolean

When true, preventDefault() is a no-op while this listener runs, so the listener cannot cancel the event.

signal?: AbortSignal

An AbortSignal that removes the listener when it aborts. A signal that is already aborted skips registration entirely; passing null throws.

Classes

class Event {

Flat-dispatch implementation of the WHATWG Event interface.

Fino does not have a DOM tree, so every dispatch runs at AT_TARGET and composedPath() returns either the dispatch target or an empty array.

const event = new Event('ready', { cancelable: true });
event.type; // "ready"

Static Properties

static NONE

Event phase constant for no active dispatch.

Event.NONE; // 0
static CAPTURING_PHASE

Event phase constant for DOM capture.

Fino stores the value for compatibility but never enters this phase because there is no parent tree.

Event.CAPTURING_PHASE; // 1
static AT_TARGET

Event phase constant used while dispatching to the target.

Event.AT_TARGET; // 2
static BUBBLING_PHASE

Event phase constant for DOM bubbling.

The value is exposed for compatibility, but Fino never bubbles events.

Event.BUBBLING_PHASE; // 3

Constructors

constructor(type: string, eventInitDict?: { bubbles?: boolean; cancelable?: boolean; composed?: boolean; })

Create an Event with optional bubbles, cancelable, and composed flags.

The type argument is required and string-coerced. The flags are stored for compatibility, but bubbles and composed do not cause propagation in this flat EventTarget implementation.

const event = new Event('submit', { cancelable: true });
event.cancelable; // true

Getters

get type()

Event type supplied at construction or initEvent().

new Event('message').type; // "message"
get bubbles()

Whether the event was constructed with bubbles: true.

This flag is stored only; Fino has no bubbling tree.

new Event('x', { bubbles: true }).bubbles; // true
get cancelable()

Whether preventDefault() can set defaultPrevented.

Passive listeners cannot cancel even when this is true.

new Event('x', { cancelable: true }).cancelable; // true
get composed()

Whether the event was constructed with composed: true.

This value is exposed for compatibility and has no propagation effect.

new Event('x', { composed: true }).composed; // true
get defaultPrevented()

Whether preventDefault() has successfully canceled the event.

It remains false for non-cancelable events and inside passive listeners.

const event = new Event('x', { cancelable: true });
event.preventDefault();
event.defaultPrevented; // true
get target()

EventTarget currently dispatching or last dispatched this event.

The target is null before dispatch and preserved after dispatch, matching browser behavior.

const target = new EventTarget();
const event = new Event('x');
target.dispatchEvent(event);
event.target === target; // true
get currentTarget()

EventTarget whose listener is currently running.

This is set during dispatch and reset to null after dispatch completes.

const target = new EventTarget();
target.addEventListener('x', (event) => console.log(event.currentTarget));
get eventPhase()

Current dispatch phase.

Fino reports AT_TARGET during listener execution and NONE otherwise.

const event = new Event('x');
event.eventPhase; // Event.NONE
get timeStamp()

Monotonic timestamp captured when the Event was created.

Uses performance.now() when available, otherwise Date.now().

const event = new Event('x');
typeof event.timeStamp; // "number"
get isTrusted()

Whether the event was generated by the runtime rather than user code.

Events created with new Event(...) are untrusted. Built-in APIs may mark their own spec-defined events as trusted before dispatch.

new Event('x').isTrusted; // false

Methods

preventDefault()

Mark a cancelable event as default-prevented.

Calling this on a non-cancelable event or from a passive listener has no effect.

const event = new Event('x', { cancelable: true });
event.preventDefault();
stopPropagation()

Request that event propagation stop after the current target.

With flat dispatch this flag is stored for compatibility but there are no ancestor targets to skip.

const event = new Event('x');
event.stopPropagation();
stopImmediatePropagation()

Stop dispatching any remaining listeners for this event.

During dispatch this prevents later listeners on the same EventTarget from running.

const target = new EventTarget();
target.addEventListener('x', (event) => event.stopImmediatePropagation());
composedPath()

Return the composed path for this event.

Because there is no DOM tree, the path is [target] while dispatching and an empty array outside dispatch.

const event = new Event('x');
event.composedPath(); // []

class CustomEvent extends Event {

Event subclass that carries arbitrary detail data.

The detail value defaults to null and is stored by reference.

const event = new CustomEvent('data', { detail: { id: 1 } });
event.detail.id; // 1

Constructors

constructor(type: string, eventInitDict?: { bubbles?: boolean; cancelable?: boolean; composed?: boolean; detail?: unknown; })

Create a CustomEvent with optional detail.

Event flags are passed through to Event. Missing detail becomes null.

const event = new CustomEvent('x', { detail: 'payload' });
event.detail; // "payload"

Getters

get detail()

Application-defined payload for the custom event.

new CustomEvent('x').detail; // null

Methods

initCustomEvent( type: string, bubbles: boolean = false, cancelable: boolean = false, detail: unknown = null ): void

Legacy initializer for CustomEvent instances.

Calls during dispatch are ignored. The method updates type, bubbles, cancelable, and detail.

const event = new CustomEvent('old');
event.initCustomEvent('new', false, false, 123);

class EventTarget {

WHATWG EventTarget with flat listener dispatch.

Listener registration is idempotent for the same callback and capture flag. Listener exceptions are swallowed so later listeners still run; this runtime does not surface those exceptions through a global error event.

const target = new EventTarget();
target.addEventListener('ready', () => console.log('ready'));
target.dispatchEvent(new Event('ready'));

Constructors

constructor()

Create an EventTarget with an empty listener registry.

const target = new EventTarget();

Methods

addEventListener( type: string, callback: EventCallback | null, options?: boolean | AddEventListenerOptions ): void

Register an event listener.

Registration is idempotent: adding the same callback with the same capture flag again is a no-op. Null callbacks and objects without a handleEvent method are silently ignored, and a signal that is already aborted skips registration entirely. The once option removes the listener after its first invocation, passive prevents preventDefault() from canceling the event while that listener runs, and signal removes the listener when the AbortSignal aborts.

Throws if signal is explicitly null rather than an AbortSignal or undefined — even when the callback is also null.

const target = new EventTarget();
target.addEventListener('tick', (event) => console.log(event.type), { once: true });
removeEventListener(type: string, callback: EventCallback, options?: boolean | { capture?: boolean; }): void

Remove a previously registered event listener.

The type, callback, and capture flag must match the original registration. Unknown listeners are ignored.

const target = new EventTarget();
const fn = () => {};
target.addEventListener('x', fn);
target.removeEventListener('x', fn);
dispatchEvent(event: Event): boolean

Dispatch an Event synchronously to matching listeners.

Listeners run in registration order against a snapshot taken at dispatch time: listeners added during dispatch do not run for the current event, while listeners removed during dispatch are skipped. Exceptions thrown by listeners are swallowed so later listeners still run. Returns false only when a cancelable event was canceled via preventDefault().

Throws if the argument is not an Event instance, or if the event is already being dispatched.

const target = new EventTarget();
const ok = target.dispatchEvent(new Event('x', { cancelable: true }));