use key instead of keyCode in follow

jh-changes
Shin'ya Ueoka 7 years ago
parent ea455059bd
commit 944683a2d8
  1. 64
      src/components/follow.js
  2. 4
      src/reducers/follow.js
  3. 10
      test/components/follow.test.js
  4. 20
      test/reducers/follow.test.js

@ -5,21 +5,6 @@ import HintKeyProducer from 'content/hint-key-producer';
const DEFAULT_HINT_CHARSET = 'abcdefghijklmnopqrstuvwxyz'; const DEFAULT_HINT_CHARSET = 'abcdefghijklmnopqrstuvwxyz';
const availableKey = (keyCode) => {
return (
KeyboardEvent.DOM_VK_0 <= keyCode && keyCode <= KeyboardEvent.DOM_VK_9 ||
KeyboardEvent.DOM_VK_A <= keyCode && keyCode <= KeyboardEvent.DOM_VK_Z
);
};
const isNumericKey = (code) => {
return KeyboardEvent.DOM_VK_0 <= code && code <= KeyboardEvent.DOM_VK_9;
};
const isAlphabeticKey = (code) => {
return KeyboardEvent.DOM_VK_A <= code && code <= KeyboardEvent.DOM_VK_Z;
};
const inWindow = (window, element) => { const inWindow = (window, element) => {
let { let {
top, left, bottom, right top, left, bottom, right
@ -49,8 +34,7 @@ export default class FollowComponent {
this.create(); this.create();
} else if (prevState.enabled && !this.state.enabled) { } else if (prevState.enabled && !this.state.enabled) {
this.remove(); this.remove();
} else if (JSON.stringify(prevState.keys) !== } else if (prevState.keys !== this.state.keys) {
JSON.stringify(this.state.keys)) {
this.updateHints(); this.updateHints();
} }
} }
@ -60,23 +44,21 @@ export default class FollowComponent {
return; return;
} }
let { keyCode } = e; let { key } = e;
switch (keyCode) { switch (key) {
case KeyboardEvent.DOM_VK_ENTER: case 'Enter':
case KeyboardEvent.DOM_VK_RETURN: this.activate(this.hintElements[this.state.keys].target);
this.activate(this.hintElements[
FollowComponent.codeChars(this.state.keys)].target);
return; return;
case KeyboardEvent.DOM_VK_ESCAPE: case 'Escape':
this.store.dispatch(followActions.disable()); this.store.dispatch(followActions.disable());
return; return;
case KeyboardEvent.DOM_VK_BACK_SPACE: case 'Backspace':
case KeyboardEvent.DOM_VK_DELETE: case 'Delete':
this.store.dispatch(followActions.backspace()); this.store.dispatch(followActions.backspace());
break; break;
default: default:
if (availableKey(keyCode)) { if (DEFAULT_HINT_CHARSET.includes(key)) {
this.store.dispatch(followActions.keyPress(keyCode)); this.store.dispatch(followActions.keyPress(key));
} }
break; break;
} }
@ -86,18 +68,18 @@ export default class FollowComponent {
} }
updateHints() { updateHints() {
let chars = FollowComponent.codeChars(this.state.keys); let keys = this.state.keys;
let shown = Object.keys(this.hintElements).filter((key) => { let shown = Object.keys(this.hintElements).filter((key) => {
return key.startsWith(chars); return key.startsWith(keys);
}); });
let hidden = Object.keys(this.hintElements).filter((key) => { let hidden = Object.keys(this.hintElements).filter((key) => {
return !key.startsWith(chars); return !key.startsWith(keys);
}); });
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.activate(this.hintElements[chars].target); this.activate(this.hintElements[keys].target);
this.remove(); this.remove();
} }
@ -177,24 +159,6 @@ export default class FollowComponent {
}); });
} }
static codeChars(codes) {
const CHARCODE_ZERO = '0'.charCodeAt(0);
const CHARCODE_A = 'a'.charCodeAt(0);
let chars = '';
for (let code of codes) {
if (isNumericKey(code)) {
chars += String.fromCharCode(
code - KeyboardEvent.DOM_VK_0 + CHARCODE_ZERO);
} else if (isAlphabeticKey(code)) {
chars += String.fromCharCode(
code - KeyboardEvent.DOM_VK_A + CHARCODE_A);
}
}
return chars;
}
static getTargetElements(doc) { static getTargetElements(doc) {
let all = doc.querySelectorAll('a,button,input,textarea'); let all = doc.querySelectorAll('a,button,input,textarea');
let filtered = Array.prototype.filter.call(all, (element) => { let filtered = Array.prototype.filter.call(all, (element) => {

@ -3,7 +3,7 @@ import actions from 'actions';
const defaultState = { const defaultState = {
enabled: false, enabled: false,
newTab: false, newTab: false,
keys: [], keys: '',
}; };
export default function reducer(state = defaultState, action = {}) { export default function reducer(state = defaultState, action = {}) {
@ -19,7 +19,7 @@ export default function reducer(state = defaultState, action = {}) {
}); });
case actions.FOLLOW_KEY_PRESS: case actions.FOLLOW_KEY_PRESS:
return Object.assign({}, state, { return Object.assign({}, state, {
keys: state.keys.concat([action.key]), keys: state.keys + action.key,
}); });
case actions.FOLLOW_BACKSPACE: case actions.FOLLOW_BACKSPACE:
return Object.assign({}, state, { return Object.assign({}, state, {

@ -2,16 +2,6 @@ import { expect } from "chai";
import FollowComponent from 'components/follow'; import FollowComponent from 'components/follow';
describe('FollowComponent', () => { describe('FollowComponent', () => {
describe('#codeChars', () => {
it('returns a string for key codes', () => {
let chars = [
KeyboardEvent.DOM_VK_0, KeyboardEvent.DOM_VK_1,
KeyboardEvent.DOM_VK_A, KeyboardEvent.DOM_VK_B];
expect(FollowComponent.codeChars(chars)).to.equal('01ab');
expect(FollowComponent.codeChars([])).to.be.equal('');
});
});
describe('#getTargetElements', () => { describe('#getTargetElements', () => {
beforeEach(() => { beforeEach(() => {
document.body.innerHTML = __html__['test/components/follow.html']; document.body.innerHTML = __html__['test/components/follow.html'];

@ -7,7 +7,7 @@ describe('follow reducer', () => {
let state = followReducer(undefined, {}); let state = followReducer(undefined, {});
expect(state).to.have.property('enabled', false); expect(state).to.have.property('enabled', false);
expect(state).to.have.property('newTab'); expect(state).to.have.property('newTab');
expect(state).to.have.deep.property('keys', []); expect(state).to.have.deep.property('keys', '');
}); });
it ('returns next state for FOLLOW_ENABLE', () => { it ('returns next state for FOLLOW_ENABLE', () => {
@ -24,24 +24,24 @@ describe('follow reducer', () => {
}); });
it ('returns next state for FOLLOW_KEY_PRESS', () => { it ('returns next state for FOLLOW_KEY_PRESS', () => {
let action = { type: actions.FOLLOW_KEY_PRESS, key: 100}; let action = { type: actions.FOLLOW_KEY_PRESS, key: 'a'};
let state = followReducer({ keys: [] }, action); let state = followReducer({ keys: '' }, action);
expect(state).to.have.deep.property('keys', [100]); expect(state).to.have.deep.property('keys', 'a');
action = { type: actions.FOLLOW_KEY_PRESS, key: 200}; action = { type: actions.FOLLOW_KEY_PRESS, key: 'b'};
state = followReducer(state, action); state = followReducer(state, action);
expect(state).to.have.deep.property('keys', [100, 200]); expect(state).to.have.deep.property('keys', 'ab');
}); });
it ('returns next state for FOLLOW_BACKSPACE', () => { it ('returns next state for FOLLOW_BACKSPACE', () => {
let action = { type: actions.FOLLOW_BACKSPACE }; let action = { type: actions.FOLLOW_BACKSPACE };
let state = followReducer({ keys: [100, 200] }, action); let state = followReducer({ keys: 'ab' }, action);
expect(state).to.have.deep.property('keys', [100]); expect(state).to.have.deep.property('keys', 'a');
state = followReducer(state, action); state = followReducer(state, action);
expect(state).to.have.deep.property('keys', []); expect(state).to.have.deep.property('keys', '');
state = followReducer(state, action); state = followReducer(state, action);
expect(state).to.have.deep.property('keys', []); expect(state).to.have.deep.property('keys', '');
}); });
}); });