From ed2fe16f45c96bb95376e4bab0912eccded8ef53 Mon Sep 17 00:00:00 2001 From: Daniel Dominguez Date: Wed, 16 May 2018 18:34:07 -0300 Subject: [PATCH 1/3] Add right click context menu on all text inputs. --- src/renderer/index.js | 3 ++ src/renderer/util/contextMenu.js | 65 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/renderer/util/contextMenu.js diff --git a/src/renderer/index.js b/src/renderer/index.js index c82db3287..fe0b9e695 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -16,6 +16,7 @@ import 'scss/all.scss'; import store from 'store'; import app from './app'; import analytics from './analytics'; +import getMenu from './util/contextMenu'; const { autoUpdater } = remote.require('electron-updater'); @@ -95,6 +96,8 @@ document.addEventListener('click', event => { } }); +document.addEventListener('contextmenu', getMenu); + const init = () => { autoUpdater.on('update-downloaded', () => { app.store.dispatch(doAutoUpdate()); diff --git a/src/renderer/util/contextMenu.js b/src/renderer/util/contextMenu.js new file mode 100644 index 000000000..0348423bf --- /dev/null +++ b/src/renderer/util/contextMenu.js @@ -0,0 +1,65 @@ +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 }, + { + label: 'Paste', + accelerator: 'CmdOrCtrl+V', + role: 'paste', + enabled: clipboard.readText().length > 0, + }, + { + label: 'Select All', + accelerator: 'CmdOrCtrl+A', + role: 'selectAll', + enabled: hasValue, + click: selectAll, + }, + ]; + + return template; +} + +function getTemplate(target) { + const { type } = target; + if (target.matches('input') && (type === 'text' || type === 'number')) { + return textInputTemplate(target); + } + return []; +} + +export default event => { + event.preventDefault(); + const { target } = event; + const template = getTemplate(target); + if (isDev) { + const { screenX, screenY } = event; + const separator = { type: 'separator' }; + const developmentTemplateAddition = [ + { + label: 'Inspect element', + accelerator: 'CmdOrCtrl+Shift+I', + click: () => { + remote.getCurrentWindow().inspectElement(screenX, screenY); + }, + }, + ]; + if (template.length > 0) { + template.push(separator); + } + template.push(...developmentTemplateAddition); + } + remote.Menu.buildFromTemplate(template).popup(); +}; From 86876d6a1982e55c0856efc9f6944d0113ea7417 Mon Sep 17 00:00:00 2001 From: Daniel Dominguez Date: Sun, 20 May 2018 22:00:59 -0300 Subject: [PATCH 2/3] Add context menu helper to be able to modify the menu templates in react way and not be static. --- src/main/createWindow.js | 2 - src/main/menu/setupContextMenu.js | 27 ------ src/renderer/component/fileCard/view.jsx | 5 ++ src/renderer/index.js | 6 +- src/renderer/util/contextMenu.js | 107 ++++++++++++----------- 5 files changed, 63 insertions(+), 84 deletions(-) delete mode 100644 src/main/menu/setupContextMenu.js diff --git a/src/main/createWindow.js b/src/main/createWindow.js index 738ab792a..764003c65 100644 --- a/src/main/createWindow.js +++ b/src/main/createWindow.js @@ -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) { diff --git a/src/main/menu/setupContextMenu.js b/src/main/menu/setupContextMenu.js deleted file mode 100644 index 658ac731a..000000000 --- a/src/main/menu/setupContextMenu.js +++ /dev/null @@ -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(); - }); -}; diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx index 88bb99946..6fc765633 100644 --- a/src/renderer/component/fileCard/view.jsx +++ b/src/renderer/component/fileCard/view.jsx @@ -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 { 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 { 'card--link': !pending, 'card--pending': pending, })} + onContextMenu={handleContextMenu} >
{showPrice && }
diff --git a/src/renderer/index.js b/src/renderer/index.js index fe0b9e695..c19790f06 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -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(
- + openContextMenu(e)} />
, diff --git a/src/renderer/util/contextMenu.js b/src/renderer/util/contextMenu.js index 0348423bf..79f47da5b 100644 --- a/src/renderer/util/contextMenu.js +++ b/src/renderer/util/contextMenu.js @@ -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(); + } +} From b4542517def09c07b423700fad15208b4f445cb0 Mon Sep 17 00:00:00 2001 From: Daniel Dominguez Date: Mon, 21 May 2018 14:18:02 -0300 Subject: [PATCH 3/3] Correctly copy an URI so it can be opened with lbry-app when shared. --- src/renderer/component/fileCard/view.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx index 6fc765633..818d8cd4a 100644 --- a/src/renderer/component/fileCard/view.jsx +++ b/src/renderer/component/fileCard/view.jsx @@ -1,6 +1,6 @@ // @flow import * as React from 'react'; -import { normalizeURI } from 'lbry-redux'; +import { normalizeURI, convertToShareLink } from 'lbry-redux'; import Button from 'component/button'; import CardMedia from 'component/cardMedia'; import TruncatedText from 'component/common/truncated-text'; @@ -62,7 +62,7 @@ class FileCard extends React.PureComponent { const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw; const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id); const handleContextMenu = event => { - openCopyLinkMenu(uri, event); + openCopyLinkMenu(convertToShareLink(uri), event); }; // We should be able to tab through cards