| /* |
| * noVNC: HTML5 VNC client |
| * Copyright (C) 2012 Joel Martin |
| * Copyright (C) 2013 Samuel Mannehed for Cendio AB |
| * Licensed under MPL 2.0 (see LICENSE.txt) |
| * |
| * See README.md for usage and integration instructions. |
| */ |
| |
| /* jslint white: false, browser: true */ |
| /* global window, $D, Util, WebUtil, RFB, Display */ |
| |
| var UI; |
| |
| (function () { |
| "use strict"; |
| |
| // Load supporting scripts |
| window.onscriptsload = function () { UI.load(); }; |
| window.onload = function () { UI.keyboardinputReset(); }; |
| Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js", |
| "keysymdef.js", "keyboard.js", "input.js", "display.js", |
| "jsunzip.js", "rfb.js", "keysym.js"]); |
| |
| var UI = { |
| |
| rfb_state : 'loaded', |
| settingsOpen : false, |
| connSettingsOpen : false, |
| popupStatusOpen : false, |
| clipboardOpen: false, |
| keyboardVisible: false, |
| hideKeyboardTimeout: null, |
| lastKeyboardinput: null, |
| defaultKeyboardinputLen: 100, |
| extraKeysVisible: false, |
| ctrlOn: false, |
| altOn: false, |
| isTouchDevice: false, |
| |
| // 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); |
| }, |
| |
| // Render default UI and initialize settings menu |
| start: function(callback) { |
| UI.isTouchDevice = 'ontouchstart' in document.documentElement; |
| |
| // Stylesheet selection dropdown |
| var sheet = WebUtil.selectStylesheet(); |
| 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); |
| } |
| |
| // 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]); |
| } |
| |
| // 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')); |
| |
| // if port == 80 (or 443) then it won't be present and should be |
| // set manually |
| var port = window.location.port; |
| if (!port) { |
| if (window.location.protocol.substring(0,5) == 'https') { |
| port = 443; |
| } |
| else if (window.location.protocol.substring(0,4) == 'http') { |
| port = 80; |
| } |
| } |
| |
| /* 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('shared', true); |
| UI.initSetting('view_only', false); |
| UI.initSetting('path', 'websockify'); |
| UI.initSetting('repeaterID', ''); |
| |
| UI.rfb = new RFB({'target': $D('noVNC_canvas'), |
| 'onUpdateState': UI.updateState, |
| 'onXvpInit': UI.updateXvpVisualState, |
| 'onClipboard': UI.clipReceive, |
| 'onDesktopName': UI.updateDocumentTitle}); |
| |
| var autoconnect = WebUtil.getQueryVar('autoconnect', false); |
| if (autoconnect === 'true' || autoconnect == '1') { |
| autoconnect = true; |
| UI.connect(); |
| } else { |
| autoconnect = false; |
| } |
| |
| UI.updateVisualState(); |
| |
| // Show mouse selector buttons on touch screen devices |
| if (UI.isTouchDevice) { |
| // Show mobile buttons |
| $D('noVNC_mobile_buttons').style.display = "inline"; |
| UI.setMouseButton(); |
| // Remove the address bar |
| setTimeout(function() { window.scrollTo(0, 1); }, 100); |
| UI.forceSetting('clip', true); |
| $D('noVNC_clip').disabled = true; |
| } else { |
| UI.initSetting('clip', false); |
| } |
| |
| //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(); |
| } |
| UI.setBarPosition(); |
| |
| $D('noVNC_host').focus(); |
| |
| UI.setViewClip(); |
| Util.addEvent(window, 'resize', UI.setViewClip); |
| |
| Util.addEvent(window, 'beforeunload', function () { |
| if (UI.rfb_state === 'normal') { |
| return "You are currently connected."; |
| } |
| } ); |
| |
| // Show description by default when hosted at for kanaka.github.com |
| if (location.host === "kanaka.github.io") { |
| // Open the description dialog |
| $D('noVNC_description').style.display = "block"; |
| } else { |
| // Show the connect panel on first load unless autoconnecting |
| if (autoconnect === UI.connSettingsOpen) { |
| UI.toggleConnectPanel(); |
| } |
| } |
| |
| // Add mouse event click/focus/blur event handlers to the UI |
| UI.addMouseHandlers(); |
| |
| if (typeof callback === "function") { |
| callback(UI.rfb); |
| } |
| }, |
| |
| addMouseHandlers: function() { |
| // Setup interface handlers that can't be inline |
| $D("noVNC_view_drag_button").onclick = UI.setViewDrag; |
| $D("noVNC_mouse_button0").onclick = function () { UI.setMouseButton(1); }; |
| $D("noVNC_mouse_button1").onclick = function () { UI.setMouseButton(2); }; |
| $D("noVNC_mouse_button2").onclick = function () { UI.setMouseButton(4); }; |
| $D("noVNC_mouse_button4").onclick = function () { UI.setMouseButton(0); }; |
| $D("showKeyboard").onclick = UI.showKeyboard; |
| |
| $D("keyboardinput").oninput = UI.keyInput; |
| $D("keyboardinput").onblur = UI.keyInputBlur; |
| |
| $D("showExtraKeysButton").onclick = UI.showExtraKeys; |
| $D("toggleCtrlButton").onclick = UI.toggleCtrl; |
| $D("toggleAltButton").onclick = UI.toggleAlt; |
| $D("sendTabButton").onclick = UI.sendTab; |
| $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.togglePopupStatusPanel; |
| $D("noVNC_popup_status_panel").onclick = UI.togglePopupStatusPanel; |
| $D("xvpButton").onclick = UI.toggleXvpPanel; |
| $D("clipboardButton").onclick = UI.toggleClipboardPanel; |
| $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_connect_button").onclick = UI.connect; |
| }, |
| |
| // Read form control compatible setting from cookie |
| getSetting: function(name) { |
| var ctrl = $D('noVNC_' + name); |
| var val = WebUtil.readSetting(name); |
| if (val !== null && ctrl.type === 'checkbox') { |
| if (val.toString().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) { |
| |
| // Save the cookie for this session |
| if (typeof value !== 'undefined') { |
| WebUtil.writeSetting(name, value); |
| } |
| |
| // Update the settings control |
| value = UI.getSetting(name); |
| |
| var ctrl = $D('noVNC_' + name); |
| if (ctrl.type === 'checkbox') { |
| ctrl.checked = value; |
| |
| } else if (typeof ctrl.options !== 'undefined') { |
| for (var 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.writeSetting(name, val); |
| //Util.Debug("Setting saved '" + name + "=" + val + "'"); |
| return val; |
| }, |
| |
| // Initial page load read/initialization of settings |
| initSetting: function(name, defVal) { |
| // Check Query string followed by cookie |
| var val = WebUtil.getQueryVar(name); |
| if (val === null) { |
| val = WebUtil.readSetting(name, defVal); |
| } |
| UI.updateSetting(name, val); |
| return val; |
| }, |
| |
| // Force a setting to be a certain value |
| forceSetting: function(name, val) { |
| UI.updateSetting(name, val); |
| return val; |
| }, |
| |
| |
| // Show the popup status panel |
| togglePopupStatusPanel: function() { |
| var psp = $D('noVNC_popup_status_panel'); |
| if (UI.popupStatusOpen === true) { |
| psp.style.display = "none"; |
| UI.popupStatusOpen = false; |
| } else { |
| psp.innerHTML = $D('noVNC_status').innerHTML; |
| psp.style.display = "block"; |
| psp.style.left = window.innerWidth/2 - |
| parseInt(window.getComputedStyle(psp, false).width)/2 -30 + "px"; |
| UI.popupStatusOpen = true; |
| } |
| }, |
| |
| // Show the XVP panel |
| toggleXvpPanel: function() { |
| // Close the description panel |
| $D('noVNC_description').style.display = "none"; |
| // Close settings if open |
| if (UI.settingsOpen === true) { |
| UI.settingsApply(); |
| UI.closeSettingsMenu(); |
| } |
| // Close connection settings if open |
| if (UI.connSettingsOpen === true) { |
| UI.toggleConnectPanel(); |
| } |
| // Close popup status panel if open |
| if (UI.popupStatusOpen === true) { |
| UI.togglePopupStatusPanel(); |
| } |
| // Close clipboard panel if open |
| if (UI.clipboardOpen === true) { |
| UI.toggleClipboardPanel(); |
| } |
| // Toggle XVP panel |
| if (UI.xvpOpen === true) { |
| $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"; |
| UI.xvpOpen = true; |
| } |
| }, |
| |
| // Show the clipboard panel |
| toggleClipboardPanel: function() { |
| // Close the description panel |
| $D('noVNC_description').style.display = "none"; |
| // Close settings if open |
| if (UI.settingsOpen === true) { |
| UI.settingsApply(); |
| UI.closeSettingsMenu(); |
| } |
| // 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(); |
| } |
| // Toggle Clipboard Panel |
| if (UI.clipboardOpen === true) { |
| $D('noVNC_clipboard').style.display = "none"; |
| $D('clipboardButton').className = "noVNC_status_button"; |
| UI.clipboardOpen = false; |
| } else { |
| $D('noVNC_clipboard').style.display = "block"; |
| $D('clipboardButton').className = "noVNC_status_button_selected"; |
| UI.clipboardOpen = true; |
| } |
| }, |
| |
| // Show the connection settings panel/menu |
| toggleConnectPanel: function() { |
| // Close the description panel |
| $D('noVNC_description').style.display = "none"; |
| // Close connection settings if open |
| if (UI.settingsOpen === true) { |
| UI.settingsApply(); |
| UI.closeSettingsMenu(); |
| $D('connectButton').className = "noVNC_status_button"; |
| } |
| // Close clipboard panel if open |
| if (UI.clipboardOpen === true) { |
| UI.toggleClipboardPanel(); |
| } |
| // Close popup status panel if open |
| if (UI.popupStatusOpen === true) { |
| UI.togglePopupStatusPanel(); |
| } |
| // Close XVP panel if open |
| if (UI.xvpOpen === true) { |
| UI.toggleXvpPanel(); |
| } |
| |
| // Toggle Connection Panel |
| if (UI.connSettingsOpen === true) { |
| $D('noVNC_controls').style.display = "none"; |
| $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"; |
| UI.connSettingsOpen = true; |
| $D('noVNC_host').focus(); |
| } |
| }, |
| |
| // Toggle the settings menu: |
| // On open, settings are refreshed from saved cookies. |
| // On close, settings are applied |
| toggleSettingsPanel: function() { |
| // Close the description panel |
| $D('noVNC_description').style.display = "none"; |
| 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', !UI.isTouchDevice); |
| $D('noVNC_cursor').disabled = true; |
| } |
| UI.updateSetting('clip'); |
| UI.updateSetting('shared'); |
| UI.updateSetting('view_only'); |
| UI.updateSetting('path'); |
| UI.updateSetting('repeaterID'); |
| UI.updateSetting('stylesheet'); |
| UI.updateSetting('logging'); |
| |
| UI.openSettingsMenu(); |
| } |
| }, |
| |
| // Open menu |
| openSettingsMenu: function() { |
| // Close the description panel |
| $D('noVNC_description').style.display = "none"; |
| // 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(); |
| } |
| $D('noVNC_settings').style.display = "block"; |
| $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"; |
| UI.settingsOpen = false; |
| }, |
| |
| // 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('clip'); |
| UI.saveSetting('shared'); |
| UI.saveSetting('view_only'); |
| UI.saveSetting('path'); |
| UI.saveSetting('repeaterID'); |
| UI.saveSetting('stylesheet'); |
| UI.saveSetting('logging'); |
| |
| // Settings with immediate (non-connected related) effect |
| WebUtil.selectStylesheet(UI.getSetting('stylesheet')); |
| WebUtil.init_logging(UI.getSetting('logging')); |
| UI.setViewClip(); |
| UI.setViewDrag(UI.rfb.get_viewportDrag()); |
| //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.toggleConnectPanel(); |
| return false; |
| }, |
| |
| sendCtrlAltDel: function() { |
| UI.rfb.sendCtrlAltDel(); |
| }, |
| |
| xvpShutdown: function() { |
| UI.rfb.xvpShutdown(); |
| }, |
| |
| xvpReboot: function() { |
| UI.rfb.xvpReboot(); |
| }, |
| |
| xvpReset: function() { |
| UI.rfb.xvpReset(); |
| }, |
| |
| setMouseButton: function(num) { |
| if (typeof num === 'undefined') { |
| // Disable mouse buttons |
| num = -1; |
| } |
| if (UI.rfb) { |
| UI.rfb.get_mouse().set_touchButton(num); |
| } |
| |
| var blist = [0, 1,2,4]; |
| for (var b = 0; b < blist.length; b++) { |
| var button = $D('noVNC_mouse_button' + blist[b]); |
| if (blist[b] === num) { |
| button.style.display = ""; |
| } else { |
| button.style.display = "none"; |
| } |
| } |
| }, |
| |
| updateState: function(rfb, state, oldstate, msg) { |
| UI.rfb_state = state; |
| var klass; |
| switch (state) { |
| case 'failed': |
| case 'fatal': |
| klass = "noVNC_status_error"; |
| break; |
| case 'normal': |
| klass = "noVNC_status_normal"; |
| break; |
| case 'disconnected': |
| $D('noVNC_logo').style.display = "block"; |
| /* falls through */ |
| case 'loaded': |
| klass = "noVNC_status_normal"; |
| break; |
| case 'password': |
| UI.toggleConnectPanel(); |
| |
| $D('noVNC_connect_button').value = "Send Password"; |
| $D('noVNC_connect_button').onclick = UI.setPassword; |
| $D('noVNC_password').focus(); |
| |
| klass = "noVNC_status_warn"; |
| break; |
| default: |
| klass = "noVNC_status_warn"; |
| break; |
| } |
| |
| if (typeof(msg) !== 'undefined') { |
| $D('noVNC-control-bar').setAttribute("class", klass); |
| $D('noVNC_status').innerHTML = msg; |
| } |
| |
| UI.updateVisualState(); |
| }, |
| |
| // Disable/enable controls depending on connection state |
| updateVisualState: function() { |
| var connected = UI.rfb_state === 'normal' ? true : false; |
| |
| //Util.Debug(">> updateVisualState"); |
| $D('noVNC_encrypt').disabled = connected; |
| $D('noVNC_true_color').disabled = connected; |
| if (UI.rfb && UI.rfb.get_display() && |
| UI.rfb.get_display().get_cursor_uri()) { |
| $D('noVNC_cursor').disabled = connected; |
| } else { |
| UI.updateSetting('cursor', !UI.isTouchDevice); |
| $D('noVNC_cursor').disabled = true; |
| } |
| $D('noVNC_shared').disabled = connected; |
| $D('noVNC_view_only').disabled = connected; |
| $D('noVNC_path').disabled = connected; |
| $D('noVNC_repeaterID').disabled = connected; |
| |
| if (connected) { |
| UI.setViewClip(); |
| UI.setMouseButton(1); |
| $D('clipboardButton').style.display = "inline"; |
| $D('showKeyboard').style.display = "inline"; |
| $D('noVNC_extra_keys').style.display = ""; |
| $D('sendCtrlAltDelButton').style.display = "inline"; |
| } else { |
| UI.setMouseButton(); |
| $D('clipboardButton').style.display = "none"; |
| $D('showKeyboard').style.display = "none"; |
| $D('noVNC_extra_keys').style.display = "none"; |
| $D('sendCtrlAltDelButton').style.display = "none"; |
| UI.updateXvpVisualState(0); |
| } |
| |
| // State change disables viewport dragging. |
| // It is enabled (toggled) by direct click on the button |
| UI.setViewDrag(false); |
| |
| switch (UI.rfb_state) { |
| case 'fatal': |
| case 'failed': |
| case 'loaded': |
| case 'disconnected': |
| $D('connectButton').style.display = ""; |
| $D('disconnectButton').style.display = "none"; |
| break; |
| default: |
| $D('connectButton').style.display = "none"; |
| $D('disconnectButton').style.display = ""; |
| break; |
| } |
| |
| //Util.Debug("<< updateVisualState"); |
| }, |
| |
| // Disable/enable XVP button |
| updateXvpVisualState: function(ver) { |
| if (ver >= 1) { |
| $D('xvpButton').style.display = 'inline'; |
| } else { |
| $D('xvpButton').style.display = 'none'; |
| // Close XVP panel if open |
| if (UI.xvpOpen === true) { |
| UI.toggleXvpPanel(); |
| } |
| } |
| }, |
| |
| // Display the desktop name in the document title |
| updateDocumentTitle: function(rfb, name) { |
| document.title = name + " - noVNC"; |
| }, |
| |
| clipReceive: function(rfb, text) { |
| Util.Debug(">> UI.clipReceive: " + text.substr(0,40) + "..."); |
| $D('noVNC_clipboard_text').value = text; |
| Util.Debug("<< UI.clipReceive"); |
| }, |
| |
| connect: function() { |
| UI.closeSettingsMenu(); |
| UI.toggleConnectPanel(); |
| |
| var host = $D('noVNC_host').value; |
| var port = $D('noVNC_port').value; |
| var password = $D('noVNC_password').value; |
| var path = $D('noVNC_path').value; |
| if ((!host) || (!port)) { |
| throw new Error("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_view_only(UI.getSetting('view_only')); |
| UI.rfb.set_repeaterID(UI.getSetting('repeaterID')); |
| |
| UI.rfb.connect(host, port, password, path); |
| |
| //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.toggleConnectPanel(); |
| }, |
| |
| 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"); |
| }, |
| |
| // Enable/disable and configure viewport clipping |
| setViewClip: function(clip) { |
| var display; |
| if (UI.rfb) { |
| display = UI.rfb.get_display(); |
| } else { |
| return; |
| } |
| |
| var cur_clip = display.get_viewport(); |
| |
| if (typeof(clip) !== 'boolean') { |
| // Use current setting |
| clip = UI.getSetting('clip'); |
| } |
| |
| if (clip && !cur_clip) { |
| // Turn clipping on |
| UI.updateSetting('clip', true); |
| } else if (!clip && cur_clip) { |
| // Turn clipping off |
| UI.updateSetting('clip', false); |
| display.set_viewport(false); |
| $D('noVNC_canvas').style.position = 'static'; |
| display.viewportChange(); |
| } |
| if (UI.getSetting('clip')) { |
| // If clipping, update clipping settings |
| $D('noVNC_canvas').style.position = 'absolute'; |
| var pos = Util.getPosition($D('noVNC_canvas')); |
| var new_w = window.innerWidth - pos.x; |
| var new_h = window.innerHeight - pos.y; |
| display.set_viewport(true); |
| display.viewportChange(0, 0, new_w, new_h); |
| } |
| }, |
| |
| // Toggle/set/unset the viewport drag/move button |
| setViewDrag: function(drag) { |
| var vmb = $D('noVNC_view_drag_button'); |
| if (!UI.rfb) { return; } |
| |
| if (UI.rfb_state === 'normal' && |
| UI.rfb.get_display().get_viewport()) { |
| vmb.style.display = "inline"; |
| } else { |
| vmb.style.display = "none"; |
| } |
| |
| if (typeof(drag) === "undefined" || |
| typeof(drag) === "object") { |
| // If not specified, then toggle |
| drag = !UI.rfb.get_viewportDrag(); |
| } |
| if (drag) { |
| vmb.className = "noVNC_status_button_selected"; |
| UI.rfb.set_viewportDrag(true); |
| } else { |
| vmb.className = "noVNC_status_button"; |
| UI.rfb.set_viewportDrag(false); |
| } |
| }, |
| |
| // On touch devices, show the OS keyboard |
| showKeyboard: function() { |
| var kbi = $D('keyboardinput'); |
| var skb = $D('showKeyboard'); |
| var l = kbi.value.length; |
| if(UI.keyboardVisible === false) { |
| kbi.focus(); |
| try { kbi.setSelectionRange(l, l); } // Move the caret to the end |
| catch (err) {} // setSelectionRange is undefined in Google Chrome |
| UI.keyboardVisible = true; |
| skb.className = "noVNC_status_button_selected"; |
| } else if(UI.keyboardVisible === true) { |
| kbi.blur(); |
| skb.className = "noVNC_status_button"; |
| UI.keyboardVisible = false; |
| } |
| }, |
| |
| keepKeyboard: function() { |
| clearTimeout(UI.hideKeyboardTimeout); |
| if(UI.keyboardVisible === true) { |
| $D('keyboardinput').focus(); |
| $D('showKeyboard').className = "noVNC_status_button_selected"; |
| } else if(UI.keyboardVisible === false) { |
| $D('keyboardinput').blur(); |
| $D('showKeyboard').className = "noVNC_status_button"; |
| } |
| }, |
| |
| keyboardinputReset: function() { |
| var kbi = $D('keyboardinput'); |
| kbi.value = new Array(UI.defaultKeyboardinputLen).join("_"); |
| UI.lastKeyboardinput = kbi.value; |
| }, |
| |
| // When normal keyboard events are left uncought, use the input events from |
| // the keyboardinput element instead and generate the corresponding key events. |
| // This code is required since some browsers on Android are inconsistent in |
| // sending keyCodes in the normal keyboard events when using on screen keyboards. |
| keyInput: function(event) { |
| var newValue = event.target.value; |
| var oldValue = UI.lastKeyboardinput; |
| |
| var newLen; |
| try { |
| // Try to check caret position since whitespace at the end |
| // will not be considered by value.length in some browsers |
| newLen = Math.max(event.target.selectionStart, newValue.length); |
| } catch (err) { |
| // selectionStart is undefined in Google Chrome |
| newLen = newValue.length; |
| } |
| var oldLen = oldValue.length; |
| |
| var backspaces; |
| var inputs = newLen - oldLen; |
| if (inputs < 0) { |
| backspaces = -inputs; |
| } else { |
| backspaces = 0; |
| } |
| |
| // Compare the old string with the new to account for |
| // text-corrections or other input that modify existing text |
| var i; |
| for (i = 0; i < Math.min(oldLen, newLen); i++) { |
| if (newValue.charAt(i) != oldValue.charAt(i)) { |
| inputs = newLen - i; |
| backspaces = oldLen - i; |
| break; |
| } |
| } |
| |
| // Send the key events |
| for (i = 0; i < backspaces; i++) { |
| UI.rfb.sendKey(XK_BackSpace); |
| } |
| for (i = newLen - inputs; i < newLen; i++) { |
| UI.rfb.sendKey(newValue.charCodeAt(i)); |
| } |
| |
| // Control the text content length in the keyboardinput element |
| if (newLen > 2 * UI.defaultKeyboardinputLen) { |
| UI.keyboardinputReset(); |
| } else if (newLen < 1) { |
| // There always have to be some text in the keyboardinput |
| // element with which backspace can interact. |
| UI.keyboardinputReset(); |
| // This sometimes causes the keyboard to disappear for a second |
| // but it is required for the android keyboard to recognize that |
| // 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(function() { UI.keepKeyboard(); }, 0); |
| } else { |
| UI.lastKeyboardinput = newValue; |
| } |
| }, |
| |
| keyInputBlur: function() { |
| $D('showKeyboard').className = "noVNC_status_button"; |
| //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.setKeyboard(); },100); |
| }, |
| |
| showExtraKeys: function() { |
| UI.keepKeyboard(); |
| if(UI.extraKeysVisible === false) { |
| $D('toggleCtrlButton').style.display = "inline"; |
| $D('toggleAltButton').style.display = "inline"; |
| $D('sendTabButton').style.display = "inline"; |
| $D('sendEscButton').style.display = "inline"; |
| $D('showExtraKeysButton').className = "noVNC_status_button_selected"; |
| UI.extraKeysVisible = true; |
| } else if(UI.extraKeysVisible === true) { |
| $D('toggleCtrlButton').style.display = ""; |
| $D('toggleAltButton').style.display = ""; |
| $D('sendTabButton').style.display = ""; |
| $D('sendEscButton').style.display = ""; |
| $D('showExtraKeysButton').className = "noVNC_status_button"; |
| UI.extraKeysVisible = false; |
| } |
| }, |
| |
| toggleCtrl: function() { |
| UI.keepKeyboard(); |
| if(UI.ctrlOn === false) { |
| UI.rfb.sendKey(XK_Control_L, true); |
| $D('toggleCtrlButton').className = "noVNC_status_button_selected"; |
| UI.ctrlOn = true; |
| } else if(UI.ctrlOn === true) { |
| UI.rfb.sendKey(XK_Control_L, false); |
| $D('toggleCtrlButton').className = "noVNC_status_button"; |
| UI.ctrlOn = false; |
| } |
| }, |
| |
| toggleAlt: function() { |
| UI.keepKeyboard(); |
| if(UI.altOn === false) { |
| UI.rfb.sendKey(XK_Alt_L, true); |
| $D('toggleAltButton').className = "noVNC_status_button_selected"; |
| UI.altOn = true; |
| } else if(UI.altOn === true) { |
| UI.rfb.sendKey(XK_Alt_L, false); |
| $D('toggleAltButton').className = "noVNC_status_button"; |
| UI.altOn = false; |
| } |
| }, |
| |
| sendTab: function() { |
| UI.keepKeyboard(); |
| UI.rfb.sendKey(XK_Tab); |
| }, |
| |
| sendEsc: function() { |
| UI.keepKeyboard(); |
| UI.rfb.sendKey(XK_Escape); |
| }, |
| |
| setKeyboard: function() { |
| UI.keyboardVisible = false; |
| }, |
| |
| // 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'; |
| |
| var vncwidth = $D('noVNC_screen').style.offsetWidth; |
| $D('noVNC-control-bar').style.width = vncwidth + 'px'; |
| } |
| |
| }; |
| })(); |