Merge pull request #4021 from vector-im/t3chguy/electron_context_menus
add moar context menus [Electron]
This commit is contained in:
commit
5ccab395d7
|
@ -24,11 +24,11 @@ const check_squirrel_hooks = require('./squirrelhooks');
|
|||
if (check_squirrel_hooks()) return;
|
||||
|
||||
const electron = require('electron');
|
||||
const url = require('url');
|
||||
|
||||
const tray = require('./tray');
|
||||
|
||||
const VectorMenu = require('./vectormenu');
|
||||
const webContentsHandler = require('./webcontents-handler');
|
||||
|
||||
const windowStateKeeper = require('electron-window-state');
|
||||
|
||||
|
@ -42,60 +42,12 @@ try {
|
|||
// Continue with the defaults (ie. an empty config)
|
||||
}
|
||||
|
||||
const PERMITTED_URL_SCHEMES = [
|
||||
'http:',
|
||||
'https:',
|
||||
'mailto:',
|
||||
];
|
||||
|
||||
const UPDATE_POLL_INTERVAL_MS = 60 * 60 * 1000;
|
||||
const INITIAL_UPDATE_DELAY_MS = 30 * 1000;
|
||||
|
||||
let mainWindow = null;
|
||||
let appQuitting = false;
|
||||
|
||||
function safeOpenURL(target) {
|
||||
// openExternal passes the target to open/start/xdg-open,
|
||||
// so put fairly stringent limits on what can be opened
|
||||
// (for instance, open /bin/sh does indeed open a terminal
|
||||
// with a shell, albeit with no arguments)
|
||||
const parsed_url = url.parse(target);
|
||||
if (PERMITTED_URL_SCHEMES.indexOf(parsed_url.protocol) > -1) {
|
||||
// explicitly use the URL re-assembled by the url library,
|
||||
// so we know the url parser has understood all the parts
|
||||
// of the input string
|
||||
const new_target = url.format(parsed_url);
|
||||
electron.shell.openExternal(new_target);
|
||||
}
|
||||
}
|
||||
|
||||
function onWindowOrNavigate(ev, target) {
|
||||
// always prevent the default: if something goes wrong,
|
||||
// we don't want to end up opening it in the electron
|
||||
// app, as we could end up opening any sort of random
|
||||
// url in a window that has node scripting access.
|
||||
ev.preventDefault();
|
||||
safeOpenURL(target);
|
||||
}
|
||||
|
||||
function onLinkContextMenu(ev, params) {
|
||||
const popup_menu = new electron.Menu();
|
||||
popup_menu.append(new electron.MenuItem({
|
||||
label: params.linkURL,
|
||||
click() {
|
||||
safeOpenURL(params.linkURL);
|
||||
},
|
||||
}));
|
||||
popup_menu.append(new electron.MenuItem({
|
||||
label: 'Copy Link Address',
|
||||
click() {
|
||||
electron.clipboard.writeText(params.linkURL);
|
||||
},
|
||||
}));
|
||||
popup_menu.popup();
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
function installUpdate() {
|
||||
// for some reason, quitAndInstall does not fire the
|
||||
// before-quit event, so we need to set the flag here.
|
||||
|
@ -259,15 +211,7 @@ electron.app.on('ready', () => {
|
|||
}
|
||||
});
|
||||
|
||||
mainWindow.webContents.on('new-window', onWindowOrNavigate);
|
||||
mainWindow.webContents.on('will-navigate', onWindowOrNavigate);
|
||||
|
||||
mainWindow.webContents.on('context-menu', function(ev, params) {
|
||||
if (params.linkURL) {
|
||||
onLinkContextMenu(ev, params);
|
||||
}
|
||||
});
|
||||
|
||||
webContentsHandler(mainWindow.webContents);
|
||||
mainWindowState.manage(mainWindow);
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
const {clipboard, nativeImage, Menu, MenuItem, shell} = require('electron');
|
||||
const url = require('url');
|
||||
|
||||
const PERMITTED_URL_SCHEMES = [
|
||||
'http:',
|
||||
'https:',
|
||||
'mailto:',
|
||||
];
|
||||
|
||||
function safeOpenURL(target) {
|
||||
// openExternal passes the target to open/start/xdg-open,
|
||||
// so put fairly stringent limits on what can be opened
|
||||
// (for instance, open /bin/sh does indeed open a terminal
|
||||
// with a shell, albeit with no arguments)
|
||||
const parsedUrl = url.parse(target);
|
||||
if (PERMITTED_URL_SCHEMES.indexOf(parsedUrl.protocol) > -1) {
|
||||
// explicitly use the URL re-assembled by the url library,
|
||||
// so we know the url parser has understood all the parts
|
||||
// of the input string
|
||||
const newTarget = url.format(parsedUrl);
|
||||
shell.openExternal(newTarget);
|
||||
}
|
||||
}
|
||||
|
||||
function onWindowOrNavigate(ev, target) {
|
||||
// always prevent the default: if something goes wrong,
|
||||
// we don't want to end up opening it in the electron
|
||||
// app, as we could end up opening any sort of random
|
||||
// url in a window that has node scripting access.
|
||||
ev.preventDefault();
|
||||
safeOpenURL(target);
|
||||
}
|
||||
|
||||
function onLinkContextMenu(ev, params) {
|
||||
const url = params.linkURL || params.srcURL;
|
||||
|
||||
const popupMenu = new Menu();
|
||||
popupMenu.append(new MenuItem({
|
||||
label: url,
|
||||
click() {
|
||||
safeOpenURL(url);
|
||||
},
|
||||
}));
|
||||
|
||||
if (params.mediaType && params.mediaType === 'image' && !url.startsWith('file://')) {
|
||||
popupMenu.append(new MenuItem({
|
||||
label: 'Copy Image',
|
||||
click() {
|
||||
if (url.startsWith('data:')) {
|
||||
clipboard.writeImage(nativeImage.createFromDataURL(url));
|
||||
} else {
|
||||
ev.sender.copyImageAt(params.x, params.y);
|
||||
}
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
popupMenu.append(new MenuItem({
|
||||
label: 'Copy Link Address',
|
||||
click() {
|
||||
clipboard.writeText(url);
|
||||
},
|
||||
}));
|
||||
popupMenu.popup();
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
function _CutCopyPasteSelectContextMenus(params) {
|
||||
return [{
|
||||
role: 'cut',
|
||||
enabled: params.editFlags.canCut,
|
||||
}, {
|
||||
role: 'copy',
|
||||
enabled: params.editFlags.canCopy,
|
||||
}, {
|
||||
role: 'paste',
|
||||
enabled: params.editFlags.canPaste,
|
||||
}, {
|
||||
role: 'pasteandmatchstyle',
|
||||
enabled: params.editFlags.canPaste,
|
||||
}, {
|
||||
role: 'selectall',
|
||||
enabled: params.editFlags.canSelectAll,
|
||||
}];
|
||||
}
|
||||
|
||||
function onSelectedContextMenu(ev, params) {
|
||||
const items = _CutCopyPasteSelectContextMenus(params);
|
||||
const popupMenu = Menu.buildFromTemplate(items);
|
||||
|
||||
popupMenu.popup();
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
function onEditableContextMenu(ev, params) {
|
||||
const items = [
|
||||
{ role: 'undo' },
|
||||
{ role: 'redo', enabled: params.editFlags.canRedo },
|
||||
{ type: 'separator' },
|
||||
].concat(_CutCopyPasteSelectContextMenus(params));
|
||||
|
||||
const popupMenu = Menu.buildFromTemplate(items);
|
||||
|
||||
popupMenu.popup();
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
|
||||
module.exports = (webContents) => {
|
||||
webContents.on('new-window', onWindowOrNavigate);
|
||||
webContents.on('will-navigate', onWindowOrNavigate);
|
||||
|
||||
webContents.on('context-menu', function(ev, params) {
|
||||
if (params.linkURL || params.srcURL) {
|
||||
onLinkContextMenu(ev, params);
|
||||
} else if (params.selectionText) {
|
||||
onSelectedContextMenu(ev, params);
|
||||
} else if (params.isEditable) {
|
||||
onEditableContextMenu(ev, params);
|
||||
}
|
||||
});
|
||||
};
|
Loading…
Reference in New Issue