diff options
Diffstat (limited to 'src/background')
-rw-r--r-- | src/background/index.js | 126 | ||||
-rw-r--r-- | src/background/key-queue.js | 82 | ||||
-rw-r--r-- | src/background/keys.js | 73 | ||||
-rw-r--r-- | src/background/tabs.js | 4 |
4 files changed, 87 insertions, 198 deletions
diff --git a/src/background/index.js b/src/background/index.js index 8913a83..e72cab0 100644 --- a/src/background/index.js +++ b/src/background/index.js @@ -1,103 +1,45 @@ -import * as actions from '../shared/actions'; -import * as tabs from './tabs'; -import * as zooms from './zooms'; -import KeyQueue from './key-queue'; +import * as keys from './keys'; +import * as inputActions from '../actions/input'; +import backgroundReducers from '../reducers/background'; +import commandReducer from '../reducers/command'; +import inputReducers from '../reducers/input'; -const queue = new KeyQueue(); +let inputState = inputReducers(undefined, {}); -const keyPressHandle = (request, sender) => { - let action = queue.push({ - code: request.code, - ctrl: request.ctrl - }); - if (!action) { +const keyQueueChanged = (sender, prevState, state) => { + if (state.keys.length === 0) { return Promise.resolve(); } - if (actions.isBackgroundAction(action[0])) { - return doBackgroundAction(sender, action); - } else if (actions.isContentAction(action[0])) { - return Promise.resolve({ - type: 'response.action', - action: action - }); + 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(); } - 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 doBackgroundAction = (sender, action) => { - switch(action[0]) { - case actions.TABS_CLOSE: - return tabs.closeTab(sender.tab.id); - case actions.TABS_REOPEN: - return tabs.reopenTab(); - case actions.TABS_PREV: - return tabs.selectPrevTab(sender.tab.index, actions[1] || 1); - case actions.TABS_NEXT: - return tabs.selectNextTab(sender.tab.index, actions[1] || 1); - case actions.TABS_RELOAD: - return tabs.reload(sender.tab, actions[1] || false); - case actions.ZOOM_IN: - return zooms.zoomIn(); - case actions.ZOOM_OUT: - return zooms.zoomOut(); - case actions.ZOOM_NEUTRAL: - return zooms.neutral(); - } - return Promise.resolve(); -} - -const normalizeUrl = (string) => { - try { - return new URL(string).href - } catch (e) { - return 'http://' + string; +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); } -} - -const cmdBuffer = (sender, arg) => { - if (isNaN(arg)) { - return tabs.selectByKeyword(sender.tab, arg); - } else { - let index = parseInt(arg, 10) - 1; - return tabs.selectAt(index); - } -} - -const cmdEnterHandle = (request, sender) => { - let words = request.text.split(' ').filter((s) => s.length > 0); - switch (words[0]) { - case 'open': - return browser.tabs.update(sender.tab.id, { url: normalizeUrl(words[1]) }); - case 'tabopen': - return browser.tabs.create({ url: normalizeUrl(words[1]) }); - case 'b': - case 'buffer': - return cmdBuffer(sender, words[1]); - } - throw new Error(words[0] + ' command is not defined'); + return backgroundReducers(undefined, action, sender).then(() => { + return commandReducer(undefined, action, sender).then(() => { + return browser.tabs.sendMessage(sender.tab.id, action); + }); + }); }; -browser.runtime.onMessage.addListener((request, sender) => { - switch (request.type) { - case 'event.keypress': - 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 - }; - }); - } -}); +browser.runtime.onMessage.addListener(handleMessage); diff --git a/src/background/key-queue.js b/src/background/key-queue.js deleted file mode 100644 index d7f0984..0000000 --- a/src/background/key-queue.js +++ /dev/null @@ -1,82 +0,0 @@ -import * as actions from '../shared/actions'; - -const DEFAULT_KEYMAP = { - ':': [ actions.CMD_OPEN ], - 'o': [ actions.CMD_TABS_OPEN, false ], - 'O': [ actions.CMD_TABS_OPEN, true ], - 'b': [ actions.CMD_BUFFER ], - 'k': [ actions.SCROLL_LINES, -1 ], - 'j': [ actions.SCROLL_LINES, 1 ], - '<C-E>': [ actions.SCROLL_LINES, -1 ], - '<C-Y>': [ actions.SCROLL_LINES, 1 ], - '<C-U>': [ actions.SCROLL_PAGES, -0.5 ], - '<C-D>': [ actions.SCROLL_PAGES, 0.5 ], - '<C-B>': [ actions.SCROLL_PAGES, -1 ], - '<C-F>': [ actions.SCROLL_PAGES, 1 ], - 'gg': [ actions.SCROLL_TOP ], - 'G': [ actions.SCROLL_BOTTOM ], - '0': [ actions.SCROLL_LEFT ], - '$': [ actions.SCROLL_RIGHT ], - 'd': [ actions.TABS_CLOSE ], - 'u': [ actions.TABS_REOPEN], - 'h': [ actions.TABS_PREV, 1 ], - 'l': [ actions.TABS_NEXT, 1 ], - 'r': [ actions.TABS_RELOAD, false ], - 'R': [ actions.TABS_RELOAD, true ], - 'zi': [ actions.ZOOM_IN ], - 'zo': [ actions.ZOOM_OUT ], - 'zz': [ actions.ZOOM_NEUTRAL], - 'f': [ actions.FOLLOW_START, false ], - 'F': [ actions.FOLLOW_START, true ], - 'H': [ actions.HISTORY_PREV ], - 'L': [ 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 '<C-' + c.toUpperCase() + '>'; - } 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 index 2fd00a2..0ce53fa 100644 --- a/src/background/keys.js +++ b/src/background/keys.js @@ -1,28 +1,57 @@ -const identifyKey = (key1, key2) => { - return (key1.code === key2.code) && - ((key1.shift || false) === (key2.shift || false)) && - ((key1.ctrl || false) === (key2.ctrl || false)) && - ((key1.alt || false) === (key2.alt || false)) && - ((key1.meta || false) === (key2.meta || false)); -}; +import actions from '../actions'; -const hasPrefix = (keys, prefix) => { - if (keys.length < prefix.length) { - return false; - } - for (let i = 0; i < prefix.length; ++i) { - if (!identifyKey(keys[i], prefix[i])) { - return false; +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 }, + '<C-E>': { type: actions.SCROLL_LINES, count: -1 }, + '<C-Y>': { type: actions.SCROLL_LINES, count: 1 }, + '<C-U>': { type: actions.SCROLL_PAGES, count: -0.5 }, + '<C-D>': { type: actions.SCROLL_PAGES, count: 0.5 }, + '<C-B>': { type: actions.SCROLL_PAGES, count: -1 }, + '<C-F>': { 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 '<C-' + c.toUpperCase() + '>'; + } else { + return c } - } - return true; + }).join(''); } -const identifyKeys = (keys1, keys2) => { - if (keys1.length !== keys2.length) { - return false; - } - return hasPrefix(keys1, keys2); +const asCaretChars = (keys) => { + return keys.map((k) => { + let c = String.fromCharCode(k.code); + if (k.ctrl) { + return '^' + c.toUpperCase(); + } else { + return c; + } + }).join(''); } -export { identifyKey, identifyKeys, hasPrefix }; +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; } |