mirror of
https://github.com/novnc/noVNC.git
synced 2026-05-27 15:39:41 +00:00
Another firefox issue is that height: 100% is calculated as 100% of the containing element even when the containing element is the window. This means that the size of any sibling element shifts the window size down by that much and causes the vertical scroll bars to appear. This doesn't happen in Chrome. - So instead, put a pad element inside the noVNC_screen element that is the size of the control bar. This is hidden by the control bar, however, it causes things to be sized correctly. - Also, rename noVNC_defaultScreen to noVNC_logo. - Clean some style specification out of the HTML.
531 lines
15 KiB
JavaScript
531 lines
15 KiB
JavaScript
/*
|
|
* noVNC: HTML5 VNC client
|
|
* Copyright (C) 2011 Joel Martin
|
|
* Licensed under LGPL-3 (see LICENSE.txt)
|
|
*
|
|
* See README.md for usage and integration instructions.
|
|
*/
|
|
|
|
"use strict";
|
|
/*jslint white: false, browser: true */
|
|
/*global window, $D, Util, WebUtil, RFB, Display */
|
|
|
|
var UI = {
|
|
|
|
settingsOpen : false,
|
|
connSettingsOpen : true,
|
|
clipboardOpen: false,
|
|
|
|
// Render default UI and initialize settings menu
|
|
load: function() {
|
|
var html = '', i, sheet, sheets, llevels;
|
|
|
|
// Stylesheet selection dropdown
|
|
sheet = WebUtil.selectStylesheet();
|
|
sheets = WebUtil.getStylesheets();
|
|
for (i = 0; i < sheets.length; i += 1) {
|
|
UI.addOption($D('noVNC_stylesheet'),sheets[i].title, sheets[i].title);
|
|
}
|
|
|
|
// Logging selection dropdown
|
|
llevels = ['error', 'warn', 'info', 'debug'];
|
|
for (i = 0; i < llevels.length; i += 1) {
|
|
UI.addOption($D('noVNC_logging'),llevels[i], llevels[i]);
|
|
}
|
|
|
|
// Settings with immediate effects
|
|
UI.initSetting('logging', 'warn');
|
|
WebUtil.init_logging(UI.getSetting('logging'));
|
|
UI.initSetting('stylesheet', 'default');
|
|
|
|
WebUtil.selectStylesheet(null);
|
|
// call twice to get around webkit bug
|
|
WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
|
|
|
|
/* Populate the controls if defaults are provided in the URL */
|
|
UI.initSetting('host', '');
|
|
UI.initSetting('port', '');
|
|
UI.initSetting('password', '');
|
|
UI.initSetting('encrypt', false);
|
|
UI.initSetting('true_color', true);
|
|
UI.initSetting('cursor', false);
|
|
UI.initSetting('shared', true);
|
|
UI.initSetting('connectTimeout', 2);
|
|
|
|
UI.rfb = RFB({'target': $D('noVNC_canvas'),
|
|
'onUpdateState': UI.updateState,
|
|
'onClipboard': UI.clipReceive});
|
|
|
|
// Unfocus clipboard when over the VNC area
|
|
//$D('VNC_screen').onmousemove = function () {
|
|
// var keyboard = UI.rfb.get_keyboard();
|
|
// if ((! keyboard) || (! keyboard.get_focused())) {
|
|
// $D('VNC_clipboard_text').blur();
|
|
// }
|
|
// };
|
|
|
|
// Show mouse selector buttons on touch screen devices
|
|
if ('ontouchstart' in document.documentElement) {
|
|
$D('noVNC_mobile_buttons').style.display = "inline";
|
|
UI.setMouseButton();
|
|
window.scrollTo(0, 1);
|
|
}
|
|
|
|
//iOS Safari does not support CSS position:fixed.
|
|
//This detects iOS devices and enables javascript workaround.
|
|
if ((navigator.userAgent.match(/iPhone/i)) ||
|
|
(navigator.userAgent.match(/iPod/i)) ||
|
|
(navigator.userAgent.match(/iPad/i))) {
|
|
UI.setOnscroll();
|
|
UI.setResize();
|
|
}
|
|
|
|
$D('noVNC_host').focus();
|
|
},
|
|
|
|
// Read form control compatible setting from cookie
|
|
getSetting: function(name) {
|
|
var val, ctrl = $D('noVNC_' + name);
|
|
val = WebUtil.readCookie(name);
|
|
if (ctrl.type === 'checkbox') {
|
|
if (val.toLowerCase() in {'0':1, 'no':1, 'false':1}) {
|
|
val = false;
|
|
} else {
|
|
val = true;
|
|
}
|
|
}
|
|
return val;
|
|
},
|
|
|
|
// Update cookie and form control setting. If value is not set, then
|
|
// updates from control to current cookie setting.
|
|
updateSetting: function(name, value) {
|
|
|
|
var i, ctrl = $D('noVNC_' + name);
|
|
// Save the cookie for this session
|
|
if (typeof value !== 'undefined') {
|
|
WebUtil.createCookie(name, value);
|
|
}
|
|
|
|
// Update the settings control
|
|
value = UI.getSetting(name);
|
|
|
|
if (ctrl.type === 'checkbox') {
|
|
ctrl.checked = value;
|
|
|
|
} else if (typeof ctrl.options !== 'undefined') {
|
|
for (i = 0; i < ctrl.options.length; i += 1) {
|
|
if (ctrl.options[i].value === value) {
|
|
ctrl.selectedIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
/*Weird IE9 error leads to 'null' appearring
|
|
in textboxes instead of ''.*/
|
|
if (value === null) {
|
|
value = "";
|
|
}
|
|
ctrl.value = value;
|
|
}
|
|
},
|
|
|
|
// Save control setting to cookie
|
|
saveSetting: function(name) {
|
|
var val, ctrl = $D('noVNC_' + name);
|
|
if (ctrl.type === 'checkbox') {
|
|
val = ctrl.checked;
|
|
} else if (typeof ctrl.options !== 'undefined') {
|
|
val = ctrl.options[ctrl.selectedIndex].value;
|
|
} else {
|
|
val = ctrl.value;
|
|
}
|
|
WebUtil.createCookie(name, val);
|
|
//Util.Debug("Setting saved '" + name + "=" + val + "'");
|
|
return val;
|
|
},
|
|
|
|
// Initial page load read/initialization of settings
|
|
initSetting: function(name, defVal) {
|
|
var val;
|
|
|
|
// Check Query string followed by cookie
|
|
val = WebUtil.getQueryVar(name);
|
|
if (val === null) {
|
|
val = WebUtil.readCookie(name, defVal);
|
|
}
|
|
UI.updateSetting(name, val);
|
|
//Util.Debug("Setting '" + name + "' initialized to '" + val + "'");
|
|
return val;
|
|
},
|
|
|
|
|
|
// Toggle the settings menu:
|
|
// On open, settings are refreshed from saved cookies.
|
|
// On close, settings are applied
|
|
clickSettingsMenu: function() {
|
|
if (UI.settingsOpen) {
|
|
UI.settingsApply();
|
|
|
|
UI.closeSettingsMenu();
|
|
} else {
|
|
UI.updateSetting('encrypt');
|
|
UI.updateSetting('true_color');
|
|
if (UI.rfb.get_display().get_cursor_uri()) {
|
|
UI.updateSetting('cursor');
|
|
} else {
|
|
UI.updateSetting('cursor', false);
|
|
$D('noVNC_cursor').disabled = true;
|
|
}
|
|
UI.updateSetting('shared');
|
|
UI.updateSetting('connectTimeout');
|
|
UI.updateSetting('stylesheet');
|
|
UI.updateSetting('logging');
|
|
|
|
UI.openSettingsMenu();
|
|
}
|
|
},
|
|
|
|
// Open menu
|
|
openSettingsMenu: function() {
|
|
if (UI.clipboardOpen == true) {
|
|
UI.showClipboard();
|
|
}
|
|
//Close connection settings if open
|
|
if (UI.connSettingsOpen == true) {
|
|
UI.connectPanelbutton();
|
|
}
|
|
$D('noVNC_Settings').style.display = "block";
|
|
UI.settingsOpen = true;
|
|
},
|
|
|
|
// Close menu (without applying settings)
|
|
closeSettingsMenu: function() {
|
|
$D('noVNC_Settings').style.display = "none";
|
|
UI.settingsOpen = false;
|
|
},
|
|
|
|
// Disable/enable controls depending on connection state
|
|
settingsDisabled: function(disabled, rfb) {
|
|
//Util.Debug(">> settingsDisabled");
|
|
$D('noVNC_encrypt').disabled = disabled;
|
|
$D('noVNC_true_color').disabled = disabled;
|
|
if (rfb && rfb.get_display() && rfb.get_display().get_cursor_uri()) {
|
|
$D('noVNC_cursor').disabled = disabled;
|
|
} else {
|
|
UI.updateSetting('cursor', false);
|
|
$D('noVNC_cursor').disabled = true;
|
|
}
|
|
$D('noVNC_shared').disabled = disabled;
|
|
$D('noVNC_connectTimeout').disabled = disabled;
|
|
//Util.Debug("<< settingsDisabled");
|
|
},
|
|
|
|
// Save/apply settings when 'Apply' button is pressed
|
|
settingsApply: function() {
|
|
//Util.Debug(">> settingsApply");
|
|
UI.saveSetting('encrypt');
|
|
UI.saveSetting('true_color');
|
|
if (UI.rfb.get_display().get_cursor_uri()) {
|
|
UI.saveSetting('cursor');
|
|
}
|
|
UI.saveSetting('shared');
|
|
UI.saveSetting('connectTimeout');
|
|
UI.saveSetting('stylesheet');
|
|
UI.saveSetting('logging');
|
|
|
|
// Settings with immediate (non-connected related) effect
|
|
WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
|
|
WebUtil.init_logging(UI.getSetting('logging'));
|
|
//Util.Debug("<< settingsApply");
|
|
},
|
|
|
|
|
|
|
|
setPassword: function() {
|
|
UI.rfb.sendPassword($D('noVNC_password').value);
|
|
//Reset connect button.
|
|
$D('noVNC_connect_button').value = "Connect";
|
|
$D('noVNC_connect_button').onclick = UI.Connect;
|
|
//Hide connection panel.
|
|
UI.connectPanelbutton();
|
|
return false;
|
|
},
|
|
|
|
sendCtrlAltDel: function() {
|
|
UI.rfb.sendCtrlAltDel();
|
|
},
|
|
|
|
setMouseButton: function(num) {
|
|
var b, blist = [1,2,4], button,
|
|
mouse = UI.rfb.get_mouse();
|
|
|
|
if (typeof num === 'undefined') {
|
|
// Show the default
|
|
num = mouse.get_touchButton();
|
|
} else if (num === mouse.get_touchButton()) {
|
|
// Set all buttons off (no clicks)
|
|
mouse.set_touchButton(0);
|
|
num = 0;
|
|
} else {
|
|
// Turn on one button
|
|
mouse.set_touchButton(num);
|
|
}
|
|
|
|
for (b = 0; b < blist.length; b++) {
|
|
button = $D('noVNC_mouse_button' + blist[b]);
|
|
if (blist[b] === num) {
|
|
button.style.backgroundColor = "black";
|
|
button.style.color = "lightgray";
|
|
} else {
|
|
button.style.backgroundColor = "";
|
|
button.style.color = "";
|
|
}
|
|
}
|
|
},
|
|
|
|
updateState: function(rfb, state, oldstate, msg) {
|
|
var s, sb, c, cad, klass;
|
|
s = $D('noVNC_status');
|
|
sb = $D('noVNC_status_bar');
|
|
c = $D('connectPanelbutton');
|
|
cad = $D('sendCtrlAltDelButton');
|
|
switch (state) {
|
|
case 'failed':
|
|
case 'fatal':
|
|
c.disabled = true;
|
|
cad.style.display = "none";
|
|
UI.settingsDisabled(true, rfb);
|
|
klass = "noVNC_status_error";
|
|
break;
|
|
case 'normal':
|
|
c.value = "Disconnect";
|
|
c.onclick = UI.disconnect;
|
|
c.disabled = false;
|
|
cad.style.display = "block";
|
|
UI.settingsDisabled(true, rfb);
|
|
klass = "noVNC_status_normal";
|
|
break;
|
|
case 'disconnected':
|
|
$D('noVNC_logo').style.display = "block";
|
|
c.value = "Connection";
|
|
c.onclick = UI.connectPanelbutton;
|
|
case 'loaded':
|
|
c.value = "Connection";
|
|
c.onclick = UI.connectPanelbutton;
|
|
c.disabled = false;
|
|
cad.style.display = "none";
|
|
UI.settingsDisabled(false, rfb);
|
|
klass = "noVNC_status_normal";
|
|
break;
|
|
case 'password':
|
|
UI.connectPanelbutton();
|
|
|
|
$D('noVNC_connect_button').value = "Send Password";
|
|
$D('noVNC_connect_button').onclick = UI.setPassword;
|
|
$D('noVNC_password').focus();
|
|
|
|
c.disabled = false;
|
|
cad.style.display = "none";
|
|
UI.settingsDisabled(true, rfb);
|
|
klass = "noVNC_status_warn";
|
|
break;
|
|
default:
|
|
c.disabled = true;
|
|
cad.style.display = "none";
|
|
UI.settingsDisabled(true, rfb);
|
|
klass = "noVNC_status_warn";
|
|
break;
|
|
}
|
|
|
|
if (typeof(msg) !== 'undefined') {
|
|
s.setAttribute("class", klass);
|
|
sb.setAttribute("class", klass);
|
|
s.innerHTML = msg;
|
|
}
|
|
|
|
},
|
|
|
|
clipReceive: function(rfb, text) {
|
|
Util.Debug(">> UI.clipReceive: " + text.substr(0,40) + "...");
|
|
$D('noVNC_clipboard_text').value = text;
|
|
Util.Debug("<< UI.clipReceive");
|
|
},
|
|
|
|
|
|
connect: function() {
|
|
var host, port, password;
|
|
|
|
UI.closeSettingsMenu();
|
|
UI.connectPanelbutton();
|
|
|
|
host = $D('noVNC_host').value;
|
|
port = $D('noVNC_port').value;
|
|
password = $D('noVNC_password').value;
|
|
if ((!host) || (!port)) {
|
|
throw("Must set host and port");
|
|
}
|
|
|
|
UI.rfb.set_encrypt(UI.getSetting('encrypt'));
|
|
UI.rfb.set_true_color(UI.getSetting('true_color'));
|
|
UI.rfb.set_local_cursor(UI.getSetting('cursor'));
|
|
UI.rfb.set_shared(UI.getSetting('shared'));
|
|
UI.rfb.set_connectTimeout(UI.getSetting('connectTimeout'));
|
|
|
|
UI.rfb.connect(host, port, password);
|
|
//Close dialog.
|
|
setTimeout(UI.setBarPosition, 100);
|
|
$D('noVNC_logo').style.display = "none";
|
|
},
|
|
|
|
disconnect: function() {
|
|
UI.closeSettingsMenu();
|
|
UI.rfb.disconnect();
|
|
|
|
$D('noVNC_logo').style.display = "block";
|
|
UI.connSettingsOpen = false;
|
|
UI.connectPanelbutton();
|
|
},
|
|
|
|
displayBlur: function() {
|
|
UI.rfb.get_keyboard().set_focused(false);
|
|
UI.rfb.get_mouse().set_focused(false);
|
|
},
|
|
|
|
displayFocus: function() {
|
|
UI.rfb.get_keyboard().set_focused(true);
|
|
UI.rfb.get_mouse().set_focused(true);
|
|
},
|
|
|
|
clipClear: function() {
|
|
$D('noVNC_clipboard_text').value = "";
|
|
UI.rfb.clipboardPasteFrom("");
|
|
},
|
|
|
|
clipSend: function() {
|
|
var text = $D('noVNC_clipboard_text').value;
|
|
Util.Debug(">> UI.clipSend: " + text.substr(0,40) + "...");
|
|
UI.rfb.clipboardPasteFrom(text);
|
|
Util.Debug("<< UI.clipSend");
|
|
},
|
|
|
|
showClipboard: function() {
|
|
//Close settings if open
|
|
if (UI.settingsOpen == true) {
|
|
UI.closeSettingsMenu();
|
|
}
|
|
//Close connection settings if open
|
|
if (UI.connSettingsOpen == true) {
|
|
UI.connectPanelbutton();
|
|
}
|
|
//Toggle Connection Panel
|
|
if (UI.clipboardOpen == true) {
|
|
$D('noVNC_clipboard').style.display = "none";
|
|
UI.clipboardOpen = false;
|
|
} else {
|
|
$D('noVNC_clipboard').style.display = "block";
|
|
UI.clipboardOpen = true;
|
|
}
|
|
},
|
|
|
|
|
|
showKeyboard: function() {
|
|
//Get Current Scroll Position
|
|
var scrollx =
|
|
(document.all)?document.body.scrollLeft:window.pageXOffset;
|
|
var scrolly =
|
|
(document.all)?document.body.scrollTop:window.pageYOffset;
|
|
|
|
//Stop browser zooming on textbox.
|
|
UI.zoomDisable();
|
|
$D('keyboardinput').focus();
|
|
scroll(scrollx,scrolly);
|
|
//Renable user zoom.
|
|
UI.zoomEnable();
|
|
},
|
|
|
|
zoomDisable: function() {
|
|
//Change viewport meta data to disable zooming.
|
|
UI.changeViewportMeta("user-scalable=0");
|
|
},
|
|
|
|
zoomEnable: function(){
|
|
//Change viewport meta data to enable user zooming.
|
|
UI.changeViewportMeta("user-scalable=1");
|
|
},
|
|
|
|
changeViewportMeta: function (newattributes) {
|
|
|
|
// First, get the array of meta-tag elements
|
|
var metatags = document.getElementsByTagName("meta");
|
|
|
|
// Update only the Viewport meta tag
|
|
for (var cnt = 0; cnt < metatags.length; cnt++)
|
|
{
|
|
var name = metatags[cnt].getAttribute("name");
|
|
var content = metatags[cnt].getAttribute("content");
|
|
|
|
// Update the Viewport meta tag
|
|
if (metatags[cnt].getAttribute("name") == "viewport") {
|
|
metatags[cnt].setAttribute("content", newattributes);
|
|
}
|
|
}
|
|
},
|
|
|
|
//iOS < Version 5 does not support position fixed. Javascript workaround:
|
|
setOnscroll: function() {
|
|
window.onscroll = function() {
|
|
UI.setBarPosition();
|
|
};
|
|
},
|
|
|
|
setResize: function () {
|
|
window.onResize = function() {
|
|
UI.setBarPosition();
|
|
};
|
|
},
|
|
|
|
//Helper to add options to dropdown.
|
|
addOption: function(selectbox,text,value )
|
|
{
|
|
var optn = document.createElement("OPTION");
|
|
optn.text = text;
|
|
optn.value = value;
|
|
selectbox.options.add(optn);
|
|
},
|
|
|
|
setBarPosition: function() {
|
|
$D('noVNC-control-bar').style.top = (window.pageYOffset) + 'px';
|
|
$D('noVNC_mobile_buttons').style.left = (window.pageXOffset) + 'px';
|
|
$D('noVNC_buttons_right').style.right = 0 + 'px';
|
|
|
|
var vncwidth = $D('noVNC_screen').style.offsetWidth;
|
|
$D('noVNC-control-bar').style.width = vncwidth + 'px';
|
|
},
|
|
|
|
connectPanelbutton: function() {
|
|
//Close connection settings if open
|
|
if (UI.settingsOpen == true) {
|
|
UI.closeSettingsMenu();
|
|
}
|
|
if (UI.clipboardOpen == true) {
|
|
UI.showClipboard();
|
|
}
|
|
|
|
//Toggle Connection Panel
|
|
if (UI.connSettingsOpen == true) {
|
|
$D('noVNC_controls').style.display = "none";
|
|
UI.connSettingsOpen = false;
|
|
} else {
|
|
$D('noVNC_controls').style.display = "block";
|
|
UI.connSettingsOpen = true;
|
|
$D('noVNC_host').focus();
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|