parent
4c9d0433a6
commit
ac5354020e
11 changed files with 234 additions and 95 deletions
@ -0,0 +1,115 @@ |
||||
import * as followActions from 'content/actions/follow'; |
||||
import messages from 'shared/messages'; |
||||
import HintKeyProducer from 'content/hint-key-producer'; |
||||
|
||||
const DEFAULT_HINT_CHARSET = 'abcdefghijklmnopqrstuvwxyz'; |
||||
|
||||
const broadcastMessage = (win, message) => { |
||||
let json = JSON.stringify(message); |
||||
let frames = [window.self].concat(Array.from(window.frames)); |
||||
frames.forEach(frame => frame.postMessage(json, '*')); |
||||
}; |
||||
|
||||
export default class FollowController { |
||||
constructor(win, store) { |
||||
this.win = win; |
||||
this.store = store; |
||||
this.state = {}; |
||||
this.keys = []; |
||||
this.producer = null; |
||||
} |
||||
|
||||
onMessage(message, sender) { |
||||
switch (message.type) { |
||||
case messages.FOLLOW_START: |
||||
return this.store.dispatch(followActions.enable(message.newTab)); |
||||
case messages.FOLLOW_RESPONSE_COUNT_TARGETS: |
||||
return this.create(message.count, sender); |
||||
case messages.FOLLOW_KEY_PRESS: |
||||
return this.keyPress(message.key); |
||||
} |
||||
} |
||||
|
||||
update() { |
||||
let prevState = this.state; |
||||
this.state = this.store.getState().follow; |
||||
|
||||
if (!prevState.enabled && this.state.enabled) { |
||||
this.count(); |
||||
} else if (prevState.enabled && !this.state.enabled) { |
||||
this.remove(); |
||||
} else if (prevState.keys !== this.state.keys) { |
||||
this.updateHints(); |
||||
} |
||||
} |
||||
|
||||
updateHints() { |
||||
let shown = this.keys.filter(key => key.startsWith(this.state.keys)); |
||||
if (shown.length === 1) { |
||||
this.activate(); |
||||
this.store.dispatch(followActions.disable()); |
||||
} |
||||
|
||||
broadcastMessage(this.win, { |
||||
type: messages.FOLLOW_SHOW_HINTS, |
||||
keys: this.state.keys, |
||||
}); |
||||
} |
||||
|
||||
activate() { |
||||
broadcastMessage(this.win, { |
||||
type: messages.FOLLOW_ACTIVATE, |
||||
keys: this.state.keys, |
||||
}); |
||||
} |
||||
|
||||
keyPress(key) { |
||||
switch (key) { |
||||
case 'Enter': |
||||
this.activate(); |
||||
this.store.dispatch(followActions.disable()); |
||||
break; |
||||
case 'Escape': |
||||
this.store.dispatch(followActions.disable()); |
||||
break; |
||||
case 'Backspace': |
||||
case 'Delete': |
||||
this.store.dispatch(followActions.backspace()); |
||||
break; |
||||
default: |
||||
if (DEFAULT_HINT_CHARSET.includes(key)) { |
||||
this.store.dispatch(followActions.keyPress(key)); |
||||
} |
||||
break; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
count() { |
||||
this.producer = new HintKeyProducer(DEFAULT_HINT_CHARSET); |
||||
broadcastMessage(this.win, { |
||||
type: messages.FOLLOW_REQUEST_COUNT_TARGETS, |
||||
}); |
||||
} |
||||
|
||||
create(count, sender) { |
||||
let produced = []; |
||||
for (let i = 0; i < count; ++i) { |
||||
produced.push(this.producer.produce()); |
||||
} |
||||
this.keys = this.keys.concat(produced); |
||||
|
||||
sender.postMessage(JSON.stringify({ |
||||
type: messages.FOLLOW_CREATE_HINTS, |
||||
keysArray: produced, |
||||
newTab: this.state.newTab, |
||||
}), '*'); |
||||
} |
||||
|
||||
remove() { |
||||
this.keys = []; |
||||
broadcastMessage(this.win, { |
||||
type: messages.FOLLOW_REMOVE_HINTS, |
||||
}); |
||||
} |
||||
} |
Reference in new issue