Merge pull request #24 from ueokande/yank-url

Yank url
jh-changes
Shin'ya Ueoka 7 years ago committed by GitHub
commit 8b9125871b
  1. 0
      src/background/actions/index.js
  2. 2
      src/background/components/background.js
  3. 14
      src/console/actions/console.js
  4. 5
      src/console/actions/index.js
  5. 31
      src/console/components/console.js
  6. 4
      src/console/index.html
  7. 27
      src/console/index.js
  8. 26
      src/console/reducers/index.js
  9. 10
      src/console/site.scss
  10. 8
      src/content/actions/operation.js
  11. 7
      src/content/console-frames.js
  12. 2
      src/content/index.js
  13. 15
      src/content/urls.js
  14. 3
      src/shared/default-settings.js
  15. 3
      src/shared/messages.js
  16. 3
      src/shared/operations.js
  17. 14
      test/console/actions/console.test.js
  18. 32
      test/console/reducers/console.test.js

@ -48,7 +48,7 @@ export default class BackgroundComponent {
tabActions.openToTab(message.url, sender.tab), sender); tabActions.openToTab(message.url, sender.tab), sender);
case messages.CONSOLE_BLURRED: case messages.CONSOLE_BLURRED:
return browser.tabs.sendMessage(sender.tab.id, { return browser.tabs.sendMessage(sender.tab.id, {
type: messages.CONSOLE_HIDE, type: messages.CONSOLE_HIDE_COMMAND,
}); });
case messages.CONSOLE_ENTERED: case messages.CONSOLE_ENTERED:
return commands.exec(message.text, this.settings).catch((e) => { return commands.exec(message.text, this.settings).catch((e) => {

@ -14,9 +14,16 @@ const showError = (text) => {
}; };
}; };
const hide = () => { const showInfo = (text) => {
return { return {
type: actions.CONSOLE_HIDE type: actions.CONSOLE_SHOW_INFO,
text: text
};
};
const hideCommand = () => {
return {
type: actions.CONSOLE_HIDE_COMMAND,
}; };
}; };
@ -40,5 +47,6 @@ const completionPrev = () => {
}; };
export { export {
showCommand, showError, hide, setCompletions, completionNext, completionPrev showCommand, showError, showInfo, hideCommand,
setCompletions, completionNext, completionPrev
}; };

@ -1,9 +1,10 @@
export default { export default {
// console commands // console commands
CONSOLE_SHOW_COMMAND: 'console.show.command', CONSOLE_SHOW_COMMAND: 'console.show.command',
CONSOLE_SET_COMPLETIONS: 'console.set.completions',
CONSOLE_SHOW_ERROR: 'console.show.error', CONSOLE_SHOW_ERROR: 'console.show.error',
CONSOLE_HIDE: 'console.hide', 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_NEXT: 'console.completion.next',
CONSOLE_COMPLETION_PREV: 'console.completion.prev', CONSOLE_COMPLETION_PREV: 'console.completion.prev',
}; };

