]> git.proxmox.com Git - mirror_novnc.git/blobdiff - app/ui.js
Merge pull request #996 from PeterDaveHelloKitchen/zh-tw-translation
[mirror_novnc.git] / app / ui.js
index 0ee0c00b8d4984d101efb63e86fc101110d365ad..0991c708ea41006880912a86a0d5ff63a086886f 100644 (file)
--- a/app/ui.js
+++ b/app/ui.js
@@ -12,7 +12,7 @@
 /* global window, document.getElementById, Util, WebUtil, RFB, Display */
 
 import * as Log from '../core/util/logging.js';
-import _, { l10n } from '../core/util/localization.js';
+import _, { l10n } from './localization.js';
 import { isTouchDevice } from '../core/util/browsers.js';
 import { setCapture, getPointerEvent } from '../core/util/events.js';
 import KeyTable from "../core/input/keysym.js";
@@ -27,7 +27,6 @@ var UI = {
     connected: false,
     desktopName: "",
 
-    resizeTimeout: null,
     statusTimeout: null,
     hideKeyboardTimeout: null,
     idleControlbarTimeout: null,
@@ -87,7 +86,6 @@ var UI = {
         UI.initFullscreen();
 
         // Setup event handlers
-        UI.addResizeHandlers();
         UI.addControlbarHandlers();
         UI.addTouchSpecificHandlers();
         UI.addExtraKeysHandlers();
@@ -103,8 +101,6 @@ var UI = {
 
         UI.openControlbar();
 
-        UI.updateViewClip();
-
         UI.updateVisualState('init');
 
         document.documentElement.classList.remove("noVNC_loading");
@@ -205,11 +201,6 @@ var UI = {
 * 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);
@@ -432,7 +423,6 @@ var UI = {
             UI.disableSetting('port');
             UI.disableSetting('path');
             UI.disableSetting('repeaterID');
-            UI.updateViewClip();
             UI.setMouseButton(1);
 
             // Hide the controlbar after 2 seconds
@@ -479,21 +469,40 @@ var UI = {
             status_type = 'normal';
         }
 
-        statusElem.classList.remove("noVNC_status_normal");
-        statusElem.classList.remove("noVNC_status_warn");
-        statusElem.classList.remove("noVNC_status_error");
+        // 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 'error':
-                statusElem.classList.add("noVNC_status_error");
-                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;
         }
@@ -980,6 +989,12 @@ var UI = {
     },
 
     connect: function(event, password) {
+
+        // Ignore when rfb already exists
+        if (typeof UI.rfb !== 'undefined') {
+            return;
+        }
+
         var host = UI.getSetting('host');
         var port = UI.getSetting('port');
         var path = UI.getSetting('path');
@@ -993,6 +1008,8 @@ var UI = {
             password = undefined;
         }
 
+        UI.hideStatus();
+
         if (!host) {
             Log.Error("Can't connect when host is: " + host);
             UI.showStatus(_("Must set host"), 'error');
@@ -1002,10 +1019,6 @@ var UI = {
         UI.closeAllPanels();
         UI.closeConnectPanel();
 
-        UI.updateVisualState('connecting');
-
-        UI.updateViewOnly();
-
         var url;
 
         url = UI.getSetting('encrypt') ? 'wss' : 'ws';
@@ -1016,18 +1029,24 @@ var UI = {
         }
         url += '/' + path;
 
-        UI.rfb = new RFB(document.getElementById('noVNC_canvas'), url,
+        UI.rfb = new RFB(document.getElementById('noVNC_container'), url,
                          { shared: UI.getSetting('shared'),
                            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("capabilities", function () { UI.updatePowerButton(); UI.initialResize(); });
+        UI.rfb.addEventListener("securityfailure", UI.securityFailed);
+        UI.rfb.addEventListener("capabilities", function () { UI.updatePowerButton(); });
         UI.rfb.addEventListener("clipboard", UI.clipboardReceive);
         UI.rfb.addEventListener("bell", UI.bell);
-        UI.rfb.addEventListener("fbresize", UI.updateSessionSize);
         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.updateVisualState('connecting');
+        UI.updateViewOnly();
     },
 
     disconnect: function() {
@@ -1041,6 +1060,8 @@ var UI = {
 
         UI.updateVisualState('disconnecting');
 
+        UI.rfb = undefined;
+
         // Don't display the connection settings until we're actually disconnected
     },
 
@@ -1055,10 +1076,21 @@ var UI = {
         UI.connect(null, UI.reconnect_password);
     },
 
+    cancelReconnect: function() {
+        if (UI.reconnect_callback !== null) {
+            clearTimeout(UI.reconnect_callback);
+            UI.reconnect_callback = null;
+        }
+
+        UI.updateVisualState('disconnected');
+
+        UI.openControlbar();
+        UI.openConnectPanel();
+    },
+
     connectFinished: function (e) {
         UI.connected = true;
         UI.inhibit_reconnect = false;
-        UI.doneInitialResize = false;
 
         let msg;
         if (UI.getSetting('encrypt')) {
@@ -1070,19 +1102,26 @@ var UI = {
         UI.updateVisualState('connected');
 
         // Do this last because it can only be used on rendered elements
-        document.getElementById('noVNC_canvas').focus();
+        UI.rfb.focus();
     },
 
     disconnectFinished: function (e) {
+        let 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;
 
-        if (typeof e.detail.reason !== 'undefined') {
-            UI.showStatus(e.detail.reason, 'error');
+        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');
 
@@ -1098,16 +1137,18 @@ var UI = {
         UI.openConnectPanel();
     },
 
-    cancelReconnect: function() {
-        if (UI.reconnect_callback !== null) {
-            clearTimeout(UI.reconnect_callback);
-            UI.reconnect_callback = null;
+    securityFailed: function (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.updateVisualState('disconnected');
-
-        UI.openControlbar();
-        UI.openConnectPanel();
+        UI.showStatus(msg, 'error');
     },
 
 /* ------^-------
@@ -1201,74 +1242,8 @@ var UI = {
     applyResizeMode: function() {
         if (!UI.rfb) return;
 
-        var screen = UI.screenSize();
-
-        if (screen && UI.connected) {
-
-            var resizeMode = UI.getSetting('resize');
-            UI.rfb.viewportScale = 1.0;
-
-            // Make sure the viewport is adjusted first
-            UI.updateViewClip();
-
-            if (resizeMode === 'remote') {
-
-                // Request changing the resolution of the remote display to
-                // the size of the local browser viewport.
-
-                // In order to not send multiple requests before the browser-resize
-                // is finished we wait 0.5 seconds before sending the request.
-                clearTimeout(UI.resizeTimeout);
-                UI.resizeTimeout = setTimeout(function(){
-                    // Request a remote size covering the viewport
-                    if (UI.rfb.requestDesktopSize(screen.w, screen.h)) {
-                        Log.Debug('Requested new desktop size: ' +
-                                   screen.w + 'x' + screen.h);
-                    }
-                }, 500);
-
-            } else {
-                UI.updateScaling();
-            }
-        }
-    },
-
-    // Re-calculate local scaling
-    updateScaling: function() {
-        if (!UI.rfb) return;
-
-        var resizeMode = UI.getSetting('resize');
-        if (resizeMode !== 'scale') {
-            return;
-        }
-
-        var screen = UI.screenSize();
-
-        if (!screen || !UI.connected) {
-            return;
-        }
-
-        UI.rfb.autoscale(screen.w, screen.h);
-        UI.fixScrollbars();
-    },
-
-    // Gets the the size of the available viewport in the browser window
-    screenSize: function() {
-        var screen = document.getElementById('noVNC_screen');
-        return {w: screen.offsetWidth, h: screen.offsetHeight};
-    },
-
-    // Normally we only apply the current resize mode after a window resize
-    // event. This means that when a new connection is opened, there is no
-    // resize mode active.
-    // We have to wait until we know the capabilities of the server as
-    // some calls later in the chain is dependant on knowing the
-    // server-capabilities.
-    initialResize: function() {
-        if (UI.doneInitialResize) return;
-
-        UI.applyResizeMode();
-        UI.doneInitialResize = true;
+        UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
+        UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
     },
 
 /* ------^-------
@@ -1277,12 +1252,6 @@ var UI = {
  * VIEW CLIPPING
  * ------v------*/
 
-    // Set and configure viewport clipping
-    setViewClip: function(clip) {
-        UI.updateSetting('view_clip', clip);
-        UI.updateViewClip();
-    },
-
     // Update parameters that depend on the viewport clip setting
     updateViewClip: function() {
         if (!UI.rfb) return;
@@ -1290,11 +1259,7 @@ var UI = {
         var cur_clip = UI.rfb.clipViewport;
         var new_clip = UI.getSetting('view_clip');
 
-        var resizeSetting = UI.getSetting('resize');
-        if (resizeSetting === 'scale') {
-            // Disable viewport clipping if we are scaling
-            new_clip = false;
-        } else if (isTouchDevice) {
+        if (isTouchDevice) {
             // Touch devices usually have shit scrollbars
             new_clip = true;
         }
@@ -1303,15 +1268,6 @@ var UI = {
             UI.rfb.clipViewport = new_clip;
         }
 
-        var size = UI.screenSize();
-
-        if (new_clip && size) {
-            // When clipping is enabled, the screen is limited to
-            // the size of the browser window.
-            UI.rfb.viewportChangeSize(size.w, size.h);
-            UI.fixScrollbars();
-        }
-
         // Changing the viewport may change the state of
         // the dragging button
         UI.updateViewDrag();
@@ -1352,23 +1308,13 @@ var UI = {
     },
 
     updateViewDrag: function() {
-        var clipping = false;
-
         if (!UI.connected) return;
 
-        // Check if viewport drag is possible. It is only possible
-        // if the remote display is clipping the client display.
-        if (UI.rfb.clipViewport && UI.rfb.isClipped) {
-            clipping = true;
-        }
-
         var viewDragButton = document.getElementById('noVNC_view_drag_button');
 
-        if (!clipping &&
-            UI.rfb.dragViewport) {
-            // The size of the remote display is the same or smaller
-            // than the client display. Make sure viewport drag isn't
-            // active when it can't be used.
+        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;
         }
 
@@ -1383,7 +1329,7 @@ var UI = {
         if (isTouchDevice) {
             viewDragButton.classList.remove("noVNC_hidden");
 
-            if (clipping) {
+            if (UI.rfb.clipViewport) {
                 viewDragButton.disabled = false;
             } else {
                 viewDragButton.disabled = true;
@@ -1391,7 +1337,7 @@ var UI = {
         } else {
             viewDragButton.disabled = false;
 
-            if (clipping) {
+            if (UI.rfb.clipViewport) {
                 viewDragButton.classList.remove("noVNC_hidden");
             } else {
                 viewDragButton.classList.add("noVNC_hidden");
@@ -1444,7 +1390,7 @@ var UI = {
         document.getElementById('noVNC_keyboard_button')
             .classList.add("noVNC_selected");
         if (UI.rfb) {
-            UI.rfb.set_focus_on_click(false);
+            UI.rfb.focusOnClick = false;
         }
     },
 
@@ -1452,7 +1398,7 @@ var UI = {
         document.getElementById('noVNC_keyboard_button')
             .classList.remove("noVNC_selected");
         if (UI.rfb) {
-            UI.rfb.set_focus_on_click(true);
+            UI.rfb.focusOnClick = true;
         }
     },
 
@@ -1666,24 +1612,6 @@ var UI = {
         WebUtil.init_logging(UI.getSetting('logging'));
     },
 
-    updateSessionSize: function(e) {
-        UI.updateViewClip();
-        UI.updateScaling();
-        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 = "";
-    },
-
     updateDesktopName: function(e) {
         UI.desktopName = e.detail.name;
         // Display the desktop name in the document title
@@ -1723,7 +1651,7 @@ var UI = {
 };
 
 // Set up translations
-var LINGUAS = ["de", "el", "nl", "pl", "sv"];
+var LINGUAS = ["de", "el", "nl", "pl", "sv", "zh"];
 l10n.setup(LINGUAS);
 if (l10n.language !== "en" && l10n.dictionary === undefined) {
     WebUtil.fetchJSON('app/locale/' + l10n.language + '.json', function (translations) {