diff --git a/src/background/infrastructures/content-message-listener.js b/src/background/infrastructures/content-message-listener.js index beb52fe..aae07c0 100644 --- a/src/background/infrastructures/content-message-listener.js +++ b/src/background/infrastructures/content-message-listener.js @@ -16,6 +16,8 @@ export default class ContentMessageListener { this.linkController = new LinkController(); this.backgroundOperationController = new OperationController(); this.markController = new MarkController(); + + this.consolePorts = {}; } run() { @@ -38,6 +40,7 @@ export default class ContentMessageListener { }); } }); + browser.runtime.onConnect.addListener(this.onConnected.bind(this)); } onMessage(message, sender) { @@ -65,6 +68,8 @@ export default class ContentMessageListener { return this.onMarkSetGlobal(message.key, message.x, message.y); case messages.MARK_JUMP_GLOBAL: return this.onMarkJumpGlobal(message.key); + case messages.CONSOLE_FRAME_MESSAGE: + return this.onConsoleFrameMessage(sender.tab.id, message.message); } } @@ -116,4 +121,21 @@ export default class ContentMessageListener { onMarkJumpGlobal(key) { return this.markController.jumpGlobal(key); } + + onConsoleFrameMessage(tabId, message) { + let port = this.consolePorts[tabId]; + if (!port) { + return; + } + port.postMessage(message); + } + + onConnected(port) { + if (port.name !== 'vimvixen-console') { + return; + } + + let id = port.sender.tab.id; + this.consolePorts[id] = port; + } } diff --git a/src/console/components/completion.js b/src/console/components/completion.js deleted file mode 100644 index a49a221..0000000 --- a/src/console/components/completion.js +++ /dev/null @@ -1,65 +0,0 @@ -export default class Completion { - constructor(wrapper, store) { - this.wrapper = wrapper; - this.store = store; - this.prevState = {}; - - store.subscribe(() => { - this.update(); - }); - } - - update() { - let state = this.store.getState(); - if (JSON.stringify(this.prevState) === JSON.stringify(state)) { - return; - } - - this.wrapper.innerHTML = ''; - - for (let i = 0; i < state.completions.length; ++i) { - let group = state.completions[i]; - let title = this.createCompletionTitle(group.name); - this.wrapper.append(title); - - for (let j = 0; j < group.items.length; ++j) { - let item = group.items[j]; - let li = this.createCompletionItem(item.icon, item.caption, item.url); - this.wrapper.append(li); - - if (i === state.groupSelection && j === state.itemSelection) { - li.classList.add('vimvixen-completion-selected'); - } - } - } - - this.prevState = state; - } - - createCompletionTitle(text) { - let doc = this.wrapper.ownerDocument; - let li = doc.createElement('li'); - li.className = 'vimvixen-console-completion-title'; - li.textContent = text; - return li; - } - - createCompletionItem(icon, caption, url) { - let doc = this.wrapper.ownerDocument; - - let captionEle = doc.createElement('span'); - captionEle.className = 'vimvixen-console-completion-item-caption'; - captionEle.textContent = caption; - - let urlEle = doc.createElement('span'); - urlEle.className = 'vimvixen-console-completion-item-url'; - urlEle.textContent = url; - - let li = doc.createElement('li'); - li.style.backgroundImage = 'url(' + icon + ')'; - li.className = 'vimvixen-console-completion-item'; - li.append(captionEle); - li.append(urlEle); - return li; - } -} diff --git a/src/console/components/console.js b/src/console/components/console.js deleted file mode 100644 index 4fc8a53..0000000 --- a/src/console/components/console.js +++ /dev/null @@ -1,175 +0,0 @@ -import * as consoleActions from 'console/actions/console'; - -const inputShownMode = (state) => { - return ['command', 'find'].includes(state.mode); -}; - -export default class ConsoleComponent { - constructor(wrapper, store) { - this.wrapper = wrapper; - this.store = store; - this.prevMode = ''; - - let doc = this.wrapper.ownerDocument; - let input = doc.querySelector('#vimvixen-console-command-input'); - - input.addEventListener('blur', this.onBlur.bind(this)); - input.addEventListener('keydown', this.onKeyDown.bind(this)); - input.addEventListener('input', this.onInput.bind(this)); - - store.subscribe(() => { - this.update(); - }); - this.update(); - } - - onBlur() { - let state = this.store.getState(); - if (state.mode === 'command' || state.mode === 'find') { - return this.store.dispatch(consoleActions.hideCommand()); - } - } - - doEnter(e) { - e.stopPropagation(); - e.preventDefault(); - - let state = this.store.getState(); - let value = e.target.value; - if (state.mode === 'command') { - return this.store.dispatch(consoleActions.enterCommand(value)); - } else if (state.mode === 'find') { - return this.store.dispatch(consoleActions.enterFind(value)); - } - } - - selectNext(e) { - this.store.dispatch(consoleActions.completionNext()); - e.stopPropagation(); - e.preventDefault(); - } - - selectPrev(e) { - this.store.dispatch(consoleActions.completionPrev()); - e.stopPropagation(); - e.preventDefault(); - } - - onKeyDown(e) { - if (e.keyCode === KeyboardEvent.DOM_VK_ESCAPE && e.ctrlKey) { - this.store.dispatch(consoleActions.hideCommand()); - } - switch (e.keyCode) { - case KeyboardEvent.DOM_VK_ESCAPE: - return this.store.dispatch(consoleActions.hideCommand()); - case KeyboardEvent.DOM_VK_RETURN: - return this.doEnter(e); - case KeyboardEvent.DOM_VK_TAB: - if (e.shiftKey) { - this.store.dispatch(consoleActions.completionPrev()); - } else { - this.store.dispatch(consoleActions.completionNext()); - } - e.stopPropagation(); - e.preventDefault(); - break; - case KeyboardEvent.DOM_VK_OPEN_BRACKET: - if (e.ctrlKey) { - return this.store.dispatch(consoleActions.hideCommand()); - } - break; - case KeyboardEvent.DOM_VK_M: - if (e.ctrlKey) { - return this.doEnter(e); - } - break; - case KeyboardEvent.DOM_VK_N: - if (e.ctrlKey) { - this.selectNext(e); - } - break; - case KeyboardEvent.DOM_VK_P: - if (e.ctrlKey) { - this.selectPrev(e); - } - break; - } - } - - onInput(e) { - let state = this.store.getState(); - let text = e.target.value; - this.store.dispatch(consoleActions.setConsoleText(text)); - if (state.mode === 'command') { - this.store.dispatch(consoleActions.getCompletions(text)); - } - } - - onInputShown(state) { - let doc = this.wrapper.ownerDocument; - let input = doc.querySelector('#vimvixen-console-command-input'); - - input.focus(); - window.focus(); - - if (state.mode === 'command') { - let text = state.consoleText; - input.value = text; - this.store.dispatch(consoleActions.getCompletions(text)); - } - } - - update() { - let state = this.store.getState(); - - this.updateMessage(state); - this.updateCommand(state); - this.updatePrompt(state); - - if (this.prevMode !== state.mode && inputShownMode(state)) { - this.onInputShown(state); - } - this.prevMode = state.mode; - } - - updateMessage(state) { - let doc = this.wrapper.ownerDocument; - let box = doc.querySelector('.vimvixen-console-message'); - let display = 'none'; - let classList = ['vimvixen-console-message']; - - if (state.mode === 'error' || state.mode === 'info') { - display = 'block'; - classList.push('vimvixen-console-' + state.mode); - } - - box.className = classList.join(' '); - box.style.display = display; - box.textContent = state.messageText; - } - - updateCommand(state) { - let doc = this.wrapper.ownerDocument; - let command = doc.querySelector('#vimvixen-console-command'); - let input = doc.querySelector('#vimvixen-console-command-input'); - - let display = 'none'; - if (inputShownMode(state)) { - display = 'block'; - } - - command.style.display = display; - input.value = state.consoleText; - } - - updatePrompt(state) { - let classList = ['vimvixen-console-command-prompt']; - if (inputShownMode(state)) { - classList.push('prompt-' + state.mode); - } - - let doc = this.wrapper.ownerDocument; - let ele = doc.querySelector('.vimvixen-console-command-prompt'); - ele.className = classList.join(' '); - } -} diff --git a/src/console/components/console.jsx b/src/console/components/console.jsx new file mode 100644 index 0000000..23c93e3 --- /dev/null +++ b/src/console/components/console.jsx @@ -0,0 +1,133 @@ +import './console.scss'; +import { connect } from 'preact-redux'; +import { Component, h } from 'preact'; +import Input from './console/input'; +import Completion from './console/completion'; +import Message from './console/message'; +import * as consoleActions from '../../console/actions/console'; + +class ConsoleComponent extends Component { + onBlur() { + if (this.props.mode === 'command' || this.props.mode === 'find') { + return this.context.store.dispatch(consoleActions.hideCommand()); + } + } + + doEnter(e) { + e.stopPropagation(); + e.preventDefault(); + + let value = e.target.value; + if (this.props.mode === 'command') { + return this.context.store.dispatch(consoleActions.enterCommand(value)); + } else if (this.props.mode === 'find') { + return this.context.store.dispatch(consoleActions.enterFind(value)); + } + } + + selectNext(e) { + this.context.store.dispatch(consoleActions.completionNext()); + e.stopPropagation(); + e.preventDefault(); + } + + selectPrev(e) { + this.context.store.dispatch(consoleActions.completionPrev()); + e.stopPropagation(); + e.preventDefault(); + } + + onKeyDown(e) { + if (e.keyCode === KeyboardEvent.DOM_VK_ESCAPE && e.ctrlKey) { + this.context.store.dispatch(consoleActions.hideCommand()); + } + switch (e.keyCode) { + case KeyboardEvent.DOM_VK_ESCAPE: + return this.context.store.dispatch(consoleActions.hideCommand()); + case KeyboardEvent.DOM_VK_RETURN: + return this.doEnter(e); + case KeyboardEvent.DOM_VK_TAB: + if (e.shiftKey) { + this.context.store.dispatch(consoleActions.completionPrev()); + } else { + this.context.store.dispatch(consoleActions.completionNext()); + } + e.stopPropagation(); + e.preventDefault(); + break; + case KeyboardEvent.DOM_VK_OPEN_BRACKET: + if (e.ctrlKey) { + return this.context.store.dispatch(consoleActions.hideCommand()); + } + break; + case KeyboardEvent.DOM_VK_M: + if (e.ctrlKey) { + return this.doEnter(e); + } + break; + case KeyboardEvent.DOM_VK_N: + if (e.ctrlKey) { + this.selectNext(e); + } + break; + case KeyboardEvent.DOM_VK_P: + if (e.ctrlKey) { + this.selectPrev(e); + } + break; + } + } + + onInput(e) { + let text = e.target.value; + this.context.store.dispatch(consoleActions.setConsoleText(text)); + if (this.props.mode === 'command') { + this.context.store.dispatch(consoleActions.getCompletions(text)); + } + } + + + componentDidUpdate(prevProps) { + if (!this.input) { + return; + } + if (prevProps.mode !== 'command' && this.props.mode === 'command') { + this.context.store.dispatch( + consoleActions.getCompletions(this.props.consoleText)); + this.focus(); + } else if (prevProps.mode !== 'find' && this.props.mode === 'find') { + this.focus(); + } + } + + render() { + switch (this.props.mode) { + case 'command': + case 'find': + return
+ { props.children } +
+ ); + case 'info': + return ( ++ { props.children } +
+ ); + } +} diff --git a/src/console/index.html b/src/console/index.html index e049b5e..5c1e99c 100644 --- a/src/console/index.html +++ b/src/console/index.html @@ -5,15 +5,5 @@