/* jslint white: false, browser: true */
/* global window, document.getElementById, Util, WebUtil, RFB, Display */
-/* [module]
- * import Util from "../core/util";
- * import KeyTable from "../core/input/keysym";
- * import RFB from "../core/rfb";
- * import Display from "../core/display";
- * import WebUtil from "./webutil";
- */
+import Util from "../core/util.js";
+import KeyTable from "../core/input/keysym.js";
+import keysyms from "../core/input/keysymdef.js";
+import RFB from "../core/rfb.js";
+import Display from "../core/display.js";
+import WebUtil from "./webutil.js";
var UI;
(function () {
"use strict";
- /* [begin skip-as-module] */
- // Load supporting scripts
- WebUtil.load_scripts(
- {'core': ["base64.js", "websock.js", "des.js", "input/keysymdef.js",
- "input/xtscancodes.js", "input/util.js", "input/devices.js",
- "display.js", "inflator.js", "rfb.js", "input/keysym.js"]});
+ // Fallback for all uncought errors
+ window.addEventListener('error', function(event) {
+ try {
+ var msg, div, text;
+
+ msg = document.getElementById('noVNC_fallback_errormsg');
+
+ // Only show the initial error
+ if (msg.hasChildNodes()) {
+ return false;
+ }
+
+ div = document.createElement("div");
+ div.appendChild(document.createTextNode(event.message));
+ msg.appendChild(div);
+
+ div = document.createElement("div");
+ div.className = 'noVNC_location';
+ text = event.filename + ":" + event.lineno + ":" + event.colno;
+ div.appendChild(document.createTextNode(text));
+ msg.appendChild(div);
+
+ if ((event.error !== undefined) &&
+ (event.error.stack !== undefined)) {
+ div = document.createElement("div");
+ div.className = 'noVNC_stack';
+ div.appendChild(document.createTextNode(event.error.stack));
+ msg.appendChild(div);
+ }
- window.onscriptsload = function () { UI.load(); };
- /* [end skip-as-module] */
+ document.getElementById('noVNC_fallback_error')
+ .classList.add("noVNC_open");
+ } catch (exc) {
+ document.write("noVNC encountered an error.");
+ }
+ // Don't return true since this would prevent the error
+ // from being printed to the browser console.
+ return false;
+ });
+
+ // Set up translations
+ var LINGUAS = ["de", "el", "nl", "sv"];
+ Util.Localisation.setup(LINGUAS);
+ if (Util.Localisation.language !== "en") {
+ WebUtil.load_scripts(
+ {'app': ["locale/" + Util.Localisation.language + ".js"]});
+ }
+
+ var _ = Util.Localisation.get;
UI = {
controlbarDrag: false,
controlbarMouseDownClientY: 0,
controlbarMouseDownOffsetY: 0,
- keyboardVisible: false,
- isTouchDevice: false,
isSafari: false,
rememberedClipSetting: null,
lastKeyboardinput: null,
defaultKeyboardinputLen: 100,
+ inhibit_reconnect: true,
+ reconnect_callback: null,
+ reconnect_password: null,
+
// Setup rfb object, load settings from browser storage, then call
// UI.init to setup the UI/menus
load: function(callback) {
start: function(callback) {
// Setup global variables first
- UI.isTouchDevice = 'ontouchstart' in document.documentElement;
UI.isSafari = (navigator.userAgent.indexOf('Safari') !== -1 &&
navigator.userAgent.indexOf('Chrome') === -1);
UI.initSettings();
+ // Translate the DOM
+ Util.Localisation.translateDOM();
+
// Adapt the interface for touch screen devices
- if (UI.isTouchDevice) {
+ if (Util.isTouchDevice) {
document.documentElement.classList.add("noVNC_touch");
// Remove the address bar
setTimeout(function() { window.scrollTo(0, 1); }, 100);
- UI.forceSetting('clip', true);
- } else {
- UI.initSetting('clip', false);
}
- // Setup and initialize event handlers
- UI.setupWindowEvents();
- UI.setupFullscreen();
+ // Restore control bar position
+ if (WebUtil.readSetting('controlbar_pos') === 'right') {
+ UI.toggleControlbarSide();
+ }
+
+ UI.initFullscreen();
+
+ // Setup event handlers
+ UI.addResizeHandlers();
UI.addControlbarHandlers();
UI.addTouchSpecificHandlers();
UI.addExtraKeysHandlers();
UI.addConnectionControlHandlers();
UI.addClipboardHandlers();
UI.addSettingsHandlers();
+ document.getElementById("noVNC_status")
+ .addEventListener('click', UI.hideStatus);
+
+ UI.openControlbar();
// Show the connect panel on first load unless autoconnecting
if (!autoconnect) {
}
},
+ initFullscreen: function() {
+ // Only show the button if fullscreen is properly supported
+ // * Safari doesn't support alphanumerical input while in fullscreen
+ if (!UI.isSafari &&
+ (document.documentElement.requestFullscreen ||
+ document.documentElement.mozRequestFullScreen ||
+ document.documentElement.webkitRequestFullscreen ||
+ document.body.msRequestFullscreen)) {
+ document.getElementById('noVNC_fullscreen_button')
+ .classList.remove("noVNC_hidden");
+ UI.addFullscreenHandlers();
+ }
+ },
+
initSettings: function() {
- // Stylesheet selection dropdown
- var sheet = WebUtil.selectStylesheet();
- var sheets = WebUtil.getStylesheets();
var i;
- for (i = 0; i < sheets.length; i += 1) {
- UI.addOption(document.getElementById('noVNC_setting_stylesheet'),sheets[i].title, sheets[i].title);
- }
// Logging selection dropdown
var llevels = ['error', 'warn', 'info', 'debug'];
// 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'));
+ UI.updateLogging();
// if port == 80 (or 443) then it won't be present and should be
// set manually
/* 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('cursor', !Util.isTouchDevice);
+ UI.initSetting('clip', false);
UI.initSetting('resize', 'off');
UI.initSetting('shared', true);
UI.initSetting('view_only', false);
UI.initSetting('path', 'websockify');
UI.initSetting('repeaterID', '');
- UI.initSetting('token', '');
- },
+ UI.initSetting('reconnect', false);
+ UI.initSetting('reconnect_delay', 5000);
- setupWindowEvents: function() {
- window.addEventListener( 'resize', function () {
- UI.applyResizeMode();
- UI.updateViewClip();
- UI.updateViewDrag();
- } );
+ UI.setupSettingLabels();
+ },
- document.getElementById("noVNC_status")
- .addEventListener('click', UI.hideStatus);
+ // Adds a link to the label elements on the corresponding input elements
+ setupSettingLabels: function() {
+ var labels = document.getElementsByTagName('LABEL');
+ for (var i = 0; i < labels.length; i++) {
+ var htmlFor = labels[i].htmlFor;
+ if (htmlFor != '') {
+ var elem = document.getElementById(htmlFor);
+ if (elem) elem.label = labels[i];
+ } else {
+ // If 'for' isn't set, use the first input element child
+ var children = labels[i].children;
+ for (var j = 0; j < children.length; j++) {
+ if (children[j].form !== undefined) {
+ children[j].label = labels[i];
+ break;
+ }
+ }
+ }
+ }
},
- setupFullscreen: function() {
- // Only show the button if fullscreen is properly supported
- // * Safari doesn't support alphanumerical input while in fullscreen
- if (!UI.isSafari &&
- (document.documentElement.requestFullscreen ||
- document.documentElement.mozRequestFullScreen ||
- document.documentElement.webkitRequestFullscreen ||
- document.body.msRequestFullscreen)) {
- document.getElementById('noVNC_fullscreen_button')
- .classList.remove("noVNC_hidden");
- UI.addFullscreenHandlers();
+ initRFB: function() {
+ try {
+ UI.rfb = new RFB({'target': document.getElementById('noVNC_canvas'),
+ 'onNotification': UI.notification,
+ 'onUpdateState': UI.updateState,
+ 'onDisconnected': UI.disconnectFinished,
+ 'onPasswordRequired': UI.passwordRequired,
+ 'onXvpInit': UI.updateXvpButton,
+ 'onClipboard': UI.clipboardReceive,
+ 'onBell': UI.bell,
+ 'onFBUComplete': UI.initialResize,
+ 'onFBResize': UI.updateSessionSize,
+ 'onDesktopName': UI.updateDesktopName});
+ return true;
+ } catch (exc) {
+ var msg = "Unable to create RFB client -- " + exc;
+ Util.Error(msg);
+ UI.showStatus(msg, 'error');
+ return false;
}
},
+/* ------^-------
+ * /INIT
+ * ==============
+ * EVENT HANDLERS
+ * ------v------*/
+
+ addResizeHandlers: function() {
+ window.addEventListener('resize', UI.applyResizeMode);
+ window.addEventListener('resize', UI.updateViewClip);
+ },
+
addControlbarHandlers: function() {
document.getElementById("noVNC_control_bar")
.addEventListener('mousemove', UI.activateControlbar);
.addEventListener('mousemove', UI.dragControlbarHandle);
// resize events aren't available for elements
window.addEventListener('resize', UI.updateControlbarHandle);
+
+ var exps = document.getElementsByClassName("noVNC_expander");
+ for (var i = 0;i < exps.length;i++) {
+ exps[i].addEventListener('click', UI.toggleExpander);
+ }
},
addTouchSpecificHandlers: function() {
document.getElementById("noVNC_keyboardinput")
.addEventListener('input', UI.keyInput);
+ document.getElementById("noVNC_keyboardinput")
+ .addEventListener('focus', UI.onfocusVirtualKeyboard);
document.getElementById("noVNC_keyboardinput")
.addEventListener('blur', UI.onblurVirtualKeyboard);
document.getElementById("noVNC_keyboardinput")
.addEventListener('submit', function () { return false; });
+ document.documentElement
+ .addEventListener('mousedown', UI.keepVirtualKeyboard, true);
+
document.getElementById("noVNC_control_bar")
.addEventListener('touchstart', UI.activateControlbar);
document.getElementById("noVNC_control_bar")
},
addConnectionControlHandlers: function() {
- document.getElementById("noVNC_connect_controls_button")
- .addEventListener('click', UI.toggleConnectPanel);
document.getElementById("noVNC_disconnect_button")
.addEventListener('click', UI.disconnect);
document.getElementById("noVNC_connect_button")
.addEventListener('click', UI.connect);
+ document.getElementById("noVNC_cancel_reconnect_button")
+ .addEventListener('click', UI.cancelReconnect);
document.getElementById("noVNC_password_button")
.addEventListener('click', UI.setPassword);
.addEventListener('click', UI.clipboardClear);
},
+ // Add a call to save settings when the element changes,
+ // unless the optional parameter changeFunc is used instead.
+ addSettingChangeHandler: function(name, changeFunc) {
+ var settingElem = document.getElementById("noVNC_setting_" + name);
+ if (changeFunc === undefined) {
+ changeFunc = function () { UI.saveSetting(name); };
+ }
+ settingElem.addEventListener('change', changeFunc);
+ },
+
addSettingsHandlers: function() {
document.getElementById("noVNC_settings_button")
.addEventListener('click', UI.toggleSettingsPanel);
- document.getElementById("noVNC_settings_apply")
- .addEventListener('click', UI.settingsApply);
- document.getElementById("noVNC_setting_resize")
- .addEventListener('change', UI.enableDisableViewClip);
+ UI.addSettingChangeHandler('encrypt');
+ UI.addSettingChangeHandler('true_color');
+ UI.addSettingChangeHandler('cursor');
+ UI.addSettingChangeHandler('cursor', UI.updateLocalCursor);
+ UI.addSettingChangeHandler('resize');
+ UI.addSettingChangeHandler('resize', UI.enableDisableViewClip);
+ UI.addSettingChangeHandler('resize', UI.applyResizeMode);
+ UI.addSettingChangeHandler('clip');
+ UI.addSettingChangeHandler('clip', UI.updateViewClip);
+ UI.addSettingChangeHandler('shared');
+ UI.addSettingChangeHandler('view_only');
+ UI.addSettingChangeHandler('view_only', UI.updateViewOnly);
+ UI.addSettingChangeHandler('host');
+ UI.addSettingChangeHandler('port');
+ UI.addSettingChangeHandler('path');
+ UI.addSettingChangeHandler('repeaterID');
+ UI.addSettingChangeHandler('logging');
+ UI.addSettingChangeHandler('logging', UI.updateLogging);
+ UI.addSettingChangeHandler('reconnect');
+ UI.addSettingChangeHandler('reconnect_delay');
},
addFullscreenHandlers: function() {
window.addEventListener('msfullscreenchange', UI.updateFullscreenButton);
},
- initRFB: function() {
- try {
- UI.rfb = new RFB({'target': document.getElementById('noVNC_canvas'),
- 'onNotification': UI.notification,
- 'onUpdateState': UI.updateState,
- 'onDisconnected': UI.disconnectFinished,
- 'onPasswordRequired': UI.passwordRequired,
- 'onXvpInit': UI.updateXvpButton,
- 'onClipboard': UI.clipboardReceive,
- 'onBell': UI.bell,
- 'onFBUComplete': UI.initialResize,
- 'onFBResize': UI.updateViewDrag,
- 'onDesktopName': UI.updateDesktopName});
- return true;
- } catch (exc) {
- UI.showStatus('Unable to create RFB client -- ' + exc, 'error');
- return false;
- }
- },
-
/* ------^-------
- * /INIT
+ * /EVENT HANDLERS
* ==============
* VISUAL
* ------v------*/
updateState: function(rfb, state, oldstate) {
+ var msg;
+
+ document.documentElement.classList.remove("noVNC_connecting");
+ document.documentElement.classList.remove("noVNC_connected");
+ document.documentElement.classList.remove("noVNC_disconnecting");
+ document.documentElement.classList.remove("noVNC_reconnecting");
+
switch (state) {
case 'connecting':
- UI.showStatus("Connecting");
+ document.getElementById("noVNC_transition_text").textContent = _("Connecting...");
+ document.documentElement.classList.add("noVNC_connecting");
break;
case 'connected':
UI.connected = true;
+ UI.inhibit_reconnect = false;
+ document.documentElement.classList.add("noVNC_connected");
if (rfb && rfb.get_encrypt()) {
- UI.showStatus("Connected (encrypted) to " +
- UI.desktopName);
+ msg = _("Connected (encrypted) to ") + UI.desktopName;
} else {
- UI.showStatus("Connected (unencrypted) to " +
- UI.desktopName);
+ msg = _("Connected (unencrypted) to ") + UI.desktopName;
}
+ UI.showStatus(msg);
break;
case 'disconnecting':
- UI.showStatus("Disconnecting");
+ UI.connected = false;
+ document.getElementById("noVNC_transition_text").textContent = _("Disconnecting...");
+ document.documentElement.classList.add("noVNC_disconnecting");
break;
case 'disconnected':
- UI.connected = false;
- UI.showStatus("Disconnected");
+ UI.showStatus(_("Disconnected"));
break;
default:
- UI.showStatus("Invalid state", 'error');
+ msg = "Invalid UI state";
+ Util.Error(msg);
+ UI.showStatus(msg, 'error');
break;
}
// Disable/enable controls depending on connection state
updateVisualState: function() {
//Util.Debug(">> updateVisualState");
- document.getElementById('noVNC_setting_encrypt').disabled = UI.connected;
- document.getElementById('noVNC_setting_true_color').disabled = UI.connected;
- if (Util.browserSupportsCursorURIs()) {
- document.getElementById('noVNC_setting_cursor').disabled = UI.connected;
- } else {
- UI.updateSetting('cursor', !UI.isTouchDevice);
- document.getElementById('noVNC_setting_cursor').disabled = true;
- }
UI.enableDisableViewClip();
- document.getElementById('noVNC_setting_resize').disabled = UI.connected;
- document.getElementById('noVNC_setting_shared').disabled = UI.connected;
- document.getElementById('noVNC_setting_view_only').disabled = UI.connected;
- document.getElementById('noVNC_setting_path').disabled = UI.connected;
- document.getElementById('noVNC_setting_repeaterID').disabled = UI.connected;
+
+ if (Util.browserSupportsCursorURIs() && !Util.isTouchDevice) {
+ UI.enableSetting('cursor');
+ } else {
+ UI.disableSetting('cursor');
+ }
if (UI.connected) {
- document.documentElement.classList.add("noVNC_connected");
+ UI.disableSetting('encrypt');
+ UI.disableSetting('true_color');
+ UI.disableSetting('shared');
+ UI.disableSetting('host');
+ UI.disableSetting('port');
+ UI.disableSetting('path');
+ UI.disableSetting('repeaterID');
UI.updateViewClip();
UI.setMouseButton(1);
// Hide the controlbar after 2 seconds
UI.closeControlbarTimeout = setTimeout(UI.closeControlbar, 2000);
} else {
- document.documentElement.classList.remove("noVNC_connected");
+ UI.enableSetting('encrypt');
+ UI.enableSetting('true_color');
+ UI.enableSetting('shared');
+ UI.enableSetting('host');
+ UI.enableSetting('port');
+ UI.enableSetting('path');
+ UI.enableSetting('repeaterID');
UI.updateXvpButton(0);
UI.keepControlbar();
}
+ // Hide input related buttons in view only mode
+ if (UI.rfb && UI.rfb.get_view_only()) {
+ document.getElementById('noVNC_keyboard_button')
+ .classList.add('noVNC_hidden');
+ document.getElementById('noVNC_toggle_extra_keys_button')
+ .classList.add('noVNC_hidden');
+ } else {
+ document.getElementById('noVNC_keyboard_button')
+ .classList.remove('noVNC_hidden');
+ document.getElementById('noVNC_toggle_extra_keys_button')
+ .classList.remove('noVNC_hidden');
+ }
+
// State change disables viewport dragging.
// It is enabled (toggled) by direct click on the button
UI.setViewDrag(false);
status_type = 'normal';
}
- statusElem.classList.remove("noVNC_status_normal",
- "noVNC_status_warn",
- "noVNC_status_error");
+ statusElem.classList.remove("noVNC_status_normal");
+ statusElem.classList.remove("noVNC_status_warn");
+ statusElem.classList.remove("noVNC_status_error");
switch (status_type) {
case 'warning':
break;
}
- statusElem.innerHTML = text;
+ statusElem.textContent = text;
statusElem.classList.add("noVNC_open");
// If no time was specified, show the status for 1.5 seconds
}
},
+ toggleControlbarSide: function () {
+ // Temporarily disable animation to avoid weird movement
+ var bar = document.getElementById('noVNC_control_bar');
+ bar.style.transitionDuration = '0s';
+ bar.addEventListener('transitionend', function () { this.style.transitionDuration = ""; });
+
+ var anchor = document.getElementById('noVNC_control_bar_anchor');
+ if (anchor.classList.contains("noVNC_right")) {
+ WebUtil.writeSetting('controlbar_pos', 'left');
+ anchor.classList.remove("noVNC_right");
+ } else {
+ WebUtil.writeSetting('controlbar_pos', 'right');
+ anchor.classList.add("noVNC_right");
+ }
+
+ // Consider this a movement of the handle
+ UI.controlbarDrag = true;
+ },
+
dragControlbarHandle: function (e) {
if (!UI.controlbarGrabbed) return;
var ptr = Util.getPointerEvent(e);
+ var anchor = document.getElementById('noVNC_control_bar_anchor');
+ if (ptr.clientX < (window.innerWidth * 0.1)) {
+ if (anchor.classList.contains("noVNC_right")) {
+ UI.toggleControlbarSide();
+ }
+ } else if (ptr.clientX > (window.innerWidth * 0.9)) {
+ if (!anchor.classList.contains("noVNC_right")) {
+ UI.toggleControlbarSide();
+ }
+ }
+
if (!UI.controlbarDrag) {
// The goal is to trigger on a certain physical width, the
// devicePixelRatio brings us a bit closer but is not optimal.
e.preventDefault();
e.stopPropagation();
+ UI.keepControlbar();
+ UI.activateControlbar();
},
// Move the handle but don't allow any position outside the bounds
UI.toggleControlbar();
e.preventDefault();
e.stopPropagation();
+ UI.keepControlbar();
+ UI.activateControlbar();
}
UI.controlbarGrabbed = false;
},
var handle = document.getElementById("noVNC_control_bar_handle");
var bounds = handle.getBoundingClientRect();
- WebUtil.setCapture(handle);
+ Util.setCapture(handle);
UI.controlbarGrabbed = true;
UI.controlbarDrag = false;
UI.controlbarMouseDownOffsetY = ptr.clientY - bounds.top;
e.preventDefault();
e.stopPropagation();
+ UI.keepControlbar();
+ UI.activateControlbar();
+ },
+
+ toggleExpander: function(e) {
+ if (this.classList.contains("noVNC_open")) {
+ this.classList.remove("noVNC_open");
+ } else {
+ this.classList.add("noVNC_open");
+ }
},
/* ------^-------
return val;
},
- // Force a setting to be a certain value
- forceSetting: function(name, val) {
- UI.updateSetting(name, val);
- return val;
- },
-
// Read form control compatible setting from cookie
getSetting: function(name) {
var ctrl = document.getElementById('noVNC_setting_' + name);
return val;
},
- // Save/apply settings when 'Apply' button is pressed
- settingsApply: function() {
- //Util.Debug(">> settingsApply");
- UI.saveSetting('encrypt');
- UI.saveSetting('true_color');
- if (Util.browserSupportsCursorURIs()) {
- UI.saveSetting('cursor');
- }
-
- UI.saveSetting('resize');
-
- if (UI.getSetting('resize') === 'downscale' || UI.getSetting('resize') === 'scale') {
- UI.forceSetting('clip', false);
- }
-
- UI.saveSetting('clip');
- UI.saveSetting('shared');
- UI.saveSetting('view_only');
- UI.saveSetting('path');
- UI.saveSetting('repeaterID');
- UI.saveSetting('stylesheet');
- UI.saveSetting('logging');
+ // These helpers compensate for the lack of parent-selectors and
+ // previous-sibling-selectors in CSS which are needed when we want to
+ // disable the labels that belong to disabled input elements.
+ disableSetting: function(name) {
+ var ctrl = document.getElementById('noVNC_setting_' + name);
+ ctrl.disabled = true;
+ ctrl.label.classList.add('noVNC_disabled');
+ },
- // Settings with immediate (non-connected related) effect
- WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
- WebUtil.init_logging(UI.getSetting('logging'));
- UI.updateViewClip();
- UI.updateViewDrag();
- //Util.Debug("<< settingsApply");
+ enableSetting: function(name) {
+ var ctrl = document.getElementById('noVNC_setting_' + name);
+ ctrl.disabled = false;
+ ctrl.label.classList.remove('noVNC_disabled');
},
/* ------^-------
UI.closeSettingsPanel();
UI.closeXvpPanel();
UI.closeClipboardPanel();
- UI.closeConnectPanel();
UI.closeExtraKeys();
},
UI.closeAllPanels();
UI.openControlbar();
+ // Refresh UI elements from saved cookies
UI.updateSetting('encrypt');
UI.updateSetting('true_color');
if (Util.browserSupportsCursorURIs()) {
UI.updateSetting('cursor');
} else {
- UI.updateSetting('cursor', !UI.isTouchDevice);
- document.getElementById('noVNC_setting_cursor').disabled = true;
+ UI.updateSetting('cursor', !Util.isTouchDevice);
+ UI.disableSetting('cursor');
}
UI.updateSetting('clip');
UI.updateSetting('resize');
UI.updateSetting('view_only');
UI.updateSetting('path');
UI.updateSetting('repeaterID');
- UI.updateSetting('stylesheet');
UI.updateSetting('logging');
+ UI.updateSetting('reconnect');
+ UI.updateSetting('reconnect_delay');
document.getElementById('noVNC_settings')
.classList.add("noVNC_open");
.classList.remove("noVNC_selected");
},
- // Toggle the settings menu:
- // On open, settings are refreshed from saved cookies.
- // On close, settings are applied
toggleSettingsPanel: function() {
if (document.getElementById('noVNC_settings')
.classList.contains("noVNC_open")) {
- UI.settingsApply();
UI.closeSettingsPanel();
} else {
UI.openSettingsPanel();
// Disable/enable XVP button
updateXvpButton: function(ver) {
- if (ver >= 1) {
+ if (ver >= 1 && !UI.rfb.get_view_only()) {
document.getElementById('noVNC_xvp_button')
.classList.remove("noVNC_hidden");
} else {
* ------v------*/
openConnectPanel: function() {
- UI.closeAllPanels();
- UI.openControlbar();
-
- document.getElementById('noVNC_connect_controls')
+ document.getElementById('noVNC_connect_dlg')
.classList.add("noVNC_open");
- document.getElementById('noVNC_connect_controls_button')
- .classList.add("noVNC_selected");
-
- document.getElementById('noVNC_setting_host').focus();
},
closeConnectPanel: function() {
- document.getElementById('noVNC_connect_controls')
+ document.getElementById('noVNC_connect_dlg')
.classList.remove("noVNC_open");
- document.getElementById('noVNC_connect_controls_button')
- .classList.remove("noVNC_selected");
-
- UI.saveSetting('host');
- UI.saveSetting('port');
- UI.saveSetting('token');
- //UI.saveSetting('password');
},
- toggleConnectPanel: function() {
- if (document.getElementById('noVNC_connect_controls')
- .classList.contains("noVNC_open")) {
- UI.closeConnectPanel();
- } else {
- UI.openConnectPanel();
- }
- },
+ connect: function(event, password) {
+ var host = UI.getSetting('host');
+ var port = UI.getSetting('port');
+ var path = UI.getSetting('path');
- connect: function() {
- var host = document.getElementById('noVNC_setting_host').value;
- var port = document.getElementById('noVNC_setting_port').value;
- var password = document.getElementById('noVNC_setting_password').value;
- var token = document.getElementById('noVNC_setting_token').value;
- var path = document.getElementById('noVNC_setting_path').value;
+ if (typeof password === 'undefined') {
+ password = WebUtil.getConfigVar('password');
+ }
- //if token is in path then ignore the new token variable
- if (token) {
- path = WebUtil.injectParamIfMissing(path, "token", token);
+ if (password === null) {
+ password = undefined;
}
if ((!host) || (!port)) {
- UI.showStatus("Must set host and port", 'error');
+ var msg = _("Must set host and port");
+ Util.Error(msg);
+ UI.showStatus(msg, 'error');
return;
}
if (!UI.initRFB()) return;
UI.closeAllPanels();
+ UI.closeConnectPanel();
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_view_only(UI.getSetting('view_only'));
UI.rfb.set_repeaterID(UI.getSetting('repeaterID'));
+ UI.updateLocalCursor();
+ UI.updateViewOnly();
+
UI.rfb.connect(host, port, password, path);
},
UI.closeAllPanels();
UI.rfb.disconnect();
+ // Disable automatic reconnecting
+ UI.inhibit_reconnect = true;
+
// Restore the callback used for initial resize
UI.rfb.set_onFBUComplete(UI.initialResize);
// Don't display the connection settings until we're actually disconnected
},
+ reconnect: function() {
+ UI.reconnect_callback = null;
+
+ // if reconnect has been disabled in the meantime, do nothing.
+ if (UI.inhibit_reconnect) {
+ return;
+ }
+
+ UI.connect(null, UI.reconnect_password);
+ },
+
disconnectFinished: function (rfb, reason) {
if (typeof reason !== 'undefined') {
UI.showStatus(reason, 'error');
+ } else if (UI.getSetting('reconnect', false) === true && !UI.inhibit_reconnect) {
+ document.getElementById("noVNC_transition_text").textContent = _("Reconnecting...");
+ document.documentElement.classList.add("noVNC_reconnecting");
+
+ var delay = parseInt(UI.getSetting('reconnect_delay'));
+ UI.reconnect_callback = setTimeout(UI.reconnect, delay);
+ return;
}
+
+ UI.openControlbar();
+ UI.openConnectPanel();
+ },
+
+ cancelReconnect: function() {
+ if (UI.reconnect_callback !== null) {
+ clearTimeout(UI.reconnect_callback);
+ UI.reconnect_callback = null;
+ }
+
+ document.documentElement.classList.remove("noVNC_reconnecting");
+ UI.openControlbar();
UI.openConnectPanel();
},
}, 100);
if (typeof msg === 'undefined') {
- msg = "Password is required";
+ msg = _("Password is required");
}
+ Util.Warn(msg);
UI.showStatus(msg, "warning");
},
- setPassword: function() {
- UI.rfb.sendPassword(document.getElementById('noVNC_password_input').value);
+ setPassword: function(e) {
+ var password = document.getElementById('noVNC_password_input').value;
+ UI.rfb.sendPassword(password);
+ UI.reconnect_password = password;
document.getElementById('noVNC_password_dlg')
.classList.remove('noVNC_open');
- return false;
+ // Prevent actually submitting the form
+ e.preventDefault();
},
/* ------^-------
var display = UI.rfb.get_display();
var resizeMode = UI.getSetting('resize');
+ display.set_scale(1);
+
+ // Make sure the viewport is adjusted first
+ UI.updateViewClip();
if (resizeMode === 'remote') {
// is finished we wait 0.5 seconds before sending the request.
clearTimeout(UI.resizeTimeout);
UI.resizeTimeout = setTimeout(function(){
-
- // Limit the viewport to the size of the browser window
- display.set_maxWidth(screen.w);
- display.set_maxHeight(screen.h);
-
- Util.Debug('Attempting requestDesktopSize(' +
- screen.w + ', ' + screen.h + ')');
-
// Request a remote size covering the viewport
- UI.rfb.requestDesktopSize(screen.w, screen.h);
+ if (UI.rfb.requestDesktopSize(screen.w, screen.h)) {
+ Util.Debug('Requested new desktop size: ' +
+ screen.w + 'x' + screen.h);
+ }
}, 500);
} else if (resizeMode === 'scale' || resizeMode === 'downscale') {
var downscaleOnly = resizeMode === 'downscale';
- var scaleRatio = display.autoscale(screen.w, screen.h, downscaleOnly);
- UI.rfb.get_mouse().set_scale(scaleRatio);
- Util.Debug('Scaling by ' + UI.rfb.get_mouse().get_scale());
+ display.autoscale(screen.w, screen.h, downscaleOnly);
+ UI.fixScrollbars();
}
}
},
- // The screen is always the same size as the available viewport
- // in the browser window minus the height of the control bar
+ // Gets the the size of the available viewport in the browser window
screenSize: function() {
var screen = document.getElementById('noVNC_screen');
-
- // Hide the scrollbars until the size is calculated
- screen.style.overflow = "hidden";
-
- var pos = Util.getPosition(screen);
- var w = pos.width;
- var h = pos.height;
-
- screen.style.overflow = "visible";
-
- if (isNaN(w) || isNaN(h)) {
- return false;
- } else {
- return {w: w, h: h};
- }
+ return {w: screen.offsetWidth, h: screen.offsetHeight};
},
// Normally we only apply the current resize mode after a window resize
var cur_clip = display.get_viewport();
var new_clip = UI.getSetting('clip');
+ var resizeSetting = UI.getSetting('resize');
+ if (resizeSetting === 'downscale' || resizeSetting === 'scale') {
+ // Disable clipping if we are scaling
+ new_clip = false;
+ } else if (Util.isTouchDevice) {
+ // Touch devices usually have shit scrollbars
+ new_clip = true;
+ }
+
if (cur_clip !== new_clip) {
display.set_viewport(new_clip);
}
if (new_clip && size) {
// When clipping is enabled, the screen is limited to
// the size of the browser window.
- display.set_maxWidth(size.w);
- display.set_maxHeight(size.h);
-
- var screen = document.getElementById('noVNC_screen');
- var canvas = document.getElementById('noVNC_canvas');
-
- // Hide potential scrollbars that can skew the position
- screen.style.overflow = "hidden";
-
- // The x position marks the left margin of the canvas,
- // remove the margin from both sides to keep it centered.
- var new_w = size.w - (2 * Util.getPosition(canvas).x);
-
- screen.style.overflow = "visible";
-
- display.viewportChangeSize(new_w, size.h);
- } else {
- // Disable max dimensions
- display.set_maxWidth(0);
- display.set_maxHeight(0);
- display.viewportChangeSize();
+ display.viewportChangeSize(size.w, size.h);
+ UI.fixScrollbars();
}
+
+ // Changing the viewport may change the state of
+ // the dragging button
+ UI.updateViewDrag();
},
// Handle special cases where clipping is forced on/off or locked
enableDisableViewClip: function() {
- var resizeSetting = document.getElementById('noVNC_setting_resize');
-
- if (UI.isSafari) {
- // Safari auto-hides the scrollbars which makes them
- // impossible to use in most cases
- UI.setViewClip(true);
- document.getElementById('noVNC_setting_clip').disabled = true;
- } else if (resizeSetting.value === 'downscale' || resizeSetting.value === 'scale') {
- // Disable clipping if we are scaling
- UI.setViewClip(false);
- document.getElementById('noVNC_setting_clip').disabled = true;
- } else if (document.msFullscreenElement) {
- // The browser is IE and we are in fullscreen mode.
- // - We need to force clipping while in fullscreen since
- // scrollbars doesn't work.
- UI.showStatus("Forcing clipping mode since scrollbars aren't supported by IE in fullscreen");
- UI.rememberedClipSetting = UI.getSetting('clip');
- UI.setViewClip(true);
- document.getElementById('noVNC_setting_clip').disabled = true;
- } else if (document.body.msRequestFullscreen && UI.rememberedClip !== null) {
- // Restore view clip to what it was before fullscreen on IE
- UI.setViewClip(UI.rememberedClipSetting);
- document.getElementById('noVNC_setting_clip').disabled =
- UI.connected || UI.isTouchDevice;
+ var resizeSetting = UI.getSetting('resize');
+ // Disable clipping if we are scaling, connected or on touch
+ if (resizeSetting === 'downscale' || resizeSetting === 'scale' ||
+ Util.isTouchDevice) {
+ UI.disableSetting('clip');
} else {
- document.getElementById('noVNC_setting_clip').disabled =
- UI.connected || UI.isTouchDevice;
- if (UI.isTouchDevice) {
- UI.setViewClip(true);
- }
+ UI.enableSetting('clip');
}
},
// Different behaviour for touch vs non-touch
// The button is disabled instead of hidden on touch devices
- if (UI.isTouchDevice) {
+ if (Util.isTouchDevice) {
viewDragButton.classList.remove("noVNC_hidden");
if (clipping) {
* ------v------*/
showVirtualKeyboard: function() {
- if (!UI.isTouchDevice) return;
+ if (!Util.isTouchDevice) return;
var input = document.getElementById('noVNC_keyboardinput');
if (document.activeElement == input) return;
- UI.keyboardVisible = true;
- document.getElementById('noVNC_keyboard_button')
- .classList.add("noVNC_selected");
input.focus();
try {
},
hideVirtualKeyboard: function() {
- if (!UI.isTouchDevice) return;
+ if (!Util.isTouchDevice) return;
var input = document.getElementById('noVNC_keyboardinput');
},
toggleVirtualKeyboard: function () {
- if (UI.keyboardVisible) {
+ if (document.getElementById('noVNC_keyboard_button')
+ .classList.contains("noVNC_selected")) {
UI.hideVirtualKeyboard();
} else {
UI.showVirtualKeyboard();
}
},
- onblurVirtualKeyboard: function() {
- //Weird bug in iOS if you change keyboardVisible
- //here it does not actually occur so next time
- //you click keyboard icon it doesnt work.
- UI.hideKeyboardTimeout = setTimeout(function() {
- UI.keyboardVisible = false;
- document.getElementById('noVNC_keyboard_button')
- .classList.remove("noVNC_selected");
- },100);
+ onfocusVirtualKeyboard: function(event) {
+ document.getElementById('noVNC_keyboard_button')
+ .classList.add("noVNC_selected");
},
- keepKeyboard: function() {
- clearTimeout(UI.hideKeyboardTimeout);
- if(UI.keyboardVisible === true) {
- UI.showVirtualKeyboard();
- } else if(UI.keyboardVisible === false) {
- UI.hideVirtualKeyboard();
+ onblurVirtualKeyboard: function(event) {
+ document.getElementById('noVNC_keyboard_button')
+ .classList.remove("noVNC_selected");
+ },
+
+ keepVirtualKeyboard: function(event) {
+ var input = document.getElementById('noVNC_keyboardinput');
+
+ // Only prevent focus change if the virtual keyboard is active
+ if (document.activeElement != input) {
+ return;
}
+
+ // Only allow focus to move to other elements that need
+ // focus to function properly
+ if (event.target.form !== undefined) {
+ switch (event.target.type) {
+ case 'text':
+ case 'email':
+ case 'search':
+ case 'password':
+ case 'tel':
+ case 'url':
+ case 'textarea':
+ case 'select-one':
+ case 'select-multiple':
+ return;
+ }
+ }
+
+ event.preventDefault();
},
keyboardinputReset: function() {
UI.rfb.sendKey(KeyTable.XK_BackSpace);
}
for (i = newLen - inputs; i < newLen; i++) {
- UI.rfb.sendKey(newValue.charCodeAt(i));
+ UI.rfb.sendKey(keysyms.fromUnicode(newValue.charCodeAt(i)).keysym);
}
// Control the text content length in the keyboardinput element
// text has been added to the field
event.target.blur();
// This has to be ran outside of the input handler in order to work
- setTimeout(UI.keepKeyboard, 0);
+ setTimeout(event.target.focus.bind(event.target), 0);
} else {
UI.lastKeyboardinput = newValue;
}
},
toggleExtraKeys: function() {
- UI.keepKeyboard();
if(document.getElementById('noVNC_modifiers')
.classList.contains("noVNC_open")) {
UI.closeExtraKeys();
},
sendEsc: function() {
- UI.keepKeyboard();
UI.rfb.sendKey(KeyTable.XK_Escape);
},
sendTab: function() {
- UI.keepKeyboard();
UI.rfb.sendKey(KeyTable.XK_Tab);
},
toggleCtrl: function() {
- UI.keepKeyboard();
var btn = document.getElementById('noVNC_toggle_ctrl_button');
if (btn.classList.contains("noVNC_selected")) {
UI.rfb.sendKey(KeyTable.XK_Control_L, false);
},
toggleAlt: function() {
- UI.keepKeyboard();
var btn = document.getElementById('noVNC_toggle_alt_button');
if (btn.classList.contains("noVNC_selected")) {
UI.rfb.sendKey(KeyTable.XK_Alt_L, false);
},
sendCtrlAltDel: function() {
- UI.keepKeyboard();
UI.rfb.sendCtrlAltDel();
},
* ------v------*/
setMouseButton: function(num) {
- if (UI.rfb) {
+ var view_only = UI.rfb.get_view_only();
+ if (UI.rfb && !view_only) {
UI.rfb.get_mouse().set_touchButton(num);
}
var blist = [0, 1,2,4];
for (var b = 0; b < blist.length; b++) {
- var button = document.getElementById('noVNC_mouse_button' + blist[b]);
- if (blist[b] === num) {
+ var button = document.getElementById('noVNC_mouse_button' +
+ blist[b]);
+ if (blist[b] === num && !view_only) {
button.classList.remove("noVNC_hidden");
} else {
button.classList.add("noVNC_hidden");
},
displayBlur: function() {
- if (!UI.rfb) return;
-
- UI.rfb.get_keyboard().set_focused(false);
- UI.rfb.get_mouse().set_focused(false);
+ if (UI.rfb && !UI.rfb.get_view_only()) {
+ UI.rfb.get_keyboard().set_focused(false);
+ UI.rfb.get_mouse().set_focused(false);
+ }
},
displayFocus: function() {
- if (!UI.rfb) return;
+ if (UI.rfb && !UI.rfb.get_view_only()) {
+ UI.rfb.get_keyboard().set_focused(true);
+ UI.rfb.get_mouse().set_focused(true);
+ }
+ },
+
+ updateLocalCursor: function() {
+ UI.rfb.set_local_cursor(UI.getSetting('cursor'));
+ },
+
+ updateViewOnly: function() {
+ UI.rfb.set_view_only(UI.getSetting('view_only'));
+ },
- UI.rfb.get_keyboard().set_focused(true);
- UI.rfb.get_mouse().set_focused(true);
+ updateLogging: function() {
+ WebUtil.init_logging(UI.getSetting('logging'));
+ },
+
+ updateSessionSize: function(rfb, width, height) {
+ UI.updateViewClip();
+ UI.fixScrollbars();
+ },
+
+ fixScrollbars: function() {
+ // This is a hack because Chrome screws up the calculation
+ // for when scrollbars are needed. So to fix it we temporarily
+ // toggle them off and on.
+ var screen = document.getElementById('noVNC_screen');
+ screen.style.overflow = 'hidden';
+ // Force Chrome to recalculate the layout by asking for
+ // an element's dimensions
+ screen.getBoundingClientRect();
+ screen.style.overflow = null;
},
updateDesktopName: function(rfb, name) {
*/
};
- /* [module] UI.load(); */
+ UI.load();
})();
-/* [module] export default UI; */
+export default UI;