mirror of https://github.com/midoks/mdserver-web
parent
39851704d1
commit
cc2b2b2bd9
@ -0,0 +1,141 @@ |
||||
/** |
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved. |
||||
* @license MIT |
||||
* |
||||
* Implements the attach method, that attaches the terminal to a WebSocket stream. |
||||
*/ |
||||
|
||||
(function (attach) { |
||||
if (typeof exports === 'object' && typeof module === 'object') { |
||||
/* |
||||
* CommonJS environment |
||||
*/ |
||||
module.exports = attach(require('../../Terminal').Terminal); |
||||
} else if (typeof define == 'function') { |
||||
/* |
||||
* Require.js is available |
||||
*/ |
||||
define(['../../xterm'], attach); |
||||
} else { |
||||
/* |
||||
* Plain browser environment |
||||
*/ |
||||
attach(window.Terminal); |
||||
} |
||||
})(function (Terminal) { |
||||
'use strict'; |
||||
|
||||
var exports = {}; |
||||
|
||||
/** |
||||
* Attaches the given terminal to the given socket. |
||||
* |
||||
* @param {Terminal} term - The terminal to be attached to the given socket. |
||||
* @param {WebSocket} socket - The socket to attach the current terminal. |
||||
* @param {boolean} bidirectional - Whether the terminal should send data |
||||
* to the socket as well. |
||||
* @param {boolean} buffered - Whether the rendering of incoming data |
||||
* should happen instantly or at a maximum |
||||
* frequency of 1 rendering per 10ms. |
||||
*/ |
||||
exports.attach = function (term, socket, bidirectional, buffered) { |
||||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; |
||||
term.socket = socket; |
||||
|
||||
term._flushBuffer = function () { |
||||
term.write(term._attachSocketBuffer); |
||||
term._attachSocketBuffer = null; |
||||
}; |
||||
|
||||
term._pushToBuffer = function (data) { |
||||
if (term._attachSocketBuffer) { |
||||
term._attachSocketBuffer += data; |
||||
} else { |
||||
term._attachSocketBuffer = data; |
||||
setTimeout(term._flushBuffer, 10); |
||||
} |
||||
}; |
||||
|
||||
var myTextDecoder; |
||||
|
||||
term._getMessage = function (ev) { |
||||
var str; |
||||
if (typeof ev.data === "object") { |
||||
if (ev.data instanceof ArrayBuffer) { |
||||
if (!myTextDecoder) { |
||||
myTextDecoder = new TextDecoder(); |
||||
} |
||||
|
||||
str = myTextDecoder.decode( ev.data ); |
||||
} |
||||
else { |
||||
throw "TODO: handle Blob?"; |
||||
} |
||||
} |
||||
|
||||
if (buffered) { |
||||
term._pushToBuffer(str || ev.data); |
||||
} else { |
||||
term.write(str || ev.data); |
||||
} |
||||
}; |
||||
|
||||
term._sendData = function (data) { |
||||
socket.send(data); |
||||
}; |
||||
|
||||
socket.addEventListener('message', term._getMessage); |
||||
|
||||
if (bidirectional) { |
||||
term.on('data', term._sendData); |
||||
} |
||||
|
||||
socket.addEventListener('close', term.detach.bind(term, socket)); |
||||
socket.addEventListener('error', term.detach.bind(term, socket)); |
||||
}; |
||||
|
||||
/** |
||||
* Detaches the given terminal from the given socket |
||||
* |
||||
* @param {Terminal} term - The terminal to be detached from the given socket. |
||||
* @param {WebSocket} socket - The socket from which to detach the current |
||||
* terminal. |
||||
*/ |
||||
exports.detach = function (term, socket) { |
||||
term.off('data', term._sendData); |
||||
|
||||
socket = (typeof socket == 'undefined') ? term.socket : socket; |
||||
|
||||
if (socket) { |
||||
socket.removeEventListener('message', term._getMessage); |
||||
} |
||||
|
||||
delete term.socket; |
||||
}; |
||||
|
||||
/** |
||||
* Attaches the current terminal to the given socket |
||||
* |
||||
* @param {WebSocket} socket - The socket to attach the current terminal. |
||||
* @param {boolean} bidirectional - Whether the terminal should send data |
||||
* to the socket as well. |
||||
* @param {boolean} buffered - Whether the rendering of incoming data |
||||
* should happen instantly or at a maximum |
||||
* frequency of 1 rendering per 10ms. |
||||
*/ |
||||
Terminal.prototype.attach = function (socket, bidirectional, buffered) { |
||||
return exports.attach(this, socket, bidirectional, buffered); |
||||
}; |
||||
|
||||
/** |
||||
* Detaches the current terminal from the given socket. |
||||
* |
||||
* @param {WebSocket} socket - The socket from which to detach the current |
||||
* terminal. |
||||
*/ |
||||
Terminal.prototype.detach = function (socket) { |
||||
return exports.detach(this, socket); |
||||
}; |
||||
|
||||
return exports; |
||||
}); |
@ -0,0 +1,93 @@ |
||||
<!doctype html> |
||||
<html> |
||||
<head> |
||||
<link rel="stylesheet" href="../../src/xterm.css" /> |
||||
<link rel="stylesheet" href="../../demo/style.css" /> |
||||
<script src="../../src/xterm.js"></script> |
||||
<script src="attach.js"></script> |
||||
<style> |
||||
body { |
||||
color: #111; |
||||
} |
||||
|
||||
h1, h2 { |
||||
color: #444; |
||||
border-bottom: 1px solid #ddd; |
||||
text-align: left; |
||||
} |
||||
|
||||
form { |
||||
margin-bottom: 32px; |
||||
} |
||||
|
||||
input, button { |
||||
line-height: 22px; |
||||
font-size: 16px; |
||||
display: inline-block; |
||||
border-radius: 2px; |
||||
border: 1px solid #ccc; |
||||
} |
||||
|
||||
input { |
||||
height: 22px; |
||||
padding-left: 4px; |
||||
padding-right: 4px; |
||||
} |
||||
|
||||
button { |
||||
height: 28px; |
||||
background-color: #ccc; |
||||
cursor: pointer; |
||||
color: #333; |
||||
} |
||||
|
||||
.container { |
||||
max-width: 900px; |
||||
margin: 0 auto; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<div class="container"> |
||||
|
||||
<h1> |
||||
xterm.js: socket attach |
||||
</h1> |
||||
<p> |
||||
Attach the terminal to a WebSocket terminal stream with ease. Perfect for attaching to your |
||||
Docker containers. |
||||
</p> |
||||
<h2> |
||||
Socket information |
||||
</h2> |
||||
<form id="socket-form"> |
||||
<input id="socket-url" |
||||
type="text" |
||||
placeholder="Enter socket url (e.g. ws://mysock)" |
||||
autofocus /> |
||||
<button> |
||||
Attach |
||||
</button> |
||||
</form> |
||||
<div id="terminal-container"></div> |
||||
|
||||
</div> |
||||
<script> |
||||
var term = new Terminal(), |
||||
container = document.getElementById('terminal-container'), |
||||
socketUrl = document.getElementById('socket-url'), |
||||
socketForm = document.getElementById('socket-form'); |
||||
|
||||
socketForm.addEventListener('submit', function (ev) { |
||||
ev.preventDefault(); |
||||
var url = socketUrl.value, |
||||
sock = new WebSocket(url); |
||||
sock.addEventListener('open', function () { |
||||
term.attach(sock); |
||||
}); |
||||
}); |
||||
|
||||
term.open(container); |
||||
</script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,5 @@ |
||||
{ |
||||
"name": "xterm.attach", |
||||
"main": "attach.js", |
||||
"private": true |
||||
} |
@ -0,0 +1,81 @@ |
||||
/** |
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved. |
||||
* @license MIT |
||||
* |
||||
* Fit terminal columns and rows to the dimensions of its DOM element. |
||||
* |
||||
* ## Approach |
||||
* |
||||
* Rows: Truncate the division of the terminal parent element height by the |
||||
* terminal row height. |
||||
* Columns: Truncate the division of the terminal parent element width by the |
||||
* terminal character width (apply display: inline at the terminal |
||||
* row and truncate its width with the current number of columns). |
||||
*/ |
||||
|
||||
(function (fit) { |
||||
if (typeof exports === 'object' && typeof module === 'object') { |
||||
/* |
||||
* CommonJS environment |
||||
*/ |
||||
module.exports = fit(require('../../Terminal').Terminal); |
||||
} else if (typeof define == 'function') { |
||||
/* |
||||
* Require.js is available |
||||
*/ |
||||
define(['../../xterm'], fit); |
||||
} else { |
||||
/* |
||||
* Plain browser environment |
||||
*/ |
||||
fit(window.Terminal); |
||||
} |
||||
})(function (Terminal) { |
||||
var exports = {}; |
||||
|
||||
exports.proposeGeometry = function (term) { |
||||
if (!term.element.parentElement) { |
||||
return null; |
||||
} |
||||
var parentElementStyle = window.getComputedStyle(term.element.parentElement); |
||||
var parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')); |
||||
var parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17); |
||||
var elementStyle = window.getComputedStyle(term.element); |
||||
var elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')); |
||||
var elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')); |
||||
var availableHeight = parentElementHeight - elementPaddingVer; |
||||
var availableWidth = parentElementWidth - elementPaddingHor; |
||||
var geometry = { |
||||
cols: Math.floor(availableWidth / term.charMeasure.width), |
||||
rows: Math.floor(availableHeight / Math.floor(term.charMeasure.height * term.getOption('lineHeight'))) |
||||
}; |
||||
|
||||
return geometry; |
||||
}; |
||||
|
||||
exports.fit = function (term) { |
||||
// Wrap fit in a setTimeout as charMeasure needs time to get initialized
|
||||
// after calling Terminal.open
|
||||
setTimeout(function () { |
||||
var geometry = exports.proposeGeometry(term); |
||||
|
||||
if (geometry) { |
||||
// Force a full render
|
||||
if (term.rows !== geometry.rows || term.cols !== geometry.cols) { |
||||
term.renderer.clear(); |
||||
term.resize(geometry.cols, geometry.rows); |
||||
} |
||||
} |
||||
}, 0); |
||||
}; |
||||
|
||||
Terminal.prototype.proposeGeometry = function () { |
||||
return exports.proposeGeometry(this); |
||||
}; |
||||
|
||||
Terminal.prototype.fit = function () { |
||||
return exports.fit(this); |
||||
}; |
||||
|
||||
return exports; |
||||
}); |
@ -0,0 +1,5 @@ |
||||
{ |
||||
"name": "xterm.fit", |
||||
"main": "fit.js", |
||||
"private": true |
||||
} |
@ -0,0 +1,10 @@ |
||||
.xterm.fullscreen { |
||||
position: fixed; |
||||
top: 0; |
||||
bottom: 0; |
||||
left: 0; |
||||
right: 0; |
||||
width: auto; |
||||
height: auto; |
||||
z-index: 255; |
||||
} |
@ -0,0 +1,50 @@ |
||||
/** |
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved. |
||||
* @license MIT |
||||
*/ |
||||
|
||||
(function (fullscreen) { |
||||
if (typeof exports === 'object' && typeof module === 'object') { |
||||
/* |
||||
* CommonJS environment |
||||
*/ |
||||
module.exports = fullscreen(require('../../Terminal').Terminal); |
||||
} else if (typeof define == 'function') { |
||||
/* |
||||
* Require.js is available |
||||
*/ |
||||
define(['../../xterm'], fullscreen); |
||||
} else { |
||||
/* |
||||
* Plain browser environment |
||||
*/ |
||||
fullscreen(window.Terminal); |
||||
} |
||||
})(function (Terminal) { |
||||
var exports = {}; |
||||
|
||||
/** |
||||
* Toggle the given terminal's fullscreen mode. |
||||
* @param {Terminal} term - The terminal to toggle full screen mode |
||||
* @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false) |
||||
*/ |
||||
exports.toggleFullScreen = function (term, fullscreen) { |
||||
var fn; |
||||
|
||||
if (typeof fullscreen == 'undefined') { |
||||
fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add'; |
||||
} else if (!fullscreen) { |
||||
fn = 'remove'; |
||||
} else { |
||||
fn = 'add'; |
||||
} |
||||
|
||||
term.element.classList[fn]('fullscreen'); |
||||
}; |
||||
|
||||
Terminal.prototype.toggleFullscreen = function (fullscreen) { |
||||
exports.toggleFullScreen(this, fullscreen); |
||||
}; |
||||
|
||||
return exports; |
||||
}); |
@ -0,0 +1,5 @@ |
||||
{ |
||||
"name": "xterm.fullscreen", |
||||
"main": "fullscreen.js", |
||||
"private": true |
||||
} |
@ -0,0 +1,116 @@ |
||||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ |
||||
"use strict"; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
||||
var SearchHelper = (function () { |
||||
function SearchHelper(_terminal) { |
||||
this._terminal = _terminal; |
||||
} |
||||
SearchHelper.prototype.findNext = function (term) { |
||||
if (!term || term.length === 0) { |
||||
return false; |
||||
} |
||||
var result; |
||||
var startRow = this._terminal.buffer.ydisp; |
||||
if (this._terminal.selectionManager.selectionEnd) { |
||||
startRow = this._terminal.selectionManager.selectionEnd[1]; |
||||
} |
||||
for (var y = startRow + 1; y < this._terminal.buffer.ybase + this._terminal.rows; y++) { |
||||
result = this._findInLine(term, y); |
||||
if (result) { |
||||
break; |
||||
} |
||||
} |
||||
if (!result) { |
||||
for (var y = 0; y < startRow; y++) { |
||||
result = this._findInLine(term, y); |
||||
if (result) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
return this._selectResult(result); |
||||
}; |
||||
SearchHelper.prototype.findPrevious = function (term) { |
||||
if (!term || term.length === 0) { |
||||
return false; |
||||
} |
||||
var result; |
||||
var startRow = this._terminal.buffer.ydisp; |
||||
if (this._terminal.selectionManager.selectionStart) { |
||||
startRow = this._terminal.selectionManager.selectionStart[1]; |
||||
} |
||||
for (var y = startRow - 1; y >= 0; y--) { |
||||
result = this._findInLine(term, y); |
||||
if (result) { |
||||
break; |
||||
} |
||||
} |
||||
if (!result) { |
||||
for (var y = this._terminal.buffer.ybase + this._terminal.rows - 1; y > startRow; y--) { |
||||
result = this._findInLine(term, y); |
||||
if (result) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
return this._selectResult(result); |
||||
}; |
||||
SearchHelper.prototype._findInLine = function (term, y) { |
||||
var lowerStringLine = this._terminal.buffer.translateBufferLineToString(y, true).toLowerCase(); |
||||
var lowerTerm = term.toLowerCase(); |
||||
var searchIndex = lowerStringLine.indexOf(lowerTerm); |
||||
if (searchIndex >= 0) { |
||||
return { |
||||
term: term, |
||||
col: searchIndex, |
||||
row: y |
||||
}; |
||||
} |
||||
}; |
||||
SearchHelper.prototype._selectResult = function (result) { |
||||
if (!result) { |
||||
return false; |
||||
} |
||||
this._terminal.selectionManager.setSelection(result.col, result.row, result.term.length); |
||||
this._terminal.scrollLines(result.row - this._terminal.buffer.ydisp, false); |
||||
return true; |
||||
}; |
||||
return SearchHelper; |
||||
}()); |
||||
exports.SearchHelper = SearchHelper; |
||||
|
||||
|
||||
|
||||
},{}],2:[function(require,module,exports){ |
||||
"use strict"; |
||||
Object.defineProperty(exports, "__esModule", { value: true }); |
||||
var SearchHelper_1 = require("./SearchHelper"); |
||||
(function (addon) { |
||||
if (typeof window !== 'undefined' && 'Terminal' in window) { |
||||
addon(window.Terminal); |
||||
} |
||||
else if (typeof exports === 'object' && typeof module === 'object') { |
||||
module.exports = addon(require('../../Terminal').Terminal); |
||||
} |
||||
else if (typeof define === 'function') { |
||||
define(['../../xterm'], addon); |
||||
} |
||||
})(function (Terminal) { |
||||
Terminal.prototype.findNext = function (term) { |
||||
if (!this._searchHelper) { |
||||
this.searchHelper = new SearchHelper_1.SearchHelper(this); |
||||
} |
||||
return this.searchHelper.findNext(term); |
||||
}; |
||||
Terminal.prototype.findPrevious = function (term) { |
||||
if (!this._searchHelper) { |
||||
this.searchHelper = new SearchHelper_1.SearchHelper(this); |
||||
} |
||||
return this.searchHelper.findPrevious(term); |
||||
}; |
||||
}); |
||||
|
||||
|
||||
|
||||
},{"../../Terminal":undefined,"./SearchHelper":1}]},{},[2]) |
||||
//# sourceMappingURL=search.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,5 @@ |
||||
{ |
||||
"name": "xterm.terminado", |
||||
"main": "terminado.js", |
||||
"private": true |
||||
} |
@ -0,0 +1,134 @@ |
||||
/** |
||||
* Copyright (c) 2016 The xterm.js authors. All rights reserved. |
||||
* @license MIT |
||||
* |
||||
* This module provides methods for attaching a terminal to a terminado |
||||
* WebSocket stream. |
||||
*/ |
||||
|
||||
(function (attach) { |
||||
if (typeof exports === 'object' && typeof module === 'object') { |
||||
/* |
||||
* CommonJS environment |
||||
*/ |
||||
module.exports = attach(require('../../Terminal').Terminal); |
||||
} else if (typeof define == 'function') { |
||||
/* |
||||
* Require.js is available |
||||
*/ |
||||
define(['../../xterm'], attach); |
||||
} else { |
||||
/* |
||||
* Plain browser environment |
||||
*/ |
||||
attach(window.Terminal); |
||||
} |
||||
})(function (Terminal) { |
||||
'use strict'; |
||||
|
||||
var exports = {}; |
||||
|
||||
/** |
||||
* Attaches the given terminal to the given socket. |
||||
* |
||||
* @param {Terminal} term - The terminal to be attached to the given socket. |
||||
* @param {WebSocket} socket - The socket to attach the current terminal. |
||||
* @param {boolean} bidirectional - Whether the terminal should send data |
||||
* to the socket as well. |
||||
* @param {boolean} buffered - Whether the rendering of incoming data |
||||
* should happen instantly or at a maximum |
||||
* frequency of 1 rendering per 10ms. |
||||
*/ |
||||
exports.terminadoAttach = function (term, socket, bidirectional, buffered) { |
||||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; |
||||
term.socket = socket; |
||||
|
||||
term._flushBuffer = function () { |
||||
term.write(term._attachSocketBuffer); |
||||
term._attachSocketBuffer = null; |
||||
}; |
||||
|
||||
term._pushToBuffer = function (data) { |
||||
if (term._attachSocketBuffer) { |
||||
term._attachSocketBuffer += data; |
||||
} else { |
||||
term._attachSocketBuffer = data; |
||||
setTimeout(term._flushBuffer, 10); |
||||
} |
||||
}; |
||||
|
||||
term._getMessage = function (ev) { |
||||
var data = JSON.parse(ev.data) |
||||
if( data[0] == "stdout" ) { |
||||
if (buffered) { |
||||
term._pushToBuffer(data[1]); |
||||
} else { |
||||
term.write(data[1]); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
term._sendData = function (data) { |
||||
socket.send(JSON.stringify(['stdin', data])); |
||||
}; |
||||
|
||||
term._setSize = function (size) { |
||||
socket.send(JSON.stringify(['set_size', size.rows, size.cols])); |
||||
}; |
||||
|
||||
socket.addEventListener('message', term._getMessage); |
||||
|
||||
if (bidirectional) { |
||||
term.on('data', term._sendData); |
||||
} |
||||
term.on('resize', term._setSize); |
||||
|
||||
socket.addEventListener('close', term.terminadoDetach.bind(term, socket)); |
||||
socket.addEventListener('error', term.terminadoDetach.bind(term, socket)); |
||||
}; |
||||
|
||||
/** |
||||
* Detaches the given terminal from the given socket |
||||
* |
||||
* @param {Xterm} term - The terminal to be detached from the given socket. |
||||
* @param {WebSocket} socket - The socket from which to detach the current |
||||
* terminal. |
||||
*/ |
||||
exports.terminadoDetach = function (term, socket) { |
||||
term.off('data', term._sendData); |
||||
|
||||
socket = (typeof socket == 'undefined') ? term.socket : socket; |
||||
|
||||
if (socket) { |
||||
socket.removeEventListener('message', term._getMessage); |
||||
} |
||||
|
||||
delete term.socket; |
||||
}; |
||||
|
||||
/** |
||||
* Attaches the current terminal to the given socket |
||||
* |
||||
* @param {WebSocket} socket - The socket to attach the current terminal. |
||||
* @param {boolean} bidirectional - Whether the terminal should send data |
||||
* to the socket as well. |
||||
* @param {boolean} buffered - Whether the rendering of incoming data |
||||
* should happen instantly or at a maximum |
||||
* frequency of 1 rendering per 10ms. |
||||
*/ |
||||
Terminal.prototype.terminadoAttach = function (socket, bidirectional, buffered) { |
||||
return exports.terminadoAttach(this, socket, bidirectional, buffered); |
||||
}; |
||||
|
||||
/** |
||||
* Detaches the current terminal from the given socket. |
||||
* |
||||
* @param {WebSocket} socket - The socket from which to detach the current |
||||
* terminal. |
||||
*/ |
||||
Terminal.prototype.terminadoDetach = function (socket) { |
||||
return exports.terminadoDetach(this, socket); |
||||
}; |
||||
|
||||
return exports; |
||||
}); |
@ -0,0 +1,29 @@ |
||||
(function (addon) { |
||||
if (typeof window !== 'undefined' && 'Terminal' in window) { |
||||
addon(window.Terminal); |
||||
} |
||||
else if (typeof exports === 'object' && typeof module === 'object') { |
||||
module.exports = addon(require('../../Terminal').Terminal); |
||||
} |
||||
else if (typeof define === 'function') { |
||||
define(['../../xterm'], addon); |
||||
} |
||||
})(function (Terminal) { |
||||
Terminal.prototype.winptyCompatInit = function () { |
||||
var _this = this; |
||||
var isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0; |
||||
if (!isWindows) { |
||||
return; |
||||
} |
||||
this.on('lineFeed', function () { |
||||
var line = _this.buffer.lines.get(_this.buffer.ybase + _this.buffer.y - 1); |
||||
var lastChar = line[_this.cols - 1]; |
||||
if (lastChar[3] !== 32) { |
||||
var nextLine = _this.buffer.lines.get(_this.buffer.ybase + _this.buffer.y); |
||||
nextLine.isWrapped = true; |
||||
} |
||||
}); |
||||
}; |
||||
}); |
||||
|
||||
//# sourceMappingURL=winptyCompat.js.map
|
@ -0,0 +1 @@ |
||||
{"version":3,"sources":["../../../src/addons/winptyCompat/winptyCompat.ts"],"names":[],"mappings":"AAQA,CAAC,UAAU,KAAK;IACd,EAAE,CAAC,CAAC,OAAO,MAAM,KAAK,WAAW,IAAI,UAAU,IAAI,MAAM,CAAC,CAAC,CAAC;QAI1D,KAAK,CAAO,MAAO,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC;QAIrE,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC7D,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC;QAIxC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;AACH,CAAC,CAAC,CAAC,UAAC,QAAa;IACf,QAAQ,CAAC,SAAS,CAAC,gBAAgB,GAAG;QAAA,iBAyBrC;QAvBC,IAAM,SAAS,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC1F,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,CAAC;QACT,CAAC;QAYD,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE;YAClB,IAAM,IAAI,GAAG,KAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAI,CAAC,MAAM,CAAC,KAAK,GAAG,KAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1E,IAAM,QAAQ,GAAG,IAAI,CAAC,KAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;YACrC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAY,CAAC,CAAC,CAAC;gBACjC,IAAM,QAAQ,GAAG,KAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAI,CAAC,MAAM,CAAC,KAAK,GAAG,KAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACpE,QAAS,CAAC,SAAS,GAAG,IAAI,CAAC;YACnC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","file":"winptyCompat.js","sourceRoot":"."} |
@ -0,0 +1,87 @@ |
||||
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); |
@ -0,0 +1,128 @@ |
||||
<!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> |
@ -0,0 +1,383 @@ |
||||
"use strict"; |
||||
|
||||
var term, |
||||
protocol, |
||||
socketURL, |
||||
socket, |
||||
pid; |
||||
|
||||
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); |
||||
}); |
||||
} |
@ -0,0 +1,108 @@ |
||||
/** |
||||
* |
||||
* Allow xterm.js to handle ZMODEM uploads and downloads. |
||||
* |
||||
* This addon is a wrapper around zmodem.js. It adds the following to the |
||||
* Terminal class: |
||||
* |
||||
* - function `zmodemAttach(<WebSocket>, <Object>)` - creates a Zmodem.Sentry |
||||
* on the passed WebSocket object. The Object passed is optional and |
||||
* can contain: |
||||
* - noTerminalWriteOutsideSession: Suppress writes from the Sentry |
||||
* object to the Terminal while there is no active Session. This |
||||
* is necessary for compatibility with, for example, the |
||||
* `attach.js` addon. |
||||
* |
||||
* - event `zmodemDetect` - fired on Zmodem.Sentry’s `on_detect` callback. |
||||
* Passes the zmodem.js Detection object. |
||||
* |
||||
* - event `zmodemRetract` - fired on Zmodem.Sentry’s `on_retract` callback. |
||||
* |
||||
* You’ll need to provide logic to handle uploads and downloads. |
||||
* See zmodem.js’s documentation for more details. |
||||
* |
||||
* **IMPORTANT:** After you confirm() a zmodem.js Detection, if you have |
||||
* used the `attach` or `terminado` addons, you’ll need to suspend their |
||||
* operation for the duration of the ZMODEM session. (The demo does this |
||||
* via `detach()` and a re-`attach()`.) |
||||
*/ |
||||
(function (addon) { |
||||
if (typeof exports === 'object' && typeof module === 'object') { |
||||
/* |
||||
* CommonJS environment |
||||
*/ |
||||
module.exports = addon(require('../../Terminal').Terminal); |
||||
} else if (typeof define == 'function') { |
||||
/* |
||||
* Require.js is available |
||||
*/ |
||||
define(['../../xterm'], addon); |
||||
} else { |
||||
/* |
||||
* Plain browser environment |
||||
*/ |
||||
addon(window.Terminal); |
||||
} |
||||
})(function _zmodemAddon(Terminal) { |
||||
Object.assign( |
||||
Terminal.prototype, |
||||
{ |
||||
zmodemAttach: function zmodemAttach(ws, opts) { |
||||
var term = this; |
||||
|
||||
if (!opts) opts = {}; |
||||
|
||||
var senderFunc = function _ws_sender_func(octets) { |
||||
ws.send( new Uint8Array(octets) ); |
||||
}; |
||||
|
||||
var zsentry; |
||||
|
||||
function _shouldWrite() { |
||||
return !!zsentry.get_confirmed_session() || !opts.noTerminalWriteOutsideSession; |
||||
} |
||||
|
||||
zsentry = new Zmodem.Sentry( { |
||||
to_terminal: function _to_terminal(octets) { |
||||
if (_shouldWrite()) { |
||||
term.write( |
||||
String.fromCharCode.apply(String, octets) |
||||
); |
||||
} |
||||
}, |
||||
|
||||
sender: senderFunc, |
||||
|
||||
on_retract: function _on_retract() { |
||||
term.emit("zmodemRetract"); |
||||
}, |
||||
|
||||
on_detect: function _on_detect(detection) { |
||||
term.emit("zmodemDetect", detection); |
||||
}, |
||||
} ); |
||||
|
||||
function handleWSMessage(evt) { |
||||
|
||||
//In testing with xterm.js’s demo the first message was
|
||||
//always text even if the rest were binary. While that
|
||||
//may be specific to xterm.js’s demo, ultimately we
|
||||
//should reject anything that isn’t binary.
|
||||
if (typeof evt.data === "string") { |
||||
if (_shouldWrite()) { |
||||
term.write(evt.data); |
||||
} |
||||
} |
||||
else { |
||||
zsentry.consume(evt.data); |
||||
} |
||||
} |
||||
|
||||
ws.binaryType = "arraybuffer"; |
||||
ws.addEventListener("message", handleWSMessage); |
||||
}, |
||||
|
||||
zmodemBrowser: Zmodem.Browser, |
||||
} |
||||
); |
||||
}); |
@ -0,0 +1,124 @@ |
||||
/** |
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved. |
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) |
||||
* https://github.com/chjj/term.js |
||||
* @license MIT |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
* of this software and associated documentation files (the "Software"), to deal |
||||
* in the Software without restriction, including without limitation the rights |
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
* copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in |
||||
* all copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
* THE SOFTWARE. |
||||
* |
||||
* Originally forked from (with the author's permission): |
||||
* Fabrice Bellard's javascript vt100 for jslinux: |
||||
* http://bellard.org/jslinux/ |
||||
* Copyright (c) 2011 Fabrice Bellard |
||||
* The original design remains. The terminal itself |
||||
* has been extended to include xterm CSI codes, among |
||||
* other features. |
||||
*/ |
||||
|
||||
/** |
||||
* Default styles for xterm.js |
||||
*/ |
||||
|
||||
.xterm { |
||||
font-family: courier-new, courier, monospace; |
||||
font-feature-settings: "liga" 0; |
||||
position: relative; |
||||
user-select: none; |
||||
-ms-user-select: none; |
||||
-webkit-user-select: none; |
||||
} |
||||
|
||||
.xterm.focus, |
||||
.xterm:focus { |
||||
outline: none; |
||||
} |
||||
|
||||
.xterm .xterm-helpers { |
||||
position: absolute; |
||||
top: 0; |
||||
/** |
||||
* The z-index of the helpers must be higher than the canvases in order for |
||||
* IMEs to appear on top. |
||||
*/ |
||||
z-index: 10; |
||||
} |
||||
|
||||
.xterm .xterm-helper-textarea { |
||||
/* |
||||
* HACK: to fix IE's blinking cursor |
||||
* Move textarea out of the screen to the far left, so that the cursor is not visible. |
||||
*/ |
||||
position: absolute; |
||||
opacity: 0; |
||||
left: -9999em; |
||||
top: 0; |
||||
width: 0; |
||||
height: 0; |
||||
z-index: -10; |
||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */ |
||||
white-space: nowrap; |
||||
overflow: hidden; |
||||
resize: none; |
||||
} |
||||
|
||||
.xterm .composition-view { |
||||
/* TODO: Composition position got messed up somewhere */ |
||||
background: #333; |
||||
color: #FFF; |
||||
display: none; |
||||
position: absolute; |
||||
white-space: nowrap; |
||||
z-index: 1; |
||||
} |
||||
|
||||
.xterm .composition-view.active { |
||||
display: block; |
||||
} |
||||
|
||||
.xterm .xterm-viewport { |
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */ |
||||
background-color: #333; |
||||
overflow-y: scroll; |
||||
} |
||||
|
||||
.xterm canvas { |
||||
position: absolute; |
||||
left: 0; |
||||
top: 0; |
||||
} |
||||
|
||||
.xterm .xterm-scroll-area { |
||||
visibility: hidden; |
||||
} |
||||
|
||||
.xterm .xterm-char-measure-element { |
||||
display: inline-block; |
||||
visibility: hidden; |
||||
position: absolute; |
||||
left: -9999em; |
||||
} |
||||
|
||||
.xterm.enable-mouse-events { |
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ |
||||
cursor: default; |
||||
} |
||||
|
||||
.xterm:not(.enable-mouse-events) { |
||||
cursor: text; |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue