fix: allow other events to call preventDefault (#12089)

This commit is contained in:
Joshua Cain
2026-07-24 12:46:28 -04:00
committed by GitHub
parent ba814fd6ec
commit 565af341dd
2 changed files with 20 additions and 2 deletions
@@ -83,6 +83,22 @@ describe('IdleActivityTracker', () => {
expect(spy).toHaveBeenCalledTimes(1);
});
it('should allow a later listener to prevent default when an activity event fires', () => {
const preventDefault = jasmine.createSpy('preventDefault').and.callFake((event: Event) => event.preventDefault());
tracker.start();
doc.addEventListener('mousemove', preventDefault);
try {
const event = new MouseEvent('mousemove', { cancelable: true });
doc.dispatchEvent(event);
expect(preventDefault).toHaveBeenCalledTimes(1);
expect(event.defaultPrevented).toBeTrue();
} finally {
doc.removeEventListener('mousemove', preventDefault);
}
});
it('is a no-op when stop() is called without a prior start()', () => {
const spy = jasmine.createSpy('activity');
tracker.activity$.subscribe(spy);
@@ -25,6 +25,8 @@ export const ACTIVITY_EVENTS = ['click', 'keydown', 'mousedown', 'mousemove', 'p
/** High-frequency activity events (e.g. mousemove, scroll) are throttled to avoid rescheduling the idle timer on every DOM event. */
export const ACTIVITY_THROTTLE_MS = 1000;
const ACTIVITY_LISTENER_OPTIONS: AddEventListenerOptions = { capture: true, passive: true };
@Injectable()
export class IdleActivityTracker implements OnDestroy {
private readonly document = inject(DOCUMENT);
@@ -44,7 +46,7 @@ export class IdleActivityTracker implements OnDestroy {
}
this.ngZone.runOutsideAngular(() => {
ACTIVITY_EVENTS.forEach((eventName) => this.document.addEventListener(eventName, this.handleActivity, { passive: true }));
ACTIVITY_EVENTS.forEach((eventName) => this.document.addEventListener(eventName, this.handleActivity, ACTIVITY_LISTENER_OPTIONS));
this.document.addEventListener('visibilitychange', this.handleVisibilityChange);
});
this.isRegistered = true;
@@ -55,7 +57,7 @@ export class IdleActivityTracker implements OnDestroy {
return;
}
ACTIVITY_EVENTS.forEach((eventName) => this.document.removeEventListener(eventName, this.handleActivity));
ACTIVITY_EVENTS.forEach((eventName) => this.document.removeEventListener(eventName, this.handleActivity, ACTIVITY_LISTENER_OPTIONS));
this.document.removeEventListener('visibilitychange', this.handleVisibilityChange);
this.isRegistered = false;
}