add follow fot a tags

jh-changes
Shin'ya Ueoka 7 years ago
parent 99c1b83133
commit 355da18d3d
  1. 2
      src/background/key-queue.js
  2. 110
      src/content/follow.js
  3. 4
      src/content/index.js
  4. 4
      src/shared/actions.js

@ -13,6 +13,8 @@ const DEFAULT_KEYMAP = [
{ keys: [{ code: KeyboardEvent.DOM_VK_U }], action: [ actions.TABS_REOPEN]}, { keys: [{ code: KeyboardEvent.DOM_VK_U }], action: [ actions.TABS_REOPEN]},
{ keys: [{ code: KeyboardEvent.DOM_VK_H }], action: [ actions.TABS_PREV, 1 ]}, { keys: [{ code: KeyboardEvent.DOM_VK_H }], action: [ actions.TABS_PREV, 1 ]},
{ keys: [{ code: KeyboardEvent.DOM_VK_L }], action: [ actions.TABS_NEXT, 1 ]}, { keys: [{ code: KeyboardEvent.DOM_VK_L }], action: [ actions.TABS_NEXT, 1 ]},
{ keys: [{ code: KeyboardEvent.DOM_VK_F }], action: [ actions.FOLLOW_START, false ]},
{ keys: [{ code: KeyboardEvent.DOM_VK_F, shift: true }], action: [ actions.FOLLOW_START, true ]},
] ]
export default class KeyQueue { export default class KeyQueue {

@ -0,0 +1,110 @@
import Hint from './hint';
import HintKeyProducer from './hint-key-producer';
const DEFAULT_HINT_CHARSET = 'abcdefghijklmnopqrstuvwxyz'
export default class Follow {
constructor(doc) {
this.doc = doc;
this.hintElements = {};
this.keys = [];
// TODO activate input elements and push button elements
let links = Follow.getTargetElements(doc);
this.addHints(links);
this.boundKeydown = this.handleKeydown.bind(this);
doc.addEventListener('keydown', this.boundKeydown);
}
addHints(elements) {
let producer = new HintKeyProducer(DEFAULT_HINT_CHARSET);
Array.prototype.forEach.call(elements, (ele) => {
let keys = producer.produce();
let hint = new Hint(ele, keys)
this.hintElements[keys] = hint;
});
}
handleKeydown(e) {
let keyCode = e.keyCode;
if (keyCode === KeyboardEvent.DOM_VK_ESCAPE) {
this.remove();
return;
} else if (keyCode === KeyboardEvent.DOM_VK_ENTER ||
keyCode === KeyboardEvent.DOM_VK_RETURN) {
this.openUrl(this.keys);
return;
} else if (Follow.availableKey(keyCode)) {
this.keys.push(keyCode);
} else if (keyCode === KeyboardEvent.DOM_VK_BACK_SPACE ||
keyCode === KeyboardEvent.DOM_VK_DELETE) {
this.keys.pop();
}
let keysAsString = Follow.codeChars(this.keys);
let shown = Object.keys(this.hintElements).filter((key) => {
return key.startsWith(keysAsString);
});
let hidden = Object.keys(this.hintElements).filter((key) => {
return !key.startsWith(keysAsString);
});
if (shown.length == 0) {
this.remove();
return;
} else if (shown.length == 1) {
this.openUrl(this.keys);
return;
}
shown.forEach((key) => {
this.hintElements[key].show();
});
hidden.forEach((key) => {
this.hintElements[key].hide();
});
}
remove() {
this.doc.removeEventListener("keydown", this.boundKeydown);
Object.keys(this.hintElements).forEach((key) => {
this.hintElements[key].remove();
});
}
openUrl(keys) {
let chars = Follow.codeChars(keys);
this.hintElements[chars].activate();
}
static availableKey(keyCode) {
return (
KeyboardEvent.DOM_VK_0 <= keyCode && keyCode <= KeyboardEvent.DOM_VK_9 ||
KeyboardEvent.DOM_VK_A <= keyCode && keyCode <= KeyboardEvent.DOM_VK_Z
);
}
static codeChars(codes) {
const CHARCODE_ZERO = '0'.charCodeAt(0);
const CHARCODE_A = 'a'.charCodeAt(0);
let chars = '';
for (let code of codes) {
if (KeyboardEvent.DOM_VK_0 <= code && code <= KeyboardEvent.DOM_VK_9) {
chars += String.fromCharCode(code - KeyboardEvent.DOM_VK_0 + CHARCODE_ZERO);
} else if (KeyboardEvent.DOM_VK_A <= code && code <= KeyboardEvent.DOM_VK_Z) {
chars += String.fromCharCode(code - KeyboardEvent.DOM_VK_A + CHARCODE_A);
}
}
return chars;
}
static getTargetElements(doc) {
return doc.querySelectorAll('a')
}
}

@ -1,5 +1,6 @@
import * as scrolls from './scrolls'; import * as scrolls from './scrolls';
import FooterLine from './footer-line'; import FooterLine from './footer-line';
import Follow from './follow';
import * as actions from '../shared/actions'; import * as actions from '../shared/actions';
var footer = null; var footer = null;
@ -52,6 +53,9 @@ const invokeEvent = (action) => {
case actions.SCROLL_BOTTOM: case actions.SCROLL_BOTTOM:
scrolls.scrollBottom(window, action[1]); scrolls.scrollBottom(window, action[1]);
break; break;
case actions.FOLLOW_START:
new Follow(window.document, action[1] || false);
break;
} }
} }

@ -8,6 +8,7 @@ export const SCROLL_UP = 'scroll.up';
export const SCROLL_DOWN = 'scroll.down'; export const SCROLL_DOWN = 'scroll.down';
export const SCROLL_TOP = 'scroll.top'; export const SCROLL_TOP = 'scroll.top';
export const SCROLL_BOTTOM = 'scroll.bottom'; export const SCROLL_BOTTOM = 'scroll.bottom';
export const FOLLOW_START = 'follow.start';
const BACKGROUND_ACTION_SET = new Set([ const BACKGROUND_ACTION_SET = new Set([
TABS_CLOSE, TABS_CLOSE,
@ -22,7 +23,8 @@ const CONTENT_ACTION_SET = new Set([
SCROLL_UP, SCROLL_UP,
SCROLL_DOWN, SCROLL_DOWN,
SCROLL_TOP, SCROLL_TOP,
SCROLL_BOTTOM SCROLL_BOTTOM,
FOLLOW_START
]); ]);
export const isBackgroundAction = (action) => { export const isBackgroundAction = (action) => {