aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/background/infrastructures/content-message-listener.js22
-rw-r--r--src/console/components/completion.js65
-rw-r--r--src/console/components/console.js175
-rw-r--r--src/console/components/console.jsx133
-rw-r--r--src/console/components/console.scss (renamed from src/console/site.scss)10
-rw-r--r--src/console/components/console/completion.jsx56
-rw-r--r--src/console/components/console/input.jsx32
-rw-r--r--src/console/components/console/message.jsx18
-rw-r--r--src/console/index.html12
-rw-r--r--src/console/index.jsx (renamed from src/console/index.js)21
-rw-r--r--src/content/actions/find.js25
-rw-r--r--src/content/actions/operation.js2
-rw-r--r--src/content/components/common/mark.js4
-rw-r--r--src/content/console-frames.js27
-rw-r--r--src/shared/messages.js3
15 files changed, 298 insertions, 307 deletions
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 <div className='vimvixen-console-command-wrapper'>
+ <Completion />
+ <Input
+ ref={(c) => { this.input = c; }}
+ mode={this.props.mode}
+ onBlur={this.onBlur.bind(this)}
+ onKeyDown={this.onKeyDown.bind(this)}
+ onInput={this.onInput.bind(this)}
+ value={this.props.consoleText}
+ />
+ </div>;
+ case 'info':
+ case 'error':
+ return <Message mode={ this.props.mode } >
+ { this.props.messageText }
+ </Message>;
+ }
+ }
+
+ focus() {
+ window.focus();
+ this.input.focus();
+ }
+}
+
+const mapStateToProps = state => state;
+export default connect(mapStateToProps)(ConsoleComponent);
diff --git a/src/console/site.scss b/src/console/components/console.scss
index b9b1016..c0b9b12 100644
--- a/src/console/site.scss
+++ b/src/console/components/console.scss
@@ -89,18 +89,10 @@ body {
background-color: white;
display: flex;
- &-prompt:before {
+ &-prompt {
@include consoole-font;
}
- &-prompt.prompt-command:before {
- content: ':';
- }
-
- &-prompt.prompt-find:before {
- content: '/';
- }
-
&-input {
border: none;
flex-grow: 1;
diff --git a/src/console/components/console/completion.jsx b/src/console/components/console/completion.jsx
new file mode 100644
index 0000000..c60543b
--- /dev/null
+++ b/src/console/components/console/completion.jsx
@@ -0,0 +1,56 @@
+import { Component, h } from 'preact';
+import { connect } from 'preact-redux';
+
+const CompletionTitle = (props) => {
+ return <li className='vimvixen-console-completion-title' >{props.title}</li>;
+};
+
+const CompletionItem = (props) => {
+ let className = 'vimvixen-console-completion-item';
+ if (props.highlight) {
+ className += ' vimvixen-completion-selected';
+ }
+ return <li
+ className={className}
+ style={{ backgroundImage: 'url(' + props.icon + ')' }}
+ >
+ <span
+ className='vimvixen-console-completion-item-caption'
+ >{props.caption}</span>
+ <span
+ className='vimvixen-console-completion-item-url'
+ >{props.url}</span>
+ </li>;
+};
+
+
+class CompletionComponent extends Component {
+ render() {
+ let eles = [];
+ for (let i = 0; i < this.props.completions.length; ++i) {
+ let group = this.props.completions[i];
+ eles.push(<CompletionTitle title={ group.name }/>);
+ for (let j = 0; j < group.items.length; ++j) {
+ let item = group.items[j];
+ let selected =
+ i === this.props.groupSelection &&
+ j === this.props.itemSelection;
+ eles.push(<CompletionItem
+ icon={item.icon}
+ caption={item.caption}
+ url={item.url}
+ highlight={selected}
+ / >);
+ }
+ }
+
+ return (
+ <ul className='vimvixen-console-completion'>
+ { eles }
+ </ul>
+ );
+ }
+}
+
+const mapStateToProps = state => state;
+export default connect(mapStateToProps)(CompletionComponent);
diff --git a/src/console/components/console/input.jsx b/src/console/components/console/input.jsx
new file mode 100644
index 0000000..d59e6e7
--- /dev/null
+++ b/src/console/components/console/input.jsx
@@ -0,0 +1,32 @@
+import { Component, h } from 'preact';
+
+export default class InputComponent extends Component {
+ focus() {
+ this.input.focus();
+ }
+
+ render() {
+ let prompt = '';
+ if (this.props.mode === 'command') {
+ prompt = ':';
+ } else if (this.props.mode === 'find') {
+ prompt = '/';
+ }
+
+ return (
+ <div className='vimvixen-console-command'>
+ <i className='vimvixen-console-command-prompt'>
+ { prompt }
+ </i>
+ <input
+ className='vimvixen-console-command-input'
+ ref={(c) => { this.input = c; }}
+ onBlur={this.props.onBlur}
+ onKeyDown={this.props.onKeyDown}
+ onInput={this.props.onInput}
+ value={this.props.value}
+ />
+ </div>
+ );
+ }
+}
diff --git a/src/console/components/console/message.jsx b/src/console/components/console/message.jsx
new file mode 100644
index 0000000..5b60af4
--- /dev/null
+++ b/src/console/components/console/message.jsx
@@ -0,0 +1,18 @@
+import { h } from 'preact';
+
+export default function Message(props) {
+ switch (props.mode) {
+ case 'error':
+ return (
+ <p className='vimvixen-console-message vimvixen-console-error'>
+ { props.children }
+ </p>
+ );
+ case 'info':
+ return (
+ <p className='vimvixen-console-message vimvixen-console-info'>
+ { props.children }
+ </p>
+ );
+ }
+}
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 @@
<title>VimVixen console</title>
<script src='console.js'></script>
</head>
- <body class='vimvixen-console'>
- <p class='vimvixen-console-message'></p>
- <div id='vimvixen-console-command' class='vimvixen-console-command-wrapper'>
- <ul id='vimvixen-console-completion' class='vimvixen-console-completion'></ul>
- <div class='vimvixen-console-command'>
- <i class='vimvixen-console-command-prompt'></i><input
- id='vimvixen-console-command-input'
- class='vimvixen-console-command-input'></input>
- </div>
- </div>
- </body>
+ <body class='vimvixen-console'></body>
</html>
diff --git a/src/console/index.js b/src/console/index.jsx
index 8724a44..dfd323e 100644
--- a/src/console/index.js
+++ b/src/console/index.jsx
@@ -1,21 +1,25 @@
-import './site.scss';
import messages from 'shared/messages';
-import CompletionComponent from 'console/components/completion';
-import ConsoleComponent from 'console/components/console';
import reducers from 'console/reducers';
import { createStore, applyMiddleware } from 'redux';
import promise from 'redux-promise';
import * as consoleActions from 'console/actions/console';
+import { Provider } from 'preact-redux';
+import Console from './components/console';
+
+import { render, h } from 'preact';
+
const store = createStore(
reducers,
applyMiddleware(promise),
);
window.addEventListener('load', () => {
- let wrapper = document.querySelector('#vimvixen-console-completion');
- new CompletionComponent(wrapper, store); // eslint-disable-line no-new
- new ConsoleComponent(document.body, store); // eslint-disable-line no-new
+ render(
+ <Provider store={store} >
+ <Console></Console>
+ </Provider>,
+ document.body);
});
const onMessage = (message) => {
@@ -34,6 +38,5 @@ const onMessage = (message) => {
};
browser.runtime.onMessage.addListener(onMessage);
-window.addEventListener('message', (event) => {
- onMessage(JSON.parse(event.data));
-}, false);
+let port = browser.runtime.connect({ name: 'vimvixen-console' });
+port.onMessage.addListener(onMessage);
diff --git a/src/content/actions/find.js b/src/content/actions/find.js
index b3d7e30..e08d7e5 100644
--- a/src/content/actions/find.js
+++ b/src/content/actions/find.js
@@ -9,25 +9,6 @@ import messages from 'shared/messages';
import actions from 'content/actions';
import * as consoleFrames from '../console-frames';
-const postPatternNotFound = (pattern) => {
- return consoleFrames.postError(
- window.document,
- 'Pattern not found: ' + pattern);
-};
-
-const postPatternFound = (pattern) => {
- return consoleFrames.postInfo(
- window.document,
- 'Pattern found: ' + pattern,
- );
-};
-
-const postNoPrevious = () => {
- return consoleFrames.postError(
- window.document,
- 'No previous search keywords');
-};
-
const find = (string, backwards) => {
let caseSensitive = false;
let wrapScan = true;
@@ -60,13 +41,13 @@ const findNext = async(currentKeyword, reset, backwards) => {
});
}
if (!keyword) {
- return postNoPrevious();
+ return consoleFrames.postError('No previous search keywords');
}
let found = find(keyword, backwards);
if (found) {
- postPatternFound(keyword);
+ consoleFrames.postInfo('Pattern found: ' + keyword);
} else {
- postPatternNotFound(keyword);
+ consoleFrames.postError('Pattern not found: ' + keyword);
}
return {
diff --git a/src/content/actions/operation.js b/src/content/actions/operation.js
index 1aeb8be..b96c6b9 100644
--- a/src/content/actions/operation.js
+++ b/src/content/actions/operation.js
@@ -85,7 +85,7 @@ const exec = (operation, repeat, settings, addonEnabled) => {
break;
case operations.URLS_YANK:
urls.yank(window);
- consoleFrames.postInfo(window.document, 'Current url yanked');
+ consoleFrames.postInfo('Current url yanked');
break;
case operations.URLS_PASTE:
urls.paste(
diff --git a/src/content/components/common/mark.js b/src/content/components/common/mark.js
index 1ed636b..0f838a9 100644
--- a/src/content/components/common/mark.js
+++ b/src/content/components/common/mark.js
@@ -33,7 +33,7 @@ export default class MarkComponent {
}
if (key.ctrlKey || key.metaKey || key.altKey) {
- consoleFrames.postError(window.document, 'Unknown mark');
+ consoleFrames.postError('Unknown mark');
} else if (globalKey(key.key) && markStage.setMode) {
this.doSetGlobal(key);
} else if (globalKey(key.key) && markStage.jumpMode) {
@@ -55,7 +55,7 @@ export default class MarkComponent {
doJump(marks, key, smoothscroll) {
if (!marks[key.key]) {
- consoleFrames.postError(window.document, 'Mark is not set');
+ consoleFrames.postError('Mark is not set');
return;
}
diff --git a/src/content/console-frames.js b/src/content/console-frames.js
index 0c0ec02..401765c 100644
--- a/src/content/console-frames.js
+++ b/src/content/console-frames.js
@@ -16,22 +16,23 @@ const blur = (doc) => {
iframe.blur();
};
-const postMessage = (doc, message) => {
- let iframe = doc.getElementById('vimvixen-console-frame');
- iframe.contentWindow.postMessage(JSON.stringify(message), '*');
-};
-
-const postError = (doc, message) => {
- return postMessage(doc, {
- type: messages.CONSOLE_SHOW_ERROR,
- text: message,
+const postError = (text) => {
+ browser.runtime.sendMessage({
+ type: messages.CONSOLE_FRAME_MESSAGE,
+ message: {
+ type: messages.CONSOLE_SHOW_ERROR,
+ text,
+ },
});
};
-const postInfo = (doc, message) => {
- return postMessage(doc, {
- type: messages.CONSOLE_SHOW_INFO,
- text: message,
+const postInfo = (text) => {
+ browser.runtime.sendMessage({
+ type: messages.CONSOLE_FRAME_MESSAGE,
+ message: {
+ type: messages.CONSOLE_SHOW_INFO,
+ text,
+ },
});
};
diff --git a/src/shared/messages.js b/src/shared/messages.js
index dad2b7a..e86600e 100644
--- a/src/shared/messages.js
+++ b/src/shared/messages.js
@@ -63,6 +63,9 @@ export default {
SETTINGS_CHANGED: 'settings.changed',
SETTINGS_QUERY: 'settings.query',
+ WINDOW_TOP_MESSAGE: 'window.top.message',
+ CONSOLE_FRAME_MESSAGE: 'console.frame.message',
+
onWebMessage,
onBackgroundMessage,
onMessage,