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;
|
if (check_squirrel_hooks()) return;
|
||||||
|
|
||||||
const electron = require('electron');
|
const electron = require('electron');
|
||||||
const url = require('url');
|
|
||||||
|
|
||||||
const tray = require('./tray');
|
const tray = require('./tray');
|
||||||
|
|
||||||
const VectorMenu = require('./vectormenu');
|
const VectorMenu = require('./vectormenu');
|
||||||
|
const webContentsHandler = require('./webcontents-handler');
|
||||||
|
|
||||||
const windowStateKeeper = require('electron-window-state');
|
const windowStateKeeper = require('electron-window-state');
|
||||||
|
|
||||||
|
@ -42,60 +42,12 @@ try {
|
||||||
// Continue with the defaults (ie. an empty config)
|
// Continue with the defaults (ie. an empty config)
|
||||||
}
|
}
|
||||||
|
|
||||||
const PERMITTED_URL_SCHEMES = [
|
|
||||||
'http:',
|
|
||||||
'https:',
|
|
||||||
'mailto:',
|
|
||||||
];
|
|
||||||
|
|
||||||
const UPDATE_POLL_INTERVAL_MS = 60 * 60 * 1000;
|
const UPDATE_POLL_INTERVAL_MS = 60 * 60 * 1000;
|
||||||
const INITIAL_UPDATE_DELAY_MS = 30 * 1000;
|
const INITIAL_UPDATE_DELAY_MS = 30 * 1000;
|
||||||
|
|
||||||
let mainWindow = null;
|
let mainWindow = null;
|
||||||
let appQuitting = false;
|
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() {
|
function installUpdate() {
|
||||||
// for some reason, quitAndInstall does not fire the
|
// for some reason, quitAndInstall does not fire the
|
||||||
// before-quit event, so we need to set the flag here.
|
// 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);
|
webContentsHandler(mainWindow.webContents);
|
||||||
mainWindow.webContents.on('will-navigate', onWindowOrNavigate);
|
|
||||||
|
|
||||||
mainWindow.webContents.on('context-menu', function(ev, params) {
|
|
||||||
if (params.linkURL) {
|
|
||||||
onLinkContextMenu(ev, params);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mainWindowState.manage(mainWindow);
|
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