From f6996a2274f3293d7c5860174dd224b28877e108 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 8 Oct 2017 16:37:26 +0900 Subject: [PATCH 1/3] yank a URL --- src/content/actions/operation.js | 3 +++ src/content/urls.js | 15 +++++++++++++++ src/shared/default-settings.js | 3 ++- src/shared/operations.js | 3 +++ 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/content/urls.js diff --git a/src/content/actions/operation.js b/src/content/actions/operation.js index d188a60..0c8b0ff 100644 --- a/src/content/actions/operation.js +++ b/src/content/actions/operation.js @@ -2,6 +2,7 @@ import operations from 'shared/operations'; import messages from 'shared/messages'; import * as scrolls from 'content/scrolls'; import * as navigates from 'content/navigates'; +import * as urls from 'content/urls'; import * as followActions from 'content/actions/follow'; const exec = (operation) => { @@ -32,6 +33,8 @@ const exec = (operation) => { return navigates.parent(window); case operations.NAVIGATE_ROOT: return navigates.root(window); + case operations.URLS_YANK: + return urls.yank(window); default: browser.runtime.sendMessage({ type: messages.BACKGROUND_OPERATION, diff --git a/src/content/urls.js b/src/content/urls.js new file mode 100644 index 0000000..8f8a1ac --- /dev/null +++ b/src/content/urls.js @@ -0,0 +1,15 @@ +const yank = (win) => { + let input = win.document.createElement('input'); + win.document.body.append(input); + + input.style.position = 'fixed'; + input.style.top = '-100px'; + input.value = win.location.href; + input.select(); + + win.document.execCommand('copy'); + + input.remove(); +}; + +export { yank }; diff --git a/src/shared/default-settings.js b/src/shared/default-settings.js index d602117..24ac536 100644 --- a/src/shared/default-settings.js +++ b/src/shared/default-settings.js @@ -37,7 +37,8 @@ export default { "[[": { "type": "navigate.link.prev" }, "]]": { "type": "navigate.link.next" }, "gu": { "type": "navigate.parent" }, - "gU": { "type": "navigate.root" } + "gU": { "type": "navigate.root" }, + "y": { "type": "urls.yank" } }, "search": { "default": "google", diff --git a/src/shared/operations.js b/src/shared/operations.js index 5e4a1e5..ca62716 100644 --- a/src/shared/operations.js +++ b/src/shared/operations.js @@ -36,4 +36,7 @@ export default { ZOOM_IN: 'zoom.in', ZOOM_OUT: 'zoom.out', ZOOM_NEUTRAL: 'zoom.neutral', + + // Url yank + URLS_YANK: 'urls.yank', }; From b0d2b5328107a9a2018132938fb5a9efcd77fc50 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 8 Oct 2017 18:41:44 +0900 Subject: [PATCH 2/3] use mode in console message --- src/background/actions/index.js | 0 src/background/components/background.js | 2 +- src/console/actions/console.js | 7 ++++--- src/console/actions/index.js | 2 +- src/console/components/console.js | 8 ++++---- src/console/index.js | 4 ++-- src/console/reducers/index.js | 21 +++++++-------------- src/content/index.js | 2 +- src/shared/messages.js | 2 +- test/console/actions/console.test.js | 6 +++--- test/console/reducers/console.test.js | 25 ++++++++++++------------- 11 files changed, 36 insertions(+), 43 deletions(-) delete mode 100644 src/background/actions/index.js diff --git a/src/background/actions/index.js b/src/background/actions/index.js deleted file mode 100644 index e69de29..0000000 diff --git a/src/background/components/background.js b/src/background/components/background.js index bfe1b3f..0570a5a 100644 --- a/src/background/components/background.js +++ b/src/background/components/background.js @@ -48,7 +48,7 @@ export default class BackgroundComponent { tabActions.openToTab(message.url, sender.tab), sender); case messages.CONSOLE_BLURRED: return browser.tabs.sendMessage(sender.tab.id, { - type: messages.CONSOLE_HIDE, + type: messages.CONSOLE_HIDE_COMMAND, }); case messages.CONSOLE_ENTERED: return commands.exec(message.text, this.settings).catch((e) => { diff --git a/src/console/actions/console.js b/src/console/actions/console.js index 01d9a9b..aacc21a 100644 --- a/src/console/actions/console.js +++ b/src/console/actions/console.js @@ -14,9 +14,9 @@ const showError = (text) => { }; }; -const hide = () => { +const hideCommand = () => { return { - type: actions.CONSOLE_HIDE + type: actions.CONSOLE_HIDE_COMMAND, }; }; @@ -40,5 +40,6 @@ const completionPrev = () => { }; export { - showCommand, showError, hide, setCompletions, completionNext, completionPrev + showCommand, showError, hideCommand, + setCompletions, completionNext, completionPrev }; diff --git a/src/console/actions/index.js b/src/console/actions/index.js index a5d03bc..3a6cf07 100644 --- a/src/console/actions/index.js +++ b/src/console/actions/index.js @@ -3,7 +3,7 @@ export default { CONSOLE_SHOW_COMMAND: 'console.show.command', CONSOLE_SET_COMPLETIONS: 'console.set.completions', CONSOLE_SHOW_ERROR: 'console.show.error', - CONSOLE_HIDE: 'console.hide', + CONSOLE_HIDE_COMMAND: 'console.hide.command', CONSOLE_COMPLETION_NEXT: 'console.completion.next', CONSOLE_COMPLETION_PREV: 'console.completion.prev', }; diff --git a/src/console/components/console.js b/src/console/components/console.js index 9023d91..b8431ce 100644 --- a/src/console/components/console.js +++ b/src/console/components/console.js @@ -72,14 +72,14 @@ export default class ConsoleComponent { update() { let state = this.store.getState(); - if (!this.prevState.commandShown && state.commandShown) { + if (this.prevState.mode !== 'command' && state.mode === 'command') { this.showCommand(state.commandText); - } else if (!state.commandShown) { + } else if (state.mode !== 'command') { this.hideCommand(); } - if (state.errorShown) { - this.setErrorText(state.errorText); + if (state.mode === 'error') { + this.setErrorText(state.messageText); this.showError(); } else { this.hideError(); diff --git a/src/console/index.js b/src/console/index.js index 7396a96..b07d8e7 100644 --- a/src/console/index.js +++ b/src/console/index.js @@ -28,7 +28,7 @@ browser.runtime.onMessage.addListener((action) => { return store.dispatch(consoleActions.showCommand(action.command)); case messages.CONSOLE_SHOW_ERROR: return store.dispatch(consoleActions.showError(action.text)); - case messages.CONSOLE_HIDE: - return store.dispatch(consoleActions.hide(action.command)); + case messages.CONSOLE_HIDE_COMMAND: + return store.dispatch(consoleActions.hideCommand()); } }); diff --git a/src/console/reducers/index.js b/src/console/reducers/index.js index ee9c691..78b73b0 100644 --- a/src/console/reducers/index.js +++ b/src/console/reducers/index.js @@ -1,9 +1,8 @@ import actions from 'console/actions'; const defaultState = { - errorShown: false, - errorText: '', - commandShown: false, + mode: '', + messageText: '', commandText: '', completions: [], groupSelection: -1, @@ -48,25 +47,19 @@ export default function reducer(state = defaultState, action = {}) { switch (action.type) { case actions.CONSOLE_SHOW_COMMAND: return Object.assign({}, state, { - commandShown: true, + mode: 'command', commandText: action.text, errorShown: false, completions: [] }); case actions.CONSOLE_SHOW_ERROR: return Object.assign({}, state, { - errorText: action.text, - errorShown: true, - commandShown: false, + mode: 'error', + messageText: action.text, }); - case actions.CONSOLE_HIDE: - if (state.errorShown) { - // keep error message if shown - return state; - } + case actions.CONSOLE_HIDE_COMMAND: return Object.assign({}, state, { - errorShown: false, - commandShown: false + mode: state.mode === 'command' ? '' : state.mode, }); case actions.CONSOLE_SET_COMPLETIONS: return Object.assign({}, state, { diff --git a/src/content/index.js b/src/content/index.js index adea871..63bbf77 100644 --- a/src/content/index.js +++ b/src/content/index.js @@ -40,7 +40,7 @@ const reloadSettings = () => { browser.runtime.onMessage.addListener((action) => { switch (action.type) { - case messages.CONSOLE_HIDE: + case messages.CONSOLE_HIDE_COMMAND: window.focus(); consoleFrames.blur(window.document); return Promise.resolve(); diff --git a/src/shared/messages.js b/src/shared/messages.js index 138f0e0..bba730e 100644 --- a/src/shared/messages.js +++ b/src/shared/messages.js @@ -8,7 +8,7 @@ export default { CONSOLE_QUERY_COMPLETIONS: 'console.query.completions', CONSOLE_SHOW_COMMAND: 'console.show.command', CONSOLE_SHOW_ERROR: 'console.show.error', - CONSOLE_HIDE: 'console.hide', + CONSOLE_HIDE_COMMAND: 'console.hide.command', OPEN_URL: 'open.url', diff --git a/test/console/actions/console.test.js b/test/console/actions/console.test.js index dd04c85..a2c906f 100644 --- a/test/console/actions/console.test.js +++ b/test/console/actions/console.test.js @@ -20,9 +20,9 @@ describe("console actions", () => { }); describe("hide", () => { - it('create CONSOLE_HIDE action', () => { - let action = consoleActions.hide(); - expect(action.type).to.equal(actions.CONSOLE_HIDE); + it('create CONSOLE_HIDE_COMMAND action', () => { + let action = consoleActions.hideCommand(); + expect(action.type).to.equal(actions.CONSOLE_HIDE_COMMAND); }); }); diff --git a/test/console/reducers/console.test.js b/test/console/reducers/console.test.js index 95ac993..497baf2 100644 --- a/test/console/reducers/console.test.js +++ b/test/console/reducers/console.test.js @@ -5,9 +5,8 @@ import reducer from 'console/reducers'; describe("console reducer", () => { it('return the initial state', () => { let state = reducer(undefined, {}); - expect(state).to.have.property('errorShown', false); - expect(state).to.have.property('errorText', ''); - expect(state).to.have.property('commandShown', false); + expect(state).to.have.property('mode', ''); + expect(state).to.have.property('messageText', ''); expect(state).to.have.property('commandText', ''); expect(state).to.have.deep.property('completions', []); expect(state).to.have.property('groupSelection', -1); @@ -17,24 +16,24 @@ describe("console reducer", () => { it('return next state for CONSOLE_SHOW_COMMAND', () => { let action = { type: actions.CONSOLE_SHOW_COMMAND, text: 'open ' }; let state = reducer({}, action); - expect(state).to.have.property('commandShown', true); + expect(state).to.have.property('mode', 'command'); expect(state).to.have.property('commandText', 'open '); - expect(state).to.have.property('errorShown', false); }); it('return next state for CONSOLE_SHOW_ERROR', () => { let action = { type: actions.CONSOLE_SHOW_ERROR, text: 'an error' }; let state = reducer({}, action); - expect(state).to.have.property('errorShown', true); - expect(state).to.have.property('errorText', 'an error'); - expect(state).to.have.property('commandShown', false); + expect(state).to.have.property('mode', 'error'); + expect(state).to.have.property('messageText', 'an error'); }); - it('return next state for CONSOLE_HIDE', () => { - let action = { type: actions.CONSOLE_HIDE }; - let state = reducer({}, action); - expect(state).to.have.property('errorShown', false); - expect(state).to.have.property('commandShown', false); + it('return next state for CONSOLE_HIDE_COMMAND', () => { + let action = { type: actions.CONSOLE_HIDE_COMMAND }; + let state = reducer({ mode: 'command' }, action); + expect(state).to.have.property('mode', ''); + + state = reducer({ mode: 'error' }, action); + expect(state).to.have.property('mode', 'error'); }); it ('return next state for CONSOLE_SET_COMPLETIONS', () => { From 7ac00fce6f6c431f96c531179c6af3796df7e07a Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 8 Oct 2017 19:08:51 +0900 Subject: [PATCH 3/3] Show info on yanked --- src/console/actions/console.js | 9 ++++++++- src/console/actions/index.js | 3 ++- src/console/components/console.js | 27 +++++++++++++-------------- src/console/index.html | 4 ++-- src/console/index.js | 25 ++++++++++++++++--------- src/console/reducers/index.js | 5 +++++ src/console/site.scss | 10 +++++++++- src/content/actions/operation.js | 7 ++++++- src/content/console-frames.js | 7 ++++++- src/shared/messages.js | 1 + test/console/actions/console.test.js | 8 ++++++++ test/console/reducers/console.test.js | 7 +++++++ 12 files changed, 83 insertions(+), 30 deletions(-) diff --git a/src/console/actions/console.js b/src/console/actions/console.js index aacc21a..0d891bb 100644 --- a/src/console/actions/console.js +++ b/src/console/actions/console.js @@ -14,6 +14,13 @@ const showError = (text) => { }; }; +const showInfo = (text) => { + return { + type: actions.CONSOLE_SHOW_INFO, + text: text + }; +}; + const hideCommand = () => { return { type: actions.CONSOLE_HIDE_COMMAND, @@ -40,6 +47,6 @@ const completionPrev = () => { }; export { - showCommand, showError, hideCommand, + showCommand, showError, showInfo, hideCommand, setCompletions, completionNext, completionPrev }; diff --git a/src/console/actions/index.js b/src/console/actions/index.js index 3a6cf07..c4f88cd 100644 --- a/src/console/actions/index.js +++ b/src/console/actions/index.js @@ -1,9 +1,10 @@ export default { // console commands CONSOLE_SHOW_COMMAND: 'console.show.command', - CONSOLE_SET_COMPLETIONS: 'console.set.completions', CONSOLE_SHOW_ERROR: 'console.show.error', + CONSOLE_SHOW_INFO: 'console.show.info', CONSOLE_HIDE_COMMAND: 'console.hide.command', + CONSOLE_SET_COMPLETIONS: 'console.set.completions', CONSOLE_COMPLETION_NEXT: 'console.completion.next', CONSOLE_COMPLETION_PREV: 'console.completion.prev', }; diff --git a/src/console/components/console.js b/src/console/components/console.js index b8431ce..93802f8 100644 --- a/src/console/components/console.js +++ b/src/console/components/console.js @@ -16,7 +16,7 @@ export default class ConsoleComponent { input.addEventListener('keyup', this.onKeyUp.bind(this)); this.hideCommand(); - this.hideError(); + this.hideMessage(); } onBlur() { @@ -78,11 +78,10 @@ export default class ConsoleComponent { this.hideCommand(); } - if (state.mode === 'error') { - this.setErrorText(state.messageText); - this.showError(); + if (state.mode === 'error' || state.mode === 'info') { + this.showMessage(state.mode, state.messageText); } else { - this.hideError(); + this.hideMessage(); } if (state.groupSelection >= 0 && state.itemSelection >= 0) { @@ -128,21 +127,21 @@ export default class ConsoleComponent { input.value = this.completionOrigin; } - setErrorText(text) { + showMessage(mode, text) { let doc = this.wrapper.ownerDocument; - let error = doc.querySelector('#vimvixen-console-error'); + let error = doc.querySelector('#vimvixen-console-message'); + error.classList.remove( + 'vimvixen-console-info', + 'vimvixen-console-error' + ); + error.classList.add('vimvixen-console-' + mode); error.textContent = text; - } - - showError() { - let doc = this.wrapper.ownerDocument; - let error = doc.querySelector('#vimvixen-console-error'); error.style.display = 'block'; } - hideError() { + hideMessage() { let doc = this.wrapper.ownerDocument; - let error = doc.querySelector('#vimvixen-console-error'); + let error = doc.querySelector('#vimvixen-console-message'); error.style.display = 'none'; } } diff --git a/src/console/index.html b/src/console/index.html index 4222f12..f41a8dc 100644 --- a/src/console/index.html +++ b/src/console/index.html @@ -6,8 +6,8 @@ -

+

    diff --git a/src/console/index.js b/src/console/index.js index b07d8e7..895fcc2 100644 --- a/src/console/index.js +++ b/src/console/index.js @@ -17,18 +17,25 @@ window.addEventListener('load', () => { consoleComponent = new ConsoleComponent(document.body, store); }); -store.subscribe(() => { - completionComponent.update(); - consoleComponent.update(); -}); - -browser.runtime.onMessage.addListener((action) => { - switch (action.type) { +const onMessage = (message) => { + switch (message.type) { case messages.CONSOLE_SHOW_COMMAND: - return store.dispatch(consoleActions.showCommand(action.command)); + return store.dispatch(consoleActions.showCommand(message.command)); case messages.CONSOLE_SHOW_ERROR: - return store.dispatch(consoleActions.showError(action.text)); + return store.dispatch(consoleActions.showError(message.text)); + case messages.CONSOLE_SHOW_INFO: + return store.dispatch(consoleActions.showInfo(message.text)); case messages.CONSOLE_HIDE_COMMAND: return store.dispatch(consoleActions.hideCommand()); } +}; + +store.subscribe(() => { + completionComponent.update(); + consoleComponent.update(); }); + +browser.runtime.onMessage.addListener(onMessage); +window.addEventListener('message', (message) => { + onMessage(JSON.parse(message.data)); +}, false); diff --git a/src/console/reducers/index.js b/src/console/reducers/index.js index 78b73b0..d4affa7 100644 --- a/src/console/reducers/index.js +++ b/src/console/reducers/index.js @@ -57,6 +57,11 @@ export default function reducer(state = defaultState, action = {}) { mode: 'error', messageText: action.text, }); + case actions.CONSOLE_SHOW_INFO: + return Object.assign({}, state, { + mode: 'info', + messageText: action.text, + }); case actions.CONSOLE_HIDE_COMMAND: return Object.assign({}, state, { mode: state.mode === 'command' ? '' : state.mode, diff --git a/src/console/site.scss b/src/console/site.scss index 5823dce..e5cb2df 100644 --- a/src/console/site.scss +++ b/src/console/site.scss @@ -64,12 +64,20 @@ body { } } + &-message { + @include consoole-font; + } + &-error { background-color: red; font-weight: bold; color: white; + } - @include consoole-font; + &-info { + background-color: white; + font-weight: normal; + color: green; } &-command { diff --git a/src/content/actions/operation.js b/src/content/actions/operation.js index 0c8b0ff..0d5088b 100644 --- a/src/content/actions/operation.js +++ b/src/content/actions/operation.js @@ -4,6 +4,7 @@ import * as scrolls from 'content/scrolls'; import * as navigates from 'content/navigates'; import * as urls from 'content/urls'; import * as followActions from 'content/actions/follow'; +import * as consoleFrames from 'content/console-frames'; const exec = (operation) => { switch (operation.type) { @@ -34,7 +35,11 @@ const exec = (operation) => { case operations.NAVIGATE_ROOT: return navigates.root(window); case operations.URLS_YANK: - return urls.yank(window); + urls.yank(window); + return consoleFrames.postMessage(window.document, { + type: messages.CONSOLE_SHOW_INFO, + text: 'Current url yanked', + }); default: browser.runtime.sendMessage({ type: messages.BACKGROUND_OPERATION, diff --git a/src/content/console-frames.js b/src/content/console-frames.js index 3f06466..35b975f 100644 --- a/src/content/console-frames.js +++ b/src/content/console-frames.js @@ -15,4 +15,9 @@ const blur = (doc) => { iframe.blur(); }; -export { initialize, blur }; +const postMessage = (doc, message) => { + let iframe = doc.getElementById('vimvixen-console-frame'); + iframe.contentWindow.postMessage(JSON.stringify(message), '*'); +}; + +export { initialize, blur, postMessage }; diff --git a/src/shared/messages.js b/src/shared/messages.js index bba730e..2467a67 100644 --- a/src/shared/messages.js +++ b/src/shared/messages.js @@ -8,6 +8,7 @@ export default { CONSOLE_QUERY_COMPLETIONS: 'console.query.completions', CONSOLE_SHOW_COMMAND: 'console.show.command', CONSOLE_SHOW_ERROR: 'console.show.error', + CONSOLE_SHOW_INFO: 'console.show.info', CONSOLE_HIDE_COMMAND: 'console.hide.command', OPEN_URL: 'open.url', diff --git a/test/console/actions/console.test.js b/test/console/actions/console.test.js index a2c906f..3b02d4a 100644 --- a/test/console/actions/console.test.js +++ b/test/console/actions/console.test.js @@ -11,6 +11,14 @@ describe("console actions", () => { }); }); + describe("showInfo", () => { + it('create CONSOLE_SHOW_INFO action', () => { + let action = consoleActions.showInfo('an info'); + expect(action.type).to.equal(actions.CONSOLE_SHOW_INFO); + expect(action.text).to.equal('an info'); + }); + }); + describe("showError", () => { it('create CONSOLE_SHOW_ERROR action', () => { let action = consoleActions.showError('an error'); diff --git a/test/console/reducers/console.test.js b/test/console/reducers/console.test.js index 497baf2..4f85e55 100644 --- a/test/console/reducers/console.test.js +++ b/test/console/reducers/console.test.js @@ -20,6 +20,13 @@ describe("console reducer", () => { expect(state).to.have.property('commandText', 'open '); }); + it('return next state for CONSOLE_SHOW_INFO', () => { + let action = { type: actions.CONSOLE_SHOW_INFO, text: 'an info' }; + let state = reducer({}, action); + expect(state).to.have.property('mode', 'info'); + expect(state).to.have.property('messageText', 'an info'); + }); + it('return next state for CONSOLE_SHOW_ERROR', () => { let action = { type: actions.CONSOLE_SHOW_ERROR, text: 'an error' }; let state = reducer({}, action);