Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37517329
en ru br
Репозитории ALT

Группа :: Сети/WWW
Пакет: pve-novnc

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: pveui.patch
Скачать


From 280c1f8b3c07fde35282cd46d965bc1bc8f5649d Mon Sep 17 00:00:00 2001
From: Alexandre Derumier <aderumier@odiso.com>
Date: Thu, 25 Jun 2015 02:50:03 +0200
Subject: [PATCH] pveui : add promox code
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
 pveui.js | 724 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 675 insertions(+), 49 deletions(-)
diff --git a/pveui.js b/pveui.js
index cb5717c..ceaa4fc 100644
--- a/pveui.js
+++ b/pveui.js
@@ -39,10 +39,17 @@ var UI;
         isTouchDevice: false,
         rememberedClipSetting: null,
 
+        pveAllowMigratedVMTest: false, // set to true after a succesful conection
+        pveCommandsOpen: false,
+        consoletype: undefined,
+        vmid: undefined,
+        vmname: undefined,
+        nodename: undefined,
+        resize: undefined,
         // Setup rfb object, load settings from browser storage, then call
         // UI.init to setup the UI/menus
         load: function (callback) {
-            WebUtil.initSettings(UI.start, callback);
+            WebUtil.initSettings(UI.pve_start, callback);
         },
 
         // Render default UI and initialize settings menu
@@ -54,13 +61,13 @@ var UI;
             var sheets = WebUtil.getStylesheets();
             var i;
             for (i = 0; i < sheets.length; i += 1) {
-                UI.addOption($D('noVNC_stylesheet'),sheets[i].title, sheets[i].title);
+                //UI.addOption($D('noVNC_stylesheet'),sheets[i].title, sheets[i].title);
             }
 
             // Logging selection dropdown
             var llevels = ['error', 'warn', 'info', 'debug'];
             for (i = 0; i < llevels.length; i += 1) {
-                UI.addOption($D('noVNC_logging'),llevels[i], llevels[i]);
+                //UI.addOption($D('noVNC_logging'),llevels[i], llevels[i]);
             }
 
             // Settings with immediate effects
@@ -84,20 +91,10 @@ var UI;
                 }
             }
 
-            /* Populate the controls if defaults are provided in the URL */
-            UI.initSetting('host', window.location.hostname);
-            UI.initSetting('port', port);
-            UI.initSetting('password', '');
-            UI.initSetting('encrypt', (window.location.protocol === "https:"));
-            UI.initSetting('true_color', true);
-            UI.initSetting('cursor', !UI.isTouchDevice);
-            UI.initSetting('resize', 'off');
-            UI.initSetting('shared', true);
-            UI.initSetting('view_only', false);
-            UI.initSetting('path', 'websockify');
+
             UI.initSetting('repeaterID', '');
 
