From c2cb695a8fa064e1abec528d0abe878dac913b52 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 20 Jan 2026 11:20:12 -0800 Subject: [PATCH] fix: Annotate potentially blocking event listeners with passivity (#9555) * fix: Annotate potentially blocking event listeners with passivity * fix: Improve typings for `options` arg to `bind()`/`conditionalBind()` --- core/browser_events.ts | 16 ++++++++++++---- core/comments/comment_editor.ts | 13 ++++++++++--- core/flyout_base.ts | 2 ++ core/workspace_svg.ts | 6 +++++- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/core/browser_events.ts b/core/browser_events.ts index 8176fe10f..065a5bc53 100644 --- a/core/browser_events.ts +++ b/core/browser_events.ts @@ -46,6 +46,9 @@ const PAGE_MODE_MULTIPLIER = 125; * @param opt_noCaptureIdentifier True if triggering on this event should not * block execution of other event handlers on this touch or other * simultaneous touches. False by default. + * @param options An object with options controlling the behavior of the event + * listener. Passed through directly as the third argument to + * `addEventListener`. * @returns Opaque data that can be passed to unbindEvent_. */ export function conditionalBind( @@ -54,6 +57,7 @@ export function conditionalBind( thisObject: object | null, func: Function, opt_noCaptureIdentifier?: boolean, + options?: AddEventListenerOptions, ): Data { /** * @@ -75,11 +79,11 @@ export function conditionalBind( if (name in Touch.TOUCH_MAP) { for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) { const type = Touch.TOUCH_MAP[name][i]; - node.addEventListener(type, wrapFunc, false); + node.addEventListener(type, wrapFunc, {capture: false, ...options}); bindData.push([node, type, wrapFunc]); } } else { - node.addEventListener(name, wrapFunc, false); + node.addEventListener(name, wrapFunc, {capture: false, ...options}); bindData.push([node, name, wrapFunc]); } return bindData; @@ -95,6 +99,9 @@ export function conditionalBind( * @param name Event name to listen to (e.g. 'mousedown'). * @param thisObject The value of 'this' in the function. * @param func Function to call when event is triggered. + * @param options An object with options controlling the behavior of the event + * listener. Passed through directly as the third argument to + * `addEventListener`. * @returns Opaque data that can be passed to unbindEvent_. */ export function bind( @@ -102,6 +109,7 @@ export function bind( name: string, thisObject: object | null, func: Function, + options?: AddEventListenerOptions, ): Data { /** * @@ -119,11 +127,11 @@ export function bind( if (name in Touch.TOUCH_MAP) { for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) { const type = Touch.TOUCH_MAP[name][i]; - node.addEventListener(type, wrapFunc, false); + node.addEventListener(type, wrapFunc, {capture: false, ...options}); bindData.push([node, type, wrapFunc]); } } else { - node.addEventListener(name, wrapFunc, false); + node.addEventListener(name, wrapFunc, {capture: false, ...options}); bindData.push([node, name, wrapFunc]); } return bindData; diff --git a/core/comments/comment_editor.ts b/core/comments/comment_editor.ts index 2005a9991..92c92fa54 100644 --- a/core/comments/comment_editor.ts +++ b/core/comments/comment_editor.ts @@ -95,9 +95,16 @@ export class CommentEditor implements IFocusableNode { ); // Don't zoom with mousewheel; let it scroll instead. - browserEvents.conditionalBind(this.textArea, 'wheel', this, (e: Event) => { - e.stopPropagation(); - }); + browserEvents.conditionalBind( + this.textArea, + 'wheel', + this, + (e: Event) => { + e.stopPropagation(); + }, + false, + {passive: true}, + ); // Register listener for keydown events that would finish editing. browserEvents.conditionalBind( diff --git a/core/flyout_base.ts b/core/flyout_base.ts index 3b0bc6148..1d16f05f1 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -357,6 +357,8 @@ export abstract class Flyout 'wheel', this, this.wheel_, + false, + {passive: false}, ), ); diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index af395b077..de158c6d4 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -809,12 +809,16 @@ export class WorkspaceSvg // which otherwise prevents zoom/scroll events from being observed in // Safari. Once that bug is fixed it should be removed. this.dummyWheelListener = () => {}; - document.body.addEventListener('wheel', this.dummyWheelListener); + document.body.addEventListener('wheel', this.dummyWheelListener, { + passive: true, + }); browserEvents.conditionalBind( this.svgGroup_, 'wheel', this, this.onMouseWheel, + false, + {passive: false}, ); }