Skip to content

Commit

Permalink
Removing event listeners from memory(kamranahmedse#452)
Browse files Browse the repository at this point in the history
  • Loading branch information
k-ivan committed Dec 1, 2023
1 parent 0889e01 commit 6b92e1b
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 31 deletions.
98 changes: 69 additions & 29 deletions src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,37 @@ function onKeyup(e: KeyboardEvent) {
}
}

type EventCallback = (pointer: MouseEvent | PointerEvent) => void
type EventHandlers = {
[key: string]: {
clickedListener?: EventCallback,
disabledlistener?: EventCallback
}
}
const driverEventHandlers: EventHandlers = {}

const listenerWrapper = (
element?: Element,
listener?: EventCallback,
shouldPreventDefault?: (target: HTMLElement) => boolean
) => {
return function (e: MouseEvent | PointerEvent) {
// event and extra_data will be available here
const target = e.target as HTMLElement;
if (!element?.contains(target)) {
return;
}

if (!shouldPreventDefault || shouldPreventDefault(target)) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
}

listener?.(e);
};
};

/**
* Attaches click handler to the elements created by driver.js. It makes
* sure to give the listener the first chance to handle the event, and
Expand All @@ -76,41 +107,49 @@ function onKeyup(e: KeyboardEvent) {
*/
export function onDriverClick(
element: Element,
listener: (pointer: MouseEvent | PointerEvent) => void,
listener: EventCallback,
shouldPreventDefault?: (target: HTMLElement) => boolean
) {
const listenerWrapper = (e: MouseEvent | PointerEvent, listener?: (pointer: MouseEvent | PointerEvent) => void) => {
const target = e.target as HTMLElement;
if (!element.contains(target)) {
return;
}

if (!shouldPreventDefault || shouldPreventDefault(target)) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
}
// event handlers
const clickedListener = listenerWrapper(element, listener, shouldPreventDefault);
const disabledlistener = listenerWrapper();

// save event handlers so we can remove events later
// use the element ID as the object key
// save event handlers as values
driverEventHandlers[element.id] = { clickedListener }

if (element.classList.contains('driver-popover')) {
// save event handlers so we can remove events later
// use the element ID as the object key
// save event handlers as values
driverEventHandlers[element.id].disabledlistener = disabledlistener

// Events to disable
document.addEventListener("pointerdown", disabledlistener, true);
document.addEventListener("mousedown", disabledlistener, true);
document.addEventListener("pointerup", disabledlistener, true);
document.addEventListener("mouseup", disabledlistener, true);
}
// Actual click handler
document.addEventListener('click', clickedListener, true)
}

listener?.(e);
};
export function destroyDriverEvents (element: Element) {
// extract the saved event handlers to delete these events
const { clickedListener, disabledlistener } = driverEventHandlers[element.id];

// We want to be the absolute first one to hear about the event
const useCapture = true;
clickedListener && document.removeEventListener('click', clickedListener, true);

// Events to disable
document.addEventListener("pointerdown", listenerWrapper, useCapture);
document.addEventListener("mousedown", listenerWrapper, useCapture);
document.addEventListener("pointerup", listenerWrapper, useCapture);
document.addEventListener("mouseup", listenerWrapper, useCapture);
if (disabledlistener) {
document.removeEventListener("pointerdown", disabledlistener, true);
document.removeEventListener("mousedown", disabledlistener, true);
document.removeEventListener("pointerup", disabledlistener, true);
document.removeEventListener("mouseup", disabledlistener, true);
}

// Actual click handler
document.addEventListener(
"click",
e => {
listenerWrapper(e, listener);
},
useCapture
);
// clear driverEventHandlers
delete driverEventHandlers[element.id]
}

export function initEvents() {
Expand All @@ -122,6 +161,7 @@ export function initEvents() {

export function destroyEvents() {
window.removeEventListener("keyup", onKeyup);
window.removeEventListener("keydown", trapFocus);
window.removeEventListener("resize", requireRefresh);
window.removeEventListener("scroll", requireRefresh);
}
6 changes: 5 additions & 1 deletion src/overlay.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { easeInOutQuad } from "./utils";
import { onDriverClick } from "./events";
import { destroyDriverEvents, onDriverClick } from "./events";
import { emit } from "./emitter";
import { getConfig } from "./config";
import { getState, setState } from "./state";
Expand Down Expand Up @@ -112,6 +112,7 @@ function createOverlaySvg(stage: StageDefinition): SVGSVGElement {
const windowY = window.innerHeight;

const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.id = "driver-overlay";
svg.classList.add("driver-overlay", "driver-overlay-animated");

svg.setAttribute("viewBox", `0 0 ${windowX} ${windowY}`);
Expand Down Expand Up @@ -172,7 +173,10 @@ function generateStageSvgPathString(stage: StageDefinition) {

export function destroyOverlay() {
const overlaySvg = getState("__overlaySvg");

if (overlaySvg) {
// remove all events associated with the overlay
destroyDriverEvents(overlaySvg);
overlaySvg.remove();
}
}
8 changes: 7 additions & 1 deletion src/popover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { bringInView, getFocusableElements } from "./utils";
import { Config, DriverHook, getConfig } from "./config";
import { getState, setState, State } from "./state";
import { DriveStep } from "./driver";
import { onDriverClick } from "./events";
import { destroyDriverEvents, onDriverClick } from "./events";
import { emit } from "./emitter";

export type Side = "top" | "right" | "bottom" | "left" | "over";
Expand Down Expand Up @@ -55,6 +55,9 @@ export function hidePopover() {
return;
}

// remove all events associated with the popover
destroyDriverEvents(popover.wrapper)

popover.wrapper.style.display = "none";
}

Expand Down Expand Up @@ -668,5 +671,8 @@ export function destroyPopover() {
return;
}

// remove all events associated with the popover
destroyDriverEvents(popover.wrapper)

popover.wrapper.parentElement?.removeChild(popover.wrapper);
}

0 comments on commit 6b92e1b

Please sign in to comment.