From 44ba3413481098a448d93bed6c18ac70d3e904c7 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 19 Dec 2016 22:51:23 -0500 Subject: [PATCH] Fix clipboard no avail in renderer proces Auditors: @bsclifton Fix #6302 --- app/browser/reducers/clipboardReducer.js | 19 +++++++++ docs/appActions.md | 10 +++++ js/actions/appActions.js | 11 +++++ js/components/frame.js | 3 +- js/constants/appConstants.js | 3 +- js/contextMenus.js | 4 +- js/stores/appStore.js | 14 ++++--- .../browser/reducers/clipboardReducerTest.js | 41 +++++++++++++++++++ .../browser/reducers/downloadsReducerTest.js | 6 +-- 9 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 app/browser/reducers/clipboardReducer.js create mode 100644 test/unit/app/browser/reducers/clipboardReducerTest.js diff --git a/app/browser/reducers/clipboardReducer.js b/app/browser/reducers/clipboardReducer.js new file mode 100644 index 00000000000..4a98fb0e20e --- /dev/null +++ b/app/browser/reducers/clipboardReducer.js @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict' + +const appConstants = require('../../../js/constants/appConstants') +const {clipboard} = require('electron') + +const clipboardReducer = (state, action) => { + switch (action.actionType) { + case appConstants.APP_CLIPBOARD_TEXT_UPDATED: + clipboard.writeText(action.text) + break + } + return state +} + +module.exports = clipboardReducer diff --git a/docs/appActions.md b/docs/appActions.md index 744628cb03c..15cd89cae90 100644 --- a/docs/appActions.md +++ b/docs/appActions.md @@ -620,6 +620,16 @@ Dispatches a message when a download is being redownloaded +### clipboardTextCopied(text) + +Dispatches a message when text is updated to the clipboard + +**Parameters** + +**text**: `string`, clipboard text which is copied + + + * * * diff --git a/js/actions/appActions.js b/js/actions/appActions.js index 51d8baeb5a0..669b9433d99 100644 --- a/js/actions/appActions.js +++ b/js/actions/appActions.js @@ -763,6 +763,17 @@ const appActions = { actionType: appConstants.APP_DOWNLOAD_REDOWNLOADED, downloadId }) + }, + + /** + * Dispatches a message when text is updated to the clipboard + * @param {string} text - clipboard text which is copied + */ + clipboardTextCopied: function (text) { + AppDispatcher.dispatch({ + actionType: appConstants.APP_CLIPBOARD_TEXT_UPDATED, + text + }) } } diff --git a/js/components/frame.js b/js/components/frame.js index 155ea4b70fa..abbfe261990 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -16,7 +16,6 @@ const UrlUtil = require('../lib/urlutil') const messages = require('../constants/messages') const contextMenus = require('../contextMenus') const ipc = require('electron').ipcRenderer -const clipboard = require('electron').clipboard const FullScreenWarning = require('./fullScreenWarning') const debounce = require('../lib/debounce') const getSetting = require('../settings').getSetting @@ -514,7 +513,7 @@ class Frame extends ImmutableComponent { case 'copy': let selection = window.getSelection() if (selection && selection.toString()) { - clipboard.writeText(selection.toString()) + appActions.clipboardTextCopied(selection.toString()) } else { this.webview.copy() } diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index 78b2ff2103f..dddd751a1e5 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -82,7 +82,8 @@ const appConstants = { APP_DOWNLOAD_REDOWNLOADED: _, APP_ALLOW_FLASH_ONCE: _, APP_ALLOW_FLASH_ALWAYS: _, - APP_SHUTTING_DOWN: _ + APP_SHUTTING_DOWN: _, + APP_CLIPBOARD_TEXT_UPDATED: _ } module.exports = mapValuesByKeys(appConstants) diff --git a/js/contextMenus.js b/js/contextMenus.js index 19d8587d86b..bce324c4aa5 100644 --- a/js/contextMenus.js +++ b/js/contextMenus.js @@ -848,7 +848,7 @@ const copyAddressMenuItem = (label, location) => { label: locale.translation(label), click: (item, focusedWindow) => { if (focusedWindow && location) { - clipboard.writeText(location) + appActions.clipboardTextCopied(location) } } } @@ -858,7 +858,7 @@ const copyEmailAddressMenuItem = (location) => { return { label: locale.translation('copyEmailAddress'), click: () => { - clipboard.writeText(location.substring('mailto:'.length, location.length)) + appActions.clipboardTextCopied(location.substring('mailto:'.length, location.length)) } } } diff --git a/js/stores/appStore.js b/js/stores/appStore.js index 6ea9e475598..7cb5492fb36 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -34,7 +34,6 @@ const nativeImage = require('../../app/nativeImage') const Filtering = require('../../app/filtering') const basicAuth = require('../../app/browser/basicAuth') const windows = require('../../app/browser/windows') -const downloadsReducer = require('../../app/browser/reducers/downloadsReducer') // state helpers const basicAuthState = require('../../app/common/state/basicAuthState') @@ -43,8 +42,6 @@ const aboutNewTabState = require('../../app/common/state/aboutNewTabState') const aboutHistoryState = require('../../app/common/state/aboutHistoryState') const windowState = require('../../app/common/state/windowState') -const flashReducer = require('../../app/browser/reducers/flashReducer') -const tabsReducer = require('../../app/browser/reducers/tabsReducer') const webtorrent = require('../../app/browser/webtorrent') const isDarwin = process.platform === 'darwin' @@ -353,6 +350,13 @@ function handleChangeSettingAction (settingKey, settingValue) { } } +const reducers = [ + require('../../app/browser/reducers/downloadsReducer'), + require('../../app/browser/reducers/flashReducer'), + require('../../app/browser/reducers/tabsReducer'), + require('../../app/browser/reducers/clipboardReducer') +] + const handleAppAction = (action) => { if (shuttingDown) { return @@ -360,9 +364,7 @@ const handleAppAction = (action) => { const ledger = require('../../app/ledger') - appState = downloadsReducer(appState, action) - appState = flashReducer(appState, action) - appState = tabsReducer(appState, action) + appState = reducers.reduce((appState, reducer) => reducer(appState, action), appState) switch (action.actionType) { case appConstants.APP_SET_STATE: diff --git a/test/unit/app/browser/reducers/clipboardReducerTest.js b/test/unit/app/browser/reducers/clipboardReducerTest.js new file mode 100644 index 00000000000..323c6f59d3d --- /dev/null +++ b/test/unit/app/browser/reducers/clipboardReducerTest.js @@ -0,0 +1,41 @@ +/* global describe, it, before, after */ +const mockery = require('mockery') +const sinon = require('sinon') +const Immutable = require('immutable') +const assert = require('assert') +const fakeElectron = require('../../../lib/fakeElectron') + +const appConstants = require('../../../../../js/constants/appConstants') +require('../../../braveUnit') + +describe('clipboardReducer', function () { + let clipboardReducer + before(function () { + mockery.enable({ + warnOnReplace: false, + warnOnUnregistered: false, + useCleanCache: true + }) + mockery.registerMock('electron', fakeElectron) + clipboardReducer = require('../../../../../app/browser/reducers/clipboardReducer') + }) + + after(function () { + mockery.disable() + }) + + describe('APP_CLIPBOARD_TEXT_UPDATED', function () { + before(function () { + this.spy = sinon.spy(fakeElectron.clipboard, 'writeText') + // Make sure clipboardReducer doesn't update state when text is updated + this.text = 'Mn = 2n − 1' + this.newState = clipboardReducer(Immutable.Map(), {actionType: appConstants.APP_CLIPBOARD_TEXT_UPDATED, text: this.text}) + }) + it('Does not modify state', function () { + assert(this.newState.isEmpty()) + }) + it('Copies text into electron.clipboard', function () { + assert(this.spy.withArgs(this.text).calledOnce) + }) + }) +}) diff --git a/test/unit/app/browser/reducers/downloadsReducerTest.js b/test/unit/app/browser/reducers/downloadsReducerTest.js index 1248b26cc63..d8dc85c27c5 100644 --- a/test/unit/app/browser/reducers/downloadsReducerTest.js +++ b/test/unit/app/browser/reducers/downloadsReducerTest.js @@ -1,4 +1,4 @@ -/* global describe, it, before, after, beforeEach */ +/* global describe, it, before, after */ const mockery = require('mockery') const sinon = require('sinon') const Immutable = require('immutable') @@ -42,9 +42,6 @@ describe('downloadsReducer', function () { downloadsReducer = require('../../../../../app/browser/reducers/downloadsReducer') }) - beforeEach(function () { - }) - after(function () { mockery.disable() }) @@ -120,7 +117,6 @@ describe('downloadsReducer', function () { describe('APP_DOWNLOAD_COPIED_TO_CLIPBOARD', function () { it('copies the download URL to the clipboard', function () { const spy = sinon.spy(fakeElectron.clipboard, 'writeText') - spy.withArgs(downloadUrl) const oldState = oneDownloadWithState(IN_PROGRESS) downloadsReducer(oldState, {actionType: appConstants.APP_DOWNLOAD_COPIED_TO_CLIPBOARD, downloadId: downloadId(oldState)}) assert(spy.withArgs(downloadUrl).calledOnce)