Add right click context menu on all text inputs #1486
5 changed files with 63 additions and 84 deletions
|
@ -3,7 +3,6 @@ import isDev from 'electron-is-dev';
|
|||
import windowStateKeeper from 'electron-window-state';
|
||||
|
||||
import setupBarMenu from './menu/setupBarMenu';
|
||||
import setupContextMenu from './menu/setupContextMenu';
|
||||
|
||||
export default appState => {
|
||||
// Get primary display dimensions from Electron.
|
||||
|
@ -73,7 +72,6 @@ export default appState => {
|
|||
}
|
||||
|
||||
setupBarMenu();
|
||||
setupContextMenu(window);
|
||||
|
||||
window.on('close', event => {
|
||||
if (!appState.isQuitting && !appState.autoUpdateAccepted) {
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
// @flow
|
||||
import { Menu, BrowserWindow } from 'electron';
|
||||
import isDev from 'electron-is-dev';
|
||||
|
||||
export default (rendererWindow: BrowserWindow) => {
|
||||
rendererWindow.webContents.on('context-menu', (e, params) => {
|
||||
const { x, y } = params;
|
||||
|
||||
const template = [{ role: 'cut' }, { role: 'copy' }, { role: 'paste' }];
|
||||
|
||||
const developmentTemplateAddition = [
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Inspect element',
|
||||
click: () => {
|
||||
rendererWindow.inspectElement(x, y);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
if (isDev) {
|
||||
template.push(...developmentTemplateAddition);
|
||||
}
|
||||
|
||||
Menu.buildFromTemplate(template).popup();
|
||||
});
|
||||
};
|
|
@ -9,6 +9,7 @@ import FilePrice from 'component/filePrice';
|
|||
import UriIndicator from 'component/uriIndicator';
|
||||
import * as icons from 'constants/icons';
|
||||
import classnames from 'classnames';
|
||||
import { openCopyLinkMenu } from '../../util/contextMenu';
|
||||
|
||||
// TODO: iron these out
|
||||
type Props = {
|
||||
|
@ -60,6 +61,9 @@ class FileCard extends React.PureComponent<Props> {
|
|||
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw;
|
||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||
const handleContextMenu = event => {
|
||||
openCopyLinkMenu(uri, event);
|
||||
};
|
||||
|
||||
// We should be able to tab through cards
|
||||
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
||||
|
@ -72,6 +76,7 @@ class FileCard extends React.PureComponent<Props> {
|
|||
'card--link': !pending,
|
||||
'card--pending': pending,
|
||||
})}
|
||||
onContextMenu={handleContextMenu}
|
||||
>
|
||||
<CardMedia nsfw={shouldObscureNsfw} thumbnail={thumbnail} />
|
||||
<div className="card-media__internal-links">{showPrice && <FilePrice uri={uri} />}</div>
|
||||
|
|
|
@ -16,7 +16,7 @@ import 'scss/all.scss';
|
|||
import store from 'store';
|
||||
import app from './app';
|
||||
import analytics from './analytics';
|
||||
import getMenu from './util/contextMenu';
|
||||
import { initContextMenu } from './util/contextMenu';
|
||||
|
||||
const { autoUpdater } = remote.require('electron-updater');
|
||||
|
||||
|
@ -96,7 +96,7 @@ document.addEventListener('click', event => {
|
|||
}
|
||||
});
|
||||
|
||||
document.addEventListener('contextmenu', getMenu);
|
||||
document.addEventListener('contextmenu', initContextMenu);
|
||||
|
||||
const init = () => {
|
||||
autoUpdater.on('update-downloaded', () => {
|
||||
|
@ -132,7 +132,7 @@ const init = () => {
|
|||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<div>
|
||||
<App />
|
||||
<App onContextMenu={e => openContextMenu(e)} />
|
||||
<SnackBar />
|
||||
</div>
|
||||
</Provider>,
|
||||
|
|
|
@ -1,65 +1,68 @@
|
|||
import { clipboard, remote } from 'electron';
|
||||
import isDev from 'electron-is-dev';
|
||||
|
||||
function textInputTemplate(target) {
|
||||
const somethingSelected = target.selectionStart < target.selectionEnd;
|
||||
const hasValue = target.value.length > 0;
|
||||
|
||||
// Native Electron selectAll role does not work
|
||||
function selectAll() {
|
||||
target.selectionStart = 0;
|
||||
target.selectionEnd = target.value.length + 1;
|
||||
}
|
||||
|
||||
const template = [
|
||||
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut', enabled: somethingSelected },
|
||||
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy', enabled: somethingSelected },
|
||||
function injectDevelopmentTemplate(event, templates) {
|
||||
if (!isDev) return templates;
|
||||
const { screenX, screenY } = event;
|
||||
const separator = { type: 'separator' };
|
||||
const developmentTemplateAddition = [
|
||||
{
|
||||
label: 'Paste',
|
||||
accelerator: 'CmdOrCtrl+V',
|
||||
role: 'paste',
|
||||
enabled: clipboard.readText().length > 0,
|
||||
},
|
||||
{
|
||||
label: 'Select All',
|
||||
accelerator: 'CmdOrCtrl+A',
|
||||
role: 'selectAll',
|
||||
enabled: hasValue,
|
||||
click: selectAll,
|
||||
label: 'Inspect element',
|
||||
accelerator: 'CmdOrCtrl+Shift+I',
|
||||
click: () => {
|
||||
remote.getCurrentWindow().inspectElement(screenX, screenY);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
function getTemplate(target) {
|
||||
const { type } = target;
|
||||
if (target.matches('input') && (type === 'text' || type === 'number')) {
|
||||
return textInputTemplate(target);
|
||||
if (templates.length > 0) {
|
||||
templates.push(separator);
|
||||
}
|
||||
return [];
|
||||
templates.push(...developmentTemplateAddition);
|
||||
return templates;
|
||||
}
|
||||
|
||||
export default event => {
|
||||
event.preventDefault();
|
||||
const { target } = event;
|
||||
const template = getTemplate(target);
|
||||
if (isDev) {
|
||||
const { screenX, screenY } = event;
|
||||
const separator = { type: 'separator' };
|
||||
const developmentTemplateAddition = [
|
||||
export function openContextMenu(event, templates = [], addDefaultTemplates = true) {
|
||||
if (addDefaultTemplates) {
|
||||
const { value } = event.target;
|
||||
const inputTemplates = [
|
||||
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut' },
|
||||
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' },
|
||||
{
|
||||
label: 'Inspect element',
|
||||
accelerator: 'CmdOrCtrl+Shift+I',
|
||||
click: () => {
|
||||
remote.getCurrentWindow().inspectElement(screenX, screenY);
|
||||
},
|
||||
label: 'Paste',
|
||||
accelerator: 'CmdOrCtrl+V',
|
||||
role: 'paste',
|
||||
enabled: clipboard.readText().length > 0,
|
||||
},
|
||||
{
|
||||
label: 'Select All',
|
||||
accelerator: 'CmdOrCtrl+A',
|
||||
role: 'selectall',
|
||||
enabled: !!value,
|
||||
},
|
||||
];
|
||||
if (template.length > 0) {
|
||||
template.push(separator);
|
||||
}
|
||||
template.push(...developmentTemplateAddition);
|
||||
templates.push(...inputTemplates);
|
||||
}
|
||||
remote.Menu.buildFromTemplate(template).popup();
|
||||
};
|
||||
|
||||
injectDevelopmentTemplate(event, templates);
|
||||
remote.Menu.buildFromTemplate(templates).popup();
|
||||
}
|
||||
export function openCopyLinkMenu(text, event) {
|
||||
const templates = [
|
||||
{
|
||||
label: 'Copy link',
|
||||
click: () => {
|
||||
clipboard.writeText(text);
|
||||
},
|
||||
},
|
||||
];
|
||||
openContextMenu(event, templates, false);
|
||||
}
|
||||
|
||||
export function initContextMenu(event) {
|
||||
const { type } = event.target;
|
||||
if (event.target.matches('input') && (type === 'text' || type === 'number')) {
|
||||
openContextMenu(event);
|
||||
} else {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue