]> git.proxmox.com Git - mirror_novnc.git/blobdiff - vnc_lite.html
Make Cursor.detach() safe to call when not attached
[mirror_novnc.git] / vnc_lite.html
index e00f96e01ddf2b6679ea8381a668bc5ed2e56b9f..e0267716c43115655daa0f7cada64b78b27e6c37 100644 (file)
 <!DOCTYPE html>
-<html>
+<html lang="en">
 <head>
 
     <!--
     noVNC example: lightweight example using minimal UI and features
-    Copyright (C) 2012 Joel Martin
-    Copyright (C) 2017 Samuel Mannehed for Cendio AB
+
+    This is a self-contained file which doesn't import WebUtil or external CSS.
+
+    Copyright (C) 2019 The noVNC Authors
     noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
     This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
 
     Connect parameters are provided in query string:
-        http://example.com/?host=HOST&port=PORT&encrypt=1
-    or the fragment:
-        http://example.com/#host=HOST&port=PORT&encrypt=1
+        http://example.com/?host=HOST&port=PORT&scale=true
     -->
     <title>noVNC</title>
 
     <meta charset="utf-8">
 
-    <!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
-                Remove this if you use the .htaccess -->
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-
-    <!-- Icons (see Makefile for what the sizes are for) -->
-    <link rel="icon" sizes="16x16" type="image/png" href="app/images/icons/novnc-16x16.png">
-    <link rel="icon" sizes="24x24" type="image/png" href="app/images/icons/novnc-24x24.png">
-    <link rel="icon" sizes="32x32" type="image/png" href="app/images/icons/novnc-32x32.png">
-    <link rel="icon" sizes="48x48" type="image/png" href="app/images/icons/novnc-48x48.png">
-    <link rel="icon" sizes="60x60" type="image/png" href="app/images/icons/novnc-60x60.png">
-    <link rel="icon" sizes="64x64" type="image/png" href="app/images/icons/novnc-64x64.png">
-    <link rel="icon" sizes="72x72" type="image/png" href="app/images/icons/novnc-72x72.png">
-    <link rel="icon" sizes="76x76" type="image/png" href="app/images/icons/novnc-76x76.png">
-    <link rel="icon" sizes="96x96" type="image/png" href="app/images/icons/novnc-96x96.png">
-    <link rel="icon" sizes="120x120" type="image/png" href="app/images/icons/novnc-120x120.png">
-    <link rel="icon" sizes="144x144" type="image/png" href="app/images/icons/novnc-144x144.png">
-    <link rel="icon" sizes="152x152" type="image/png" href="app/images/icons/novnc-152x152.png">
-    <link rel="icon" sizes="192x192" type="image/png" href="app/images/icons/novnc-192x192.png">
-    <link rel="icon" sizes="any" type="image/svg+xml" href="app/images/icons/novnc-icon.svg">
-    <!-- Repeated last so that legacy handling will pick this -->
-    <link rel="icon" sizes="16x16" type="image/png" href="app/images/icons/novnc-16x16.png">
-
-    <!-- Apple iOS Safari settings -->
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
-    <meta name="apple-mobile-web-app-capable" content="yes" />
-    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
-    <!-- Home Screen Icons (favourites and bookmarks use the normal icons) -->
-    <link rel="apple-touch-icon" sizes="60x60" type="image/png" href="app/images/icons/novnc-60x60.png">
-    <link rel="apple-touch-icon" sizes="76x76" type="image/png" href="app/images/icons/novnc-76x76.png">
-    <link rel="apple-touch-icon" sizes="120x120" type="image/png" href="app/images/icons/novnc-120x120.png">
-    <link rel="apple-touch-icon" sizes="152x152" type="image/png" href="app/images/icons/novnc-152x152.png">
-
-    <!-- Stylesheets -->
-    <link rel="stylesheet" href="app/styles/lite.css">
-
-     <!--
-    <script type='text/javascript'
-        src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-    -->
+    <style>
+
+        body {
+            margin: 0;
+            background-color: dimgrey;
+            height: 100%;
+            display: flex;
+            flex-direction: column;
+        }
+        html {
+            height: 100%;
+        }
 
-    <!-- promise polyfills promises for IE11 -->
+        #top_bar {
+            background-color: #6e84a3;
+            color: white;
+            font: bold 12px Helvetica;
+            padding: 6px 5px 4px 5px;
+            border-bottom: 1px outset;
+        }
+        #status {
+            text-align: center;
+        }
+        #sendCtrlAltDelButton {
+            position: fixed;
+            top: 0px;
+            right: 0px;
+            border: 1px outset;
+            padding: 5px 5px 4px 5px;
+            cursor: pointer;
+        }
+
+        #screen {
+            flex: 1; /* fill remaining space */
+            overflow: hidden;
+        }
+
+    </style>
+
+    <!-- Promise polyfill for IE11 -->
     <script src="vendor/promise.js"></script>
+
     <!-- ES2015/ES6 modules polyfill -->
