aboutsummaryrefslogtreecommitdiff
path: root/src/pages
diff options
context:
space:
mode:
Diffstat (limited to 'src/pages')
-rw-r--r--src/pages/completion.js27
-rw-r--r--src/pages/console.html20
-rw-r--r--src/pages/console.js186
-rw-r--r--src/pages/console.scss92
-rw-r--r--src/pages/settings.html18
-rw-r--r--src/pages/settings.js22
-rw-r--r--src/pages/settings.scss8
7 files changed, 373 insertions, 0 deletions
diff --git a/src/pages/completion.js b/src/pages/completion.js
new file mode 100644
index 0000000..4c69afb
--- /dev/null
+++ b/src/pages/completion.js
@@ -0,0 +1,27 @@
+export default class Completion {
+ constructor(completions) {
+ if (typeof completions.length !== 'number') {
+ throw new TypeError('completions does not have a length in number');
+ }
+ this.completions = completions;
+ this.index = 0;
+ }
+
+ prev() {
+ let length = this.completions.length;
+ if (length === 0) {
+ return null;
+ }
+ this.index = (this.index + length - 1) % length;
+ return this.completions[this.index];
+ }
+
+ next() {
+ if (this.completions.length === 0) {
+ return null;
+ }
+ let item = this.completions[this.index];
+ this.index = (this.index + 1) % this.completions.length;
+ return item;
+ }
+}
diff --git a/src/pages/console.html b/src/pages/console.html
new file mode 100644
index 0000000..4222f12
--- /dev/null
+++ b/src/pages/console.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset=utf-8 />
+ <title>VimVixen console</title>
+ <script src='console.js'></script>
+ </head>
+ <body class='vimvixen-console'>
+ <p id='vimvixen-console-error'
+ class='vimvixen-console-error'></p>
+ <div id='vimvixen-console-command'>
+ <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>
+</html>
diff --git a/src/pages/console.js b/src/pages/console.js
new file mode 100644
index 0000000..31f2643
--- /dev/null
+++ b/src/pages/console.js
@@ -0,0 +1,186 @@
+import './console.scss';
+import Completion from './completion';
+import messages from '../content/messages';
+
+// TODO consider object-oriented
+let prevValue = '';
+let completion = null;
+let completionOrigin = '';
+let prevState = {};
+
+const handleBlur = () => {
+ return browser.runtime.sendMessage({
+ type: messages.CONSOLE_BLURRED,
+ });
+};
+
+const selectCompletion = (target) => {
+ let container = window.document.querySelector('#vimvixen-console-completion');
+ Array.prototype.forEach.call(container.children, (ele) => {
+ if (!ele.classList.contains('vimvixen-console-completion-item')) {
+ return;
+ }
+ if (ele === target) {
+ ele.classList.add('vimvixen-completion-selected');
+ } else {
+ ele.classList.remove('vimvixen-completion-selected');
+ }
+ });
+};
+
+const completeNext = () => {
+ if (!completion) {
+ return;
+ }
+ let item = completion.next();
+ if (!item) {
+ return;
+ }
+
+ let input = window.document.querySelector('#vimvixen-console-command-input');
+ input.value = completionOrigin + ' ' + item[0].content;
+
+ selectCompletion(item[1]);
+};
+
+const completePrev = () => {
+ if (!completion) {
+ return;
+ }
+ let item = completion.prev();
+ if (!item) {
+ return;
+ }
+
+ let input = window.document.querySelector('#vimvixen-console-command-input');
+ input.value = completionOrigin + ' ' + item[0].content;
+
+ selectCompletion(item[1]);
+};
+
+const handleKeydown = (e) => {
+ let input = window.document.querySelector('#vimvixen-console-command-input');
+
+ switch (e.keyCode) {
+ case KeyboardEvent.DOM_VK_ESCAPE:
+ return input.blur();
+ case KeyboardEvent.DOM_VK_RETURN:
+ return browser.runtime.sendMessage({
+ type: messages.CONSOLE_ENTERED,
+ text: e.target.value
+ });
+ case KeyboardEvent.DOM_VK_TAB:
+ if (e.shiftKey) {
+ completePrev();
+ } else {
+ completeNext();
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ break;
+ }
+};
+
+const handleKeyup = (e) => {
+ if (e.keyCode === KeyboardEvent.DOM_VK_TAB) {
+ return;
+ }
+ if (e.target.value === prevValue) {
+ return;
+ }
+ prevValue = e.target.value;
+ return browser.runtime.sendMessage({
+ type: messages.CONSOLE_CHANGEED,
+ text: e.target.value
+ });
+};
+
+window.addEventListener('load', () => {
+ let input = window.document.querySelector('#vimvixen-console-command-input');
+ input.addEventListener('blur', handleBlur);
+ input.addEventListener('keydown', handleKeydown);
+ input.addEventListener('keyup', handleKeyup);
+});
+
+const createCompletionTitle = (text) => {
+ let li = document.createElement('li');
+ li.className = 'vimvixen-console-completion-title';
+ li.textContent = text;
+ return li;
+};
+
+const createCompletionItem = (icon, caption, url) => {
+ let captionEle = document.createElement('span');
+ captionEle.className = 'vimvixen-console-completion-item-caption';
+ captionEle.textContent = caption;
+
+ let urlEle = document.createElement('span');
+ urlEle.className = 'vimvixen-console-completion-item-url';
+ urlEle.textContent = url;
+
+ let li = document.createElement('li');
+ li.style.backgroundImage = 'url(' + icon + ')';
+ li.className = 'vimvixen-console-completion-item';
+ li.append(captionEle);
+ li.append(urlEle);
+ return li;
+};
+
+const updateCompletions = (completions) => {
+ let completionsContainer =
+ window.document.querySelector('#vimvixen-console-completion');
+ let input = window.document.querySelector('#vimvixen-console-command-input');
+
+ completionsContainer.innerHTML = '';
+
+ let pairs = [];
+
+ for (let group of completions) {
+ let title = createCompletionTitle(group.name);
+ completionsContainer.append(title);
+
+ for (let item of group.items) {
+ let li = createCompletionItem(item.icon, item.caption, item.url);
+ completionsContainer.append(li);
+
+ pairs.push([item, li]);
+ }
+ }
+
+ completion = new Completion(pairs);
+ completionOrigin = input.value.split(' ')[0];
+};
+
+const update = (state) => {
+ let error = window.document.querySelector('#vimvixen-console-error');
+ let command = window.document.querySelector('#vimvixen-console-command');
+ let input = window.document.querySelector('#vimvixen-console-command-input');
+
+ error.style.display = state.errorShown ? 'block' : 'none';
+ error.textContent = state.errorText;
+
+ command.style.display = state.commandShown ? 'block' : 'none';
+ if (state.commandShown && !prevState.commandShown) {
+ input.value = state.commandText;
+ input.focus();
+ }
+ if (JSON.stringify(state.completions) !==
+ JSON.stringify(prevState.completions)) {
+ updateCompletions(state.completions);
+ }
+
+ prevState = state;
+};
+
+browser.runtime.onMessage.addListener((action) => {
+ if (action.type === messages.STATE_UPDATE) {
+ return update(action.state.console);
+ }
+});
+
+window.addEventListener('load', () => {
+ let error = window.document.querySelector('#vimvixen-console-error');
+ let command = window.document.querySelector('#vimvixen-console-command');
+ error.style.display = 'none';
+ command.style.display = 'none';
+});
diff --git a/src/pages/console.scss b/src/pages/console.scss
new file mode 100644
index 0000000..5823dce
--- /dev/null
+++ b/src/pages/console.scss
@@ -0,0 +1,92 @@
+html, body, * {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ overflow: hidden;
+}
+
+.vimvixen-console {
+ border-top: 1px solid gray;
+ bottom: 0;
+ margin: 0;
+ padding: 0;
+
+ @mixin consoole-font {
+ font-style: normal;
+ font-family: monospace;
+ font-size: 12px;
+ line-height: 16px;
+ }
+
+ &-completion {
+ background-color: white;
+
+ @include consoole-font;
+
+ &-title {
+ background-color: lightgray;
+ font-weight: bold;
+ margin: 0;
+ padding: 0;
+ }
+
+ &-item {
+ padding-left: 1.5rem;
+ background-position: 0 center;
+ background-size: contain;
+ background-repeat: no-repeat;
+ white-space: nowrap;
+
+ &.vimvixen-completion-selected {
+ background-color: yellow;
+ }
+
+ &-caption {
+ display: inline-block;
+ width: 40%;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+
+ &-url {
+ display: inline-block;
+ color: green;
+ width: 60%;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+ }
+ }
+
+ &-error {
+ background-color: red;
+ font-weight: bold;
+ color: white;
+
+ @include consoole-font;
+ }
+
+ &-command {
+ background-color: white;
+ display: flex;
+
+ &-prompt:before {
+ content: ':';
+
+ @include consoole-font;
+ }
+
+ &-input {
+ border: none;
+ flex-grow: 1;
+
+ @include consoole-font;
+ }
+ }
+}
diff --git a/src/pages/settings.html b/src/pages/settings.html
new file mode 100644
index 0000000..99d6c6b
--- /dev/null
+++ b/src/pages/settings.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ </head>
+ <body>
+ <h1>Configure</h1>
+
+ <h2>Home page</h2>
+ <form id='vimvixen-settings-form' class='vimvixen-settings-form'>
+ <label for='load-from-json'>Load from JSON:</label>
+ <textarea name='plain-json' spellcheck='false'></textarea>
+
+ <button type='submit'>Save</button>
+ </form>
+ <script src='settings.js'></script>
+ </body>
+</html>
diff --git a/src/pages/settings.js b/src/pages/settings.js
new file mode 100644
index 0000000..6e00ed3
--- /dev/null
+++ b/src/pages/settings.js
@@ -0,0 +1,22 @@
+import './settings.scss';
+import messages from '../content/messages';
+
+document.addEventListener('DOMContentLoaded', () => {
+ let form = document.getElementById('vimvixen-settings-form');
+ form.addEventListener('submit', (e) => {
+ e.preventDefault();
+ browser.storage.local.set({
+ settings: {
+ json: e.target.elements['plain-json'].value
+ }
+ }).then(() => {
+ return browser.runtime.sendMessage({
+ type: messages.SETTINGS_RELOAD
+ });
+ });
+ });
+
+ browser.storage.local.get('settings').then((value) => {
+ form.elements['plain-json'].value = value.settings.json;
+ }, console.error);
+});
diff --git a/src/pages/settings.scss b/src/pages/settings.scss
new file mode 100644
index 0000000..5707c8a
--- /dev/null
+++ b/src/pages/settings.scss
@@ -0,0 +1,8 @@
+.vimvixen-settings-form {
+ textarea[name=plain-json] {
+ font-family: monospace;
+ width: 100%;
+ min-height: 64ex;
+ resize: vertical;
+ }
+}