remove xternjs for now
Signed-off-by: Arthur Lu <learthurgo@gmail.com>
This commit is contained in:
parent
f8ea7a0a03
commit
8dfbdbac78
@ -1,24 +0,0 @@
|
|||||||
<!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>
|
|
@ -1,408 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
@ -1,144 +0,0 @@
|
|||||||
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%;
|
|
||||||
}
|
|
@ -1,134 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
!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
|
|
File diff suppressed because one or more lines are too long
@ -1,175 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user