more strict lint
This commit is contained in:
parent
c5529958d5
commit
9ae814dfe4
21 changed files with 211 additions and 157 deletions
33
.eslintrc
33
.eslintrc
|
@ -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 };
|
||||||
|
|
Reference in a new issue