]> git.proxmox.com Git - mirror_novnc.git/blobdiff - app/ui.js
Uncomment ES6 module syntax
[mirror_novnc.git] / app / ui.js
index 4b9b27d4f03c01b61eedf4f768c1ffad10294848..8009c3825fcdea20305597b7bdcb14f1a0097f11 100644 (file)
--- a/app/ui.js
+++ b/app/ui.js
 /* jslint white: false, browser: true */
 /* global window, document.getElementById, Util, WebUtil, RFB, Display */
 
-/* [module]
- * import Util from "../core/util";
- * import KeyTable from "../core/input/keysym";
- * import keysyms from "./keysymdef";
- * import RFB from "../core/rfb";
- * import Display from "../core/display";
- * import WebUtil from "./webutil";
- */
+import Util from "../core/util.js";
+import KeyTable from "../core/input/keysym.js";
+import keysyms from "../core/input/keysymdef.js";
+import RFB from "../core/rfb.js";
+import Display from "../core/display.js";
+import WebUtil from "./webutil.js";
 
 var UI;
 
@@ -73,16 +71,6 @@ var UI;
             {'app': ["locale/" + Util.Localisation.language + ".js"]});
     }
 
-    /* [begin skip-as-module] */
-    // Load supporting scripts
-    WebUtil.load_scripts(
-        {'core': ["base64.js", "websock.js", "des.js", "input/keysymdef.js",
-                  "input/xtscancodes.js", "input/util.js", "input/devices.js",
-                  "display.js", "inflator.js", "rfb.js", "input/keysym.js"]});
-
-    window.onscriptsload = function () { UI.load(); };
-    /* [end skip-as-module] */
-
     var _ = Util.Localisation.get;
 
     UI = {
@@ -133,9 +121,6 @@ var UI;
                 document.documentElement.classList.add("noVNC_touch");
                 // Remove the address bar
                 setTimeout(function() { window.scrollTo(0, 1); }, 100);
-                UI.forceSetting('clip', true);
-            } else {
-                UI.initSetting('clip', false);
             }
 
             // Restore control bar position
@@ -228,6 +213,7 @@ var UI;
             UI.initSetting('encrypt', (window.location.protocol === "https:"));
             UI.initSetting('true_color', true);
             UI.initSetting('cursor', !Util.isTouchDevice);
+            UI.initSetting('clip', false);
             UI.initSetting('resize', 'off');
             UI.initSetting('shared', true);
             UI.initSetting('view_only', false);
@@ -235,12 +221,62 @@ var UI;
             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: function() {
+            var labels = document.getElementsByTagName('LABEL');
+            for (var i = 0; i < labels.length; i++) {
+                var htmlFor = labels[i].htmlFor;
+                if (htmlFor != '') {
+                    var elem = document.getElementById(htmlFor);
+                    if (elem) elem.label = labels[i];
+                } else {
+                    // If 'for' isn't set, use the first input element child
+                    var children = labels[i].children;
+                    for (var j = 0; j < children.length; j++) {
+                        if (children[j].form !== undefined) {
+                            children[j].label = labels[i];
+                            break;
+                        }
+                    }
+                }
+            }
+        },
+
+        initRFB: function() {
+            try {
+                UI.rfb = new RFB({'target': document.getElementById('noVNC_canvas'),
+                                  'onNotification': UI.notification,
+                                  'onUpdateState': UI.updateState,
+                                  'onDisconnected': UI.disconnectFinished,
+                                  'onPasswordRequired': UI.passwordRequired,
+                                  'onXvpInit': UI.updateXvpButton,
+                                  'onClipboard': UI.clipboardReceive,
+                                  'onBell': UI.bell,
+                                  'onFBUComplete': UI.initialResize,
+                                  'onFBResize': UI.updateSessionSize,
+                                  'onDesktopName': UI.updateDesktopName});
+                return true;
+            } catch (exc) {
+                var msg = "Unable to create RFB client -- " + exc;
+                Util.Error(msg);
+                UI.showStatus(msg, 'error');
+                return false;
+            }
+        },
+
+/* ------^-------
+ *     /INIT
+ * ==============
+ * EVENT HANDLERS
+ * ------v------*/
+
         addResizeHandlers: function() {
             window.addEventListener('resize', UI.applyResizeMode);
             window.addEventListener('resize', UI.updateViewClip);
-            window.addEventListener('resize', UI.updateViewDrag);
         },
 
         addControlbarHandlers: function() {
@@ -392,10 +428,15 @@ var UI;
             UI.addSettingChangeHandler('encrypt');
             UI.addSettingChangeHandler('true_color');
             UI.addSettingChangeHandler('cursor');
+            UI.addSettingChangeHandler('cursor', UI.updateLocalCursor);
             UI.addSettingChangeHandler('resize');
+            UI.addSettingChangeHandler('resize', UI.enableDisableViewClip);
+            UI.addSettingChangeHandler('resize', UI.applyResizeMode);
             UI.addSettingChangeHandler('clip');
+            UI.addSettingChangeHandler('clip', UI.updateViewClip);
             UI.addSettingChangeHandler('shared');
             UI.addSettingChangeHandler('view_only');
+            UI.addSettingChangeHandler('view_only', UI.updateViewOnly);
             UI.addSettingChangeHandler('host');
             UI.addSettingChangeHandler('port');
             UI.addSettingChangeHandler('path');
@@ -416,30 +457,8 @@ var UI;
             window.addEventListener('msfullscreenchange', UI.updateFullscreenButton);
         },
 
-        initRFB: function() {
-            try {
-                UI.rfb = new RFB({'target': document.getElementById('noVNC_canvas'),
-                                  'onNotification': UI.notification,
-                                  'onUpdateState': UI.updateState,
-                                  'onDisconnected': UI.disconnectFinished,
-                                  'onPasswordRequired': UI.passwordRequired,
-                                  'onXvpInit': UI.updateXvpButton,
-                                  'onClipboard': UI.clipboardReceive,
-                                  'onBell': UI.bell,
-                                  'onFBUComplete': UI.initialResize,
-                                  'onFBResize': UI.updateSessionSize,
-                                  'onDesktopName': UI.updateDesktopName});
-                return true;
-            } catch (exc) {
-                var msg = "Unable to create RFB client -- " + exc;
-                Util.Error(msg);
-                UI.showStatus(msg, 'error');
-                return false;
-            }
-        },
-
 /* ------^-------
- *     /INIT
+ * /EVENT HANDLERS
  * ==============
  *     VISUAL
  * ------v------*/
@@ -489,33 +508,36 @@ var UI;
         // Disable/enable controls depending on connection state
         updateVisualState: function() {
             //Util.Debug(">> updateVisualState");
-            document.getElementById('noVNC_setting_encrypt').disabled = UI.connected;
-            document.getElementById('noVNC_setting_true_color').disabled = UI.connected;
-            if (Util.browserSupportsCursorURIs()) {
-                document.getElementById('noVNC_setting_cursor').disabled = UI.connected;
-            } else {
-                UI.updateSetting('cursor', !Util.isTouchDevice);
-                document.getElementById('noVNC_setting_cursor').disabled = true;
-            }
 
             UI.enableDisableViewClip();
-            document.getElementById('noVNC_setting_resize').disabled = UI.connected;
-            document.getElementById('noVNC_setting_shared').disabled = UI.connected;
-            document.getElementById('noVNC_setting_view_only').disabled = UI.connected;
-            document.getElementById('noVNC_setting_host').disabled = UI.connected;
-            document.getElementById('noVNC_setting_port').disabled = UI.connected;
-            document.getElementById('noVNC_setting_path').disabled = UI.connected;
-            document.getElementById('noVNC_setting_repeaterID').disabled = UI.connected;
-            document.getElementById('noVNC_setting_reconnect').disabled = UI.connected;
-            document.getElementById('noVNC_setting_reconnect_delay').disabled = UI.connected;
+
+            if (Util.browserSupportsCursorURIs() && !Util.isTouchDevice) {
+                UI.enableSetting('cursor');
+            } else {
+                UI.disableSetting('cursor');
+            }
 
             if (UI.connected) {
+                UI.disableSetting('encrypt');
+                UI.disableSetting('true_color');
+                UI.disableSetting('shared');
+                UI.disableSetting('host');
+                UI.disableSetting('port');
+                UI.disableSetting('path');
+                UI.disableSetting('repeaterID');
                 UI.updateViewClip();
                 UI.setMouseButton(1);
 
                 // Hide the controlbar after 2 seconds
                 UI.closeControlbarTimeout = setTimeout(UI.closeControlbar, 2000);
             } else {
+                UI.enableSetting('encrypt');
+                UI.enableSetting('true_color');
+                UI.enableSetting('shared');
+                UI.enableSetting('host');
+                UI.enableSetting('port');
+                UI.enableSetting('path');
+                UI.enableSetting('repeaterID');
                 UI.updateXvpButton(0);
                 UI.keepControlbar();
             }
@@ -553,9 +575,9 @@ var UI;
                 status_type = 'normal';
             }
 
