Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
220828f7db | ||
|
|
7df7f8f598 | ||
|
|
05aff199b2 | ||
|
|
01c20807c2 | ||
|
|
243ce59806 | ||
|
|
5d6e0356b3 | ||
|
|
8324b43cc2 | ||
|
|
4c3ccc264c | ||
|
|
197c83d993 | ||
|
|
aaded29855 | ||
|
|
e5656b9982 | ||
|
|
c06b08df5b | ||
|
|
fc16752cec | ||
|
|
588d3b12e0 | ||
|
|
7de7bdac71 | ||
|
|
6e8e78db57 | ||
|
|
dcc991bd5c | ||
|
|
04cb9f33ff | ||
|
|
9bd167c10d | ||
|
|
dc6aab88b0 | ||
|
|
43fc6f1fa3 | ||
|
|
c2aa0d75ec | ||
|
|
c24ae84b00 | ||
|
|
92605a9734 | ||
|
|
b32a34b97c | ||
|
|
12923a6649 | ||
|
|
e7c7160f85 | ||
|
|
2a0962183e | ||
|
|
95d9ad46cf | ||
|
|
e60513f554 | ||
|
|
a557a82b40 | ||
|
|
3dd6f368d6 | ||
|
|
5ce012bdac | ||
|
|
a2338c49b9 | ||
|
|
dd6886f358 | ||
|
|
5ddf6301c2 | ||
|
|
14dd2c0afb | ||
|
|
fc2a0d3e65 | ||
|
|
0f8fc63a5e | ||
|
|
f57a40eeb3 | ||
|
|
2c9c95f531 | ||
|
|
7048f6edf7 | ||
|
|
c333cfa073 | ||
|
|
64d77d2491 | ||
|
|
9604674c65 | ||
|
|
d9294779a6 | ||
|
|
3117fe9465 | ||
|
|
0a74b9aa3b | ||
|
|
7e90576391 | ||
|
|
0a34885fbc | ||
|
|
61201525a8 | ||
|
|
1b886a4420 | ||
|
|
6f70984ab6 | ||
|
|
38fa2d78da | ||
|
|
fe905bace5 | ||
|
|
e7e1434293 | ||
|
|
363c647a5f | ||
|
|
aac60eb029 | ||
|
|
06ca03ae9c | ||
|
|
ff927b8e79 | ||
|
|
670b0d58c7 | ||
|
|
3113cdf0ea | ||
|
|
d2cef6f29d | ||
|
|
d62bd5f748 | ||
|
|
e6fd1381ce | ||
|
|
65b2be7831 | ||
|
|
e2d0de2686 | ||
|
|
495b2d7fbb | ||
|
|
5e662d0eb7 | ||
|
|
892db98c96 | ||
|
|
10fbf0dccc | ||
|
|
4595a18197 | ||
|
|
577a3d81e5 | ||
|
|
55fb5dbcb5 | ||
|
|
8e7eeff45c | ||
|
|
ec7130b46f | ||
|
|
0010a5a109 | ||
|
|
9cb5b005bb | ||
|
|
06a3aa6cf8 | ||
|
|
d4e9d34d2d | ||
|
|
a3a7017f6b | ||
|
|
fedc1fd325 | ||
|
|
11d5f51e67 | ||
|
|
534a9e7f5a | ||
|
|
14a62c0f8b | ||
|
|
89d29bbc10 | ||
|
|
ac8db6e8ec | ||
|
|
0a7c1bfd98 | ||
|
|
4efb8d24ac | ||
|
|
38d08873bc | ||
|
|
8074d754d3 | ||
|
|
e1c1b07a0b | ||
|
|
c18794f202 | ||
|
|
8b46e84263 | ||
|
|
237e6819bf | ||
|
|
8faea59e31 | ||
|
|
cab79c473f | ||
|
|
c656ed04b0 | ||
|
|
29000fb79e | ||
|
|
03fa017d4a | ||
|
|
26af6ffd4d | ||
|
|
7d8e28a7dd | ||
|
|
a52b7e7a4e | ||
|
|
aaedcfc700 | ||
|
|
fc7b22dc48 |
@@ -1,8 +1,11 @@
|
||||
List of xterm.js contributors. Updated before every release.
|
||||
|
||||
Alessandro Nadalin <alessandro.nadalin@gmail.com>
|
||||
Alexander Olsson <noseglid@gmail.com>
|
||||
Antonis Kalipetis <akalipetis@sourcelair.com>
|
||||
Anton Skshidlevsky <meefik@gmail.com>
|
||||
Austin Robertson <austinrobertson@gmail.com>
|
||||
ayapi <colors.aya@gmail.com>
|
||||
Benjamin Fischer <benjamin.fischer@rwth-aachen.de>
|
||||
Carson Anderson <carson@betterservers.com>
|
||||
Christopher Jeffrey <chjjeffrey@gmail.com>
|
||||
@@ -17,3 +20,4 @@ Paris Kasidiaris <paris@sourcelair.com>
|
||||
runarberg <runar@greenqloud.com>
|
||||
Steven Silvester <steven.silvester@ieee.org>
|
||||
Thanasis Daglis <thanasis@sourcelair.com>
|
||||
Tine Jozelj <tine.jozelj@outlook.com>
|
||||
|
||||
@@ -1,18 +1,35 @@
|
||||
# xterm.js
|
||||
|
||||

