add basic xternjs functionality

This commit is contained in:
alu committed 2023-02-14 05:14:33 +00:00
1 parent d902277635
commit eb26054c74
13 files changed
+916 -3

No files matched your search

+1
View File
@@ -0,0 +1 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M2 7a5 5 0 015-5h10a5 5 0 015 5v10a5 5 0 01-5 5H7a5 5 0 01-5-5V7zm5-3a3 3 0 00-3 3v10a3 3 0 003 3h10a3 3 0 003-3V7a3 3 0 00-3-3H7zm0 13a1 1 0 011-1h8a1 1 0 110 2H8a1 1 0 01-1-1zm1.707-9.707a1 1 0 10-1.414 1.414L9.586 11l-2.293 2.293a1 1 0 101.414 1.414l3-3a1 1 0 000-1.414l-3-3z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 443 B

+1
View File
@@ -0,0 +1 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M2 7a5 5 0 015-5h10a5 5 0 015 5v10a5 5 0 01-5 5H7a5 5 0 01-5-5V7zm5-3a3 3 0 00-3 3v10a3 3 0 003 3h10a3 3 0 003-3V7a3 3 0 00-3-3H7zm0 13a1 1 0 011-1h8a1 1 0 110 2H8a1 1 0 01-1-1zm1.707-9.707a1 1 0 10-1.414 1.414L9.586 11l-2.293 2.293a1 1 0 101.414 1.414l3-3a1 1 0 000-1.414l-3-3z" fill="#404040"/></svg>

After

Width:  |  Height:  |  Size: 446 B

