clarity-js
Version:
An analytics library that uses web page interactions to generate aggregated insights
54 lines (45 loc) • 1.87 kB
text/typescript
import { BrowserEvent, Constant } from "@clarity-types/core";
import api from "./api";
import measure from "./measure";
let bindings: Map<EventTarget, BrowserEvent[]> = new Map();
export function bind(target: EventTarget, event: string, listener: EventListener, capture: boolean = false, passive: boolean = true): void {
listener = measure(listener) as EventListener;
// Wrapping following lines inside try / catch to cover edge cases where we might try to access an inaccessible element.
// E.g. Iframe may start off as same-origin but later turn into cross-origin, and the following lines will throw an exception.
try {
target[api(Constant.AddEventListener)](event, listener, { capture, passive });
if (!has(target)) {
bindings.set(target, []);
}
bindings.get(target).push({ event, listener, options: { capture, passive } });
} catch {
/* do nothing */
}
}
export function reset(): void {
// Walk through existing list of bindings and remove them all
bindings.forEach((bindingsPerTarget: BrowserEvent[], target: EventTarget) => {
resetByTarget(bindingsPerTarget, target);
});
bindings = new Map();
}
export function unbind(target: EventTarget) {
if (!has(target)) {
return;
}
resetByTarget(bindings.get(target), target);
}
export function has(target: EventTarget): boolean {
return bindings.has(target);
}
function resetByTarget(bindingsPerTarget: BrowserEvent[], target: EventTarget): void {
bindingsPerTarget.forEach((binding) => {
// Wrapping inside try / catch to avoid situations where the element may be destroyed before we get a chance to unbind
try {
target[api(Constant.RemoveEventListener)](binding.event, binding.listener, { capture: binding.options.capture, passive: binding.options.passive });
} catch {
/* do nothing */
}
});
bindings.delete(target);
}