-            statusElem.classList.remove("noVNC_status_normal",
-                                        "noVNC_status_warn",
-                                        "noVNC_status_error");
+            statusElem.classList.remove("noVNC_status_normal");
+            statusElem.classList.remove("noVNC_status_warn");
+            statusElem.classList.remove("noVNC_status_error");
 
             switch (status_type) {
                 case 'warning':
@@ -757,7 +779,7 @@ var UI;
             var handle = document.getElementById("noVNC_control_bar_handle");
             var bounds = handle.getBoundingClientRect();
 
-            WebUtil.setCapture(handle);
+            Util.setCapture(handle);
             UI.controlbarGrabbed = true;
             UI.controlbarDrag = false;
 
@@ -842,12 +864,6 @@ var UI;
             return val;
         },
 
-        // Force a setting to be a certain value
-        forceSetting: function(name, val) {
-            UI.updateSetting(name, val);
-            return val;
-        },
-
         // Read form control compatible setting from cookie
         getSetting: function(name) {
             var ctrl = document.getElementById('noVNC_setting_' + name);
@@ -862,6 +878,21 @@ var UI;
             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: function(name) {
+            var ctrl = document.getElementById('noVNC_setting_' + name);
+            ctrl.disabled = true;
+            ctrl.label.classList.add('noVNC_disabled');
+        },
+
+        enableSetting: function(name) {
+            var ctrl = document.getElementById('noVNC_setting_' + name);
+            ctrl.disabled = false;
+            ctrl.label.classList.remove('noVNC_disabled');
+        },
+
 /* ------^-------
  *   /SETTINGS
  * ==============
@@ -892,7 +923,7 @@ var UI;
                 UI.updateSetting('cursor');
             } else {
                 UI.updateSetting('cursor', !Util.isTouchDevice);
-                document.getElementById('noVNC_setting_cursor').disabled = true;
+                UI.disableSetting('cursor');
             }
             UI.updateSetting('clip');
             UI.updateSetting('resize');
@@ -1064,11 +1095,12 @@ var UI;
 
             UI.rfb.set_encrypt(UI.getSetting('encrypt'));
             UI.rfb.set_true_color(UI.getSetting('true_color'));
-            UI.rfb.set_local_cursor(UI.getSetting('cursor'));
             UI.rfb.set_shared(UI.getSetting('shared'));
-            UI.rfb.set_view_only(UI.getSetting('view_only'));
             UI.rfb.set_repeaterID(UI.getSetting('repeaterID'));
 
+            UI.updateLocalCursor();
+            UI.updateViewOnly();
+
             UI.rfb.connect(host, port, password, path);
         },
 
@@ -1145,13 +1177,14 @@ var UI;
             UI.showStatus(msg, "warning");
         },
 
-        setPassword: function() {
+        setPassword: function(e) {
             var password = document.getElementById('noVNC_password_input').value;
             UI.rfb.sendPassword(password);
             UI.reconnect_password = password;
             document.getElementById('noVNC_password_dlg')
                 .classList.remove('noVNC_open');
-            return false;
+            // Prevent actually submitting the form
+            e.preventDefault();
         },
 
 /* ------^-------
@@ -1218,6 +1251,10 @@ var UI;
 
                 var display = UI.rfb.get_display();
                 var resizeMode = UI.getSetting('resize');
+                display.set_scale(1);
+
+                // Make sure the viewport is adjusted first
+                UI.updateViewClip();
 
                 if (resizeMode === 'remote') {
 
@@ -1237,12 +1274,8 @@ var UI;
 
                 } else if (resizeMode === 'scale' || resizeMode === 'downscale') {
                     var downscaleOnly = resizeMode === 'downscale';
-                    var scaleRatio = display.autoscale(screen.w, screen.h, downscaleOnly);
-
-                    if (!UI.rfb.get_view_only()) {
-                        UI.rfb.get_mouse().set_scale(scaleRatio);
-                        Util.Debug('Scaling by ' + UI.rfb.get_mouse().get_scale());
-                    }
+                    display.autoscale(screen.w, screen.h, downscaleOnly);
+                    UI.fixScrollbars();
                 }
             }
         },
@@ -1250,21 +1283,7 @@ var UI;
         // Gets the the size of the available viewport in the browser window
         screenSize: function() {
             var screen = document.getElementById('noVNC_screen');
-
-            // Hide the scrollbars until the size is calculated
-            screen.style.overflow = "hidden";
-
-            var pos = Util.getPosition(screen);
-            var w = pos.width;
-            var h = pos.height;
-
-            screen.style.overflow = "visible";
-
-            if (isNaN(w) || isNaN(h)) {
-                return false;
-            } else {
-                return {w: w, h: h};
-            }
+            return {w: screen.offsetWidth, h: screen.offsetHeight};
         },
 
         // Normally we only apply the current resize mode after a window resize
@@ -1299,6 +1318,15 @@ var UI;
             var cur_clip = display.get_viewport();
             var new_clip = UI.getSetting('clip');
 
+            var resizeSetting = UI.getSetting('resize');
+            if (resizeSetting === 'downscale' || resizeSetting === 'scale') {
+                // Disable clipping if we are scaling
+                new_clip = false;
+            } else if (Util.isTouchDevice) {
+                // Touch devices usually have shit scrollbars
+                new_clip = true;
+            }
+
             if (cur_clip !== new_clip) {
                 display.set_viewport(new_clip);
             }
@@ -1309,47 +1337,23 @@ var UI;
                 // When clipping is enabled, the screen is limited to
                 // the size of the browser window.
                 display.viewportChangeSize(size.w, size.h);
+                UI.fixScrollbars();
             }
+
+            // Changing the viewport may change the state of
+            // the dragging button
+            UI.updateViewDrag();
         },
 
         // Handle special cases where clipping is forced on/off or locked
         enableDisableViewClip: function() {
             var resizeSetting = UI.getSetting('resize');
-
-            if (UI.isSafari) {
-                // Safari auto-hides the scrollbars which makes them
-                // impossible to use in most cases
-                UI.setViewClip(true);
-                document.getElementById('noVNC_setting_clip').disabled = true;
-            } else if (resizeSetting === 'downscale' || resizeSetting === 'scale') {
-                // Disable clipping if we are scaling
-                UI.forceSetting('clip', false);
-                UI.setViewClip(false);
-                document.getElementById('noVNC_setting_clip').disabled = true;
-            } else if (document.msFullscreenElement) {
-                // The browser is IE and we are in fullscreen mode.
-                // - We need to force clipping while in fullscreen since
-                //   scrollbars doesn't work.
-                var msg = _("Forcing clipping mode since " +
-                            "scrollbars aren't supported " +
-                            "by IE in fullscreen");
-                Util.Debug(msg);
-                UI.showStatus(msg);
-                UI.rememberedClipSetting = UI.getSetting('clip');
-                UI.setViewClip(true);
-                document.getElementById('noVNC_setting_clip').disabled = true;
-            } else if (document.body.msRequestFullscreen &&
-                       UI.rememberedClipSetting !== null) {
-                // Restore view clip to what it was before fullscreen on IE
-                UI.setViewClip(UI.rememberedClipSetting);
-                document.getElementById('noVNC_setting_clip').disabled =
-                    UI.connected || Util.isTouchDevice;
+            // Disable clipping if we are scaling, connected or on touch
+            if (resizeSetting === 'downscale' || resizeSetting === 'scale' ||
+                Util.isTouchDevice) {
+                UI.disableSetting('clip');
             } else {
-                document.getElementById('noVNC_setting_clip').disabled =
-                    UI.connected || Util.isTouchDevice;
-                if (Util.isTouchDevice) {
-                    UI.setViewClip(true);
-                }
+                UI.enableSetting('clip');
             }
         },
 
@@ -1483,15 +1487,21 @@ var UI;
                 return;
             }
 
-            // Allow clicking on links
-            if (event.target.tagName === "A") {
-                return;
-            }
-
-            // And form elements, except standard noVNC buttons
-            if ((event.target.form !== undefined) &&
-                !event.target.classList.contains("noVNC_button")) {
-                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();
@@ -1678,13 +1688,33 @@ var UI;
             }
         },
 
+        updateLocalCursor: function() {
+            UI.rfb.set_local_cursor(UI.getSetting('cursor'));
+        },
+
+        updateViewOnly: function() {
+            UI.rfb.set_view_only(UI.getSetting('view_only'));
+        },
+
         updateLogging: function() {
             WebUtil.init_logging(UI.getSetting('logging'));
         },
 
         updateSessionSize: function(rfb, width, height) {
             UI.updateViewClip();
-            UI.updateViewDrag();
+            UI.fixScrollbars();
+        },
+
+        fixScrollbars: function() {
+            // This is a hack because Chrome screws up the calculation
+            // for when scrollbars are needed. So to fix it we temporarily
+            // toggle them off and on.
+            var screen = document.getElementById('noVNC_screen');
+            screen.style.overflow = 'hidden';
+            // Force Chrome to recalculate the layout by asking for
+            // an element's dimensions
+            screen.getBoundingClientRect();
+            screen.style.overflow = null;
         },
 
         updateDesktopName: function(rfb, name) {
@@ -1713,7 +1743,7 @@ var UI;
  */
     };
 
-    /* [module] UI.load(); */
+    UI.load();
 })();
 
-/* [module] export default UI; */
+export default UI;