Skip to content

TomokiMiyauci/get-event-listeners

Repository files navigation

get-event-listeners

Ponyfill for getEventListeners.

Install

deno.land:

import * as mod from "https://deno.land/x/get_event_listeners/mod.ts";

npm:

npm i @miyauci/get-event-listeners

Usage

updateEventListener function replaces addEventListener and removeEventListener in EventTarget.prototype with a proxy.

You can refer to the currently registered event listeners with return value.

import { updateEventListener } from "https://deno.land/x/get_event_listeners/mod.ts";
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

const getEventListeners = updateEventListener();

declare const target: EventTarget;
declare const handleClick: () => void;
target.addEventListener("click", handleClick);

assertEquals(getEventListeners(target), {
  click: [{
    type: "click",
    listener: handleClick,
    useCapture: false,
    once: false,
    passive: false,
  }],
});

Pure context

The updateEventListener has a side effect instead of being immediately available.

We provide a pure context builder with no side effects.

import { createContext } from "https://deno.land/x/get_event_listeners/mod.ts";
import {
  afterEach,
  beforeEach,
  describe,
} from "https://deno.land/std/testing/bdd.ts";

const { addEventListener, removeEventListener } = EventTarget.prototype;
const context = createContext({ addEventListener, removeEventListener });

describe("event listener monitoring", () => {
  beforeEach(() => {
    EventTarget.prototype.addEventListener = context.addEventListener;
    EventTarget.prototype.removeEventListener = context.removeEventListener;
  });

  afterEach(() => {
    EventTarget.prototype.addEventListener = addEventListener;
    EventTarget.prototype.removeEventListener = removeEventListener;
  });
});

Event listener equality

Event listeners are managed by WeakMap(called registry) throughout the realm.

Equivalence checks for event listener are performed, equivalent to addEventListener and removeEventListener.

  • addEventListener Add an event listener to the registry only if one of [type, listener, useCapture] is different from the existing one
  • removeEventListener Remove the event listener from the registry only if [type, listener, useCapture] match

Like addEventListener, you can be sure that duplicate listeners will not be registered in the registry either.

import { updateEventListener } from "https://deno.land/x/get_event_listeners/mod.ts";
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

const getEventListeners = updateEventListener();

declare const target: EventTarget;
declare const handleClick: () => void;
const expected = {
  click: [{
    type: "click",
    listener: handleClick,
    useCapture: false,
    once: false,
    passive: false,
  }, {
    type: "click",
    listener: handleClick,
    useCapture: true,
    once: false,
    passive: false,
  }],
};

target.addEventListener("click", handleClick);
target.addEventListener("click", handleClick, true);

assertEquals(getEventListeners(target), expected);

target.addEventListener("click", handleClick);
target.addEventListener("click", handleClick, true);
target.addEventListener("click", handleClick, { capture: true });
target.addEventListener("click", handleClick, { once: true });
target.addEventListener("click", handleClick, { passive: true });

assertEquals(getEventListeners(target), expected);

Compatibility

getEventListeners is based on Chrome Console Utilities API.

Safari provides similar functionality, but there is no type property on the return value of EventListener.

The DOM has also proposed adding a similar API to EventTarget.

API

See deno doc for all APIs.

Contributing

See contributing.

License

MIT © 2023 Tomoki Miyauchi