From eff7fe276b5a9d50037c7d965712dc24d226a984 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 9 Sep 2017 16:43:17 +0900 Subject: remove keys --- test/background/keys.test.js | 55 -------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 test/background/keys.test.js (limited to 'test') diff --git a/test/background/keys.test.js b/test/background/keys.test.js deleted file mode 100644 index da9d430..0000000 --- a/test/background/keys.test.js +++ /dev/null @@ -1,55 +0,0 @@ -import { expect } from "chai"; -import { identifyKey, identifyKeys, hasPrefix } from '../../src/background/keys'; - -describe('keys', () => { - describe('#identifyKey', () => { - it('return true if key matched', () => { - expect(identifyKey( - { code: 100 }, - { code: 100 })).to.be.true; - expect(identifyKey( - { code: 100, shift: true, ctrl: true }, - { code: 100, shift: true, ctrl: true })).to.be.true; - expect(identifyKey( - { code: 100, shift: false, ctrl: false }, - { code: 100 })).to.be.true; - }); - - it('return false if key not matched', () => { - expect(identifyKey( - { code: 100 }, - { code: 101 })).to.be.false; - expect(identifyKey( - { code: 100, shift: true, ctrl: true }, - { code: 100, shift: true })).to.be.false; - }); - }); - - describe('#identifyKeys', () => { - it ('return true if keys matched', () => { - let keys = [{ code: 100 }, { code: 101, ctrl: false}]; - let prefix = [{ code: 100, ctrl: false }, { code: 101 }]; - expect(hasPrefix(keys, prefix)).to.be.true; - }); - - it ('return false if keys matched', () => { - let keys = [{ code: 100 }, { code: 101, ctrl: true }]; - let prefix = [{ code: 100 }, { code: 101 }]; - expect(hasPrefix(keys, prefix)).to.be.false; - }); - }); - - describe('#hasPrefix', () => { - it ('return true if prefix matched', () => { - let keys = [{ code: 100 }, { code: 101 }, { code: 102 }]; - let prefix = [{ code: 100 }, { code: 101 }]; - expect(hasPrefix(keys, prefix)).to.be.true; - }); - - it ('return false if prefix not matched', () => { - let keys = [{ code: 100 }, { code: 101 }, { code: 102 }]; - let prefix = [{ code: 102 }]; - expect(hasPrefix(keys, prefix)).to.be.false; - }); - }); -}); -- cgit v1.2.3 From 8593b3f5cd0992dd250f5a845c19dc60bbb0bc91 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 9 Sep 2017 20:36:07 +0900 Subject: remove messages --- src/shared/messages.js | 19 ------------------- test/shared/messages.test.js | 25 ------------------------- 2 files changed, 44 deletions(-) delete mode 100644 src/shared/messages.js delete mode 100644 test/shared/messages.test.js (limited to 'test') diff --git a/src/shared/messages.js b/src/shared/messages.js deleted file mode 100644 index 517fc4c..0000000 --- a/src/shared/messages.js +++ /dev/null @@ -1,19 +0,0 @@ -const receive = (win, callback) => { - win.addEventListener('message', (e) => { - let message; - try { - message = JSON.parse(e.data); - } catch (e) { - // ignore message posted by author of web page - return; - } - - callback(message); - }) -} - -const send = (win, message) => { - win.postMessage(JSON.stringify(message), '*'); -} - -export { receive, send }; diff --git a/test/shared/messages.test.js b/test/shared/messages.test.js deleted file mode 100644 index 0ebaf1a..0000000 --- a/test/shared/messages.test.js +++ /dev/null @@ -1,25 +0,0 @@ -import { expect } from "chai"; -import * as messages from '../../src/shared/messages'; - -describe('messages', () => { - describe('#receive', () => { - it('received a message', (done) => { - messages.receive(window, (message) => { - expect(message).to.deep.equal({ type: 'vimvixen.test' }); - done(); - }); - window.postMessage(JSON.stringify({ type: 'vimvixen.test' }), '*'); - }); - }); - - describe('#send', () => { - it('sends a message', (done) => { - window.addEventListener('message', (e) => { - let json = JSON.parse(e.data); - expect(json).to.deep.equal({ type: 'vimvixen.test' }); - done(); - }); - messages.send(window, { type: 'vimvixen.test' }); - }); - }); -}); -- cgit v1.2.3 From 7e35d11f659029febd738c83b19ab4b8a8b69642 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 9 Sep 2017 22:50:00 +0900 Subject: add console actions/reducer tests and fix targets --- src/console/console.js | 4 ++-- src/reducers/console.js | 12 ++++++------ test/actions/console.test.js | 37 +++++++++++++++++++++++++++++++++++++ test/reducers/console.test.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 test/actions/console.test.js create mode 100644 test/reducers/console.test.js (limited to 'test') diff --git a/src/console/console.js b/src/console/console.js index 044aa5f..35d98e0 100644 --- a/src/console/console.js +++ b/src/console/console.js @@ -1,12 +1,12 @@ import './console.scss'; import Completion from './completion'; -import consoleReducer, { defaultState } from '../reducers/console'; +import consoleReducer from '../reducers/console'; // TODO consider object-oriented var prevValue = ""; var completion = null; var completionOrigin = ""; -let state = defaultState; +let state = consoleReducer(undefined, {}); const blurMessage = () => { return { diff --git a/src/reducers/console.js b/src/reducers/console.js index 62fc951..3303802 100644 --- a/src/reducers/console.js +++ b/src/reducers/console.js @@ -1,10 +1,10 @@ import actions from '../actions'; -export const defaultState = { - errorText: '', +const defaultState = { errorShown: false, - commandText: '', + errorText: '', commandShown: false, + commandText: '', completions: [], }; @@ -14,7 +14,7 @@ export default function reducer(state = defaultState, action = {}) { return Object.assign({}, state, { commandShown: true, commandText: action.text, - errorShow: false, + errorShown: false, completions: [] }); case actions.CONSOLE_SET_COMPLETIONS: @@ -23,8 +23,8 @@ export default function reducer(state = defaultState, action = {}) { }); case actions.CONSOLE_SHOW_ERROR: return Object.assign({}, state, { - errorText: action.message, - errorShow: true, + errorText: action.text, + errorShown: true, commandShown: false, }); case actions.CONSOLE_HIDE: diff --git a/test/actions/console.test.js b/test/actions/console.test.js new file mode 100644 index 0000000..512ee40 --- /dev/null +++ b/test/actions/console.test.js @@ -0,0 +1,37 @@ +import { expect } from "chai"; +import actions from '../../src/actions'; +import * as consoleActions from '../../src/actions/console'; + +describe("console actions", () => { + describe("showCommand", () => { + it('create CONSOLE_SHOW_COMMAND action', () => { + let action = consoleActions.showCommand('hello'); + expect(action.type).to.equal(actions.CONSOLE_SHOW_COMMAND); + expect(action.text).to.equal('hello'); + }); + }); + + describe("setCompletions", () => { + it('create CONSOLE_SET_COMPLETIONS action', () => { + let action = consoleActions.setCompletions([1,2,3]); + expect(action.type).to.equal(actions.CONSOLE_SET_COMPLETIONS); + expect(action.completions).to.deep.equal([1, 2, 3]); + }); + }); + + describe("showError", () => { + it('create CONSOLE_SHOW_ERROR action', () => { + let action = consoleActions.showError('an error'); + expect(action.type).to.equal(actions.CONSOLE_SHOW_ERROR); + expect(action.text).to.equal('an error'); + }); + }); + + describe("hide", () => { + it('create CONSOLE_HIDE action', () => { + let action = consoleActions.hide(); + expect(action.type).to.equal(actions.CONSOLE_HIDE); + }); + }); +}); + diff --git a/test/reducers/console.test.js b/test/reducers/console.test.js new file mode 100644 index 0000000..9820a08 --- /dev/null +++ b/test/reducers/console.test.js @@ -0,0 +1,43 @@ +import { expect } from "chai"; +import actions from '../../src/actions'; +import consoleReducer from '../../src/reducers/console'; + +describe("console reducer", () => { + it('return the initial state', () => { + let state = consoleReducer(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('commandText', ''); + expect(state).to.have.deep.property('completions', []); + }); + + it('return next state for CONSOLE_SHOW_COMMAND', () => { + let action = { type: actions.CONSOLE_SHOW_COMMAND, text: 'open ' }; + let state = consoleReducer({}, action); + expect(state).to.have.property('commandShown', true); + expect(state).to.have.property('commandText', 'open '); + expect(state).to.have.property('errorShown', false); + }); + + it('return next state for CONSOLE_SET_COMPLETIONS', () => { + let action = { type: actions.CONSOLE_SET_COMPLETIONS, completions: [1, 2, 3] }; + let state = consoleReducer({}, action); + expect(state).to.have.deep.property('completions', [1, 2, 3]); + }); + + it('return next state for CONSOLE_SHOW_ERROR', () => { + let action = { type: actions.CONSOLE_SHOW_ERROR, text: 'an error' }; + let state = consoleReducer({}, action); + expect(state).to.have.property('errorShown', true); + expect(state).to.have.property('errorText', 'an error'); + expect(state).to.have.property('commandShown', false); + }); + + it('return next state for CONSOLE_HIDE', () => { + let action = { type: actions.CONSOLE_HIDE }; + let state = consoleReducer({}, action); + expect(state).to.have.property('errorShown', false); + expect(state).to.have.property('commandShown', false); + }); +}); -- cgit v1.2.3 From 3c67cc0a002aded07e88ea25acc881ff080d1ae4 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 10 Sep 2017 09:20:54 +0900 Subject: completion as action/reducer --- src/actions/background.js | 11 +++++++++++ src/actions/index.js | 4 +++- src/background/index.js | 20 +++++--------------- src/console/console-frame.js | 4 ---- src/console/console.js | 12 ++++-------- src/content/index.js | 19 ------------------- src/reducers/background.js | 38 ++++++++++++++++++++++++++++++++++++++ test/actions/background.test.js | 14 ++++++++++++++ 8 files changed, 75 insertions(+), 47 deletions(-) create mode 100644 src/actions/background.js create mode 100644 src/reducers/background.js create mode 100644 test/actions/background.test.js (limited to 'test') diff --git a/src/actions/background.js b/src/actions/background.js new file mode 100644 index 0000000..40b901b --- /dev/null +++ b/src/actions/background.js @@ -0,0 +1,11 @@ +import actions from '../actions'; + +export function requestCompletions(line) { + let command = line.split(' ', 1)[0]; + let keywords = line.replace(command + ' ', ''); + return { + type: actions.BACKGROUND_REQUEST_COMPLETIONS, + command, + keywords + }; +} diff --git a/src/actions/index.js b/src/actions/index.js index 38ced9d..8f22193 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -2,5 +2,7 @@ export default { CONSOLE_SHOW_COMMAND: 'vimvixen.console.show.command', CONSOLE_SET_COMPLETIONS: 'vimvixen.console.set.completions', CONSOLE_SHOW_ERROR: 'vimvixen.console.show.error', - CONSOLE_HIDE: 'vimvixen.console.hide' + CONSOLE_HIDE: 'vimvixen.console.hide', + + BACKGROUND_REQUEST_COMPLETIONS: 'vimvixen.background.request.completions' }; diff --git a/src/background/index.js b/src/background/index.js index 61d4895..a80d1ea 100644 --- a/src/background/index.js +++ b/src/background/index.js @@ -2,6 +2,7 @@ import * as actions from '../shared/actions'; import * as tabs from './tabs'; import * as zooms from './zooms'; import KeyQueue from './key-queue'; +import backgroundReducers from '../reducers/background'; const queue = new KeyQueue(); @@ -81,22 +82,11 @@ browser.runtime.onMessage.addListener((request, sender) => { return keyPressHandle(request, sender); case 'event.cmd.enter': return cmdEnterHandle(request, sender); - case 'event.cmd.tabs.completion': - return tabs.getCompletions(request.text).then((tabs) => { - let items = tabs.map((tab) => { - return { - caption: tab.title, - content: tab.title, - url: tab.url, - icon: tab.favIconUrl - } - }); - return { - name: "Buffers", - items: items - }; - }); default: return browser.tabs.sendMessage(sender.tab.id, request); } }); + +browser.runtime.onMessage.addListener((action, sender) => { + return backgroundReducers(undefined, action, sender.tab.id); +}); diff --git a/src/console/console-frame.js b/src/console/console-frame.js index 8b4c17a..063026c 100644 --- a/src/console/console-frame.js +++ b/src/console/console-frame.js @@ -45,8 +45,4 @@ export default class ConsoleFrame { isErrorShown() { return this.element.style.display === 'block' && this.errorShown; } - - setCompletions(completions) { - return browser.runtime.sendMessage(consoleActions.setCompletions(completions)); - } } diff --git a/src/console/console.js b/src/console/console.js index 35d98e0..d79e154 100644 --- a/src/console/console.js +++ b/src/console/console.js @@ -1,4 +1,5 @@ import './console.scss'; +import * as backgroundActions from '../actions/background'; import Completion from './completion'; import consoleReducer from '../reducers/console'; @@ -21,13 +22,6 @@ const keydownMessage = (input) => { }; }; -const keyupMessage = (input) => { - return { - type: 'vimvixen.command.change', - value: input.value - }; -}; - const handleBlur = () => { return browser.runtime.sendMessage(blurMessage()); }; @@ -88,7 +82,9 @@ const handleKeyup = (e) => { return; } prevValue = e.target.value; - return browser.runtime.sendMessage(keyupMessage(e.target)); + return browser.runtime.sendMessage( + backgroundActions.requestCompletions(e.target.value) + ); }; window.addEventListener('load', () => { diff --git a/src/content/index.js b/src/content/index.js index deb3506..1a7fa55 100644 --- a/src/content/index.js +++ b/src/content/index.js @@ -68,23 +68,6 @@ window.addEventListener("keypress", (e) => { }); }); -const doCompletion = (line) => { - if (line.startsWith('buffer ')) { - let keyword = line.replace('buffer ', ''); - - browser.runtime.sendMessage({ - type: 'event.cmd.tabs.completion', - text: keyword - }).then((completions) => { - vvConsole.setCompletions([completions]); - }).catch((err) => { - console.error("Vim Vixen:", err); - vvConsole.showError(err.message); - }); - } - return Promise.resolve(); -}; - browser.runtime.onMessage.addListener((action) => { switch (action.type) { case 'vimvixen.command.blur': @@ -100,8 +83,6 @@ browser.runtime.onMessage.addListener((action) => { console.error("Vim Vixen:", err); vvConsole.showError(err.message); }); - case 'vimvixen.command.change': - return doCompletion(action.value); default: return Promise.resolve(); } diff --git a/src/reducers/background.js b/src/reducers/background.js new file mode 100644 index 0000000..eccc8ca --- /dev/null +++ b/src/reducers/background.js @@ -0,0 +1,38 @@ +import * as tabs from '../background/tabs'; +import * as consoleActions from '../actions/console'; +import actions from '../actions'; + +const doCompletion = (command, keywords, sendto) => { + if (command === 'buffer') { + return tabs.getCompletions(keywords).then((tabs) => { + let items = tabs.map((tab) => { + return { + caption: tab.title, + content: tab.title, + url: tab.url, + icon: tab.favIconUrl + } + }); + let completions = { + name: "Buffers", + items: items + }; + return browser.tabs.sendMessage( + sendto, + consoleActions.setCompletions([completions])); + }); + } + return Promise.resolve(); +}; + + + +export default function reducer(state, action = {}, sendto) { + // TODO hide sendto object + switch (action.type) { + case actions.BACKGROUND_REQUEST_COMPLETIONS: + return doCompletion(action.command, action.keywords, sendto); + default: + return Promise.resolve(); + } +} diff --git a/test/actions/background.test.js b/test/actions/background.test.js new file mode 100644 index 0000000..a3203ee --- /dev/null +++ b/test/actions/background.test.js @@ -0,0 +1,14 @@ +import { expect } from "chai"; +import actions from '../../src/actions'; +import * as backgroundActions from '../../src/actions/background'; + +describe("background actions", () => { + describe("requestCompletions", () => { + it('create BACKGROUND_REQUEST_COMPLETIONS action', () => { + let action = backgroundActions.requestCompletions('buffer hoge fuga'); + expect(action.type).to.equal(actions.BACKGROUND_REQUEST_COMPLETIONS); + expect(action.command).to.equal('buffer'); + expect(action.keywords).to.equal('hoge fuga'); + }); + }); +}); -- cgit v1.2.3 From 879b5afe66ee79424c3ffee3951ef1c0b8c86eaa Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 10 Sep 2017 21:28:00 +0900 Subject: key input sequence as action/reducer --- src/actions/index.js | 4 ++ src/actions/input.js | 15 +++++++ src/background/index.js | 56 ++++++++++++++++---------- src/background/key-queue.js | 82 --------------------------------------- src/background/keys.js | 57 +++++++++++++++++++++++++++ src/background/tabs.js | 4 +- src/content/index.js | 10 +---- src/reducers/input.js | 23 +++++++++++ test/background/key-queue.test.js | 50 ------------------------ test/background/keys.test.js | 31 +++++++++++++++ 10 files changed, 170 insertions(+), 162 deletions(-) create mode 100644 src/actions/input.js delete mode 100644 src/background/key-queue.js create mode 100644 src/background/keys.js create mode 100644 src/reducers/input.js delete mode 100644 test/background/key-queue.test.js create mode 100644 test/background/keys.test.js (limited to 'test') diff --git a/src/actions/index.js b/src/actions/index.js index de3ab42..135dd4a 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -29,4 +29,8 @@ export default { FOLLOW_START: 'follow.start', HISTORY_PREV: 'history.prev', HISTORY_NEXT: 'history.next', + + // User input + INPUT_KEY_PRESS: 'input.key,press', + INPUT_CLEAR_KEYS: 'input.clear.keys', }; diff --git a/src/actions/input.js b/src/actions/input.js new file mode 100644 index 0000000..c72b9e0 --- /dev/null +++ b/src/actions/input.js @@ -0,0 +1,15 @@ +import actions from '../actions'; + +export function keyPress(code, ctrl) { + return { + type: actions.INPUT_KEY_PRESS, + code, + ctrl + }; +} + +export function clearKeys() { + return { + type: actions.INPUT_CLEAR_KEYS + } +} diff --git a/src/background/index.js b/src/background/index.js index 3fa8553..4d75b33 100644 --- a/src/background/index.js +++ b/src/background/index.js @@ -1,22 +1,10 @@ import * as tabs from './tabs'; -import KeyQueue from './key-queue'; +import * as keys from './keys'; +import * as inputActions from '../actions/input'; import backgroundReducers from '../reducers/background'; +import inputReducers from '../reducers/input'; -const queue = new KeyQueue(); - -const keyPressHandle = (request, sender) => { - let action = queue.push({ - code: request.code, - ctrl: request.ctrl - }); - if (!action) { - return Promise.resolve(); - } - - return backgroundReducers(undefined, action, sender).then(() => { - return browser.tabs.sendMessage(sender.tab.id, action); - }); -}; +let inputState = inputReducers(undefined, {}); const normalizeUrl = (string) => { try { @@ -51,8 +39,6 @@ const cmdEnterHandle = (request, sender) => { browser.runtime.onMessage.addListener((request, sender) => { switch (request.type) { - case 'event.keypress': - return keyPressHandle(request, sender); case 'event.cmd.enter': return cmdEnterHandle(request, sender); default: @@ -60,6 +46,36 @@ browser.runtime.onMessage.addListener((request, sender) => { } }); -browser.runtime.onMessage.addListener((action, sender) => { +const keyQueueChanged = (sender, prevState, state) => { + if (state.keys.length === 0) { + return Promise.resolve(); + } + + let prefix = keys.asKeymapChars(state.keys); + let matched = Object.keys(keys.defaultKeymap).filter((keys) => { + return keys.startsWith(prefix); + }); + if (matched.length == 0) { + return handleMessage(inputActions.clearKeys(), sender); + } else if (matched.length > 1 || matched.length === 1 && prefix !== matched[0]) { + return Promise.resolve(); + } + let action = keys.defaultKeymap[matched]; + return handleMessage(inputActions.clearKeys(), sender).then(() => { + return backgroundReducers(undefined, action, sender).then(() => { + return browser.tabs.sendMessage(sender.tab.id, action); + }); + }); +}; + +const handleMessage = (action, sender) => { + let nextInputState = inputReducers(inputState, action); + if (JSON.stringify(nextInputState) !== JSON.stringify(inputState)) { + let prevState = inputState; + inputState = nextInputState; + return keyQueueChanged(sender, prevState, inputState); + } return backgroundReducers(undefined, action, sender); -}); +}; + +browser.runtime.onMessage.addListener(handleMessage); diff --git a/src/background/key-queue.js b/src/background/key-queue.js deleted file mode 100644 index 924bf77..0000000 --- a/src/background/key-queue.js +++ /dev/null @@ -1,82 +0,0 @@ -import actions from '../actions'; - -const DEFAULT_KEYMAP = { - ':': { type: actions.CMD_OPEN }, - 'o': { type: actions.CMD_TABS_OPEN, alter: false }, - 'O': { type: actions.CMD_TABS_OPEN, alter: true }, - 'b': { type: actions.CMD_BUFFER }, - 'k': { type: actions.SCROLL_LINES, count: -1 }, - 'j': { type: actions.SCROLL_LINES, count: 1 }, - '': { type: actions.SCROLL_LINES, count: -1 }, - '': { type: actions.SCROLL_LINES, count: 1 }, - '': { type: actions.SCROLL_PAGES, count: -0.5 }, - '': { type: actions.SCROLL_PAGES, count: 0.5 }, - '': { type: actions.SCROLL_PAGES, count: -1 }, - '': { type: actions.SCROLL_PAGES, count: 1 }, - 'gg': { type: actions.SCROLL_TOP }, - 'G': { type: actions.SCROLL_BOTTOM }, - '0': { type: actions.SCROLL_LEFT }, - '$': { type: actions.SCROLL_RIGHT }, - 'd': { type: actions.TABS_CLOSE }, - 'u': { type: actions.TABS_REOPEN }, - 'h': { type: actions.TABS_PREV, count: 1 }, - 'l': { type: actions.TABS_NEXT, count: 1 }, - 'r': { type: actions.TABS_RELOAD, cache: false }, - 'R': { type: actions.TABS_RELOAD, cache: true }, - 'zi': { type: actions.ZOOM_IN }, - 'zo': { type: actions.ZOOM_OUT }, - 'zz': { type: actions.ZOOM_NEUTRAL }, - 'f': { type: actions.FOLLOW_START, newTab: false }, - 'F': { type: actions.FOLLOW_START, newTab: true }, - 'H': { type: actions.HISTORY_PREV }, - 'L': { type: actions.HISTORY_NEXT }, -} - -export default class KeyQueue { - - constructor(keymap = DEFAULT_KEYMAP) { - this.data = []; - this.keymap = keymap; - } - - push(key) { - this.data.push(key); - - let current = this.asKeymapChars(); - let filtered = Object.keys(this.keymap).filter((keys) => { - return keys.startsWith(current); - }); - - if (filtered.length == 0) { - this.data = []; - return null; - } else if (filtered.length === 1 && current === filtered[0]) { - let action = this.keymap[filtered[0]]; - this.data = []; - return action; - } - return null; - } - - asKeymapChars() { - return this.data.map((k) => { - let c = String.fromCharCode(k.code); - if (k.ctrl) { - return ''; - } else { - return c - } - }).join(''); - } - - asCaretChars() { - return this.data.map((k) => { - let c = String.fromCharCode(k.code); - if (k.ctrl) { - return '^' + c.toUpperCase(); - } else { - return c; - } - }).join(''); - } -} diff --git a/src/background/keys.js b/src/background/keys.js new file mode 100644 index 0000000..0ce53fa --- /dev/null +++ b/src/background/keys.js @@ -0,0 +1,57 @@ +import actions from '../actions'; + +const defaultKeymap = { + ':': { type: actions.CMD_OPEN }, + 'o': { type: actions.CMD_TABS_OPEN, alter: false }, + 'O': { type: actions.CMD_TABS_OPEN, alter: true }, + 'b': { type: actions.CMD_BUFFER }, + 'k': { type: actions.SCROLL_LINES, count: -1 }, + 'j': { type: actions.SCROLL_LINES, count: 1 }, + '': { type: actions.SCROLL_LINES, count: -1 }, + '': { type: actions.SCROLL_LINES, count: 1 }, + '': { type: actions.SCROLL_PAGES, count: -0.5 }, + '': { type: actions.SCROLL_PAGES, count: 0.5 }, + '': { type: actions.SCROLL_PAGES, count: -1 }, + '': { type: actions.SCROLL_PAGES, count: 1 }, + 'gg': { type: actions.SCROLL_TOP }, + 'G': { type: actions.SCROLL_BOTTOM }, + '0': { type: actions.SCROLL_LEFT }, + '$': { type: actions.SCROLL_RIGHT }, + 'd': { type: actions.TABS_CLOSE }, + 'u': { type: actions.TABS_REOPEN }, + 'h': { type: actions.TABS_PREV, count: 1 }, + 'l': { type: actions.TABS_NEXT, count: 1 }, + 'r': { type: actions.TABS_RELOAD, cache: false }, + 'R': { type: actions.TABS_RELOAD, cache: true }, + 'zi': { type: actions.ZOOM_IN }, + 'zo': { type: actions.ZOOM_OUT }, + 'zz': { type: actions.ZOOM_NEUTRAL }, + 'f': { type: actions.FOLLOW_START, newTab: false }, + 'F': { type: actions.FOLLOW_START, newTab: true }, + 'H': { type: actions.HISTORY_PREV }, + 'L': { type: actions.HISTORY_NEXT }, +} + +const asKeymapChars = (keys) => { + return keys.map((k) => { + let c = String.fromCharCode(k.code); + if (k.ctrl) { + return ''; + } else { + return c + } + }).join(''); +} + +const asCaretChars = (keys) => { + return keys.map((k) => { + let c = String.fromCharCode(k.code); + if (k.ctrl) { + return '^' + c.toUpperCase(); + } else { + return c; + } + }).join(''); +} + +export { defaultKeymap, asKeymapChars, asCaretChars }; diff --git a/src/background/tabs.js b/src/background/tabs.js index 111bbd9..bd69b4b 100644 --- a/src/background/tabs.js +++ b/src/background/tabs.js @@ -59,7 +59,7 @@ const getCompletions = (keyword) => { }; const selectPrevTab = (current, count) => { - return browser.tabs.query({ currentWindow: true }, (tabs) => { + return browser.tabs.query({ currentWindow: true }).then((tabs) => { if (tabs.length < 2) { return; } @@ -70,7 +70,7 @@ const selectPrevTab = (current, count) => { }; const selectNextTab = (current, count) => { - return browser.tabs.query({ currentWindow: true }, (tabs) => { + return browser.tabs.query({ currentWindow: true }).then((tabs) => { if (tabs.length < 2) { return; } diff --git a/src/content/index.js b/src/content/index.js index 314dfea..12d079f 100644 --- a/src/content/index.js +++ b/src/content/index.js @@ -1,4 +1,5 @@ import '../console/console-frame.scss'; +import * as inputActions from '../actions/input'; import * as consoleFrames from '../console/frames'; import actions from '../actions'; import contentReducer from '../reducers/content'; @@ -14,14 +15,7 @@ window.addEventListener("keypress", (e) => { if (e.target instanceof HTMLInputElement) { return; } - - let request = { - type: 'event.keypress', - code: e.which, - ctrl: e.ctrlKey, - } - - browser.runtime.sendMessage(request) + browser.runtime.sendMessage(inputActions.keyPress(e.which, e.ctrlKey)) .catch((err) => { console.error("Vim Vixen:", err); return consoleFrames.showError(err.message); diff --git a/src/reducers/input.js b/src/reducers/input.js new file mode 100644 index 0000000..25ff1a3 --- /dev/null +++ b/src/reducers/input.js @@ -0,0 +1,23 @@ +import actions from '../actions'; + +const defaultState = { + keys: [], +}; + +export default function reducer(state = defaultState, action = {}) { + switch (action.type) { + case actions.INPUT_KEY_PRESS: + return Object.assign({}, state, { + keys: state.keys.concat([{ + code: action.code, + ctrl: action.ctrl + }]) + }); + case actions.INPUT_CLEAR_KEYS: + return Object.assign({}, state, { + keys: [], + }); + default: + return state; + } +} diff --git a/test/background/key-queue.test.js b/test/background/key-queue.test.js deleted file mode 100644 index ac43228..0000000 --- a/test/background/key-queue.test.js +++ /dev/null @@ -1,50 +0,0 @@ -import { expect } from "chai"; -import KeyQueue from '../../src/background/key-queue'; - -describe("keyQueue class", () => { - const KEYMAP = { - 'gGG': [], - 'gg': [ 'scroll.top' ], - }; - - const g = 'g'.charCodeAt(0); - const G = 'G'.charCodeAt(0); - const x = 'x'.charCodeAt(0); - - describe("#push", () => { - it("returns matched action", () => { - let queue = new KeyQueue(KEYMAP); - queue.push({ code: g }); - let action = queue.push({ code: g }); - - expect(action).to.deep.equal([ 'scroll.top' ]); - }); - - it("returns null on no actions matched", () => { - let queue = new KeyQueue(KEYMAP); - queue.push({ code: g }); - let action = queue.push({ code: G }); - - expect(action).to.be.null; - expect(queue.asKeymapChars()).to.be.empty; - }); - }); - - describe('#asKeymapChars', () => { - let queue = new KeyQueue(KEYMAP); - queue.push({ code: g }); - queue.push({ code: x, ctrl: true }); - queue.push({ code: G }); - - expect(queue.asKeymapChars()).to.equal('gG'); - }); - - describe('#asCaretChars', () => { - let queue = new KeyQueue(KEYMAP); - queue.push({ code: g }); - queue.push({ code: x, ctrl: true }); - queue.push({ code: G }); - - expect(queue.asCaretChars()).to.equal('g^XG'); - }); -}); diff --git a/test/background/keys.test.js b/test/background/keys.test.js new file mode 100644 index 0000000..2cb9a3a --- /dev/null +++ b/test/background/keys.test.js @@ -0,0 +1,31 @@ +import { expect } from "chai"; +import * as keys from '../../src/background/keys'; + +describe("keys", () => { + const KEYMAP = { + 'gGG': [], + 'gg': { type: 'scroll.top' }, + }; + + const g = 'g'.charCodeAt(0); + const G = 'G'.charCodeAt(0); + const x = 'x'.charCodeAt(0); + + describe('#asKeymapChars', () => { + let keySequence = [ + { code: g }, + { code: x, ctrl: true }, + { code: G } + ]; + expect(keys.asKeymapChars(keySequence)).to.equal('gG'); + }); + + describe('#asCaretChars', () => { + let keySequence = [ + { code: g }, + { code: x, ctrl: true }, + { code: G } + ]; + expect(keys.asCaretChars(keySequence)).to.equal('g^XG'); + }); +}); -- cgit v1.2.3 From 14d13e2c3abdb090431f59970681cdaf95f0a24a Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 10 Sep 2017 22:23:17 +0900 Subject: add tests for input action/reducer --- test/actions/input.test.js | 17 +++++++++++++++++ test/reducers/input.test.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 test/actions/input.test.js create mode 100644 test/reducers/input.test.js (limited to 'test') diff --git a/test/actions/input.test.js b/test/actions/input.test.js new file mode 100644 index 0000000..a49a5bc --- /dev/null +++ b/test/actions/input.test.js @@ -0,0 +1,17 @@ +import { expect } from "chai"; +import actions from '../../src/actions'; +import * as inputActions from '../../src/actions/input'; + +describe("input actions", () => { + describe("keyPress", () => { + let action = inputActions.keyPress(123, true); + expect(action.type).to.equal(actions.INPUT_KEY_PRESS); + expect(action.code).to.equal(123); + expect(action.ctrl).to.be.true; + }); + + describe("clearKeys", () => { + let action = inputActions.clearKeys(); + expect(action.type).to.equal(actions.INPUT_CLEAR_KEYS); + }); +}); diff --git a/test/reducers/input.test.js b/test/reducers/input.test.js new file mode 100644 index 0000000..d7a0855 --- /dev/null +++ b/test/reducers/input.test.js @@ -0,0 +1,34 @@ +import { expect } from "chai"; +import actions from '../../src/actions'; +import inputReducer from '../../src/reducers/input'; + +describe("input reducer", () => { + it('return the initial state', () => { + let state = inputReducer(undefined, {}); + expect(state).to.have.deep.property('keys', []); + }); + + it('return next state for INPUT_KEY_PRESS', () => { + let action = { type: actions.INPUT_KEY_PRESS, code: 123, ctrl: true }; + let state = inputReducer(undefined, action); + expect(state).to.have.deep.property('keys', [{ code: 123, ctrl: true }]); + + action = { type: actions.INPUT_KEY_PRESS, code: 456, ctrl: false }; + state = inputReducer(state, action); + expect(state).to.have.deep.property('keys', [ + { code: 123, ctrl: true }, + { code: 456, ctrl: false } + ]); + }); + + it('return next state for INPUT_CLEAR_KEYS', () => { + let action = { type: actions.INPUT_CLEAR_KEYS }; + let state = inputReducer({ + keys: [ + { code: 123, ctrl: true }, + { code: 456, ctrl: false } + ] + }, action); + expect(state).to.have.deep.property('keys', []); + }); +}); -- cgit v1.2.3 From 2190a525b40a102851121c40654dcde2bb5ac6b3 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 11 Sep 2017 21:37:32 +0900 Subject: add command actions test --- src/actions/command.js | 2 +- test/actions/command.test.js | 51 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 test/actions/command.test.js (limited to 'test') diff --git a/src/actions/command.js b/src/actions/command.js index 982255c..c983278 100644 --- a/src/actions/command.js +++ b/src/actions/command.js @@ -22,7 +22,7 @@ export function exec(line) { case 'tabopen': return { type: actions.COMMAND_TABOPEN_URL, - url: remaining + url: normalizeUrl(remaining) }; case 'b': case 'buffer': diff --git a/test/actions/command.test.js b/test/actions/command.test.js new file mode 100644 index 0000000..01a67f2 --- /dev/null +++ b/test/actions/command.test.js @@ -0,0 +1,51 @@ +import { expect } from "chai"; +import actions from '../../src/actions'; +import * as commandActions from '../../src/actions/command'; + +describe("command actions", () => { + describe("exec", () => { + context("open command", () => { + it('create COMMAND_OPEN_URL acion with a full url', () => { + let action = commandActions.exec("open https://github.com/") + expect(action.type).to.equal(actions.COMMAND_OPEN_URL); + expect(action.url).to.equal('https://github.com/'); + }); + + it('create COMMAND_OPEN_URL acion with a domain name', () => { + let action = commandActions.exec("open github.com") + expect(action.type).to.equal(actions.COMMAND_OPEN_URL); + expect(action.url).to.equal('http://github.com'); + }); + }); + + context("tabopen command", () => { + it('create COMMAND_TABOPEN_URL acion with a full url', () => { + let action = commandActions.exec("tabopen https://github.com/") + expect(action.type).to.equal(actions.COMMAND_TABOPEN_URL); + expect(action.url).to.equal('https://github.com/'); + }); + + it('create COMMAND_TABOPEN_URL acion with a domain name', () => { + let action = commandActions.exec("tabopen github.com") + expect(action.type).to.equal(actions.COMMAND_TABOPEN_URL); + expect(action.url).to.equal('http://github.com'); + }); + }); + + context("buffer command", () => { + it('create COMMAND_BUFFER acion with a keywords', () => { + let action = commandActions.exec("buffer foo bar") + expect(action.type).to.equal(actions.COMMAND_BUFFER); + expect(action.keywords).to.equal('foo bar'); + }); + }); + + context("b command", () => { + it('create COMMAND_BUFFER acion with a keywords', () => { + let action = commandActions.exec("b foo bar") + expect(action.type).to.equal(actions.COMMAND_BUFFER); + expect(action.keywords).to.equal('foo bar'); + }); + }); + }); +}); -- cgit v1.2.3 From 7bc569eac745b97137e1db8b9271493b3e5c8a20 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 11 Sep 2017 21:37:51 +0900 Subject: fix input actions test --- test/actions/input.test.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/test/actions/input.test.js b/test/actions/input.test.js index a49a5bc..9ec6de4 100644 --- a/test/actions/input.test.js +++ b/test/actions/input.test.js @@ -4,14 +4,18 @@ import * as inputActions from '../../src/actions/input'; describe("input actions", () => { describe("keyPress", () => { - let action = inputActions.keyPress(123, true); - expect(action.type).to.equal(actions.INPUT_KEY_PRESS); - expect(action.code).to.equal(123); - expect(action.ctrl).to.be.true; + it('create INPUT_KEY_PRESS action', () => { + let action = inputActions.keyPress(123, true); + expect(action.type).to.equal(actions.INPUT_KEY_PRESS); + expect(action.code).to.equal(123); + expect(action.ctrl).to.be.true; + }); }); describe("clearKeys", () => { - let action = inputActions.clearKeys(); - expect(action.type).to.equal(actions.INPUT_CLEAR_KEYS); + it('create INPUT_CLEAR_KEYSaction', () => { + let action = inputActions.clearKeys(); + expect(action.type).to.equal(actions.INPUT_CLEAR_KEYS); + }); }); }); -- cgit v1.2.3