From 95a944d0b466f3ea07a69260cbb50e518bdf87f1 Mon Sep 17 00:00:00 2001 From: ioj4 <69911332+ioj4@users.noreply.github.com> Date: Sat, 5 Oct 2024 05:44:48 +0200 Subject: [PATCH 1/3] fix: beforeunload not getting dispatched --- src-tauri/injection/global.d.ts | 1 + src-tauri/injection/preinject.ts | 15 ++++++++++++++- src-tauri/injection/shared/recreate.ts | 24 ++++++++++++++++++++++++ src-tauri/src/functionality/tray.rs | 8 +++++++- 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src-tauri/injection/global.d.ts b/src-tauri/injection/global.d.ts index 58294399..155e277a 100644 --- a/src-tauri/injection/global.d.ts +++ b/src-tauri/injection/global.d.ts @@ -12,6 +12,7 @@ declare global { emit: (event: string, payload: unknown) => void TauriEvent: { WINDOW_RESIZED: string + WINDOW_CLOSE_REQUESTED: string } } shell: { diff --git a/src-tauri/injection/preinject.ts b/src-tauri/injection/preinject.ts index f81459d8..ef9d6577 100644 --- a/src-tauri/injection/preinject.ts +++ b/src-tauri/injection/preinject.ts @@ -1,4 +1,4 @@ -import { badPostMessagePatch, createLocalStorage, proxyFetch, proxyXHR } from './shared/recreate' +import { badPostMessagePatch, createLocalStorage, proxyFetch, proxyXHR, proxyAddEventListener } from './shared/recreate' import { safemodeTimer, typingAnim } from './shared/ui' import { cssSanitize, fetchImage, isJson, waitForApp, waitForElm, saferEval } from './shared/util' import { applyNotificationCount } from './shared/window' @@ -40,6 +40,7 @@ if (!window.__DORION_INITIALIZED__) window.__DORION_INITIALIZED__ = false createLocalStorage() proxyFetch() proxyXHR() + proxyAddEventListener() while (!window.__TAURI__) { console.log('Waiting for definition...') @@ -105,6 +106,18 @@ async function init() { typingAnim() + // Discord Web depends on the `beforeunload` event being dispatched by the browser when + // a tab is closed. However, this event is not triggered by the Webview so we need to + // dispatch the `beforeunload` event ourselves. + const dispatchBeforeUnload = () => { + let event = new Event("beforeunload") as Event & { isTrustedOverwrite: boolean } + event.isTrustedOverwrite = true + window.dispatchEvent(event) + } + + event.listen('beforeunload', dispatchBeforeUnload) + event.listen(event.TauriEvent.WINDOW_CLOSE_REQUESTED, dispatchBeforeUnload) + // Start the loading_log event listener const logUnlisten = await event.listen('loading_log', (event: TauriEvent) => { const log = event.payload as string diff --git a/src-tauri/injection/shared/recreate.ts b/src-tauri/injection/shared/recreate.ts index 8eeffbf2..cdcbe888 100644 --- a/src-tauri/injection/shared/recreate.ts +++ b/src-tauri/injection/shared/recreate.ts @@ -66,6 +66,30 @@ export function proxyXHR() { } } +export function proxyAddEventListener() { + const original = window.addEventListener + + window.addEventListener = function(...args: Parameters) { + const [type, listener] = args + if (type === "beforeunload") { + args[1] = (...listenerArgs: Parameters) => { + // @ts-expect-error this is fine + const isTrustedOverwrite = listenerArgs[0]?.isTrustedOverwrite + + if (isTrustedOverwrite !== undefined) { + listenerArgs[0] = Object.assign({}, listenerArgs[0]) + // @ts-expect-error this is fine + listenerArgs[0].isTrusted = isTrustedOverwrite + } + + return ('handleEvent' in listener) ? listener.handleEvent(...listenerArgs) : listener(...listenerArgs) + } + } + + return original(...args) + } +} + export function createLocalStorage() { const iframe = document.createElement('iframe') diff --git a/src-tauri/src/functionality/tray.rs b/src-tauri/src/functionality/tray.rs index c86206bf..08d7469f 100644 --- a/src-tauri/src/functionality/tray.rs +++ b/src-tauri/src/functionality/tray.rs @@ -3,7 +3,7 @@ use tauri::{ image::Image, menu::{MenuBuilder, MenuItemBuilder}, tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}, - AppHandle, Manager, + AppHandle, Emitter, Manager, }; use crate::{log, util::window_helpers::ultrashow}; @@ -60,6 +60,9 @@ pub fn create_tray(app: &AppHandle) -> Result<(), tauri::Error> { .menu(&menu) .on_menu_event(move |app, event| match event.id().as_ref() { "quit" => { + if let Some(win) = app.get_webview_window("main") { + win.emit("beforeunload", ()).unwrap_or_default(); + } app.exit(0); } "open" => { @@ -68,6 +71,9 @@ pub fn create_tray(app: &AppHandle) -> Result<(), tauri::Error> { } } "restart" => { + if let Some(win) = app.get_webview_window("main") { + win.emit("beforeunload", ()).unwrap_or_default(); + } app.restart(); } "reload" => { From 46f1aa9dac8b5272b1029fbed5ccbf5b2ba4d37d Mon Sep 17 00:00:00 2001 From: ioj4 <69911332+ioj4@users.noreply.github.com> Date: Sat, 5 Oct 2024 06:22:01 +0200 Subject: [PATCH 2/3] fix: use proxy instead --- src-tauri/injection/shared/recreate.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src-tauri/injection/shared/recreate.ts b/src-tauri/injection/shared/recreate.ts index cdcbe888..0d913384 100644 --- a/src-tauri/injection/shared/recreate.ts +++ b/src-tauri/injection/shared/recreate.ts @@ -77,9 +77,13 @@ export function proxyAddEventListener() { const isTrustedOverwrite = listenerArgs[0]?.isTrustedOverwrite if (isTrustedOverwrite !== undefined) { - listenerArgs[0] = Object.assign({}, listenerArgs[0]) - // @ts-expect-error this is fine - listenerArgs[0].isTrusted = isTrustedOverwrite + const event = listenerArgs[0] + listenerArgs[0] = new Proxy(event, { + get(target, prop, receiver) { + if (prop === "isTrusted") return isTrustedOverwrite + return Reflect.get(target, prop, receiver) + } + }) } return ('handleEvent' in listener) ? listener.handleEvent(...listenerArgs) : listener(...listenerArgs) From d1c1cd71be0dfc8df7a11b435ce71d002ce8b519 Mon Sep 17 00:00:00 2001 From: SpikeHD <25207995+SpikeHD@users.noreply.github.com> Date: Fri, 4 Oct 2024 22:05:55 -0700 Subject: [PATCH 3/3] fix: lints --- src-tauri/injection/preinject.ts | 2 +- src-tauri/injection/shared/recreate.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src-tauri/injection/preinject.ts b/src-tauri/injection/preinject.ts index ef9d6577..59aba05b 100644 --- a/src-tauri/injection/preinject.ts +++ b/src-tauri/injection/preinject.ts @@ -110,7 +110,7 @@ async function init() { // a tab is closed. However, this event is not triggered by the Webview so we need to // dispatch the `beforeunload` event ourselves. const dispatchBeforeUnload = () => { - let event = new Event("beforeunload") as Event & { isTrustedOverwrite: boolean } + const event = new Event('beforeunload') as Event & { isTrustedOverwrite: boolean } event.isTrustedOverwrite = true window.dispatchEvent(event) } diff --git a/src-tauri/injection/shared/recreate.ts b/src-tauri/injection/shared/recreate.ts index 0d913384..facf1a27 100644 --- a/src-tauri/injection/shared/recreate.ts +++ b/src-tauri/injection/shared/recreate.ts @@ -71,7 +71,7 @@ export function proxyAddEventListener() { window.addEventListener = function(...args: Parameters) { const [type, listener] = args - if (type === "beforeunload") { + if (type === 'beforeunload') { args[1] = (...listenerArgs: Parameters) => { // @ts-expect-error this is fine const isTrustedOverwrite = listenerArgs[0]?.isTrustedOverwrite @@ -80,7 +80,7 @@ export function proxyAddEventListener() { const event = listenerArgs[0] listenerArgs[0] = new Proxy(event, { get(target, prop, receiver) { - if (prop === "isTrusted") return isTrustedOverwrite + if (prop === 'isTrusted') return isTrustedOverwrite return Reflect.get(target, prop, receiver) } })