Merge branch 'master' into fix_1879
This commit is contained in:
Vendored
+6
-5
@@ -23,10 +23,7 @@
|
|||||||
"type": "chrome",
|
"type": "chrome",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Demo Client",
|
"name": "Demo Client",
|
||||||
"url": "http://0.0.0.0:3000",
|
"url": "http://127.0.0.1:3000",
|
||||||
"windows": {
|
|
||||||
"url": "http://127.0.0.1:3000"
|
|
||||||
},
|
|
||||||
"webRoot": "${workspaceFolder}/"
|
"webRoot": "${workspaceFolder}/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -38,7 +35,11 @@
|
|||||||
"run",
|
"run",
|
||||||
"start-debug"
|
"start-debug"
|
||||||
],
|
],
|
||||||
"port": 9229
|
"port": 9229,
|
||||||
|
"serverReadyAction": {
|
||||||
|
"action": "openExternally",
|
||||||
|
"pattern": "App listening to (http://.*?:[0-9]+)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ Xterm.js is used in several world-class applications to provide great terminal e
|
|||||||
- [**Kubebox**](https://github.com/astefanutti/kubebox): Terminal console for Kubernetes clusters.
|
- [**Kubebox**](https://github.com/astefanutti/kubebox): Terminal console for Kubernetes clusters.
|
||||||
- [**Azure Cloud Shell**](https://shell.azure.com): Azure Cloud Shell is a Microsoft-managed admin machine built on Azure, for Azure.
|
- [**Azure Cloud Shell**](https://shell.azure.com): Azure Cloud Shell is a Microsoft-managed admin machine built on Azure, for Azure.
|
||||||
- [**atom-xterm**](https://atom.io/packages/atom-xterm): Atom plugin for providing terminals inside your Atom workspace.
|
- [**atom-xterm**](https://atom.io/packages/atom-xterm): Atom plugin for providing terminals inside your Atom workspace.
|
||||||
- [**rtty**](https://github.com/zhaojh329/rtty): A reverse proxy WebTTY. It is composed of the client and the server.
|
- [**rtty**](https://github.com/zhaojh329/rtty): Access your terminals from anywhere via the web.
|
||||||
- [**Pisth**](https://github.com/ColdGrub1384/Pisth): An SFTP and SSH client for iOS.
|
- [**Pisth**](https://github.com/ColdGrub1384/Pisth): An SFTP and SSH client for iOS.
|
||||||
- [**abstruse**](https://github.com/bleenco/abstruse): Abstruse CI is a continuous integration platform based on Node.JS and Docker.
|
- [**abstruse**](https://github.com/bleenco/abstruse): Abstruse CI is a continuous integration platform based on Node.JS and Docker.
|
||||||
- [**Azure Data Studio**](https://github.com/Microsoft/azuredatastudio): A data management tool that enables working with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux.
|
- [**Azure Data Studio**](https://github.com/Microsoft/azuredatastudio): A data management tool that enables working with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux.
|
||||||
@@ -154,6 +154,7 @@ Xterm.js is used in several world-class applications to provide great terminal e
|
|||||||
- [**webssh**](https://github.com/huashengdun/webssh): Web based ssh client.
|
- [**webssh**](https://github.com/huashengdun/webssh): Web based ssh client.
|
||||||
- [**info-beamer hosted**](https://info-beamer.com): Uses xterm.js to manage digital signage devices from the web dashboard.
|
- [**info-beamer hosted**](https://info-beamer.com): Uses xterm.js to manage digital signage devices from the web dashboard.
|
||||||
- [**Jumpserver**](https://github.com/jumpserver/luna): Jumpserver Luna project, Jumpserver is a bastion server project, Luna use xterm.js for web terminal emulation.
|
- [**Jumpserver**](https://github.com/jumpserver/luna): Jumpserver Luna project, Jumpserver is a bastion server project, Luna use xterm.js for web terminal emulation.
|
||||||
|
- [**LxdMosaic**](https://github.com/turtle0x1/LxdMosaic): Uses xterm.js to give terminal access to containers through LXD
|
||||||
|
|
||||||
[And much more...](https://github.com/xtermjs/xterm.js/network/dependents)
|
[And much more...](https://github.com/xtermjs/xterm.js/network/dependents)
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -30,7 +30,10 @@ Terminal.applyAddon(fit);
|
|||||||
Terminal.applyAddon(fullscreen);
|
Terminal.applyAddon(fullscreen);
|
||||||
Terminal.applyAddon(search);
|
Terminal.applyAddon(search);
|
||||||
Terminal.applyAddon(webLinks);
|
Terminal.applyAddon(webLinks);
|
||||||
Terminal.applyAddon(winptyCompat);
|
const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0;
|
||||||
|
if (isWindows) {
|
||||||
|
Terminal.applyAddon(winptyCompat);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let term;
|
let term;
|
||||||
@@ -99,7 +102,9 @@ function createTerminal(): void {
|
|||||||
socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/';
|
socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/';
|
||||||
|
|
||||||
term.open(terminalContainer);
|
term.open(terminalContainer);
|
||||||
term.winptyCompatInit();
|
if (isWindows) {
|
||||||
|
term.winptyCompatInit();
|
||||||
|
}
|
||||||
term.webLinksInit();
|
term.webLinksInit();
|
||||||
term.fit();
|
term.fit();
|
||||||
term.focus();
|
term.focus();
|
||||||
|
|||||||
+2
-2
@@ -2,8 +2,8 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>xterm.js demo</title>
|
<title>xterm.js demo</title>
|
||||||
<link rel="stylesheet" href="/build/xterm.css" />
|
<link rel="stylesheet" href="/src/xterm.css" />
|
||||||
<link rel="stylesheet" href="/build/addons/fullscreen/fullscreen.css" />
|
<link rel="stylesheet" href="/src/addons/fullscreen/fullscreen.css" />
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.auto.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.auto.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script>
|
||||||
|
|||||||
+2
-2
@@ -10,7 +10,7 @@ function startServer() {
|
|||||||
var terminals = {},
|
var terminals = {},
|
||||||
logs = {};
|
logs = {};
|
||||||
|
|
||||||
app.use('/build', express.static(__dirname + '/../build'));
|
app.use('/src', express.static(__dirname + '/../src'));
|
||||||
|
|
||||||
app.get('/', function(req, res){
|
app.get('/', function(req, res){
|
||||||
res.sendFile(__dirname + '/index.html');
|
res.sendFile(__dirname + '/index.html');
|
||||||
@@ -99,7 +99,7 @@ function startServer() {
|
|||||||
var port = process.env.PORT || 3000,
|
var port = process.env.PORT || 3000,
|
||||||
host = os.platform() === 'win32' ? '127.0.0.1' : '0.0.0.0';
|
host = os.platform() === 'win32' ? '127.0.0.1' : '0.0.0.0';
|
||||||
|
|
||||||
console.log('App listening to http://' + host + ':' + port);
|
console.log('App listening to http://127.0.0.1:' + port);
|
||||||
app.listen(port, host);
|
app.listen(port, host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
var express = require('express');
|
|
||||||
var app = express();
|
|
||||||
var expressWs = require('express-ws')(app);
|
|
||||||
var os = require('os');
|
|
||||||
var pty = require('node-pty');
|
|
||||||
|
|
||||||
var terminals = {},
|
|
||||||
logs = {};
|
|
||||||
|
|
||||||
app.use('/build', express.static(__dirname + '/../../build'));
|
|
||||||
app.use('/demo', express.static(__dirname + '/../../demo'));
|
|
||||||
app.use('/zmodemjs', express.static(__dirname + '/../../node_modules/zmodem.js/dist'));
|
|
||||||
|
|
||||||
app.get('/', function(req, res){
|
|
||||||
res.sendFile(__dirname + '/index.html');
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/style.css', function(req, res){
|
|
||||||
res.sendFile(__dirname + '../style.css');
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/main.js', function(req, res){
|
|
||||||
res.sendFile(__dirname + '/main.js');
|
|
||||||
});
|
|
||||||
|
|
||||||
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', [], {
|
|
||||||
encoding: null,
|
|
||||||
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);
|
|
||||||
} catch (ex) {
|
|
||||||
// The WebSocket is not open, ignore
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ws.on('message', function(msg) {
|
|
||||||
term.write(msg);
|
|
||||||
});
|
|
||||||
ws.on('close', function () {
|
|
||||||
term.kill();
|
|
||||||
console.log('Closed terminal ' + term.pid);
|
|
||||||
// Clean things up
|
|
||||||
delete terminals[term.pid];
|
|
||||||
delete logs[term.pid];
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var port = process.env.PORT || 3000,
|
|
||||||
host = os.platform() === 'win32' ? '127.0.0.1' : '0.0.0.0';
|
|
||||||
|
|
||||||
console.log('App listening to http://' + host + ':' + port);
|
|
||||||
app.listen(port, host);
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>xterm.js demo</title>
|
|
||||||
<link rel="stylesheet" href="/build/xterm.css" />
|
|
||||||
<link rel="stylesheet" href="/build/addons/fullscreen/fullscreen.css" />
|
|
||||||
<link rel="stylesheet" href="/demo/style.css" />
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.auto.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script>
|
|
||||||
<script src="/build/xterm.js" ></script>
|
|
||||||
|
|
||||||
<script src="/build/addons/attach/attach.js" ></script>
|
|
||||||
<script src="/zmodemjs/zmodem.js"></script>
|
|
||||||
<script src="/build/addons/zmodem/zmodem.js" ></script>
|
|
||||||
|
|
||||||
<script src="/build/addons/fit/fit.js" ></script>
|
|
||||||
<script src="/build/addons/fullscreen/fullscreen.js" ></script>
|
|
||||||
<script src="/build/addons/search/search.js" ></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>xterm.js: xterm, in the browser</h1>
|
|
||||||
|
|
||||||
<div id="terminal-container"></div>
|
|
||||||
|
|
||||||
<div id="zmodem_controls">
|
|
||||||
<form id="zm_start" style="display: none" action="javascript:void(0)">
|
|
||||||
ZMODEM detected: Start ZMODEM session?
|
|
||||||
<label><input id="zmstart_yes" name="zmstart" type=radio checked value="1"> Yes</label>
|
|
||||||
|
|
||||||
<label><input name="zmstart" type=radio value=""> No</label>
|
|
||||||
<button type="submit">Submit</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<form id="zm_offer" style="display: none" action="javascript:void(0)">
|
|
||||||
<p>ZMODEM File offered!</p>
|
|
||||||
|
|
||||||
<label><input id="zmaccept_yes" name="zmaccept" type=radio checked value="1"> Accept</label>
|
|
||||||
|
|
||||||
<label><input name="zmaccept" type=radio value=""> Skip</label>
|
|
||||||
<button type="submit">Submit</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div id="zm_file" style="display: none">
|
|
||||||
<div>Name: <span id="name"></span></div>
|
|
||||||
<div>Size: <span id="size"></span></div>
|
|
||||||
<div>Last modified: <span id="mtime"></span></div>
|
|
||||||
<div>Mode: <span id="mode"></span></div>
|
|
||||||
<br>
|
|
||||||
<div>Conversion: <span id="zfile_conversion"></span></div>
|
|
||||||
<div>Management: <span id="zfile_management"></span></div>
|
|
||||||
<div>Transport: <span id="zfile_transport"></span></div>
|
|
||||||
<div>Sparse? <span id="zfile_sparse"></span></div>
|
|
||||||
<br>
|
|
||||||
<div>Files remaining in batch: <span id="files_remaining"></span></div>
|
|
||||||
<div>Bytes remaining in batch: <span id="bytes_remaining"></span></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form id="zm_progress" style="display: none" action="javascript:void(0)">
|
|
||||||
<div><span id="percent_received"></span>% (<span id="bytes_received"></span> bytes) received</div>
|
|
||||||
<button id="zm_progress_skipper" type="button" onclick="skip_current_file();">Skip File</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<form id="zm_choose" style="display: none" action="javascript:void(0)">
|
|
||||||
<label>Choose file(s): <input id="zm_files" type="file" multiple></label>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h2>Actions</h2>
|
|
||||||
<p>
|
|
||||||
<label>Find next <input id="find-next"/></label>
|
|
||||||
<label>Find previous <input id="find-previous"/></label>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2>Options</h2>
|
|
||||||
<p>
|
|
||||||
<label><input type="checkbox" id="option-cursor-blink"> cursorBlink</label>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<label><input type="checkbox" checked id="zmodem-auto"> Accept all ZMODEM prompts<sup>*</sup></label>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<label>
|
|
||||||
cursorStyle
|
|
||||||
<select id="option-cursor-style">
|
|
||||||
<option value="block">block</option>
|
|
||||||
<option value="underline">underline</option>
|
|
||||||
<option value="bar">bar</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<label>
|
|
||||||
bellStyle
|
|
||||||
<select id="option-bell-style">
|
|
||||||
<option value="">none</option>
|
|
||||||
<option value="sound">sound</option>
|
|
||||||
<option value="visual">visual</option>
|
|
||||||
<option value="both">both</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<label>scrollback <input type="number" id="option-scrollback" value="1000" /></label>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<label>tabStopWidth <input type="number" id="option-tabstopwidth" value="8" /></label>
|
|
||||||
</p>
|
|
||||||
<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>
|
|
||||||
<p><sup>*</sup> ZMODEM file transfers are supported via an addon. To try it out, install <a href="https://ohse.de/uwe/software/lrzsz.html"><code>lrzsz</code></a> onto the remote peer, then run <code>rz</code> to send from your browser or <code>sz <file></code> to send from the remote peer.</p>
|
|
||||||
<script src="main.js" defer ></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,388 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
var term,
|
|
||||||
protocol,
|
|
||||||
socketURL,
|
|
||||||
socket,
|
|
||||||
pid;
|
|
||||||
|
|
||||||
Terminal.applyAddon(fit);
|
|
||||||
Terminal.applyAddon(attach);
|
|
||||||
Terminal.applyAddon(zmodem);
|
|
||||||
Terminal.applyAddon(search);
|
|
||||||
|
|
||||||
var terminalContainer = document.getElementById('terminal-container'),
|
|
||||||
actionElements = {
|
|
||||||
findNext: document.querySelector('#find-next'),
|
|
||||||
findPrevious: document.querySelector('#find-previous')
|
|
||||||
},
|
|
||||||
optionElements = {
|
|
||||||
cursorBlink: document.querySelector('#option-cursor-blink'),
|
|
||||||
cursorStyle: document.querySelector('#option-cursor-style'),
|
|
||||||
scrollback: document.querySelector('#option-scrollback'),
|
|
||||||
tabstopwidth: document.querySelector('#option-tabstopwidth'),
|
|
||||||
bellStyle: document.querySelector('#option-bell-style')
|
|
||||||
},
|
|
||||||
colsElement = document.getElementById('cols'),
|
|
||||||
rowsElement = document.getElementById('rows');
|
|
||||||
|
|
||||||
function setTerminalSize() {
|
|
||||||
var cols = parseInt(colsElement.value, 10);
|
|
||||||
var rows = parseInt(rowsElement.value, 10);
|
|
||||||
var viewportElement = document.querySelector('.xterm-viewport');
|
|
||||||
var scrollBarWidth = viewportElement.offsetWidth - viewportElement.clientWidth;
|
|
||||||
var width = (cols * term.charMeasure.width + 20 /*room for scrollbar*/).toString() + 'px';
|
|
||||||
var height = (rows * term.charMeasure.height).toString() + 'px';
|
|
||||||
|
|
||||||
terminalContainer.style.width = width;
|
|
||||||
terminalContainer.style.height = height;
|
|
||||||
term.resize(cols, rows);
|
|
||||||
}
|
|
||||||
|
|
||||||
colsElement.addEventListener('change', setTerminalSize);
|
|
||||||
rowsElement.addEventListener('change', setTerminalSize);
|
|
||||||
|
|
||||||
actionElements.findNext.addEventListener('keypress', function (e) {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
e.preventDefault();
|
|
||||||
term.findNext(actionElements.findNext.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
actionElements.findPrevious.addEventListener('keypress', function (e) {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
e.preventDefault();
|
|
||||||
term.findPrevious(actionElements.findPrevious.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
optionElements.cursorBlink.addEventListener('change', function () {
|
|
||||||
term.setOption('cursorBlink', optionElements.cursorBlink.checked);
|
|
||||||
});
|
|
||||||
optionElements.cursorStyle.addEventListener('change', function () {
|
|
||||||
term.setOption('cursorStyle', optionElements.cursorStyle.value);
|
|
||||||
});
|
|
||||||
optionElements.bellStyle.addEventListener('change', function () {
|
|
||||||
term.setOption('bellStyle', optionElements.bellStyle.value);
|
|
||||||
});
|
|
||||||
optionElements.scrollback.addEventListener('change', function () {
|
|
||||||
term.setOption('scrollback', parseInt(optionElements.scrollback.value, 10));
|
|
||||||
});
|
|
||||||
optionElements.tabstopwidth.addEventListener('change', function () {
|
|
||||||
term.setOption('tabStopWidth', parseInt(optionElements.tabstopwidth.value, 10));
|
|
||||||
});
|
|
||||||
|
|
||||||
createTerminal();
|
|
||||||
|
|
||||||
function createTerminal() {
|
|
||||||
// Clean terminal
|
|
||||||
while (terminalContainer.children.length) {
|
|
||||||
terminalContainer.removeChild(terminalContainer.children[0]);
|
|
||||||
}
|
|
||||||
term = new Terminal({
|
|
||||||
cursorBlink: optionElements.cursorBlink.checked,
|
|
||||||
scrollback: parseInt(optionElements.scrollback.value, 10),
|
|
||||||
tabStopWidth: parseInt(optionElements.tabstopwidth.value, 10)
|
|
||||||
});
|
|
||||||
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) : '') + '/terminals/';
|
|
||||||
|
|
||||||
term.open(terminalContainer);
|
|
||||||
term.fit();
|
|
||||||
|
|
||||||
// fit is called within a setTimeout, cols and rows need this.
|
|
||||||
setTimeout(function () {
|
|
||||||
colsElement.value = term.cols;
|
|
||||||
rowsElement.value = term.rows;
|
|
||||||
|
|
||||||
// Set terminal size again to set the specific dimensions on the demo
|
|
||||||
setTerminalSize();
|
|
||||||
|
|
||||||
fetch('/terminals?cols=' + term.cols + '&rows=' + term.rows, {method: 'POST'}).then(function (res) {
|
|
||||||
|
|
||||||
res.text().then(function (pid) {
|
|
||||||
window.pid = pid;
|
|
||||||
socketURL += pid;
|
|
||||||
socket = new WebSocket(socketURL);
|
|
||||||
socket.onopen = runRealTerminal;
|
|
||||||
socket.onclose = runFakeTerminal;
|
|
||||||
socket.onerror = runFakeTerminal;
|
|
||||||
|
|
||||||
term.zmodemAttach(socket, {
|
|
||||||
noTerminalWriteOutsideSession: true,
|
|
||||||
} );
|
|
||||||
|
|
||||||
term.on("zmodemRetract", () => {
|
|
||||||
start_form.style.display = "none";
|
|
||||||
start_form.onsubmit = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
term.on("zmodemDetect", (detection) => {
|
|
||||||
function do_zmodem() {
|
|
||||||
term.detach();
|
|
||||||
let zsession = detection.confirm();
|
|
||||||
|
|
||||||
var promise;
|
|
||||||
|
|
||||||
if (zsession.type === "receive") {
|
|
||||||
promise = _handle_receive_session(zsession);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
promise = _handle_send_session(zsession);
|
|
||||||
}
|
|
||||||
|
|
||||||
promise.catch( console.error.bind(console) ).then( () => {
|
|
||||||
term.attach(socket);
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_auto_zmodem()) {
|
|
||||||
do_zmodem();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
start_form.style.display = "";
|
|
||||||
start_form.onsubmit = function(e) {
|
|
||||||
start_form.style.display = "none";
|
|
||||||
|
|
||||||
if (document.getElementById("zmstart_yes").checked) {
|
|
||||||
do_zmodem();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
detection.deny();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
|
||||||
// UI STUFF
|
|
||||||
|
|
||||||
function _show_file_info(xfer) {
|
|
||||||
var file_info = xfer.get_details();
|
|
||||||
|
|
||||||
document.getElementById("name").textContent = file_info.name;
|
|
||||||
document.getElementById("size").textContent = file_info.size;
|
|
||||||
document.getElementById("mtime").textContent = file_info.mtime;
|
|
||||||
document.getElementById("files_remaining").textContent = file_info.files_remaining;
|
|
||||||
document.getElementById("bytes_remaining").textContent = file_info.bytes_remaining;
|
|
||||||
|
|
||||||
document.getElementById("mode").textContent = "0" + file_info.mode.toString(8);
|
|
||||||
|
|
||||||
var xfer_opts = xfer.get_options();
|
|
||||||
["conversion", "management", "transport", "sparse"].forEach( (lbl) => {
|
|
||||||
document.getElementById(`zfile_${lbl}`).textContent = xfer_opts[lbl];
|
|
||||||
} );
|
|
||||||
|
|
||||||
document.getElementById("zm_file").style.display = "";
|
|
||||||
}
|
|
||||||
function _hide_file_info() {
|
|
||||||
document.getElementById("zm_file").style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
function _save_to_disk(xfer, buffer) {
|
|
||||||
return Zmodem.Browser.save_to_disk(buffer, xfer.get_details().name);
|
|
||||||
}
|
|
||||||
|
|
||||||
var skipper_button = document.getElementById("zm_progress_skipper");
|
|
||||||
var skipper_button_orig_text = skipper_button.textContent;
|
|
||||||
|
|
||||||
function _show_progress() {
|
|
||||||
skipper_button.disabled = false;
|
|
||||||
skipper_button.textContent = skipper_button_orig_text;
|
|
||||||
|
|
||||||
document.getElementById("bytes_received").textContent = 0;
|
|
||||||
document.getElementById("percent_received").textContent = 0;
|
|
||||||
|
|
||||||
document.getElementById("zm_progress").style.display = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
function _update_progress(xfer) {
|
|
||||||
var total_in = xfer.get_offset();
|
|
||||||
|
|
||||||
document.getElementById("bytes_received").textContent = total_in;
|
|
||||||
|
|
||||||
var percent_received = 100 * total_in / xfer.get_details().size;
|
|
||||||
document.getElementById("percent_received").textContent = percent_received.toFixed(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _hide_progress() {
|
|
||||||
document.getElementById("zm_progress").style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
var start_form = document.getElementById("zm_start");
|
|
||||||
|
|
||||||
function _auto_zmodem() {
|
|
||||||
return document.getElementById("zmodem-auto").checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
// END UI STUFF
|
|
||||||
//----------------------------------------------------------------------
|
|
||||||
|
|
||||||
function _handle_receive_session(zsession) {
|
|
||||||
zsession.on("offer", function(xfer) {
|
|
||||||
current_receive_xfer = xfer;
|
|
||||||
|
|
||||||
_show_file_info(xfer);
|
|
||||||
|
|
||||||
var offer_form = document.getElementById("zm_offer");
|
|
||||||
|
|
||||||
function on_form_submit() {
|
|
||||||
offer_form.style.display = "none";
|
|
||||||
|
|
||||||
//START
|
|
||||||
//if (offer_form.zmaccept.value) {
|
|
||||||
if (_auto_zmodem() || document.getElementById("zmaccept_yes").checked) {
|
|
||||||
_show_progress();
|
|
||||||
|
|
||||||
var FILE_BUFFER = [];
|
|
||||||
xfer.on("input", (payload) => {
|
|
||||||
_update_progress(xfer);
|
|
||||||
FILE_BUFFER.push( new Uint8Array(payload) );
|
|
||||||
});
|
|
||||||
xfer.accept().then(
|
|
||||||
() => {
|
|
||||||
_save_to_disk(xfer, FILE_BUFFER);
|
|
||||||
},
|
|
||||||
console.error.bind(console)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
xfer.skip();
|
|
||||||
}
|
|
||||||
//END
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_auto_zmodem()) {
|
|
||||||
on_form_submit();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
offer_form.onsubmit = on_form_submit;
|
|
||||||
offer_form.style.display = "";
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
var promise = new Promise( (res) => {
|
|
||||||
zsession.on("session_end", () => {
|
|
||||||
_hide_file_info();
|
|
||||||
_hide_progress();
|
|
||||||
res();
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
|
|
||||||
zsession.start();
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _handle_send_session(zsession) {
|
|
||||||
var choose_form = document.getElementById("zm_choose");
|
|
||||||
choose_form.style.display = "";
|
|
||||||
|
|
||||||
var file_el = document.getElementById("zm_files");
|
|
||||||
|
|
||||||
var promise = new Promise( (res) => {
|
|
||||||
file_el.onchange = function(e) {
|
|
||||||
choose_form.style.display = "none";
|
|
||||||
|
|
||||||
var files_obj = file_el.files;
|
|
||||||
|
|
||||||
Zmodem.Browser.send_files(
|
|
||||||
zsession,
|
|
||||||
files_obj,
|
|
||||||
{
|
|
||||||
on_offer_response(obj, xfer) {
|
|
||||||
if (xfer) _show_progress();
|
|
||||||
//console.log("offer", xfer ? "accepted" : "skipped");
|
|
||||||
},
|
|
||||||
on_progress(obj, xfer) {
|
|
||||||
_update_progress(xfer);
|
|
||||||
},
|
|
||||||
on_file_complete(obj) {
|
|
||||||
//console.log("COMPLETE", obj);
|
|
||||||
_hide_progress();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
).then(_hide_progress).then(
|
|
||||||
zsession.close.bind(zsession),
|
|
||||||
console.error.bind(console)
|
|
||||||
).then( () => {
|
|
||||||
_hide_file_info();
|
|
||||||
_hide_progress();
|
|
||||||
res();
|
|
||||||
} );
|
|
||||||
};
|
|
||||||
} );
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
//This is here to allow canceling of an in-progress ZMODEM transfer.
|
|
||||||
var current_receive_xfer;
|
|
||||||
|
|
||||||
//Called from HTML directly.
|
|
||||||
function skip_current_file() {
|
|
||||||
current_receive_xfer.skip();
|
|
||||||
|
|
||||||
skipper_button.disabled = true;
|
|
||||||
skipper_button.textContent = "Waiting for server to acknowledge skip …";
|
|
||||||
}
|
|
||||||
|
|
||||||
function runRealTerminal() {
|
|
||||||
term.attach(socket);
|
|
||||||
|
|
||||||
term._initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function runFakeTerminal() {
|
|
||||||
if (term._initialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
term._initialized = true;
|
|
||||||
|
|
||||||
var shellprompt = '$ ';
|
|
||||||
|
|
||||||
term.prompt = function () {
|
|
||||||
term.write('\r\n' + shellprompt);
|
|
||||||
};
|
|
||||||
|
|
||||||
term.writeln('Welcome to xterm.js');
|
|
||||||
term.writeln('This is a local terminal emulation, without a real terminal in the back-end.');
|
|
||||||
term.writeln('Type some keys and commands to play around.');
|
|
||||||
term.writeln('');
|
|
||||||
term.prompt();
|
|
||||||
|
|
||||||
term.on('key', function (key, ev) {
|
|
||||||
var printable = (
|
|
||||||
!ev.altKey && !ev.altGraphKey && !ev.ctrlKey && !ev.metaKey
|
|
||||||
);
|
|
||||||
|
|
||||||
if (ev.keyCode == 13) {
|
|
||||||
term.prompt();
|
|
||||||
} else if (ev.keyCode == 8) {
|
|
||||||
// Do not delete the prompt
|
|
||||||
if (term.x > 2) {
|
|
||||||
term.write('\b \b');
|
|
||||||
}
|
|
||||||
} else if (printable) {
|
|
||||||
term.write(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
term.on('paste', function (data, ev) {
|
|
||||||
term.write(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
+1
-1
@@ -7,7 +7,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./:/usr/src/app
|
- ./:/usr/src/app
|
||||||
ports:
|
ports:
|
||||||
- ${XTERMJS_PORT:3000}:3000
|
- ${XTERMJS_PORT:-3000}:3000
|
||||||
command: ["npm", "start"]
|
command: ["npm", "start"]
|
||||||
|
|
||||||
watch:
|
watch:
|
||||||
|
|||||||
+5
-5
@@ -16,9 +16,9 @@ const ts = require('gulp-typescript');
|
|||||||
const util = require('gulp-util');
|
const util = require('gulp-util');
|
||||||
|
|
||||||
const buildDir = process.env.BUILD_DIR || 'build';
|
const buildDir = process.env.BUILD_DIR || 'build';
|
||||||
const tsProject = ts.createProject('tsconfig.json');
|
const tsProject = ts.createProject('src/tsconfig.json');
|
||||||
let srcDir = tsProject.config.compilerOptions.rootDir;
|
let srcDir = './src';
|
||||||
let outDir = tsProject.config.compilerOptions.outDir;
|
let outDir = './lib';
|
||||||
|
|
||||||
const addons = fs.readdirSync(`${__dirname}/src/addons`);
|
const addons = fs.readdirSync(`${__dirname}/src/addons`);
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ gulp.task('browserify', function() {
|
|||||||
};
|
};
|
||||||
let bundleStream = browserify(browserifyOptions)
|
let bundleStream = browserify(browserifyOptions)
|
||||||
.bundle()
|
.bundle()
|
||||||
.pipe(source('xterm.js'))
|
.pipe(source(`xterm.js`))
|
||||||
.pipe(buffer())
|
.pipe(buffer())
|
||||||
.pipe(sourcemaps.init({loadMaps: true, sourceRoot: '..'}))
|
.pipe(sourcemaps.init({loadMaps: true, sourceRoot: '..'}))
|
||||||
.pipe(sourcemaps.write('./'))
|
.pipe(sourcemaps.write('./'))
|
||||||
@@ -136,6 +136,6 @@ gulp.task('sorcery-addons', ['browserify-addons'], function () {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('build', ['sorcery', 'sorcery-addons']);
|
gulp.task('build', ['css', 'sorcery', 'sorcery-addons']);
|
||||||
gulp.task('test', ['mocha']);
|
gulp.task('test', ['mocha']);
|
||||||
gulp.task('default', ['build']);
|
gulp.task('default', ['build']);
|
||||||
|
|||||||
+4
-9
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "xterm",
|
"name": "xterm",
|
||||||
"description": "Full xterm terminal, in your browser",
|
"description": "Full xterm terminal, in your browser",
|
||||||
"version": "3.11.0",
|
"version": "3.12.0",
|
||||||
"main": "lib/public/Terminal.js",
|
"main": "lib/public/Terminal.js",
|
||||||
"types": "typings/xterm.d.ts",
|
"types": "typings/xterm.d.ts",
|
||||||
"repository": "https://github.com/xtermjs/xterm.js",
|
"repository": "https://github.com/xtermjs/xterm.js",
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
"@types/webpack": "^4.4.11",
|
"@types/webpack": "^4.4.11",
|
||||||
"browserify": "^13.3.0",
|
"browserify": "^13.3.0",
|
||||||
"chai": "3.5.0",
|
"chai": "3.5.0",
|
||||||
"concurrently": "^3.5.1",
|
|
||||||
"coveralls": "^3.0.1",
|
"coveralls": "^3.0.1",
|
||||||
"express": "4.13.4",
|
"express": "4.13.4",
|
||||||
"express-ws": "2.0.0-rc.1",
|
"express-ws": "2.0.0-rc.1",
|
||||||
@@ -38,7 +37,7 @@
|
|||||||
"ts-loader": "^4.5.0",
|
"ts-loader": "^4.5.0",
|
||||||
"tslint": "^5.9.1",
|
"tslint": "^5.9.1",
|
||||||
"tslint-consistent-codestyle": "^1.13.0",
|
"tslint-consistent-codestyle": "^1.13.0",
|
||||||
"typescript": "3.1",
|
"typescript": "3.4",
|
||||||
"vinyl-buffer": "^1.0.0",
|
"vinyl-buffer": "^1.0.0",
|
||||||
"vinyl-source-stream": "^1.1.0",
|
"vinyl-source-stream": "^1.1.0",
|
||||||
"webpack": "^4.17.1",
|
"webpack": "^4.17.1",
|
||||||
@@ -50,20 +49,16 @@
|
|||||||
"start-debug": "node --inspect-brk demo/start",
|
"start-debug": "node --inspect-brk demo/start",
|
||||||
"start-zmodem": "node demo/zmodem/app",
|
"start-zmodem": "node demo/zmodem/app",
|
||||||
"lint": "tslint 'src/**/*.ts' './demo/**/*.ts'",
|
"lint": "tslint 'src/**/*.ts' './demo/**/*.ts'",
|
||||||
"pretest": "npm run layering",
|
|
||||||
"test": "npm run mocha",
|
"test": "npm run mocha",
|
||||||
"posttest": "npm run lint",
|
"posttest": "npm run lint",
|
||||||
"test-debug": "node --inspect-brk node_modules/.bin/gulp test",
|
"test-debug": "node --inspect-brk node_modules/.bin/gulp test",
|
||||||
"test-suite": "gulp mocha-suite --test",
|
"test-suite": "gulp mocha-suite --test",
|
||||||
"test-coverage": "nyc -x gulpfile.js -x '**/*test*' npm run mocha",
|
"test-coverage": "nyc -x gulpfile.js -x '**/*test*' npm run mocha",
|
||||||
"mocha": "gulp test",
|
"mocha": "gulp test",
|
||||||
"tsc": "tsc",
|
"prebuild": "tsc -b ./src/tsconfig.all.json",
|
||||||
"prebuild": "concurrently --kill-others-on-fail --names \"lib,attach,fit,fullscreen,search,terminado,webLinks,winptyCompat,zmodem,css\" \"tsc\" \"tsc -p ./src/addons/attach\" \"tsc -p ./src/addons/fit\" \"tsc -p ./src/addons/fullscreen\" \"tsc -p ./src/addons/search\" \"tsc -p ./src/addons/terminado\" \"tsc -p ./src/addons/webLinks\" \"tsc -p ./src/addons/winptyCompat\" \"tsc -p ./src/addons/zmodem\" \"gulp css\"",
|
|
||||||
"build": "gulp build",
|
"build": "gulp build",
|
||||||
"prepublish": "npm run build",
|
"prepublish": "npm run build",
|
||||||
"coveralls": "nyc report --reporter=text-lcov | coveralls",
|
"coveralls": "nyc report --reporter=text-lcov | coveralls",
|
||||||
"watch": "concurrently --kill-others-on-fail --names \"lib,css\" \"tsc -w\" \"gulp watch-css\"",
|
"watch": "tsc -b -w ./src/tsconfig.all.json --preserveWatchOutput"
|
||||||
"watch-addons": "concurrently --kill-others-on-fail --names \"attach,fit,fullscreen,search,terminado,webLinks,winptyCompat,zmodem\" \"tsc -w -p ./src/addons/attach\" \"tsc -w -p ./src/addons/fit\" \"tsc -w -p ./src/addons/fullscreen\" \"tsc -w -p ./src/addons/search\" \"tsc -w -p ./src/addons/terminado\" \"tsc -w -p ./src/addons/webLinks\" \"tsc -w -p ./src/addons/winptyCompat\" \"tsc -w -p ./src/addons/zmodem\"",
|
|
||||||
"layering": "concurrently --kill-others-on-fail --names \"common,core\" \"tsc -p ./src/common\" \"tsc -p ./src/core\""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -211,7 +211,7 @@ export class Buffer implements IBuffer {
|
|||||||
|
|
||||||
this.scrollBottom = newRows - 1;
|
this.scrollBottom = newRows - 1;
|
||||||
|
|
||||||
if (this._hasScrollback) {
|
if (this._isReflowEnabled) {
|
||||||
this._reflow(newCols, newRows);
|
this._reflow(newCols, newRows);
|
||||||
|
|
||||||
// Trim the end of the line off if cols shrunk
|
// Trim the end of the line off if cols shrunk
|
||||||
@@ -226,6 +226,10 @@ export class Buffer implements IBuffer {
|
|||||||
this._rows = newRows;
|
this._rows = newRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get _isReflowEnabled(): boolean {
|
||||||
|
return this._hasScrollback && !(this._terminal as any).isWinptyCompatEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
private _reflow(newCols: number, newRows: number): void {
|
private _reflow(newCols: number, newRows: number): void {
|
||||||
if (this._cols === newCols) {
|
if (this._cols === newCols) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+23
-21
@@ -64,10 +64,12 @@ const document = (typeof window !== 'undefined') ? window.document : null;
|
|||||||
const WRITE_BUFFER_PAUSE_THRESHOLD = 5;
|
const WRITE_BUFFER_PAUSE_THRESHOLD = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of writes to perform in a single batch before allowing the
|
* The max number of ms to spend on writes before allowing the renderer to
|
||||||
* renderer to catch up with a 0ms setTimeout.
|
* catch up with a 0ms setTimeout. A value of < 33 to keep us close to
|
||||||
|
* 30fps, and a value of < 16 to try to run at 60fps. Of course, the real FPS
|
||||||
|
* depends on the time it takes for the renderer to draw the frame.
|
||||||
*/
|
*/
|
||||||
const WRITE_BATCH_SIZE = 300;
|
const WRITE_TIMEOUT_MS = 12;
|
||||||
|
|
||||||
const MINIMUM_COLS = 2; // Less than 2 can mess with wide chars
|
const MINIMUM_COLS = 2; // Less than 2 can mess with wide chars
|
||||||
const MINIMUM_ROWS = 1;
|
const MINIMUM_ROWS = 1;
|
||||||
@@ -341,7 +343,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
|
|||||||
*/
|
*/
|
||||||
public focus(): void {
|
public focus(): void {
|
||||||
if (this.textarea) {
|
if (this.textarea) {
|
||||||
this.textarea.focus();
|
this.textarea.focus({ preventScroll: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -859,17 +861,11 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
|
|||||||
if (ch > 127) ch = 127;
|
if (ch > 127) ch = 127;
|
||||||
data.push(ch);
|
data.push(ch);
|
||||||
} else {
|
} else {
|
||||||
if (ch === 2047) {
|
if (ch > 2047) {
|
||||||
data.push(0);
|
data.push(2047);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ch < 127) {
|
data.push(ch);
|
||||||
data.push(ch);
|
|
||||||
} else {
|
|
||||||
if (ch > 2047) ch = 2047;
|
|
||||||
data.push(0xC0 | (ch >> 6));
|
|
||||||
data.push(0x80 | (ch & 0x3F));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1348,19 +1344,20 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _innerWrite(): void {
|
protected _innerWrite(bufferOffset: number = 0): void {
|
||||||
// Ensure the terminal isn't disposed
|
// Ensure the terminal isn't disposed
|
||||||
if (this._isDisposed) {
|
if (this._isDisposed) {
|
||||||
this.writeBuffer = [];
|
this.writeBuffer = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const writeBatch = this.writeBuffer.splice(0, WRITE_BATCH_SIZE);
|
const startTime = Date.now();
|
||||||
while (writeBatch.length > 0) {
|
while (this.writeBuffer.length > bufferOffset) {
|
||||||
const data = writeBatch.shift();
|
const data = this.writeBuffer[bufferOffset];
|
||||||
|
bufferOffset++;
|
||||||
|
|
||||||
// If XOFF was sent in order to catch up with the pty process, resume it if
|
// If XOFF was sent in order to catch up with the pty process, resume it if
|
||||||
// the writeBuffer is empty to allow more data to come in.
|
// we reached the end of the writeBuffer to allow more data to come in.
|
||||||
if (this._xoffSentToCatchUp && writeBatch.length === 0 && this.writeBuffer.length === 0) {
|
if (this._xoffSentToCatchUp && this.writeBuffer.length === bufferOffset) {
|
||||||
this.handler(C0.DC1);
|
this.handler(C0.DC1);
|
||||||
this._xoffSentToCatchUp = false;
|
this._xoffSentToCatchUp = false;
|
||||||
}
|
}
|
||||||
@@ -1378,12 +1375,17 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
|
|||||||
|
|
||||||
this.updateRange(this.buffer.y);
|
this.updateRange(this.buffer.y);
|
||||||
this.refresh(this._refreshStart, this._refreshEnd);
|
this.refresh(this._refreshStart, this._refreshEnd);
|
||||||
|
|
||||||
|
if (Date.now() - startTime >= WRITE_TIMEOUT_MS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.writeBuffer.length > 0) {
|
if (this.writeBuffer.length > bufferOffset) {
|
||||||
// Allow renderer to catch up before processing the next batch
|
// Allow renderer to catch up before processing the next batch
|
||||||
setTimeout(() => this._innerWrite(), 0);
|
setTimeout(() => this._innerWrite(bufferOffset), 0);
|
||||||
} else {
|
} else {
|
||||||
this._writeInProgress = false;
|
this._writeInProgress = false;
|
||||||
|
this.writeBuffer = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,7 @@
|
|||||||
"outDir": "../../../lib/addons/attach/",
|
"outDir": "../../../lib/addons/attach/",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"declaration": true,
|
"declaration": true
|
||||||
"preserveWatchOutput": true
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"**/*.ts",
|
"**/*.ts",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"preserveWatchOutput": true,
|
|
||||||
"types": [
|
"types": [
|
||||||
"../../node_modules/@types/mocha"
|
"../../node_modules/@types/mocha"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"preserveWatchOutput": true,
|
|
||||||
"types": [
|
"types": [
|
||||||
"../../node_modules/@types/mocha"
|
"../../node_modules/@types/mocha"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"preserveWatchOutput": true,
|
|
||||||
"types": [
|
"types": [
|
||||||
"../../node_modules/@types/mocha"
|
"../../node_modules/@types/mocha"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"preserveWatchOutput": true,
|
|
||||||
"types": [
|
"types": [
|
||||||
"../../node_modules/@types/mocha"
|
"../../node_modules/@types/mocha"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"preserveWatchOutput": true,
|
|
||||||
"types": [
|
"types": [
|
||||||
"../../node_modules/@types/mocha"
|
"../../node_modules/@types/mocha"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"preserveWatchOutput": true,
|
|
||||||
"types": [
|
"types": [
|
||||||
"../../node_modules/@types/mocha"
|
"../../node_modules/@types/mocha"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -13,11 +13,7 @@ const WHITESPACE_CELL_CODE = 32;
|
|||||||
export function winptyCompatInit(terminal: Terminal): void {
|
export function winptyCompatInit(terminal: Terminal): void {
|
||||||
const addonTerminal = <IWinptyCompatAddonTerminal>terminal;
|
const addonTerminal = <IWinptyCompatAddonTerminal>terminal;
|
||||||
|
|
||||||
// Don't do anything when the platform is not Windows
|
(addonTerminal._core as any).isWinptyCompatEnabled = true;
|
||||||
const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0;
|
|
||||||
if (!isWindows) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Winpty does not support wraparound mode which means that lines will never
|
// Winpty does not support wraparound mode which means that lines will never
|
||||||
// be marked as wrapped. This causes issues for things like copying a line
|
// be marked as wrapped. This causes issues for things like copying a line
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"preserveWatchOutput": true,
|
|
||||||
"types": [
|
"types": [
|
||||||
"../../node_modules/@types/mocha"
|
"../../node_modules/@types/mocha"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,17 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"extends": "../tsconfig-library-base",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"outDir": "../../lib"
|
||||||
"lib": [
|
|
||||||
"es5"
|
|
||||||
],
|
|
||||||
"rootDir": ".",
|
|
||||||
"noEmit": true,
|
|
||||||
"strict": true,
|
|
||||||
"pretty": true,
|
|
||||||
"types": [
|
|
||||||
"../../node_modules/@types/mocha",
|
|
||||||
"../../"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./**/*"
|
"./**/*"
|
||||||
|
|||||||
+6
-14
@@ -1,20 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"extends": "../tsconfig-library-base",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"outDir": "../../lib"
|
||||||
"lib": [
|
|
||||||
"es5"
|
|
||||||
],
|
|
||||||
"rootDir": ".",
|
|
||||||
"noEmit": true,
|
|
||||||
"strict": true,
|
|
||||||
"pretty": true,
|
|
||||||
"types": [
|
|
||||||
"../../node_modules/@types/mocha",
|
|
||||||
"../../"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./**/*",
|
"./**/*"
|
||||||
"../common/**/*"
|
],
|
||||||
|
"references": [
|
||||||
|
{ "path": "../common" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
|||||||
this._ctx.fillText(
|
this._ctx.fillText(
|
||||||
charData[CHAR_DATA_CHAR_INDEX],
|
charData[CHAR_DATA_CHAR_INDEX],
|
||||||
x * this._scaledCellWidth + this._scaledCharLeft,
|
x * this._scaledCellWidth + this._scaledCharLeft,
|
||||||
(y + 0.5) * this._scaledCellHeight + this._scaledCharTop);
|
y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -316,7 +316,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
|||||||
this._ctx.fillText(
|
this._ctx.fillText(
|
||||||
chars,
|
chars,
|
||||||
x * this._scaledCellWidth + this._scaledCharLeft,
|
x * this._scaledCellWidth + this._scaledCharLeft,
|
||||||
(y + 0.5) * this._scaledCellHeight + this._scaledCharTop);
|
y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight / 2);
|
||||||
this._ctx.restore();
|
this._ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ export class Renderer extends EventEmitter implements IRenderer {
|
|||||||
this._isPaused = entry.intersectionRatio === 0;
|
this._isPaused = entry.intersectionRatio === 0;
|
||||||
if (!this._isPaused && this._needsFullRefresh) {
|
if (!this._isPaused && this._needsFullRefresh) {
|
||||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||||
|
this._needsFullRefresh = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ITheme } from 'xterm';
|
|||||||
import { EventEmitter } from '../../common/EventEmitter';
|
import { EventEmitter } from '../../common/EventEmitter';
|
||||||
import { ColorManager } from '../ColorManager';
|
import { ColorManager } from '../ColorManager';
|
||||||
import { RenderDebouncer } from '../../ui/RenderDebouncer';
|
import { RenderDebouncer } from '../../ui/RenderDebouncer';
|
||||||
import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from './DomRendererRowFactory';
|
import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from './DomRendererRowFactory';
|
||||||
import { INVERTED_DEFAULT_COLOR } from '../atlas/Types';
|
import { INVERTED_DEFAULT_COLOR } from '../atlas/Types';
|
||||||
|
|
||||||
const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-';
|
const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-';
|
||||||
@@ -75,7 +75,7 @@ export class DomRenderer extends EventEmitter implements IRenderer {
|
|||||||
this._updateDimensions();
|
this._updateDimensions();
|
||||||
|
|
||||||
this._renderDebouncer = new RenderDebouncer(this._terminal, this._renderRows.bind(this));
|
this._renderDebouncer = new RenderDebouncer(this._terminal, this._renderRows.bind(this));
|
||||||
this._rowFactory = new DomRendererRowFactory(document);
|
this._rowFactory = new DomRendererRowFactory(_terminal.options, document);
|
||||||
|
|
||||||
this._terminal.element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass);
|
this._terminal.element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass);
|
||||||
this._terminal.screenElement.appendChild(this._rowContainer);
|
this._terminal.screenElement.appendChild(this._rowContainer);
|
||||||
@@ -165,12 +165,22 @@ export class DomRenderer extends EventEmitter implements IRenderer {
|
|||||||
`${this._terminalSelector} span.${ITALIC_CLASS} {` +
|
`${this._terminalSelector} span.${ITALIC_CLASS} {` +
|
||||||
` font-style: italic;` +
|
` font-style: italic;` +
|
||||||
`}`;
|
`}`;
|
||||||
|
// Blink animation
|
||||||
|
styles +=
|
||||||
|
`@keyframes blink {` +
|
||||||
|
` 0 % { opacity: 1.0; }` +
|
||||||
|
` 50% { opacity: 0.0; }` +
|
||||||
|
` 100 % { opacity: 1.0; }` +
|
||||||
|
`}`;
|
||||||
// Cursor
|
// Cursor
|
||||||
styles +=
|
styles +=
|
||||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}:not(.${FOCUS_CLASS}) .${CURSOR_CLASS} {` +
|
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}:not(.${FOCUS_CLASS}) .${CURSOR_CLASS} {` +
|
||||||
` outline: 1px solid ${this.colorManager.colors.cursor.css};` +
|
` outline: 1px solid ${this.colorManager.colors.cursor.css};` +
|
||||||
` outline-offset: -1px;` +
|
` outline-offset: -1px;` +
|
||||||
`}` +
|
`}` +
|
||||||
|
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_BLINK_CLASS} {` +
|
||||||
|
` animation: blink 1s step-end infinite;` +
|
||||||
|
`}` +
|
||||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BLOCK_CLASS} {` +
|
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BLOCK_CLASS} {` +
|
||||||
` background-color: ${this.colorManager.colors.cursor.css};` +
|
` background-color: ${this.colorManager.colors.cursor.css};` +
|
||||||
` color: ${this.colorManager.colors.cursorAccent.css};` +
|
` color: ${this.colorManager.colors.cursorAccent.css};` +
|
||||||
@@ -328,6 +338,7 @@ export class DomRenderer extends EventEmitter implements IRenderer {
|
|||||||
|
|
||||||
const cursorAbsoluteY = terminal.buffer.ybase + terminal.buffer.y;
|
const cursorAbsoluteY = terminal.buffer.ybase + terminal.buffer.y;
|
||||||
const cursorX = this._terminal.buffer.x;
|
const cursorX = this._terminal.buffer.x;
|
||||||
|
const cursorBlink = this._terminal.options.cursorBlink;
|
||||||
|
|
||||||
for (let y = start; y <= end; y++) {
|
for (let y = start; y <= end; y++) {
|
||||||
const rowElement = this._rowElements[y];
|
const rowElement = this._rowElements[y];
|
||||||
@@ -336,7 +347,7 @@ export class DomRenderer extends EventEmitter implements IRenderer {
|
|||||||
const row = y + terminal.buffer.ydisp;
|
const row = y + terminal.buffer.ydisp;
|
||||||
const lineData = terminal.buffer.lines.get(row);
|
const lineData = terminal.buffer.lines.get(row);
|
||||||
const cursorStyle = terminal.options.cursorStyle;
|
const cursorStyle = terminal.options.cursorStyle;
|
||||||
rowElement.appendChild(this._rowFactory.createRow(lineData, row === cursorAbsoluteY, cursorStyle, cursorX, this.dimensions.actualCellWidth, terminal.cols));
|
rowElement.appendChild(this._rowFactory.createRow(lineData, row === cursorAbsoluteY, cursorStyle, cursorX, cursorBlink, this.dimensions.actualCellWidth, terminal.cols));
|
||||||
}
|
}
|
||||||
|
|
||||||
this._terminal.emit('refresh', {start, end});
|
this._terminal.emit('refresh', {start, end});
|
||||||
|
|||||||
@@ -9,23 +9,28 @@ import { DomRendererRowFactory } from './DomRendererRowFactory';
|
|||||||
import { DEFAULT_ATTR, NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR } from '../../Buffer';
|
import { DEFAULT_ATTR, NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR } from '../../Buffer';
|
||||||
import { FLAGS } from '../Types';
|
import { FLAGS } from '../Types';
|
||||||
import { BufferLine } from '../../BufferLine';
|
import { BufferLine } from '../../BufferLine';
|
||||||
import { IBufferLine } from '../../Types';
|
import { IBufferLine, ITerminalOptions } from '../../Types';
|
||||||
import { DEFAULT_COLOR } from '../atlas/Types';
|
import { DEFAULT_COLOR } from '../atlas/Types';
|
||||||
|
|
||||||
describe('DomRendererRowFactory', () => {
|
describe('DomRendererRowFactory', () => {
|
||||||
let dom: jsdom.JSDOM;
|
let dom: jsdom.JSDOM;
|
||||||
|
const options: ITerminalOptions = {};
|
||||||
let rowFactory: DomRendererRowFactory;
|
let rowFactory: DomRendererRowFactory;
|
||||||
let lineData: IBufferLine;
|
let lineData: IBufferLine;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
dom = new jsdom.JSDOM('');
|
dom = new jsdom.JSDOM('');
|
||||||
rowFactory = new DomRendererRowFactory(dom.window.document);
|
|
||||||
|
options.enableBold = true;
|
||||||
|
options.drawBoldTextInBrightColors = true;
|
||||||
|
|
||||||
|
rowFactory = new DomRendererRowFactory(options, dom.window.document);
|
||||||
lineData = createEmptyLineData(2);
|
lineData = createEmptyLineData(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createRow', () => {
|
describe('createRow', () => {
|
||||||
it('should not create anything for an empty row', () => {
|
it('should not create anything for an empty row', () => {
|
||||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
@@ -35,7 +40,7 @@ describe('DomRendererRowFactory', () => {
|
|||||||
lineData.set(0, [DEFAULT_ATTR, '語', 2, '語'.charCodeAt(0)]);
|
lineData.set(0, [DEFAULT_ATTR, '語', 2, '語'.charCodeAt(0)]);
|
||||||
// There should be no element for the following "empty" cell
|
// There should be no element for the following "empty" cell
|
||||||
lineData.set(1, [DEFAULT_ATTR, '', 0, undefined]);
|
lineData.set(1, [DEFAULT_ATTR, '', 0, undefined]);
|
||||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
'<span style="width: 10px;">語</span>'
|
'<span style="width: 10px;">語</span>'
|
||||||
);
|
);
|
||||||
@@ -43,17 +48,24 @@ describe('DomRendererRowFactory', () => {
|
|||||||
|
|
||||||
it('should add class for cursor and cursor style', () => {
|
it('should add class for cursor and cursor style', () => {
|
||||||
for (const style of ['block', 'bar', 'underline']) {
|
for (const style of ['block', 'bar', 'underline']) {
|
||||||
const fragment = rowFactory.createRow(lineData, true, style, 0, 5, 20);
|
const fragment = rowFactory.createRow(lineData, true, style, 0, false, 5, 20);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
`<span class="xterm-cursor xterm-cursor-${style}"> </span>`
|
`<span class="xterm-cursor xterm-cursor-${style}"> </span>`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should add class for cursor blink', () => {
|
||||||
|
const fragment = rowFactory.createRow(lineData, true, 'block', 0, true, 5, 20);
|
||||||
|
assert.equal(getFragmentHtml(fragment),
|
||||||
|
`<span class="xterm-cursor xterm-cursor-blink xterm-cursor-block"> </span>`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('should not render cells that go beyond the terminal\'s columns', () => {
|
it('should not render cells that go beyond the terminal\'s columns', () => {
|
||||||
lineData.set(0, [DEFAULT_ATTR, 'a', 1, 'a'.charCodeAt(0)]);
|
lineData.set(0, [DEFAULT_ATTR, 'a', 1, 'a'.charCodeAt(0)]);
|
||||||
lineData.set(1, [DEFAULT_ATTR, 'b', 1, 'b'.charCodeAt(0)]);
|
lineData.set(1, [DEFAULT_ATTR, 'b', 1, 'b'.charCodeAt(0)]);
|
||||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 1);
|
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 1);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
'<span>a</span>'
|
'<span>a</span>'
|
||||||
);
|
);
|
||||||
@@ -62,7 +74,7 @@ describe('DomRendererRowFactory', () => {
|
|||||||
describe('attributes', () => {
|
describe('attributes', () => {
|
||||||
it('should add class for bold', () => {
|
it('should add class for bold', () => {
|
||||||
lineData.set(0, [DEFAULT_ATTR | (FLAGS.BOLD << 18), 'a', 1, 'a'.charCodeAt(0)]);
|
lineData.set(0, [DEFAULT_ATTR | (FLAGS.BOLD << 18), 'a', 1, 'a'.charCodeAt(0)]);
|
||||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
'<span class="xterm-bold">a</span>'
|
'<span class="xterm-bold">a</span>'
|
||||||
);
|
);
|
||||||
@@ -70,7 +82,7 @@ describe('DomRendererRowFactory', () => {
|
|||||||
|
|
||||||
it('should add class for italic', () => {
|
it('should add class for italic', () => {
|
||||||
lineData.set(0, [DEFAULT_ATTR | (FLAGS.ITALIC << 18), 'a', 1, 'a'.charCodeAt(0)]);
|
lineData.set(0, [DEFAULT_ATTR | (FLAGS.ITALIC << 18), 'a', 1, 'a'.charCodeAt(0)]);
|
||||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
'<span class="xterm-italic">a</span>'
|
'<span class="xterm-italic">a</span>'
|
||||||
);
|
);
|
||||||
@@ -80,7 +92,7 @@ describe('DomRendererRowFactory', () => {
|
|||||||
const defaultAttrNoFgColor = (0 << 9) | (DEFAULT_COLOR << 0);
|
const defaultAttrNoFgColor = (0 << 9) | (DEFAULT_COLOR << 0);
|
||||||
for (let i = 0; i < 256; i++) {
|
for (let i = 0; i < 256; i++) {
|
||||||
lineData.set(0, [defaultAttrNoFgColor | (i << 9), 'a', 1, 'a'.charCodeAt(0)]);
|
lineData.set(0, [defaultAttrNoFgColor | (i << 9), 'a', 1, 'a'.charCodeAt(0)]);
|
||||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
`<span class="xterm-fg-${i}">a</span>`
|
`<span class="xterm-fg-${i}">a</span>`
|
||||||
);
|
);
|
||||||
@@ -91,7 +103,7 @@ describe('DomRendererRowFactory', () => {
|
|||||||
const defaultAttrNoBgColor = (DEFAULT_ATTR << 9) | (0 << 0);
|
const defaultAttrNoBgColor = (DEFAULT_ATTR << 9) | (0 << 0);
|
||||||
for (let i = 0; i < 256; i++) {
|
for (let i = 0; i < 256; i++) {
|
||||||
lineData.set(0, [defaultAttrNoBgColor | (i << 0), 'a', 1, 'a'.charCodeAt(0)]);
|
lineData.set(0, [defaultAttrNoBgColor | (i << 0), 'a', 1, 'a'.charCodeAt(0)]);
|
||||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
`<span class="xterm-bg-${i}">a</span>`
|
`<span class="xterm-bg-${i}">a</span>`
|
||||||
);
|
);
|
||||||
@@ -100,7 +112,7 @@ describe('DomRendererRowFactory', () => {
|
|||||||
|
|
||||||
it('should correctly invert colors', () => {
|
it('should correctly invert colors', () => {
|
||||||
lineData.set(0, [(FLAGS.INVERSE << 18) | (2 << 9) | (1 << 0), 'a', 1, 'a'.charCodeAt(0)]);
|
lineData.set(0, [(FLAGS.INVERSE << 18) | (2 << 9) | (1 << 0), 'a', 1, 'a'.charCodeAt(0)]);
|
||||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
'<span class="xterm-fg-1 xterm-bg-2">a</span>'
|
'<span class="xterm-fg-1 xterm-bg-2">a</span>'
|
||||||
);
|
);
|
||||||
@@ -108,7 +120,7 @@ describe('DomRendererRowFactory', () => {
|
|||||||
|
|
||||||
it('should correctly invert default fg color', () => {
|
it('should correctly invert default fg color', () => {
|
||||||
lineData.set(0, [(FLAGS.INVERSE << 18) | (DEFAULT_ATTR << 9) | (1 << 0), 'a', 1, 'a'.charCodeAt(0)]);
|
lineData.set(0, [(FLAGS.INVERSE << 18) | (DEFAULT_ATTR << 9) | (1 << 0), 'a', 1, 'a'.charCodeAt(0)]);
|
||||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
'<span class="xterm-fg-1 xterm-bg-257">a</span>'
|
'<span class="xterm-fg-1 xterm-bg-257">a</span>'
|
||||||
);
|
);
|
||||||
@@ -116,7 +128,7 @@ describe('DomRendererRowFactory', () => {
|
|||||||
|
|
||||||
it('should correctly invert default bg color', () => {
|
it('should correctly invert default bg color', () => {
|
||||||
lineData.set(0, [(FLAGS.INVERSE << 18) | (1 << 9) | (DEFAULT_COLOR << 0), 'a', 1, 'a'.charCodeAt(0)]);
|
lineData.set(0, [(FLAGS.INVERSE << 18) | (1 << 9) | (DEFAULT_COLOR << 0), 'a', 1, 'a'.charCodeAt(0)]);
|
||||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
'<span class="xterm-fg-257 xterm-bg-1">a</span>'
|
'<span class="xterm-fg-257 xterm-bg-1">a</span>'
|
||||||
);
|
);
|
||||||
@@ -125,7 +137,7 @@ describe('DomRendererRowFactory', () => {
|
|||||||
it('should turn bold fg text bright', () => {
|
it('should turn bold fg text bright', () => {
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
lineData.set(0, [(FLAGS.BOLD << 18) | (i << 9) | (DEFAULT_COLOR << 0), 'a', 1, 'a'.charCodeAt(0)]);
|
lineData.set(0, [(FLAGS.BOLD << 18) | (i << 9) | (DEFAULT_COLOR << 0), 'a', 1, 'a'.charCodeAt(0)]);
|
||||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||||
assert.equal(getFragmentHtml(fragment),
|
assert.equal(getFragmentHtml(fragment),
|
||||||
`<span class="xterm-bold xterm-fg-${i + 8}">a</span>`
|
`<span class="xterm-bold xterm-fg-${i + 8}">a</span>`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,23 +5,25 @@
|
|||||||
|
|
||||||
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_ATTR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from '../../Buffer';
|
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_ATTR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from '../../Buffer';
|
||||||
import { FLAGS } from '../Types';
|
import { FLAGS } from '../Types';
|
||||||
import { IBufferLine } from '../../Types';
|
import { IBufferLine, ITerminalOptions } from '../../Types';
|
||||||
import { DEFAULT_COLOR, INVERTED_DEFAULT_COLOR } from '../atlas/Types';
|
import { DEFAULT_COLOR, INVERTED_DEFAULT_COLOR } from '../atlas/Types';
|
||||||
|
|
||||||
export const BOLD_CLASS = 'xterm-bold';
|
export const BOLD_CLASS = 'xterm-bold';
|
||||||
export const ITALIC_CLASS = 'xterm-italic';
|
export const ITALIC_CLASS = 'xterm-italic';
|
||||||
export const CURSOR_CLASS = 'xterm-cursor';
|
export const CURSOR_CLASS = 'xterm-cursor';
|
||||||
|
export const CURSOR_BLINK_CLASS = 'xterm-cursor-blink';
|
||||||
export const CURSOR_STYLE_BLOCK_CLASS = 'xterm-cursor-block';
|
export const CURSOR_STYLE_BLOCK_CLASS = 'xterm-cursor-block';
|
||||||
export const CURSOR_STYLE_BAR_CLASS = 'xterm-cursor-bar';
|
export const CURSOR_STYLE_BAR_CLASS = 'xterm-cursor-bar';
|
||||||
export const CURSOR_STYLE_UNDERLINE_CLASS = 'xterm-cursor-underline';
|
export const CURSOR_STYLE_UNDERLINE_CLASS = 'xterm-cursor-underline';
|
||||||
|
|
||||||
export class DomRendererRowFactory {
|
export class DomRendererRowFactory {
|
||||||
constructor(
|
constructor(
|
||||||
|
private _terminalOptions: ITerminalOptions,
|
||||||
private _document: Document
|
private _document: Document
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public createRow(lineData: IBufferLine, isCursorRow: boolean, cursorStyle: string | undefined, cursorX: number, cellWidth: number, cols: number): DocumentFragment {
|
public createRow(lineData: IBufferLine, isCursorRow: boolean, cursorStyle: string | undefined, cursorX: number, cursorBlink: boolean, cellWidth: number, cols: number): DocumentFragment {
|
||||||
const fragment = this._document.createDocumentFragment();
|
const fragment = this._document.createDocumentFragment();
|
||||||
|
|
||||||
// Find the line length first, this prevents the need to output a bunch of
|
// Find the line length first, this prevents the need to output a bunch of
|
||||||
@@ -62,6 +64,10 @@ export class DomRendererRowFactory {
|
|||||||
if (isCursorRow && x === cursorX) {
|
if (isCursorRow && x === cursorX) {
|
||||||
charElement.classList.add(CURSOR_CLASS);
|
charElement.classList.add(CURSOR_CLASS);
|
||||||
|
|
||||||
|
if (cursorBlink) {
|
||||||
|
charElement.classList.add(CURSOR_BLINK_CLASS);
|
||||||
|
}
|
||||||
|
|
||||||
switch (cursorStyle) {
|
switch (cursorStyle) {
|
||||||
case 'bar':
|
case 'bar':
|
||||||
charElement.classList.add(CURSOR_STYLE_BAR_CLASS);
|
charElement.classList.add(CURSOR_STYLE_BAR_CLASS);
|
||||||
@@ -88,10 +94,10 @@ export class DomRendererRowFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & FLAGS.BOLD) {
|
if (flags & FLAGS.BOLD && this._terminalOptions.enableBold) {
|
||||||
// Convert the FG color to the bold variant. This should not happen when
|
// Convert the FG color to the bold variant. This should not happen when
|
||||||
// the fg is the inverse default color as there is no bold variant.
|
// the fg is the inverse default color as there is no bold variant.
|
||||||
if (fg < 8) {
|
if (fg < 8 && this._terminalOptions.drawBoldTextInBrightColors) {
|
||||||
fg += 8;
|
fg += 8;
|
||||||
}
|
}
|
||||||
charElement.classList.add(BOLD_CLASS);
|
charElement.classList.add(BOLD_CLASS);
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [ "es5" ],
|
||||||
|
"rootDir": ".",
|
||||||
|
|
||||||
|
"sourceMap": true,
|
||||||
|
"removeComments": true,
|
||||||
|
"pretty": true,
|
||||||
|
|
||||||
|
"incremental": true,
|
||||||
|
|
||||||
|
"skipLibCheck": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig-base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"types": [
|
||||||
|
"../../node_modules/@types/mocha",
|
||||||
|
"../../"
|
||||||
|
],
|
||||||
|
"composite": true,
|
||||||
|
"strict": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{ "path": "." },
|
||||||
|
{ "path": "./addons/attach" },
|
||||||
|
{ "path": "./addons/fit" },
|
||||||
|
{ "path": "./addons/fullscreen" },
|
||||||
|
{ "path": "./addons/search" },
|
||||||
|
{ "path": "./addons/terminado" },
|
||||||
|
{ "path": "./addons/webLinks" },
|
||||||
|
{ "path": "./addons/winptyCompat" },
|
||||||
|
{ "path": "./addons/zmodem" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"extends": "./tsconfig-base",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"target": "es5",
|
|
||||||
"lib": [
|
"lib": [
|
||||||
"dom",
|
"dom",
|
||||||
"es5",
|
"es5",
|
||||||
@@ -9,19 +9,22 @@
|
|||||||
"scripthost",
|
"scripthost",
|
||||||
"es2015.promise"
|
"es2015.promise"
|
||||||
],
|
],
|
||||||
"rootDir": "src",
|
"rootDir": ".",
|
||||||
"outDir": "lib",
|
"outDir": "../lib",
|
||||||
"sourceMap": true,
|
|
||||||
"removeComments": true,
|
|
||||||
"preserveWatchOutput": true,
|
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noImplicitAny": true
|
"noImplicitAny": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*",
|
"./**/*",
|
||||||
"typings/xterm.d.ts"
|
"../typings/xterm.d.ts"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"src/addons/**/*"
|
"./addons/**/*"
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{ "path": "./common" },
|
||||||
|
{ "path": "./core" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,11 +23,13 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager {
|
|||||||
|
|
||||||
private _areZonesActive: boolean = false;
|
private _areZonesActive: boolean = false;
|
||||||
private _mouseMoveListener: (e: MouseEvent) => any;
|
private _mouseMoveListener: (e: MouseEvent) => any;
|
||||||
|
private _mouseLeaveListener: (e: MouseEvent) => any;
|
||||||
private _clickListener: (e: MouseEvent) => any;
|
private _clickListener: (e: MouseEvent) => any;
|
||||||
|
|
||||||
private _tooltipTimeout: number = null;
|
private _tooltipTimeout: number = null;
|
||||||
private _currentZone: IMouseZone = null;
|
private _currentZone: IMouseZone = null;
|
||||||
private _lastHoverCoords: [number, number] = [null, null];
|
private _lastHoverCoords: [number, number] = [null, null];
|
||||||
|
private _initialSelectionLength: number;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _terminal: ITerminal
|
private _terminal: ITerminal
|
||||||
@@ -38,6 +40,7 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager {
|
|||||||
|
|
||||||
// These events are expensive, only listen to it when mouse zones are active
|
// These events are expensive, only listen to it when mouse zones are active
|
||||||
this._mouseMoveListener = e => this._onMouseMove(e);
|
this._mouseMoveListener = e => this._onMouseMove(e);
|
||||||
|
this._mouseLeaveListener = e => this._onMouseLeave(e);
|
||||||
this._clickListener = e => this._onClick(e);
|
this._clickListener = e => this._onClick(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +92,7 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager {
|
|||||||
if (!this._areZonesActive) {
|
if (!this._areZonesActive) {
|
||||||
this._areZonesActive = true;
|
this._areZonesActive = true;
|
||||||
this._terminal.element.addEventListener('mousemove', this._mouseMoveListener);
|
this._terminal.element.addEventListener('mousemove', this._mouseMoveListener);
|
||||||
|
this._terminal.element.addEventListener('mouseleave', this._mouseLeaveListener);
|
||||||
this._terminal.element.addEventListener('click', this._clickListener);
|
this._terminal.element.addEventListener('click', this._clickListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,6 +101,7 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager {
|
|||||||
if (this._areZonesActive) {
|
if (this._areZonesActive) {
|
||||||
this._areZonesActive = false;
|
this._areZonesActive = false;
|
||||||
this._terminal.element.removeEventListener('mousemove', this._mouseMoveListener);
|
this._terminal.element.removeEventListener('mousemove', this._mouseMoveListener);
|
||||||
|
this._terminal.element.removeEventListener('mouseleave', this._mouseLeaveListener);
|
||||||
this._terminal.element.removeEventListener('click', this._clickListener);
|
this._terminal.element.removeEventListener('click', this._clickListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,6 +158,10 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _onMouseDown(e: MouseEvent): void {
|
private _onMouseDown(e: MouseEvent): void {
|
||||||
|
// Store current terminal selection length, to check if we're performing
|
||||||
|
// a selection operation
|
||||||
|
this._initialSelectionLength = this._terminal.getSelection().length;
|
||||||
|
|
||||||
// Ignore the event if there are no zones active
|
// Ignore the event if there are no zones active
|
||||||
if (!this._areZonesActive) {
|
if (!this._areZonesActive) {
|
||||||
return;
|
return;
|
||||||
@@ -169,10 +178,25 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _onMouseLeave(e: MouseEvent): void {
|
||||||
|
// Fire the hover end callback and cancel any existing timer if the mouse
|
||||||
|
// leaves the terminal element
|
||||||
|
if (this._currentZone) {
|
||||||
|
this._currentZone.leaveCallback();
|
||||||
|
this._currentZone = null;
|
||||||
|
if (this._tooltipTimeout) {
|
||||||
|
clearTimeout(this._tooltipTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _onClick(e: MouseEvent): void {
|
private _onClick(e: MouseEvent): void {
|
||||||
// Find the active zone and click it if found
|
// Find the active zone and click it if found and no selection was
|
||||||
|
// being performed
|
||||||
const zone = this._findZoneEventAt(e);
|
const zone = this._findZoneEventAt(e);
|
||||||
if (zone) {
|
const currentSelectionLength = this._terminal.getSelection().length;
|
||||||
|
|
||||||
|
if (zone && currentSelectionLength === this._initialSelectionLength) {
|
||||||
zone.clickCallback(e);
|
zone.clickCallback(e);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
|
|||||||
@@ -1275,11 +1275,6 @@ combined-stream@1.0.6, combined-stream@~1.0.5:
|
|||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream "~1.0.0"
|
delayed-stream "~1.0.0"
|
||||||
|
|
||||||
commander@2.6.0:
|
|
||||||
version "2.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.6.0.tgz#9df7e52fb2a0cb0fb89058ee80c3104225f37e1d"
|
|
||||||
integrity sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=
|
|
||||||
|
|
||||||
commander@2.9.0:
|
commander@2.9.0:
|
||||||
version "2.9.0"
|
version "2.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
|
||||||
@@ -1338,21 +1333,6 @@ concat-with-sourcemaps@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
|
|
||||||
concurrently@^3.5.1:
|
|
||||||
version "3.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-3.6.0.tgz#c25e34b156a9d5bd4f256a0d85f6192438ae481f"
|
|
||||||
integrity sha512-6XiIYtYzmGEccNZFkih5JOH92jLA4ulZArAYy5j1uDSdrPLB3KzdE8GW7t2fHPcg9ry2+5LP9IEYzXzxw9lFdA==
|
|
||||||
dependencies:
|
|
||||||
chalk "^2.4.1"
|
|
||||||
commander "2.6.0"
|
|
||||||
date-fns "^1.23.0"
|
|
||||||
lodash "^4.5.1"
|
|
||||||
read-pkg "^3.0.0"
|
|
||||||
rx "2.3.24"
|
|
||||||
spawn-command "^0.0.2-1"
|
|
||||||
supports-color "^3.2.3"
|
|
||||||
tree-kill "^1.1.0"
|
|
||||||
|
|
||||||
configstore@^1.0.0:
|
configstore@^1.0.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021"
|
resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021"
|
||||||
@@ -1595,11 +1575,6 @@ data-urls@^1.0.0:
|
|||||||
whatwg-mimetype "^2.0.0"
|
whatwg-mimetype "^2.0.0"
|
||||||
whatwg-url "^6.4.0"
|
whatwg-url "^6.4.0"
|
||||||
|
|
||||||
date-fns@^1.23.0:
|
|
||||||
version "1.29.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6"
|
|
||||||
integrity sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==
|
|
||||||
|
|
||||||
date-now@^0.1.4:
|
date-now@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
|
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
|
||||||
@@ -1933,7 +1908,7 @@ errno@^0.1.3, errno@~0.1.7:
|
|||||||
dependencies:
|
dependencies:
|
||||||
prr "~1.0.1"
|
prr "~1.0.1"
|
||||||
|
|
||||||
error-ex@^1.2.0, error-ex@^1.3.1:
|
error-ex@^1.2.0:
|
||||||
version "1.3.2"
|
version "1.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
||||||
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
|
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
|
||||||
@@ -3625,7 +3600,7 @@ jsesc@^1.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
|
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
|
||||||
integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s=
|
integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s=
|
||||||
|
|
||||||
json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
|
json-parse-better-errors@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
|
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
|
||||||
integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
|
integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
|
||||||
@@ -3815,16 +3790,6 @@ load-json-file@^1.0.0:
|
|||||||
pinkie-promise "^2.0.0"
|
pinkie-promise "^2.0.0"
|
||||||
strip-bom "^2.0.0"
|
strip-bom "^2.0.0"
|
||||||
|
|
||||||
load-json-file@^4.0.0:
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
|
|
||||||
integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs=
|
|
||||||
dependencies:
|
|
||||||
graceful-fs "^4.1.2"
|
|
||||||
parse-json "^4.0.0"
|
|
||||||
pify "^3.0.0"
|
|
||||||
strip-bom "^3.0.0"
|
|
||||||
|
|
||||||
loader-runner@^2.3.0:
|
loader-runner@^2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
|
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
|
||||||
@@ -4037,7 +4002,7 @@ lodash.templatesettings@^3.0.0:
|
|||||||
lodash._reinterpolate "^3.0.0"
|
lodash._reinterpolate "^3.0.0"
|
||||||
lodash.escape "^3.0.0"
|
lodash.escape "^3.0.0"
|
||||||
|
|
||||||
lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.5.1:
|
lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.4:
|
||||||
version "4.17.10"
|
version "4.17.10"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
|
||||||
integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==
|
integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==
|
||||||
@@ -4984,14 +4949,6 @@ parse-json@^2.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
error-ex "^1.2.0"
|
error-ex "^1.2.0"
|
||||||
|
|
||||||
parse-json@^4.0.0:
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
|
|
||||||
integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
|
|
||||||
dependencies:
|
|
||||||
error-ex "^1.3.1"
|
|
||||||
json-parse-better-errors "^1.0.1"
|
|
||||||
|
|
||||||
parse-passwd@^1.0.0:
|
parse-passwd@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
|
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
|
||||||
@@ -5092,13 +5049,6 @@ path-type@^1.0.0:
|
|||||||
pify "^2.0.0"
|
pify "^2.0.0"
|
||||||
pinkie-promise "^2.0.0"
|
pinkie-promise "^2.0.0"
|
||||||
|
|
||||||
path-type@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
|
|
||||||
integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==
|
|
||||||
dependencies:
|
|
||||||
pify "^3.0.0"
|
|
||||||
|
|
||||||
pause-stream@0.0.11:
|
pause-stream@0.0.11:
|
||||||
version "0.0.11"
|
version "0.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
|
resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
|
||||||
@@ -5384,15 +5334,6 @@ read-pkg@^1.0.0:
|
|||||||
normalize-package-data "^2.3.2"
|
normalize-package-data "^2.3.2"
|
||||||
path-type "^1.0.0"
|
path-type "^1.0.0"
|
||||||
|
|
||||||
read-pkg@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
|
|
||||||
integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=
|
|
||||||
dependencies:
|
|
||||||
load-json-file "^4.0.0"
|
|
||||||
normalize-package-data "^2.3.2"
|
|
||||||
path-type "^3.0.0"
|
|
||||||
|
|
||||||
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6:
|
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6:
|
||||||
version "2.3.6"
|
version "2.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
|
||||||
@@ -5688,11 +5629,6 @@ run-queue@^1.0.0, run-queue@^1.0.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
aproba "^1.1.1"
|
aproba "^1.1.1"
|
||||||
|
|
||||||
rx@2.3.24:
|
|
||||||
version "2.3.24"
|
|
||||||
resolved "https://registry.yarnpkg.com/rx/-/rx-2.3.24.tgz#14f950a4217d7e35daa71bbcbe58eff68ea4b2b7"
|
|
||||||
integrity sha1-FPlQpCF9fjXapxu8vljv9o6ksrc=
|
|
||||||
|
|
||||||
rxjs@^6.1.0:
|
rxjs@^6.1.0:
|
||||||
version "6.3.1"
|
version "6.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.1.tgz#878a1a8c64b8a5da11dcf74b5033fe944cdafb84"
|
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.1.tgz#878a1a8c64b8a5da11dcf74b5033fe944cdafb84"
|
||||||
@@ -6025,11 +5961,6 @@ sparkles@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c"
|
resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c"
|
||||||
integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==
|
integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==
|
||||||
|
|
||||||
spawn-command@^0.0.2-1:
|
|
||||||
version "0.0.2-1"
|
|
||||||
resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0"
|
|
||||||
integrity sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=
|
|
||||||
|
|
||||||
spawn-wrap@^1.4.2:
|
spawn-wrap@^1.4.2:
|
||||||
version "1.4.2"
|
version "1.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.4.2.tgz#cff58e73a8224617b6561abdc32586ea0c82248c"
|
resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.4.2.tgz#cff58e73a8224617b6561abdc32586ea0c82248c"
|
||||||
@@ -6271,11 +6202,6 @@ strip-bom@^1.0.0:
|
|||||||
first-chunk-stream "^1.0.0"
|
first-chunk-stream "^1.0.0"
|
||||||
is-utf8 "^0.2.0"
|
is-utf8 "^0.2.0"
|
||||||
|
|
||||||
strip-bom@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
|
|
||||||
integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
|
|
||||||
|
|
||||||
strip-eof@^1.0.0:
|
strip-eof@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
|
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
|
||||||
@@ -6305,7 +6231,7 @@ supports-color@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
||||||
integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
|
integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
|
||||||
|
|
||||||
supports-color@^3.1.2, supports-color@^3.2.3:
|
supports-color@^3.1.2:
|
||||||
version "3.2.3"
|
version "3.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
|
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
|
||||||
integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=
|
integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=
|
||||||
@@ -6521,11 +6447,6 @@ tr46@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.0"
|
punycode "^2.1.0"
|
||||||
|
|
||||||
tree-kill@^1.1.0:
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36"
|
|
||||||
integrity sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg==
|
|
||||||
|
|
||||||
trim-right@^1.0.1:
|
trim-right@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
|
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
|
||||||
@@ -6633,10 +6554,10 @@ typedarray@^0.0.6, typedarray@~0.0.5:
|
|||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||||
|
|
||||||
typescript@3.1:
|
typescript@3.4:
|
||||||
version "3.1.6"
|
version "3.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.1.tgz#b6691be11a881ffa9a05765a205cb7383f3b63c6"
|
||||||
integrity sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==
|
integrity sha512-3NSMb2VzDQm8oBTLH6Nj55VVtUEpe/rgkIzMir0qVoLyjDZlnMBva0U6vDiV3IH+sl/Yu6oP5QwsAQtHPmDd2Q==
|
||||||
|
|
||||||
uglify-es@^3.3.4:
|
uglify-es@^3.3.4:
|
||||||
version "3.3.9"
|
version "3.3.9"
|
||||||
|
|||||||
Reference in New Issue
Block a user