aboutsummaryrefslogtreecommitdiff
path: root/src/background
diff options
context:
space:
mode:
Diffstat (limited to 'src/background')
-rw-r--r--src/background/index.js126
-rw-r--r--src/background/key-queue.js82
-rw-r--r--src/background/keys.js73
-rw-r--r--src/background/tabs.js4
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;
}