Skip to content

Commit 68cda09

Browse files
authored
Merge pull request microsoft#158892 from microsoft/joh/crooked-tahr
joh/crooked tahr
2 parents 9628fab + 4c567d1 commit 68cda09

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

src/vs/base/browser/dom.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ import { withNullAsUndefined } from 'vs/base/common/types';
1919
import { URI } from 'vs/base/common/uri';
2020

2121
export function clearNode(node: HTMLElement): void {
22-
node.replaceChildren();
22+
while (node.firstChild) {
23+
node.firstChild.remove();
24+
}
2325
}
2426

2527
/**
@@ -29,20 +31,40 @@ export function isInDOM(node: Node | null): boolean {
2931
return node?.isConnected ?? false;
3032
}
3133

32-
export function addDisposableListener<K extends keyof GlobalEventHandlersEventMap>(node: EventTarget, type: K, handler: (event: GlobalEventHandlersEventMap[K]) => void, useCaptureOrOptions?: boolean | AddEventListenerOptions): IDisposable;
33-
export function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCaptureOrOptions?: boolean | AddEventListenerOptions): IDisposable;
34-
export function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCaptureOrOptions?: boolean | AddEventListenerOptions): IDisposable {
35-
let controller: AbortController | undefined = new AbortController();
34+
class DomListener implements IDisposable {
3635

37-
const opts: AddEventListenerOptions = typeof useCaptureOrOptions === 'boolean'
38-
? { capture: useCaptureOrOptions, signal: controller.signal }
39-
: { signal: controller.signal, ...(useCaptureOrOptions ?? {}) };
36+
private _handler: (e: any) => void;
37+
private _node: EventTarget;
38+
private readonly _type: string;
39+
private readonly _options: boolean | AddEventListenerOptions;
4040

41-
node.addEventListener(type, handler, opts);
42-
return toDisposable(() => {
43-
controller?.abort();
44-
controller = undefined;
45-
});
41+
constructor(node: EventTarget, type: string, handler: (e: any) => void, options?: boolean | AddEventListenerOptions) {
42+
this._node = node;
43+
this._type = type;
44+
this._handler = handler;
45+
this._options = (options || false);
46+
this._node.addEventListener(this._type, this._handler, this._options);
47+
}
48+
49+
public dispose(): void {
50+
if (!this._handler) {
51+
// Already disposed
52+
return;
53+
}
54+
55+
this._node.removeEventListener(this._type, this._handler, this._options);
56+
57+
// Prevent leakers from holding on to the dom or handler func
58+
this._node = null!;
59+
this._handler = null!;
60+
}
61+
}
62+
63+
export function addDisposableListener<K extends keyof GlobalEventHandlersEventMap>(node: EventTarget, type: K, handler: (event: GlobalEventHandlersEventMap[K]) => void, useCapture?: boolean): IDisposable;
64+
export function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable;
65+
export function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, options: AddEventListenerOptions): IDisposable;
66+
export function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCaptureOrOptions?: boolean | AddEventListenerOptions): IDisposable {
67+
return new DomListener(node, type, handler, useCaptureOrOptions);
4668
}
4769

4870
export interface IAddStandardDisposableListenerSignature {

0 commit comments

Comments
 (0)