-    <script type="module">
-        window._noVNC_has_module_support = true;
-    </script>
-    <script>
-        window.addEventListener("load", function() {
-            if (window._noVNC_has_module_support) return;
-            var loader = document.createElement("script");
-            loader.src = "vendor/browser-es-module-loader/dist/browser-es-module-loader.js";
-            document.head.appendChild(loader);
-        });
-    </script>
+    <script nomodule src="vendor/browser-es-module-loader/dist/browser-es-module-loader.js"></script>
 
     <!-- actual script modules -->
     <script type="module" crossorigin="anonymous">
-        // Load supporting scripts
-        import * as WebUtil from './app/webutil.js';
+        // RFB holds the API to connect and communicate with a VNC server
         import RFB from './core/rfb.js';
 
-        var rfb;
-        var desktopName;
+        let rfb;
+        let desktopName;
 
-        function updateDesktopName(e) {
-            desktopName = e.detail.name;
+        // When this function is called we have
+        // successfully connected to a server
+        function connectedToServer(e) {
+            status("Connected to " + desktopName);
+        }
+
+        // This function is called when we are disconnected
+        function disconnectedFromServer(e) {
+            if (e.detail.clean) {
+                status("Disconnected");
+            } else {
+                status("Something went wrong, connection is closed");
+            }
         }
-        function credentials(e) {
-            var html;
-
-            var form = document.createElement('form');
-            form.innerHTML = '<label></label>';
-            form.innerHTML += '<input type=password size=10 id="password_input">';
-            form.onsubmit = setPassword;
-
-            // bypass status() because it sets text content
-            document.getElementById('noVNC_status_bar').setAttribute("class", "noVNC_status_warn");
-            document.getElementById('noVNC_status').innerHTML = '';
-            document.getElementById('noVNC_status').appendChild(form);
-            document.getElementById('noVNC_status').querySelector('label').textContent = 'Password Required: ';
+
+        // When this function is called, the server requires
+        // credentials to authenticate
+        function credentialsAreRequired(e) {
+            const password = prompt("Password Required:");
+            rfb.sendCredentials({ password: password });
         }
-        function setPassword() {
-            rfb.sendCredentials({ password: document.getElementById('password_input').value });
-            return false;
+
+        // When this function is called we have received
+        // a desktop name from the server
+        function updateDesktopName(e) {
+            desktopName = e.detail.name;
         }
+
+        // Since most operating systems will catch Ctrl+Alt+Del
+        // before they get a chance to be intercepted by the browser,
+        // we provide a way to emulate this key sequence.
         function sendCtrlAltDel() {
             rfb.sendCtrlAltDel();
             return false;
         }
-        function machineShutdown() {
-            rfb.machineShutdown();
-            return false;
-        }
-        function machineReboot() {
-            rfb.machineReboot();
-            return false;
-        }
-        function machineReset() {
-            rfb.machineReset();
-            return false;
-        }
-        function status(text, level) {
-            switch (level) {
-                case 'normal':
-                case 'warn':
-                case 'error':
-                    break;
-                default:
-                    level = "warn";
-            }
-            document.getElementById('noVNC_status_bar').className = "noVNC_status_" + level;
-            document.getElementById('noVNC_status').textContent = text;
-        }
 
-        function connected(e) {
-            document.getElementById('sendCtrlAltDelButton').disabled = false;
-            if (WebUtil.getConfigVar('encrypt',
-                                     (window.location.protocol === "https:"))) {
-                status("Connected (encrypted) to " + desktopName, "normal");
-            } else {
-                status("Connected (unencrypted) to " + desktopName, "normal");
-            }
+        // Show a status text in the top bar
+        function status(text) {
+            document.getElementById('status').textContent = text;
         }
 
-        function disconnected(e) {
-            document.getElementById('sendCtrlAltDelButton').disabled = true;
-            updatePowerButtons();
-            if (e.detail.clean) {
-                status("Disconnected", "normal");
-            } else {
-                status("Something went wrong, connection is closed", "error");
+        // This function extracts the value of one variable from the
+        // query string. If the variable isn't defined in the URL
+        // it returns the default value instead.
+        function readQueryVariable(name, defaultValue) {
+            // A URL with a query parameter can look like this:
+            // https://www.example.com?myqueryparam=myvalue
+            //
+            // Note that we use location.href instead of location.search
+            // because Firefox < 53 has a bug w.r.t location.search
+            const re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
+                  match = document.location.href.match(re);
+            if (typeof defaultValue === 'undefined') { defaultValue = null; }
+
+            if (match) {
+                // We have to decode the URL since want the cleartext value
+                return decodeURIComponent(match[1]);
             }
-        }
 
-        function updatePowerButtons() {
-            var powerbuttons;
-            powerbuttons = document.getElementById('noVNC_power_buttons');
-            if (rfb.capabilities.power) {
-                powerbuttons.className= "noVNC_shown";
-            } else {
-                powerbuttons.className = "noVNC_hidden";
-            }
+            return defaultValue;
         }
 
-        document.getElementById('sendCtrlAltDelButton').onclick = sendCtrlAltDel;
-        document.getElementById('machineShutdownButton').onclick = machineShutdown;
-        document.getElementById('machineRebootButton').onclick = machineReboot;
-        document.getElementById('machineResetButton').onclick = machineReset;
+        document.getElementById('sendCtrlAltDelButton')
+            .onclick = sendCtrlAltDel;
 
-        WebUtil.init_logging(WebUtil.getConfigVar('logging', 'warn'));
-        document.title = WebUtil.getConfigVar('title', 'noVNC');
+        // Read parameters specified in the URL query string
         // By default, use the host and port of server that served this file
-        var host = WebUtil.getConfigVar('host', window.location.hostname);
-        var port = WebUtil.getConfigVar('port', window.location.port);
-
-        // if port == 80 (or 443) then it won't be present and should be
-        // set manually
-        if (!port) {
-            if (window.location.protocol.substring(0,5) == 'https') {
-                port = 443;
-            }
-            else if (window.location.protocol.substring(0,4) == 'http') {
-                port = 80;
-            }
+        const host = readQueryVariable('host', window.location.hostname);
+        let port = readQueryVariable('port', window.location.port);
+        const password = readQueryVariable('password', '');
+        const path = readQueryVariable('path', 'websockify');
+
+        // | | |         | | |
+        // | | | Connect | | |
+        // v v v         v v v
+
+        status("Connecting");
+
+        // Build the websocket URL used to connect
+        let url;
+        if (window.location.protocol === "https:") {
+            url = 'wss';
+        } else {
+            url = 'ws';
         }
-
-        var password = WebUtil.getConfigVar('password', '');
-        var path = WebUtil.getConfigVar('path', 'websockify');
-
-        // If a token variable is passed in, set the parameter in a cookie.
-        // This is used by nova-novncproxy.
-        var token = WebUtil.getConfigVar('token', null);
-        if (token) {
-            // if token is already present in the path we should use it
-            path = WebUtil.injectParamIfMissing(path, "token", token);
-
-            WebUtil.createCookie('token', token, 1)
+        url += '://' + host;
+        if(port) {
+            url += ':' + port;
         }
+        url += '/' + path;
 
-        (function() {
-
-            status("Connecting", "normal");
+        // Creating a new RFB object will start a new connection
+        rfb = new RFB(document.getElementById('screen'), url,
+                      { credentials: { password: password } });
 
-            if ((!host) || (!port)) {
-                status('Must specify host and port in URL', 'error');
-            }
-
-            var url;
+        // Add listeners to important events from the RFB module
+        rfb.addEventListener("connect",  connectedToServer);
+        rfb.addEventListener("disconnect", disconnectedFromServer);
+        rfb.addEventListener("credentialsrequired", credentialsAreRequired);
+        rfb.addEventListener("desktopname", updateDesktopName);
 
-            if (WebUtil.getConfigVar('encrypt',
-                                     (window.location.protocol === "https:"))) {
-                url = 'wss';
-            } else {
-                url = 'ws';
-            }
-
-            url += '://' + host;
-            if(port) {
-                url += ':' + port;
-            }
-            url += '/' + path;
-
-            rfb = new RFB(document.body, url,
-                          { repeaterID: WebUtil.getConfigVar('repeaterID', ''),
-                            shared: WebUtil.getConfigVar('shared', true),
-                            credentials: { password: password } });
-            rfb.viewOnly = WebUtil.getConfigVar('view_only', false);
-            rfb.addEventListener("connect",  connected);
-            rfb.addEventListener("disconnect", disconnected);
-            rfb.addEventListener("capabilities", function () { updatePowerButtons(); });
-            rfb.addEventListener("credentialsrequired", credentials);
-            rfb.addEventListener("desktopname", updateDesktopName);
-            rfb.scaleViewport = WebUtil.getConfigVar('scale', false);
-            rfb.resizeSession = WebUtil.getConfigVar('resize', false);
-        })();
+        // Set parameters that can be changed on an active connection
+        rfb.viewOnly = readQueryVariable('view_only', false);
+        rfb.scaleViewport = readQueryVariable('scale', false);
     </script>
 </head>
 
 <body>
-  <div id="noVNC_status_bar">
-    <div id="noVNC_left_dummy_elem"></div>
-    <div id="noVNC_status">Loading</div>
-    <div id="noVNC_buttons">
-      <input type=button value="Send CtrlAltDel"
-             id="sendCtrlAltDelButton" class="noVNC_shown">
-      <span id="noVNC_power_buttons" class="noVNC_hidden">
-        <input type=button value="Shutdown"
-               id="machineShutdownButton">
-        <input type=button value="Reboot"
-               id="machineRebootButton">
-        <input type=button value="Reset"
-               id="machineResetButton">
-      </span>
+    <div id="top_bar">
+        <div id="status">Loading</div>
+        <div id="sendCtrlAltDelButton">Send CtrlAltDel</div>
+    </div>
+    <div id="screen">
+        <!-- This is where the remote screen will appear -->
     </div>
-  </div>
 </body>
 </html>