Add right click context menu on all text inputs #1486
5 changed files with 78 additions and 31 deletions
|
@ -3,7 +3,6 @@ import isDev from 'electron-is-dev';
|
||||||
import windowStateKeeper from 'electron-window-state';
|
import windowStateKeeper from 'electron-window-state';
|
||||||
|
|
||||||
import setupBarMenu from './menu/setupBarMenu';
|
import setupBarMenu from './menu/setupBarMenu';
|
||||||
import setupContextMenu from './menu/setupContextMenu';
|
|
||||||
|
|
||||||
export default appState => {
|
export default appState => {
|
||||||
// Get primary display dimensions from Electron.
|
// Get primary display dimensions from Electron.
|
||||||
|
@ -73,7 +72,6 @@ export default appState => {
|
||||||
}
|
}
|
||||||
|
|
||||||
setupBarMenu();
|
setupBarMenu();
|
||||||
setupContextMenu(window);
|
|
||||||
|
|
||||||
window.on('close', event => {
|
window.on('close', event => {
|
||||||
if (!appState.isQuitting && !appState.autoUpdateAccepted) {
|
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();
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { normalizeURI } from 'lbry-redux';
|
import { normalizeURI, convertToShareLink } from 'lbry-redux';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import CardMedia from 'component/cardMedia';
|
import CardMedia from 'component/cardMedia';
|
||||||
import TruncatedText from 'component/common/truncated-text';
|
import TruncatedText from 'component/common/truncated-text';
|
||||||
|
@ -9,6 +9,7 @@ import FilePrice from 'component/filePrice';
|
||||||
import UriIndicator from 'component/uriIndicator';
|
import UriIndicator from 'component/uriIndicator';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import { openCopyLinkMenu } from '../../util/contextMenu';
|
||||||
|
|
||||||
// TODO: iron these out
|
// TODO: iron these out
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -60,6 +61,9 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||||
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw;
|
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw;
|
||||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||||
|
const handleContextMenu = event => {
|
||||||
|
openCopyLinkMenu(convertToShareLink(uri), event);
|
||||||
|
};
|
||||||
|
|
||||||
// We should be able to tab through cards
|
// We should be able to tab through cards
|
||||||
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
||||||
|
@ -72,6 +76,7 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
'card--link': !pending,
|
'card--link': !pending,
|
||||||
'card--pending': pending,
|
'card--pending': pending,
|
||||||
})}
|
})}
|
||||||
|
onContextMenu={handleContextMenu}
|
||||||
>
|
>
|
||||||
<CardMedia nsfw={shouldObscureNsfw} thumbnail={thumbnail} />
|
<CardMedia nsfw={shouldObscureNsfw} thumbnail={thumbnail} />
|
||||||
<div className="card-media__internal-links">{showPrice && <FilePrice uri={uri} />}</div>
|
<div className="card-media__internal-links">{showPrice && <FilePrice uri={uri} />}</div>
|
||||||
|
|
|
@ -16,6 +16,7 @@ import 'scss/all.scss';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
import app from './app';
|
import app from './app';
|
||||||
import analytics from './analytics';
|
import analytics from './analytics';
|
||||||
|
import { initContextMenu } from './util/contextMenu';
|
||||||
|
|
||||||
const { autoUpdater } = remote.require('electron-updater');
|
const { autoUpdater } = remote.require('electron-updater');
|
||||||
|
|
||||||
|
@ -95,6 +96,8 @@ document.addEventListener('click', event => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.addEventListener('contextmenu', initContextMenu);
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
autoUpdater.on('update-downloaded', () => {
|
autoUpdater.on('update-downloaded', () => {
|
||||||
app.store.dispatch(doAutoUpdate());
|
app.store.dispatch(doAutoUpdate());
|
||||||
|
@ -129,7 +132,7 @@ const init = () => {
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<div>
|
<div>
|
||||||
<App />
|
<App onContextMenu={e => openContextMenu(e)} />
|
||||||
<SnackBar />
|
<SnackBar />
|
||||||
</div>
|
</div>
|
||||||
</Provider>,
|
</Provider>,
|
||||||
|
|
68
src/renderer/util/contextMenu.js
Normal file
68
src/renderer/util/contextMenu.js
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import { clipboard, remote } from 'electron';
|
||||||
|
import isDev from 'electron-is-dev';
|
||||||
|
|
||||||
|
function injectDevelopmentTemplate(event, templates) {
|
||||||
|
if (!isDev) return templates;
|
||||||
|
const { screenX, screenY } = event;
|
||||||
|
const separator = { type: 'separator' };
|
||||||
|
const developmentTemplateAddition = [
|
||||||
|
{
|
||||||
|
label: 'Inspect element',
|
||||||
|
accelerator: 'CmdOrCtrl+Shift+I',
|
||||||
|
click: () => {
|
||||||
|
remote.getCurrentWindow().inspectElement(screenX, screenY);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
if (templates.length > 0) {
|
||||||
|
templates.push(separator);
|
||||||
|
}
|
||||||
|
templates.push(...developmentTemplateAddition);
|
||||||
|
return templates;
|
||||||
|
}
|
||||||
|
|
||||||
|
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: 'Paste',
|
||||||
|
accelerator: 'CmdOrCtrl+V',
|
||||||
|
role: 'paste',
|
||||||
|
enabled: clipboard.readText().length > 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Select All',
|
||||||
|
accelerator: 'CmdOrCtrl+A',
|
||||||
|
role: 'selectall',
|
||||||
|
enabled: !!value,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
templates.push(...inputTemplates);
|
||||||
|
}
|
||||||
|
|
||||||
|
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