Merge branch 'iframe-command-line'
This commit is contained in:
commit
f1b9c6ba9d
12 changed files with 1708 additions and 151 deletions
|
@ -10,9 +10,14 @@
|
|||
}
|
||||
],
|
||||
"background": {
|
||||
"scripts": ["build/background.js"]
|
||||
"scripts": [
|
||||
"build/background.js"
|
||||
]
|
||||
},
|
||||
"permissions": [
|
||||
"sessions"
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
"build/command-line.html"
|
||||
]
|
||||
}
|
||||
|
|
1481
package-lock.json
generated
1481
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -24,6 +24,7 @@
|
|||
"chai": "^4.1.1",
|
||||
"css-loader": "^0.28.4",
|
||||
"eslint": "^4.4.1",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"karma": "^1.7.0",
|
||||
"karma-firefox-launcher": "^1.0.1",
|
||||
"karma-html2js-preprocessor": "^1.1.0",
|
||||
|
@ -32,6 +33,8 @@
|
|||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^2.0.4",
|
||||
"mocha": "^3.5.0",
|
||||
"node-sass": "^4.5.3",
|
||||
"sass-loader": "^6.0.6",
|
||||
"style-loader": "^0.18.2",
|
||||
"webpack": "^3.5.3"
|
||||
}
|
||||
|
|
19
src/command-line/command-line-frame.js
Normal file
19
src/command-line/command-line-frame.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import './command-line-frame.scss';
|
||||
|
||||
export default class CommandLineFrame {
|
||||
constructor(win, initial = '') {
|
||||
let url = browser.runtime.getURL('build/command-line.html') +
|
||||
'#' + encodeURIComponent(initial);
|
||||
|
||||
let element = window.document.createElement('iframe');
|
||||
element.src = url;
|
||||
element.className = 'vimvixen-command-line-frame';
|
||||
win.document.body.append(element);
|
||||
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.element.remove();
|
||||
}
|
||||
}
|
11
src/command-line/command-line-frame.scss
Normal file
11
src/command-line/command-line-frame.scss
Normal file
|
@ -0,0 +1,11 @@
|
|||
.vimvixen-command-line-frame {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
z-index: 10000;
|
||||
border: none;
|
||||
}
|
18
src/command-line/command-line.html
Normal file
18
src/command-line/command-line.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8 />
|
||||
<title>VimVixen command-line</title>
|
||||
<script src='command-line.js'></script>
|
||||
</head>
|
||||
<body class='vimvixen-command-line'>
|
||||
<div>
|
||||
<p class='vimvixen-command-line-title'></p>
|
||||
<div class='vimvixen-command-line-line'>
|
||||
<i class='vimvixen-command-line-line-prompt'></i><input
|
||||
id='vimvixen-command-line-line-input'
|
||||
class='vimvixen-command-line-line-input'></input>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
64
src/command-line/command-line.js
Normal file
64
src/command-line/command-line.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import './command-line.scss';
|
||||
|
||||
const parent = window.parent;
|
||||
|
||||
// TODO consider object-oriented
|
||||
var prevValue = "";
|
||||
|
||||
const blurData = () => {
|
||||
return JSON.stringify({
|
||||
type: 'vimvixen.commandline.blur'
|
||||
});
|
||||
};
|
||||
|
||||
const keydownData = (input) => {
|
||||
return JSON.stringify({
|
||||
type: 'vimvixen.commandline.enter',
|
||||
value: input.value
|
||||
});
|
||||
};
|
||||
|
||||
const keyupData = (input) => {
|
||||
return JSON.stringify({
|
||||
type: 'vimvixen.commandline.change',
|
||||
value: input.value
|
||||
});
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
parent.postMessage(blurData(), '*');
|
||||
};
|
||||
|
||||
const handleKeydown = (e) => {
|
||||
switch(e.keyCode) {
|
||||
case KeyboardEvent.DOM_VK_ESCAPE:
|
||||
parent.postMessage(blurData(), '*');
|
||||
break;
|
||||
case KeyboardEvent.DOM_VK_RETURN:
|
||||
parent.postMessage(keydownData(e.target), '*');
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyup = (e) => {
|
||||
if (e.target.value === prevValue) {
|
||||
return;
|
||||
}
|
||||
parent.postMessage(keyupData(e.target), '*');
|
||||
prevValue = e.target.value;
|
||||
};
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
let hash = window.location.hash;
|
||||
let initial = '';
|
||||
if (hash.length > 0) {
|
||||
initial = decodeURIComponent(hash.substring(1));
|
||||
}
|
||||
|
||||
let input = window.document.querySelector('#vimvixen-command-line-line-input');
|
||||
input.addEventListener('blur', handleBlur);
|
||||
input.addEventListener('keydown', handleKeydown);
|
||||
input.addEventListener('keyup', handleKeyup);
|
||||
input.value = initial;
|
||||
input.focus();
|
||||
});
|
52
src/command-line/command-line.scss
Normal file
52
src/command-line/command-line.scss
Normal file
|
@ -0,0 +1,52 @@
|
|||
html, body, * {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.vimvixen-command-line {
|
||||
border-top: 1px solid gray;
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
@mixin input-style {
|
||||
font-style: normal;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
||||
&-title {
|
||||
background-color: lightgray;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
@include input-style;
|
||||
}
|
||||
|
||||
&-line {
|
||||
background-color: white;
|
||||
display: flex;
|
||||
|
||||
&-prompt:before {
|
||||
content: ':';
|
||||
|
||||
@include input-style;
|
||||
}
|
||||
|
||||
&-input {
|
||||
border: none;
|
||||
flex-grow: 1;
|
||||
|
||||
@include input-style;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
.vimvixen-footerline {
|
||||
border-top: 1px solid gray;
|
||||
bottom: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.vimvixen-footerline-title {
|
||||
background-color: lightgray;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.vimvixen-footerline-container-outer {
|
||||
background-color: white;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.vimvixen-footerline-container-outer:before {
|
||||
content: ':';
|
||||
background-color: white;
|
||||
float: left;
|
||||
text-align: right;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.vimvixen-footerline-container-inner {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.vimvixen-footerline-input {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
import './footer-line.css';
|
||||
|
||||
export default class FooterLine {
|
||||
constructor(doc, initial = '') {
|
||||
this.initUi(doc);
|
||||
|
||||
this.enteredCallback = () => {}
|
||||
this.promptChangeCallback = () => {}
|
||||
|
||||
this.input.addEventListener('blur', this.handleBlur.bind(this));
|
||||
this.input.addEventListener('keydown', this.handleKeydown.bind(this));
|
||||
this.input.addEventListener('keyup', this.handleKeyup.bind(this));
|
||||
this.input.value = initial;
|
||||
}
|
||||
|
||||
initUi(doc) {
|
||||
this.title = doc.createElement('p');
|
||||
this.title.className = 'vimvixen-footerline-title';
|
||||
|
||||
let containerInner = doc.createElement('div');
|
||||
containerInner.className = 'vimvixen-footerline-container-inner';
|
||||
|
||||
let containerOuter = doc.createElement('div');
|
||||
containerOuter.className = 'vimvixen-footerline-container-outer';
|
||||
|
||||
this.input = doc.createElement('input');
|
||||
this.input.className = 'vimvixen-footerline-input';
|
||||
|
||||
this.wrapper = doc.createElement('div');
|
||||
this.wrapper.className = 'vimvixen-footerline';
|
||||
|
||||
containerOuter.append(containerInner);
|
||||
containerInner.append(this.input);
|
||||
this.wrapper.append(this.title);
|
||||
this.wrapper.append(containerOuter);
|
||||
doc.body.append(this.wrapper)
|
||||
}
|
||||
|
||||
focus() {
|
||||
this.input.focus();
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.wrapper.remove();
|
||||
}
|
||||
|
||||
onPromptChange(callback) {
|
||||
this.promptChangeCallback = callback;
|
||||
}
|
||||
|
||||
onEntered(callback) {
|
||||
this.enteredCallback = callback;
|
||||
}
|
||||
|
||||
handleBlur() {
|
||||
this.remove();
|
||||
}
|
||||
|
||||
handleKeydown(e) {
|
||||
this.prevValue = e.target.value;
|
||||
switch(e.keyCode) {
|
||||
case KeyboardEvent.DOM_VK_ESCAPE:
|
||||
this.remove();
|
||||
break;
|
||||
case KeyboardEvent.DOM_VK_RETURN:
|
||||
this.enteredCallback(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyup(e) {
|
||||
if (e.target.value === this.prevValue) {
|
||||
return;
|
||||
}
|
||||
this.promptChangeCallback(e);
|
||||
this.prevValue = e.target.value;
|
||||
}
|
||||
}
|
|
@ -1,29 +1,10 @@
|
|||
import * as scrolls from './scrolls';
|
||||
import * as histories from './histories';
|
||||
import * as actions from '../shared/actions';
|
||||
import FooterLine from './footer-line';
|
||||
import CommandLineFrame from '../command-line/command-line-frame';
|
||||
import Follow from './follow';
|
||||
|
||||
var footer = null;
|
||||
|
||||
const createFooterLine = (initial = '') => {
|
||||
footer = new FooterLine(document, initial);
|
||||
footer.onPromptChange((e) => {
|
||||
let request = {
|
||||
type: 'event.cmd.suggest',
|
||||
text: e.target.value
|
||||
};
|
||||
browser.runtime.sendMessage(request);
|
||||
});
|
||||
footer.onEntered((e) => {
|
||||
let request = {
|
||||
type: 'event.cmd.enter',
|
||||
text: e.target.value
|
||||
};
|
||||
browser.runtime.sendMessage(request);
|
||||
});
|
||||
footer.focus();
|
||||
}
|
||||
let cmd = null;
|
||||
|
||||
const invokeEvent = (action) => {
|
||||
if (typeof action === 'undefined' || action === null) {
|
||||
|
@ -32,14 +13,14 @@ const invokeEvent = (action) => {
|
|||
|
||||
switch (action[0]) {
|
||||
case actions.CMD_OPEN:
|
||||
createFooterLine();
|
||||
cmd = new CommandLineFrame(window);
|
||||
break;
|
||||
case actions.CMD_TABS_OPEN:
|
||||
if (action[1] || false) {
|
||||
// alter url
|
||||
createFooterLine('open ' + window.location.href);
|
||||
cmd = new CommandLineFrame(window, 'open ' + window.location.href);
|
||||
} else {
|
||||
createFooterLine('open ');
|
||||
cmd = new CommandLineFrame(window, 'open ');
|
||||
}
|
||||
break;
|
||||
case actions.SCROLL_LINES:
|
||||
|
@ -89,3 +70,36 @@ window.addEventListener("keypress", (e) => {
|
|||
console.log(`Vim Vixen: ${err}`);
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('message', (e) => {
|
||||
let message;
|
||||
try {
|
||||
message = JSON.parse(e.data);
|
||||
} catch (e) {
|
||||
// ignore message posted by author of web page
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message.type) {
|
||||
case 'vimvixen.commandline.blur':
|
||||
if (cmd) {
|
||||
cmd.remove();
|
||||
cmd = null;
|
||||
}
|
||||
break;
|
||||
case 'vimvixen.commandline.enter':
|
||||
browser.runtime.sendMessage({
|
||||
type: 'event.cmd.enter',
|
||||
text: message.value
|
||||
});
|
||||
break;
|
||||
case 'vimvixen.commandline.change':
|
||||
browser.runtime.sendMessage({
|
||||
type: 'event.cmd.suggest',
|
||||
text: message.value
|
||||
});
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
var path = require('path');
|
||||
|
||||
const src = path.resolve(__dirname, 'src');
|
||||
|
@ -6,7 +7,8 @@ const dist = path.resolve(__dirname, 'build');
|
|||
module.exports = {
|
||||
entry: {
|
||||
index: path.join(src, 'content'),
|
||||
background: path.join(src, 'background')
|
||||
background: path.join(src, 'background'),
|
||||
'command-line': path.join(src, 'command-line', 'command-line.js')
|
||||
},
|
||||
|
||||
output: {
|
||||
|
@ -28,10 +30,22 @@ module.exports = {
|
|||
test: /\.css$/,
|
||||
loader: 'style-loader!css-loader',
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
loader: 'style-loader!css-loader!sass-loader?sourceMap=true'
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: [ '.js' ]
|
||||
}
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
template: path.join(src, 'command-line', 'command-line.html'),
|
||||
filename: path.join(dist, 'command-line.html'),
|
||||
inject: false
|
||||
})
|
||||
]
|
||||
};
|
||||
|
|
Reference in a new issue