Merge branch 'lint'

jh-changes
Shin'ya Ueoka 7 years ago
commit cd47088981
  1. 33
      .eslintrc
  2. 59
      src/actions/command.js
  3. 22
      src/actions/console.js
  4. 12
      src/actions/input.js
  5. 10
      src/actions/operation.js
  6. 30
      src/background/index.js
  7. 12
      src/background/keys.js
  8. 32
      src/background/tabs.js
  9. 9
      src/console/completion.js
  10. 60
      src/console/console.js
  11. 4
      src/console/frames.js
  12. 32
      src/content/follow.js
  13. 6
      src/content/hint-key-producer.js
  14. 5
      src/content/hint.js
  15. 4
      src/content/histories.js
  16. 8
      src/content/index.js
  17. 4
      src/content/scrolls.js
  18. 6
      src/operations/index.js
  19. 2
      src/reducers/console.js
  20. 10
      src/reducers/input.js
  21. 8
      src/store/index.js

@ -11,28 +11,47 @@
"jsx": true "jsx": true
} }
}, },
"extends": [ "eslint:recommended" ], "extends": [ "eslint:all" ],
"rules": { "rules": {
"array-bracket-newline": ["error", { "multiline": true }],
"arrow-body-style": "off", "arrow-body-style": "off",
"array-element-newline": "off",
"arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }],
"brace-style": ["error", "1tbs", { "allowSingleLine": true }], "brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"comma-dangle": "off",
"consistent-return": "off",
"default-case": "off",
"id-length": "off", "id-length": "off",
"indent": ["error", 2], "indent": ["error", 2],
"max-statements": ["error", 15],
"multiline-ternary": "off",
"newline-after-var": "off", "newline-after-var": "off",
"newline-before-return": "off", "newline-before-return": "off",
"multiline-ternary": "off", "no-magic-numbers": "off",
"max-statements": ["error", 15], "no-bitwise": "off",
"no-console": "off", "no-use-before-define": "off",
"no-param-reassign": "off", "no-warning-comments": "off",
"no-console": ["error", { "allow": ["warn", "error"] }],
"no-empty-function": "off",
"no-mixed-operators": "off",
"no-plusplus": "off",
"capitalized-comments": "off",
"no-ternary": "off", "no-ternary": "off",
"no-undefined": "off",
"object-curly-spacing": [ "object-curly-spacing": [
"error", "error",
"always", { "arraysInObjects": false, "objectsInObjects": false } "always", { "arraysInObjects": false, "objectsInObjects": false }
], ],
"object-curly-newline": "off", "object-curly-newline": ["error", { "consistent": true }],
"object-property-newline": "off", "object-property-newline": ["error", { "allowMultiplePropertiesPerLine": true }],
"object-shorthand": "off", "object-shorthand": "off",
"one-var": "off",
"padded-blocks": "off", "padded-blocks": "off",
"prefer-const": "off",
"prefer-destructuring": ["error", { "AssignmentExpression": {"array": false}}],
"prefer-template": "off", "prefer-template": "off",
"quotes": ["error", "single", { "allowTemplateLiterals": true }],
"quote-props": "off",
"require-jsdoc": "off", "require-jsdoc": "off",
"sort-imports": "off", "sort-imports": "off",
"sort-keys": "off", "sort-keys": "off",

@ -3,36 +3,39 @@ import * as consoleActions from './console';
const normalizeUrl = (string) => { const normalizeUrl = (string) => {
try { try {
return new URL(string).href return new URL(string).href;
} catch (e) { } catch (e) {
return 'http://' + string; return 'http://' + string;
} }
} };
const openCommand = (url) => { const openCommand = (url) => {
return browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => { return browser.tabs.query({
if (tabs.length > 0) { active: true, currentWindow: true
return browser.tabs.update(tabs[0].id, { url: url }); }).then((gotTabs) => {
if (gotTabs.length > 0) {
return browser.tabs.update(gotTabs[0].id, { url: url });
} }
}); });
} };
const tabopenCommand = (url) => { const tabopenCommand = (url) => {
return browser.tabs.create({ url: url }); return browser.tabs.create({ url: url });
} };
const bufferCommand = (keywords) => { const bufferCommand = (keywords) => {
return browser.tabs.query({ active: true, currentWindow: true }).then((tabss) => { return browser.tabs.query({
if (tabss.length > 0) { active: true, currentWindow: true
}).then((gotTabs) => {
if (gotTabs.length > 0) {
if (isNaN(keywords)) { if (isNaN(keywords)) {
return tabs.selectByKeyword(tabss[0], keywords); return tabs.selectByKeyword(gotTabs[0], keywords);
} else {
let index = parseInt(keywords, 10) - 1;
return tabs.selectAt(index);
} }
let index = parseInt(keywords, 10) - 1;
return tabs.selectAt(index);
} }
}); });
} };
const doCommand = (name, remaining) => { const doCommand = (name, remaining) => {
switch (name) { switch (name) {
@ -46,39 +49,43 @@ const doCommand = (name, remaining) => {
return bufferCommand(remaining); return bufferCommand(remaining);
} }
throw new Error(name + ' command is not defined'); throw new Error(name + ' command is not defined');
} };
const getCompletions = (command, keywords) => { const getCompletions = (command, keywords) => {
switch (command) { switch (command) {
case 'buffer': case 'buffer':
return tabs.getCompletions(keywords).then((tabs) => { return tabs.getCompletions(keywords).then((gotTabs) => {
let items = tabs.map((tab) => { let items = gotTabs.map((tab) => {
return { return {
caption: tab.title, caption: tab.title,
content: tab.title, content: tab.title,
url: tab.url, url: tab.url,
icon: tab.favIconUrl icon: tab.favIconUrl
} };
}); });
return [{ return [
name: "Buffers", {
items: items name: 'Buffers',
}]; items: items
}
];
}); });
} }
return Promise.resolve([]); return Promise.resolve([]);
}; };
export function exec(line) { const exec = (line) => {
let name = line.split(' ')[0]; let name = line.split(' ')[0];
let remaining = line.replace(name + ' ', ''); let remaining = line.replace(name + ' ', '');
return doCommand(name, remaining).then(() => { return doCommand(name, remaining).then(() => {
return consoleActions.hide(); return consoleActions.hide();
}); });
} };
export function complete(line) { const complete = (line) => {
let command = line.split(' ', 1)[0]; let command = line.split(' ', 1)[0];
let keywords = line.replace(command + ' ', ''); let keywords = line.replace(command + ' ', '');
return getCompletions(command, keywords).then(consoleActions.setCompletions); return getCompletions(command, keywords).then(consoleActions.setCompletions);
} };
export { exec, complete };

@ -1,28 +1,30 @@
import actions from '../actions'; import actions from '../actions';
export function showCommand(text) { const showCommand = (text) => {
return { return {
type: actions.CONSOLE_SHOW_COMMAND, type: actions.CONSOLE_SHOW_COMMAND,
text: text text: text
}; };
} };
export function setCompletions(completions) { const setCompletions = (completions) => {
return { return {
type: actions.CONSOLE_SET_COMPLETIONS, type: actions.CONSOLE_SET_COMPLETIONS,
completions: completions completions: completions
}; };
} };
export function showError(text) { const showError = (text) => {
return { return {
type: actions.CONSOLE_SHOW_ERROR, type: actions.CONSOLE_SHOW_ERROR,
text: text text: text
}; };
} };
export function hide() { const hide = () => {
return { return {
type: actions.CONSOLE_HIDE type: actions.CONSOLE_HIDE
}; };
} };
export { showCommand, setCompletions, showError, hide };

@ -1,15 +1,17 @@
import actions from '../actions'; import actions from '../actions';
export function keyPress(code, ctrl) { const keyPress = (code, ctrl) => {
return { return {
type: actions.INPUT_KEY_PRESS, type: actions.INPUT_KEY_PRESS,
code, code,
ctrl ctrl
}; };
} };
export function clearKeys() { const clearKeys = () => {
return { return {
type: actions.INPUT_CLEAR_KEYS type: actions.INPUT_CLEAR_KEYS
} };
} };
export { keyPress, clearKeys };

@ -1,10 +1,10 @@
import operations from '../operations'; import operations from '../operations';
import messages from '../messages'; import messages from '../messages';
import * as consoleActions from './console'; import * as consoleActions from './console';
import * as tabs from '../background/tabs'; import * as tabs from '../background/tabs';
import * as zooms from '../background/zooms'; import * as zooms from '../background/zooms';
export function exec(operation, tab) { const exec = (operation, tab) => {
switch (operation.type) { switch (operation.type) {
case operations.TABS_CLOSE: case operations.TABS_CLOSE:
return tabs.closeTab(tab.id); return tabs.closeTab(tab.id);
@ -28,9 +28,8 @@ export function exec(operation, tab) {
if (operations.alter) { if (operations.alter) {
// alter url // alter url
return consoleActions.showCommand('open ' + tab.url); return consoleActions.showCommand('open ' + tab.url);
} else {
return consoleActions.showCommand('open ');
} }
return consoleActions.showCommand('open ');
case operations.COMMAND_BUFFER: case operations.COMMAND_BUFFER:
return consoleActions.showCommand('buffer '); return consoleActions.showCommand('buffer ');
default: default:
@ -39,5 +38,6 @@ export function exec(operation, tab) {
operation operation
}); });
} }
} };
export { exec };

