diff --git a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-area.svelte b/web/src/lib/components/asset-viewer/editor/crop-tool/crop-area.svelte index a264ad8ddd..d61a534ed1 100644 --- a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-area.svelte +++ b/web/src/lib/components/asset-viewer/editor/crop-tool/crop-area.svelte @@ -53,12 +53,10 @@ img.src = getAssetOriginalUrl({ id: asset.id, cacheKey: asset.thumbhash }); - img.addEventListener('load', () => onImageLoad(true)); - img.addEventListener('error', (error) => { - handleError(error, $t('error_loading_image')); - }); + img.addEventListener('load', () => onImageLoad(true), { passive: true }); + img.addEventListener('error', (error) => handleError(error, $t('error_loading_image')), { passive: true }); - globalThis.addEventListener('mousemove', handleMouseMove); + globalThis.addEventListener('mousemove', handleMouseMove, { passive: true }); }); onDestroy(() => { diff --git a/web/src/lib/components/asset-viewer/editor/crop-tool/image-loading.ts b/web/src/lib/components/asset-viewer/editor/crop-tool/image-loading.ts index bce90efd9e..63a42b8b96 100644 --- a/web/src/lib/components/asset-viewer/editor/crop-tool/image-loading.ts +++ b/web/src/lib/components/asset-viewer/editor/crop-tool/image-loading.ts @@ -31,8 +31,8 @@ export function onImageLoad(resetSize: boolean = false) { cropFrameEl?.classList.add('transition'); cropSettings.update((crop) => normalizeCropArea(crop, img, scale)); cropFrameEl?.classList.add('transition'); - cropFrameEl?.addEventListener('transitionend', () => { - cropFrameEl?.classList.remove('transition'); + cropFrameEl?.addEventListener('transitionend', () => cropFrameEl?.classList.remove('transition'), { + passive: true, }); } cropImageScale.set(scale); diff --git a/web/src/lib/components/asset-viewer/editor/crop-tool/mouse-handlers.ts b/web/src/lib/components/asset-viewer/editor/crop-tool/mouse-handlers.ts index b00f5331b2..832f0e4339 100644 --- a/web/src/lib/components/asset-viewer/editor/crop-tool/mouse-handlers.ts +++ b/web/src/lib/components/asset-viewer/editor/crop-tool/mouse-handlers.ts @@ -58,7 +58,7 @@ export function handleMouseDown(e: MouseEvent) { } document.body.style.userSelect = 'none'; - globalThis.addEventListener('mouseup', handleMouseUp); + globalThis.addEventListener('mouseup', handleMouseUp, { passive: true }); } export function handleMouseMove(e: MouseEvent) { diff --git a/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte b/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte index 517e630dc9..820c7f3fd4 100644 --- a/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte +++ b/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte @@ -7,9 +7,9 @@ type AdapterConstructor, type PluginConstructor, } from '@photo-sphere-viewer/core'; - import { SettingsPlugin } from '@photo-sphere-viewer/settings-plugin'; - import { ResolutionPlugin } from '@photo-sphere-viewer/resolution-plugin'; import '@photo-sphere-viewer/core/index.css'; + import { ResolutionPlugin } from '@photo-sphere-viewer/resolution-plugin'; + import { SettingsPlugin } from '@photo-sphere-viewer/settings-plugin'; import '@photo-sphere-viewer/settings-plugin/index.css'; import { onDestroy, onMount } from 'svelte'; @@ -68,18 +68,20 @@ fisheye: false, }); const resolutionPlugin = viewer.getPlugin(ResolutionPlugin) as ResolutionPlugin; + const zoomHandler = ({ zoomLevel }: events.ZoomUpdatedEvent) => { + // zoomLevel range: [0, 100] + if (Math.round(zoomLevel) >= 75) { + // Replace the preview with the original + void resolutionPlugin.setResolution('original'); + viewer.removeEventListener(events.ZoomUpdatedEvent.type, zoomHandler); + } + }; if (originalPanorama && !$alwaysLoadOriginalFile) { - const zoomHandler = ({ zoomLevel }: events.ZoomUpdatedEvent) => { - // zoomLevel range: [0, 100] - if (Math.round(zoomLevel) >= 75) { - // Replace the preview with the original - void resolutionPlugin.setResolution('original'); - viewer.removeEventListener(events.ZoomUpdatedEvent.type, zoomHandler); - } - }; - viewer.addEventListener(events.ZoomUpdatedEvent.type, zoomHandler); + viewer.addEventListener(events.ZoomUpdatedEvent.type, zoomHandler, { passive: true }); } + + return () => viewer.removeEventListener(events.ZoomUpdatedEvent.type, zoomHandler); }); onDestroy(() => { diff --git a/web/src/lib/components/asset-viewer/photo-viewer.svelte b/web/src/lib/components/asset-viewer/photo-viewer.svelte index db7901dfbe..5b3c84ed5a 100644 --- a/web/src/lib/components/asset-viewer/photo-viewer.svelte +++ b/web/src/lib/components/asset-viewer/photo-viewer.svelte @@ -193,8 +193,8 @@ if (loader?.complete) { onload(); } - loader?.addEventListener('load', onload); - loader?.addEventListener('error', onerror); + loader?.addEventListener('load', onload, { passive: true }); + loader?.addEventListener('error', onerror, { passive: true }); return () => { loader?.removeEventListener('load', onload); loader?.removeEventListener('error', onerror); diff --git a/web/src/lib/components/assets/thumbnail/thumbnail.svelte b/web/src/lib/components/assets/thumbnail/thumbnail.svelte index 00fef98c09..ea04593cb0 100644 --- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte @@ -123,17 +123,21 @@ mouseOver = false; }; - let timer: ReturnType; + let timer: ReturnType | null = null; const preventContextMenu = (evt: Event) => evt.preventDefault(); - let disposeables: (() => void)[] = []; + const disposeables: (() => void)[] = []; const clearLongPressTimer = () => { + if (!timer) { + return; + } clearTimeout(timer); + timer = null; for (const dispose of disposeables) { dispose(); } - disposeables = []; + disposeables.length = 0; }; let startX: number = 0; @@ -162,7 +166,7 @@ }; element.addEventListener('click', click); element.addEventListener('pointerdown', start, true); - element.addEventListener('pointerup', clearLongPressTimer, true); + element.addEventListener('pointerup', clearLongPressTimer, { capture: true, passive: true }); return { destroy: () => { element.removeEventListener('click', click); @@ -172,17 +176,15 @@ }; } function moveHandler(e: PointerEvent) { - var diffX = Math.abs(startX - e.clientX); - var diffY = Math.abs(startY - e.clientY); - if (diffX >= 10 || diffY >= 10) { + if (Math.abs(startX - e.clientX) >= 10 || Math.abs(startY - e.clientY) >= 10) { clearLongPressTimer(); } } onMount(() => { - document.addEventListener('scroll', clearLongPressTimer, true); - document.addEventListener('wheel', clearLongPressTimer, true); - document.addEventListener('contextmenu', clearLongPressTimer, true); - document.addEventListener('pointermove', moveHandler, true); + document.addEventListener('scroll', clearLongPressTimer, { capture: true, passive: true }); + document.addEventListener('wheel', clearLongPressTimer, { capture: true, passive: true }); + document.addEventListener('contextmenu', clearLongPressTimer, { capture: true, passive: true }); + document.addEventListener('pointermove', moveHandler, { capture: true, passive: true }); return () => { document.removeEventListener('scroll', clearLongPressTimer, true); document.removeEventListener('wheel', clearLongPressTimer, true); diff --git a/web/src/lib/components/shared-components/combobox.svelte b/web/src/lib/components/shared-components/combobox.svelte index dd74faa56b..2b3dd23cd4 100644 --- a/web/src/lib/components/shared-components/combobox.svelte +++ b/web/src/lib/components/shared-components/combobox.svelte @@ -105,9 +105,9 @@ } observer.observe(input); const scrollableAncestor = input?.closest('.overflow-y-auto, .overflow-y-scroll'); - scrollableAncestor?.addEventListener('scroll', onPositionChange); - window.visualViewport?.addEventListener('resize', onPositionChange); - window.visualViewport?.addEventListener('scroll', onPositionChange); + scrollableAncestor?.addEventListener('scroll', onPositionChange, { passive: true }); + window.visualViewport?.addEventListener('resize', onPositionChange, { passive: true }); + window.visualViewport?.addEventListener('scroll', onPositionChange, { passive: true }); return () => { observer.disconnect(); diff --git a/web/src/lib/components/shared-components/control-app-bar.svelte b/web/src/lib/components/shared-components/control-app-bar.svelte index 340964b224..22ee340006 100644 --- a/web/src/lib/components/shared-components/control-app-bar.svelte +++ b/web/src/lib/components/shared-components/control-app-bar.svelte @@ -53,7 +53,7 @@ onMount(() => { if (browser) { - document.addEventListener('scroll', onScroll); + document.addEventListener('scroll', onScroll, { passive: true }); } }); diff --git a/web/src/lib/components/shared-components/scrubber/scrubber.svelte b/web/src/lib/components/shared-components/scrubber/scrubber.svelte index 730ff39c56..4e49f9a012 100644 --- a/web/src/lib/components/shared-components/scrubber/scrubber.svelte +++ b/web/src/lib/components/shared-components/scrubber/scrubber.svelte @@ -357,18 +357,18 @@ }; /* eslint-enable tscompat/tscompat */ onMount(() => { - document.addEventListener('touchmove', onTouchMove, true); + document.addEventListener('touchmove', onTouchMove, { capture: true, passive: true }); return () => { - document.removeEventListener('touchmove', onTouchMove); + document.removeEventListener('touchmove', onTouchMove, true); }; }); onMount(() => { - document.addEventListener('touchstart', onTouchStart, true); - document.addEventListener('touchend', onTouchEnd, true); + document.addEventListener('touchstart', onTouchStart, { capture: true, passive: true }); + document.addEventListener('touchend', onTouchEnd, { capture: true, passive: true }); return () => { - document.addEventListener('touchstart', onTouchStart, true); - document.addEventListener('touchend', onTouchEnd, true); + document.removeEventListener('touchstart', onTouchStart, true); + document.removeEventListener('touchend', onTouchEnd, true); }; }); diff --git a/web/src/lib/managers/theme-manager.svelte.ts b/web/src/lib/managers/theme-manager.svelte.ts index a20e5f9a98..4efac4a44d 100644 --- a/web/src/lib/managers/theme-manager.svelte.ts +++ b/web/src/lib/managers/theme-manager.svelte.ts @@ -52,11 +52,15 @@ class ThemeManager { } #onAppInit() { - globalThis.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { - if (this.theme.system) { - this.#update('system'); - } - }); + globalThis.matchMedia('(prefers-color-scheme: dark)').addEventListener( + 'change', + () => { + if (this.theme.system) { + this.#update('system'); + } + }, + { passive: true }, + ); } #update(value: Theme | 'system') { diff --git a/web/src/lib/utils/file-uploader.ts b/web/src/lib/utils/file-uploader.ts index c5dd3ebd8e..9b0361e1e0 100644 --- a/web/src/lib/utils/file-uploader.ts +++ b/web/src/lib/utils/file-uploader.ts @@ -67,15 +67,19 @@ export const openFileUploadDialog = async (options: FileUploadParam = {}) => { fileSelector.type = 'file'; fileSelector.multiple = multiple; fileSelector.accept = extensions.join(','); - fileSelector.addEventListener('change', (e: Event) => { - const target = e.target as HTMLInputElement; - if (!target.files) { - return; - } - const files = Array.from(target.files); + fileSelector.addEventListener( + 'change', + (e: Event) => { + const target = e.target as HTMLInputElement; + if (!target.files) { + return; + } + const files = Array.from(target.files); - resolve(fileUploadHandler({ files, albumId, replaceAssetId: assetId })); - }); + resolve(fileUploadHandler({ files, albumId, replaceAssetId: assetId })); + }, + { passive: true }, + ); fileSelector.click(); } catch (error) { diff --git a/web/src/service-worker/index.ts b/web/src/service-worker/index.ts index 796b06b7df..b3c1fda38e 100644 --- a/web/src/service-worker/index.ts +++ b/web/src/service-worker/index.ts @@ -20,7 +20,7 @@ const handleInstall = (event: ExtendableEvent) => { event.waitUntil(addFilesToCache()); }; -sw.addEventListener('install', handleInstall); -sw.addEventListener('activate', handleActivate); -sw.addEventListener('fetch', handleFetchEvent); +sw.addEventListener('install', handleInstall, { passive: true }); +sw.addEventListener('activate', handleActivate, { passive: true }); +sw.addEventListener('fetch', handleFetchEvent, { passive: true }); installBroadcastChannelListener();