mirror of
https://github.com/retspen/webvirtcloud
synced 2024-12-25 15:45:23 +00:00
Merge pull request #521 from catborise/master
remove css urls, add missing socketio requirements, fix cookie import…
This commit is contained in:
commit
d23896ddf6
17 changed files with 13357 additions and 22 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
.vagrant
|
.vagrant
|
||||||
|
.venv
|
||||||
venv
|
venv
|
||||||
venv2
|
venv2
|
||||||
.vscode
|
.vscode
|
||||||
|
@ -14,3 +15,4 @@ webvirtcloud/settings.py
|
||||||
*migrations/*
|
*migrations/*
|
||||||
.coverage
|
.coverage
|
||||||
htmlcov
|
htmlcov
|
||||||
|
*.log
|
||||||
|
|
|
@ -19,7 +19,7 @@ def error_handler(unused, error) -> None:
|
||||||
# The console stream errors on VM shutdown; we don't care
|
# The console stream errors on VM shutdown; we don't care
|
||||||
if error[0] == libvirt.VIR_ERR_RPC and error[1] == libvirt.VIR_FROM_STREAMS:
|
if error[0] == libvirt.VIR_ERR_RPC and error[1] == libvirt.VIR_FROM_STREAMS:
|
||||||
return
|
return
|
||||||
logging.warn(error)
|
logging.warning(error)
|
||||||
|
|
||||||
|
|
||||||
class Console(object):
|
class Console(object):
|
||||||
|
|
|
@ -14,3 +14,4 @@ websockify==0.10.0
|
||||||
zipp==3.6.0
|
zipp==3.6.0
|
||||||
ldap3==2.9.1
|
ldap3==2.9.1
|
||||||
python-socketio==5.7.0
|
python-socketio==5.7.0
|
||||||
|
eventlet==0.33.1
|
|
@ -17,7 +17,8 @@ django.setup()
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
from six.moves import http_cookies as Cookie
|
#from six.moves import http_cookies as Cookie
|
||||||
|
from http import cookies as Cookie
|
||||||
from webvirtcloud.settings import WS_PORT, WS_HOST, WS_CERT
|
from webvirtcloud.settings import WS_PORT, WS_HOST, WS_CERT
|
||||||
from vrtManager.connection import CONN_SSH, CONN_SOCKET
|
from vrtManager.connection import CONN_SSH, CONN_SOCKET
|
||||||
from console.sshtunnels import SSHTunnels
|
from console.sshtunnels import SSHTunnels
|
||||||
|
|
|
@ -32,7 +32,8 @@ import tty
|
||||||
import termios
|
import termios
|
||||||
import libvirt
|
import libvirt
|
||||||
|
|
||||||
from six.moves import http_cookies as Cookie
|
#from six.moves import http_cookies as Cookie
|
||||||
|
from http import cookies as Cookie
|
||||||
from webvirtcloud.settings import SOCKETIO_PORT, SOCKETIO_HOST
|
from webvirtcloud.settings import SOCKETIO_PORT, SOCKETIO_HOST
|
||||||
from vrtManager.connection import CONN_SSH, CONN_SOCKET
|
from vrtManager.connection import CONN_SSH, CONN_SOCKET
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
@ -79,7 +80,7 @@ else:
|
||||||
logging.basicConfig(level=logging.WARNING, format=FORMAT)
|
logging.basicConfig(level=logging.WARNING, format=FORMAT)
|
||||||
|
|
||||||
async_mode = "eventlet"
|
async_mode = "eventlet"
|
||||||
sio = socketio.Server(async_mode=async_mode, cors_allowed_origins="https://vmm.cyborgside.net")
|
sio = socketio.Server(async_mode=async_mode, cors_allowed_origins=[])
|
||||||
|
|
||||||
fd = None
|
fd = None
|
||||||
child_pid = None
|
child_pid = None
|
||||||
|
@ -171,7 +172,8 @@ def connect(sid, environ):
|
||||||
(instance, conn) = get_connection_infos(token)
|
(instance, conn) = get_connection_infos(token)
|
||||||
uuid = conn.get_uuid()
|
uuid = conn.get_uuid()
|
||||||
uri = conn.wvm.getURI()
|
uri = conn.wvm.getURI()
|
||||||
subprocess.run(["/srv/webvirtcloud/venv/bin/python3", "/srv/webvirtcloud/venv/bin/consolecallback", uri, uuid])
|
|
||||||
|
subprocess.run(['conf/daemon/consolecallback', uri, uuid])
|
||||||
else:
|
else:
|
||||||
# this is the parent process fork.
|
# this is the parent process fork.
|
||||||
sio.start_background_task(target=read_and_forward_pty_output)
|
sio.start_background_task(target=read_and_forward_pty_output)
|
||||||
|
|
|
@ -4,28 +4,45 @@
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<title>WebVirtCloud - XTerm</title>
|
<title>WebVirtCloud - XTerm</title>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/xterm@3.6.0/dist/xterm.css" />
|
<link rel="stylesheet" href="{% static 'css/xterm.css' %}"/>
|
||||||
<script src="https://unpkg.com/xterm@3.6.0/dist/xterm.js"></script>
|
<script src="{% static 'js/xterm@3.6.0/xterm.js' %}"></script>
|
||||||
<script src="https://unpkg.com/xterm@3.6.0/dist/addons/fit/fit.js"></script>
|
<script src="{% static 'js/xterm@3.6.0/addons/fit/fit.js' %}"></script>
|
||||||
<script src="https://unpkg.com/xterm@3.6.0/dist/addons/fullscreen/fullscreen.js"></script>
|
<script src="{% static 'js/xterm@3.6.0/addons/fullscreen/fullscreen.js' %}"></script>
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.0/socket.io.js"></script>
|
<script src="{% static 'js/socket.io.js' %}"></script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div style="background: white; padding-bottom: 5px;">
|
<div style="background: white; padding-bottom: 5px;">
|
||||||
<span style="font-size: small;">Status: <span style="font-size: small;" id="status">connecting...</span></span>
|
<span style="font-size: small;">Status: <span style="font-size: small;" id="status">connecting...</span></span>
|
||||||
<button id="button"; type="button"; onclick="myFunction()";>Connect</button>
|
<button id="button" type="button" onclick="myFunction();">Connect</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="width: 100%; height:100%;" id="terminal"></div>
|
<div style="width: 100%; height:100%;" id="terminal"></div>
|
||||||
<script crossorigin="anonymous">
|
<script crossorigin="anonymous">
|
||||||
Terminal.applyAddon(fit)
|
Terminal.applyAddon(fit);
|
||||||
|
|
||||||
var socket = io.connect({transports: ["websocket", "polling"]});
|
let host = readQueryVariable('host', '{{ socketio_host }}');
|
||||||
|
let port = readQueryVariable('port', '{{ socketio_port }}');
|
||||||
|
let path = readQueryVariable('path', '{{ socketio_path }}');
|
||||||
|
|
||||||
const status = document.getElementById("status")
|
|
||||||
const button = document.getElementById("button")
|
// Build the websocket URL used to connect
|
||||||
|
let url;
|
||||||
|
if (window.location.protocol === "https:") {
|
||||||
|
url = 'wss';
|
||||||
|
} else {
|
||||||
|
url = 'ws';
|
||||||
|
}
|
||||||
|
url += '://' + host;
|
||||||
|
if (port) {
|
||||||
|
url += ':' + port;
|
||||||
|
}
|
||||||
|
|
||||||
|
var socket = io.connect(url, {transports: ["websocket", "polling"]});
|
||||||
|
|
||||||
|
const status = document.getElementById("status");
|
||||||
|
const button = document.getElementById("button");
|
||||||
|
|
||||||
var term = new Terminal({
|
var term = new Terminal({
|
||||||
cursorBlink: true,
|
cursorBlink: true,
|
||||||
|
@ -44,14 +61,13 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on("connect", () => {
|
socket.on("connect", () => {
|
||||||
status.innerHTML = '<span style="background-color: lightgreen;">connected</span>'
|
status.innerHTML = '<span style="background-color: lightgreen;">connected</span>'
|
||||||
button.innerHTML = 'Disconnect'
|
button.innerHTML = 'Disconnect'
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on("disconnect", () => {
|
socket.on("disconnect", () => {
|
||||||
status.innerHTML = '<span style="background-color: #ff8383;">disconnected</span>'
|
status.innerHTML = '<span style="background-color: #ff8383;">disconnected</span>'
|
||||||
button.innerHTML = 'Connect'
|
button.innerHTML = 'Connect'
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function myFunction(){
|
function myFunction(){
|
||||||
|
@ -69,6 +85,26 @@
|
||||||
socket.emit("resize", {"cols": term.cols, "rows": term.rows})
|
socket.emit("resize", {"cols": term.cols, "rows": term.rows})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function extracts the value of one variable from the
|
||||||
|
// query string. If the variable isn't defined in the URL
|
||||||
|
// it returns the default value instead.
|
||||||
|
function readQueryVariable(name, defaultValue) {
|
||||||
|
// A URL with a query parameter can look like this:
|
||||||
|
// https://www.example.com?myqueryparam=myvalue
|
||||||
|
//
|
||||||
|
// Note that we use location.href instead of location.search
|
||||||
|
// because Firefox < 53 has a bug w.r.t location.search
|
||||||
|
const re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
|
||||||
|
match = document.location.href.match(re);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
// We have to decode the URL since want the cleartext value
|
||||||
|
return decodeURIComponent(match[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
window.onresize = resize
|
window.onresize = resize
|
||||||
window.onload = resize
|
window.onload = resize
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -15,6 +15,9 @@ from webvirtcloud.settings import (
|
||||||
WS_PUBLIC_HOST,
|
WS_PUBLIC_HOST,
|
||||||
WS_PUBLIC_PATH,
|
WS_PUBLIC_PATH,
|
||||||
WS_PUBLIC_PORT,
|
WS_PUBLIC_PORT,
|
||||||
|
SOCKETIO_PUBLIC_HOST,
|
||||||
|
SOCKETIO_PUBLIC_PORT,
|
||||||
|
SOCKETIO_PUBLIC_PATH
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,6 +83,13 @@ def console(request):
|
||||||
console_page = "console-" + console_type + "-" + view_type + ".html"
|
console_page = "console-" + console_type + "-" + view_type + ".html"
|
||||||
response = render(request, console_page, locals())
|
response = render(request, console_page, locals())
|
||||||
elif console_type == "pty":
|
elif console_type == "pty":
|
||||||
|
socketio_host = SOCKETIO_PUBLIC_HOST if SOCKETIO_PUBLIC_HOST else request.get_host()
|
||||||
|
socketio_port = SOCKETIO_PUBLIC_PORT if SOCKETIO_PUBLIC_PORT else 6081
|
||||||
|
socketio_path = SOCKETIO_PUBLIC_PATH if SOCKETIO_PUBLIC_PATH else "/"
|
||||||
|
|
||||||
|
if ":" in socketio_host:
|
||||||
|
socketio_host = re.sub(":[0-9]+", "", socketio_host)
|
||||||
|
|
||||||
response = render(request, "console-xterm.html", locals())
|
response = render(request, "console-xterm.html", locals())
|
||||||
else:
|
else:
|
||||||
if console_type is None:
|
if console_type is None:
|
||||||
|
|
164
static/css/xterm.css
Normal file
164
static/css/xterm.css
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/**
|
||||||
|
* 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: #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 {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm.xterm-cursor-crosshair {
|
||||||
|
/* Column selection mode */
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-accessibility,
|
||||||
|
.xterm .xterm-message {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .live-region {
|
||||||
|
position: absolute;
|
||||||
|
left: -9999px;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
4440
static/js/socket.io.js
Normal file
4440
static/js/socket.io.js
Normal file
File diff suppressed because it is too large
Load diff
51
static/js/xterm@3.6.0/addons/fit/fit.js
Normal file
51
static/js/xterm@3.6.0/addons/fit/fit.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.fit = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
function proposeGeometry(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')));
|
||||||
|
var elementStyle = window.getComputedStyle(term.element);
|
||||||
|
var elementPadding = {
|
||||||
|
top: parseInt(elementStyle.getPropertyValue('padding-top')),
|
||||||
|
bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')),
|
||||||
|
right: parseInt(elementStyle.getPropertyValue('padding-right')),
|
||||||
|
left: parseInt(elementStyle.getPropertyValue('padding-left'))
|
||||||
|
};
|
||||||
|
var elementPaddingVer = elementPadding.top + elementPadding.bottom;
|
||||||
|
var elementPaddingHor = elementPadding.right + elementPadding.left;
|
||||||
|
var availableHeight = parentElementHeight - elementPaddingVer;
|
||||||
|
var availableWidth = parentElementWidth - elementPaddingHor - term._core.viewport.scrollBarWidth;
|
||||||
|
var geometry = {
|
||||||
|
cols: Math.floor(availableWidth / term._core.renderer.dimensions.actualCellWidth),
|
||||||
|
rows: Math.floor(availableHeight / term._core.renderer.dimensions.actualCellHeight)
|
||||||
|
};
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
exports.proposeGeometry = proposeGeometry;
|
||||||
|
function fit(term) {
|
||||||
|
var geometry = proposeGeometry(term);
|
||||||
|
if (geometry) {
|
||||||
|
if (term.rows !== geometry.rows || term.cols !== geometry.cols) {
|
||||||
|
term._core.renderer.clear();
|
||||||
|
term.resize(geometry.cols, geometry.rows);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.fit = fit;
|
||||||
|
function apply(terminalConstructor) {
|
||||||
|
terminalConstructor.prototype.proposeGeometry = function () {
|
||||||
|
return proposeGeometry(this);
|
||||||
|
};
|
||||||
|
terminalConstructor.prototype.fit = function () {
|
||||||
|
fit(this);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
exports.apply = apply;
|
||||||
|
|
||||||
|
},{}]},{},[1])(1)
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=fit.js.map
|
1
static/js/xterm@3.6.0/addons/fit/fit.js.map
Normal file
1
static/js/xterm@3.6.0/addons/fit/fit.js.map
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"fit.js","sources":["../../../src/addons/fit/fit.ts","../../../node_modules/browser-pack/_prelude.js"],"sourcesContent":["/**\n * Copyright (c) 2014 The xterm.js authors. All rights reserved.\n * @license MIT\n *\n * Fit terminal columns and rows to the dimensions of its DOM element.\n *\n * ## Approach\n *\n * Rows: Truncate the division of the terminal parent element height by the\n * terminal row height.\n * Columns: Truncate the division of the terminal parent element width by the\n * terminal character width (apply display: inline at the terminal\n * row and truncate its width with the current number of columns).\n */\n\nimport { Terminal } from 'xterm';\n\nexport interface IGeometry {\n rows: number;\n cols: number;\n}\n\nexport function proposeGeometry(term: Terminal): IGeometry {\n if (!term.element.parentElement) {\n return null;\n }\n const parentElementStyle = window.getComputedStyle(term.element.parentElement);\n const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));\n const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')));\n const elementStyle = window.getComputedStyle(term.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.right + elementPadding.left;\n const availableHeight = parentElementHeight - elementPaddingVer;\n const availableWidth = parentElementWidth - elementPaddingHor - (<any>term)._core.viewport.scrollBarWidth;\n const geometry = {\n cols: Math.floor(availableWidth / (<any>term)._core.renderer.dimensions.actualCellWidth),\n rows: Math.floor(availableHeight / (<any>term)._core.renderer.dimensions.actualCellHeight)\n };\n return geometry;\n}\n\nexport function fit(term: Terminal): void {\n const geometry = proposeGeometry(term);\n if (geometry) {\n // Force a full render\n if (term.rows !== geometry.rows || term.cols !== geometry.cols) {\n (<any>term)._core.renderer.clear();\n term.resize(geometry.cols, geometry.rows);\n }\n }\n}\n\nexport function apply(terminalConstructor: typeof Terminal): void {\n (<any>terminalConstructor.prototype).proposeGeometry = function (): IGeometry {\n return proposeGeometry(this);\n };\n\n (<any>terminalConstructor.prototype).fit = function (): void {\n fit(this);\n };\n}\n",null],"names":[],"mappings":"ACAA;;;ADsBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAvBA;AAyBA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AATA;AAWA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AARA;"}
|
10
static/js/xterm@3.6.0/addons/fullscreen/fullscreen.css
Normal file
10
static/js/xterm@3.6.0/addons/fullscreen/fullscreen.css
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
.xterm.fullscreen {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
z-index: 255;
|
||||||
|
}
|
27
static/js/xterm@3.6.0/addons/fullscreen/fullscreen.js
Normal file
27
static/js/xterm@3.6.0/addons/fullscreen/fullscreen.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.fullscreen = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
function toggleFullScreen(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');
|
||||||
|
}
|
||||||
|
exports.toggleFullScreen = toggleFullScreen;
|
||||||
|
function apply(terminalConstructor) {
|
||||||
|
terminalConstructor.prototype.toggleFullScreen = function (fullscreen) {
|
||||||
|
toggleFullScreen(this, fullscreen);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
exports.apply = apply;
|
||||||
|
|
||||||
|
},{}]},{},[1])(1)
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=fullscreen.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"fullscreen.js","sources":["../../../src/addons/fullscreen/fullscreen.ts","../../../node_modules/browser-pack/_prelude.js"],"sourcesContent":["/**\n * Copyright (c) 2014 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { Terminal } from 'xterm';\n\n/**\n * Toggle the given terminal's fullscreen mode.\n * @param term The terminal to toggle full screen mode\n * @param fullscreen Toggle fullscreen on (true) or off (false)\n */\nexport function toggleFullScreen(term: Terminal, fullscreen: boolean): void {\n let fn: string;\n\n if (typeof fullscreen === 'undefined') {\n fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add';\n } else if (!fullscreen) {\n fn = 'remove';\n } else {\n fn = 'add';\n }\n\n term.element.classList[fn]('fullscreen');\n}\n\nexport function apply(terminalConstructor: typeof Terminal): void {\n (<any>terminalConstructor.prototype).toggleFullScreen = function (fullscreen: boolean): void {\n toggleFullScreen(this, fullscreen);\n };\n}\n",null],"names":[],"mappings":"ACAA;;;ADYA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AAZA;AAcA;AACA;AACA;AACA;AACA;AAJA;"}
|
8588
static/js/xterm@3.6.0/xterm.js
Normal file
8588
static/js/xterm@3.6.0/xterm.js
Normal file
File diff suppressed because it is too large
Load diff
1
static/js/xterm@3.6.0/xterm.js.map
Normal file
1
static/js/xterm@3.6.0/xterm.js.map
Normal file
File diff suppressed because one or more lines are too long
|
@ -254,7 +254,7 @@ install_webvirtcloud () {
|
||||||
pip3 install -r conf/requirements.txt -q
|
pip3 install -r conf/requirements.txt -q
|
||||||
|
|
||||||
|
|
||||||
cp "$APP_PATH/conf/daemon/consolecallback" "$APP_PATH/venv/bin/consolecallback"
|
|
||||||
chown -R "$nginx_group":"$nginx_group" "$APP_PATH"
|
chown -R "$nginx_group":"$nginx_group" "$APP_PATH"
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue