diff --git a/src-electron/ipcListeners.ts b/src-electron/ipcListeners.ts index 23bebcad6..11f279231 100644 --- a/src-electron/ipcListeners.ts +++ b/src-electron/ipcListeners.ts @@ -1,4 +1,4 @@ -import { ipcMain, dialog, App, BrowserWindow } from 'electron'; +import { ipcMain, dialog, App, BrowserWindow, Menu, MenuItem } from 'electron'; import electronUpdater from 'electron-updater'; import os from 'os'; import { fileURLToPath } from 'url'; @@ -72,3 +72,19 @@ ipcMain.on('get-statics-directory', (event) => { const __dirname = path.dirname(__filename); event.returnValue = __dirname; }); + +ipcMain.on('electron:showContextMenu', (event, options: any) => { + const templateItems: MenuItem[] = []; + templateItems.push(new MenuItem({ + label: 'Copy', + role: 'copy' + })); + if (!options.readonly) { + templateItems.push(new MenuItem({ + label: 'Paste', + role: 'paste' + })); + } + const menu = Menu.buildFromTemplate(templateItems); + menu.popup(); +}) diff --git a/src-electron/preload/electron-preload.ts b/src-electron/preload/electron-ipc-preload.ts similarity index 91% rename from src-electron/preload/electron-preload.ts rename to src-electron/preload/electron-ipc-preload.ts index f87cbc366..9da1d6d89 100644 --- a/src-electron/preload/electron-preload.ts +++ b/src-electron/preload/electron-ipc-preload.ts @@ -34,3 +34,7 @@ export function copyToClipboard(value: string) { export async function getEnvironmentVariables() { return ipcRenderer.invoke('electron:getEnvironmentVariables'); } + +export function showContextMenu(options: any) { + ipcRenderer.send('electron:showContextMenu', options); +} diff --git a/src-electron/preload/expose-preload.ts b/src-electron/preload/expose-preload.ts index d8d11186f..4fc97c54d 100644 --- a/src-electron/preload/expose-preload.ts +++ b/src-electron/preload/expose-preload.ts @@ -6,7 +6,7 @@ import * as buffer from './node-buffer'; import * as os from './node-os'; import * as zip from './zip-preload'; import * as appGlobals from "./app-preload-globals"; -import * as electron from "./electron-preload"; +import * as electron from "./electron-ipc-preload"; contextBridge.exposeInMainWorld('node', { path: path, diff --git a/src/App.vue b/src/App.vue index 407578702..1a53f7d6b 100644 --- a/src/App.vue +++ b/src/App.vue @@ -52,6 +52,7 @@ import { NodeFsImplementation } from './providers/node/fs/NodeFsImplementation'; import { useRouter } from 'vue-router'; import { ProtocolProviderImplementation } from './providers/generic/protocol/ProtocolProviderImplementation'; import { provideProtocolImplementation } from './providers/generic/protocol/ProtocolProvider'; +import contextMenu from './providers/node/context_menu/context_menu'; const store = baseStore; const router = useRouter(); @@ -142,6 +143,23 @@ onMounted(async () => { watchEffect(() => { document.documentElement.classList.toggle('html--dark', quasar.dark.isActive); +}); + +document.addEventListener('contextmenu', e => { + if (e.target) { + const target = e.target as HTMLElement; + switch (true) { + case target instanceof HTMLInputElement: { + contextMenu.showContextMenu({ readonly: false }); + break; + } + case ['code', 'pre'].includes(target.tagName.toLowerCase()): { + contextMenu.showContextMenu({ readonly: true }); + break; + } + default: { break; } + } + } }) diff --git a/src/providers/node/context_menu/ContextMenuImplementation.ts b/src/providers/node/context_menu/ContextMenuImplementation.ts new file mode 100644 index 000000000..55d56fcc7 --- /dev/null +++ b/src/providers/node/context_menu/ContextMenuImplementation.ts @@ -0,0 +1,7 @@ +import { ContextMenuProcessProvider } from './context_menu'; + +let execIdentifier = 0; + +export const ContextMenuProcessImplementation: ContextMenuProcessProvider = { + showContextMenu: (options) => window.electron.showContextMenu(options), +} diff --git a/src/providers/node/context_menu/context_menu.ts b/src/providers/node/context_menu/context_menu.ts new file mode 100644 index 000000000..8d02cc873 --- /dev/null +++ b/src/providers/node/context_menu/context_menu.ts @@ -0,0 +1,28 @@ +import { ContextMenuProcessImplementation } from './ContextMenuImplementation'; + +export type ContextMenuOptions = { + readonly: boolean +} + +export type ContextMenuProcessProvider = { + showContextMenu: (options: ContextMenuOptions) => Promise; +} + +let implementation: () => ContextMenuProcessProvider; + +function getImplementation(): ContextMenuProcessProvider { + if (!implementation) { + return ContextMenuProcessImplementation; + } + return implementation(); +} + +export function provideContextMenuImplementation(provider: () => ContextMenuProcessProvider) { + implementation = provider; +} + +const contextMenu: ContextMenuProcessProvider = { + showContextMenu: (options) => getImplementation().showContextMenu(options), +}; + +export default contextMenu;