1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-23 22:50:09 +03:00

F #5055: Refactor guacamole client styles (#1140)

Co-authored-by: Tino Vázquez <cvazquez@opennebula.io>
(cherry picked from commit 6cfc15a4c09505b78efc0624a6e427383d2986ea)
This commit is contained in:
Sergio Betanzos 2021-04-28 19:47:48 +02:00 committed by Ruben S. Montero
parent 1b58d80838
commit 506a1eea65
No known key found for this signature in database
GPG Key ID: A0CEA6FA880A1D87
16 changed files with 366 additions and 264 deletions

View File

@ -2612,7 +2612,6 @@ SUNSTONE_PUBLIC_IMAGES_FILES="src/sunstone/public/images/ajax-loader.gif \
src/sunstone/public/images/opennebula-5.0.png \
src/sunstone/public/images/opennebula-sunstone-v4.0.png \
src/sunstone/public/images/opennebula-sunstone-v4.14-small.png \
src/sunstone/public/images/one_small_logo.png \
src/sunstone/public/images/panel.png \
src/sunstone/public/images/panel_short.png \
src/sunstone/public/images/pbar.gif \

View File

@ -15,24 +15,57 @@
/* -------------------------------------------------------------------------- */
define(function(require) {
require("jquery-ui");
var GuacController = require('utils/guacamole/controller');
try {
var endpoint = new URL(window.location.href);
var encoded_socket = endpoint.searchParams.get("socket");
var socket_string = atob(encoded_socket);
var url = new URL(socket_string);
var params = url.searchParams;
var token = params.get("token");
var info = params.get("info");
var controller = new GuacController();
controller.setInformation(info);
controller.setConnection(token);
} catch (error) {
console.log(error);
$('#guacamole-state').empty().text('Failed');
var controller = new GuacController();
var reconnectButton = document.getElementById('buttons__reconnect');
var endpoint = new URL(window.location.href);
var encoded_socket = endpoint.searchParams.get("socket");
var socket_string = atob(encoded_socket);
var url = new URL(socket_string);
var params = url.searchParams;
var token = params.get("token");
var connectionType = params.get("type");
var info = params.get("info");
controller.setInformation(info);
// Trigger first connect
document.readyState !== 'loading'
? connect()
: document.addEventListener('DOMContentLoaded', connect);
window.onunload = disconnect;
reconnectButton.onclick = function reconnect() {
disconnect();
document.querySelector('.toolbar__state h5').innerHTML = "";
document.querySelector('.toolbar__state .spinner').style.display = "block";
setTimeout(connect, 500)
}
function connect() {
try {
controller && controller.setConnection(token, connectionType);
} catch (error) {
controller && controller.disconnect();
document.querySelector('.toolbar__state h5').innerHTML = "Failed";
}
}
function disconnect() {
try {
controller && controller.disconnect();
} catch (error) {
document.querySelector('.toolbar__state h5').innerHTML = "Failed";
}
}
});

View File

@ -172,14 +172,14 @@ define(function(require) {
}
}
},
"logo": (_config["view"]["provision_logo"] || "images/one_small_logo.png"),
"logo": (_config["view"]["provision_logo"] || "images/opennebula-5.0.png"),
},
"tableOrder": _config["user_config"]["table_order"],
"vncProxyPort": _config["system_config"]["vnc_client_port"] || _config["system_config"]["vnc_proxy_port"].split(":")[1] || _config["system_config"]["vnc_proxy_port"],
"vncWSS": _config["user_config"]["vnc_wss"],
"requestVNCPassword": _config["system_config"]["vnc_request_password"],
"logo": (_config["view"]["small_logo"] || "images/one_small_logo.png"),
"logo": (_config["view"]["small_logo"] || "images/opennebula-5.0.png"),
"link_logo": (_config["view"]["link_logo"] || false),
"text_link_logo": (_config["view"]["text_link_logo"] || false),
"vmLogos": (_config["vm_logos"]),

View File

@ -371,10 +371,13 @@ define(function(require) {
"VM.startguac_action" : {
type: "single",
call: OpenNebulaVM.guac,
callback: function(_, response) {
var link = RemoteActions.getLink(response, {
callback: function(request, response) {
var protocolConnection = request.request.data[0].extra_param;
var link = getLink(response, {
connnection_type: 'guac',
extra_path: '/fireedge/guacamole'
extra_path: '/fireedge/guacamole',
extra_params: ['type=' + protocolConnection]
});
// Open in a new tab the noVNC connection
window.open(link);

View File

@ -16,53 +16,45 @@
define(function(require) {
require("guacamole-common-js")
var ManagedClient = require("utils/guacamole/types/client");
var ManagedClientState = require("utils/guacamole/types/client-state");
var Utils = require("utils/guacamole/utils");
var UtilsConnection = require("utils/info-connection/utils");
require('guacamole-common-js')
var ConnectionTypes = require('utils/guacamole/types/connection-types');
var ManagedClient = require('utils/guacamole/types/client');
var ManagedClientState = require('utils/guacamole/types/client-state');
var Utils = require('utils/guacamole/utils');
var UtilsConnection = require('utils/info-connection/utils');
var GuacButtons = require("utils/guacamole/directives/guacButtons");
var GuacClipboard = require("utils/guacamole/directives/guacClipboard");
var GuacKeyboard = require("utils/guacamole/directives/guacKeyboard");
var GuacMouse = require("utils/guacamole/directives/guacMouse");
var GuacOsk = require("utils/guacamole/directives/guacOsk");
var GuacButtons = require('utils/guacamole/directives/guacButtons');
var GuacClipboard = require('utils/guacamole/directives/guacClipboard');
var GuacKeyboard = require('utils/guacamole/directives/guacKeyboard');
var GuacMouse = require('utils/guacamole/directives/guacMouse');
var GuacOsk = require('utils/guacamole/directives/guacOsk');
function GuacController() {
var $guac = {};
var $scope = {};
var $elements = {
main: document.getElementById('guacamole-main'),
displayContainer: document.getElementById('guacamole-display'),
main: document.querySelector('.wrapper__display'),
displayContainer: document.getElementById('display'),
osk: document.getElementById('osk'),
closeOskButton: document.getElementById('osk-close'),
closeOskButton: document.querySelector('.osk__header__buttons .close'),
/* Buttons */
sendCtrlAltDelButton: document.getElementById('sendCtrlAltDelButton'),
mouseButton: document.getElementById('mouseButton'),
screenshotButton: document.getElementById('takeScreenshot'),
oskButton: document.getElementById('oskButton'),
sendCtrlAltDelButton: document.getElementById('buttons__sendctrlaltdel'),
mouseButton: document.getElementById('buttons__mouse'),
screenshotButton: document.getElementById('buttons__screenshot'),
oskButton: document.getElementById('buttons__osk'),
fullscreenButton: document.getElementById('buttons__fullscreen'),
};
var throttleResizeFunction = Utils.throttle(containerResized, 250);
window.addEventListener('resize', throttleResizeFunction);
this.disconnect = disconnect;
this.disconnect = function() {
if ($guac.client) $guac.client.disconnect();
if ($guac.keyboard) GuacKeyboard.destroy();
if ($guac.mouse) GuacMouse.destroy();
if ($guac.osk) GuacOsk.destroy();
this.setConnection = function(token, connectionType) {
$scope.connectionType = String(connectionType).toUpperCase();
GuacButtons.destroy();
GuacClipboard.destroy();
window.removeEventListener('resize', throttleResizeFunction);
$('#guacamole-state').text('');
$scope.connectionType === ConnectionTypes.SSH
? $elements.displayContainer.classList.add('ssh')
: $elements.displayContainer.classList.remove('ssh');
$guac = {};
$scope = {};
}
this.setConnection = function(token) {
var managedClient = ManagedClient.getInstance(token, undefined, $elements.displayContainer)
new GuacKeyboard($guac, $scope, $elements);
@ -70,14 +62,16 @@ define(function(require) {
new GuacOsk($guac, $scope, $elements);
new GuacButtons($guac, $scope, $elements);
new GuacClipboard($guac, $scope, $elements);
window.addEventListener('resize', containerResized);
document.addEventListener('fullscreenchange', containerResized)
// Remove any existing display
$elements.displayContainer.innerHTML = "";
$elements.displayContainer.innerHTML = '';
// Only proceed if a client is given
if (!managedClient) return;
$scope.client = managedClient;
// Get Guacamole client instance
$guac.client = managedClient.client;
@ -108,36 +102,40 @@ define(function(require) {
}
}).bind(this));
Utils.observe($scope, 'disableCursor', (function(disabled) {
$elements.mouseButton.disabled = !!disabled;
}).bind(this));
Utils.observe($scope.client.clientState, 'connectionState', (function(connectionState) {
var isLoading = connectionState === ManagedClientState.ConnectionState.WAITING;
$('#guacamole-loading')[isLoading ? 'fadeIn' : 'fadeOut']('fast');
$('#guacamole-state').text(connectionState).animate();
}).bind(this));
var isConnected = connectionState === ManagedClientState.ConnectionState.CONNECTED;
var isDisconnected = connectionState === ManagedClientState.ConnectionState.DISCONNECTED;
Utils.observe($scope.client.clientProperties, 'scale', (function(scale) {
scale = Math.max(scale, $scope.client.clientProperties.minScale);
scale = Math.min(scale, $scope.client.clientProperties.maxScale);
// Apply scale if client attached
if ($guac.display && scale !== 0) {
$guac.display.scale(scale);
$elements.displayContainer.style['min-height'] = $guac.display.getHeight() + "px";
}
isConnected && setTimeout(containerResized, 100);
isDisconnected && disconnect();
if (scale !== $scope.client.clientProperties.scale) {
$scope.client.clientProperties.scale = scale;
}
$('.spinner')[isLoading ? 'fadeIn' : 'fadeOut']('fast');
$('.toolbar__state h5').text(connectionState).animate();
}).bind(this));
};
this.setInformation = function(information) {
var info_decode = UtilsConnection.decodeInfoConnection(information);
UtilsConnection.printInfoConnection($('.guacamole_info'), info_decode);
UtilsConnection.printInfoConnection($('.information'), info_decode);
}
function disconnect() {
if ($guac.client) $guac.client.disconnect();
if ($guac.keyboard) GuacKeyboard.destroy();
if ($guac.mouse) GuacMouse.destroy();
if ($guac.osk) GuacOsk.destroy();
GuacButtons.destroy();
GuacClipboard.destroy();
window.removeEventListener('resize', containerResized);
document.removeEventListener('fullscreenchange', containerResized)
while($elements.displayContainer.firstChild)
$elements.displayContainer.removeChild($elements.displayContainer.firstChild);
$guac = {};
$scope = {};
}
function containerResized() {
@ -150,38 +148,37 @@ define(function(require) {
if ($guac.display.getWidth() !== width || $guac.display.getHeight() !== height) {
$guac.client.sendSize(width, height);
}
if ($guac.osk) {
var MAX_OSK_WIDTH = 1000;
$guac.osk.resize(Math.min(MAX_OSK_WIDTH, width));
}
// when type connection is SSH, display doesn't need scale
$scope.connectionType !== ConnectionTypes.SSH && updateDisplayScale();
}
updateDisplayScale();
if ($guac.osk) {
$guac.osk.resize(1000);
}
};
function updateDisplayScale() {
if (!$guac.display) return;
// Calculate scale to fit screen
$scope.client.clientProperties.minScale = Math.min(
$elements.main.offsetWidth / Math.max($guac.display.getWidth(), 1),
$elements.main.offsetHeight / Math.max($guac.display.getHeight(), 1)
);
// Get screen resolution.
var origHeight = Math.max($guac.display.getHeight(), 1);
var origWidth = Math.max($guac.display.getWidth(), 1);
var htmlWidth = window.innerWidth;
var htmlHeight = window.innerHeight;
var xScale = htmlWidth / origWidth;
var yScale = htmlHeight / origHeight;
// This is done to handle both X and Y axis
var scale = Math.min(yScale, xScale);
// Calculate appropriate maximum zoom level
$scope.client.clientProperties.maxScale = Math.max($scope.client.clientProperties.minScale, 3);
// Limit to 1
scale = Math.min(scale, 1);
// Clamp zoom level, maintain auto-fit
if (
$guac.display.getScale() < $scope.client.clientProperties.minScale ||
$scope.client.clientProperties.autoFit
) {
$scope.client.clientProperties.scale = $scope.client.clientProperties.minScale;
}
else if ($guac.display.getScale() > $scope.client.clientProperties.maxScale) {
$scope.client.clientProperties.scale = $scope.client.clientProperties.maxScale;
if (scale !== 0) {
$guac.display.scale(scale);
}
};
}

View File

@ -17,6 +17,7 @@
define(function(require) {
var Files = require('utils/files');
var ConnectionTypes = require("utils/guacamole/types/connection-types");
function GuacButtons($guac, $scope, $elements) {
$elements.screenshotButton.onclick = function() {
@ -45,7 +46,7 @@ define(function(require) {
$elements.closeOskButton.onclick = function() {
if (!$guac.client) return;
$('#osk-container').fadeToggle('fast');
$('#osk__container').fadeToggle('fast');
};
$elements.mouseButton.onclick = function() {
@ -55,16 +56,25 @@ define(function(require) {
$scope.localCursor = $elements.mouseButton.classList.contains('disabled');
};
$elements.fullscreenButton.onclick = function() {
// If the document is not in full screen mode make the video full screen
if (!document.fullscreenElement && document.fullscreenEnabled) {
$elements.main.requestFullscreen();
} else if (document.exitFullscreen) {
document.exitFullscreen();
}
};
GuacButtons.destroy = function() {
// reset default state
$('#osk-container').hide();
$('#osk__container').hide();
$elements.mouseButton.classList.remove('disabled');
$elements.sendCtrlAltDelButton =
$elements.screenshotButton.onclick =
$elements.mouseButton.onclick =
$elements.oskButton.onclick =
$elements.closeOskButton.onclick = null;
$elements.sendCtrlAltDelButton.onclick =
$elements.screenshotButton.onclick =
$elements.mouseButton.onclick =
$elements.oskButton.onclick =
$elements.closeOskButton.onclick = null;
};
}

View File

@ -30,9 +30,7 @@ define(function(require) {
// Forward mousemove events untouched
mouse.onmousemove = function(mouseState) {
mouseState.y = mouseState.y / $guac.display.getScale();
mouseState.x = mouseState.x / $guac.display.getScale();
handleMouseState(mouseState);
handleMouseState(mouseState, true);
}
// Hide software cursor when mouse leaves display
@ -42,10 +40,15 @@ define(function(require) {
$guac.display.showCursor(false);
};
function handleMouseState(mouseState) {
function handleMouseState(mouseState, scaleMouse = false) {
// Do not attempt to handle mouse state changes if the client
// or display are not yet available
if (!$guac.client || !$guac.display) return;
if (!$guac.client || !$guac.display || $scope.disabledMouse) return;
if (scaleMouse) {
mouseState.y = mouseState.y / $guac.display.getScale();
mouseState.x = mouseState.x / $guac.display.getScale();
}
// Send mouse state, show cursor if necessary
$guac.display.showCursor(!$scope.localCursor);

View File

@ -26,18 +26,21 @@ define(function(require) {
loadLayouts();
changeLayout(DEFAULT_LAYOUT);
// $('#osk-container').draggable();
$('#osk__container').draggable({
start: function() { $scope.disabledMouse = true; },
stop: function() { $scope.disabledMouse = false; }
});
function loadLayouts() {
$('#osk-qwerty').empty();
$('#select__qwerty').empty();
var enUsLayout = new Option(enUsQwerty.language, enUsQwerty.language);
$('#osk-qwerty').append(enUsLayout);
$('#select__qwerty').append(enUsLayout);
var esEsLayout = new Option(esEsQwerty.language, esEsQwerty.language);
$('#osk-qwerty').append(esEsLayout);
$('#select__qwerty').append(esEsLayout);
$('#osk-qwerty').off().on('change', function() {
$('#select__qwerty').off().on('change', function() {
changeLayout(this.value);
})
};

View File

@ -215,9 +215,15 @@ define(function(require) {
function getConnectString(token, connectionParameters, display = window) {
// Calculate optimal width/height for display
var pixel_density = window.devicePixelRatio || 1;
var optimal_width = display.innerWidth * pixel_density;
var optimal_height = display.innerHeight * pixel_density;
var optimal_dpi = pixel_density * 96;
var optimal_width = display instanceof Window
? display.innerWidth * pixel_density
: display.offsetWidth * pixel_density;
var optimal_height = display instanceof Window
? display.innerHeight * pixel_density
: display.offsetHeight * pixel_density;
// Build base connect string
var connectString = [

View File

@ -0,0 +1,31 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
define(function() {
/**
* Valid connection type strings. Each type string represents a protocol.
*/
var ConnectionTypes = {
SSH : "SSH",
RDP : "RDP",
VNC : "VNC",
TELNET : "TELNET"
}
return ConnectionTypes;
});

View File

@ -1,87 +1,122 @@
body {
margin:0;
padding:0;
font-family: Helvetica;
height:100%;
}
/*
* CSS TABLE OF CONTENTS
*
* 1.0 - Globals
* 2.0 - Header
* 3.0 - Body
* 3.1 - Guacamole display
* 3.2 - Defaults classes by guacamole-common-js
*/
/*** 1.0 - Globals ***/
html {
height:100%;
box-sizing: border-box;
}
.remote-buttons {
white-space: nowrap;
*, *:before, *:after {
box-sizing: inherit;
}
.main {
width: 100%;
display: inline-flex;
height: 100%;
flex-direction: column;
background-color: rgb(40, 40, 40);
body {
display: grid;
grid-template-rows: auto 1fr;
}
.guacamole-main{
flex-grow: 1;
h5 {
margin: 0;
padding: 0;
}
.guacamole-status {
text-align: center;
position: relative;
width: 100%;
/*** 2.0 - Header ***/
header {
background: #f2f4f8;
padding: 1em 1em 0.8em;
box-shadow: 0px 2px 1px -1px rgb(0 0 0 / 20%),
0px 1px 1px 0px rgb(0 0 0 / 14%), 0px 1px 3px 0px rgb(0 0 0 / 12%);
}
.remote-logo{
border-radius: 50%;
background-color: #282828;
padding: 0.4em;
margin-right: 1em;
height: 40px;
width: 40px;
.header__wrapper {
max-width: 1250px;
margin: 0 auto;
}
.container{
.toolbar {
padding: 1em;
display: flex;
justify-content: center;
gap: 2em;
flex-wrap: wrap;
}
.toolbar img {
height: 40px;
}
.toolbar__state {
flex-grow: 1;
display: flex;
gap: 1em;
align-items: center;
justify-content: center;
}
.guacamole-state{
white-space: nowrap;
max-width: 20em;
overflow: hidden;
text-overflow: ellipsis;
.toolbar__state img {
width: 40px;
background-color: #282828;
border-radius: 50%;
padding: 0.4em;
}
.toolbar__buttons {
display: flex;
justify-content: flex-end;
}
/* left-align the status text on lower resolutions */
@media screen and (max-width: 800px){
.guacamole-status {
z-index: 1;
position: relative;
width: auto;
float: left;
@media (max-width: 768px) {
.toolbar__state {
justify-content: end;
flex-direction: row-reverse;
}
.toolbar__buttons {
flex-grow: 1;
}
}
.guacamole-main {
width: 100%;
height: fit-content;
display: flex;
align-items: center;
place-content: center;
background-color: #282828;
/*** 3.0 - Body ***/
main {
background-color: #222431;
}
.guacamole-main > div {
main > div {
z-index: 1;
}
.guacamole-main .guacamole-display {
/*** 3.1 - Guacamole display ***/
.wrapper__display {
width: 100%;
height: 100%;
display: flex;
align-items: center;
place-content: center;
}
#display {
overflow: hidden;
cursor: none;
}
.osk-container {
#display.ssh {
width: 100vw;
height: 100%;
}
/*** 3.2 - Guacamole OSK ***/
.osk__container {
z-index: 2;
background: rgba(0, 0, 0, 0.59);
position: absolute;
@ -93,30 +128,24 @@ html {
box-shadow: 0 0 20px #acacac;
}
.osk-container-header {
.osk__header {
background: linear-gradient(to top, #ebebeb, #d5d5d5);
color: #4d494d;
font-size: 11pt;
line-height: 20px;
text-align: center;
width: 100%;
height: 28px;
user-select: none;
cursor: default;
border-top: 1px solid #f3f1f3;
border-bottom: 1px solid #b1aeb1;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
padding: 0.5em;
display: flex;
justify-content: space-between;
align-items: start;
}
.osk-container-header .buttons {
padding-left: 8px;
padding-top: 3px;
float: left;
line-height: 0;
}
.osk-container-header .buttons .close {
.osk__header__buttons .close {
background: #ff5c5c;
font-size: 13px;
font-weight: bold;
@ -126,18 +155,17 @@ html {
display: inline-block;
}
.osk-container-header .layouts {
padding-right: 8px;
padding-top: 3px;
float: right;
line-height: 0;
.osk__header select {
width: auto;
margin: 0;
}
/*** 3.2 Defaults classes by guacamole-common-js ***/
.guac-keyboard {
display: inline-block;
width: 100%;
margin: 0;
padding: 0;
cursor: default;
@ -159,20 +187,19 @@ html {
}
.guac-keyboard .guac-keyboard-key {
position: absolute;
left: 0;
right: 0;
top: 0;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: #444;
border: 0.125em solid #666;
-moz-border-radius: 0.25em;
-moz-border-radius: 0.25em;
-webkit-border-radius: 0.25em;
-khtml-border-radius: 0.25em;
border-radius: 0.25em;
-khtml-border-radius: 0.25em;
border-radius: 0.25em;
color: white;
font-size: 40%;
@ -180,11 +207,8 @@ html {
text-align: center;
white-space: pre;
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.25),
1px -1px 0 rgba(0, 0, 0, 0.25),
-1px 1px 0 rgba(0, 0, 0, 0.25),
-1px -1px 0 rgba(0, 0, 0, 0.25);
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.25), 1px -1px 0 rgba(0, 0, 0, 0.25),
-1px 1px 0 rgba(0, 0, 0, 0.25), -1px -1px 0 rgba(0, 0, 0, 0.25);
}
.guac-keyboard .guac-keyboard-key:hover {
@ -232,12 +256,12 @@ html {
/* Active super */
.guac-keyboard.guac-keyboard-modifier-super .guac-keyboard-key-super {
background: #882;
border-color: #DD4;
border-color: #dd4;
}
.guac-keyboard .guac-keyboard-key.guac-keyboard-pressed {
background: #822;
border-color: #D44;
border-color: #d44;
}
.guac-keyboard .guac-keyboard-group {
@ -252,7 +276,6 @@ html {
}
.guac-keyboard .guac-keyboard-group.guac-keyboard-main {
/* IE10 */
display: -ms-flexbox;
-ms-flex-align: stretch;
@ -262,7 +285,7 @@ html {
display: -moz-box;
-moz-box-align: stretch;
-moz-box-orient: horizontal;
/* Ancient WebKit */
display: -webkit-box;
-webkit-box-align: stretch;
@ -277,7 +300,6 @@ html {
display: flex;
align-items: stretch;
flex-direction: row;
}
.guac-keyboard .guac-keyboard-group.guac-keyboard-movement {
@ -315,13 +337,11 @@ html {
.guac-keyboard.guac-keyboard-modifier-alt-gr
.guac-keyboard-key.guac-keyboard-uses-alt-gr
.guac-keyboard-cap:not(.guac-keyboard-requires-alt-gr) {
display: none;
}
/* Fade out keys which do not use AltGr if AltGr is active */
.guac-keyboard.guac-keyboard-modifier-alt-gr
.guac-keyboard-key:not(.guac-keyboard-uses-alt-gr):not(.guac-keyboard-key-alt-gr) {
.guac-keyboard-key:not(.guac-keyboard-uses-alt-gr):not(.guac-keyboard-key-alt-gr) {
opacity: 0.5;
}
}

View File

@ -49,7 +49,6 @@ $global-font-size: 13px;
$global-width: rem-calc(1200);
$global-lineheight: 1.5;
$foundation-palette: (
//primary: #2199e8,
primary: #4DBBD3,
secondary: #8a8a8a,
success: #3adb76,

View File

@ -4,66 +4,64 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link rel="apple-touch-startup-image" href="images/screen_320x460.png" />
<link rel="apple-touch-icon" href="images/screen_57x57.png">
<link rel="icon" href="images/favicon.png">
<!-- Stylesheets -->
<link rel="stylesheet" type="text/css" href="css/app.css" title="plain">
<link rel="stylesheet" type="text/css" href="css/guac-custom.css" title="plain">
</head>
<body>
<div class="main">
<div style="background: #f7f7f7; padding: 1.5em 1.5em 0.8em;">
<div style="max-width: 1250px; margin: 0 auto;">
<div style="display: flex; align-items: center;">
<img src="images/one_small_logo.png" style="height:40px;">
<h5 class="guacamole-status">
<div class="container">
<div class="remote-logo">
<img src="images/remote_console/guacamole.png">
</div>
<div id="guacamole-state" class="guacamole-state">
<span id="guacamole-loading">
<i class="fas fa-spinner fa-spin"></i>
</span>
</div>
</div>
</h5>
<div class="remote-buttons">
<button class="button alert" id="sendCtrlAltDelButton">
Send CtrlAltDel
</button>
<button class="button primary" id="oskButton" style="display: none !important;">
<i class="fas fa-keyboard fa-fw"></i>
</button>
<button class="button primary" id="mouseButton">
<i class="fas fa-mouse-pointer fa-fw"></i>
</button>
<button class="button primary" id="takeScreenshot">
<i class="fas fa-camera fa-fw" title="Take screenshot"></i>
</button>
</div>
<header>
<div class="header__wrapper">
<div class="toolbar">
<img src="images/opennebula-5.0.png">
<div class="toolbar__state">
<img src="images/remote_console/guacamole.png">
<h5></h5>
<span class="spinner">
<i class="fas fa-spinner fa-spin"></i>
</span>
</div>
<div class="toolbar__buttons">
<button class="button alert" id="buttons__sendctrlaltdel">
Send CtrlAltDel
</button>
<button class="button secondary" id="buttons__reconnect" title="Reconnect">
<i class="fas fa-redo-alt fa-fw"></i>
</button>
<button class="button secondary" id="buttons__fullscreen" title="Fullscreen">
<i class="fas fa-expand fa-fw"></i>
</button>
<button class="button primary" id="buttons__osk" title="Show keyboard">
<i class="fas fa-keyboard fa-fw"></i>
</button>
<button class="button primary" id="buttons__mouse" title="Emulate mouse">
<i class="fas fa-mouse-pointer fa-fw"></i>
</button>
<button class="button primary" id="buttons__screenshot" title="Take screenshot">
<i class="fas fa-camera fa-fw"></i>
</button>
</div>
<div class="guacVNC_info"></div>
</div>
<div class="information"></div>
</div>
<div id="guacamole-main" class="guacamole-main">
<div id="guacamole-display" class="guacamole-display"></div>
</header>
<main>
<%### Guacamole display screen ###%>
<div class="wrapper__display">
<div id="display"></div>
</div>
<!-- On-screen keyboard -->
<div class="osk-container" id="osk-container">
<div class="osk-container-header" id="osk-container-header">
<div class="buttons">
<button class="close" id="osk-close">x</button>
</div>
<div class="layouts">
<select id="osk-qwerty"></select>
<%### Guacamole on-screen keyboard ###%>
<div class="osk__container" id="osk__container">
<div class="osk__header">
<div class="osk__header__buttons">
<button class="close">x</button>
</div>
<select id="select__qwerty"></select>
</div>
<div class="osk" id="osk"></div>
</div>
</div>
</main>
<script src="dist/console/guacamole.js?v=<%= OpenNebula::VERSION %>"></script>
<% view = $views_config.view(session[:user], session[:user_gname], session[:default_view]) %>

View File

@ -37,7 +37,7 @@
<div style="background: #f7f7f7; padding: 1.5em 1.5em 0.8em;">
<div style="max-width: 1250px; margin: 0 auto;">
<div id="noVNC_status_bar" class="noVNC_status_bar" style="display: flex; align-items: center;">
<img src="images/one_small_logo.png" style="height:40px;">
<img src="images/opennebula-5.0.png" style="height:40px;">
<h5 id="message-div" class="spice-message"></h5>
</div>
<div class="SPICE_info"></div>

View File

@ -72,7 +72,7 @@
<div style="background: #f7f7f7; padding: 1.5em 1.5em 0.8em;">
<div style="max-width: 1250px; margin: 0 auto;">
<div id="VMRC_status_bar" class="noVNC_status_bar" style="display: flex; align-items: center;">
<img src="images/one_small_logo.png" style="height:40px;">
<img src="images/opennebula-5.0.png" style="height:40px;">
<h5 id="VMRC_status" style="position: relative;">
<div class="container">

View File

@ -17,7 +17,7 @@
<div style="background: #f7f7f7; padding: 1.5em 1.5em 0.8em;">
<div style="max-width: 1250px; margin: 0 auto;">
<div id="noVNC_status_bar" class="noVNC_status_bar" style="display: flex; align-items: center;">
<img src="images/one_small_logo.png" style="height:40px;">
<img src="images/opennebula-5.0.png" style="height:40px;">
<h5 id="noVNC_status" style="position: relative;">
<div class="container">
<div class="remote_logo">