From a8db1808c8c800a4262a422de15c2e095bcd9943 Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Thu, 23 Apr 2026 15:55:59 -0700 Subject: [PATCH 1/3] Desktop: Fixes #15189: Revert #15035 --- packages/app-desktop/gui/NewWindowOrIFrame.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/app-desktop/gui/NewWindowOrIFrame.tsx b/packages/app-desktop/gui/NewWindowOrIFrame.tsx index d7e9acc3054..2eb87fde53f 100644 --- a/packages/app-desktop/gui/NewWindowOrIFrame.tsx +++ b/packages/app-desktop/gui/NewWindowOrIFrame.tsx @@ -44,6 +44,12 @@ const useDocument = ( setDoc(iframeElement?.contentWindow?.document); } else if (mode === WindowMode.NewWindow) { openedWindow = window.open('about:blank'); + + // Required to support TinyMCE: + openedWindow.document.open(); + openedWindow.document.write(''); + openedWindow.document.close(); + setDoc(openedWindow.document); // .onbeforeunload and .onclose events don't seem to fire when closed by a user -- rely on polling From 1a58102fcd0ad6d6fa5ff71d83ca22022b48832b Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Thu, 23 Apr 2026 16:01:05 -0700 Subject: [PATCH 2/3] Fix crash when closing windows --- packages/app-desktop/ElectronAppWrapper.ts | 1 + .../NoteBody/CodeMirror/utils/useContextMenu.ts | 17 ++++++++++++++--- .../NoteBody/TinyMCE/utils/useContextMenu.ts | 12 ++++++++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/app-desktop/ElectronAppWrapper.ts b/packages/app-desktop/ElectronAppWrapper.ts index 7351c80dd18..266fe35651b 100644 --- a/packages/app-desktop/ElectronAppWrapper.ts +++ b/packages/app-desktop/ElectronAppWrapper.ts @@ -412,6 +412,7 @@ export default class ElectronAppWrapper { action: 'allow', overrideBrowserWindowOptions: { webPreferences: { + nodeIntegration: false, preload: resolve(__dirname, './utils/window/secondaryWindowPreload.js'), }, }, diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts index e296408582b..03cdf758d32 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts @@ -16,6 +16,9 @@ import { menuItems } from '../../../utils/contextMenu'; import isItemId from '@joplin/lib/models/utils/isItemId'; import { extractResourceUrls } from '@joplin/lib/urlUtils'; import { WindowIdContext } from '../../../../NewWindowOrIFrame'; +import Logger from '@joplin/utils/Logger'; + +const logger = Logger.create('useContextMenu'); export type ResourceMarkupType = 'image' | 'file'; @@ -355,11 +358,19 @@ const useContextMenu = (props: ContextMenuProps) => { // Prepend the event listener so that it gets called before // the listener that shows the default menu. - targetWindow.webContents.prependListener('context-menu', onContextMenu); + try { + targetWindow.webContents.prependListener('context-menu', onContextMenu); + } catch (error) { + logger.warn('Error registering menu', error); + } return () => { - if (!targetWindow.isDestroyed()) { - targetWindow.webContents.off('context-menu', onContextMenu); + try { + if (!targetWindow.isDestroyed()) { + targetWindow.webContents.off('context-menu', onContextMenu); + } + } catch (error) { + logger.warn('Error removing menu listener', error); } }; }, [ diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts index 6f900ef3e51..383dfa3cf42 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts @@ -19,6 +19,9 @@ import { _ } from '@joplin/lib/locale'; import type { MenuItem as MenuItemType } from 'electron'; import isItemId from '@joplin/lib/models/utils/isItemId'; import { WindowIdContext } from '../../../../NewWindowOrIFrame'; +import Logger from '@joplin/utils/Logger'; + +const logger = Logger.create('useContextMenu'); const Menu = bridge().Menu; const MenuItem = bridge().MenuItem; @@ -162,8 +165,13 @@ export default function(editor: Editor, plugins: PluginStates, dispatch: Dispatc return () => { editor.off('contextmenu', onBrowserContextMenu); - if (!targetWindow.isDestroyed() && targetWindow?.webContents?.off) { - targetWindow.webContents.off('context-menu', onElectronContextMenu); + + try { + if (!targetWindow.isDestroyed() && targetWindow?.webContents?.off) { + targetWindow.webContents.off('context-menu', onElectronContextMenu); + } + } catch (error) { + logger.warn('Error removing context menu listener', error); } }; }, [editor, plugins, dispatch, htmlToMd, mdToHtml, editDialog, windowId]); From b279cb45a1f2f5ea24c6bcfe8f51deef6f060e55 Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Thu, 23 Apr 2026 16:05:33 -0700 Subject: [PATCH 3/3] Commenting (for consistency) --- .../NoteBody/CodeMirror/utils/useContextMenu.ts | 2 ++ .../NoteBody/TinyMCE/utils/useContextMenu.ts | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts index 03cdf758d32..745d835bd78 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts @@ -370,6 +370,8 @@ const useContextMenu = (props: ContextMenuProps) => { targetWindow.webContents.off('context-menu', onContextMenu); } } catch (error) { + // This can happen if the window closes after the isDestroyed check, but before webContents.off + // finishes running. logger.warn('Error removing menu listener', error); } }; diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts index 383dfa3cf42..51210f31361 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts @@ -160,7 +160,11 @@ export default function(editor: Editor, plugins: PluginStates, dispatch: Dispatc } }; - targetWindow.webContents.prependListener('context-menu', onElectronContextMenu); + try { + targetWindow.webContents.prependListener('context-menu', onElectronContextMenu); + } catch (error) { + logger.error('Failed to register context menu', error); + } editor.on('contextmenu', onBrowserContextMenu); return () => { @@ -171,7 +175,9 @@ export default function(editor: Editor, plugins: PluginStates, dispatch: Dispatc targetWindow.webContents.off('context-menu', onElectronContextMenu); } } catch (error) { - logger.warn('Error removing context menu listener', error); + // This can happen if the window closes after the isDestroyed check, but before webContents.off + // finishes running. + logger.error('Error removing context menu listener', error); } }; }, [editor, plugins, dispatch, htmlToMd, mdToHtml, editDialog, windowId]);