|
||||
 [](https://gitter.im/sourcelair/xterm.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
Xterm.js is a full xterm clone, written in JavaScript.
|
||||
Xterm.js is a terminal front-end component written in JavaScript that works in the browser.
|
||||
|
||||
It is used at [SourceLair](https://www.sourcelair.com/home) to help people develop their applications in their browsers.
|
||||
It enables applications to provide fully featured terminals to their users and create great development experiences.
|
||||
|
||||
Xterm.js supplies a modular, event-based interface that lets developers build addons and themes on top of it.
|
||||
## Features
|
||||
- **Text-based application support**: Use xterm.js to work with applications like `bash`, `git` etc.
|
||||
- **Curses-based application support**: Use xterm.js to work with applications like `vim`, `tmux` etc.
|
||||
- **Mouse events support**: Xterm.js captures mouse events like click and scroll and passes them to the terminal's back-end controlling process
|
||||
- **CJK (Chinese, Japanese, Korean) character support**: Xterm.js renders CJK characters seamlessly
|
||||
- **IME support**: Insert international (including CJK) characters using IME input with your keyboard
|
||||
- **Self-contained library**: Xterm.js works on its own. It does not require any external libraries like jQuery or React to work
|
||||
- **Modular, event-based API**: Lets you build addons and themes with ease
|
||||
|
||||

|
||||
## What xterm.js is not
|
||||
- Xterm.js is not a terminal application that you can download and use on your computer
|
||||
- Xterm.js is not `bash`. Xterm.js can be connected to processes like `bash` and let you interact with them (provide input, receive output)
|
||||
|
||||
## Real-world uses
|
||||
Xterm.js is used in several world-class applications to provide great terminal experiences.
|
||||
|
||||
- [**SourceLair**](https://www.sourcelair.com/): In-browser IDE that provides its users with fully-featured Linux terminals based on xterm.js
|
||||
- [**Microsoft Visual Studio Code**](http://code.visualstudio.com/): Modern, versatile, powerful and open source code editor that provides integrated terminal based on xterm.js
|
||||
|
||||
Do you use xterm.js in your application as well? Please [open a Pull Request](https://github.com/sourcelair/xterm.js/pulls) to include it here. We would love to have it in our list.
|
||||
|
||||
## Browser Support
|
||||
|
||||
Since xterm.js is typically implemented as a developer tool, only modern browsers are supported officially. Here is a list of the versions we aim to support:
|
||||
Since xterm.js is typically implemented as a developer tool, only modern browsers are supported officially. Here is a list of the versions we aim to support:
|
||||
|
||||
- Chrome 48+
|
||||
- Edge 13+
|
||||
@@ -21,7 +38,7 @@ Since xterm.js is typically implemented as a developer tool, only modern browser
|
||||
- Opera 35+
|
||||
- Safari 8+
|
||||
|
||||
xterm.js may work on earlier versions of the browsers but these are the browsers we strive to keep working.
|
||||
Xterm.js works seamlessly in Electron apps and may even work on earlier versions of the browsers but these are the browsers we strive to keep working.
|
||||
|
||||
## Demo
|
||||
|
||||
@@ -51,8 +68,16 @@ var xterm = new Terminal();
|
||||
xterm.fit();
|
||||
```
|
||||
|
||||
## Releases
|
||||
|
||||
Xterm.js follows a monthly release cycle roughly.
|
||||
|
||||
The existing releases are available at this GitHub repo's [Releases](https://github.com/sourcelair/xterm.js/releases), while the roadmap is available as [Milestones](https://github.com/sourcelair/xterm.js/milestones).
|
||||
|
||||
## Development and Contribution
|
||||
|
||||
Xterm.js is maintained by [SourceLair](https://www.sourcelair.com/) and a few external contributors, but we would love to receive contributions from everyone!
|
||||
|
||||
To contribute either code, documentation or issues to xterm.js please read the [Contributing document](CONTRIBUTING.md) before.
|
||||
|
||||
The development of xterm.js does not require any special tool. All you need is an editor that supports JavaScript and a browser (if you would like to run the demo you will need Node.js to get all features).
|
||||
|
||||
@@ -54,10 +54,12 @@
|
||||
* "linkified".
|
||||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is
|
||||
* false, the regex requires a protocol clause. Defaults to true.
|
||||
* @param {string} target - Sets target="" attribute with value provided to links.
|
||||
* Default doesn't set target attribute
|
||||
* @emits linkify
|
||||
* @emits linkify:line
|
||||
*/
|
||||
exports.linkifyTerminalLine = function (terminal, line, lenient) {
|
||||
exports.linkifyTerminalLine = function (terminal, line, lenient, target) {
|
||||
if (typeof line == 'number') {
|
||||
line = terminal.rowContainer.children[line];
|
||||
} else if (! (line instanceof HTMLDivElement)) {
|
||||
@@ -67,6 +69,12 @@
|
||||
throw new TypeError(message);
|
||||
}
|
||||
|
||||
if (typeof target === 'undefined') {
|
||||
target = '';
|
||||
} else {
|
||||
target = 'target="' + target + '"';
|
||||
}
|
||||
|
||||
var buffer = document.createElement('span'),
|
||||
nodes = line.childNodes;
|
||||
|
||||
@@ -100,7 +108,7 @@
|
||||
var startsWithProtocol = new RegExp('^' + protocolClause),
|
||||
urlHasProtocol = url.match(startsWithProtocol),
|
||||
href = (urlHasProtocol) ? url : 'http://' + url,
|
||||
link = '<a href="' + href + '" >' + url + '</a>',
|
||||
link = '<a href="' + href + '" ' + target + '>' + url + '</a>',
|
||||
newHTML = nodeHTML.replace(url, link);
|
||||
|
||||
line.innerHTML = line.innerHTML.replace(nodeHTML, newHTML);
|
||||
@@ -137,17 +145,19 @@
|
||||
* @param {Xterm} terminal - The terminal that should get "linkified".
|
||||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is
|
||||
* false, the regex requires a protocol clause. Defaults to true.
|
||||
* @param {string} target - Sets target="" attribute with value provided to links.
|
||||
* Default doesn't set target attribute
|
||||
* @emits linkify
|
||||
* @emits linkify:line
|
||||
*/
|
||||
exports.linkify = function (terminal, lenient) {
|
||||
exports.linkify = function (terminal, lenient, target) {
|
||||
var rows = terminal.rowContainer.children;
|
||||
|
||||
lenient = (typeof lenient == "boolean") ? lenient : true;
|
||||
for (var i=0; i<rows.length; i++) {
|
||||
var line = rows[i];
|
||||
|
||||
exports.linkifyTerminalLine(terminal, line, lenient);
|
||||
exports.linkifyTerminalLine(terminal, line, lenient, target);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,9 +183,11 @@
|
||||
* "linkified".
|
||||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is
|
||||
* false, the regex requires a protocol clause. Defaults to true.
|
||||
* @param {string} target - Sets target="" attribute with value provided to links.
|
||||
* Default doesn't set target attribute
|
||||
*/
|
||||
Xterm.prototype.linkifyTerminalLine = function (line, lenient) {
|
||||
return exports.linkifyTerminalLine(this, line, lenient);
|
||||
Xterm.prototype.linkifyTerminalLine = function (line, lenient, target) {
|
||||
return exports.linkifyTerminalLine(this, line, lenient, target);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -184,9 +196,11 @@
|
||||
* @memberof Xterm
|
||||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is
|
||||
* false, the regex requires a protocol clause. Defaults to true.
|
||||
* @param {string} target - Sets target="" attribute with value provided to links.
|
||||
* Default doesn't set target attribute
|
||||
*/
|
||||
Xterm.prototype.linkify = function (lenient) {
|
||||
return exports.linkify(this, lenient);
|
||||
Xterm.prototype.linkify = function (lenient, target) {
|
||||
return exports.linkify(this, lenient, target);
|
||||
};
|
||||
|
||||
return exports;
|
||||
|
||||
+2
-1
@@ -24,4 +24,5 @@ sed -i "s/\"version\": \"$CURRENT_BOWER_JSON_VERSION\"/\"version\": \"$NEW_VERSI
|
||||
# Update AUTHORS file
|
||||
sh bin/generate-authors
|
||||
|
||||
git commit -a -m "Bump version to $NEW_VERSION"
|
||||
git commit -S -s -a -m "Bump version to $NEW_VERSION"
|
||||
git tag $NEW_VERSION
|
||||
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#! /usr/bin/env sh
|
||||
|
||||
# Usage: ./bin/release x.y.z
|
||||
# x.y.z should be semver (e.g. 1.0.0)
|
||||
|
||||
if [ -z "$1" ];
|
||||
then
|
||||
echo "No version supplied. Please a version argument\n"
|
||||
echo "Usage: $0 VERSION\n"
|
||||
echo "Example: $0 1.0.0"
|
||||
exit
|
||||
fi
|
||||
|
||||
NEW_VERSION=$1
|
||||
|
||||
./bin/prepare-release $NEW_VERSION
|
||||
|
||||
git push && \
|
||||
git push --tags && \
|
||||
npm publish
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "xterm.js",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.3",
|
||||
"ignore": ["demo", "test", ".gitignore"]
|
||||
}
|
||||
|
||||
+43
-11
@@ -4,6 +4,9 @@ var expressWs = require('express-ws')(app);
|
||||
var os = require('os');
|
||||
var pty = require('pty.js');
|
||||
|
||||
var terminals = {},
|
||||
logs = {};
|
||||
|
||||
app.use('/src', express.static(__dirname + '/../src'));
|
||||
app.use('/addons', express.static(__dirname + '/../addons'));
|
||||
|
||||
@@ -19,17 +22,43 @@ app.get('/main.js', function(req, res){
|
||||
res.sendFile(__dirname + '/main.js');
|
||||
});
|
||||
|
||||
app.ws('/bash', function(ws, req) {
|
||||
/**
|
||||
* Open bash terminal and attach it
|
||||
*/
|
||||
var term = pty.spawn(process.platform === 'win32' ? 'cmd.exe' : 'bash', [], {
|
||||
name: 'xterm-color',
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
cwd: process.env.PWD,
|
||||
env: process.env
|
||||
app.post('/terminals', function (req, res) {
|
||||
var cols = parseInt(req.query.cols),
|
||||
rows = parseInt(req.query.rows),
|
||||
term = pty.spawn(process.platform === 'win32' ? 'cmd.exe' : 'bash', [], {
|
||||
name: 'xterm-color',
|
||||
cols: cols || 80,
|
||||
rows: rows || 24,
|
||||
cwd: process.env.PWD,
|
||||
env: process.env
|
||||
});
|
||||
|
||||
console.log('Created terminal with PID: ' + term.pid);
|
||||
terminals[term.pid] = term;
|
||||
logs[term.pid] = '';
|
||||
term.on('data', function(data) {
|
||||
logs[term.pid] += data;
|
||||
});
|
||||
res.send(term.pid.toString());
|
||||
res.end();
|
||||
});
|
||||
|
||||
app.post('/terminals/:pid/size', function (req, res) {
|
||||
var pid = parseInt(req.params.pid),
|
||||
cols = parseInt(req.query.cols),
|
||||
rows = parseInt(req.query.rows),
|
||||
term = terminals[pid];
|
||||
|
||||
term.resize(cols, rows);
|
||||
console.log('Resized terminal ' + pid + ' to ' + cols + ' cols and ' + rows + ' rows.');
|
||||
res.end();
|
||||
});
|
||||
|
||||
app.ws('/terminals/:pid', function (ws, req) {
|
||||
var term = terminals[parseInt(req.params.pid)];
|
||||
console.log('Connected to terminal ' + term.pid);
|
||||
ws.send(logs[term.pid]);
|
||||
|
||||
term.on('data', function(data) {
|
||||
try {
|
||||
ws.send(data);
|
||||
@@ -41,8 +70,11 @@ app.ws('/bash', function(ws, req) {
|
||||
term.write(msg);
|
||||
});
|
||||
ws.on('close', function () {
|
||||
console.log('close');
|
||||
process.kill(term.pid);
|
||||
console.log('Closed terminal ' + term.pid);
|
||||
// Clean things up
|
||||
delete terminals[term.pid];
|
||||
delete logs[term.pid];
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+16
-3
@@ -5,20 +5,33 @@
|
||||
<link rel="stylesheet" href="../src/xterm.css" />
|
||||
<link rel="stylesheet" href="../addons/fullscreen/fullscreen.css" />
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script>
|
||||
<script src="../src/xterm.js" ></script>
|
||||
<script src="../addons/attach/attach.js" ></script>
|
||||
<script src="../addons/fit/fit.js" ></script>
|
||||
<script src="../addons/fullscreen/fullscreen.js" ></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>
|
||||
xterm.js: xterm, in the browser
|
||||
</h1>
|
||||
<h1>xterm.js: xterm, in the browser</h1>
|
||||
<div id="terminal-container"></div>
|
||||
<div>
|
||||
<h2>Options</h2>
|
||||
<label><input type="checkbox" id="option-cursor-blink"> cursorBlink</label>
|
||||
<div>
|
||||
<h3>Size</h3>
|
||||
<div>
|
||||
<div style="display: inline-block; margin-right: 16px;">
|
||||
<label for="cols">Columns</label>
|
||||
<input type="number" id="cols" />
|
||||
</div>
|
||||
<div style="display: inline-block; margin-right: 16px;">
|
||||
<label for="rows">Rows</label>
|
||||
<input type="number" id="rows" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p><strong>Attention:</strong> The demo is a barebones implementation and is designed for xterm.js evaluation purposes only. Exposing the demo to the public as is would introduce security risks for the host.</p>
|
||||
<script src="main.js" defer ></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+58
-13
@@ -1,34 +1,81 @@
|
||||
var term,
|
||||
protocol,
|
||||
socketURL,
|
||||
socket;
|
||||
socket,
|
||||
pid,
|
||||
charWidth,
|
||||
charHeight;
|
||||
|
||||
var terminalContainer = document.getElementById('terminal-container');
|
||||
var optionElements = {
|
||||
cursorBlink: document.querySelector('#option-cursor-blink')
|
||||
};
|
||||
var terminalContainer = document.getElementById('terminal-container'),
|
||||
optionElements = {
|
||||
cursorBlink: document.querySelector('#option-cursor-blink')
|
||||
},
|
||||
colsElement = document.getElementById('cols'),
|
||||
rowsElement = document.getElementById('rows');
|
||||
|
||||
function setTerminalSize () {
|
||||
var cols = parseInt(colsElement.value),
|
||||
rows = parseInt(rowsElement.value),
|
||||
width = (cols * charWidth).toString() + 'px',
|
||||
height = (rows * charHeight).toString() + 'px';
|
||||
|
||||
terminalContainer.style.width = width;
|
||||
terminalContainer.style.height = height;
|
||||
term.resize(cols, rows);
|
||||
}
|
||||
|
||||
colsElement.addEventListener('change', setTerminalSize);
|
||||
rowsElement.addEventListener('change', setTerminalSize);
|
||||
|
||||
optionElements.cursorBlink.addEventListener('change', createTerminal);
|
||||
|
||||
createTerminal();
|
||||
|
||||
function createTerminal() {
|
||||
// Clean terminal
|
||||
while (terminalContainer.children.length) {
|
||||
terminalContainer.removeChild(terminalContainer.children[0]);
|
||||
}
|
||||
term = new Terminal({
|
||||
cursorBlink: optionElements.cursorBlink.checked
|
||||
});
|
||||
term.on('resize', function (size) {
|
||||
if (!pid) {
|
||||
return;
|
||||
}
|
||||
var cols = size.cols,
|
||||
rows = size.rows,
|
||||
url = '/terminals/' + pid + '/size?cols=' + cols + '&rows=' + rows;
|
||||
|
||||
fetch(url, {method: 'POST'});
|
||||
});
|
||||
protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
|
||||
socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/bash';
|
||||
socket = new WebSocket(socketURL);
|
||||
socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/';
|
||||
|
||||
term.open(terminalContainer);
|
||||
term.fit();
|
||||
|
||||
socket.onopen = runRealTerminal;
|
||||
socket.onclose = runFakeTerminal;
|
||||
socket.onerror = runFakeTerminal;
|
||||
var initialGeometry = term.proposeGeometry(),
|
||||
cols = initialGeometry.cols,
|
||||
rows = initialGeometry.rows;
|
||||
|
||||
colsElement.value = cols;
|
||||
rowsElement.value = rows;
|
||||
|
||||
fetch('/terminals?cols=' + cols + '&rows=' + rows, {method: 'POST'}).then(function (res) {
|
||||
|
||||
charWidth = Math.ceil(term.element.offsetWidth / cols);
|
||||
charHeight = Math.ceil(term.element.offsetHeight / rows);
|
||||
|
||||
res.text().then(function (pid) {
|
||||
window.pid = pid;
|
||||
socketURL += pid;
|
||||
socket = new WebSocket(socketURL);
|
||||
socket.onopen = runRealTerminal;
|
||||
socket.onclose = runFakeTerminal;
|
||||
socket.onerror = runFakeTerminal;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -64,9 +111,7 @@ function runFakeTerminal() {
|
||||
if (ev.keyCode == 13) {
|
||||
term.prompt();
|
||||
} else if (ev.keyCode == 8) {
|
||||
/*
|
||||
* Do not delete the prompt
|
||||
*/
|
||||
// Do not delete the prompt
|
||||
if (term.x > 2) {
|
||||
term.write('\b \b');
|
||||
}
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@ h1 {
|
||||
}
|
||||
|
||||
#terminal-container {
|
||||
width: 960px;
|
||||
height: 600px;
|
||||
width: 800px;
|
||||
height: 450px;
|
||||
margin: 0 auto;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xterm",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.3",
|
||||
"ignore": [
|
||||
"demo",
|
||||
"test",
|
||||
@@ -17,7 +17,7 @@
|
||||
"glob": "^7.0.5",
|
||||
"jsdoc": "3.4.0",
|
||||
"mocha": "2.5.3",
|
||||
"pty.js": "0.3.0",
|
||||
"pty.js": "0.3.1",
|
||||
"sleep": "^3.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
+57
-10
@@ -43,22 +43,41 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.terminal.focus,
|
||||
.terminal:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.terminal .xterm-helpers {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.terminal .xterm-helper-textarea {
|
||||
position: absolute;
|
||||
/*
|
||||
* HACK: to fix IE's blinking cursor
|
||||
* Move textarea out of the screen to the far left, so that the cursor is not visible.
|
||||
*/
|
||||
left: -9999em;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: -10;
|
||||
}
|
||||
|
||||
.terminal .terminal-cursor {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.terminal:not(:focus) .terminal-cursor {
|
||||
.terminal:not(.focus) .terminal-cursor {
|
||||
outline: 1px solid #fff;
|
||||
outline-offset: -1px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.terminal:focus .terminal-cursor.blinking {
|
||||
.terminal.focus .terminal-cursor.blinking {
|
||||
animation: blink-cursor 1.2s infinite step-end;
|
||||
}
|
||||
|
||||
@@ -73,6 +92,42 @@
|
||||
}
|
||||
}
|
||||
|
||||
.terminal .composition-view {
|
||||
background: #000;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.terminal .composition-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.terminal .xterm-viewport {
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #000;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.terminal .xterm-rows {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.terminal .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.terminal .xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
left: -9999em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine default colors for xterm.js
|
||||
*/
|
||||
@@ -2139,11 +2194,3 @@
|
||||
.terminal .xterm-bg-color-255 {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
/**
|
||||
* All terminal rows should have explicitly declared height,
|
||||
* in order to allow child elements to adjust.
|
||||
*/
|
||||
.terminal .xterm-rows > div {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
+521
-223
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,263 @@
|
||||
var assert = require('chai').assert;
|
||||
var Terminal = require('../src/xterm');
|
||||
|
||||
describe('CompositionHelper', function () {
|
||||
var terminal;
|
||||
var compositionHelper;
|
||||
var compositionView;
|
||||
var textarea;
|
||||
var handledText;
|
||||
|
||||
beforeEach(function () {
|
||||
compositionView = {
|
||||
classList: {
|
||||
add: function () {},
|
||||
remove: function () {},
|
||||
},
|
||||
getBoundingClientRect: function () {
|
||||
return { width: 0 }
|
||||
},
|
||||
style: {
|
||||
left: 0,
|
||||
top: 0
|
||||
},
|
||||
textContent: ''
|
||||
};
|
||||
textarea = {
|
||||
value: '',
|
||||
style: {
|
||||
left: 0,
|
||||
top: 0
|
||||
}
|
||||
};
|
||||
terminal = {
|
||||
element: {
|
||||
querySelector: function () {
|
||||
return { offsetLeft: 0, offsetTop: 0 };
|
||||
}
|
||||
},
|
||||
handler: function (text) {
|
||||
handledText += text;
|
||||
}
|
||||
};
|
||||
handledText = '';
|
||||
compositionHelper = new Terminal.CompositionHelper(textarea, compositionView, terminal);
|
||||
});
|
||||
|
||||
describe('Public API', function () {
|
||||
it('should define CompositionHelper.prototype.compositionstart', function () {
|
||||
assert.isDefined(Terminal.CompositionHelper.prototype.compositionstart);
|
||||
});
|
||||
it('should define CompositionHelper.prototype.compositionupdate', function () {
|
||||
assert.isDefined(Terminal.CompositionHelper.prototype.compositionupdate);
|
||||
});
|
||||
it('should define CompositionHelper.prototype.compositionend', function () {
|
||||
assert.isDefined(Terminal.CompositionHelper.prototype.compositionend);
|
||||
});
|
||||
it('should define CompositionHelper.prototype.finalizeComposition', function () {
|
||||
assert.isDefined(Terminal.CompositionHelper.prototype.finalizeComposition);
|
||||
});
|
||||
it('should define CompositionHelper.prototype.handleAnyTextareaChanges', function () {
|
||||
assert.isDefined(Terminal.CompositionHelper.prototype.handleAnyTextareaChanges);
|
||||
});
|
||||
it('should define CompositionHelper.prototype.updateCompositionElements', function () {
|
||||
assert.isDefined(Terminal.CompositionHelper.prototype.updateCompositionElements);
|
||||
});
|
||||
it('should define CompositionHelper.isComposing', function () {
|
||||
assert.isDefined(compositionHelper.isComposing);
|
||||
});
|
||||
it('should define CompositionHelper.isSendingComposition', function () {
|
||||
assert.isDefined(compositionHelper.isSendingComposition);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Input', function () {
|
||||
it('Should insert simple characters', function (done) {
|
||||
// First character 'ㅇ'
|
||||
compositionHelper.compositionstart();
|
||||
compositionHelper.compositionupdate({ data: 'ㅇ' });
|
||||
textarea.value = 'ㅇ';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionend();
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
assert.equal(handledText, 'ㅇ');
|
||||
// Second character 'ㅇ'
|
||||
compositionHelper.compositionstart();
|
||||
compositionHelper.compositionupdate({ data: 'ㅇ' });
|
||||
textarea.value = 'ㅇㅇ';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionend();
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
assert.equal(handledText, 'ㅇㅇ');
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('Should insert complex characters', function (done) {
|
||||
// First character '앙'
|
||||
compositionHelper.compositionstart();
|
||||
compositionHelper.compositionupdate({ data: 'ㅇ' });
|
||||
textarea.value = 'ㅇ';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionupdate({ data: '아' });
|
||||
textarea.value = '아';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionupdate({ data: '앙' });
|
||||
textarea.value = '앙';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionend();
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
assert.equal(handledText, '앙');
|
||||
// Second character '앙'
|
||||
compositionHelper.compositionstart();
|
||||
compositionHelper.compositionupdate({ data: 'ㅇ' });
|
||||
textarea.value = '앙ㅇ';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionupdate({ data: '아' });
|
||||
textarea.value = '앙아';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionupdate({ data: '앙' });
|
||||
textarea.value = '앙앙';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionend();
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
assert.equal(handledText, '앙앙');
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('Should insert complex characters that change with following character', function (done) {
|
||||
// First character '아'
|
||||
compositionHelper.compositionstart();
|
||||
compositionHelper.compositionupdate({ data: 'ㅇ' });
|
||||
textarea.value = 'ㅇ';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionupdate({ data: '아' });
|
||||
textarea.value = '아';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
// Start second character '아' in first character
|
||||
compositionHelper.compositionupdate({ data: '앙' });
|
||||
textarea.value = '앙';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionend();
|
||||
compositionHelper.compositionstart();
|
||||
compositionHelper.compositionupdate({ data: '아' });
|
||||
textarea.value = '아아'
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionend();
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
assert.equal(handledText, '아아');
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('Should insert multi-characters compositions', function (done) {
|
||||
// First character 'だ'
|
||||
compositionHelper.compositionstart();
|
||||
compositionHelper.compositionupdate({ data: 'd' });
|
||||
textarea.value = 'd';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionupdate({ data: 'だ' });
|
||||
textarea.value = 'だ';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
// Second character 'あ'
|
||||
compositionHelper.compositionupdate({ data: 'だあ' });
|
||||
textarea.value = 'だあ';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionend();
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
assert.equal(handledText, 'だあ');
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('Should insert multi-character compositions that are converted to other characters with the same length', function (done) {
|
||||
// First character 'だ'
|
||||
compositionHelper.compositionstart();
|
||||
compositionHelper.compositionupdate({ data: 'd' });
|
||||
textarea.value = 'd';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionupdate({ data: 'だ' });
|
||||
textarea.value = 'だ';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
// Second character 'ー'
|
||||
compositionHelper.compositionupdate({ data: 'だー' });
|
||||
textarea.value = 'だー';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
// Convert to katakana 'ダー'
|
||||
compositionHelper.compositionupdate({ data: 'ダー' });
|
||||
textarea.value = 'ダー';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionend();
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
assert.equal(handledText, 'ダー');
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
})
|
||||
|
||||
it('Should insert multi-character compositions that are converted to other characters with different lengths', function (done) {
|
||||
// First character 'い'
|
||||
compositionHelper.compositionstart();
|
||||
compositionHelper.compositionupdate({ data: 'い' });
|
||||
textarea.value = 'い';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
// Second character 'ま'
|
||||
compositionHelper.compositionupdate({ data: 'いm' });
|
||||
textarea.value = 'いm';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionupdate({ data: 'いま' });
|
||||
textarea.value = 'いま';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
// Convert to kanji '今'
|
||||
compositionHelper.compositionupdate({ data: '今' });
|
||||
textarea.value = '今';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionend();
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
assert.equal(handledText, '今');
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('Should insert non-composition characters input immediately after composition characters', function (done) {
|
||||
// First character 'ㅇ'
|
||||
compositionHelper.compositionstart();
|
||||
compositionHelper.compositionupdate({ data: 'ㅇ' });
|
||||
textarea.value = 'ㅇ';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
compositionHelper.compositionend();
|
||||
// Second character '1' (a non-composition character)
|
||||
textarea.value = 'ㅇ1';
|
||||
setTimeout(function() { // wait for any textarea updates
|
||||
assert.equal(handledText, 'ㅇ1');
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
+74
-4
@@ -24,8 +24,8 @@ describe('xterm.js', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 33 }).key, '\x1b[5~'); // CSI 5 ~
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 34 }).key, '\x1b[6~'); // CSI 6 ~
|
||||
// End, Home
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 35 }).key, '\x1bOF'); // SS3 F
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 36 }).key, '\x1bOH'); // SS3 H
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 35 }).key, '\x1b[F'); // SS3 F
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 36 }).key, '\x1b[H'); // SS3 H
|
||||
// Left, up, right, down arrows
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 37 }).key, '\x1b[D'); // CSI D
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 38 }).key, '\x1b[A'); // CSI A
|
||||
@@ -50,10 +50,72 @@ describe('xterm.js', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 123 }).key, '\x1b[24~'); // CSI 2 4 ~
|
||||
});
|
||||
it('should return \\x1b[5D for ctrl+left', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 37 }).key, '\x1b[5D'); // CSI 5 D
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D
|
||||
});
|
||||
it('should return \\x1b[5C for ctrl+right', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 39 }).key, '\x1b[5C'); // CSI 5 C
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C
|
||||
});
|
||||
it('should return \\x1b[5A for ctrl+up', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A
|
||||
});
|
||||
it('should return \\x1b[5B for ctrl+down', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B
|
||||
});
|
||||
// Evalueate alt + arrow key movement, which is a feature of terminal emulators but not VT100
|
||||
// http://unix.stackexchange.com/a/108106
|
||||
it('should return \\x1b[5D for alt+left', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D
|
||||
});
|
||||
it('should return \\x1b[5C for alt+right', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C
|
||||
});
|
||||
it('should return \\x1b[5A for alt+up', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A
|
||||
});
|
||||
it('should return \\x1b[5B for alt+down', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B
|
||||
});
|
||||
});
|
||||
|
||||
describe('attachCustomEventHandler', function () {
|
||||
var evKeyDown = {
|
||||
preventDefault: function() {},
|
||||
stopPropagation: function() {},
|
||||
type: 'keydown'
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
xterm.handler = function() {};
|
||||
xterm.showCursor = function() {};
|
||||
xterm.clearSelection = function() {};
|
||||
xterm.compositionHelper = {
|
||||
keydown: {
|
||||
bind: function() {
|
||||
return function () { return true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should process the keydown event based on what the handler returns', function () {
|
||||
assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), true);
|
||||
xterm.attachCustomKeydownHandler(function (ev) {
|
||||
return ev.keyCode === 77;
|
||||
});
|
||||
assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), true);
|
||||
xterm.attachCustomKeydownHandler(function (ev) {
|
||||
return ev.keyCode !== 77;
|
||||
});
|
||||
assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), false);
|
||||
});
|
||||
|
||||
it('should alive after reset(ESC c Full Reset (RIS))', function () {
|
||||
xterm.attachCustomKeydownHandler(function (ev) {
|
||||
return ev.keyCode !== 77;
|
||||
});
|
||||
assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), false);
|
||||
xterm.reset();
|
||||
assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -87,6 +149,14 @@ describe('xterm.js', function() {
|
||||
xterm.handler = function() {};
|
||||
xterm.showCursor = function() {};
|
||||
xterm.clearSelection = function() {};
|
||||
xterm.compositionHelper = {
|
||||
isComposing: false,
|
||||
keydown: {
|
||||
bind: function() {
|
||||
return function() { return true; };
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
describe('On Mac OS', function() {
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
var assert = require('chai').assert;
|
||||
var Terminal = require('../src/xterm');
|
||||
|
||||
describe('Viewport', function () {
|
||||
var terminal;
|
||||
var viewportElement;
|
||||
var charMeasureElement;
|
||||
var viewport;
|
||||
|
||||
var CHARACTER_HEIGHT = 10;
|
||||
|
||||
beforeEach(function () {
|
||||
terminal = {
|
||||
lines: [],
|
||||
rows: 0,
|
||||
ydisp: 0,
|
||||
on: function () {},
|
||||
rowContainer: {
|
||||
style: {
|
||||
lineHeight: 0
|
||||
}
|
||||
}
|
||||
};
|
||||
viewportElement = {
|
||||
addEventListener: function () {},
|
||||
style: {
|
||||
height: 0,
|
||||
lineHeight: 0
|
||||
}
|
||||
};
|
||||
scrollAreaElement = {
|
||||
style: {
|
||||
height: 0
|
||||
}
|
||||
};
|
||||
charMeasureElement = {
|
||||
getBoundingClientRect: function () {
|
||||
return { width: null, height: CHARACTER_HEIGHT };
|
||||
}
|
||||
};
|
||||
viewport = new Terminal.Viewport(terminal, viewportElement, scrollAreaElement, charMeasureElement);
|
||||
});
|
||||
|
||||
describe('Public API', function () {
|
||||
it('should define Viewport.prototype.onWheel', function () {
|
||||
assert.isDefined(Terminal.Viewport.prototype.onWheel);
|
||||
});
|
||||
it('should define Viewport.prototype.setApplicationMode', function () {
|
||||
assert.isDefined(Terminal.Viewport.prototype.setApplicationMode);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setApplicationMode', function () {
|
||||
it('should restrict the scroll area to the viewport', function () {
|
||||
terminal.lines.push('');
|
||||
terminal.lines.push('');
|
||||
terminal.rows = 1;
|
||||
viewport.syncScrollArea();
|
||||
assert.equal(scrollAreaElement.style.height, 2 * CHARACTER_HEIGHT + 'px');
|
||||
viewport.setApplicationMode(true);
|
||||
assert.equal(scrollAreaElement.style.height, CHARACTER_HEIGHT + 'px');
|
||||
viewport.setApplicationMode(false);
|
||||
assert.equal(scrollAreaElement.style.height, 2 * CHARACTER_HEIGHT + 'px');
|
||||
});
|
||||
});
|
||||
|
||||
describe('refresh', function () {
|
||||
it('should set the line-height of the terminal', function () {
|
||||
assert.equal(viewportElement.style.lineHeight, CHARACTER_HEIGHT + 'px');
|
||||
assert.equal(terminal.rowContainer.style.lineHeight, CHARACTER_HEIGHT + 'px');
|
||||
charMeasureElement.getBoundingClientRect = function () {
|
||||
return { width: null, height: 1 };
|
||||
};
|
||||
viewport.refresh();
|
||||
assert.equal(viewportElement.style.lineHeight, '1px');
|
||||
assert.equal(terminal.rowContainer.style.lineHeight, '1px');
|
||||
});
|
||||
it('should set the height of the viewport when the line-height changed', function () {
|
||||
terminal.lines.push('');
|
||||
terminal.lines.push('');
|
||||
terminal.rows = 1;
|
||||
viewport.refresh();
|
||||
assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px');
|
||||
charMeasureElement.getBoundingClientRect = function () {
|
||||
return { width: null, height: 20 };
|
||||
};
|
||||
viewport.refresh();
|
||||
assert.equal(viewportElement.style.height, 20 + 'px');
|
||||
});
|
||||
});
|
||||
|
||||
describe('syncScrollArea', function () {
|
||||
it('should sync the scroll area', function () {
|
||||
terminal.lines.push('');
|
||||
terminal.rows = 1;
|
||||
assert.equal(scrollAreaElement.style.height, 0 * CHARACTER_HEIGHT + 'px');
|
||||
viewport.syncScrollArea();
|
||||
assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px');
|
||||
assert.equal(scrollAreaElement.style.height, 1 * CHARACTER_HEIGHT + 'px');
|
||||
terminal.lines.push('');
|
||||
viewport.syncScrollArea();
|
||||
assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px');
|
||||
assert.equal(scrollAreaElement.style.height, 2 * CHARACTER_HEIGHT + 'px');
|
||||
});
|
||||
});
|
||||
});
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 212 KiB |
Reference in New Issue
Block a user