diff --git a/src/main/sessions.ts b/src/main/sessions.ts index 179479e6..dcc57547 100644 --- a/src/main/sessions.ts +++ b/src/main/sessions.ts @@ -2,7 +2,7 @@ // Distributed under the terms of the Modified BSD License. import { - BrowserWindow, ipcMain, app + BrowserWindow, ipcMain, app, Menu, MenuItemConstructorOptions, clipboard } from 'electron'; import { @@ -407,6 +407,7 @@ class JupyterLabSession { }); this._window.setMenuBarVisibility(false); + this._addFallbackContextMenu(); if (this._info.x && this._info.y) { this._window.setBounds({x: this._info.x, y: this._info.y, height: this._info.height, width: this._info.width }); @@ -485,6 +486,55 @@ class JupyterLabSession { }; } + /** + * Simple fallback context menu shown on Shift + Right Click. + * May be removed in future versions once (/if) JupyterLab builtin menu + * supports cut/copy/paste, including "Copy link URL" and "Copy image". + * @private + */ + private _addFallbackContextMenu(): void { + const selectionTemplate: MenuItemConstructorOptions[] = [ + {role: 'copy'}, + ]; + + const inputMenu = Menu.buildFromTemplate([ + {role: 'cut'}, + {role: 'copy'}, + {role: 'paste'}, + {role: 'selectAll'} + ]); + + this._window.webContents.on('context-menu', (event, params) => { + if (params.isEditable) { + inputMenu.popup({window: this._window}); + } else { + const template: MenuItemConstructorOptions[] = [] + if (params.selectionText) { + template.push(...selectionTemplate); + } + if (params.linkURL) { + template.push({ + 'label': 'Copy link URL', + 'click': () => { + clipboard.writeText(params.linkURL); + } + }) + } + if (params.hasImageContents) { + template.push({ + 'label': 'Copy image', + 'click': () => { + this._window.webContents.copyImageAt(params.x, params.y); + } + }); + } + if (template.length) { + Menu.buildFromTemplate(template).popup({window: this._window}); + } + } + }); + } + private _addRenderAPI(): void { ipcMain.on('state-update', (evt: any, arg: any) => { for (let key in arg) {