2020-07-06 20:24:54 +00:00
|
|
|
import { app, BrowserWindow, WebContents, MenuItemConstructorOptions } from 'electron';
|
2016-06-22 22:21:45 +00:00
|
|
|
|
2020-03-20 20:28:31 +00:00
|
|
|
const isMac = process.platform === 'darwin';
|
|
|
|
const isWindows = process.platform === 'win32';
|
|
|
|
const isLinux = process.platform === 'linux';
|
2019-01-10 13:32:03 +00:00
|
|
|
|
2020-07-06 20:24:54 +00:00
|
|
|
type RoleId = 'about' | 'close' | 'copy' | 'cut' | 'delete' | 'forcereload' | 'front' | 'help' | 'hide' | 'hideothers' | 'minimize' |
|
|
|
|
'paste' | 'pasteandmatchstyle' | 'quit' | 'redo' | 'reload' | 'resetzoom' | 'selectall' | 'services' | 'recentdocuments' | 'clearrecentdocuments' | 'startspeaking' | 'stopspeaking' |
|
|
|
|
'toggledevtools' | 'togglefullscreen' | 'undo' | 'unhide' | 'window' | 'zoom' | 'zoomin' | 'zoomout' | 'appmenu' | 'filemenu' | 'editmenu' | 'viewmenu' | 'windowmenu'
|
|
|
|
interface Role {
|
|
|
|
label: string;
|
|
|
|
accelerator?: string;
|
|
|
|
windowMethod?: ((window: BrowserWindow) => void);
|
|
|
|
webContentsMethod?: ((webContents: WebContents) => void);
|
|
|
|
appMethod?: () => void;
|
|
|
|
registerAccelerator?: boolean;
|
|
|
|
nonNativeMacOSRole?: boolean;
|
|
|
|
submenu?: MenuItemConstructorOptions[];
|
|
|
|
}
|
|
|
|
|
|
|
|
export const roleList: Record<RoleId, Role> = {
|
2016-06-22 20:15:20 +00:00
|
|
|
about: {
|
|
|
|
get label () {
|
2020-03-20 20:28:31 +00:00
|
|
|
return isLinux ? 'About' : `About ${app.name}`;
|
2020-05-21 22:38:26 +00:00
|
|
|
},
|
2020-07-06 20:24:54 +00:00
|
|
|
...(isWindows && { appMethod: () => app.showAboutPanel() })
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
2016-06-22 20:15:20 +00:00
|
|
|
close: {
|
2019-01-10 13:32:03 +00:00
|
|
|
label: isMac ? 'Close Window' : 'Close',
|
2016-06-22 22:26:17 +00:00
|
|
|
accelerator: 'CommandOrControl+W',
|
2020-07-06 20:24:54 +00:00
|
|
|
windowMethod: w => w.close()
|
2016-06-22 20:15:20 +00:00
|
|
|
},
|
|
|
|
copy: {
|
|
|
|
label: 'Copy',
|
2016-06-22 22:26:17 +00:00
|
|
|
accelerator: 'CommandOrControl+C',
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod: wc => wc.copy(),
|
2018-11-26 18:43:55 +00:00
|
|
|
registerAccelerator: false
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
|
|
|
cut: {
|
|
|
|
label: 'Cut',
|
2016-06-22 22:26:17 +00:00
|
|
|
accelerator: 'CommandOrControl+X',
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod: wc => wc.cut(),
|
2018-11-26 18:43:55 +00:00
|
|
|
registerAccelerator: false
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
2016-06-22 20:15:20 +00:00
|
|
|
delete: {
|
|
|
|
label: 'Delete',
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod: wc => wc.delete()
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
2017-02-02 19:18:35 +00:00
|
|
|
forcereload: {
|
|
|
|
label: 'Force Reload',
|
|
|
|
accelerator: 'Shift+CmdOrCtrl+R',
|
|
|
|
nonNativeMacOSRole: true,
|
2020-07-06 20:24:54 +00:00
|
|
|
windowMethod: (window: BrowserWindow) => {
|
2020-03-20 20:28:31 +00:00
|
|
|
window.webContents.reloadIgnoringCache();
|
2017-02-02 19:18:35 +00:00
|
|
|
}
|
|
|
|
},
|
2016-06-22 20:15:20 +00:00
|
|
|
front: {
|
|
|
|
label: 'Bring All to Front'
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
2016-06-22 20:15:20 +00:00
|
|
|
help: {
|
|
|
|
label: 'Help'
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
2016-06-22 20:15:20 +00:00
|
|
|
hide: {
|
|
|
|
get label () {
|
2020-03-20 20:28:31 +00:00
|
|
|
return `Hide ${app.name}`;
|
2016-06-22 20:15:20 +00:00
|
|
|
},
|
|
|
|
accelerator: 'Command+H'
|
|
|
|
},
|
|
|
|
hideothers: {
|
|
|
|
label: 'Hide Others',
|
|
|
|
accelerator: 'Command+Alt+H'
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
|
|
|
minimize: {
|
|
|
|
label: 'Minimize',
|
2016-06-22 22:26:17 +00:00
|
|
|
accelerator: 'CommandOrControl+M',
|
2020-07-06 20:24:54 +00:00
|
|
|
windowMethod: w => w.minimize()
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
2016-06-22 20:15:20 +00:00
|
|
|
paste: {
|
|
|
|
label: 'Paste',
|
2016-06-22 22:26:17 +00:00
|
|
|
accelerator: 'CommandOrControl+V',
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod: wc => wc.paste(),
|
2018-11-26 18:43:55 +00:00
|
|
|
registerAccelerator: false
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
2016-06-22 20:15:20 +00:00
|
|
|
pasteandmatchstyle: {
|
|
|
|
label: 'Paste and Match Style',
|
2020-06-17 21:13:46 +00:00
|
|
|
accelerator: isMac ? 'Cmd+Option+Shift+V' : 'Shift+CommandOrControl+V',
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod: wc => wc.pasteAndMatchStyle(),
|
2018-11-26 18:43:55 +00:00
|
|
|
registerAccelerator: false
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
|
|
|
quit: {
|
|
|
|
get label () {
|
2016-06-22 22:26:17 +00:00
|
|
|
switch (process.platform) {
|
2020-03-20 20:28:31 +00:00
|
|
|
case 'darwin': return `Quit ${app.name}`;
|
|
|
|
case 'win32': return 'Exit';
|
|
|
|
default: return 'Quit';
|
2016-06-22 22:26:17 +00:00
|
|
|
}
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
2019-07-16 19:54:18 +00:00
|
|
|
accelerator: isWindows ? undefined : 'CommandOrControl+Q',
|
2020-07-06 20:24:54 +00:00
|
|
|
appMethod: () => app.quit()
|
2016-06-22 17:29:49 +00:00
|
|
|
},
|
2016-06-22 20:15:20 +00:00
|
|
|
redo: {
|
|
|
|
label: 'Redo',
|
2019-01-10 13:32:03 +00:00
|
|
|
accelerator: isWindows ? 'Control+Y' : 'Shift+CommandOrControl+Z',
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod: wc => wc.redo()
|
2016-06-22 20:15:20 +00:00
|
|
|
},
|
2016-11-15 18:49:51 +00:00
|
|
|
reload: {
|
|
|
|
label: 'Reload',
|
|
|
|
accelerator: 'CmdOrCtrl+R',
|
2017-02-02 19:18:35 +00:00
|
|
|
nonNativeMacOSRole: true,
|
2020-07-06 20:24:54 +00:00
|
|
|
windowMethod: w => w.reload()
|
2016-11-15 18:49:51 +00:00
|
|
|
},
|
2016-08-08 17:09:45 +00:00
|
|
|
resetzoom: {
|
|
|
|
label: 'Actual Size',
|
|
|
|
accelerator: 'CommandOrControl+0',
|
2017-02-02 19:18:35 +00:00
|
|
|
nonNativeMacOSRole: true,
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod: (webContents: WebContents) => {
|
2020-03-20 20:28:31 +00:00
|
|
|
webContents.zoomLevel = 0;
|
2016-08-08 17:09:45 +00:00
|
|
|
}
|
|
|
|
},
|
2016-06-22 20:15:20 +00:00
|
|
|
selectall: {
|
|
|
|
label: 'Select All',
|
2016-06-22 22:26:17 +00:00
|
|
|
accelerator: 'CommandOrControl+A',
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod: wc => wc.selectAll()
|
2016-06-22 20:15:20 +00:00
|
|
|
},
|
|
|
|
services: {
|
|
|
|
label: 'Services'
|
|
|
|
},
|
2017-11-21 00:31:21 +00:00
|
|
|
recentdocuments: {
|
2017-11-21 00:15:43 +00:00
|
|
|
label: 'Open Recent'
|
|
|
|
},
|
2017-11-21 00:31:21 +00:00
|
|
|
clearrecentdocuments: {
|
2017-11-21 00:15:43 +00:00
|
|
|
label: 'Clear Menu'
|
2017-11-19 05:52:52 +00:00
|
|
|
},
|
2016-08-07 22:02:32 +00:00
|
|
|
startspeaking: {
|
|
|
|
label: 'Start Speaking'
|
|
|
|
},
|
|
|
|
stopspeaking: {
|
|
|
|
label: 'Stop Speaking'
|
|
|
|
},
|
2016-11-15 18:52:03 +00:00
|
|
|
toggledevtools: {
|
|
|
|
label: 'Toggle Developer Tools',
|
2019-01-10 13:32:03 +00:00
|
|
|
accelerator: isMac ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
2017-02-02 19:18:35 +00:00
|
|
|
nonNativeMacOSRole: true,
|
2020-07-06 20:24:54 +00:00
|
|
|
windowMethod: w => w.webContents.toggleDevTools()
|
2016-11-15 18:52:03 +00:00
|
|
|
},
|
2016-06-22 17:29:49 +00:00
|
|
|
togglefullscreen: {
|
|
|
|
label: 'Toggle Full Screen',
|
2019-01-10 13:32:03 +00:00
|
|
|
accelerator: isMac ? 'Control+Command+F' : 'F11',
|
2020-07-06 20:24:54 +00:00
|
|
|
windowMethod: (window: BrowserWindow) => {
|
2020-03-20 20:28:31 +00:00
|
|
|
window.setFullScreen(!window.isFullScreen());
|
2016-06-22 20:48:26 +00:00
|
|
|
}
|
2016-06-22 17:47:25 +00:00
|
|
|
},
|
2016-06-22 20:15:20 +00:00
|
|
|
undo: {
|
|
|
|
label: 'Undo',
|
2016-06-22 22:26:17 +00:00
|
|
|
accelerator: 'CommandOrControl+Z',
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod: wc => wc.undo()
|
2016-06-22 20:15:20 +00:00
|
|
|
},
|
|
|
|
unhide: {
|
|
|
|
label: 'Show All'
|
2016-06-22 17:47:25 +00:00
|
|
|
},
|
|
|
|
window: {
|
|
|
|
label: 'Window'
|
2016-06-22 20:09:39 +00:00
|
|
|
},
|
|
|
|
zoom: {
|
|
|
|
label: 'Zoom'
|
2016-08-08 17:09:45 +00:00
|
|
|
},
|
|
|
|
zoomin: {
|
|
|
|
label: 'Zoom In',
|
|
|
|
accelerator: 'CommandOrControl+Plus',
|
2017-02-02 19:18:35 +00:00
|
|
|
nonNativeMacOSRole: true,
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod: (webContents: WebContents) => {
|
2020-03-20 20:28:31 +00:00
|
|
|
webContents.zoomLevel += 0.5;
|
2016-08-08 17:09:45 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
zoomout: {
|
|
|
|
label: 'Zoom Out',
|
|
|
|
accelerator: 'CommandOrControl+-',
|
2017-02-02 19:18:35 +00:00
|
|
|
nonNativeMacOSRole: true,
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod: (webContents: WebContents) => {
|
2020-03-20 20:28:31 +00:00
|
|
|
webContents.zoomLevel -= 0.5;
|
2016-08-08 17:09:45 +00:00
|
|
|
}
|
2017-03-09 15:01:33 +00:00
|
|
|
},
|
2019-01-10 13:32:03 +00:00
|
|
|
// App submenu should be used for Mac only
|
|
|
|
appmenu: {
|
|
|
|
get label () {
|
2020-03-20 20:28:31 +00:00
|
|
|
return app.name;
|
2019-01-10 13:32:03 +00:00
|
|
|
},
|
|
|
|
submenu: [
|
|
|
|
{ role: 'about' },
|
|
|
|
{ type: 'separator' },
|
|
|
|
{ role: 'services' },
|
|
|
|
{ type: 'separator' },
|
|
|
|
{ role: 'hide' },
|
2019-07-31 21:13:56 +00:00
|
|
|
{ role: 'hideOthers' },
|
2019-01-10 13:32:03 +00:00
|
|
|
{ role: 'unhide' },
|
|
|
|
{ type: 'separator' },
|
|
|
|
{ role: 'quit' }
|
|
|
|
]
|
|
|
|
},
|
|
|
|
// File submenu
|
|
|
|
filemenu: {
|
|
|
|
label: 'File',
|
|
|
|
submenu: [
|
|
|
|
isMac ? { role: 'close' } : { role: 'quit' }
|
|
|
|
]
|
|
|
|
},
|
|
|
|
// Edit submenu
|
2017-12-28 05:22:39 +00:00
|
|
|
editmenu: {
|
2017-03-09 15:01:33 +00:00
|
|
|
label: 'Edit',
|
|
|
|
submenu: [
|
2019-01-10 13:32:03 +00:00
|
|
|
{ role: 'undo' },
|
|
|
|
{ role: 'redo' },
|
|
|
|
{ type: 'separator' },
|
|
|
|
{ role: 'cut' },
|
|
|
|
{ role: 'copy' },
|
|
|
|
{ role: 'paste' },
|
|
|
|
...(isMac ? [
|
|
|
|
{ role: 'pasteAndMatchStyle' },
|
|
|
|
{ role: 'delete' },
|
|
|
|
{ role: 'selectAll' },
|
|
|
|
{ type: 'separator' },
|
|
|
|
{
|
|
|
|
label: 'Speech',
|
|
|
|
submenu: [
|
2019-07-31 21:13:56 +00:00
|
|
|
{ role: 'startSpeaking' },
|
|
|
|
{ role: 'stopSpeaking' }
|
2019-01-10 13:32:03 +00:00
|
|
|
]
|
|
|
|
}
|
2020-07-06 20:24:54 +00:00
|
|
|
] as MenuItemConstructorOptions[] : [
|
2019-01-10 13:32:03 +00:00
|
|
|
{ role: 'delete' },
|
|
|
|
{ type: 'separator' },
|
|
|
|
{ role: 'selectAll' }
|
2020-07-06 20:24:54 +00:00
|
|
|
] as MenuItemConstructorOptions[])
|
2017-03-09 15:01:33 +00:00
|
|
|
]
|
|
|
|
},
|
2019-01-10 13:32:03 +00:00
|
|
|
// View submenu
|
|
|
|
viewmenu: {
|
|
|
|
label: 'View',
|
|
|
|
submenu: [
|
|
|
|
{ role: 'reload' },
|
2019-07-31 21:13:56 +00:00
|
|
|
{ role: 'forceReload' },
|
|
|
|
{ role: 'toggleDevTools' },
|
2019-01-10 13:32:03 +00:00
|
|
|
{ type: 'separator' },
|
2019-07-31 21:13:56 +00:00
|
|
|
{ role: 'resetZoom' },
|
|
|
|
{ role: 'zoomIn' },
|
|
|
|
{ role: 'zoomOut' },
|
2019-01-10 13:32:03 +00:00
|
|
|
{ type: 'separator' },
|
|
|
|
{ role: 'togglefullscreen' }
|
|
|
|
]
|
|
|
|
},
|
|
|
|
// Window submenu
|
2017-12-28 05:22:39 +00:00
|
|
|
windowmenu: {
|
2017-03-09 15:01:33 +00:00
|
|
|
label: 'Window',
|
|
|
|
submenu: [
|
2019-01-10 13:32:03 +00:00
|
|
|
{ role: 'minimize' },
|
|
|
|
{ role: 'zoom' },
|
|
|
|
...(isMac ? [
|
|
|
|
{ type: 'separator' },
|
2019-01-14 16:27:52 +00:00
|
|
|
{ role: 'front' }
|
2020-07-06 20:24:54 +00:00
|
|
|
] as MenuItemConstructorOptions[] : [
|
2019-01-10 13:32:03 +00:00
|
|
|
{ role: 'close' }
|
2020-07-06 20:24:54 +00:00
|
|
|
] as MenuItemConstructorOptions[])
|
2017-03-09 15:01:33 +00:00
|
|
|
]
|
2016-06-22 17:29:49 +00:00
|
|
|
}
|
2020-03-20 20:28:31 +00:00
|
|
|
};
|
2016-06-22 17:45:01 +00:00
|
|
|
|
2020-07-06 20:24:54 +00:00
|
|
|
const canExecuteRole = (role: keyof typeof roleList) => {
|
|
|
|
if (!Object.prototype.hasOwnProperty.call(roleList, role)) return false;
|
2020-03-20 20:28:31 +00:00
|
|
|
if (!isMac) return true;
|
2018-02-23 13:53:59 +00:00
|
|
|
|
2017-02-02 19:18:35 +00:00
|
|
|
// macOS handles all roles natively except for a few
|
2020-07-06 20:24:54 +00:00
|
|
|
return roleList[role].nonNativeMacOSRole;
|
2020-03-20 20:28:31 +00:00
|
|
|
};
|
2016-08-08 17:09:45 +00:00
|
|
|
|
2020-07-06 20:24:54 +00:00
|
|
|
export function getDefaultLabel (role: RoleId) {
|
|
|
|
return Object.prototype.hasOwnProperty.call(roleList, role) ? roleList[role].label : '';
|
|
|
|
}
|
2016-06-22 17:45:01 +00:00
|
|
|
|
2020-07-06 20:24:54 +00:00
|
|
|
export function getDefaultAccelerator (role: RoleId) {
|
|
|
|
if (Object.prototype.hasOwnProperty.call(roleList, role)) return roleList[role].accelerator;
|
|
|
|
}
|
2016-06-22 20:48:26 +00:00
|
|
|
|
2020-07-06 20:24:54 +00:00
|
|
|
export function shouldRegisterAccelerator (role: RoleId) {
|
|
|
|
const hasRoleRegister = Object.prototype.hasOwnProperty.call(roleList, role) && roleList[role].registerAccelerator !== undefined;
|
|
|
|
return hasRoleRegister ? roleList[role].registerAccelerator : true;
|
|
|
|
}
|
2018-11-26 18:43:55 +00:00
|
|
|
|
2020-07-06 20:24:54 +00:00
|
|
|
export function getDefaultSubmenu (role: RoleId) {
|
|
|
|
if (!Object.prototype.hasOwnProperty.call(roleList, role)) return;
|
2017-03-09 15:01:33 +00:00
|
|
|
|
2020-07-06 20:24:54 +00:00
|
|
|
let { submenu } = roleList[role];
|
2017-03-09 15:01:33 +00:00
|
|
|
|
2017-03-29 19:27:59 +00:00
|
|
|
// remove null items from within the submenu
|
|
|
|
if (Array.isArray(submenu)) {
|
2020-03-20 20:28:31 +00:00
|
|
|
submenu = submenu.filter((item) => item != null);
|
2017-03-09 15:01:33 +00:00
|
|
|
}
|
2017-03-29 19:27:59 +00:00
|
|
|
|
2020-03-20 20:28:31 +00:00
|
|
|
return submenu;
|
2020-07-06 20:24:54 +00:00
|
|
|
}
|
2017-03-09 15:01:33 +00:00
|
|
|
|
2020-07-06 20:24:54 +00:00
|
|
|
export function execute (role: RoleId, focusedWindow: BrowserWindow, focusedWebContents: WebContents) {
|
2020-03-20 20:28:31 +00:00
|
|
|
if (!canExecuteRole(role)) return false;
|
2016-06-22 20:48:26 +00:00
|
|
|
|
2020-07-06 20:24:54 +00:00
|
|
|
const { appMethod, webContentsMethod, windowMethod } = roleList[role];
|
2016-06-22 20:48:26 +00:00
|
|
|
|
|
|
|
if (appMethod) {
|
2020-07-06 20:24:54 +00:00
|
|
|
appMethod();
|
2020-03-20 20:28:31 +00:00
|
|
|
return true;
|
2016-06-22 20:48:26 +00:00
|
|
|
}
|
|
|
|
|
2016-06-22 21:14:32 +00:00
|
|
|
if (windowMethod && focusedWindow != null) {
|
2020-07-06 20:24:54 +00:00
|
|
|
windowMethod(focusedWindow);
|
2020-03-20 20:28:31 +00:00
|
|
|
return true;
|
2016-06-22 21:14:32 +00:00
|
|
|
}
|
|
|
|
|
2016-07-13 19:18:44 +00:00
|
|
|
if (webContentsMethod && focusedWebContents != null) {
|
2020-07-06 20:24:54 +00:00
|
|
|
webContentsMethod(focusedWebContents);
|
2020-03-20 20:28:31 +00:00
|
|
|
return true;
|
2016-06-22 20:48:26 +00:00
|
|
|
}
|
|
|
|
|
2020-03-20 20:28:31 +00:00
|
|
|
return false;
|
2020-07-06 20:24:54 +00:00
|
|
|
}
|