@ -16,7 +16,7 @@ export default class ConsoleComponent {
input.addEventListener('keyup', this.onKeyUp.bind(this)); input.addEventListener('keyup', this.onKeyUp.bind(this));
this.hideCommand(); this.hideCommand();
this.hideError(); this.hideMessage();
} }
onBlur() { onBlur() {
@ -72,17 +72,16 @@ export default class ConsoleComponent {
update() { update() {
let state = this.store.getState(); let state = this.store.getState();
if (!this.prevState.commandShown && state.commandShown) { if (this.prevState.mode !== 'command' && state.mode === 'command') {
this.showCommand(state.commandText); this.showCommand(state.commandText);
} else if (!state.commandShown) { } else if (state.mode !== 'command') {
this.hideCommand(); this.hideCommand();
} }
if (state.errorShown) { if (state.mode === 'error' || state.mode === 'info') {
this.setErrorText(state.errorText); this.showMessage(state.mode, state.messageText);
this.showError();
} else { } else {
this.hideError(); this.hideMessage();
} }
if (state.groupSelection >= 0 && state.itemSelection >= 0) { if (state.groupSelection >= 0 && state.itemSelection >= 0) {
@ -128,21 +127,21 @@ export default class ConsoleComponent {
input.value = this.completionOrigin; input.value = this.completionOrigin;
} }
setErrorText(text) { showMessage(mode, text) {
let doc = this.wrapper.ownerDocument; 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; error.textContent = text;
}
showError() {
let doc = this.wrapper.ownerDocument;
let error = doc.querySelector('#vimvixen-console-error');
error.style.display = 'block'; error.style.display = 'block';
} }
hideError() { hideMessage() {
let doc = this.wrapper.ownerDocument; let doc = this.wrapper.ownerDocument;
let error = doc.querySelector('#vimvixen-console-error'); let error = doc.querySelector('#vimvixen-console-message');
error.style.display = 'none'; error.style.display = 'none';
} }
} }

@ -6,8 +6,8 @@
<script src='console.js'></script> <script src='console.js'></script>
</head> </head>
<body class='vimvixen-console'> <body class='vimvixen-console'>
<p id='vimvixen-console-error' <p id='vimvixen-console-message'
class='vimvixen-console-error'></p> class='vimvixen-console-message'></p>
<div id='vimvixen-console-command'> <div id='vimvixen-console-command'>
<ul id='vimvixen-console-completion' class='vimvixen-console-completion'></ul> <ul id='vimvixen-console-completion' class='vimvixen-console-completion'></ul>
<div class='vimvixen-console-command'> <div class='vimvixen-console-command'>

@ -17,18 +17,25 @@ window.addEventListener('load', () => {
consoleComponent = new ConsoleComponent(document.body, store); consoleComponent = new ConsoleComponent(document.body, store);
}); });
const onMessage = (message) => {
switch (message.type) {
case messages.CONSOLE_SHOW_COMMAND:
return store.dispatch(consoleActions.showCommand(message.command));
case messages.CONSOLE_SHOW_ERROR:
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(() => { store.subscribe(() => {
completionComponent.update(); completionComponent.update();
consoleComponent.update(); consoleComponent.update();
}); });
browser.runtime.onMessage.addListener((action) => { browser.runtime.onMessage.addListener(onMessage);
switch (action.type) { window.addEventListener('message', (message) => {
case messages.CONSOLE_SHOW_COMMAND: onMessage(JSON.parse(message.data));
return store.dispatch(consoleActions.showCommand(action.command)); }, false);
case messages.CONSOLE_SHOW_ERROR:
return store.dispatch(consoleActions.showError(action.text));
case messages.CONSOLE_HIDE:
return store.dispatch(consoleActions.hide(action.command));
}
});

@ -1,9 +1,8 @@
import actions from 'console/actions'; import actions from 'console/actions';
const defaultState = { const defaultState = {
errorShown: false, mode: '',
errorText: '', messageText: '',
commandShown: false,
commandText: '', commandText: '',
completions: [], completions: [],
groupSelection: -1, groupSelection: -1,
@ -48,25 +47,24 @@ export default function reducer(state = defaultState, action = {}) {
switch (action.type) { switch (action.type) {
case actions.CONSOLE_SHOW_COMMAND: case actions.CONSOLE_SHOW_COMMAND:
return Object.assign({}, state, { return Object.assign({}, state, {
commandShown: true, mode: 'command',
commandText: action.text, commandText: action.text,
errorShown: false, errorShown: false,
completions: [] completions: []
}); });
case actions.CONSOLE_SHOW_ERROR: case actions.CONSOLE_SHOW_ERROR:
return Object.assign({}, state, { return Object.assign({}, state, {
errorText: action.text, mode: 'error',
errorShown: true, messageText: action.text,
commandShown: false,
}); });
case actions.CONSOLE_HIDE: case actions.CONSOLE_SHOW_INFO:
if (state.errorShown) {
// keep error message if shown
return state;
}
return Object.assign({}, state, { return Object.assign({}, state, {
errorShown: false, mode: 'info',
commandShown: false messageText: action.text,
});
case actions.CONSOLE_HIDE_COMMAND:
return Object.assign({}, state, {
mode: state.mode === 'command' ? '' : state.mode,
}); });
case actions.CONSOLE_SET_COMPLETIONS: case actions.CONSOLE_SET_COMPLETIONS:
return Object.assign({}, state, { return Object.assign({}, state, {

@ -64,12 +64,20 @@ body {
} }
} }
&-message {
@include consoole-font;
}
&-error { &-error {
background-color: red; background-color: red;
font-weight: bold; font-weight: bold;
color: white; color: white;
}
@include consoole-font; &-info {
background-color: white;
font-weight: normal;
color: green;
} }
&-command { &-command {

@ -2,7 +2,9 @@ import operations from 'shared/operations';
import messages from 'shared/messages'; import messages from 'shared/messages';
import * as scrolls from 'content/scrolls'; import * as scrolls from 'content/scrolls';
import * as navigates from 'content/navigates'; import * as navigates from 'content/navigates';
import * as urls from 'content/urls';
import * as followActions from 'content/actions/follow'; import * as followActions from 'content/actions/follow';
import * as consoleFrames from 'content/console-frames';
const exec = (operation) => { const exec = (operation) => {
switch (operation.type) { switch (operation.type) {
@ -32,6 +34,12 @@ const exec = (operation) => {
return navigates.parent(window); return navigates.parent(window);
case operations.NAVIGATE_ROOT: case operations.NAVIGATE_ROOT:
return navigates.root(window); return navigates.root(window);
case operations.URLS_YANK:
urls.yank(window);
return consoleFrames.postMessage(window.document, {
type: messages.CONSOLE_SHOW_INFO,
text: 'Current url yanked',
});
default: default:
browser.runtime.sendMessage({ browser.runtime.sendMessage({
type: messages.BACKGROUND_OPERATION, type: messages.BACKGROUND_OPERATION,

@ -15,4 +15,9 @@ const blur = (doc) => {
iframe.blur(); 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 };

@ -40,7 +40,7 @@ const reloadSettings = () => {
browser.runtime.onMessage.addListener((action) => { browser.runtime.onMessage.addListener((action) => {
switch (action.type) { switch (action.type) {
case messages.CONSOLE_HIDE: case messages.CONSOLE_HIDE_COMMAND:
window.focus(); window.focus();
consoleFrames.blur(window.document); consoleFrames.blur(window.document);
return Promise.resolve(); return Promise.resolve();

@ -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 };

@ -37,7 +37,8 @@ export default {
"[[": { "type": "navigate.link.prev" }, "[[": { "type": "navigate.link.prev" },
"]]": { "type": "navigate.link.next" }, "]]": { "type": "navigate.link.next" },
"gu": { "type": "navigate.parent" }, "gu": { "type": "navigate.parent" },
"gU": { "type": "navigate.root" } "gU": { "type": "navigate.root" },
"y": { "type": "urls.yank" }
}, },
"search": { "search": {
"default": "google", "default": "google",

@ -8,7 +8,8 @@ export default {
CONSOLE_QUERY_COMPLETIONS: 'console.query.completions', CONSOLE_QUERY_COMPLETIONS: 'console.query.completions',
CONSOLE_SHOW_COMMAND: 'console.show.command', CONSOLE_SHOW_COMMAND: 'console.show.command',
CONSOLE_SHOW_ERROR: 'console.show.error', CONSOLE_SHOW_ERROR: 'console.show.error',
CONSOLE_HIDE: 'console.hide', CONSOLE_SHOW_INFO: 'console.show.info',
CONSOLE_HIDE_COMMAND: 'console.hide.command',
OPEN_URL: 'open.url', OPEN_URL: 'open.url',

@ -36,4 +36,7 @@ export default {
ZOOM_IN: 'zoom.in', ZOOM_IN: 'zoom.in',
ZOOM_OUT: 'zoom.out', ZOOM_OUT: 'zoom.out',
ZOOM_NEUTRAL: 'zoom.neutral', ZOOM_NEUTRAL: 'zoom.neutral',
// Url yank
URLS_YANK: 'urls.yank',
}; };

@ -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", () => { describe("showError", () => {
it('create CONSOLE_SHOW_ERROR action', () => { it('create CONSOLE_SHOW_ERROR action', () => {
let action = consoleActions.showError('an error'); let action = consoleActions.showError('an error');
@ -20,9 +28,9 @@ describe("console actions", () => {
}); });
describe("hide", () => { describe("hide", () => {
it('create CONSOLE_HIDE action', () => { it('create CONSOLE_HIDE_COMMAND action', () => {
let action = consoleActions.hide(); let action = consoleActions.hideCommand();
expect(action.type).to.equal(actions.CONSOLE_HIDE); expect(action.type).to.equal(actions.CONSOLE_HIDE_COMMAND);
}); });
}); });

@ -5,9 +5,8 @@ import reducer from 'console/reducers';
describe("console reducer", () => { describe("console reducer", () => {
it('return the initial state', () => { it('return the initial state', () => {
let state = reducer(undefined, {}); let state = reducer(undefined, {});
expect(state).to.have.property('errorShown', false); expect(state).to.have.property('mode', '');
expect(state).to.have.property('errorText', ''); expect(state).to.have.property('messageText', '');
expect(state).to.have.property('commandShown', false);
expect(state).to.have.property('commandText', ''); expect(state).to.have.property('commandText', '');
expect(state).to.have.deep.property('completions', []); expect(state).to.have.deep.property('completions', []);
expect(state).to.have.property('groupSelection', -1); expect(state).to.have.property('groupSelection', -1);
@ -17,24 +16,31 @@ describe("console reducer", () => {
it('return next state for CONSOLE_SHOW_COMMAND', () => { it('return next state for CONSOLE_SHOW_COMMAND', () => {
let action = { type: actions.CONSOLE_SHOW_COMMAND, text: 'open ' }; let action = { type: actions.CONSOLE_SHOW_COMMAND, text: 'open ' };
let state = reducer({}, action); 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('commandText', 'open ');
expect(state).to.have.property('errorShown', false); });
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', () => { it('return next state for CONSOLE_SHOW_ERROR', () => {
let action = { type: actions.CONSOLE_SHOW_ERROR, text: 'an error' }; let action = { type: actions.CONSOLE_SHOW_ERROR, text: 'an error' };
let state = reducer({}, action); let state = reducer({}, action);
expect(state).to.have.property('errorShown', true); expect(state).to.have.property('mode', 'error');
expect(state).to.have.property('errorText', 'an error'); expect(state).to.have.property('messageText', 'an error');
expect(state).to.have.property('commandShown', false);
}); });
it('return next state for CONSOLE_HIDE', () => { it('return next state for CONSOLE_HIDE_COMMAND', () => {
let action = { type: actions.CONSOLE_HIDE }; let action = { type: actions.CONSOLE_HIDE_COMMAND };
let state = reducer({}, action); let state = reducer({ mode: 'command' }, action);
expect(state).to.have.property('errorShown', false); expect(state).to.have.property('mode', '');
expect(state).to.have.property('commandShown', false);
state = reducer({ mode: 'error' }, action);
expect(state).to.have.property('mode', 'error');
}); });
it ('return next state for CONSOLE_SET_COMPLETIONS', () => { it ('return next state for CONSOLE_SET_COMPLETIONS', () => {