|
|
@ -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) => { |
|
|
|