/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2018 Samuel Mannehed for Cendio AB
- * Copyright (C) 2016 Pierre Ossman for Cendio AB
+ * Copyright (C) 2018 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
import * as Log from '../core/util/logging.js';
import _, { l10n } from './localization.js';
-import { isTouchDevice, dragThreshold } from '../core/util/browser.js';
+import { isTouchDevice, isSafari, isIOS, isAndroid, dragThreshold }
+ from '../core/util/browser.js';
import { setCapture, getPointerEvent } from '../core/util/events.js';
import KeyTable from "../core/input/keysym.js";
import keysyms from "../core/input/keysymdef.js";
controlbarMouseDownClientY: 0,
controlbarMouseDownOffsetY: 0,
- isSafari: false,
lastKeyboardinput: null,
defaultKeyboardinputLen: 100,
reconnect_callback: null,
reconnect_password: null,
- prime(callback) {
- if (document.readyState === "interactive" || document.readyState === "complete") {
- UI.load(callback);
- } else {
- document.addEventListener('DOMContentLoaded', UI.load.bind(UI, callback));
- }
- },
+ prime() {
+ return WebUtil.initSettings().then(() => {
+ if (document.readyState === "interactive" || document.readyState === "complete") {
+ return UI.start();
+ }
- // Setup rfb object, load settings from browser storage, then call
- // UI.init to setup the UI/menus
- load(callback) {
- WebUtil.initSettings(UI.start, callback);
+ return new Promise((resolve, reject) => {
+ document.addEventListener('DOMContentLoaded', () => UI.start().then(resolve).catch(reject));
+ });
+ });
},
// Render default UI and initialize settings menu
- start(callback) {
-
- // Setup global variables first
- UI.isSafari = (navigator.userAgent.indexOf('Safari') !== -1 &&
- navigator.userAgent.indexOf('Chrome') === -1);
+ start() {
UI.initSettings();
// Translate the DOM
l10n.translateDOM();
+ WebUtil.fetchJSON('../package.json')
+ .then((packageInfo) => {
+ Array.from(document.getElementsByClassName('noVNC_version')).forEach(el => el.innerText = packageInfo.version);
+ })
+ .catch((err) => {
+ Log.Error("Couldn't fetch package.json: " + err);
+ Array.from(document.getElementsByClassName('noVNC_version_wrapper'))
+ .concat(Array.from(document.getElementsByClassName('noVNC_version_separator')))
+ .forEach(el => el.style.display = 'none');
+ });
+
// Adapt the interface for touch screen devices
if (isTouchDevice) {
document.documentElement.classList.add("noVNC_touch");
UI.openConnectPanel();
}
- if (typeof callback === "function") {
- callback(UI.rfb);
- }
+ return Promise.resolve(UI.rfb);
},
initFullscreen() {
// Only show the button if fullscreen is properly supported
// * Safari doesn't support alphanumerical input while in fullscreen
- if (!UI.isSafari &&
+ if (!isSafari() &&
(document.documentElement.requestFullscreen ||
document.documentElement.mozRequestFullScreen ||
document.documentElement.webkitRequestFullscreen ||
// set manually
let port = window.location.port;
if (!port) {
- if (window.location.protocol.substring(0,5) == 'https') {
+ if (window.location.protocol.substring(0, 5) == 'https') {
port = 443;
- }
- else if (window.location.protocol.substring(0,4) == 'http') {
+ } else if (window.location.protocol.substring(0, 4) == 'http') {
port = 80;
}
}
UI.initSetting('resize', 'off');
UI.initSetting('shared', true);
UI.initSetting('view_only', false);
+ UI.initSetting('show_dot', false);
UI.initSetting('path', 'websockify');
UI.initSetting('repeaterID', '');
UI.initSetting('reconnect', false);
.addEventListener('click', UI.toggleExtraKeys);
document.getElementById("noVNC_toggle_ctrl_button")
.addEventListener('click', UI.toggleCtrl);
+ document.getElementById("noVNC_toggle_windows_button")
+ .addEventListener('click', UI.toggleWindows);
document.getElementById("noVNC_toggle_alt_button")
.addEventListener('click', UI.toggleAlt);
document.getElementById("noVNC_send_tab_button")
UI.addSettingChangeHandler('shared');
UI.addSettingChangeHandler('view_only');
UI.addSettingChangeHandler('view_only', UI.updateViewOnly);
+ UI.addSettingChangeHandler('show_dot');
+ UI.addSettingChangeHandler('show_dot', UI.updateShowDotCursor);
UI.addSettingChangeHandler('host');
UI.addSettingChangeHandler('port');
UI.addSettingChangeHandler('path');
const ctrl = document.getElementById('noVNC_setting_' + name);
let val = WebUtil.readSetting(name);
if (typeof val !== 'undefined' && val !== null && ctrl.type === 'checkbox') {
- if (val.toString().toLowerCase() in {'0':1, 'no':1, 'false':1}) {
+ if (val.toString().toLowerCase() in {'0': 1, 'no': 1, 'false': 1}) {
val = false;
} else {
val = true;
},
clipboardReceive(e) {
- Log.Debug(">> UI.clipboardReceive: " + e.detail.text.substr(0,40) + "...");
+ Log.Debug(">> UI.clipboardReceive: " + e.detail.text.substr(0, 40) + "...");
document.getElementById('noVNC_clipboard_text').value = e.detail.text;
Log.Debug("<< UI.clipboardReceive");
},
clipboardSend() {
const text = document.getElementById('noVNC_clipboard_text').value;
- Log.Debug(">> UI.clipboardSend: " + text.substr(0,40) + "...");
+ Log.Debug(">> UI.clipboardSend: " + text.substr(0, 40) + "...");
UI.rfb.clipboardPasteFrom(text);
Log.Debug("<< UI.clipboardSend");
},
url = UI.getSetting('encrypt') ? 'wss' : 'ws';
url += '://' + host;
- if(port) {
+ if (port) {
url += ':' + port;
}
url += '/' + path;
UI.rfb = new RFB(document.getElementById('noVNC_container'), url,
{ shared: UI.getSetting('shared'),
+ showDotCursor: UI.getSetting('show_dot'),
repeaterID: UI.getSetting('repeaterID'),
credentials: { password: password } });
UI.rfb.addEventListener("connect", UI.connectFinished);
// Can't be clipping if viewport is scaled to fit
UI.forceSetting('view_clip', false);
UI.rfb.clipViewport = false;
- } else if (isTouchDevice) {
- // Touch devices usually have shit scrollbars
+ } else if (isIOS() || isAndroid()) {
+ // iOS and Android usually have shit scrollbars
UI.forceSetting('view_clip', true);
UI.rfb.clipViewport = true;
} else {
// Move the caret to the end
input.setSelectionRange(l, l);
} catch (err) {
- // setSelectionRange is undefined in Google Chrome
+ // setSelectionRange is undefined in Google Chrome
}
},
},
toggleExtraKeys() {
- if(document.getElementById('noVNC_modifiers')
+ if (document.getElementById('noVNC_modifiers')
.classList.contains("noVNC_open")) {
UI.closeExtraKeys();
} else {
}
},
+ toggleWindows() {
+ const btn = document.getElementById('noVNC_toggle_windows_button');
+ if (btn.classList.contains("noVNC_selected")) {
+ UI.rfb.sendKey(KeyTable.XK_Super_L, "MetaLeft", false);
+ btn.classList.remove("noVNC_selected");
+ } else {
+ UI.rfb.sendKey(KeyTable.XK_Super_L, "MetaLeft", true);
+ btn.classList.add("noVNC_selected");
+ }
+ },
+
toggleAlt() {
const btn = document.getElementById('noVNC_toggle_alt_button');
if (btn.classList.contains("noVNC_selected")) {
UI.rfb.touchButton = num;
}
- const blist = [0, 1,2,4];
+ const blist = [0, 1, 2, 4];
for (let b = 0; b < blist.length; b++) {
const button = document.getElementById('noVNC_mouse_button' +
blist[b]);
.classList.add('noVNC_hidden');
document.getElementById('noVNC_toggle_extra_keys_button')
.classList.add('noVNC_hidden');
+ document.getElementById('noVNC_mouse_button' + UI.rfb.touchButton)
+ .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');
+ document.getElementById('noVNC_mouse_button' + UI.rfb.touchButton)
+ .classList.remove('noVNC_hidden');
}
- UI.setMouseButton(1); //has it's own logic for hiding/showing
+ },
+
+ updateShowDotCursor() {
+ if (!UI.rfb) return;
+ UI.rfb.showDotCursor = UI.getSetting('show_dot');
},
updateLogging() {
};
// Set up translations
-const LINGUAS = ["de", "el", "es", "nl", "pl", "sv", "tr", "zh_CN", "zh_TW"];
+const LINGUAS = ["cs", "de", "el", "es", "ja", "ko", "nl", "pl", "ru", "sv", "tr", "zh_CN", "zh_TW"];
l10n.setup(LINGUAS);
-if (l10n.language !== "en" && l10n.dictionary === undefined) {
- WebUtil.fetchJSON('app/locale/' + l10n.language + '.json', (translations) => {
- l10n.dictionary = translations;
-
- // wait for translations to load before loading the UI
- UI.prime();
- }, (err) => {
- Log.Error("Failed to load translations: " + err);
- UI.prime();
- });
-} else {
+if (l10n.language === "en" || l10n.dictionary !== undefined) {
UI.prime();
+} else {
+ WebUtil.fetchJSON('app/locale/' + l10n.language + '.json')
+ .then((translations) => { l10n.dictionary = translations; })
+ .catch(err => Log.Error("Failed to load translations: " + err))
+ .then(UI.prime);
}
export default UI;