+24
View File
@@ -0,0 +1,24 @@
<!doctype html>
<html>
<head>
<title>{{ VMName }} - {{ NodeName }}</title>
<link rel="stylesheet" href="xtermjs/xterm.css" />
<link rel="stylesheet" href="style.css" />
<script src="xtermjs/xterm.js" ></script>
<script src="xtermjs/xterm-addon-fit.js" ></script>
<script src="util.js" ></script>
</head>
<body>
<div id="status_bar"></div>
<div id="wrap">
<div class="center">
<div id="connect_dlg">
<div id="pve_start_info">Guest not running</div>
<div id="connect_btn"><div> Start Now </div></div>
</div>
</div>
<div id="terminal-container"></div>
</div>
<script src="main.js" defer ></script>
</body>
</html>
+408
View File
@@ -0,0 +1,408 @@
console.log('xtermjs: starting');
var states = {
start: 1,
connecting: 2,
connected: 3,
disconnecting: 4,
disconnected: 5,
reconnecting: 6,
};
var term,
protocol,
socketURL,
socket,
ticket,
resize,
ping,
state = states.start,
starttime = new Date();
let uridata = getURIData();
var type = uridata.type;
var vmid = uridata.vmid;
var vmname = uridata.name;
var nodename = uridata.node;
if (typeof(PVE) === 'undefined') PVE = {};
PVE.UserName = uridata.user;
PVE.CSRFPreventionToken = getCookie("CSRFPreventionToken");
PVE.url = uridata.url;
document.title = document.title.replace("{{ VMName }}", vmid).replace("{{ NodeName }}", nodename);
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(";");
for(let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === " ") {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
function getURIData () {
let url = new URL(window.location.href);
return Object.fromEntries(url.searchParams);
}
function updateState(newState, msg, code) {
var timeout, severity, message;
switch (newState) {
case states.connecting:
message = "Connecting...";
timeout = 0;
severity = severities.warning;
break;
case states.connected:
window.onbeforeunload = windowUnload;
message = "Connected";
break;
case states.disconnecting:
window.onbeforeunload = undefined;
message = "Disconnecting...";
timeout = 0;
severity = severities.warning;
break;
case states.reconnecting:
window.onbeforeunload = undefined;
message = "Reconnecting...";
timeout = 0;
severity = severities.warning;
break;
case states.disconnected:
window.onbeforeunload = undefined;
switch (state) {
case states.start:
case states.connecting:
case states.reconnecting:
message = "Connection failed";
timeout = 0;
severity = severities.error;
break;
case states.connected:
case states.disconnecting:
var time_since_started = new Date() - starttime;
timeout = 5000;
if (time_since_started > 5*1000 || type === 'shell') {
message = "Connection closed";
} else {
message = "Connection failed";
severity = severities.error;
}
break;
case states.disconnected:
// no state change
break;
default:
throw "unknown state";
}
break;
default:
throw "unknown state";
}
let msgArr = [];
if (msg) {
msgArr.push(msg);
}
if (code !== undefined) {
msgArr.push(`Code: ${code}`);
}
if (msgArr.length > 0) {
message += ` (${msgArr.join(', ')})`;
}
state = newState;
showMsg(message, timeout, severity);
}
var terminalContainer = document.getElementById('terminal-container');
document.getElementById('status_bar').addEventListener('click', hideMsg);
document.getElementById('connect_btn').addEventListener('click', startGuest);
const fitAddon = new FitAddon.FitAddon();
createTerminal();
function startConnection(url, params, term) {
API2Request({
method: 'POST',
params: params,
url: url + '/termproxy',
success: function(result) {
var port = encodeURIComponent(result.data.port);
ticket = result.data.ticket;
socketURL = protocol + "pve.tronnet.net" + ((location.port) ? (':' + location.port) : '') + '/api2/json' + url + '/vncwebsocket?port=' + port + '&vncticket=' + encodeURIComponent(ticket);
term.open(terminalContainer, true);
socket = new WebSocket(socketURL, 'binary');
socket.binaryType = 'arraybuffer';
socket.onopen = runTerminal;
socket.onclose = tryReconnect;
socket.onerror = tryReconnect;
updateState(states.connecting);
},
failure: function(msg) {
updateState(states.disconnected,msg);
}
});
}
function startGuest() {
let api_type = type === 'kvm' ? 'qemu' : 'lxc';
API2Request({
method: 'POST',
url: `/nodes/${nodename}/${api_type}/${vmid}/status/start`,
success: function(result) {
showMsg('Guest started successfully', 0);
setTimeout(function() {
location.reload();
}, 1000);
},
failure: function(msg) {
if (msg.match(/already running/)) {
showMsg('Guest started successfully', 0);
setTimeout(function() {
location.reload();
}, 1000);
} else {
updateState(states.disconnected,msg);
}
}
});
}
function createTerminal() {
term = new Terminal(getTerminalSettings());
term.loadAddon(fitAddon);
term.onResize(function (size) {
if (state === states.connected) {
socket.send("1:" + size.cols + ":" + size.rows + ":");
}
});
protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
var params = {};
var url = '/nodes/' + nodename;
switch (type) {
case 'kvm':
url += '/qemu/' + vmid;
break;
case 'lxc':
url += '/lxc/' + vmid;
break;
case 'upgrade':
params.cmd = 'upgrade';
break;
case 'cmd':
params.cmd = decodeURI(cmd);
if (cmdOpts !== undefined && cmdOpts !== null && cmdOpts !== "") {
params['cmd-opts'] = decodeURI(cmdOpts);
}
break;
}
if (type === 'kvm' || type === 'lxc') {
API2Request({
method: 'GET',
url: `${url}/status/current`,
success: function(result) {
if (result.data.status === 'running') {
startConnection(url, params, term);
} else {
document.getElementById('connect_dlg').classList.add('pve_open');
}
},
failure: function(msg) {
updateState(states.disconnected, msg);
},
});
} else {
startConnection(url, params, term);
}
}
function runTerminal() {
socket.onmessage = function(event) {
var answer = new Uint8Array(event.data);
if (state === states.connected) {
term.write(answer);
} else if(state === states.connecting) {
if (answer[0] === 79 && answer[1] === 75) { // "OK"
updateState(states.connected);
term.write(answer.slice(2));
} else {
socket.close();
}
}
};
term.onData(function(data) {
if (state === states.connected) {
socket.send("0:" + unescape(encodeURIComponent(data)).length.toString() + ":" + data);
}
});
ping = setInterval(function() {
socket.send("2");
}, 30*1000);
window.addEventListener('resize', function() {
clearTimeout(resize);
resize = setTimeout(function() {
// done resizing
fitAddon.fit();
}, 250);
});
socket.send(PVE.UserName + ':' + ticket + "\n");
// initial focus and resize
setTimeout(function() {
term.focus();
fitAddon.fit();
}, 250);
}
function getLxcStatus(callback) {
API2Request({
method: 'GET',
url: '/nodes/' + nodename + '/lxc/' + vmid + '/status/current',
success: function(result) {
if (typeof callback === 'function') {
callback(true, result);
}
},
failure: function(msg) {
if (typeof callback === 'function') {
callback(false, msg);
}
}
});
}
function checkMigration() {
var apitype = type;
if (apitype === 'kvm') {
apitype = 'qemu';
}
API2Request({
method: 'GET',
params: {
type: 'vm'
},
url: '/cluster/resources',
success: function(result) {
// if not yet migrated , wait and try again
// if not migrating and stopped, cancel
// if started, connect
result.data.forEach(function(entity) {
if (entity.id === (apitype + '/' + vmid)) {
var started = entity.status === 'running';
var migrated = entity.node !== nodename;
if (migrated) {
if (started) {
// goto different node
location.href = '?console=' + type +
'&xtermjs=1&vmid=' + vmid + '&vmname=' +
vmname + '&node=' + entity.node;
} else {
// wait again
updateState(states.reconnecting, 'waiting for migration to finish...');
setTimeout(checkMigration, 5000);
}
} else {
if (type === 'lxc') {
// we have to check the status of the
// container to know if it has the
// migration lock
getLxcStatus(function(success, result) {
if (success) {
if (result.data.lock === 'migrate') {
// still waiting
updateState(states.reconnecting, 'waiting for migration to finish...');
setTimeout(checkMigration, 5000);
} else if (started) {
// container was rebooted
location.reload();
} else {
stopTerminal();
}
} else {
// probably the status call failed because
// the ct is already somewhere else, so retry
setTimeout(checkMigration, 1000);
}
});
} else if (started) {
// this happens if we have old data in
// /cluster/resources, or the connection
// disconnected, so simply try to reload here
location.reload();
} else if (type === 'kvm') {
// it seems the guest simply stopped
stopTerminal();
}
}
return;
}
});
},
failure: function(msg) {
errorTerminal({msg: msg});
}
});
}
function tryReconnect(event) {
var time_since_started = new Date() - starttime;
var type = getQueryParameter('console');
if (time_since_started < 5*1000 || type === 'shell' || type === 'cmd') { // 5 seconds
stopTerminal(event);
return;
}
updateState(states.disconnecting, 'Detecting migration...');
setTimeout(checkMigration, 5000);
}
function clearEvents() {
term.onResize(() => {});
term.onData(() => {});
}
function windowUnload(e) {
let message = "Are you sure you want to leave this page?";
e = e || window.event;
if (e) {
e.returnValue = message;
}
return message;
}
function stopTerminal(event) {
event = event || {};
clearEvents();
clearInterval(ping);
socket.close();
updateState(states.disconnected, event.reason, event.code);
}
function errorTerminal(event) {
even = event || {};
clearEvents();
clearInterval(ping);
socket.close();
term.dispose();
updateState(states.disconnected, event.msg, event.code);
}
+144
View File
@@ -0,0 +1,144 @@
html,body {
height: 100%;
min-height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
font-family: Consolas,"DejaVu Sans Mono","Liberation Mono",Courier,monospace;
background-color: #101010;
}
.terminal {
background-color: #101010;
color: #f0f0f0;
font-size: 10pt;
font-family: Consolas,"DejaVu Sans Mono","Liberation Mono",Courier,monospace;
font-variant-ligatures: none;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
.terminal .xterm-viewport {
background-color: rgba(121, 121, 121, 0);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
transition: background-color 800ms linear;
}
/* fix line height on firefox */
.xterm-rows > div > span {
display: inline-block;
}
#terminal-container {
height: 100%;
width: auto;
}
#wrap {
height: 100%;
width: auto;
box-sizing: border-box;
padding: 5px;
}
#status_bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 500;
transform: translateY(-100%);
transition: 0.25s ease-in-out;
visibility: hidden;
opacity: 0;
padding: 5px;
display: flex;
flex-direction: row;
justify-content: center;
align-content: center;
line-height: 25px;
color: #fff;
border-bottom: 1px solid rgba(0, 0, 0, 0.9);
}
#status_bar.open {
transform: translateY(0);
visibility: visible;
opacity: 1;
}
#status_bar.normal {
background: rgba(128,128,128,0.9);
}
#status_bar.error {
background: rgba(200,55,55,0.9);
}
#status_bar.warning {
background: rgba(180,180,30,0.9);
}
#pve_start_info {
color: white;
text-align: center;
font-size: 20px;
padding: 6px;
}
#connect_dlg {
transition: 0.2s ease-in-out;
transform: scale(0, 0);
visibility: hidden;
opacity: 0;
font-family: Helvetica;
}
#connect_dlg.pve_open {
transform: scale(1, 1);
visibility: visible;
opacity: 1;
}
#connect_btn {
cursor: pointer;
padding: 6px;
color: white;
background:#4c4c4c;;
border-radius: 8px;
text-align: center;
font-size: 20px;
box-shadow: 4px 4px 0px rgba(0, 0, 0, 0.5);
}
#connect_btn div {
margin: 2px;
padding: 5px 30px;
border: 1px solid #2f2f2f;
border-bottom-width: 2px;
border-radius: 5px;
background:#4c4c4c;;
/* This avoids it jumping around when :active */
vertical-align: middle;
}
#connect_btn div:active {
border-bottom-width: 1px;
margin-top: 3px;
}
div.center {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
+134
View File
@@ -0,0 +1,134 @@
function urlEncode(object) {
var i,value, params = [];
for (i in object) {
if (object.hasOwnProperty(i)) {
value = object[i];
if (value === undefined) value = '';
params.push(encodeURIComponent(i) + '=' + encodeURIComponent(String(value)));
}
}
return params.join('&');
}
var msgtimeout;
var severities = {
normal: 1,
warning: 2,
error: 3,
};
function showMsg(message, timeout, severity) {
var status_bar = document.getElementById('status_bar');
clearTimeout(msgtimeout);
status_bar.classList.remove('normal');
status_bar.classList.remove('warning');
status_bar.classList.remove('error');
status_bar.textContent = message;
severity = severity || severities.normal;
switch (severity) {
case severities.normal:
status_bar.classList.add('normal');
break;
case severities.warning:
status_bar.classList.add('warning');
break;
case severities.error:
status_bar.classList.add('error');
break;
default:
throw "unknown severity";
}
status_bar.classList.add('open');
if (timeout !== 0) {
msgtimeout = setTimeout(hideMsg, timeout || 1500);
}
}
function hideMsg() {
clearTimeout(msgtimeout);
status_bar.classList.remove('open');
}
function API2Request(reqOpts) {
var me = this;
reqOpts.method = reqOpts.method || 'GET';
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var scope = reqOpts.scope || this;
var result;
var errmsg;
if (xhr.readyState === 4) {
var ctype = xhr.getResponseHeader('Content-Type');
if (xhr.status === 200) {
if (ctype.match(/application\/json;/)) {
result = JSON.parse(xhr.responseText);
} else {
errmsg = 'got unexpected content type ' + ctype;
}
} else {
errmsg = 'Error ' + xhr.status + ': ' + xhr.statusText;
}
} else {
errmsg = 'Connection error - server offline?';
}
if (errmsg !== undefined) {
if (reqOpts.failure) {
reqOpts.failure.call(scope, errmsg);
}
} else {
if (reqOpts.success) {
reqOpts.success.call(scope, result);
}
}
if (reqOpts.callback) {
reqOpts.callback.call(scope, errmsg === undefined);
}
}
var data = urlEncode(reqOpts.params || {});
xhr.withCredentials = true;
if (reqOpts.method === 'GET') {
xhr.open(reqOpts.method, "https://" + PVE.url + reqOpts.url + '?' + data);
} else {
xhr.open(reqOpts.method, "https://" + PVE.url + reqOpts.url);
}
xhr.setRequestHeader('Cache-Control', 'no-cache');
if (reqOpts.method === 'POST' || reqOpts.method === 'PUT') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.setRequestHeader('CSRFPreventionToken', PVE.CSRFPreventionToken);
xhr.send(data);
} else if (reqOpts.method === 'GET') {
xhr.send();
} else {
throw "unknown method";
}
}
function getTerminalSettings() {
var res = {};
var settings = ['fontSize', 'fontFamily', 'letterSpacing', 'lineHeight'];
if(localStorage) {
settings.forEach(function(setting) {
var val = localStorage.getItem('pve-xterm-' + setting);
if (val !== undefined && val !== null) {
res[setting] = val;
}
});
}
return res;
}
+2
View File
@@ -0,0 +1,2 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(self,(function(){return(()=>{"use strict";var e={775:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0;var r=function(){function e(){}return e.prototype.activate=function(e){this._terminal=e},e.prototype.dispose=function(){},e.prototype.fit=function(){var e=this.proposeDimensions();if(e&&this._terminal){var t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}},e.prototype.proposeDimensions=function(){if(this._terminal&&this._terminal.element&&this._terminal.element.parentElement){var e=this._terminal._core;if(0!==e._renderService.dimensions.actualCellWidth&&0!==e._renderService.dimensions.actualCellHeight){var t=window.getComputedStyle(this._terminal.element.parentElement),r=parseInt(t.getPropertyValue("height")),i=Math.max(0,parseInt(t.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),o=r-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),a=i-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-e.viewport.scrollBarWidth;return{cols:Math.max(2,Math.floor(a/e._renderService.dimensions.actualCellWidth)),rows:Math.max(1,Math.floor(o/e._renderService.dimensions.actualCellHeight))}}}},e}();t.FitAddon=r}},t={};return function r(i){if(t[i])return t[i].exports;var n=t[i]={exports:{}};return e[i](n,n.exports,r),n.exports}(775)})()}));
//# sourceMappingURL=xterm-addon-fit.js.map
@@ -0,0 +1 @@
{"version":3,"sources":["webpack://FitAddon/webpack/universalModuleDefinition","webpack://FitAddon/./src/FitAddon.ts","webpack://FitAddon/webpack/bootstrap","webpack://FitAddon/webpack/startup"],"names":["root","factory","exports","module","define","amd","self","activate","terminal","this","_terminal","dispose","fit","dims","proposeDimensions","core","_core","rows","cols","_renderService","clear","resize","element","parentElement","dimensions","actualCellWidth","actualCellHeight","parentElementStyle","window","getComputedStyle","parentElementHeight","parseInt","getPropertyValue","parentElementWidth","Math","max","elementStyle","availableHeight","availableWidth","viewport","scrollBarWidth","floor","FitAddon","__webpack_module_cache__","__webpack_require__","moduleId","__webpack_modules__"],"mappings":"CAAA,SAA2CA,EAAMC,GAC1B,iBAAZC,SAA0C,iBAAXC,OACxCA,OAAOD,QAAUD,IACQ,mBAAXG,QAAyBA,OAAOC,IAC9CD,OAAO,GAAIH,GACe,iBAAZC,QACdA,QAAkB,SAAID,IAEtBD,EAAe,SAAIC,IARrB,CASGK,MAAM,WACT,M,yGCSA,IAGA,aAGE,cA4DF,OA1DS,YAAAC,SAAP,SAAgBC,GACdC,KAAKC,UAAYF,GAGZ,YAAAG,QAAP,aAEO,YAAAC,IAAP,WACE,IAAMC,EAAOJ,KAAKK,oBAClB,GAAKD,GAASJ,KAAKC,UAAnB,CAKA,IAAMK,EAAQN,KAAKC,UAAkBM,MAGjCP,KAAKC,UAAUO,OAASJ,EAAKI,MAAQR,KAAKC,UAAUQ,OAASL,EAAKK,OACpEH,EAAKI,eAAeC,QACpBX,KAAKC,UAAUW,OAAOR,EAAKK,KAAML,EAAKI,SAInC,YAAAH,kBAAP,WACE,GAAKL,KAAKC,WAILD,KAAKC,UAAUY,SAAYb,KAAKC,UAAUY,QAAQC,cAAvD,CAKA,IAAMR,EAAQN,KAAKC,UAAkBM,MAErC,GAAuD,IAAnDD,EAAKI,eAAeK,WAAWC,iBAA6E,IAApDV,EAAKI,eAAeK,WAAWE,iBAA3F,CAIA,IAAMC,EAAqBC,OAAOC,iBAAiBpB,KAAKC,UAAUY,QAAQC,eACpEO,EAAsBC,SAASJ,EAAmBK,iBAAiB,WACnEC,EAAqBC,KAAKC,IAAI,EAAGJ,SAASJ,EAAmBK,iBAAiB,WAC9EI,EAAeR,OAAOC,iBAAiBpB,KAAKC,UAAUY,SAStDe,EAAkBP,GAPjBC,SAASK,EAAaJ,iBAAiB,gBACpCD,SAASK,EAAaJ,iBAAiB,oBAO3CM,EAAiBL,GANdF,SAASK,EAAaJ,iBAAiB,kBACxCD,SAASK,EAAaJ,iBAAiB,kBAKiBjB,EAAKwB,SAASC,eAK9E,MAJiB,CACftB,KAAMgB,KAAKC,IA7DI,EA6DcD,KAAKO,MAAMH,EAAiBvB,EAAKI,eAAeK,WAAWC,kBACxFR,KAAMiB,KAAKC,IA7DI,EA6DcD,KAAKO,MAAMJ,EAAkBtB,EAAKI,eAAeK,WAAWE,uBAI/F,EA/DA,GAAa,EAAAgB,aCrBTC,EAA2B,GCE/B,ODCA,SAASC,EAAoBC,GAE5B,GAAGF,EAAyBE,GAC3B,OAAOF,EAAyBE,GAAU3C,QAG3C,IAAIC,EAASwC,EAAyBE,GAAY,CAGjD3C,QAAS,IAOV,OAHA4C,EAAoBD,GAAU1C,EAAQA,EAAOD,QAAS0C,GAG/CzC,EAAOD,QCjBR0C,CAAoB,M","file":"xterm-addon-fit.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"FitAddon\"] = factory();\n\telse\n\t\troot[\"FitAddon\"] = factory();\n})(self, function() {\nreturn ","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { Terminal, ITerminalAddon } from 'xterm';\n\ninterface ITerminalDimensions {\n /**\n * The number of rows in the terminal.\n */\n rows: number;\n\n /**\n * The number of columns in the terminal.\n */\n cols: number;\n}\n\nconst MINIMUM_COLS = 2;\nconst MINIMUM_ROWS = 1;\n\nexport class FitAddon implements ITerminalAddon {\n private _terminal: Terminal | undefined;\n\n constructor() {}\n\n public activate(terminal: Terminal): void {\n this._terminal = terminal;\n }\n\n public dispose(): void {}\n\n public fit(): void {\n const dims = this.proposeDimensions();\n if (!dims || !this._terminal) {\n return;\n }\n\n // TODO: Remove reliance on private API\n const core = (this._terminal as any)._core;\n\n // Force a full render\n if (this._terminal.rows !== dims.rows || this._terminal.cols !== dims.cols) {\n core._renderService.clear();\n this._terminal.resize(dims.cols, dims.rows);\n }\n }\n\n public proposeDimensions(): ITerminalDimensions | undefined {\n if (!this._terminal) {\n return undefined;\n }\n\n if (!this._terminal.element || !this._terminal.element.parentElement) {\n return undefined;\n }\n\n // TODO: Remove reliance on private API\n const core = (this._terminal as any)._core;\n\n if (core._renderService.dimensions.actualCellWidth === 0 || core._renderService.dimensions.actualCellHeight === 0) {\n return undefined;\n }\n\n const parentElementStyle = window.getComputedStyle(this._terminal.element.parentElement);\n const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));\n const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')));\n const elementStyle = window.getComputedStyle(this._terminal.element);\n const elementPadding = {\n top: parseInt(elementStyle.getPropertyValue('padding-top')),\n bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')),\n right: parseInt(elementStyle.getPropertyValue('padding-right')),\n left: parseInt(elementStyle.getPropertyValue('padding-left'))\n };\n const elementPaddingVer = elementPadding.top + elementPadding.bottom;\n const elementPaddingHor = elementPadding.rigLine truncated
+175
View File
@@ -0,0 +1,175 @@
/**
* 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 {
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: 5;
}
.xterm .xterm-helper-textarea {
padding: 0;
border: 0;
margin: 0;
/* 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: -5;
/** 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: #000;
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: #000;
overflow-y: scroll;
cursor: default;
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 0;
}
.xterm .xterm-screen {
position: relative;
}
.xterm .xterm-screen canvas {
position: absolute;
left: 0;
top: 0;
}
.xterm .xterm-scroll-area {
visibility: hidden;
}
.xterm-char-measure-element {
display: inline-block;
visibility: hidden;
position: absolute;
top: 0;
left: -9999em;
line-height: normal;
}
.xterm {
cursor: text;
}
.xterm.enable-mouse-events {
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
cursor: default;
}
.xterm.xterm-cursor-pointer,
.xterm .xterm-cursor-pointer {
cursor: pointer;
}
.xterm.column-select.focus {
/* Column selection mode */
cursor: crosshair;
}
.xterm .xterm-accessibility,
.xterm .xterm-message {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 10;
color: transparent;
}
.xterm .live-region {
position: absolute;
left: -9999px;
width: 1px;
height: 1px;
overflow: hidden;
}
.xterm-dim {
opacity: 0.5;
}
.xterm-underline {
text-decoration: underline;
}
.xterm-strikethrough {
text-decoration: line-through;
}
+2
View File
@@ -0,0 +1,2 @@
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var r=t();for(var i in r)("object"==typeof exports?exports:e)[i]=r[i]}}(self,(function(){return(()=>{"use strict";var e={4567:function(e,t,r){var i,n=this&&this.__extends||(i=function(e,t){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},i(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}i(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.AccessibilityManager=void 0;var o=r(9042),s=r(6114),a=r(9924),c=r(3656),l=r(844),h=r(5596),u=r(9631),f=function(e){function t(t,r){var i=e.call(this)||this;i._terminal=t,i._renderService=r,i._liveRegionLineCount=0,i._charsToConsume=[],i._charsToAnnounce="",i._accessibilityTreeRoot=document.createElement("div"),i._accessibilityTreeRoot.setAttribute("role","document"),i._accessibilityTreeRoot.classList.add("xterm-accessibility"),i._accessibilityTreeRoot.tabIndex=0,i._rowContainer=document.createElement("div"),i._rowContainer.setAttribute("role","list"),i._rowContainer.classList.add("xterm-accessibility-tree"),i._rowElements=[];for(var n=0;n<i._terminal.rows;n++)i._rowElements[n]=i._createAccessibilityTreeNode(),i._rowContainer.appendChild(i._rowElements[n]);if(i._topBoundaryFocusListener=function(e){return i._onBoundaryFocus(e,0)},i._bottomBoundaryFocusListener=function(e){return i._onBoundaryFocus(e,1)},i._rowElements[0].addEventListener("focus",i._topBoundaryFocusListener),i._rowElements[i._rowElements.length-1].addEventListener("focus",i._bottomBoundaryFocusListener),i._refreshRowsDimensions(),i._accessibilityTreeRoot.appendChild(i._rowContainer),i._renderRowsDebouncer=new a.TimeBasedDebouncer(i._renderRows.bind(i)),i._refreshRows(),i._liveRegion=document.createElement("div"),i._liveRegion.classList.add("live-region"),i._liveRegion.setAttribute("aria-live","assertive"),i._accessibilityTreeRoot.appendChild(i._liveRegion),!i._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");return i._terminal.element.insertAdjacentElement("afterbegin",i._accessibilityTreeRoot),i.register(i._renderRowsDebouncer),i.register(i._terminal.onResize((function(e){return i._onResize(e.rows)}))),i.register(i._terminal.onRender((function(e){return i._refreshRows(e.start,e.end)}))),i.register(i._terminal.onScroll((function(){return i._refreshRows()}))),i.register(i._terminal.onA11yChar((function(e){return i._onChar(e)}))),i.register(i._terminal.onLineFeed((function(){return i._onChar("\n")}))),i.register(i._terminal.onA11yTab((function(e){return i._onTab(e)}))),i.register(i._terminal.onKey((function(e){return i._onKey(e.key)}))),i.register(i._terminal.onBlur((function(){return i._clearLiveRegion()}))),i.register(i._renderService.onDimensionsChange((function(){return i._refreshRowsDimensions()}))),i._screenDprMonitor=new h.ScreenDprMonitor,i.register(i._screenDprMonitor),i._screenDprMonitor.setListener((function(){return i._refreshRowsDimensions()})),i.register((0,c.addDisposableDomListener)(window,"resize",(function(){return i._refreshRowsDimensions()}))),i}return n(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this),(0,u.removeElementFromParent)(this._accessibilityTreeRoot),this._rowElements.length=0},t.prototype._onBoundaryFocus=function(e,t){var r=e.target,i=this._rowElements[0===t?1:this._rowElements.length-2];if(r.getAttribute("aria-posinset")!==(0===t?"1":""+this._terminal.buffer.lines.length)&&e.relatedTarget===i){var n,o;if(0===t?(n=r,o=this._rowElements.pop(),this._rowContainer.removeChild(o)):(n=this._rowElements.shift(),o=r,this._rowContainer.removeChild(n)),n.removeEventListener("focus",this._topBoundaryFocusListener),o.removeEventListener("focus",this._bottomBoundaryFocusListener),0===t){var s=this._createAccessibilityTreeNode();this._rowElements.unshift(s),this._rowContainer.insertAdjacentElement("afterbegin",s)}else s=this._createAccessibilityTreeNode(),this._rowElements.push(s),this._rowContainer.appendChild(s);this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._terminal.scrollLines(0===t?-1:1),this._rowElements[0===t?1:this._rowElements.length-2].focus(),e.preventDefault(),e.stopImmediatePropagation()}},t.prototype._onResize=function(e){this._rowElements[this._rowElements.length-1].removeEventListener("focus",this._bottomBoundaryFocusListener);for(var t=this._rowContainer.children.length;t<this._terminal.rows;t++)this._rowElements[t]=this._createAccessibilityTreeNode(),this._rowContainer.appendChild(this._rowElements[t]);for(;Line truncated
//# sourceMappingURL=xterm.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"xterm.js","mappings":"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 truncated
+14
View File
@@ -24,6 +24,7 @@ export class Instance extends HTMLElement {
<div class="btn-group"> <div class="btn-group">
<img id="power-btn"> <img id="power-btn">
<img id="configure-btn" alt="change instance configuration"> <img id="configure-btn" alt="change instance configuration">
<img id="console-btn" alt="connect to instance console or display">
</div> </div>
</article> </article>
`; `;
@@ -73,9 +74,16 @@ export class Instance extends HTMLElement {
configButton.title = instances[this.status].configButtonAlt; configButton.title = instances[this.status].configButtonAlt;
configButton.addEventListener("click", this.handleConfigButton.bind(this)); configButton.addEventListener("click", this.handleConfigButton.bind(this));
let consoleButton = this.shadowElement.querySelector("#console-btn");
consoleButton.src = instances[this.status].consoleButtonSrc;
consoleButton.alt = instances[this.status].consoleButtonAlt;
consoleButton.title = instances[this.status].consoleButtonAlt;
consoleButton.addEventListener("click", this.handleConsoleButton.bind(this));
if (this.node.status !== "online") { if (this.node.status !== "online") {
powerButton.classList.add("hidden"); powerButton.classList.add("hidden");
configButton.classList.add("hidden"); configButton.classList.add("hidden");
consoleButton.classList.add("hidden");
} }
} }
@@ -120,6 +128,12 @@ export class Instance extends HTMLElement {
goToPage("config.html", {node: this.node.name, type: this.type, vmid: this.vmid}); goToPage("config.html", {node: this.node.name, type: this.type, vmid: this.vmid});
} }
} }
handleConsoleButton () {
if (this.status === "running") {
goToPage("pve-xtermjs/index.html", {type: this.type, vmid: this.vmid, name: this.name, node: this.node.name, user: "alu@ldap", url: "pve.tronnet.net/api2/json"});
}
}
} }
export class Dialog extends HTMLElement { export class Dialog extends HTMLElement {
+9 -3
View File
@@ -37,19 +37,25 @@ export const instances = {
powerButtonSrc: "images/actions/stop.svg", powerButtonSrc: "images/actions/stop.svg",
powerButtonAlt: "Shutdown Instance", powerButtonAlt: "Shutdown Instance",
configButtonSrc: "images/actions/config-inactive.svg", configButtonSrc: "images/actions/config-inactive.svg",
configButtonAlt: "Configuration Disabled" configButtonAlt: "Configuration Disabled",
consoleButtonSrc: "images/actions/console-active.svg",
consoleButtonAlt: "Open Console"
}, },
stopped: { stopped: {
powerButtonSrc: "images/actions/start.svg", powerButtonSrc: "images/actions/start.svg",
powerButtonAlt: "Start Instance", powerButtonAlt: "Start Instance",
configButtonSrc: "images/actions/config-active.svg", configButtonSrc: "images/actions/config-active.svg",
configButtonAlt: "Configure Instance" configButtonAlt: "Configure Instance",
consoleButtonSrc: "images/actions/console-inactive.svg",
consoleButtonAlt: "Console Inactive"
}, },
loading: { loading: {
powerButtonSrc: "images/actions/loading.svg", powerButtonSrc: "images/actions/loading.svg",
powerButtonAlt: "Loading Instance", powerButtonAlt: "Loading Instance",
configButtonSrc: "images/actions/config-inactive.svg", configButtonSrc: "images/actions/config-inactive.svg",
configButtonAlt: "Configuration Disabled" configButtonAlt: "Configuration Disabled",
consoleButtonSrc: "images/actions/console-inactive.svg",
consoleButtonAlt: "Console Inactive"
} }
} }