-            var autoconnect = WebUtil.getQueryVar('autoconnect', false);
+            var autoconnect = true;
             if (autoconnect === 'true' || autoconnect == '1') {
                 autoconnect = true;
                 UI.connect();
@@ -140,7 +137,9 @@ var UI;
                 (document.documentElement.requestFullscreen ||
                  document.documentElement.mozRequestFullScreen ||
                  document.documentElement.webkitRequestFullscreen ||
-                 document.body.msRequestFullscreen)) {
+                 document.body.msRequestFullscreen)
+		&& UI.getSetting('resize') === 'scale'
+		) {
                 $D('fullscreenButton').style.display = "inline";
                 Util.addEvent(window, 'fullscreenchange', UI.updateFullscreenButton);
                 Util.addEvent(window, 'mozfullscreenchange', UI.updateFullscreenButton);
@@ -177,13 +176,16 @@ var UI;
 
         initRFB: function () {
             try {
+		var scaleType = UI.getSetting('resize');
+
                 UI.rfb = new RFB({'target': $D('noVNC_canvas'),
                                   'onUpdateState': UI.updateState,
                                   'onXvpInit': UI.updateXvpVisualState,
                                   'onClipboard': UI.clipReceive,
                                   'onFBUComplete': UI.FBUComplete,
-                                  'onFBResize': UI.updateViewDrag,
-                                  'onDesktopName': UI.updateDocumentTitle});
+                                  'onFBResize': (typeof scaleType !== 'undefined') ? UI.updateFBSize : UI.updateViewDrag
+                                  //  'onDesktopName': UI.updateDocumentTitle
+				});
                 return true;
             } catch (exc) {
                 UI.updateState(null, 'fatal', null, 'Unable to create RFB client -- ' + exc);
@@ -211,31 +213,34 @@ var UI;
             $D("sendEscButton").onclick = UI.sendEsc;
 
             $D("sendCtrlAltDelButton").onclick = UI.sendCtrlAltDel;
-            $D("xvpShutdownButton").onclick = UI.xvpShutdown;
-            $D("xvpRebootButton").onclick = UI.xvpReboot;
-            $D("xvpResetButton").onclick = UI.xvpReset;
-            $D("noVNC_status").onclick = UI.togglePopupStatus;
+            //$D("xvpShutdownButton").onclick = UI.xvpShutdown;
+            //$D("xvpRebootButton").onclick = UI.xvpReboot;
+            //$D("xvpResetButton").onclick = UI.xvpReset;
+            //$D("noVNC_status").onclick = UI.togglePopupStatus;
             $D("noVNC_popup_status").onclick = UI.togglePopupStatus;
-            $D("xvpButton").onclick = UI.toggleXvpPanel;
+            //$D("xvpButton").onclick = UI.toggleXvpPanel;
             $D("clipboardButton").onclick = UI.toggleClipboardPanel;
             $D("fullscreenButton").onclick = UI.toggleFullscreen;
-            $D("settingsButton").onclick = UI.toggleSettingsPanel;
-            $D("connectButton").onclick = UI.toggleConnectPanel;
-            $D("disconnectButton").onclick = UI.disconnect;
-            $D("descriptionButton").onclick = UI.toggleConnectPanel;
+            //$D("settingsButton").onclick = UI.toggleSettingsPanel;
+            //$D("connectButton").onclick = UI.toggleConnectPanel;
+            //$D("disconnectButton").onclick = UI.disconnect;
+            //$D("descriptionButton").onclick = UI.toggleConnectPanel;
 
             $D("noVNC_clipboard_text").onfocus = UI.displayBlur;
             $D("noVNC_clipboard_text").onblur = UI.displayFocus;
             $D("noVNC_clipboard_text").onchange = UI.clipSend;
             $D("noVNC_clipboard_clear_button").onclick = UI.clipClear;
 
-            $D("noVNC_settings_menu").onmouseover = UI.displayBlur;
-            $D("noVNC_settings_menu").onmouseover = UI.displayFocus;
-            $D("noVNC_apply").onclick = UI.settingsApply;
+            //$D("noVNC_settings_menu").onmouseover = UI.displayBlur;
+            //$D("noVNC_settings_menu").onmouseover = UI.displayFocus;
+            //$D("noVNC_apply").onclick = UI.settingsApply;
 
-            $D("noVNC_connect_button").onclick = UI.connect;
+            //$D("noVNC_connect_button").onclick = UI.connect;
 
             $D("noVNC_resize").onchange = UI.enableDisableViewClip;
+
+            $D("pveCommandsButton").onclick = UI.togglePVECommandPanel;
+            $D("showSendKeysButton").onclick = UI.togglePVESendKeysPanel;
         },
 
         onresize: function (callback) {
@@ -398,6 +403,9 @@ var UI;
         toggleXvpPanel: function() {
             // Close the description panel
             $D('noVNC_description').style.display = "none";
+	    if (UI.pveCommandsOpen === true) {
+		UI.togglePVECommandPanel();
+	    }
             // Close settings if open
             if (UI.settingsOpen === true) {
                 UI.settingsApply();
@@ -413,12 +421,12 @@ var UI;
             }
             // Toggle XVP panel
             if (UI.xvpOpen === true) {
-                $D('noVNC_xvp').style.display = "none";
-                $D('xvpButton').className = "noVNC_status_button";
+                //$D('noVNC_xvp').style.display = "none";
+                //$D('xvpButton').className = "noVNC_status_button";
                 UI.xvpOpen = false;
             } else {
-                $D('noVNC_xvp').style.display = "block";
-                $D('xvpButton').className = "noVNC_status_button_selected";
+                //$D('noVNC_xvp').style.display = "block";
+                //$D('xvpButton').className = "noVNC_status_button_selected";
                 UI.xvpOpen = true;
             }
         },
@@ -427,6 +435,12 @@ var UI;
         toggleClipboardPanel: function() {
             // Close the description panel
             $D('noVNC_description').style.display = "none";
+	    if (UI.pveCommandsOpen === true) {
+		UI.togglePVECommandPanel();
+	    }
+	    if (UI.sendKeysVisible === true) {
+		UI.togglePVESendKeysPanel();
+	    }
             // Close settings if open
             if (UI.settingsOpen === true) {
                 UI.settingsApply();
@@ -497,6 +511,9 @@ var UI;
         toggleConnectPanel: function() {
             // Close the description panel
             $D('noVNC_description').style.display = "none";
+	    if (UI.pveCommandsOpen === true) {
+		UI.togglePVECommandPanel();
+	    }
             // Close connection settings if open
             if (UI.settingsOpen === true) {
                 UI.settingsApply();
@@ -515,14 +532,14 @@ var UI;
             // Toggle Connection Panel
             if (UI.connSettingsOpen === true) {
                 $D('noVNC_controls').style.display = "none";
-                $D('connectButton').className = "noVNC_status_button";
+                //$D('connectButton').className = "noVNC_status_button";
                 UI.connSettingsOpen = false;
                 UI.saveSetting('host');
                 UI.saveSetting('port');
                 //UI.saveSetting('password');
             } else {
                 $D('noVNC_controls').style.display = "block";
-                $D('connectButton').className = "noVNC_status_button_selected";
+                //$D('connectButton').className = "noVNC_status_button_selected";
                 UI.connSettingsOpen = true;
                 $D('noVNC_host').focus();
             }
@@ -576,14 +593,14 @@ var UI;
                 UI.toggleXvpPanel();
             }
             $D('noVNC_settings').style.display = "block";
-            $D('settingsButton').className = "noVNC_status_button_selected";
+            //$D('settingsButton').className = "noVNC_status_button_selected";
             UI.settingsOpen = true;
         },
 
         // Close menu (without applying settings)
         closeSettingsMenu: function() {
             $D('noVNC_settings').style.display = "none";
-            $D('settingsButton').className = "noVNC_status_button";
+            //$D('settingsButton').className = "noVNC_status_button";
             UI.settingsOpen = false;
         },
 
@@ -676,10 +693,15 @@ var UI;
                     break;
                 case 'normal':
                     klass = "noVNC_status_normal";
+		    UI.pveAllowMigratedVMTest = true;
                     break;
                 case 'disconnected':
                     $D('noVNC_logo').style.display = "block";
                     $D('noVNC_container').style.display = "none";
+		    if (UI.pveAllowMigratedVMTest) {
+			UI.pveAllowMigratedVMTest = false;
+			UI.pve_detect_migrated_vm();
+		    }
                     /* falls through */
                 case 'loaded':
                     klass = "noVNC_status_normal";
@@ -730,7 +752,7 @@ var UI;
             if (connected) {
                 UI.setViewClip();
                 UI.setMouseButton(1);
-                $D('clipboardButton').style.display = "inline";
+                $D('clipboardButton').style.display =  (UI.consoletype !== 'kvm') ? "inline" : "none";
                 $D('showKeyboard').style.display = "inline";
                 $D('noVNC_extra_keys').style.display = "";
                 $D('sendCtrlAltDelButton').style.display = "inline";
@@ -751,18 +773,18 @@ var UI;
                 case 'fatal':
                 case 'failed':
                 case 'disconnected':
-                    $D('connectButton').style.display = "";
-                    $D('disconnectButton').style.display = "none";
+                    //$D('connectButton').style.display = "";
+                    //$D('disconnectButton').style.display = "none";
                     UI.connSettingsOpen = false;
                     UI.toggleConnectPanel();
                     break;
                 case 'loaded':
-                    $D('connectButton').style.display = "";
-                    $D('disconnectButton').style.display = "none";
+                    //$D('connectButton').style.display = "";
+                    //$D('disconnectButton').style.display = "none";
                     break;
                 default:
-                    $D('connectButton').style.display = "none";
-                    $D('disconnectButton').style.display = "";
+                    //$D('connectButton').style.display = "none";
+                    //$D('disconnectButton').style.display = "";
                     break;
             }
 
@@ -772,9 +794,9 @@ var UI;
         // Disable/enable XVP button
         updateXvpVisualState: function(ver) {
             if (ver >= 1) {
-                $D('xvpButton').style.display = 'inline';
+                //$D('xvpButton').style.display = 'inline';
             } else {
-                $D('xvpButton').style.display = 'none';
+                //$D('xvpButton').style.display = 'none';
                 // Close XVP panel if open
                 if (UI.xvpOpen === true) {
                     UI.toggleXvpPanel();
@@ -1200,7 +1222,611 @@ var UI;
 
             var vncwidth = $D('noVNC_screen').style.offsetWidth;
             $D('noVNC-control-bar').style.width = vncwidth + 'px';
-        }
+        },
+	// Proxmox VE related code
+
+ 	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) {
+
+	  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 = UI.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";
+	  }
+
+
+	},
+
+	// show msg for 5 seconds
+	pve_show_msg: function(klass, msg, permanant) {
+	  var oldklass = $D('noVNC-control-bar').getAttribute("class");
+	  $D('noVNC-control-bar').setAttribute("class", klass);
+	  var oldmsg = $D('noVNC_status').innerHTML;
+	  $D('noVNC_status').innerHTML = msg;
+	  if (typeof permanent !== 'undefined' && permanent) return;
+
+	  setTimeout(function() {
+	      var curmsg = $D('noVNC_status').innerHTML;
+	      if (curmsg === msg) {
+		  $D('noVNC_status').innerHTML = oldmsg;
+	      }
+	      var curklass = $D('noVNC-control-bar').getAttribute("class");
+	      if (curklass === klass) {
+		  $D('noVNC-control-bar').setAttribute("class", oldklass);
+	      }
+	  }, 5000);
+	},
+
+	pve_detect_migrated_vm: function() {
+	  if (!(UI.consoletype === 'kvm' || UI.consoletype === 'lxc')) {
+	      return;
+	  }
+
+	  // try to detect migrated VM
+	  UI.API2Request({
+	      url: '/cluster/resources',
+	      method: 'GET',
+	      success: function(result) {
+		  var list = result.data;
+		  list.every(function(item) {
+		      if ((item.type === 'qemu' || item.type === 'lxc') && 
+			  (item.vmid == UI.vmid)) {
+			  var url = "?" + UI.urlEncode({
+			      console: UI.consoletype,
+			      novnc: 1,
+			      vmid: UI.vmid,
+			      vmname: UI.vmname,
+			      node: item.node,
+			      resize: UI.resize
+			  });
+			  location.href = url;	
+			  return false; // break
+		      }
+		      return true;
+		  });
+	      }
+	  });
+	},
+
+	pve_vm_command: function(cmd, params, reload) {
+	  var baseUrl;
+
+	  if (UI.consoletype === 'kvm') {
+	      baseUrl = '/nodes/' + UI.nodename + '/qemu/' + UI.vmid;
+	  } else if (UI.consoletype === 'lxc') {
+	      baseUrl = '/nodes/' + UI.nodename + '/lxc/' + UI.vmid;
+	  } else {
+	      throw "unknown VM type";
+	  }
+
+	  UI.API2Request({
+	      params: params,
+	      url: baseUrl + "/status/" + cmd,
+	      method: 'POST',
+	      failure: function(msg) {
+		  UI.pve_show_msg('noVNC_status_warn', msg);
+	      },
+	      success: function() {
+		  UI.pve_show_msg('noVNC_status_normall', "VM command '" + cmd +"' successful");
+		  if (reload) {
+		      setTimeout(function() {
+			  UI.pveReload();
+		      }, 1000);
+		  };
+	      }
+	  });
+	},
+
+	pveCmdStart: function() {
+	  if (UI.pveCommandsOpen === true) {
+	      UI.togglePVECommandPanel();
+	  }
+	  UI.pve_vm_command('start', {}, true);
+	},
+
+	pveCmdShutdown: function() {
+	  if (UI.pveCommandsOpen === true) {
+	      UI.togglePVECommandPanel();
+	  }
+	  var msg = gettext("Do you really want to shutdown VM {0}?");
+	  msg = msg.replace(/\{0\}/, UI.vmid);
+
+	  if (confirm(msg) === true) { 
+	      UI.pve_vm_command('shutdown');
+	  }
+	},
+
+	pveCmdStop: function() {
+	  if (UI.pveCommandsOpen === true) {
+	      UI.togglePVECommandPanel();
+	  }
+
+	  var msg = gettext("Do you really want to stop VM {0}?");
+	  msg = msg.replace(/\{0\}/, UI.vmid);
+
+	  if (confirm(msg) === true) { 
+	      UI.pve_vm_command('stop');
+	  }
+	},
+
+	pveCmdReset: function() {
+	  if (UI.pveCommandsOpen === true) {
+	      UI.togglePVECommandPanel();
+	  }
+	  var msg = gettext("Do you really want to reset VM {0}?");
+	  msg = msg.replace(/\{0\}/, UI.vmid);
+
+	  if (confirm(msg) === true) { 
+	      UI.pve_vm_command('reset');
+	  }
+	},
+
+	pveCmdSuspend: function() {
+	  if (UI.pveCommandsOpen === true) {
+	      UI.togglePVECommandPanel();
+	  }
+	  var msg = gettext("Do you really want to suspend VM {0}?");
+	  msg = msg.replace(/\{0\}/, UI.vmid);
+
+	  if (confirm(msg) === true) { 
+	      UI.pve_vm_command('suspend');
+	  }
+	},
+
+	pveCmdResume: function() {
+	  if (UI.pveCommandsOpen === true) {
+	      UI.togglePVECommandPanel();
+	  }
+	  UI.pve_vm_command('resume');
+	},
+
+	pveCmdReload: function() {
+	  if (UI.pveCommandsOpen === true) {
+	      UI.togglePVECommandPanel();
+	  }
+	  UI.pveReload();
+	},
+
+	pveReload: function() {
+	  location.reload();
+	},
+
+	pve_send_key: function(keyname) {
+	  var baseUrl;
+
+	  if (UI.consoletype === 'kvm') {
+	      baseUrl = '/nodes/' + UI.nodename + '/qemu/' + UI.vmid;
+	  } else {
+	      throw "send key not implemented";
+	  }
+
+	  UI.API2Request({
+	      params: { key: keyname },
+	      url: baseUrl + '/sendkey',
+	      method: 'PUT',
+	      failure: function(msg) {
+		  UI.pve_show_msg('noVNC_status_warn', msg);
+	      }
+	  });
+	},
+
+	pve_start: function(callback) {
+	  UI.consoletype = WebUtil.getQueryVar('console');
+	  UI.vmid = WebUtil.getQueryVar('vmid');
+	  UI.vmname = WebUtil.getQueryVar('vmname');
+	  UI.nodename = WebUtil.getQueryVar('node');
+	  UI.resize = WebUtil.getQueryVar('resize');
+	  
+	  var url;
+	  var wsurl;
+	  var params = { websocket: 1 };
+	  var btn;
+	  
+	  // add pve command buttons
+	  var cmdpanel = $D('noVNC_pve_command_menu');
+	  var buttonlist = [
+	      {
+		  text: gettext('Start'), 
+		  handler: UI.pveCmdStart,
+		  enable: { kvm: 1, lxc: 1 }
+	      },
+	      {
+		  text: gettext('Shutdown'), 
+		  handler: UI.pveCmdShutdown,
+		  enable: { kvm: 1, lxc: 1 }
+	      },
+	      {
+		  text: gettext('Stop'),
+		  handler: UI.pveCmdStop,
+		  enable: { kvm: 1, lxc: 1 }
+	      },
+	      {
+		  text: gettext('Reset'),
+		  handler: UI.pveCmdReset,
+		  enable: { kvm: 1 }
+	      },
+	      {
+		  text: gettext('Suspend'),
+		  handler: UI.pveCmdSuspend,
+		  enable: { kvm: 1 }
+	      },
+	      {
+		  text: gettext('Resume'),
+		  handler: UI.pveCmdResume,
+		  enable: { kvm: 1 }
+	      },
+	      {
+		  text: gettext('Reload'),
+		  handler: UI.pveCmdReload,
+		  enable: { any: 1 }
+	      }
+	  ];
+	  buttonlist.forEach(function(btn) {
+	      if (btn.enable.any || btn.enable[UI.consoletype]) {
+		  var el = document.createElement('input');
+		  el.setAttribute('type', 'button');
+		  el.setAttribute('value', btn.text);
+		  el.onclick = btn.handler;
+		  el.style.display = "block";
+		  el.style.width = "100%";
+		  el.style.minWidth = "150px";
+		  cmdpanel.appendChild(el);
+	      }
+	  });
+
+	  // add sendKeys buttons
+	  var skpanel = $D('noVNC_send_keys_panel');
+
+	  buttonlist = [
+	      {
+		  text: 'Tab', handler: function() {
+		      UI.pve_send_key('tab');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-Delete', handler: function() {
+		      UI.pve_send_key('ctrl-alt-delete');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-Backspace', handler: function() {
+		      UI.pve_send_key('ctrl-alt-backspace');  
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F1', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f1');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F2', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f2');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F3', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f3');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F4', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f4');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F5', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f5');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F6', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f6');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F7', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f7');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F8', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f8');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F9', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f9');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F10', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f10');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F11', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f11');
+		  }
+	      },
+	      {
+		  text: 'Ctrl-Alt-F12', handler: function() {
+		      UI.pve_send_key('ctrl-alt-f12');
+		  }
+	      }
+	  ];
+
+	  buttonlist.forEach(function(btn) {
+	      var el = document.createElement('input');
+	      el.setAttribute('type', 'button');
+	      el.setAttribute('value', btn.text);
+	      el.onclick = function(handler) {
+		  return function() {
+		      if (UI.sendKeysVisible === true) {
+			  UI.togglePVESendKeysPanel();
+		      }
+
+		      handler.call(this);
+		  };
+	      }(btn.handler);
+	      el.style.display = "block";
+	      el.style.width = "100%";
+	      el.style.minWidth = "150px";
+	      skpanel.appendChild(el);
+	  });
+
+	  var title;
+
+	  if (UI.consoletype === 'kvm') {
+	      var baseUrl = '/nodes/' + UI.nodename + '/qemu/' + UI.vmid;
+	      url =  baseUrl + '/vncproxy';
+	      wsurl = baseUrl + '/vncwebsocket';
+	      title = "VM " + UI.vmid;
+	      if (UI.vmname) {
+		  title += " ('" + UI.vmname + "')";
+	      }
+	  } else if (UI.consoletype === 'lxc') {
+	      var baseUrl = '/nodes/' + UI.nodename + '/lxc/' + UI.vmid;
+	      url =  baseUrl + '/vncproxy';
+	      wsurl = baseUrl + '/vncwebsocket';
+	      title = "CT " + UI.vmid;
+	      if (UI.vmname) {
+		  title += " ('" + UI.vmname + "')";
+	      }
+	  } else if (UI.consoletype === 'shell') {
+	      var baseUrl = '/nodes/' + UI.nodename;
+	      url =  baseUrl + '/vncshell';
+	      wsurl = baseUrl + '/vncwebsocket';
+	      title = "node '" + UI.nodename + "'";
+	  } else if (UI.consoletype === 'upgrade') {
+	      var baseUrl = '/nodes/' + UI.nodename;
+	      url =  baseUrl + '/vncshell';
+	      wsurl = baseUrl + '/vncwebsocket';
+	      params.upgrade = 1;
+	      title = gettext('System upgrade on node {0}');
+	      title = title.replace(/\{0\}/, UI.nodename);
+	  } else {
+	      throw "implement me";
+	  }
+
+	  document.title = title;
+
+	  var start_vnc_viewer = function(param) {
+	      var wsparams = UI.urlEncode({
+		  port: param.port,
+		  vncticket: param.ticket
+	      });
+
+	      UI.updateSetting('host', window.location.hostname);
+	      UI.updateSetting('port', window.location.port || 443);
+	      UI.updateSetting('password', param.ticket);
+	      UI.updateSetting('encrypt', true);
+	      UI.updateSetting('true_color', true);
+	      UI.updateSetting('cursor', !UI.isTouchDevice);
+	      UI.updateSetting('shared', true);
+	      UI.updateSetting('view_only', false);
+	      UI.updateSetting('resize', UI.resize);
+
+	      UI.updateSetting('path', 'api2/json' + wsurl + "?" + wsparams);
+
+	      UI.start(callback);
+	  };
+
+	  UI.API2Request({
+	      url: url,
+	      method: 'POST',
+	      params: params,
+	      success: function(result) {
+		  start_vnc_viewer(result.data);
+	      },
+	      failure: function(msg) {
+		  UI.pve_show_msg('noVNC_status_error', msg, 1);
+	      }
+	  });
+	},
+
+	lastFBWidth: undefined,
+	lastFBHeight: undefined,
+	sizeUpdateTimer: undefined,
+
+	updateFBSize: function(rfb, width, height) {
+	    try {
+		// Note1: CSS Canvas size is wrong by a few pixels in Chrome
+		// Note2: window size must be even number for firefox
+		UI.lastFBWidth = Math.floor((width + 1)/2)*2;;
+		UI.lastFBHeight = Math.floor((height + 1)/2)*2;
+
+		if (UI.sizeUpdateTimer !== undefined) {
+		    clearInterval(UI.sizeUpdateTimer);
+		}
+		if (UI.getSetting('clip')) return;
+
+		var update_size = 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";
+		    }
+		
+		    // see base.css/noVNC_screen_pad
+		    var toolbar_height = 36;
+
+		    var offsetw = UI.lastFBWidth - ow;
+		    var offseth = UI.lastFBHeight + toolbar_height - oh;
+		    if (offsetw !== 0 || offseth !== 0) {
+			//console.log("try resize by " + offsetw + " " + offseth);
+			window.resizeBy(offsetw, offseth);
+		    }
+		};
+
+		update_size();
+		UI.sizeUpdateTimer = setInterval(update_size, 1000);
+
+	    } catch(e) {
+		console.log(e);
+	    }
+	},
+	// Open/close PVE commandand menu
+	togglePVECommandPanel: function() {
+	  // Close the description panel
+	  $D('noVNC_description').style.display = "none";
+	  if (UI.sendKeysVisible === true) {
+	      UI.togglePVESendKeysPanel();
+	  }
+	  // Close clipboard panel if open
+	  if (UI.clipboardOpen === true) {
+	      UI.toggleClipboardPanel();
+	  }
+	  // Close connection settings if open
+	  if (UI.connSettingsOpen === true) {
+	      UI.toggleConnectPanel();
+	  }
+	  // Close popup status panel if open
+	  if (UI.popupStatusOpen === true) {
+	      UI.togglePopupStatusPanel();
+	  }
+	  // Close XVP panel if open
+	  if (UI.xvpOpen === true) {
+	      UI.toggleXvpPanel();
+	  }
+	  if (UI.pveCommandsOpen) {
+	      $D('noVNC_pve_commands').style.display = "none";
+	      $D('pveCommandsButton').className = "noVNC_status_button";
+	      UI.pveCommandsOpen = false;
+	  } else {
+	      $D('noVNC_pve_commands').style.display = "block";
+	      $D('pveCommandsButton').className = "noVNC_status_button_selected";
+	      UI.pveCommandsOpen = true;
+	  }
+	},
+
+	// Open/close PVE SendKeys menu
+	togglePVESendKeysPanel: function() {
+	  // Close the description panel
+	  $D('noVNC_description').style.display = "none";
+	  if (UI.pveCommandsOpen === true) {
+	      UI.togglePVECommandPanel();
+	  }
+	  // Close clipboard panel if open
+	  if (UI.clipboardOpen === true) {
+	      UI.toggleClipboardPanel();
+	  }
+	  // Close connection settings if open
+	  if (UI.connSettingsOpen === true) {
+	      UI.toggleConnectPanel();
+	  }
+	  // Close popup status panel if open
+	  if (UI.popupStatusOpen === true) {
+	      UI.togglePopupStatusPanel();
+	  }
+	  // Close XVP panel if open
+	  if (UI.xvpOpen === true) {
+	      UI.toggleXvpPanel();
+	  }
+	  if (UI.sendKeysVisible) {
+	      $D('noVNC_send_keys').style.display = "none";
+	      $D('showSendKeysButton').className = "noVNC_status_button";
+	      UI.sendKeysVisible = false;
+	  } else {
+	      $D('noVNC_send_keys').style.display = "block";
+	      $D('showSendKeysButton').className = "noVNC_status_button_selected";
+	      UI.sendKeysVisible = true;
+	  }
+	}
+
 
     };
 })();
-- 
2.1.4
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin