5
0
mirror of git://git.proxmox.com/git/novnc-pve.git synced 2025-01-21 22:03:51 +03:00

add new rebased patches

adds the new rebased patches, based on current novnc master
notable changes:
* (most of) our code is in an es6 module, opposed to patching the ui.js
* removed our sendkeys menu in favor of the novnc one
* you can now enter fullscreen from a popup console
* when a vm resizes its resolution, the canvas should also rescale in
  the console tab

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2017-05-22 16:58:11 +02:00 committed by Wolfgang Bumiller
parent 339cafefa3
commit fe91e9e1e3
9 changed files with 1246 additions and 0 deletions

View File

@ -0,0 +1,639 @@
From ad6975daaeee0798955f1d8b36d567975f4cbae5 Mon Sep 17 00:00:00 2001
From: Dominik Csapak <d.csapak@proxmox.com>
Date: Tue, 13 Dec 2016 16:11:35 +0100
Subject: [PATCH 1/9] add pve specific js code
this adds a es6 module 'PVEUI' which we use for defining the pve related
methods (API2Request, etc.)
we also modify ui.js so that it uses this module and sets up our
autoresizing, commandstoggle, etc.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
app/pve.js | 417 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
app/ui.js | 95 ++++++++++----
2 files changed, 488 insertions(+), 24 deletions(-)
create mode 100644 app/pve.js
diff --git a/app/pve.js b/app/pve.js
new file mode 100644
index 0000000..668835a
--- /dev/null
+++ b/app/pve.js
@@ -0,0 +1,417 @@
+/*
+ * PVE Utility functions for noVNC
+ * Copyright (C) 2017 Proxmox GmbH
+ */
+
+import * as WebUtil from "./webutil.js";
+
+export default function PVEUI(UI){
+ this.consoletype = WebUtil.getQueryVar('console');
+ this.vmid = WebUtil.getQueryVar('vmid');
+ this.vmname = WebUtil.getQueryVar('vmname');
+ this.nodename = WebUtil.getQueryVar('node');
+ this.resize = WebUtil.getQueryVar('resize');
+ this.lastFBWidth = undefined;
+ this.lastFBHeight = undefined;
+ this.sizeUpdateTimer = undefined;
+ this.UI = UI;
+
+ var baseUrl = '/nodes/' + this.nodename;
+ var url;
+ var params = { websocket: 1 };
+ var title;
+
+ switch (this.consoletype) {
+ case 'kvm':
+ baseUrl += '/qemu/' + this.vmid;
+ url = baseUrl + '/vncproxy';
+ title = "VM " + this.vmid;
+ if (this.vmname) {
+ title += " ('" + this.vmname + "')";
+ }
+ break;
+ case 'lxc':
+ baseUrl += '/lxc/' + this.vmid;
+ url = baseUrl + '/vncproxy';
+ title = "CT " + this.vmid;
+ if (this.vmname) {
+ title += " ('" + this.vmname + "')";
+ }
+ break;
+ case 'shell':
+ url = baseUrl + '/vncshell';
+ title = "node '" + this.nodename + "'";
+ break;
+ case 'upgrade':
+ url = baseUrl + '/vncshell';
+ params.upgrade = 1;
+ title = 'System upgrade on node ' + this.nodename;
+ break;
+ default:
+ throw 'implement me';
+ break;
+ }
+
+ this.baseUrl = baseUrl;
+ this.url = url;
+ this.params = params;
+ document.title = title;
+};
+
+PVEUI.prototype = {
+ urlEncode: function(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('&');
+ },
+
+ API2Request: function(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 = me.urlEncode(reqOpts.params || {});
+
+ if (reqOpts.method === 'GET') {
+ xhr.open(reqOpts.method, "/api2/json" + reqOpts.url + '?' + data);
+ } else {
+ xhr.open(reqOpts.method, "/api2/json" + 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";
+ }
+ },
+
+ pve_detect_migrated_vm: function() {
+ var me = this;
+ if (me.consoletype === 'kvm') {
+ // try to detect migrated VM
+ me.API2Request({
+ url: '/cluster/resources',
+ method: 'GET',
+ success: function(result) {
+ var list = result.data;
+ list.every(function(item) {
+ if (item.type === 'qemu' && item.vmid == me.vmid) {
+ var url = "?" + me.urlEncode({
+ console: me.consoletype,
+ novnc: 1,
+ vmid: me.vmid,
+ vmname: me.vmname,
+ node: item.node,
+ resize: me.resize
+ });
+ location.href = url;
+ return false; // break
+ }
+ return true;
+ });
+ }
+ });
+ } else if(me.consoletype === 'lxc') {
+ // lxc restart migration can take a while,
+ // so we need to find out if we are really migrating
+ var migrating;
+ var check = setInterval(function() {
+ if (migrating === undefined ||
+ migrating === true) {
+ // check (again) if migrating
+ me.UI.showStatus('Checking for Migration', 'warning', 5000);
+ me.API2Request({
+ url: me.baseUrl + '/config',
+ method: 'GET',
+ success: function(result) {
+ var lock = result.data.lock;
+ if (lock == 'migrate') {
+ migrating = true;
+ me.UI.showStatus('Migration detected, waiting...', 'warning', 5000);
+ } else {
+ migrating = false;
+ }
+ },
+ failure: function() {
+ migrating = false;
+ }
+ });
+ } else {
+ // not migrating any more
+ me.UI.showStatus('Migration finished', 'warning');
+ clearInterval(check);
+ me.API2Request({
+ url: '/cluster/resources',
+ method: 'GET',
+ success: function(result) {
+ var list = result.data;
+ list.every(function(item) {
+ if (item.type === 'lxc' && item.vmid == me.vmid) {
+ var url = "?" + me.urlEncode({
+ console: me.consoletype,
+ novnc: 1,
+ vmid: me.vmid,
+ vmname: me.vmname,
+ node: item.node,
+ resize: me.resize
+ });
+ location.href = url;
+ return false; // break
+ }
+ return true;
+ });
+ }
+ });
+ }
+ }, 5000);
+ }
+
+ },
+
+ pve_vm_command: function(cmd, params, reload) {
+ var me = this;
+ var baseUrl;
+ var confirmMsg = "";
+
+ switch(cmd) {
+ case "start":
+ reload = 1;
+ case "shutdown":
+ case "stop":
+ case "reset":
+ case "suspend":
+ case "resume":
+ confirmMsg = "Do you really want to " + cmd + " VM/CT {0}?";
+ break;
+ case "reload":
+ location.reload();
+ break;
+ default:
+ throw "implement me " + cmd;
+ }
+
+ confirmMsg = confirmMsg.replace('{0}', me.vmid);
+
+ if (confirmMsg !== "" && confirm(confirmMsg) !== true) {
+ return;
+ }
+
+ me.UI.closePVECommandPanel();
+
+ if (me.consoletype === 'kvm') {
+ baseUrl = '/nodes/' + me.nodename + '/qemu/' + me.vmid;
+ } else if (me.consoletype === 'lxc') {
+ baseUrl = '/nodes/' + me.nodename + '/lxc/' + me.vmid;
+ } else {
+ throw "unknown VM type";
+ }
+
+ me.API2Request({
+ params: params,
+ url: baseUrl + "/status/" + cmd,
+ method: 'POST',
+ failure: function(msg) {
+ me.UI.showStatus(msg, 'warning');
+ },
+ success: function() {
+ me.UI.showStatus("VM command '" + cmd +"' successful", 'normal');
+ if (reload) {
+ setTimeout(function() {
+ location.reload();
+ }, 1000);
+ };
+ }
+ });
+ },
+
+ addPVEHandlers: function() {
+ var me = this;
+ document.getElementById('pve_commands_button')
+ .addEventListener('click', me.UI.togglePVECommandPanel);
+
+ // show/hide the buttons
+ document.getElementById('noVNC_settings_button')
+ .classList.add('noVNC_hidden');
+ document.getElementById('noVNC_disconnect_button')
+ .classList.add('noVNC_hidden');
+ if (me.consoletype === 'kvm') {
+ document.getElementById('noVNC_clipboard_button')
+ .classList.add('noVNC_hidden');
+ }
+
+ if (me.consoletype === 'shell' || me.consoletype === 'upgrade') {
+ document.getElementById('pve_commands_button')
+ .classList.add('noVNC_hidden');
+ }
+
+ // add command logic
+ var commandArray = [
+ { cmd: 'start', kvm: 1, lxc: 1},
+ { cmd: 'stop', kvm: 1, lxc: 1},
+ { cmd: 'shutdown', kvm: 1, lxc: 1},
+ { cmd: 'suspend', kvm: 1},
+ { cmd: 'resume', kvm: 1},
+ { cmd: 'reset', kvm: 1},
+ { cmd: 'reload', kvm: 1, lxc: 1, shell: 1},
+ ];
+
+ commandArray.forEach(function(item) {
+ var el = document.getElementById('pve_command_'+item.cmd);
+ if (!el) {
+ return;
+ }
+
+ if (item[me.consoletype] === 1) {
+ el.onclick = function() {
+ me.pve_vm_command(item.cmd);
+ };
+ } else {
+ el.classList.add('noVNC_hidden');
+ }
+ });
+
+ //edge/ie11 quirk
+ var canvas = document.getElementById('noVNC_canvas');
+ canvas.onclick = canvas.focus;
+ },
+
+ getFBSize: function() {
+ var oh;
+ var ow;
+
+ if (window.innerHeight) {
+ oh = window.innerHeight;
+ ow = window.innerWidth;
+ } else if (document.documentElement &&
+ document.documentElement.clientHeight) {
+ oh = document.documentElement.clientHeight;
+ ow = document.documentElement.clientWidth;
+ } else if (document.body) {
+ oh = document.body.clientHeight;
+ ow = document.body.clientWidth;
+ } else {
+ throw "can't get window size";
+ }
+
+ return { width: ow, height: oh };
+ },
+
+ pveStart: function(callback) {
+ var me = this;
+ me.API2Request({
+ url: me.url,
+ method: 'POST',
+ params: me.params,
+ success: function(result) {
+ var wsparams = me.urlEncode({
+ port: result.data.port,
+ vncticket: result.data.ticket
+ });
+
+ document.getElementById('noVNC_password_input').value = result.data.ticket;
+ me.UI.updateSetting('path', 'api2/json' + me.baseUrl + '/vncwebsocket' + "?" + wsparams);
+
+ callback();
+ },
+ failure: function(msg) {
+ me.UI.showStatus(msg, 'error');
+ }
+ });
+ },
+
+ updateFBSize: function(rfb, width, height, clip) {
+ var me = this;
+ console.log(arguments);
+ try {
+ // Note: window size must be even number for firefox
+ me.lastFBWidth = Math.floor((width + 1)/2)*2;
+ me.lastFBHeight = Math.floor((height + 1)/2)*2;
+
+ if (me.sizeUpdateTimer !== undefined) {
+ clearInterval(me.sizeUpdateTimer);
+ }
+ if (clip) return;
+
+ var update_size = function() {
+ // we do not want to resize if we are in fullscreen
+ if (document.fullscreenElement || // alternative standard method
+ document.mozFullScreenElement || // currently working methods
+ document.webkitFullscreenElement ||
+ document.msFullscreenElement) {
+ return;
+ }
+
+ var oldsize = me.getFBSize();
+ var offsetw = me.lastFBWidth - oldsize.width;
+ var offseth = me.lastFBHeight - oldsize.height;
+ if (offsetw !== 0 || offseth !== 0) {
+ //console.log("try resize by " + offsetw + " " + offseth);
+ try {
+ window.resizeBy(offsetw, offseth);
+ // wait a little an then fix the scrollbars
+ // on chrome
+ setTimeout(function() {
+ me.UI.fixScrollbars();
+ }, 100);
+ } catch (e) {
+ console.log('resizing did not work', e);
+ }
+ }
+ };
+
+ update_size();
+ me.sizeUpdateTimer = setInterval(update_size, 1000);
+
+ } catch(e) {
+ console.log(e);
+ }
+ },
+};
diff --git a/app/ui.js b/app/ui.js
index 73ad2b4..def0eda 100644
--- a/app/ui.js
+++ b/app/ui.js
@@ -20,6 +20,7 @@ import keysyms from "../core/input/keysymdef.js";
import RFB from "../core/rfb.js";
import Display from "../core/display.js";
import * as WebUtil from "./webutil.js";
+import PVEUI from "./pve.js";
const UI = {
@@ -63,6 +64,7 @@ const UI = {
// Render default UI and initialize settings menu
start: function(callback) {
+ UI.PVE = new PVEUI(UI);
// Setup global variables first
UI.isSafari = (navigator.userAgent.indexOf('Safari') !== -1 &&
navigator.userAgent.indexOf('Chrome') === -1);
@@ -95,6 +97,9 @@ const UI = {
UI.addConnectionControlHandlers();
UI.addClipboardHandlers();
UI.addSettingsHandlers();
+
+ // add pve specific event handlers
+ UI.PVE.addPVEHandlers();
document.getElementById("noVNC_status")
.addEventListener('click', UI.hideStatus);
@@ -103,11 +108,6 @@ const UI = {
UI.openControlbar();
- // Show the connect panel on first load unless autoconnecting
- if (!autoconnect) {
- UI.openConnectPanel();
- }
-
UI.updateViewClip();
UI.updateVisualState();
@@ -115,17 +115,13 @@ const UI = {
document.getElementById('noVNC_setting_host').focus();
document.documentElement.classList.remove("noVNC_loading");
- var autoconnect = WebUtil.getConfigVar('autoconnect', false);
- if (autoconnect === 'true' || autoconnect == '1') {
- autoconnect = true;
- UI.connect();
- } else {
- autoconnect = false;
- }
+ UI.PVE.pveStart(function() {
+ UI.connect();
- if (typeof callback === "function") {
- callback(UI.rfb);
- }
+ if (typeof callback === "function") {
+ callback(UI.rfb);
+ }
+ });
},
initFullscreen: function() {
@@ -170,10 +166,14 @@ const UI = {
/* Populate the controls if defaults are provided in the URL */
UI.initSetting('host', window.location.hostname);
UI.initSetting('port', port);
- UI.initSetting('encrypt', (window.location.protocol === "https:"));
+ UI.initSetting('encrypt', true);
UI.initSetting('cursor', !isTouchDevice);
UI.initSetting('clip', false);
- UI.initSetting('resize', 'off');
+ // we need updateSetting because
+ // otherwise we load from browser storage
+ // we want to overwrite the resize mode from url
+ var resize = WebUtil.getQueryVar('resize');
+ UI.updateSetting('resize', resize);
UI.initSetting('shared', true);
UI.initSetting('view_only', false);
UI.initSetting('path', 'websockify');
@@ -434,6 +434,7 @@ const UI = {
case 'connected':
UI.connected = true;
UI.inhibit_reconnect = false;
+ UI.pveAllowMigratedTest = true;
document.documentElement.classList.add("noVNC_connected");
if (rfb && rfb.get_encrypt()) {
msg = _("Connected (encrypted) to ") + UI.desktopName;
@@ -449,6 +450,10 @@ const UI = {
break;
case 'disconnected':
UI.showStatus(_("Disconnected"));
+ if (UI.pveAllowMigratedTest === true) {
+ UI.pveAllowMigratedTest = false;
+ UI.PVE.pve_detect_migrated_vm();
+ }
break;
default:
msg = "Invalid UI state";
@@ -861,6 +866,7 @@ const UI = {
UI.closeXvpPanel();
UI.closeClipboardPanel();
UI.closeExtraKeys();
+ UI.closePVECommandPanel();
},
/* ------^-------
@@ -1033,9 +1039,15 @@ const UI = {
password = WebUtil.getConfigVar('password');
}
- if (password === null) {
- password = undefined;
- }
+ var password = document.getElementById('noVNC_password_input').value;
+
+ if (!password) {
+ password = WebUtil.getConfigVar('password');
+ }
+
+ if (password === null) {
+ password = undefined;
+ }
if ((!host) || (!port)) {
var msg = _("Must set host and port");
@@ -1608,9 +1620,36 @@ const UI = {
/* ------^-------
* /EXTRA KEYS
* ==============
- * MISC
+ * PVE
* ------v------*/
+ togglePVECommandPanel: function() {
+ if (document.getElementById('pve_commands').classList.contains("noVNC_open")) {
+ UI.closePVECommandPanel();
+ } else {
+ UI.openPVECommandPanel();
+ }
+ },
+
+ openPVECommandPanel: function() {
+ var me = this;
+ UI.closeAllPanels();
+ UI.openControlbar();
+
+ document.getElementById('pve_commands').classList.add("noVNC_open");
+ document.getElementById('pve_commands_button').classList.add("noVNC_selected");
+ },
+
+ closePVECommandPanel: function() {
+ document.getElementById('pve_commands').classList.remove("noVNC_open");
+ document.getElementById('pve_commands_button').classList.remove("noVNC_selected");
+ },
+
+/* ------^-------
+ * /PVE
+ * ==============
+ * MISC
+ * ------v------*/
setMouseButton: function(num) {
var view_only = UI.rfb.get_view_only();
if (UI.rfb && !view_only) {
@@ -1658,8 +1697,16 @@ const UI = {
},
updateSessionSize: function(rfb, width, height) {
- UI.updateViewClip();
- UI.fixScrollbars();
+ var resize = UI.getSetting('resize');
+
+ if (resize == 'null') {
+ var clip = UI.getSetting('clip');
+ UI.PVE.updateFBSize(rfb, width, height, clip);
+ }
+
+ UI.applyResizeMode();
+ UI.updateViewClip();
+ UI.updateViewDrag();
},
fixScrollbars: function() {
@@ -1704,7 +1751,7 @@ const UI = {
},
/* ------^-------
- * /MISC
+ * /MISC
* ==============
*/
};
--
2.11.0

View File

@ -0,0 +1,45 @@
From c1073cb0f19ebd64f6ee4b221b5aa06a2f8e5c99 Mon Sep 17 00:00:00 2001
From: Dominik Csapak <d.csapak@proxmox.com>
Date: Thu, 11 May 2017 10:34:10 +0200
Subject: [PATCH 2/9] change scaling when toggling fullscreen
when activating fullscreen, we change the scaling to 'scale',
and changing it back when leaving fullscreen
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
app/ui.js | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/app/ui.js b/app/ui.js
index def0eda..d4b0291 100644
--- a/app/ui.js
+++ b/app/ui.js
@@ -1174,6 +1174,15 @@ const UI = {
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
+
+ // when changing from fullscreen to window,
+ // re enable auto resize
+ if (WebUtil.getQueryVar('resize') === null) {
+ UI.updateSetting('resize', null);
+ setTimeout(function() {
+ UI.fixScrollbars();
+ }, 100);
+ }
} else {
if (document.documentElement.requestFullscreen) {
document.documentElement.requestFullscreen();
@@ -1184,6 +1193,8 @@ const UI = {
} else if (document.body.msRequestFullscreen) {
document.body.msRequestFullscreen();
}
+ // we want scaling in fullscreen mode
+ UI.updateSetting('resize', 'scale');
}
UI.enableDisableViewClip();
UI.updateFullscreenButton();
--
2.11.0

75
debian/patches/0003-add-pve-style.patch vendored Normal file
View File

@ -0,0 +1,75 @@
From 1cdfeafd561bfe4d9acb7ef8a838d82c64f9c1e5 Mon Sep 17 00:00:00 2001
From: Dominik Csapak <d.csapak@proxmox.com>
Date: Tue, 13 Dec 2016 16:03:41 +0100
Subject: [PATCH 3/9] add pve style
this adds the custom pve style (based on black.css)
we hide the connect button, and add custom colors,
and fix the z-index of the connect overlay
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
app/styles/pve.css | 37 +++++++++++++++++++++++++++++++++++++
vnc.html | 1 +
2 files changed, 38 insertions(+)
create mode 100644 app/styles/pve.css
diff --git a/app/styles/pve.css b/app/styles/pve.css
new file mode 100644
index 0000000..35002fe
--- /dev/null
+++ b/app/styles/pve.css
@@ -0,0 +1,37 @@
+/*
+ * noVNC black CSS
+ * Copyright (C) 2012 Joel Martin
+ * Copyright (C) 2013 Samuel Mannehed for Cendio AB
+ * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
+ * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
+ */
+
+.noVNC_panel {
+ border: 0px;
+ background:#4c4c4c;;
+ color:#fff;
+}
+
+#noVNC_control_bar, #noVNC_control_bar_handle, .noVNC_panel .noVNC_heading {
+ background: #4c4c4c;
+}
+
+.noVNC_button.noVNC_selected {
+ background: #3892d4;
+}
+
+#pve_commands > input[type=button] {
+ width: 100%;
+}
+
+#noVNC_canvas:focus {
+ outline: none;
+}
+
+#noVNC_transition {
+ z-index: 0;
+}
+
+#noVNC_connect_button {
+ display: none;
+}
diff --git a/vnc.html b/vnc.html
index 6cb4be4..98a9952 100644
--- a/vnc.html
+++ b/vnc.html
@@ -53,6 +53,7 @@
<!-- Stylesheets -->
<link rel="stylesheet" href="app/styles/base.css" />
+ <link rel="stylesheet" href="/novnc/app/styles/pve.css" />
<!--
<script type='text/javascript'
--
2.11.0

View File

@ -0,0 +1,54 @@
From a28b283a224990e1b46f304d9a2067afa7633d63 Mon Sep 17 00:00:00 2001
From: Dominik Csapak <d.csapak@proxmox.com>
Date: Fri, 20 Jan 2017 10:35:05 +0100
Subject: [PATCH 4/9] remove vnc logos
to show the pve icon instead
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
vnc.html | 24 ------------------------
1 file changed, 24 deletions(-)
diff --git a/vnc.html b/vnc.html
index 98a9952..cd8e594 100644
--- a/vnc.html
+++ b/vnc.html
@@ -23,34 +23,10 @@
Remove this if you use the .htaccess -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
- <!-- Icons (see Makefile for what the sizes are for) -->
- <link rel="icon" sizes="16x16" type="image/png" href="app/images/icons/novnc-16x16.png">
- <link rel="icon" sizes="24x24" type="image/png" href="app/images/icons/novnc-24x24.png">
- <link rel="icon" sizes="32x32" type="image/png" href="app/images/icons/novnc-32x32.png">
- <link rel="icon" sizes="48x48" type="image/png" href="app/images/icons/novnc-48x48.png">
- <link rel="icon" sizes="60x60" type="image/png" href="app/images/icons/novnc-60x60.png">
- <link rel="icon" sizes="64x64" type="image/png" href="app/images/icons/novnc-64x64.png">
- <link rel="icon" sizes="72x72" type="image/png" href="app/images/icons/novnc-72x72.png">
- <link rel="icon" sizes="76x76" type="image/png" href="app/images/icons/novnc-76x76.png">
- <link rel="icon" sizes="96x96" type="image/png" href="app/images/icons/novnc-96x96.png">
- <link rel="icon" sizes="120x120" type="image/png" href="app/images/icons/novnc-120x120.png">
- <link rel="icon" sizes="144x144" type="image/png" href="app/images/icons/novnc-144x144.png">
- <link rel="icon" sizes="152x152" type="image/png" href="app/images/icons/novnc-152x152.png">
- <link rel="icon" sizes="192x192" type="image/png" href="app/images/icons/novnc-192x192.png">
- <link rel="icon" sizes="any" type="image/svg+xml" href="app/images/icons/novnc-icon.svg">
- <!-- Repeated last so that legacy handling will pick this -->
- <link rel="icon" sizes="16x16" type="image/png" href="app/images/icons/novnc-16x16.png">
-
<!-- Apple iOS Safari settings -->
<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" />
- <!-- Home Screen Icons (favourites and bookmarks use the normal icons) -->
- <link rel="apple-touch-icon" sizes="60x60" type="image/png" href="app/images/icons/novnc-60x60.png">
- <link rel="apple-touch-icon" sizes="76x76" type="image/png" href="app/images/icons/novnc-76x76.png">
- <link rel="apple-touch-icon" sizes="120x120" type="image/png" href="app/images/icons/novnc-120x120.png">
- <link rel="apple-touch-icon" sizes="152x152" type="image/png" href="app/images/icons/novnc-152x152.png">
-
<!-- Stylesheets -->
<link rel="stylesheet" href="app/styles/base.css" />
<link rel="stylesheet" href="/novnc/app/styles/pve.css" />
--
2.11.0

View File

@ -0,0 +1,232 @@
From 0b7322fc05361366fc4e24e6d5b9d8e2254ace40 Mon Sep 17 00:00:00 2001
From: Dominik Csapak <d.csapak@proxmox.com>
Date: Tue, 17 Jan 2017 17:24:03 +0100
Subject: [PATCH 5/9] change src directory for images/js files
since they will be in /novnc/
also change the directory in the build script
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
app/ui.js | 2 +-
utils/use_require_helpers.js | 2 +-
vnc.html | 56 ++++++++++++++++++++++----------------------
3 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/app/ui.js b/app/ui.js
index d4b0291..d32c789 100644
--- a/app/ui.js
+++ b/app/ui.js
@@ -1771,7 +1771,7 @@ const UI = {
var LINGUAS = ["de", "el", "nl", "sv"];
l10n.setup(LINGUAS);
if (l10n.language !== "en" && l10n.dictionary === undefined) {
- WebUtil.fetchJSON('app/locale/' + l10n.language + '.json', function (translations) {
+ WebUtil.fetchJSON('/novnc/app/locale/' + l10n.language + '.json', function (translations) {
l10n.dictionary = translations;
// wait for translations to load before loading the UI
diff --git a/utils/use_require_helpers.js b/utils/use_require_helpers.js
index 990fb4d..0f44e1c 100644
--- a/utils/use_require_helpers.js
+++ b/utils/use_require_helpers.js
@@ -22,7 +22,7 @@ module.exports = {
var browserify = require('browserify');
var b = browserify(path.join(base_out_path, 'app/ui.js'), {});
b.bundle().pipe(fs.createWriteStream(out_path));
- return `<script src="${path.relative(base_out_path, out_path)}"></script>`;
+ return `<script src="/novnc/${path.relative(base_out_path, out_path)}"></script>`;
},
noCopyOverride: () => {},
},
diff --git a/vnc.html b/vnc.html
index cd8e594..23fc0e4 100644
--- a/vnc.html
+++ b/vnc.html
@@ -28,7 +28,7 @@
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<!-- Stylesheets -->
- <link rel="stylesheet" href="app/styles/base.css" />
+ <link rel="stylesheet" href="/novnc/app/styles/base.css" />
<link rel="stylesheet" href="/novnc/app/styles/pve.css" />
<!--
@@ -37,11 +37,11 @@
-->
<!-- this is included as a normal file in order to catch script-loading errors as well -->
- <script type="text/javascript" src="app/error-handler.js"></script>
+ <script type="text/javascript" src="/novnc/app/error-handler.js"></script>
<!-- begin scripts -->
<!-- promise polyfills promises for IE11 -->
- <script src="vendor/promise.js"></script>
+ <script src="/novnc/vendor/promise.js"></script>
<!-- ES2015/ES6 modules polyfill -->
<script type="module">
window._noVNC_has_module_support = true;
@@ -50,12 +50,12 @@
window.addEventListener("load", function() {
if (window._noVNC_has_module_support) return;
var loader = document.createElement("script");
- loader.src = "vendor/browser-es-module-loader/dist/browser-es-module-loader.js";
+ loader.src = "/novnc/vendor/browser-es-module-loader/dist/browser-es-module-loader.js";
document.head.appendChild(loader);
});
</script>
<!-- actual script modules -->
- <script type="module" src="app/ui.js"></script>
+ <script type="module" src="/novnc/app/ui.js"></script>
<!-- end scripts -->
</head>
@@ -80,49 +80,49 @@
<h1 class="noVNC_logo" translate="no"><span>no</span><br />VNC</h1>
<!-- Drag/Pan the viewport -->
- <input type="image" alt="viewport drag" src="app/images/drag.svg"
+ <input type="image" alt="viewport drag" src="/novnc/app/images/drag.svg"
id="noVNC_view_drag_button" class="noVNC_button noVNC_hidden"
title="Move/Drag Viewport" />
<!--noVNC Touch Device only buttons-->
<div id="noVNC_mobile_buttons">
- <input type="image" alt="No mousebutton" src="app/images/mouse_none.svg"
+ <input type="image" alt="No mousebutton" src="/novnc/app/images/mouse_none.svg"
id="noVNC_mouse_button0" class="noVNC_button"
title="Active Mouse Button"/>
- <input type="image" alt="Left mousebutton" src="app/images/mouse_left.svg"
+ <input type="image" alt="Left mousebutton" src="/novnc/app/images/mouse_left.svg"
id="noVNC_mouse_button1" class="noVNC_button"
title="Active Mouse Button"/>
- <input type="image" alt="Middle mousebutton" src="app/images/mouse_middle.svg"
+ <input type="image" alt="Middle mousebutton" src="/novnc/app/images/mouse_middle.svg"
id="noVNC_mouse_button2" class="noVNC_button"
title="Active Mouse Button"/>
- <input type="image" alt="Right mousebutton" src="app/images/mouse_right.svg"
+ <input type="image" alt="Right mousebutton" src="/novnc/app/images/mouse_right.svg"
id="noVNC_mouse_button4" class="noVNC_button"
title="Active Mouse Button"/>
- <input type="image" alt="Keyboard" src="app/images/keyboard.svg"
+ <input type="image" alt="Keyboard" src="/novnc/app/images/keyboard.svg"
id="noVNC_keyboard_button" class="noVNC_button"
value="Keyboard" title="Show Keyboard" />
</div>
<!-- Extra manual keys -->
<div id="noVNC_extra_keys">
- <input type="image" alt="Extra keys" src="app/images/toggleextrakeys.svg"
+ <input type="image" alt="Extra keys" src="/novnc/app/images/toggleextrakeys.svg"
id="noVNC_toggle_extra_keys_button" class="noVNC_button"
title="Show Extra Keys"/>
<div class="noVNC_vcenter">
<div id="noVNC_modifiers" class="noVNC_panel">
- <input type="image" alt="Ctrl" src="app/images/ctrl.svg"
+ <input type="image" alt="Ctrl" src="/novnc/app/images/ctrl.svg"
id="noVNC_toggle_ctrl_button" class="noVNC_button"
title="Toggle Ctrl"/>
- <input type="image" alt="Alt" src="app/images/alt.svg"
+ <input type="image" alt="Alt" src="/novnc/app/images/alt.svg"
id="noVNC_toggle_alt_button" class="noVNC_button"
title="Toggle Alt"/>
- <input type="image" alt="Tab" src="app/images/tab.svg"
+ <input type="image" alt="Tab" src="/novnc/app/images/tab.svg"
id="noVNC_send_tab_button" class="noVNC_button"
title="Send Tab"/>
- <input type="image" alt="Esc" src="app/images/esc.svg"
+ <input type="image" alt="Esc" src="/novnc/app/images/esc.svg"
id="noVNC_send_esc_button" class="noVNC_button"
title="Send Escape"/>
- <input type="image" alt="Ctrl+Alt+Del" src="app/images/ctrlaltdel.svg"
+ <input type="image" alt="Ctrl+Alt+Del" src="/novnc/app/images/ctrlaltdel.svg"
id="noVNC_send_ctrl_alt_del_button" class="noVNC_button"
title="Send Ctrl-Alt-Del" />
</div>
@@ -130,13 +130,13 @@
</div>
<!-- XVP Shutdown/Reboot -->
- <input type="image" alt="Shutdown/Reboot" src="app/images/power.svg"
+ <input type="image" alt="Shutdown/Reboot" src="/novnc/app/images/power.svg"
id="noVNC_xvp_button" class="noVNC_button"
title="Shutdown/Reboot..." />
<div class="noVNC_vcenter">
<div id="noVNC_xvp" class="noVNC_panel">
<div class="noVNC_heading">
- <img src="app/images/power.svg"> Power
+ <img src="/novnc/app/images/power.svg"> Power
</div>
<input type="button" id="noVNC_xvp_shutdown_button" value="Shutdown" />
<input type="button" id="noVNC_xvp_reboot_button" value="Reboot" />
@@ -145,13 +145,13 @@
</div>
<!-- Clipboard -->
- <input type="image" alt="Clipboard" src="app/images/clipboard.svg"
+ <input type="image" alt="Clipboard" src="/novnc/app/images/clipboard.svg"
id="noVNC_clipboard_button" class="noVNC_button"
title="Clipboard" />
<div class="noVNC_vcenter">
<div id="noVNC_clipboard" class="noVNC_panel">
<div class="noVNC_heading">
- <img src="app/images/clipboard.svg"> Clipboard
+ <img src="/novnc/app/images/clipboard.svg"> Clipboard
</div>
<textarea id="noVNC_clipboard_text" rows=5></textarea>
<br />
@@ -161,19 +161,19 @@
</div>
<!-- Toggle fullscreen -->
- <input type="image" alt="Fullscreen" src="app/images/fullscreen.svg"
+ <input type="image" alt="Fullscreen" src="/novnc/app/images/fullscreen.svg"
id="noVNC_fullscreen_button" class="noVNC_button noVNC_hidden"
title="Fullscreen" />
<!-- Settings -->
- <input type="image" alt="Settings" src="app/images/settings.svg"
+ <input type="image" alt="Settings" src="/novnc/app/images/settings.svg"
id="noVNC_settings_button" class="noVNC_button"
title="Settings" />
<div class="noVNC_vcenter">
<div id="noVNC_settings" class="noVNC_panel">
<ul>
<li class="noVNC_heading">
- <img src="app/images/settings.svg"> Settings
+ <img src="/novnc/app/images/settings.svg"> Settings
</li>
<li>
<label><input id="noVNC_setting_shared" type="checkbox" /> Shared Mode</label>
@@ -249,7 +249,7 @@
</div>
<!-- Connection Controls -->
- <input type="image" alt="Disconnect" src="app/images/disconnect.svg"
+ <input type="image" alt="Disconnect" src="/novnc/app/images/disconnect.svg"
id="noVNC_disconnect_button" class="noVNC_button"
title="Disconnect" />
@@ -266,7 +266,7 @@
<div id="noVNC_connect_dlg">
<div class="noVNC_logo" translate="no"><span>no</span>VNC</div>
<div id="noVNC_connect_button"><div>
- <img src="app/images/connect.svg"> Connect
+ <img src="/novnc/app/images/connect.svg"> Connect
</div></div>
</div>
</div>
@@ -314,8 +314,8 @@
</div>
<audio id="noVNC_bell">
- <source src="app/sounds/bell.oga" type="audio/ogg">
- <source src="app/sounds/bell.mp3" type="audio/mpeg">
+ <source src="/novnc/app/sounds/bell.oga" type="audio/ogg">
+ <source src="/novnc/app/sounds/bell.mp3" type="audio/mpeg">
</audio>
</body>
</html>
--
2.11.0

View File

@ -0,0 +1,44 @@
From 1a042fcad1f9242cafbb589a1da5b8b270e8b8bb Mon Sep 17 00:00:00 2001
From: Dominik Csapak <d.csapak@proxmox.com>
Date: Fri, 20 Jan 2017 10:35:43 +0100
Subject: [PATCH 6/9] add pve vnc commands
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
vnc.html | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/vnc.html b/vnc.html
index 23fc0e4..e789d04 100644
--- a/vnc.html
+++ b/vnc.html
@@ -165,6 +165,26 @@
id="noVNC_fullscreen_button" class="noVNC_button noVNC_hidden"
title="Fullscreen" />
+ <!-- PVE Commands -->
+ <input type="image" alt="Commands" src="/novnc/app/images/power.svg"
+ id="pve_commands_button" class="noVNC_button"
+ title="Commands" />
+
+ <div class="noVNC_vcenter">
+ <div id="pve_commands" class="noVNC_panel">
+ <div class="noVNC_heading">
+ <img src="/novnc/app/images/power.svg"> Commands
+ </div>
+ <input id="pve_command_start" type="button" value="Start" />
+ <input id="pve_command_shutdown" type="button" value="Shutdown" />
+ <input id="pve_command_stop" type="button" value="Stop" />
+ <input id="pve_command_reset" type="button" value="Reset" />
+ <input id="pve_command_suspend" type="button" value="Suspend" />
+ <input id="pve_command_resume" type="button" value="Resume" />
+ <input id="pve_command_reload" type="button" value="Reload" />
+ </div>
+ </div>
+
<!-- Settings -->
<input type="image" alt="Settings" src="/novnc/app/images/settings.svg"
id="noVNC_settings_button" class="noVNC_button"
--
2.11.0

View File

@ -0,0 +1,41 @@
From c3d885b78fd816201ed485eb7a681ce1fcf3a122 Mon Sep 17 00:00:00 2001
From: Dominik Csapak <d.csapak@proxmox.com>
Date: Fri, 20 Jan 2017 10:16:09 +0100
Subject: [PATCH 7/9] add replaceable snippets in vnc.html
so that we can insert the username/csrftoken via search/replace
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
vnc.html | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/vnc.html b/vnc.html
index e789d04..1423f78 100644
--- a/vnc.html
+++ b/vnc.html
@@ -15,7 +15,7 @@
or the fragment:
http://example.com/#host=HOST&port=PORT&encrypt=1
-->
- <title>noVNC</title>
+ <title>[% nodename %] - Proxmox Console</title>
<meta charset="utf-8" />
@@ -38,6 +38,12 @@
<!-- this is included as a normal file in order to catch script-loading errors as well -->
<script type="text/javascript" src="/novnc/app/error-handler.js"></script>
+ <script type="text/javascript">
+ if (typeof(PVE) === 'undefined') PVE = {};
+ PVE.UserName = '[% username %]';
+ PVE.CSRFPreventionToken = '[% token %]';
+ INCLUDE_URI='/novnc/include';
+ </script>
<!-- begin scripts -->
<!-- promise polyfills promises for IE11 -->
--
2.11.0

View File

@ -0,0 +1,43 @@
From b97c51d6a2ca70a5e60209cd7ab16563455b8d13 Mon Sep 17 00:00:00 2001
From: Dominik Csapak <d.csapak@proxmox.com>
Date: Wed, 14 Dec 2016 08:40:02 +0100
Subject: [PATCH 8/9] focus canvas after load
or else in some browsers, the canvas does not get the focus after
loading in an iframe
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
app/ui.js | 2 ++
vnc.html | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/app/ui.js b/app/ui.js
index d32c789..ed2897b 100644
--- a/app/ui.js
+++ b/app/ui.js
@@ -442,6 +442,8 @@ const UI = {
msg = _("Connected (unencrypted) to ") + UI.desktopName;
}
UI.showStatus(msg);
+ rfb.get_keyboard().set_focused(true);
+ document.getElementById("noVNC_canvas").focus();
break;
case 'disconnecting':
UI.connected = false;
diff --git a/vnc.html b/vnc.html
index 1423f78..ff70e0c 100644
--- a/vnc.html
+++ b/vnc.html
@@ -332,7 +332,7 @@
autocorrect="off" autocomplete="off" spellcheck="false"
mozactionhint="Enter"></textarea>
- <canvas id="noVNC_canvas" width="0" height="0">
+ <canvas id="noVNC_canvas" width="0" height="0" tabindex="0">
Canvas not supported.
</canvas>
</div>
--
2.11.0

View File

@ -0,0 +1,73 @@
From 3f13289a9f895b1ba86ad61ed085390bffda3e3a Mon Sep 17 00:00:00 2001
From: Dominik Csapak <d.csapak@proxmox.com>
Date: Fri, 20 Jan 2017 10:55:49 +0100
Subject: [PATCH 9/9] decrease animation time
because 0.5s is too long
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
app/styles/base.css | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/app/styles/base.css b/app/styles/base.css
index ce31cf7..6db4467 100644
--- a/app/styles/base.css
+++ b/app/styles/base.css
@@ -283,7 +283,7 @@ select:active {
position: fixed;
z-index: 10;
- transition: 0.5s ease-in-out;
+ transition: 0.1s ease-in-out;
/* Edge misrenders animations wihthout this */
transform: translateX(0);
@@ -300,7 +300,7 @@ select:active {
position: relative;
left: -100%;
- transition: 0.5s ease-in-out;
+ transition: 0.1s ease-in-out;
background-color: rgb(110, 132, 163);
border-radius: 0 10px 10px 0;
@@ -318,7 +318,7 @@ select:active {
height: 100%;
width: 30px;
left: -30px;
- transition: box-shadow 0.5s ease-in-out;
+ transition: box-shadow 0.1s ease-in-out;
}
#noVNC_control_bar.noVNC_open::before {
box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
@@ -352,7 +352,7 @@ select:active {
}
#noVNC_control_bar_handle:after {
content: "";
- transition: transform 0.5s ease-in-out;
+ transition: transform 0.1s ease-in-out;
background: url("../images/handle.svg");
position: absolute;
top: 22px; /* (50px-6px)/2 */
@@ -440,7 +440,7 @@ select:active {
.noVNC_panel {
transform: translateX(25px);
- transition: 0.5s ease-in-out;
+ transition: 0.25s ease-in-out;
max-height: 100vh; /* Chrome is buggy with 100% */
overflow-x: hidden;
@@ -617,7 +617,7 @@ select:active {
cursor: pointer;
- transition: 0.5s ease-in-out;
+ transition: 0.1s ease-in-out;
visibility: hidden;
opacity: 0;
--
2.11.0