@ -5,9 +5,10 @@ import * as commandActions from '../actions/command';
import * as consoleActions from '../actions/console'; import * as consoleActions from '../actions/console';
import reducers from '../reducers'; import reducers from '../reducers';
import messages from '../messages'; import messages from '../messages';
import * as store from '../store' import * as store from '../store';
let prevInput = []; let prevInput = [];
const backgroundStore = store.createStore(reducers, (e, sender) => { const backgroundStore = store.createStore(reducers, (e, sender) => {
console.error('Vim-Vixen:', e); console.error('Vim-Vixen:', e);
if (sender) { if (sender) {
@ -15,9 +16,9 @@ const backgroundStore = store.createStore(reducers, (e, sender) => {
} }
}); });
backgroundStore.subscribe((sender) => { backgroundStore.subscribe((sender) => {
let currentInput = backgroundStore.getState().input let currentInput = backgroundStore.getState().input;
if (JSON.stringify(prevInput) === JSON.stringify(currentInput)) { if (JSON.stringify(prevInput) === JSON.stringify(currentInput)) {
return return;
} }
prevInput = currentInput; prevInput = currentInput;
@ -39,13 +40,14 @@ backgroundStore.subscribe((sender) => {
const keyQueueChanged = (state, sender) => { const keyQueueChanged = (state, sender) => {
let prefix = keys.asKeymapChars(state.input.keys); let prefix = keys.asKeymapChars(state.input.keys);
let matched = Object.keys(keys.defaultKeymap).filter((keys) => { let matched = Object.keys(keys.defaultKeymap).filter((keyStr) => {
return keys.startsWith(prefix); return keyStr.startsWith(prefix);
}); });
if (matched.length == 0) { if (matched.length === 0) {
backgroundStore.dispatch(inputActions.clearKeys(), sender); backgroundStore.dispatch(inputActions.clearKeys(), sender);
return Promise.resolve(); return Promise.resolve();
} else if (matched.length > 1 || matched.length === 1 && prefix !== matched[0]) { } else if (matched.length > 1 ||
matched.length === 1 && prefix !== matched[0]) {
return Promise.resolve(); return Promise.resolve();
} }
let action = keys.defaultKeymap[matched]; let action = keys.defaultKeymap[matched];
@ -56,15 +58,19 @@ const keyQueueChanged = (state, sender) => {
const handleMessage = (message, sender) => { const handleMessage = (message, sender) => {
switch (message.type) { switch (message.type) {
case messages.KEYDOWN: case messages.KEYDOWN:
return backgroundStore.dispatch(inputActions.keyPress(message.code, message.ctrl), sender); return backgroundStore.dispatch(
inputActions.keyPress(message.code, message.ctrl), sender);
case messages.CONSOLE_BLURRED: case messages.CONSOLE_BLURRED:
return backgroundStore.dispatch(consoleActions.hide(), sender); return backgroundStore.dispatch(
consoleActions.hide(), sender);
case messages.CONSOLE_ENTERED: case messages.CONSOLE_ENTERED:
return backgroundStore.dispatch(commandActions.exec(message.text), sender); return backgroundStore.dispatch(
commandActions.exec(message.text), sender);
case messages.CONSOLE_CHANGEED: case messages.CONSOLE_CHANGEED:
return backgroundStore.dispatch(commandActions.complete(message.text), sender); return backgroundStore.dispatch(
commandActions.complete(message.text), sender);
} }
} };
browser.runtime.onMessage.addListener((message, sender) => { browser.runtime.onMessage.addListener((message, sender) => {
try { try {

@ -30,28 +30,26 @@ const defaultKeymap = {
'F': { type: operations.FOLLOW_START, newTab: true }, 'F': { type: operations.FOLLOW_START, newTab: true },
'H': { type: operations.HISTORY_PREV }, 'H': { type: operations.HISTORY_PREV },
'L': { type: operations.HISTORY_NEXT }, 'L': { type: operations.HISTORY_NEXT },
} };
const asKeymapChars = (keys) => { const asKeymapChars = (keys) => {
return keys.map((k) => { return keys.map((k) => {
let c = String.fromCharCode(k.code); let c = String.fromCharCode(k.code);
if (k.ctrl) { if (k.ctrl) {
return '<C-' + c.toUpperCase() + '>'; return '<C-' + c.toUpperCase() + '>';
} else {
return c
} }
return c;
}).join(''); }).join('');
} };
const asCaretChars = (keys) => { const asCaretChars = (keys) => {
return keys.map((k) => { return keys.map((k) => {
let c = String.fromCharCode(k.code); let c = String.fromCharCode(k.code);
if (k.ctrl) { if (k.ctrl) {
return '^' + c.toUpperCase(); return '^' + c.toUpperCase();
} else {
return c;
} }
return c;
}).join(''); }).join('');
} };
export { defaultKeymap, asKeymapChars, asCaretChars }; export { defaultKeymap, asKeymapChars, asCaretChars };

@ -12,9 +12,8 @@ const reopenTab = () => {
let session = sessions[0]; let session = sessions[0];
if (session.tab) { if (session.tab) {
return browser.sessions.restore(session.tab.sessionId); return browser.sessions.restore(session.tab.sessionId);
} else {
return browser.sessions.restore(session.window.sessionId);
} }
return browser.sessions.restore(session.window.sessionId);
}); });
}; };
@ -24,20 +23,20 @@ const selectAt = (index) => {
return; return;
} }
if (index < 0 || tabs.length <= index) { if (index < 0 || tabs.length <= index) {
throw new RangeError(`tab ${index} does not exist`) throw new RangeError(`tab ${index} does not exist`);
} }
let id = tabs[index].id; let id = tabs[index].id;
return browser.tabs.update(id, { active: true }) return browser.tabs.update(id, { active: true });
}); });
}; };
const selectByKeyword = (current, keyword) => { const selectByKeyword = (current, keyword) => {
return browser.tabs.query({ currentWindow: true }).then((tabs) => { return browser.tabs.query({ currentWindow: true }).then((tabs) => {
let matched = tabs.filter((t) => { let matched = tabs.filter((t) => {
return t.url.includes(keyword) || t.title.includes(keyword) return t.url.includes(keyword) || t.title.includes(keyword);
}) });
if (matched.length == 0) { if (matched.length === 0) {
throw new RangeError('No matching buffer for ' + keyword); throw new RangeError('No matching buffer for ' + keyword);
} }
for (let tab of matched) { for (let tab of matched) {
@ -47,13 +46,13 @@ const selectByKeyword = (current, keyword) => {
} }
return browser.tabs.update(matched[0].id, { active: true }); return browser.tabs.update(matched[0].id, { active: true });
}); });
} };
const getCompletions = (keyword) => { const getCompletions = (keyword) => {
return browser.tabs.query({ currentWindow: true }).then((tabs) => { return browser.tabs.query({ currentWindow: true }).then((tabs) => {
let matched = tabs.filter((t) => { let matched = tabs.filter((t) => {
return t.url.includes(keyword) || t.title.includes(keyword) return t.url.includes(keyword) || t.title.includes(keyword);
}) });
return matched; return matched;
}); });
}; };
@ -63,9 +62,9 @@ const selectPrevTab = (current, count) => {
if (tabs.length < 2) { if (tabs.length < 2) {
return; return;
} }
let select = (current - count) % tabs.length let select = (current - count) % tabs.length;
let id = tabs[select].id; let id = tabs[select].id;
return browser.tabs.update(id, { active: true }) return browser.tabs.update(id, { active: true });
}); });
}; };
@ -74,9 +73,9 @@ const selectNextTab = (current, count) => {
if (tabs.length < 2) { if (tabs.length < 2) {
return; return;
} }
let select = (current + count + tabs.length) % tabs.length let select = (current + count + tabs.length) % tabs.length;
let id = tabs[select].id; let id = tabs[select].id;
return browser.tabs.update(id, { active: true }) return browser.tabs.update(id, { active: true });
}); });
}; };
@ -87,4 +86,7 @@ const reload = (current, cache) => {
); );
}; };
export { closeTab, reopenTab, selectAt, selectByKeyword, getCompletions, selectPrevTab, selectNextTab, reload }; export {
closeTab, reopenTab, selectAt, selectByKeyword, getCompletions,
selectPrevTab, selectNextTab, reload
};

