mirror of
git://git.proxmox.com/git/novnc-pve.git
synced 2025-03-12 20:58:29 +03:00
by not using the password input at all, but pass the password to the connect function manually this changes the first patch instead of adding another one, since it only touches code from that. Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
636 lines
18 KiB
Diff
636 lines
18 KiB
Diff
From 0000000000000000000000000000000000000000 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] add PVE specific JS code
|
|
|
|
Add a ES6 module named `PVEUI` which defines the Proxmox VE
|
|
related helper methods, like for example, API2Request.
|
|
|
|
Hook the `PVEUI` module into the upstream `ui.js`, so that handlers
|
|
for `autoresizing`, `commandstoggle`, etc., get setup.
|
|
|
|
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
|
|
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
|
|
---
|
|
app/pve.js | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
app/ui.js | 62 ++++++--
|
|
vnc.html | 10 +-
|
|
3 files changed, 485 insertions(+), 15 deletions(-)
|
|
create mode 100644 app/pve.js
|
|
|
|
diff --git a/app/pve.js b/app/pve.js
|
|
new file mode 100644
|
|
index 0000000..1a062ad
|
|
--- /dev/null
|
|
+++ b/app/pve.js
|
|
@@ -0,0 +1,428 @@
|
|
+/*
|
|
+ * 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;
|
|
+ }
|
|
+
|
|
+ if (this.resize == 'scale' &&
|
|
+ (this.consoletype === 'lxc' || this.consoletype === 'shell')) {
|
|
+ var size = this.getFBSize();
|
|
+ params.width = size.width;
|
|
+ params.height = size.height;
|
|
+ }
|
|
+
|
|
+ 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('Waiting for connection...', '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('Connection resumed', '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) {
|
|
+ if (cmd === 'start' && msg.match(/already running/) !== null) {
|
|
+ // we wanted to start, but it was already running, so
|
|
+ // reload anyway
|
|
+ me.UI.showStatus("VM command '" + cmd +"' successful", 'normal');
|
|
+ setTimeout(function() {
|
|
+ location.reload();
|
|
+ }, 1000);
|
|
+ } else {
|
|
+ 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_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');
|
|
+ }
|
|
+ });
|
|
+ },
|
|
+
|
|
+ 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
|
|
+ });
|
|
+
|
|
+ let password = result.data.ticket;
|
|
+ me.UI.reconnectPassword = password;
|
|
+ me.UI.forceSetting('path', 'api2/json' + me.baseUrl + '/vncwebsocket' + "?" + wsparams);
|
|
+
|
|
+ callback(password);
|
|
+ },
|
|
+ failure: function(msg) {
|
|
+ me.UI.showStatus(msg, 'error');
|
|
+ }
|
|
+ });
|
|
+ },
|
|
+
|
|
+ updateFBSize: function(rfb, width, height) {
|
|
+ var me = this;
|
|
+ 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);
|
|
+ }
|
|
+
|
|
+ var update_size = function() {
|
|
+ var clip = me.UI.getSetting('view_clip');
|
|
+ var resize = me.UI.getSetting('resize');
|
|
+ var autoresize = me.UI.getSetting('autoresize');
|
|
+ if (clip || resize === 'scale' || !autoresize) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // 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);
|
|
+ } 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 c1f6776..c86f36c 100644
|
|
--- a/app/ui.js
|
|
+++ b/app/ui.js
|
|
@@ -17,6 +17,7 @@ import keysyms from "../core/input/keysymdef.js";
|
|
import Keyboard from "../core/input/keyboard.js";
|
|
import RFB from "../core/rfb.js";
|
|
import * as WebUtil from "./webutil.js";
|
|
+import PVEUI from "./pve.js";
|
|
|
|
const PAGE_TITLE = "noVNC";
|
|
|
|
@@ -57,6 +58,8 @@ const UI = {
|
|
// Render default UI and initialize settings menu
|
|
start() {
|
|
|
|
+ UI.PVE = new PVEUI(UI);
|
|
+
|
|
UI.initSettings();
|
|
|
|
// Translate the DOM
|
|
@@ -108,6 +111,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);
|
|
|
|
@@ -116,19 +122,15 @@ const UI = {
|
|
|
|
UI.openControlbar();
|
|
|
|
+ UI.updateViewClip();
|
|
+
|
|
UI.updateVisualState('init');
|
|
|
|
document.documentElement.classList.remove("noVNC_loading");
|
|
|
|
- let autoconnect = WebUtil.getConfigVar('autoconnect', false);
|
|
- if (autoconnect === 'true' || autoconnect == '1') {
|
|
- autoconnect = true;
|
|
- UI.connect();
|
|
- } else {
|
|
- autoconnect = false;
|
|
- // Show the connect panel on first load unless autoconnecting
|
|
- UI.openConnectPanel();
|
|
- }
|
|
+ UI.PVE.pveStart(function(password) {
|
|
+ UI.connect(undefined, password);
|
|
+ });
|
|
|
|
return Promise.resolve(UI.rfb);
|
|
},
|
|
@@ -172,11 +174,12 @@ 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('view_clip', false);
|
|
UI.initSetting('resize', 'off');
|
|
UI.initSetting('quality', 6);
|
|
UI.initSetting('compression', 2);
|
|
+ UI.initSetting('autoresize', true);
|
|
UI.initSetting('shared', true);
|
|
UI.initSetting('view_only', false);
|
|
UI.initSetting('show_dot', false);
|
|
@@ -357,6 +360,7 @@ const UI = {
|
|
UI.addSettingChangeHandler('resize');
|
|
UI.addSettingChangeHandler('resize', UI.applyResizeMode);
|
|
UI.addSettingChangeHandler('resize', UI.updateViewClip);
|
|
+ UI.addSettingChangeHandler('autoresize');
|
|
UI.addSettingChangeHandler('quality');
|
|
UI.addSettingChangeHandler('quality', UI.updateQuality);
|
|
UI.addSettingChangeHandler('compression');
|
|
@@ -411,6 +415,9 @@ const UI = {
|
|
document.documentElement.classList.add("noVNC_connecting");
|
|
break;
|
|
case 'connected':
|
|
+ UI.connected = true;
|
|
+ UI.inhibit_reconnect = false;
|
|
+ UI.pveAllowMigratedTest = true;
|
|
document.documentElement.classList.add("noVNC_connected");
|
|
break;
|
|
case 'disconnecting':
|
|
@@ -418,6 +425,11 @@ const UI = {
|
|
document.documentElement.classList.add("noVNC_disconnecting");
|
|
break;
|
|
case 'disconnected':
|
|
+ UI.showStatus(_("Disconnected"));
|
|
+ if (UI.pveAllowMigratedTest === true) {
|
|
+ UI.pveAllowMigratedTest = false;
|
|
+ UI.PVE.pve_detect_migrated_vm();
|
|
+ }
|
|
break;
|
|
case 'reconnecting':
|
|
transitionElem.textContent = _("Reconnecting...");
|
|
@@ -843,6 +855,7 @@ const UI = {
|
|
UI.closePowerPanel();
|
|
UI.closeClipboardPanel();
|
|
UI.closeExtraKeys();
|
|
+ UI.closePVECommandPanel();
|
|
},
|
|
|
|
/* ------^-------
|
|
@@ -1689,9 +1702,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------*/
|
|
updateViewOnly() {
|
|
if (!UI.rfb) return;
|
|
UI.rfb.viewOnly = UI.getSetting('view_only');
|
|
diff --git a/vnc.html b/vnc.html
|
|
index 24a118d..e8a982f 100644
|
|
--- a/vnc.html
|
|
+++ b/vnc.html
|
|
@@ -154,7 +154,7 @@
|
|
<img alt="" src="app/images/settings.svg"> Settings
|
|
</div>
|
|
<ul>
|
|
- <li>
|
|
+ <li style="display:none;">
|
|
<label><input id="noVNC_setting_shared" type="checkbox"> Shared Mode</label>
|
|
</li>
|
|
<li>
|
|
@@ -164,16 +164,18 @@
|
|
<li>
|
|
<label><input id="noVNC_setting_view_clip" type="checkbox"> Clip to Window</label>
|
|
</li>
|
|
+ <li>
|
|
+ <label><input id="noVNC_setting_autoresize" type="checkbox" /> Autoresize Window</label>
|
|
+ </li>
|
|
<li>
|
|
<label for="noVNC_setting_resize">Scaling Mode:</label>
|
|
<select id="noVNC_setting_resize" name="vncResize">
|
|
- <option value="off">None</option>
|
|
+ <option value="off">Off</option>
|
|
<option value="scale">Local Scaling</option>
|
|
- <option value="remote">Remote Resizing</option>
|
|
</select>
|
|
</li>
|
|
<li><hr></li>
|
|
- <li>
|
|
+ <li style="display:none;">
|
|
<div class="noVNC_expander">Advanced</div>
|
|
<div><ul>
|
|
<li>
|