From 8f9ee70c61ce05906bfd99648c1ea17172b8581e Mon Sep 17 00:00:00 2001 From: Dmitriy Shweew Date: Sun, 17 Feb 2019 18:36:16 +0400 Subject: [PATCH] Delete ui.js --- app/ui.js | 1663 ----------------------------------------------------- 1 file changed, 1663 deletions(-) delete mode 100644 app/ui.js diff --git a/app/ui.js b/app/ui.js deleted file mode 100644 index a5aace06..00000000 --- a/app/ui.js +++ /dev/null @@ -1,1663 +0,0 @@ -/* - * noVNC: HTML5 VNC client - * 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, 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"; -import Keyboard from "../core/input/keyboard.js"; -import RFB from "../core/rfb.js"; -import * as WebUtil from "./webutil.js"; - -const UI = { - - connected: false, - desktopName: "", - - statusTimeout: null, - hideKeyboardTimeout: null, - idleControlbarTimeout: null, - closeControlbarTimeout: null, - - controlbarGrabbed: false, - controlbarDrag: false, - controlbarMouseDownClientY: 0, - controlbarMouseDownOffsetY: 0, - - lastKeyboardinput: null, - defaultKeyboardinputLen: 100, - - inhibit_reconnect: true, - 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)); - } - }, - - // Setup rfb object, load settings from browser storage, then call - // UI.init to setup the UI/menus - load(callback) { - WebUtil.initSettings(UI.start, callback); - }, - - // Render default UI and initialize settings menu - start(callback) { - - UI.initSettings(); - - // Translate the DOM - l10n.translateDOM(); - - // Adapt the interface for touch screen devices - if (isTouchDevice) { - document.documentElement.classList.add("noVNC_touch"); - // Remove the address bar - setTimeout(() => window.scrollTo(0, 1), 100); - } - - // Restore control bar position - if (WebUtil.readSetting('controlbar_pos') === 'right') { - UI.toggleControlbarSide(); - } - - UI.initFullscreen(); - - // Setup event handlers - UI.addControlbarHandlers(); - UI.addTouchSpecificHandlers(); - UI.addExtraKeysHandlers(); - UI.addMachineHandlers(); - UI.addConnectionControlHandlers(); - UI.addClipboardHandlers(); - UI.addSettingsHandlers(); - document.getElementById("noVNC_status") - .addEventListener('click', UI.hideStatus); - - // Bootstrap fallback input handler - UI.keyboardinputReset(); - - UI.openControlbar(); - - UI.updateVisualState('init'); - - document.documentElement.classList.remove("noVNC_loading"); - - let autoconnect = WebUtil.getConfigVar('autoconnect', false); - if (autoconnect === 'true' || autoconnect == '1') { - autoconnect = true; - UI.connect(); - } else { - autoconnect = false; - // Show the connect panel on first load unless autoconnecting - UI.openConnectPanel(); - } - - if (typeof callback === "function") { - callback(UI.rfb); - } - }, - - initFullscreen() { - // Only show the button if fullscreen is properly supported - // * Safari doesn't support alphanumerical input while in fullscreen - if (!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() { - // Logging selection dropdown - const llevels = ['error', 'warn', 'info', 'debug']; - for (let i = 0; i < llevels.length; i += 1) { - UI.addOption(document.getElementById('noVNC_setting_logging'), llevels[i], llevels[i]); - } - - // Settings with immediate effects - UI.initSetting('logging', 'warn'); - UI.updateLogging(); - - // if port == 80 (or 443) then it won't be present and should be - // set manually - let 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('encrypt', (window.location.protocol === "https:")); - UI.initSetting('view_clip', false); - 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); - UI.initSetting('reconnect_delay', 5000); - - UI.setupSettingLabels(); - }, - // Adds a link to the label elements on the corresponding input elements - setupSettingLabels() { - const labels = document.getElementsByTagName('LABEL'); - for (let i = 0; i < labels.length; i++) { - const htmlFor = labels[i].htmlFor; - if (htmlFor != '') { - const elem = document.getElementById(htmlFor); - if (elem) elem.label = labels[i]; - } else { - // If 'for' isn't set, use the first input element child - const children = labels[i].children; - for (let j = 0; j < children.length; j++) { - if (children[j].form !== undefined) { - children[j].label = labels[i]; - break; - } - } - } - } - }, - -/* ------^------- -* /INIT -* ============== -* EVENT HANDLERS -* ------v------*/ - - addControlbarHandlers() { - document.getElementById("noVNC_control_bar") - .addEventListener('mousemove', UI.activateControlbar); - document.getElementById("noVNC_control_bar") - .addEventListener('mouseup', UI.activateControlbar); - document.getElementById("noVNC_control_bar") - .addEventListener('mousedown', UI.activateControlbar); - document.getElementById("noVNC_control_bar") - .addEventListener('keydown', UI.activateControlbar); - - document.getElementById("noVNC_control_bar") - .addEventListener('mousedown', UI.keepControlbar); - document.getElementById("noVNC_control_bar") - .addEventListener('keydown', UI.keepControlbar); - - document.getElementById("noVNC_view_drag_button") - .addEventListener('click', UI.toggleViewDrag); - - document.getElementById("noVNC_control_bar_handle") - .addEventListener('mousedown', UI.controlbarHandleMouseDown); - document.getElementById("noVNC_control_bar_handle") - .addEventListener('mouseup', UI.controlbarHandleMouseUp); - document.getElementById("noVNC_control_bar_handle") - .addEventListener('mousemove', UI.dragControlbarHandle); - // resize events aren't available for elements - window.addEventListener('resize', UI.updateControlbarHandle); - - const exps = document.getElementsByClassName("noVNC_expander"); - for (let i = 0;i < exps.length;i++) { - exps[i].addEventListener('click', UI.toggleExpander); - } - }, - - addTouchSpecificHandlers() { - document.getElementById("noVNC_mouse_button0") - .addEventListener('click', () => UI.setMouseButton(1)); - document.getElementById("noVNC_mouse_button1") - .addEventListener('click', () => UI.setMouseButton(2)); - document.getElementById("noVNC_mouse_button2") - .addEventListener('click', () => UI.setMouseButton(4)); - document.getElementById("noVNC_mouse_button4") - .addEventListener('click', () => UI.setMouseButton(0)); - document.getElementById("noVNC_keyboard_button") - .addEventListener('click', UI.toggleVirtualKeyboard); - - UI.touchKeyboard = new Keyboard(document.getElementById('noVNC_keyboardinput')); - UI.touchKeyboard.onkeyevent = UI.keyEvent; - UI.touchKeyboard.grab(); - 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', () => false); - - document.documentElement - .addEventListener('mousedown', UI.keepVirtualKeyboard, true); - - document.getElementById("noVNC_control_bar") - .addEventListener('touchstart', UI.activateControlbar); - document.getElementById("noVNC_control_bar") - .addEventListener('touchmove', UI.activateControlbar); - document.getElementById("noVNC_control_bar") - .addEventListener('touchend', UI.activateControlbar); - document.getElementById("noVNC_control_bar") - .addEventListener('input', UI.activateControlbar); - - document.getElementById("noVNC_control_bar") - .addEventListener('touchstart', UI.keepControlbar); - document.getElementById("noVNC_control_bar") - .addEventListener('input', UI.keepControlbar); - - document.getElementById("noVNC_control_bar_handle") - .addEventListener('touchstart', UI.controlbarHandleMouseDown); - document.getElementById("noVNC_control_bar_handle") - .addEventListener('touchend', UI.controlbarHandleMouseUp); - document.getElementById("noVNC_control_bar_handle") - .addEventListener('touchmove', UI.dragControlbarHandle); - }, - - addExtraKeysHandlers() { - document.getElementById("noVNC_toggle_extra_keys_button") - .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") - .addEventListener('click', UI.sendTab); - document.getElementById("noVNC_send_esc_button") - .addEventListener('click', UI.sendEsc); - document.getElementById("noVNC_send_ctrl_alt_del_button") - .addEventListener('click', UI.sendCtrlAltDel); - }, - - addMachineHandlers() { - document.getElementById("noVNC_shutdown_button") - .addEventListener('click', () => UI.rfb.machineShutdown()); - document.getElementById("noVNC_reboot_button") - .addEventListener('click', () => UI.rfb.machineReboot()); - document.getElementById("noVNC_reset_button") - .addEventListener('click', () => UI.rfb.machineReset()); - document.getElementById("noVNC_power_button") - .addEventListener('click', UI.togglePowerPanel); - }, - - addConnectionControlHandlers() { - 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); - }, - - addClipboardHandlers() { - document.getElementById("noVNC_clipboard_button") - .addEventListener('click', UI.toggleClipboardPanel); - document.getElementById("noVNC_clipboard_text") - .addEventListener('change', UI.clipboardSend); - document.getElementById("noVNC_clipboard_clear_button") - .addEventListener('click', UI.clipboardClear); - }, - - // Add a call to save settings when the element changes, - // unless the optional parameter changeFunc is used instead. - addSettingChangeHandler(name, changeFunc) { - const settingElem = document.getElementById("noVNC_setting_" + name); - if (changeFunc === undefined) { - changeFunc = () => UI.saveSetting(name); - } - settingElem.addEventListener('change', changeFunc); - }, - - addSettingsHandlers() { - document.getElementById("noVNC_settings_button") - .addEventListener('click', UI.toggleSettingsPanel); - - UI.addSettingChangeHandler('encrypt'); - UI.addSettingChangeHandler('resize'); - UI.addSettingChangeHandler('resize', UI.applyResizeMode); - UI.addSettingChangeHandler('resize', UI.updateViewClip); - UI.addSettingChangeHandler('view_clip'); - UI.addSettingChangeHandler('view_clip', UI.updateViewClip); - 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'); - UI.addSettingChangeHandler('repeaterID'); - UI.addSettingChangeHandler('logging'); - UI.addSettingChangeHandler('logging', UI.updateLogging); - UI.addSettingChangeHandler('reconnect'); - UI.addSettingChangeHandler('reconnect_delay'); - }, - - addFullscreenHandlers() { - document.getElementById("noVNC_fullscreen_button") - .addEventListener('click', UI.toggleFullscreen); - - window.addEventListener('fullscreenchange', UI.updateFullscreenButton); - window.addEventListener('mozfullscreenchange', UI.updateFullscreenButton); - window.addEventListener('webkitfullscreenchange', UI.updateFullscreenButton); - window.addEventListener('msfullscreenchange', UI.updateFullscreenButton); - }, - -/* ------^------- - * /EVENT HANDLERS - * ============== - * VISUAL - * ------v------*/ - - // Disable/enable controls depending on connection state - updateVisualState(state) { - - document.documentElement.classList.remove("noVNC_connecting"); - document.documentElement.classList.remove("noVNC_connected"); - document.documentElement.classList.remove("noVNC_disconnecting"); - document.documentElement.classList.remove("noVNC_reconnecting"); - - const transition_elem = document.getElementById("noVNC_transition_text"); - switch (state) { - case 'init': - break; - case 'connecting': - transition_elem.textContent = _("Connecting..."); - document.documentElement.classList.add("noVNC_connecting"); - break; - case 'connected': - document.documentElement.classList.add("noVNC_connected"); - break; - case 'disconnecting': - transition_elem.textContent = _("Disconnecting..."); - document.documentElement.classList.add("noVNC_disconnecting"); - break; - case 'disconnected': - break; - case 'reconnecting': - transition_elem.textContent = _("Reconnecting..."); - document.documentElement.classList.add("noVNC_reconnecting"); - break; - default: - Log.Error("Invalid visual state: " + state); - UI.showStatus(_("Internal error"), 'error'); - return; - } - - if (UI.connected) { - UI.updateViewClip(); - - UI.disableSetting('encrypt'); - UI.disableSetting('shared'); - UI.disableSetting('host'); - UI.disableSetting('port'); - UI.disableSetting('path'); - UI.disableSetting('repeaterID'); - UI.setMouseButton(1); - - // Hide the controlbar after 2 seconds - UI.closeControlbarTimeout = setTimeout(UI.closeControlbar, 2000); - } else { - UI.enableSetting('encrypt'); - UI.enableSetting('shared'); - UI.enableSetting('host'); - UI.enableSetting('port'); - UI.enableSetting('path'); - UI.enableSetting('repeaterID'); - UI.updatePowerButton(); - UI.keepControlbar(); - } - - // State change closes the password dialog - document.getElementById('noVNC_password_dlg') - .classList.remove('noVNC_open'); - }, - - showStatus(text, status_type, time) { - const statusElem = document.getElementById('noVNC_status'); - - clearTimeout(UI.statusTimeout); - - if (typeof status_type === 'undefined') { - status_type = 'normal'; - } - - // Don't overwrite more severe visible statuses and never - // errors. Only shows the first error. - let visible_status_type = 'none'; - if (statusElem.classList.contains("noVNC_open")) { - if (statusElem.classList.contains("noVNC_status_error")) { - visible_status_type = 'error'; - } else if (statusElem.classList.contains("noVNC_status_warn")) { - visible_status_type = 'warn'; - } else { - visible_status_type = 'normal'; - } - } - if (visible_status_type === 'error' || - (visible_status_type === 'warn' && status_type === 'normal')) { - return; - } - - switch (status_type) { - case 'error': - statusElem.classList.remove("noVNC_status_warn"); - statusElem.classList.remove("noVNC_status_normal"); - statusElem.classList.add("noVNC_status_error"); - break; - case 'warning': - case 'warn': - statusElem.classList.remove("noVNC_status_error"); - statusElem.classList.remove("noVNC_status_normal"); - statusElem.classList.add("noVNC_status_warn"); - break; - case 'normal': - case 'info': - default: - statusElem.classList.remove("noVNC_status_error"); - statusElem.classList.remove("noVNC_status_warn"); - statusElem.classList.add("noVNC_status_normal"); - break; - } - - statusElem.textContent = text; - statusElem.classList.add("noVNC_open"); - - // If no time was specified, show the status for 1.5 seconds - if (typeof time === 'undefined') { - time = 1500; - } - - // Error messages do not timeout - if (status_type !== 'error') { - UI.statusTimeout = window.setTimeout(UI.hideStatus, time); - } - }, - - hideStatus() { - clearTimeout(UI.statusTimeout); - document.getElementById('noVNC_status').classList.remove("noVNC_open"); - }, - - activateControlbar(event) { - clearTimeout(UI.idleControlbarTimeout); - // We manipulate the anchor instead of the actual control - // bar in order to avoid creating new a stacking group - document.getElementById('noVNC_control_bar_anchor') - .classList.remove("noVNC_idle"); - UI.idleControlbarTimeout = window.setTimeout(UI.idleControlbar, 2000); - }, - - idleControlbar() { - document.getElementById('noVNC_control_bar_anchor') - .classList.add("noVNC_idle"); - }, - - keepControlbar() { - clearTimeout(UI.closeControlbarTimeout); - }, - - openControlbar() { - document.getElementById('noVNC_control_bar') - .classList.add("noVNC_open"); - }, - - closeControlbar() { - UI.closeAllPanels(); - document.getElementById('noVNC_control_bar') - .classList.remove("noVNC_open"); - }, - - toggleControlbar() { - if (document.getElementById('noVNC_control_bar') - .classList.contains("noVNC_open")) { - UI.closeControlbar(); - } else { - UI.openControlbar(); - } - }, - - toggleControlbarSide() { - // Temporarily disable animation, if bar is displayed, to avoid weird - // movement. The transitionend-event will not fire when display=none. - const bar = document.getElementById('noVNC_control_bar'); - const barDisplayStyle = window.getComputedStyle(bar).display; - if (barDisplayStyle !== 'none') { - bar.style.transitionDuration = '0s'; - bar.addEventListener('transitionend', () => bar.style.transitionDuration = ''); - } - - const 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; - }, - - showControlbarHint(show) { - const hint = document.getElementById('noVNC_control_bar_hint'); - if (show) { - hint.classList.add("noVNC_active"); - } else { - hint.classList.remove("noVNC_active"); - } - }, - - dragControlbarHandle(e) { - if (!UI.controlbarGrabbed) return; - - const ptr = getPointerEvent(e); - - const 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) { - const dragDistance = Math.abs(ptr.clientY - UI.controlbarMouseDownClientY); - - if (dragDistance < dragThreshold) return; - - UI.controlbarDrag = true; - } - - const eventY = ptr.clientY - UI.controlbarMouseDownOffsetY; - - UI.moveControlbarHandle(eventY); - - e.preventDefault(); - e.stopPropagation(); - UI.keepControlbar(); - UI.activateControlbar(); - }, - - // Move the handle but don't allow any position outside the bounds - moveControlbarHandle(viewportRelativeY) { - const handle = document.getElementById("noVNC_control_bar_handle"); - const handleHeight = handle.getBoundingClientRect().height; - const controlbarBounds = document.getElementById("noVNC_control_bar") - .getBoundingClientRect(); - const margin = 10; - - // These heights need to be non-zero for the below logic to work - if (handleHeight === 0 || controlbarBounds.height === 0) { - return; - } - - let newY = viewportRelativeY; - - // Check if the coordinates are outside the control bar - if (newY < controlbarBounds.top + margin) { - // Force coordinates to be below the top of the control bar - newY = controlbarBounds.top + margin; - - } else if (newY > controlbarBounds.top + - controlbarBounds.height - handleHeight - margin) { - // Force coordinates to be above the bottom of the control bar - newY = controlbarBounds.top + - controlbarBounds.height - handleHeight - margin; - } - - // Corner case: control bar too small for stable position - if (controlbarBounds.height < (handleHeight + margin * 2)) { - newY = controlbarBounds.top + - (controlbarBounds.height - handleHeight) / 2; - } - - // The transform needs coordinates that are relative to the parent - const parentRelativeY = newY - controlbarBounds.top; - handle.style.transform = "translateY(" + parentRelativeY + "px)"; - }, - - updateControlbarHandle() { - // Since the control bar is fixed on the viewport and not the page, - // the move function expects coordinates relative the the viewport. - const handle = document.getElementById("noVNC_control_bar_handle"); - const handleBounds = handle.getBoundingClientRect(); - UI.moveControlbarHandle(handleBounds.top); - }, - - controlbarHandleMouseUp(e) { - if ((e.type == "mouseup") && (e.button != 0)) return; - - // mouseup and mousedown on the same place toggles the controlbar - if (UI.controlbarGrabbed && !UI.controlbarDrag) { - UI.toggleControlbar(); - e.preventDefault(); - e.stopPropagation(); - UI.keepControlbar(); - UI.activateControlbar(); - } - UI.controlbarGrabbed = false; - UI.showControlbarHint(false); - }, - - controlbarHandleMouseDown(e) { - if ((e.type == "mousedown") && (e.button != 0)) return; - - const ptr = getPointerEvent(e); - - const handle = document.getElementById("noVNC_control_bar_handle"); - const bounds = handle.getBoundingClientRect(); - - // Touch events have implicit capture - if (e.type === "mousedown") { - setCapture(handle); - } - - UI.controlbarGrabbed = true; - UI.controlbarDrag = false; - - UI.showControlbarHint(true); - - UI.controlbarMouseDownClientY = ptr.clientY; - UI.controlbarMouseDownOffsetY = ptr.clientY - bounds.top; - e.preventDefault(); - e.stopPropagation(); - UI.keepControlbar(); - UI.activateControlbar(); - }, - - toggleExpander(e) { - if (this.classList.contains("noVNC_open")) { - this.classList.remove("noVNC_open"); - } else { - this.classList.add("noVNC_open"); - } - }, - -/* ------^------- - * /VISUAL - * ============== - * SETTINGS - * ------v------*/ - - // Initial page load read/initialization of settings - initSetting(name, defVal) { - // Check Query string followed by cookie - let val = WebUtil.getConfigVar(name); - if (val === null) { - val = WebUtil.readSetting(name, defVal); - } - WebUtil.setSetting(name, val); - UI.updateSetting(name); - return val; - }, - - // Set the new value, update and disable form control setting - forceSetting(name, val) { - WebUtil.setSetting(name, val); - UI.updateSetting(name); - UI.disableSetting(name); - }, - - // Update cookie and form control setting. If value is not set, then - // updates from control to current cookie setting. - updateSetting(name) { - - // Update the settings control - let value = UI.getSetting(name); - - const ctrl = document.getElementById('noVNC_setting_' + name); - if (ctrl.type === 'checkbox') { - ctrl.checked = value; - - } else if (typeof ctrl.options !== 'undefined') { - for (let 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(name) { - const ctrl = document.getElementById('noVNC_setting_' + name); - let val; - 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); - //Log.Debug("Setting saved '" + name + "=" + val + "'"); - return val; - }, - - // Read form control compatible setting from cookie - getSetting(name) { - 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}) { - val = false; - } else { - val = true; - } - } - return val; - }, - - // 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(name) { - const ctrl = document.getElementById('noVNC_setting_' + name); - ctrl.disabled = true; - ctrl.label.classList.add('noVNC_disabled'); - }, - - enableSetting(name) { - const ctrl = document.getElementById('noVNC_setting_' + name); - ctrl.disabled = false; - ctrl.label.classList.remove('noVNC_disabled'); - }, - -/* ------^------- - * /SETTINGS - * ============== - * PANELS - * ------v------*/ - - closeAllPanels() { - UI.closeSettingsPanel(); - UI.closePowerPanel(); - UI.closeClipboardPanel(); - UI.closeExtraKeys(); - }, - -/* ------^------- - * /PANELS - * ============== - * SETTINGS (panel) - * ------v------*/ - - openSettingsPanel() { - UI.closeAllPanels(); - UI.openControlbar(); - - // Refresh UI elements from saved cookies - UI.updateSetting('encrypt'); - UI.updateSetting('view_clip'); - UI.updateSetting('resize'); - UI.updateSetting('shared'); - UI.updateSetting('view_only'); - UI.updateSetting('path'); - UI.updateSetting('repeaterID'); - UI.updateSetting('logging'); - UI.updateSetting('reconnect'); - UI.updateSetting('reconnect_delay'); - - document.getElementById('noVNC_settings') - .classList.add("noVNC_open"); - document.getElementById('noVNC_settings_button') - .classList.add("noVNC_selected"); - }, - - closeSettingsPanel() { - document.getElementById('noVNC_settings') - .classList.remove("noVNC_open"); - document.getElementById('noVNC_settings_button') - .classList.remove("noVNC_selected"); - }, - - toggleSettingsPanel() { - if (document.getElementById('noVNC_settings') - .classList.contains("noVNC_open")) { - UI.closeSettingsPanel(); - } else { - UI.openSettingsPanel(); - } - }, - -/* ------^------- - * /SETTINGS - * ============== - * POWER - * ------v------*/ - - openPowerPanel() { - UI.closeAllPanels(); - UI.openControlbar(); - - document.getElementById('noVNC_power') - .classList.add("noVNC_open"); - document.getElementById('noVNC_power_button') - .classList.add("noVNC_selected"); - }, - - closePowerPanel() { - document.getElementById('noVNC_power') - .classList.remove("noVNC_open"); - document.getElementById('noVNC_power_button') - .classList.remove("noVNC_selected"); - }, - - togglePowerPanel() { - if (document.getElementById('noVNC_power') - .classList.contains("noVNC_open")) { - UI.closePowerPanel(); - } else { - UI.openPowerPanel(); - } - }, - - // Disable/enable power button - updatePowerButton() { - if (UI.connected && - UI.rfb.capabilities.power && - !UI.rfb.viewOnly) { - document.getElementById('noVNC_power_button') - .classList.remove("noVNC_hidden"); - } else { - document.getElementById('noVNC_power_button') - .classList.add("noVNC_hidden"); - // Close power panel if open - UI.closePowerPanel(); - } - }, - -/* ------^------- - * /POWER - * ============== - * CLIPBOARD - * ------v------*/ - - openClipboardPanel() { - UI.closeAllPanels(); - UI.openControlbar(); - - document.getElementById('noVNC_clipboard') - .classList.add("noVNC_open"); - document.getElementById('noVNC_clipboard_button') - .classList.add("noVNC_selected"); - }, - - closeClipboardPanel() { - document.getElementById('noVNC_clipboard') - .classList.remove("noVNC_open"); - document.getElementById('noVNC_clipboard_button') - .classList.remove("noVNC_selected"); - }, - - toggleClipboardPanel() { - if (document.getElementById('noVNC_clipboard') - .classList.contains("noVNC_open")) { - UI.closeClipboardPanel(); - } else { - UI.openClipboardPanel(); - } - }, - - clipboardReceive(e) { - Log.Debug(">> UI.clipboardReceive: " + e.detail.text.substr(0, 40) + "..."); - document.getElementById('noVNC_clipboard_text').value = e.detail.text; - Log.Debug("<< UI.clipboardReceive"); - }, - - clipboardClear() { - document.getElementById('noVNC_clipboard_text').value = ""; - UI.rfb.clipboardPasteFrom(""); - }, - - clipboardSend() { - const text = document.getElementById('noVNC_clipboard_text').value; - Log.Debug(">> UI.clipboardSend: " + text.substr(0, 40) + "..."); - UI.rfb.clipboardPasteFrom(text); - Log.Debug("<< UI.clipboardSend"); - }, - -/* ------^------- - * /CLIPBOARD - * ============== - * CONNECTION - * ------v------*/ - - openConnectPanel() { - document.getElementById('noVNC_connect_dlg') - .classList.add("noVNC_open"); - }, - - closeConnectPanel() { - document.getElementById('noVNC_connect_dlg') - .classList.remove("noVNC_open"); - }, - - connect(event, password) { - - // Ignore when rfb already exists - if (typeof UI.rfb !== 'undefined') { - return; - } - - const host = UI.getSetting('host'); - const port = UI.getSetting('port'); - const path = UI.getSetting('path'); - - if (typeof password === 'undefined') { - password = WebUtil.getConfigVar('password'); - UI.reconnect_password = password; - } - - if (password === null) { - password = undefined; - } - - UI.hideStatus(); - - if (!host) { - Log.Error("Can't connect when host is: " + host); - UI.showStatus(_("Must set host"), 'error'); - return; - } - - UI.closeAllPanels(); - UI.closeConnectPanel(); - - UI.updateVisualState('connecting'); - - let url; - - url = UI.getSetting('encrypt') ? 'wss' : 'ws'; - - url += '://' + host; - 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); - UI.rfb.addEventListener("disconnect", UI.disconnectFinished); - UI.rfb.addEventListener("credentialsrequired", UI.credentials); - UI.rfb.addEventListener("securityfailure", UI.securityFailed); - UI.rfb.addEventListener("capabilities", UI.updatePowerButton); - UI.rfb.addEventListener("clipboard", UI.clipboardReceive); - UI.rfb.addEventListener("bell", UI.bell); - UI.rfb.addEventListener("desktopname", UI.updateDesktopName); - UI.rfb.clipViewport = UI.getSetting('view_clip'); - UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale'; - UI.rfb.resizeSession = UI.getSetting('resize') === 'remote'; - - UI.updateViewOnly(); // requires UI.rfb - }, - - disconnect() { - UI.closeAllPanels(); - UI.rfb.disconnect(); - - UI.connected = false; - - // Disable automatic reconnecting - UI.inhibit_reconnect = true; - - UI.updateVisualState('disconnecting'); - - // Don't display the connection settings until we're actually disconnected - }, - - reconnect() { - 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); - }, - - cancelReconnect() { - if (UI.reconnect_callback !== null) { - clearTimeout(UI.reconnect_callback); - UI.reconnect_callback = null; - } - - UI.updateVisualState('disconnected'); - - UI.openControlbar(); - UI.openConnectPanel(); - }, - - connectFinished(e) { - UI.connected = true; - UI.inhibit_reconnect = false; - - let msg; - if (UI.getSetting('encrypt')) { - msg = _("Connected (encrypted) to ") + UI.desktopName; - } else { - msg = _("Connected (unencrypted) to ") + UI.desktopName; - } - UI.showStatus(msg); - UI.updateVisualState('connected'); - - // Do this last because it can only be used on rendered elements - UI.rfb.focus(); - }, - - disconnectFinished(e) { - const wasConnected = UI.connected; - - // This variable is ideally set when disconnection starts, but - // when the disconnection isn't clean or if it is initiated by - // the server, we need to do it here as well since - // UI.disconnect() won't be used in those cases. - UI.connected = false; - - UI.rfb = undefined; - - if (!e.detail.clean) { - UI.updateVisualState('disconnected'); - if (wasConnected) { - UI.showStatus(_("Something went wrong, connection is closed"), - 'error'); - } else { - UI.showStatus(_("Failed to connect to server"), 'error'); - } - } else if (UI.getSetting('reconnect', false) === true && !UI.inhibit_reconnect) { - UI.updateVisualState('reconnecting'); - - const delay = parseInt(UI.getSetting('reconnect_delay')); - UI.reconnect_callback = setTimeout(UI.reconnect, delay); - return; - } else { - UI.updateVisualState('disconnected'); - UI.showStatus(_("Disconnected"), 'normal'); - } - - UI.openControlbar(); - UI.openConnectPanel(); - }, - - securityFailed(e) { - let msg = ""; - // On security failures we might get a string with a reason - // directly from the server. Note that we can't control if - // this string is translated or not. - if ('reason' in e.detail) { - msg = _("New connection has been rejected with reason: ") + - e.detail.reason; - } else { - msg = _("New connection has been rejected"); - } - UI.showStatus(msg, 'error'); - }, - -/* ------^------- - * /CONNECTION - * ============== - * PASSWORD - * ------v------*/ - - credentials(e) { - // FIXME: handle more types - document.getElementById('noVNC_password_dlg') - .classList.add('noVNC_open'); - - setTimeout(() => document - .getElementById('noVNC_password_input').focus(), 100); - - Log.Warn("Server asked for a password"); - UI.showStatus(_("Password is required"), "warning"); - }, - - setPassword(e) { - // Prevent actually submitting the form - e.preventDefault(); - - const inputElem = document.getElementById('noVNC_password_input'); - const password = inputElem.value; - // Clear the input after reading the password - inputElem.value = ""; - UI.rfb.sendCredentials({ password: password }); - UI.reconnect_password = password; - document.getElementById('noVNC_password_dlg') - .classList.remove('noVNC_open'); - }, - -/* ------^------- - * /PASSWORD - * ============== - * FULLSCREEN - * ------v------*/ - - toggleFullscreen() { - if (document.fullscreenElement || // alternative standard method - document.mozFullScreenElement || // currently working methods - document.webkitFullscreenElement || - document.msFullscreenElement) { - if (document.exitFullscreen) { - document.exitFullscreen(); - } else if (document.mozCancelFullScreen) { - document.mozCancelFullScreen(); - } else if (document.webkitExitFullscreen) { - document.webkitExitFullscreen(); - } else if (document.msExitFullscreen) { - document.msExitFullscreen(); - } - } else { - if (document.documentElement.requestFullscreen) { - document.documentElement.requestFullscreen(); - } else if (document.documentElement.mozRequestFullScreen) { - document.documentElement.mozRequestFullScreen(); - } else if (document.documentElement.webkitRequestFullscreen) { - document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); - } else if (document.body.msRequestFullscreen) { - document.body.msRequestFullscreen(); - } - } - UI.updateFullscreenButton(); - }, - - updateFullscreenButton() { - if (document.fullscreenElement || // alternative standard method - document.mozFullScreenElement || // currently working methods - document.webkitFullscreenElement || - document.msFullscreenElement ) { - document.getElementById('noVNC_fullscreen_button') - .classList.add("noVNC_selected"); - } else { - document.getElementById('noVNC_fullscreen_button') - .classList.remove("noVNC_selected"); - } - }, - -/* ------^------- - * /FULLSCREEN - * ============== - * RESIZE - * ------v------*/ - - // Apply remote resizing or local scaling - applyResizeMode() { - if (!UI.rfb) return; - - UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale'; - UI.rfb.resizeSession = UI.getSetting('resize') === 'remote'; - }, - -/* ------^------- - * /RESIZE - * ============== - * VIEW CLIPPING - * ------v------*/ - - // Update viewport clipping property for the connection. The normal - // case is to get the value from the setting. There are special cases - // for when the viewport is scaled or when a touch device is used. - updateViewClip() { - if (!UI.rfb) return; - - const scaling = UI.getSetting('resize') === 'scale'; - - if (scaling) { - // Can't be clipping if viewport is scaled to fit - UI.forceSetting('view_clip', false); - UI.rfb.clipViewport = false; - } else if (isIOS() || isAndroid()) { - // iOS and Android usually have shit scrollbars - UI.forceSetting('view_clip', true); - UI.rfb.clipViewport = true; - } else { - UI.enableSetting('view_clip'); - UI.rfb.clipViewport = UI.getSetting('view_clip'); - } - - // Changing the viewport may change the state of - // the dragging button - UI.updateViewDrag(); - }, - -/* ------^------- - * /VIEW CLIPPING - * ============== - * VIEWDRAG - * ------v------*/ - - toggleViewDrag() { - if (!UI.rfb) return; - - UI.rfb.dragViewport = !UI.rfb.dragViewport; - UI.updateViewDrag(); - }, - - updateViewDrag() { - if (!UI.connected) return; - - const viewDragButton = document.getElementById('noVNC_view_drag_button'); - - if (!UI.rfb.clipViewport && UI.rfb.dragViewport) { - // We are no longer clipping the viewport. Make sure - // viewport drag isn't active when it can't be used. - UI.rfb.dragViewport = false; - } - - if (UI.rfb.dragViewport) { - viewDragButton.classList.add("noVNC_selected"); - } else { - viewDragButton.classList.remove("noVNC_selected"); - } - - // Different behaviour for touch vs non-touch - // The button is disabled instead of hidden on touch devices - if (isTouchDevice) { - viewDragButton.classList.remove("noVNC_hidden"); - - if (UI.rfb.clipViewport) { - viewDragButton.disabled = false; - } else { - viewDragButton.disabled = true; - } - } else { - viewDragButton.disabled = false; - - if (UI.rfb.clipViewport) { - viewDragButton.classList.remove("noVNC_hidden"); - } else { - viewDragButton.classList.add("noVNC_hidden"); - } - } - }, - -/* ------^------- - * /VIEWDRAG - * ============== - * KEYBOARD - * ------v------*/ - - showVirtualKeyboard() { - if (!isTouchDevice) return; - - const input = document.getElementById('noVNC_keyboardinput'); - - if (document.activeElement == input) return; - - input.focus(); - - try { - const l = input.value.length; - // Move the caret to the end - input.setSelectionRange(l, l); - } catch (err) { - // setSelectionRange is undefined in Google Chrome - } - }, - - hideVirtualKeyboard() { - if (!isTouchDevice) return; - - const input = document.getElementById('noVNC_keyboardinput'); - - if (document.activeElement != input) return; - - input.blur(); - }, - - toggleVirtualKeyboard() { - if (document.getElementById('noVNC_keyboard_button') - .classList.contains("noVNC_selected")) { - UI.hideVirtualKeyboard(); - } else { - UI.showVirtualKeyboard(); - } - }, - - onfocusVirtualKeyboard(event) { - document.getElementById('noVNC_keyboard_button') - .classList.add("noVNC_selected"); - if (UI.rfb) { - UI.rfb.focusOnClick = false; - } - }, - - onblurVirtualKeyboard(event) { - document.getElementById('noVNC_keyboard_button') - .classList.remove("noVNC_selected"); - if (UI.rfb) { - UI.rfb.focusOnClick = true; - } - }, - - keepVirtualKeyboard(event) { - const 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() { - const kbi = document.getElementById('noVNC_keyboardinput'); - kbi.value = new Array(UI.defaultKeyboardinputLen).join("_"); - UI.lastKeyboardinput = kbi.value; - }, - - keyEvent(keysym, code, down) { - if (!UI.rfb) return; - - UI.rfb.sendKey(keysym, code, down); - }, - - // 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(event) { - - if (!UI.rfb) return; - - const newValue = event.target.value; - - if (!UI.lastKeyboardinput) { - UI.keyboardinputReset(); - } - const oldValue = UI.lastKeyboardinput; - - let 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; - } - const oldLen = oldValue.length; - - let inputs = newLen - oldLen; - let backspaces = inputs < 0 ? -inputs : 0; - - // Compare the old string with the new to account for - // text-corrections or other input that modify existing text - for (let 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 (let i = 0; i < backspaces; i++) { - UI.rfb.sendKey(KeyTable.XK_BackSpace, "Backspace"); - } - for (let i = newLen - inputs; i < newLen; i++) { - UI.rfb.sendKey(keysyms.lookup(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(event.target.focus.bind(event.target), 0); - } else { - UI.lastKeyboardinput = newValue; - } - }, - -/* ------^------- - * /KEYBOARD - * ============== - * EXTRA KEYS - * ------v------*/ - - openExtraKeys() { - UI.closeAllPanels(); - UI.openControlbar(); - - document.getElementById('noVNC_modifiers') - .classList.add("noVNC_open"); - document.getElementById('noVNC_toggle_extra_keys_button') - .classList.add("noVNC_selected"); - }, - - closeExtraKeys() { - document.getElementById('noVNC_modifiers') - .classList.remove("noVNC_open"); - document.getElementById('noVNC_toggle_extra_keys_button') - .classList.remove("noVNC_selected"); - }, - - toggleExtraKeys() { - if (document.getElementById('noVNC_modifiers') - .classList.contains("noVNC_open")) { - UI.closeExtraKeys(); - } else { - UI.openExtraKeys(); - } - }, - - sendEsc() { - UI.rfb.sendKey(KeyTable.XK_Escape, "Escape"); - }, - - sendTab() { - UI.rfb.sendKey(KeyTable.XK_Tab); - }, - - toggleCtrl() { - const btn = document.getElementById('noVNC_toggle_ctrl_button'); - if (btn.classList.contains("noVNC_selected")) { - UI.rfb.sendKey(KeyTable.XK_Control_L, "ControlLeft", false); - btn.classList.remove("noVNC_selected"); - } else { - UI.rfb.sendKey(KeyTable.XK_Control_L, "ControlLeft", true); - btn.classList.add("noVNC_selected"); - } - }, - - 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.sendKey(KeyTable.XK_Alt_L, "AltLeft", false); - btn.classList.remove("noVNC_selected"); - } else { - UI.rfb.sendKey(KeyTable.XK_Alt_L, "AltLeft", true); - btn.classList.add("noVNC_selected"); - } - }, - - sendCtrlAltDel() { - UI.rfb.sendCtrlAltDel(); - }, - -/* ------^------- - * /EXTRA KEYS - * ============== - * MISC - * ------v------*/ - - setMouseButton(num) { - const view_only = UI.rfb.viewOnly; - if (UI.rfb && !view_only) { - UI.rfb.touchButton = num; - } - - const blist = [0, 1, 2, 4]; - for (let b = 0; b < blist.length; b++) { - const 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"); - } - } - }, - - updateViewOnly() { - if (!UI.rfb) return; - UI.rfb.viewOnly = UI.getSetting('view_only'); - - // Hide input related buttons in view only mode - if (UI.rfb.viewOnly) { - document.getElementById('noVNC_keyboard_button') - .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'); - } - }, - - updateShowDotCursor() { - if (!UI.rfb) return; - UI.rfb.showDotCursor = UI.getSetting('show_dot'); - }, - - updateLogging() { - WebUtil.init_logging(UI.getSetting('logging')); - }, - - updateDesktopName(e) { - UI.desktopName = e.detail.name; - // Display the desktop name in the document title - document.title = e.detail.name + " - noVNC"; - }, - - bell(e) { - if (WebUtil.getConfigVar('bell', 'on') === 'on') { - const promise = document.getElementById('noVNC_bell').play(); - // The standards disagree on the return value here - if (promise) { - promise.catch((e) => { - if (e.name === "NotAllowedError") { - // Ignore when the browser doesn't let us play audio. - // It is common that the browsers require audio to be - // initiated from a user action. - } else { - Log.Error("Unable to play bell: " + e); - } - }); - } - } - }, - - //Helper to add options to dropdown. - addOption(selectbox, text, value) { - const optn = document.createElement("OPTION"); - optn.text = text; - optn.value = value; - selectbox.options.add(optn); - }, - -/* ------^------- - * /MISC - * ============== - */ -}; - -// Set up translations -const LINGUAS = ["ru", "cs", "de", "el", "es", "ko", "nl", "pl", "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 { - UI.prime(); -} - -export default UI;