From 094d369187fe80dd35110fe8d38cdf336b39308b Mon Sep 17 00:00:00 2001 From: beyondkmp Date: Sun, 4 May 2025 11:04:56 +0800 Subject: [PATCH] refactor(WindowService): improve context menu setup (#5589) * refactor(WindowService): streamline context menu setup and enhance webview spellcheck functionality * update format * delete setSpellCheckerLanguages --- src/main/services/ContextMenu.ts | 60 ++++++++++++++++++++++++++++++ src/main/services/WindowService.ts | 27 +++----------- 2 files changed, 65 insertions(+), 22 deletions(-) create mode 100644 src/main/services/ContextMenu.ts diff --git a/src/main/services/ContextMenu.ts b/src/main/services/ContextMenu.ts new file mode 100644 index 0000000000..503af88db2 --- /dev/null +++ b/src/main/services/ContextMenu.ts @@ -0,0 +1,60 @@ +import { Menu, MenuItemConstructorOptions } from 'electron' + +import { locales } from '../utils/locales' +import { configManager } from './ConfigManager' + +class ContextMenu { + public contextMenu(w: Electron.BrowserWindow) { + w.webContents.on('context-menu', (_event, properties) => { + const template: MenuItemConstructorOptions[] = this.createEditMenuItems(properties) + const filtered = template.filter((item) => item.visible !== false) + if (filtered.length > 0) { + const menu = Menu.buildFromTemplate(filtered) + menu.popup() + } + }) + } + + private createEditMenuItems(properties: Electron.ContextMenuParams): MenuItemConstructorOptions[] { + const locale = locales[configManager.getLanguage()] + const { common } = locale.translation + const hasText = properties.selectionText.trim().length > 0 + const can = (type: string) => properties.editFlags[`can${type}`] && hasText + + const template: MenuItemConstructorOptions[] = [ + { + id: 'copy', + label: common.copy, + role: 'copy', + enabled: can('Copy'), + visible: properties.isEditable || hasText + }, + { + id: 'paste', + label: common.paste, + role: 'paste', + enabled: properties.editFlags.canPaste, + visible: properties.isEditable + }, + { + id: 'cut', + label: common.cut, + role: 'cut', + enabled: can('Cut'), + visible: properties.isEditable + } + ] + + // remove role from items that are not enabled + // https://github.com/electron/electron/issues/13554 + template.forEach((item) => { + if (item.enabled === false) { + item.role = undefined + } + }) + + return template + } +} + +export const contextMenu = new ContextMenu() diff --git a/src/main/services/WindowService.ts b/src/main/services/WindowService.ts index 94cfbb39d9..be05cffe70 100644 --- a/src/main/services/WindowService.ts +++ b/src/main/services/WindowService.ts @@ -3,15 +3,15 @@ import { isDev, isLinux, isMac, isWin } from '@main/constant' import { getFilesDir } from '@main/utils/file' import { IpcChannel } from '@shared/IpcChannel' import { ThemeMode } from '@types' -import { app, BrowserWindow, Menu, MenuItem, nativeTheme, shell } from 'electron' +import { app, BrowserWindow, nativeTheme, shell } from 'electron' import Logger from 'electron-log' import windowStateKeeper from 'electron-window-state' import { join } from 'path' import icon from '../../../build/icon.png?asset' import { titleBarOverlayDark, titleBarOverlayLight } from '../config' -import { locales } from '../utils/locales' import { configManager } from './ConfigManager' +import { contextMenu } from './ContextMenu' import { initSessionUserAgent } from './WebviewService' export class WindowService { @@ -22,7 +22,6 @@ export class WindowService { //hacky-fix: store the focused status of mainWindow before miniWindow shows //to restore the focus status when miniWindow hides private wasMainWindowFocused: boolean = false - private contextMenu: Menu | null = null private lastRendererProcessCrashTime: number = 0 public static getInstance(): WindowService { @@ -140,18 +139,9 @@ export class WindowService { } private setupContextMenu(mainWindow: BrowserWindow) { - if (!this.contextMenu) { - const locale = locales[configManager.getLanguage()] - const { common } = locale.translation - - this.contextMenu = new Menu() - this.contextMenu.append(new MenuItem({ label: common.copy, role: 'copy' })) - this.contextMenu.append(new MenuItem({ label: common.paste, role: 'paste' })) - this.contextMenu.append(new MenuItem({ label: common.cut, role: 'cut' })) - } - - mainWindow.webContents.on('context-menu', () => { - this.contextMenu?.popup() + contextMenu.contextMenu(mainWindow) + app.on('browser-window-created', (_, win) => { + contextMenu.contextMenu(win) }) // Dangerous API @@ -160,13 +150,6 @@ export class WindowService { webPreferences.preload = join(__dirname, '../preload/index.js') }) } - - // Handle webview context menu - mainWindow.webContents.on('did-attach-webview', (_, webContents) => { - webContents.on('context-menu', () => { - this.contextMenu?.popup() - }) - }) } private setupWindowEvents(mainWindow: BrowserWindow) {