@ -3,15 +3,16 @@ export default class Completion {
if (typeof completions.length !== 'number') { if (typeof completions.length !== 'number') {
throw new TypeError('completions does not have a length in number'); throw new TypeError('completions does not have a length in number');
} }
this.completions = completions this.completions = completions;
this.index = 0; this.index = 0;
} }
prev() { prev() {
if (this.completions.length === 0) { let length = this.completions.length;
if (length === 0) {
return null; return null;
} }
this.index = (this.index + this.completions.length - 1) % this.completions.length this.index = (this.index + length - 1) % length;
return this.completions[this.index]; return this.completions[this.index];
} }
@ -20,7 +21,7 @@ export default class Completion {
return null; return null;
} }
let item = this.completions[this.index]; let item = this.completions[this.index];
this.index = (this.index + 1) % this.completions.length this.index = (this.index + 1) % this.completions.length;
return item; return item;
} }
} }

@ -3,10 +3,10 @@ import Completion from './completion';
import messages from '../messages'; import messages from '../messages';
// TODO consider object-oriented // TODO consider object-oriented
var prevValue = ""; let prevValue = '';
var completion = null; let completion = null;
var completionOrigin = ""; let completionOrigin = '';
var prevState = {}; let prevState = {};
const handleBlur = () => { const handleBlur = () => {
return browser.runtime.sendMessage({ return browser.runtime.sendMessage({
@ -14,6 +14,20 @@ const handleBlur = () => {
}); });
}; };
const selectCompletion = (target) => {
let container = window.document.querySelector('#vimvixen-console-completion');
Array.prototype.forEach.call(container.children, (ele) => {
if (!ele.classList.contains('vimvixen-console-completion-item')) {
return;
}
if (ele === target) {
ele.classList.add('vimvixen-completion-selected');
} else {
ele.classList.remove('vimvixen-completion-selected');
}
});
};
const completeNext = () => { const completeNext = () => {
if (!completion) { if (!completion) {
return; return;
@ -27,7 +41,7 @@ const completeNext = () => {
input.value = completionOrigin + ' ' + item[0].content; input.value = completionOrigin + ' ' + item[0].content;
selectCompletion(item[1]); selectCompletion(item[1]);
} };
const completePrev = () => { const completePrev = () => {
if (!completion) { if (!completion) {
@ -42,12 +56,12 @@ const completePrev = () => {
input.value = completionOrigin + ' ' + item[0].content; input.value = completionOrigin + ' ' + item[0].content;
selectCompletion(item[1]); selectCompletion(item[1]);
} };
const handleKeydown = (e) => { const handleKeydown = (e) => {
let input = window.document.querySelector('#vimvixen-console-command-input'); let input = window.document.querySelector('#vimvixen-console-command-input');
switch(e.keyCode) { switch (e.keyCode) {
case KeyboardEvent.DOM_VK_ESCAPE: case KeyboardEvent.DOM_VK_ESCAPE:
return input.blur(); return input.blur();
case KeyboardEvent.DOM_VK_RETURN: case KeyboardEvent.DOM_VK_RETURN:
@ -92,17 +106,17 @@ const createCompletionTitle = (text) => {
let li = document.createElement('li'); let li = document.createElement('li');
li.className = 'vimvixen-console-completion-title'; li.className = 'vimvixen-console-completion-title';
li.textContent = text; li.textContent = text;
return li return li;
} };
const createCompletionItem = (icon, caption, url) => { const createCompletionItem = (icon, caption, url) => {
let captionEle = document.createElement('span'); let captionEle = document.createElement('span');
captionEle.className = 'vimvixen-console-completion-item-caption'; captionEle.className = 'vimvixen-console-completion-item-caption';
captionEle.textContent = caption captionEle.textContent = caption;
let urlEle = document.createElement('span'); let urlEle = document.createElement('span');
urlEle.className = 'vimvixen-console-completion-item-url'; urlEle.className = 'vimvixen-console-completion-item-url';
urlEle.textContent = url urlEle.textContent = url;
let li = document.createElement('li'); let li = document.createElement('li');
li.style.backgroundImage = 'url(' + icon + ')'; li.style.backgroundImage = 'url(' + icon + ')';
@ -110,24 +124,11 @@ const createCompletionItem = (icon, caption, url) => {
li.append(captionEle); li.append(captionEle);
li.append(urlEle); li.append(urlEle);
return li; return li;
}
const selectCompletion = (target) => {
let container = window.document.querySelector('#vimvixen-console-completion');
Array.prototype.forEach.call(container.children, (ele) => {
if (!ele.classList.contains('vimvixen-console-completion-item')) {
return;
}
if (ele === target) {
ele.classList.add('vimvixen-completion-selected');
} else {
ele.classList.remove('vimvixen-completion-selected');
}
});
}; };
const updateCompletions = (completions) => { const updateCompletions = (completions) => {
let completionsContainer = window.document.querySelector('#vimvixen-console-completion'); let completionsContainer =
window.document.querySelector('#vimvixen-console-completion');
let input = window.document.querySelector('#vimvixen-console-command-input'); let input = window.document.querySelector('#vimvixen-console-command-input');
completionsContainer.innerHTML = ''; completionsContainer.innerHTML = '';
@ -148,7 +149,7 @@ const updateCompletions = (completions) => {
completion = new Completion(pairs); completion = new Completion(pairs);
completionOrigin = input.value.split(' ')[0]; completionOrigin = input.value.split(' ')[0];
} };
const update = (state) => { const update = (state) => {
let error = window.document.querySelector('#vimvixen-console-error'); let error = window.document.querySelector('#vimvixen-console-error');
@ -163,12 +164,13 @@ const update = (state) => {
input.value = state.commandText; input.value = state.commandText;
input.focus(); input.focus();
} }
if (JSON.stringify(state.completions) !== JSON.stringify(prevState.completions)) { if (JSON.stringify(state.completions) !==
JSON.stringify(prevState.completions)) {
updateCompletions(state.completions); updateCompletions(state.completions);
} }
prevState = state; prevState = state;
} };
browser.runtime.onMessage.addListener((action) => { browser.runtime.onMessage.addListener((action) => {
if (action.type === messages.STATE_UPDATE) { if (action.type === messages.STATE_UPDATE) {

@ -8,11 +8,11 @@ const initialize = (doc) => {
doc.body.append(iframe); doc.body.append(iframe);
return iframe; return iframe;
} };
const blur = (doc) => { const blur = (doc) => {
let iframe = doc.getElementById('vimvixen-console-frame'); let iframe = doc.getElementById('vimvixen-console-frame');
iframe.blur(); iframe.blur();
} };
export { initialize, blur }; export { initialize, blur };

@ -1,7 +1,7 @@
import Hint from './hint'; import Hint from './hint';
import HintKeyProducer from './hint-key-producer'; import HintKeyProducer from './hint-key-producer';
const DEFAULT_HINT_CHARSET = 'abcdefghijklmnopqrstuvwxyz' const DEFAULT_HINT_CHARSET = 'abcdefghijklmnopqrstuvwxyz';
export default class Follow { export default class Follow {
constructor(doc) { constructor(doc) {
@ -22,14 +22,14 @@ export default class Follow {
let producer = new HintKeyProducer(DEFAULT_HINT_CHARSET); let producer = new HintKeyProducer(DEFAULT_HINT_CHARSET);
Array.prototype.forEach.call(elements, (ele) => { Array.prototype.forEach.call(elements, (ele) => {
let keys = producer.produce(); let keys = producer.produce();
let hint = new Hint(ele, keys) let hint = new Hint(ele, keys);
this.hintElements[keys] = hint; this.hintElements[keys] = hint;
}); });
} }
handleKeydown(e) { handleKeydown(e) {
let keyCode = e.keyCode; let { keyCode } = e;
if (keyCode === KeyboardEvent.DOM_VK_ESCAPE) { if (keyCode === KeyboardEvent.DOM_VK_ESCAPE) {
this.remove(); this.remove();
return; return;
@ -56,10 +56,10 @@ export default class Follow {
let hidden = Object.keys(this.hintElements).filter((key) => { let hidden = Object.keys(this.hintElements).filter((key) => {
return !key.startsWith(chars); return !key.startsWith(chars);
}); });
if (shown.length == 0) { if (shown.length === 0) {
this.remove(); this.remove();
return; return;
} else if (shown.length == 1) { } else if (shown.length === 1) {
this.remove(); this.remove();
this.hintElements[chars].activate(); this.hintElements[chars].activate();
} }
@ -74,7 +74,7 @@ export default class Follow {
remove() { remove() {
this.doc.removeEventListener("keydown", this.boundKeydown); this.doc.removeEventListener('keydown', this.boundKeydown);
Object.keys(this.hintElements).forEach((key) => { Object.keys(this.hintElements).forEach((key) => {
this.hintElements[key].remove(); this.hintElements[key].remove();
}); });
@ -87,6 +87,14 @@ export default class Follow {
); );
} }
static isNumericKey(code) {
return KeyboardEvent.DOM_VK_0 <= code && code <= KeyboardEvent.DOM_VK_9;
}
static isAlphabeticKey(code) {
return KeyboardEvent.DOM_VK_A <= code && code <= KeyboardEvent.DOM_VK_Z;
}
static codeChars(codes) { static codeChars(codes) {
const CHARCODE_ZERO = '0'.charCodeAt(0); const CHARCODE_ZERO = '0'.charCodeAt(0);
const CHARCODE_A = 'a'.charCodeAt(0); const CHARCODE_A = 'a'.charCodeAt(0);
@ -94,10 +102,12 @@ export default class Follow {
let chars = ''; let chars = '';
for (let code of codes) { for (let code of codes) {
if (KeyboardEvent.DOM_VK_0 <= code && code <= KeyboardEvent.DOM_VK_9) { if (Follow.isNumericKey(code)) {
chars += String.fromCharCode(code - KeyboardEvent.DOM_VK_0 + CHARCODE_ZERO); chars += String.fromCharCode(
} else if (KeyboardEvent.DOM_VK_A <= code && code <= KeyboardEvent.DOM_VK_Z) { code - KeyboardEvent.DOM_VK_0 + CHARCODE_ZERO);
chars += String.fromCharCode(code - KeyboardEvent.DOM_VK_A + CHARCODE_A); } else if (Follow.isAlphabeticKey(code)) {
chars += String.fromCharCode(
code - KeyboardEvent.DOM_VK_A + CHARCODE_A);
} }
} }
return chars; return chars;
@ -112,7 +122,7 @@ export default class Follow {
} }
static isVisibleElement(element) { static isVisibleElement(element) {
var style = window.getComputedStyle(element); let style = window.getComputedStyle(element);
if (style.display === 'none') { if (style.display === 'none') {
return false; return false;
} else if (style.visibility === 'hidden') { } else if (style.visibility === 'hidden') {

@ -11,19 +11,19 @@ export default class HintKeyProducer {
produce() { produce() {
this.increment(); this.increment();
return this.counter.map((x) => this.charset[x]).join(''); return this.counter.map(x => this.charset[x]).join('');
} }
increment() { increment() {
let max = this.charset.length - 1; let max = this.charset.length - 1;
if (this.counter.every((x) => x == max)) { if (this.counter.every(x => x === max)) {
this.counter = new Array(this.counter.length + 1).fill(0); this.counter = new Array(this.counter.length + 1).fill(0);
return; return;
} }
this.counter.reverse(); this.counter.reverse();
let len = this.charset.length; let len = this.charset.length;
let num = this.counter.reduce((x,y,index) => x + y * (len ** index)) + 1; let num = this.counter.reduce((x, y, index) => x + y * len ** index) + 1;
for (let i = 0; i < this.counter.length; ++i) { for (let i = 0; i < this.counter.length; ++i) {
this.counter[i] = num % len; this.counter[i] = num % len;
num = ~~(num / len); num = ~~(num / len);

@ -8,10 +8,9 @@ export default class Hint {
this.target = target; this.target = target;
let doc = target.ownerDocument let doc = target.ownerDocument;
let { top, left } = target.getBoundingClientRect(); let { top, left } = target.getBoundingClientRect();
let scrollX = window.scrollX; let { scrollX, scrollY } = window;
let scrollY = window.scrollY;
this.element = doc.createElement('span'); this.element = doc.createElement('span');
this.element.className = 'vimvixen-hint'; this.element.className = 'vimvixen-hint';

@ -1,8 +1,8 @@
const prev = (win) => { const prev = (win) => {
win.history.back() win.history.back();
}; };
const next = (win) => { const next = (win) => {
win.history.forward() win.history.forward();
}; };
export { prev, next }; export { prev, next };

@ -4,11 +4,11 @@ import * as scrolls from '../content/scrolls';
import * as histories from '../content/histories'; import * as histories from '../content/histories';
import Follow from '../content/follow'; import Follow from '../content/follow';
import operations from '../operations'; import operations from '../operations';
import messages from '../messages'; import messages from '../messages';
consoleFrames.initialize(window.document); consoleFrames.initialize(window.document);
window.addEventListener("keypress", (e) => { window.addEventListener('keypress', (e) => {
if (e.target instanceof HTMLInputElement) { if (e.target instanceof HTMLInputElement) {
return; return;
} }
@ -40,14 +40,14 @@ const execOperation = (operation) => {
case operations.HISTORY_NEXT: case operations.HISTORY_NEXT:
return histories.next(window); return histories.next(window);
} }
} };
const update = (state) => { const update = (state) => {
if (!state.console.commandShown) { if (!state.console.commandShown) {
window.focus(); window.focus();
consoleFrames.blur(window.document); consoleFrames.blur(window.document);
} }
} };
browser.runtime.onMessage.addListener((action) => { browser.runtime.onMessage.addListener((action) => {
switch (action.type) { switch (action.type) {

@ -37,4 +37,6 @@ const scrollRight = (page) => {
page.scrollTo(x, y); page.scrollTo(x, y);
}; };
export { scrollLines, scrollPages, scrollTop, scrollBottom, scrollLeft, scrollRight } export {
scrollLines, scrollPages, scrollTop, scrollBottom, scrollLeft, scrollRight
};

@ -1,5 +1,5 @@
export default { export default {
// command // Command
COMMAND_OPEN: 'cmd.open', COMMAND_OPEN: 'cmd.open',
COMMAND_TABS_OPEN: 'cmd.tabs.open', COMMAND_TABS_OPEN: 'cmd.tabs.open',
COMMAND_BUFFER: 'cmd.buffer', COMMAND_BUFFER: 'cmd.buffer',
@ -14,7 +14,7 @@ export default {
HISTORY_PREV: 'history.prev', HISTORY_PREV: 'history.prev',
HISTORY_NEXT: 'history.next', HISTORY_NEXT: 'history.next',
// background // Background
TABS_CLOSE: 'tabs.close', TABS_CLOSE: 'tabs.close',
TABS_REOPEN: 'tabs.reopen', TABS_REOPEN: 'tabs.reopen',
TABS_PREV: 'tabs.prev', TABS_PREV: 'tabs.prev',
@ -23,4 +23,4 @@ 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',
} };

@ -12,7 +12,7 @@ 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, commandShown: true,
commandText: action.text, commandText: action.text,
errorShown: false, errorShown: false,
completions: [] completions: []

@ -8,10 +8,12 @@ export default function reducer(state = defaultState, action = {}) {
switch (action.type) { switch (action.type) {
case actions.INPUT_KEY_PRESS: case actions.INPUT_KEY_PRESS:
return Object.assign({}, state, { return Object.assign({}, state, {
keys: state.keys.concat([{ keys: state.keys.concat([
code: action.code, {
ctrl: action.ctrl code: action.code,
}]) ctrl: action.ctrl
}
])
}); });
case actions.INPUT_CLEAR_KEYS: case actions.INPUT_CLEAR_KEYS:
return Object.assign({}, state, { return Object.assign({}, state, {

@ -24,7 +24,7 @@ class Store {
this.catcher(e, sender); this.catcher(e, sender);
} }
} }
return action return action;
} }
getState() { getState() {
@ -46,6 +46,8 @@ class Store {
const empty = () => {}; const empty = () => {};
export function createStore(reducer, catcher = empty) { const createStore = (reducer, catcher = empty) => {
return new Store(reducer, catcher); return new Store(reducer, catcher);
} };
export { createStore };