mirror of
https://github.com/retspen/webvirtcloud
synced 2024-11-01 12:04:15 +00:00
Merge pull request #244 from catborise/master
Dockerfile and Requirement Updates
This commit is contained in:
commit
0ac126ee0d
56 changed files with 18379 additions and 19848 deletions
|
@ -1,4 +1,4 @@
|
||||||
FROM phusion/baseimage:0.9.17
|
FROM phusion/baseimage:0.11
|
||||||
MAINTAINER Jethro Yu <comet.jc@gmail.com>
|
MAINTAINER Jethro Yu <comet.jc@gmail.com>
|
||||||
|
|
||||||
RUN echo 'APT::Get::Clean=always;' >> /etc/apt/apt.conf.d/99AutomaticClean
|
RUN echo 'APT::Get::Clean=always;' >> /etc/apt/apt.conf.d/99AutomaticClean
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Django==1.11.20
|
Django==1.11.21
|
||||||
websockify==0.8.0
|
websockify==0.8.0
|
||||||
gunicorn==19.9.0
|
gunicorn==19.9.0
|
||||||
lxml==4.2.5
|
lxml==4.2.5
|
||||||
libvirt-python==4.10.0
|
libvirt-python==5.3.0
|
||||||
pytz
|
pytz
|
||||||
rwlock
|
rwlock
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="shortcut icon" href="{% static "img/favicon.ico" %}">
|
<link rel="shortcut icon" href="{% static "favicon.ico" %}">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="{% static "css/bootstrap.min.css" %}">
|
<link rel="stylesheet" href="{% static "css/bootstrap.min.css" %}">
|
||||||
<link href="{% static "css/webvirtcloud.css" %}" rel="stylesheet">
|
<link href="{% static "css/webvirtcloud.css" %}" rel="stylesheet">
|
||||||
|
|
|
@ -5,12 +5,9 @@
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<!--
|
<!--
|
||||||
noVNC example: simple example using default UI
|
noVNC example: simple example using default UI
|
||||||
Copyright (C) 2012 Joel Martin
|
Copyright (C) 2018 The noVNC Authors
|
||||||
Copyright (C) 2016 Samuel Mannehed for Cendio AB
|
|
||||||
Copyright (C) 2016 Pierre Ossman for Cendio AB
|
|
||||||
noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
|
noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
|
||||||
This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
||||||
|
|
||||||
Connect parameters are provided in query string:
|
Connect parameters are provided in query string:
|
||||||
http://example.com/?host=HOST&port=PORT&encrypt=1
|
http://example.com/?host=HOST&port=PORT&encrypt=1
|
||||||
or the fragment:
|
or the fragment:
|
||||||
|
@ -20,10 +17,6 @@
|
||||||
|
|
||||||
<meta charset="utf-8" />
|
<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) -->
|
<!-- Icons (see Makefile for what the sizes are for) -->
|
||||||
<link rel="icon" sizes="16x16" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-16x16.png" %}">
|
<link rel="icon" sizes="16x16" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-16x16.png" %}">
|
||||||
<link rel="icon" sizes="24x24" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-24x24.png" %}">
|
<link rel="icon" sizes="24x24" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-24x24.png" %}">
|
||||||
|
@ -140,6 +133,9 @@
|
||||||
<input type="image" alt="Alt" src="{% static "js/novnc/app/images/alt.svg" %}"
|
<input type="image" alt="Alt" src="{% static "js/novnc/app/images/alt.svg" %}"
|
||||||
id="noVNC_toggle_alt_button" class="noVNC_button"
|
id="noVNC_toggle_alt_button" class="noVNC_button"
|
||||||
title="Toggle Alt"/>
|
title="Toggle Alt"/>
|
||||||
|
<input type="image" alt="Windows" src="{% static "js/novnc/app/images/windows.svg" %}"
|
||||||
|
id="noVNC_toggle_windows_button" class="noVNC_button"
|
||||||
|
title="Toggle Windows">
|
||||||
<input type="image" alt="Tab" src="{% static "js/novnc/app/images/tab.svg" %}"
|
<input type="image" alt="Tab" src="{% static "js/novnc/app/images/tab.svg" %}"
|
||||||
id="noVNC_send_tab_button" class="noVNC_button"
|
id="noVNC_send_tab_button" class="noVNC_button"
|
||||||
title="Send Tab"/>
|
title="Send Tab"/>
|
||||||
|
@ -254,6 +250,10 @@
|
||||||
<label for="noVNC_setting_reconnect_delay">Reconnect Delay (ms):</label>
|
<label for="noVNC_setting_reconnect_delay">Reconnect Delay (ms):</label>
|
||||||
<input id="noVNC_setting_reconnect_delay" type="number" />
|
<input id="noVNC_setting_reconnect_delay" type="number" />
|
||||||
</li>
|
</li>
|
||||||
|
<li><hr></li>
|
||||||
|
<li>
|
||||||
|
<label><input id="noVNC_setting_show_dot" type="checkbox"> Show Dot when No Cursor</label>
|
||||||
|
</li>
|
||||||
<li><hr></li>
|
<li><hr></li>
|
||||||
<!-- Logging selection dropdown -->
|
<!-- Logging selection dropdown -->
|
||||||
<li>
|
<li>
|
||||||
|
|
|
@ -689,8 +689,6 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function get_cust_vols(compute_id, pool) {
|
function get_cust_vols(compute_id, pool) {
|
||||||
get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes";
|
get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes";
|
||||||
$.getJSON(get_vol_url, function (data) {
|
$.getJSON(get_vol_url, function (data) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
-r ../conf/requirements.txt
|
-r ../conf/requirements.txt
|
||||||
pep8==1.7.1
|
pep8==1.7.1
|
||||||
pyflakes==2.0.0
|
pyflakes==2.1.1
|
||||||
pylint==1.9.2
|
pylint==1.9.4
|
||||||
|
|
|
@ -84,11 +84,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
{% ifequal status 5 %}
|
|
||||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="add_new_vol">{% trans "Add Volume" %}</button>
|
<button type="submit" class="btn btn-lg btn-success pull-right" name="add_new_vol">{% trans "Add Volume" %}</button>
|
||||||
{% else %}
|
|
||||||
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Add Volume" %}</button>
|
|
||||||
{% endifequal %}
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -142,11 +138,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
{% ifequal status 5 %}
|
|
||||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="add_existing_vol">{% trans "Add Volume" %}</button>
|
<button type="submit" class="btn btn-lg btn-success pull-right" name="add_existing_vol">{% trans "Add Volume" %}</button>
|
||||||
{% else %}
|
|
||||||
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Add Volume" %}</button>
|
|
||||||
{% endifequal %}
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,21 +2,23 @@
|
||||||
// native support in the browsers, so that our error handler
|
// native support in the browsers, so that our error handler
|
||||||
// can catch script-loading errors.
|
// can catch script-loading errors.
|
||||||
|
|
||||||
|
// No ES6 can be used in this file since it's used for the translation
|
||||||
|
/* eslint-disable prefer-arrow-callback */
|
||||||
|
|
||||||
(function(){
|
(function _scope() {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// Fallback for all uncought errors
|
// Fallback for all uncought errors
|
||||||
function handleError (event, err) {
|
function handleError(event, err) {
|
||||||
try {
|
try {
|
||||||
var msg = document.getElementById('noVNC_fallback_errormsg');
|
const msg = document.getElementById('noVNC_fallback_errormsg');
|
||||||
|
|
||||||
// Only show the initial error
|
// Only show the initial error
|
||||||
if (msg.hasChildNodes()) {
|
if (msg.hasChildNodes()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var div = document.createElement("div");
|
let div = document.createElement("div");
|
||||||
div.classList.add('noVNC_message');
|
div.classList.add('noVNC_message');
|
||||||
div.appendChild(document.createTextNode(event.message));
|
div.appendChild(document.createTextNode(event.message));
|
||||||
msg.appendChild(div);
|
msg.appendChild(div);
|
||||||
|
@ -24,7 +26,7 @@
|
||||||
if (event.filename) {
|
if (event.filename) {
|
||||||
div = document.createElement("div");
|
div = document.createElement("div");
|
||||||
div.className = 'noVNC_location';
|
div.className = 'noVNC_location';
|
||||||
var text = event.filename;
|
let text = event.filename;
|
||||||
if (event.lineno !== undefined) {
|
if (event.lineno !== undefined) {
|
||||||
text += ":" + event.lineno;
|
text += ":" + event.lineno;
|
||||||
if (event.colno !== undefined) {
|
if (event.colno !== undefined) {
|
||||||
|
@ -35,7 +37,7 @@
|
||||||
msg.appendChild(div);
|
msg.appendChild(div);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err && (err.stack !== undefined)) {
|
if (err && err.stack) {
|
||||||
div = document.createElement("div");
|
div = document.createElement("div");
|
||||||
div.className = 'noVNC_stack';
|
div.className = 'noVNC_stack';
|
||||||
div.appendChild(document.createTextNode(err.stack));
|
div.appendChild(document.createTextNode(err.stack));
|
||||||
|
@ -51,6 +53,6 @@
|
||||||
// from being printed to the browser console.
|
// from being printed to the browser console.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
window.addEventListener('error', function (evt) { handleError(evt, evt.error); });
|
window.addEventListener('error', function onerror(evt) { handleError(evt, evt.error); });
|
||||||
window.addEventListener('unhandledrejection', function (evt) { handleError(evt.reason, evt.reason); });
|
window.addEventListener('unhandledrejection', function onreject(evt) { handleError(evt.reason, evt.reason); });
|
||||||
})();
|
})();
|
||||||
|
|
85
static/js/novnc/app/images/windows.svg
Executable file
85
static/js/novnc/app/images/windows.svg
Executable file
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="svg2"
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
sodipodi:docname="windows.svg"
|
||||||
|
inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
|
||||||
|
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="-293 384 25 23"
|
||||||
|
xml:space="preserve"
|
||||||
|
width="25"
|
||||||
|
height="23"><metadata
|
||||||
|
id="metadata21"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs19" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
id="namedview17"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:pagecheckerboard="true"
|
||||||
|
inkscape:zoom="9.44"
|
||||||
|
inkscape:cx="-0.84745763"
|
||||||
|
inkscape:cy="12.5"
|
||||||
|
inkscape:window-x="2552"
|
||||||
|
inkscape:window-y="122"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg2" />
|
||||||
|
<style
|
||||||
|
type="text/css"
|
||||||
|
id="style2">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g
|
||||||
|
id="g14"
|
||||||
|
transform="matrix(1.2624869,0,0,1.3601695,73.614445,-144.84322)">
|
||||||
|
<g
|
||||||
|
id="g12">
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m -277.4,396 c -0.7,0 -1.3,0 -2,0 -0.4,0 -0.5,-0.1 -0.5,-0.5 0,-1 0,-2 0,-3 0,-0.3 0.2,-0.5 0.5,-0.5 1.3,-0.1 2.6,-0.3 3.9,-0.4 0.4,0 0.7,0.1 0.7,0.6 0,1.1 0,2.2 0,3.3 0,0.4 -0.2,0.6 -0.6,0.6 -0.7,-0.1 -1.4,-0.1 -2,-0.1 z"
|
||||||
|
id="path4"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m -274.9,399.3 c 0,0.6 0,1.1 0,1.7 0,0.4 -0.1,0.6 -0.6,0.6 -1.4,-0.1 -2.8,-0.3 -4.1,-0.4 -0.3,0 -0.4,-0.3 -0.4,-0.5 0,-1 0,-2 0,-3 0,-0.4 0.2,-0.5 0.6,-0.5 1.3,0 2.6,0 3.9,0 0.5,0 0.6,0.2 0.6,0.6 0,0.4 0,0.9 0,1.5 z"
|
||||||
|
id="path6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m -283.5,396 c -0.6,0 -1.3,0 -1.9,0 -0.4,0 -0.6,-0.1 -0.6,-0.6 0,-0.8 0,-1.5 0,-2.3 0,-0.4 0.2,-0.6 0.6,-0.7 1.3,-0.1 2.7,-0.3 4,-0.4 0.4,0 0.5,0.1 0.5,0.5 0,1 0,1.9 0,2.9 0,0.4 -0.2,0.5 -0.5,0.5 -0.8,0.1 -1.5,0.1 -2.1,0.1 z"
|
||||||
|
id="path8"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m -283.5,397 c 0.6,0 1.3,0 1.9,0 0.4,0 0.6,0.1 0.6,0.5 0,1 0,1.9 0,2.9 0,0.4 -0.2,0.5 -0.5,0.5 -1.3,-0.1 -2.7,-0.3 -4,-0.4 -0.4,0 -0.6,-0.2 -0.6,-0.7 0,-0.7 0,-1.5 0,-2.2 0,-0.5 0.2,-0.7 0.7,-0.7 0.6,0.1 1.2,0.1 1.9,0.1 z"
|
||||||
|
id="path10"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
71
static/js/novnc/app/locale/cs.json
Executable file
71
static/js/novnc/app/locale/cs.json
Executable file
|
@ -0,0 +1,71 @@
|
||||||
|
{
|
||||||
|
"Connecting...": "Připojení...",
|
||||||
|
"Disconnecting...": "Odpojení...",
|
||||||
|
"Reconnecting...": "Obnova připojení...",
|
||||||
|
"Internal error": "Vnitřní chyba",
|
||||||
|
"Must set host": "Hostitel musí být nastavení",
|
||||||
|
"Connected (encrypted) to ": "Připojení (šifrované) k ",
|
||||||
|
"Connected (unencrypted) to ": "Připojení (nešifrované) k ",
|
||||||
|
"Something went wrong, connection is closed": "Něco se pokazilo, odpojeno",
|
||||||
|
"Failed to connect to server": "Chyba připojení k serveru",
|
||||||
|
"Disconnected": "Odpojeno",
|
||||||
|
"New connection has been rejected with reason: ": "Nové připojení bylo odmítnuto s odůvodněním: ",
|
||||||
|
"New connection has been rejected": "Nové připojení bylo odmítnuto",
|
||||||
|
"Password is required": "Je vyžadováno heslo",
|
||||||
|
"noVNC encountered an error:": "noVNC narazilo na chybu:",
|
||||||
|
"Hide/Show the control bar": "Skrýt/zobrazit ovládací panel",
|
||||||
|
"Move/Drag Viewport": "Přesunout/přetáhnout výřez",
|
||||||
|
"viewport drag": "přesun výřezu",
|
||||||
|
"Active Mouse Button": "Aktivní tlačítka myši",
|
||||||
|
"No mousebutton": "Žádné",
|
||||||
|
"Left mousebutton": "Levé tlačítko myši",
|
||||||
|
"Middle mousebutton": "Prostřední tlačítko myši",
|
||||||
|
"Right mousebutton": "Pravé tlačítko myši",
|
||||||
|
"Keyboard": "Klávesnice",
|
||||||
|
"Show Keyboard": "Zobrazit klávesnici",
|
||||||
|
"Extra keys": "Extra klávesy",
|
||||||
|
"Show Extra Keys": "Zobrazit extra klávesy",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"Toggle Ctrl": "Přepnout Ctrl",
|
||||||
|
"Alt": "Alt",
|
||||||
|
"Toggle Alt": "Přepnout Alt",
|
||||||
|
"Send Tab": "Odeslat tabulátor",
|
||||||
|
"Tab": "Tab",
|
||||||
|
"Esc": "Esc",
|
||||||
|
"Send Escape": "Odeslat Esc",
|
||||||
|
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||||
|
"Send Ctrl-Alt-Del": "Poslat Ctrl-Alt-Del",
|
||||||
|
"Shutdown/Reboot": "Vypnutí/Restart",
|
||||||
|
"Shutdown/Reboot...": "Vypnutí/Restart...",
|
||||||
|
"Power": "Napájení",
|
||||||
|
"Shutdown": "Vypnout",
|
||||||
|
"Reboot": "Restart",
|
||||||
|
"Reset": "Reset",
|
||||||
|
"Clipboard": "Schránka",
|
||||||
|
"Clear": "Vymazat",
|
||||||
|
"Fullscreen": "Celá obrazovka",
|
||||||
|
"Settings": "Nastavení",
|
||||||
|
"Shared Mode": "Sdílený režim",
|
||||||
|
"View Only": "Pouze prohlížení",
|
||||||
|
"Clip to Window": "Přizpůsobit oknu",
|
||||||
|
"Scaling Mode:": "Přizpůsobení velikosti",
|
||||||
|
"None": "Žádné",
|
||||||
|
"Local Scaling": "Místní",
|
||||||
|
"Remote Resizing": "Vzdálené",
|
||||||
|
"Advanced": "Pokročilé",
|
||||||
|
"Repeater ID:": "ID opakovače",
|
||||||
|
"WebSocket": "WebSocket",
|
||||||
|
"Encrypt": "Šifrování:",
|
||||||
|
"Host:": "Hostitel:",
|
||||||
|
"Port:": "Port:",
|
||||||
|
"Path:": "Cesta",
|
||||||
|
"Automatic Reconnect": "Automatická obnova připojení",
|
||||||
|
"Reconnect Delay (ms):": "Zpoždění připojení (ms)",
|
||||||
|
"Show Dot when No Cursor": "Tečka místo chybějícího kurzoru myši",
|
||||||
|
"Logging:": "Logování:",
|
||||||
|
"Disconnect": "Odpojit",
|
||||||
|
"Connect": "Připojit",
|
||||||
|
"Password:": "Heslo",
|
||||||
|
"Send Password": "Odeslat heslo",
|
||||||
|
"Cancel": "Zrušit"
|
||||||
|
}
|
70
static/js/novnc/app/locale/ko.json
Executable file
70
static/js/novnc/app/locale/ko.json
Executable file
|
@ -0,0 +1,70 @@
|
||||||
|
{
|
||||||
|
"Connecting...": "연결중...",
|
||||||
|
"Disconnecting...": "연결 해제중...",
|
||||||
|
"Reconnecting...": "재연결중...",
|
||||||
|
"Internal error": "내부 오류",
|
||||||
|
"Must set host": "호스트는 설정되어야 합니다.",
|
||||||
|
"Connected (encrypted) to ": "다음과 (암호화되어) 연결되었습니다:",
|
||||||
|
"Connected (unencrypted) to ": "다음과 (암호화 없이) 연결되었습니다:",
|
||||||
|
"Something went wrong, connection is closed": "무언가 잘못되었습니다, 연결이 닫혔습니다.",
|
||||||
|
"Failed to connect to server": "서버에 연결하지 못했습니다.",
|
||||||
|
"Disconnected": "연결이 해제되었습니다.",
|
||||||
|
"New connection has been rejected with reason: ": "새 연결이 다음 이유로 거부되었습니다:",
|
||||||
|
"New connection has been rejected": "새 연결이 거부되었습니다.",
|
||||||
|
"Password is required": "비밀번호가 필요합니다.",
|
||||||
|
"noVNC encountered an error:": "noVNC에 오류가 발생했습니다:",
|
||||||
|
"Hide/Show the control bar": "컨트롤 바 숨기기/보이기",
|
||||||
|
"Move/Drag Viewport": "움직이기/드래그 뷰포트",
|
||||||
|
"viewport drag": "뷰포트 드래그",
|
||||||
|
"Active Mouse Button": "마우스 버튼 활성화",
|
||||||
|
"No mousebutton": "마우스 버튼 없음",
|
||||||
|
"Left mousebutton": "왼쪽 마우스 버튼",
|
||||||
|
"Middle mousebutton": "중간 마우스 버튼",
|
||||||
|
"Right mousebutton": "오른쪽 마우스 버튼",
|
||||||
|
"Keyboard": "키보드",
|
||||||
|
"Show Keyboard": "키보드 보이기",
|
||||||
|
"Extra keys": "기타 키들",
|
||||||
|
"Show Extra Keys": "기타 키들 보이기",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"Toggle Ctrl": "Ctrl 켜기/끄기",
|
||||||
|
"Alt": "Alt",
|
||||||
|
"Toggle Alt": "Alt 켜기/끄기",
|
||||||
|
"Send Tab": "Tab 보내기",
|
||||||
|
"Tab": "Tab",
|
||||||
|
"Esc": "Esc",
|
||||||
|
"Send Escape": "Esc 보내기",
|
||||||
|
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||||
|
"Send Ctrl-Alt-Del": "Ctrl+Alt+Del 보내기",
|
||||||
|
"Shutdown/Reboot": "셧다운/리붓",
|
||||||
|
"Shutdown/Reboot...": "셧다운/리붓...",
|
||||||
|
"Power": "전원",
|
||||||
|
"Shutdown": "셧다운",
|
||||||
|
"Reboot": "리붓",
|
||||||
|
"Reset": "리셋",
|
||||||
|
"Clipboard": "클립보드",
|
||||||
|
"Clear": "지우기",
|
||||||
|
"Fullscreen": "전체화면",
|
||||||
|
"Settings": "설정",
|
||||||
|
"Shared Mode": "공유 모드",
|
||||||
|
"View Only": "보기 전용",
|
||||||
|
"Clip to Window": "창에 클립",
|
||||||
|
"Scaling Mode:": "스케일링 모드:",
|
||||||
|
"None": "없음",
|
||||||
|
"Local Scaling": "로컬 스케일링",
|
||||||
|
"Remote Resizing": "원격 크기 조절",
|
||||||
|
"Advanced": "고급",
|
||||||
|
"Repeater ID:": "중계 ID",
|
||||||
|
"WebSocket": "웹소켓",
|
||||||
|
"Encrypt": "암호화",
|
||||||
|
"Host:": "호스트:",
|
||||||
|
"Port:": "포트:",
|
||||||
|
"Path:": "위치:",
|
||||||
|
"Automatic Reconnect": "자동 재연결",
|
||||||
|
"Reconnect Delay (ms):": "재연결 지연 시간 (ms)",
|
||||||
|
"Logging:": "로깅",
|
||||||
|
"Disconnect": "연결 해제",
|
||||||
|
"Connect": "연결",
|
||||||
|
"Password:": "비밀번호:",
|
||||||
|
"Send Password": "비밀번호 전송",
|
||||||
|
"Cancel": "취소"
|
||||||
|
}
|
|
@ -1,13 +1,17 @@
|
||||||
{
|
{
|
||||||
"Connecting...": "Verbinden...",
|
"Connecting...": "Verbinden...",
|
||||||
|
"Disconnecting...": "Verbinding verbreken...",
|
||||||
|
"Reconnecting...": "Opnieuw verbinding maken...",
|
||||||
|
"Internal error": "Interne fout",
|
||||||
|
"Must set host": "Host moeten worden ingesteld",
|
||||||
"Connected (encrypted) to ": "Verbonden (versleuteld) met ",
|
"Connected (encrypted) to ": "Verbonden (versleuteld) met ",
|
||||||
"Connected (unencrypted) to ": "Verbonden (onversleuteld) met ",
|
"Connected (unencrypted) to ": "Verbonden (onversleuteld) met ",
|
||||||
"Disconnecting...": "Verbinding verbreken...",
|
"Something went wrong, connection is closed": "Er iets fout gelopen, verbinding werd verbroken",
|
||||||
|
"Failed to connect to server": "Verbinding maken met server is mislukt",
|
||||||
"Disconnected": "Verbinding verbroken",
|
"Disconnected": "Verbinding verbroken",
|
||||||
"Must set host": "Host moeten worden ingesteld",
|
"New connection has been rejected with reason: ": "Nieuwe verbinding is geweigerd omwille van de volgende reden: ",
|
||||||
"Reconnecting...": "Opnieuw verbinding maken...",
|
"New connection has been rejected": "Nieuwe verbinding is geweigerd",
|
||||||
"Password is required": "Wachtwoord is vereist",
|
"Password is required": "Wachtwoord is vereist",
|
||||||
"Disconnect timeout": "Timeout tijdens verbreken van verbinding",
|
|
||||||
"noVNC encountered an error:": "noVNC heeft een fout bemerkt:",
|
"noVNC encountered an error:": "noVNC heeft een fout bemerkt:",
|
||||||
"Hide/Show the control bar": "Verberg/Toon de bedieningsbalk",
|
"Hide/Show the control bar": "Verberg/Toon de bedieningsbalk",
|
||||||
"Move/Drag Viewport": "Verplaats/Versleep Kijkvenster",
|
"Move/Drag Viewport": "Verplaats/Versleep Kijkvenster",
|
||||||
|
@ -22,9 +26,11 @@
|
||||||
"Extra keys": "Extra toetsen",
|
"Extra keys": "Extra toetsen",
|
||||||
"Show Extra Keys": "Toon Extra Toetsen",
|
"Show Extra Keys": "Toon Extra Toetsen",
|
||||||
"Ctrl": "Ctrl",
|
"Ctrl": "Ctrl",
|
||||||
"Toggle Ctrl": "Ctrl aan/uitzetten",
|
"Toggle Ctrl": "Ctrl omschakelen",
|
||||||
"Alt": "Alt",
|
"Alt": "Alt",
|
||||||
"Toggle Alt": "Alt aan/uitzetten",
|
"Toggle Alt": "Alt omschakelen",
|
||||||
|
"Toggle Windows": "Windows omschakelen",
|
||||||
|
"Windows": "Windows",
|
||||||
"Send Tab": "Tab Sturen",
|
"Send Tab": "Tab Sturen",
|
||||||
"Tab": "Tab",
|
"Tab": "Tab",
|
||||||
"Esc": "Esc",
|
"Esc": "Esc",
|
||||||
|
@ -47,10 +53,8 @@
|
||||||
"Scaling Mode:": "Schaalmodus:",
|
"Scaling Mode:": "Schaalmodus:",
|
||||||
"None": "Geen",
|
"None": "Geen",
|
||||||
"Local Scaling": "Lokaal Schalen",
|
"Local Scaling": "Lokaal Schalen",
|
||||||
"Local Downscaling": "Lokaal Neerschalen",
|
|
||||||
"Remote Resizing": "Op Afstand Formaat Wijzigen",
|
"Remote Resizing": "Op Afstand Formaat Wijzigen",
|
||||||
"Advanced": "Geavanceerd",
|
"Advanced": "Geavanceerd",
|
||||||
"Local Cursor": "Lokale Cursor",
|
|
||||||
"Repeater ID:": "Repeater ID:",
|
"Repeater ID:": "Repeater ID:",
|
||||||
"WebSocket": "WebSocket",
|
"WebSocket": "WebSocket",
|
||||||
"Encrypt": "Versleutelen",
|
"Encrypt": "Versleutelen",
|
||||||
|
@ -59,10 +63,11 @@
|
||||||
"Path:": "Pad:",
|
"Path:": "Pad:",
|
||||||
"Automatic Reconnect": "Automatisch Opnieuw Verbinden",
|
"Automatic Reconnect": "Automatisch Opnieuw Verbinden",
|
||||||
"Reconnect Delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):",
|
"Reconnect Delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):",
|
||||||
|
"Show Dot when No Cursor": "Geef stip weer indien geen cursor",
|
||||||
"Logging:": "Logmeldingen:",
|
"Logging:": "Logmeldingen:",
|
||||||
"Disconnect": "Verbinding verbreken",
|
"Disconnect": "Verbinding verbreken",
|
||||||
"Connect": "Verbinden",
|
"Connect": "Verbinden",
|
||||||
"Password:": "Wachtwoord:",
|
"Password:": "Wachtwoord:",
|
||||||
"Cancel": "Annuleren",
|
"Send Password": "Verzend Wachtwoord:",
|
||||||
"Canvas not supported.": "Canvas wordt niet ondersteund."
|
"Cancel": "Annuleren"
|
||||||
}
|
}
|
73
static/js/novnc/app/locale/ru.json
Executable file
73
static/js/novnc/app/locale/ru.json
Executable file
|
@ -0,0 +1,73 @@
|
||||||
|
{
|
||||||
|
"Connecting...": "Подключение...",
|
||||||
|
"Disconnecting...": "Отключение...",
|
||||||
|
"Reconnecting...": "Переподключение...",
|
||||||
|
"Internal error": "Внутренняя ошибка",
|
||||||
|
"Must set host": "Задайте имя сервера или IP",
|
||||||
|
"Connected (encrypted) to ": "Подключено (с шифрованием) к ",
|
||||||
|
"Connected (unencrypted) to ": "Подключено (без шифрования) к ",
|
||||||
|
"Something went wrong, connection is closed": "Что-то пошло не так, подключение разорвано",
|
||||||
|
"Failed to connect to server": "Ошибка подключения к серверу",
|
||||||
|
"Disconnected": "Отключено",
|
||||||
|
"New connection has been rejected with reason: ": "Подключиться не удалось: ",
|
||||||
|
"New connection has been rejected": "Подключиться не удалось",
|
||||||
|
"Password is required": "Требуется пароль",
|
||||||
|
"noVNC encountered an error:": "Ошибка noVNC: ",
|
||||||
|
"Hide/Show the control bar": "Скрыть/Показать контрольную панель",
|
||||||
|
"Move/Drag Viewport": "Переместить окно",
|
||||||
|
"viewport drag": "Переместить окно",
|
||||||
|
"Active Mouse Button": "Активировать кнопки мыши",
|
||||||
|
"No mousebutton": "Отключить кнопки мыши",
|
||||||
|
"Left mousebutton": "Левая кнопка мыши",
|
||||||
|
"Middle mousebutton": "Средняя кнопка мыши",
|
||||||
|
"Right mousebutton": "Правая кнопка мыши",
|
||||||
|
"Keyboard": "Клавиатура",
|
||||||
|
"Show Keyboard": "Показать клавиатуру",
|
||||||
|
"Extra keys": "Доп. кнопки",
|
||||||
|
"Show Extra Keys": "Показать дополнительные кнопки",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"Toggle Ctrl": "Передать нажатие Ctrl",
|
||||||
|
"Alt": "Alt",
|
||||||
|
"Toggle Alt": "Передать нажатие Alt",
|
||||||
|
"Toggle Windows": "Переключение вкладок",
|
||||||
|
"Windows": "Вкладка",
|
||||||
|
"Send Tab": "Передать нажатие Tab",
|
||||||
|
"Tab": "Tab",
|
||||||
|
"Esc": "Esc",
|
||||||
|
"Send Escape": "Передать нажатие Escape",
|
||||||
|
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||||
|
"Send Ctrl-Alt-Del": "Передать нажатие Ctrl-Alt-Del",
|
||||||
|
"Shutdown/Reboot": "Выключить/Перезагрузить",
|
||||||
|
"Shutdown/Reboot...": "Выключить/Перезагрузить...",
|
||||||
|
"Power": "Питание",
|
||||||
|
"Shutdown": "Выключить",
|
||||||
|
"Reboot": "Перезагрузить",
|
||||||
|
"Reset": "Сброс",
|
||||||
|
"Clipboard": "Буфер обмена",
|
||||||
|
"Clear": "Очистить",
|
||||||
|
"Fullscreen": "Во весь экран",
|
||||||
|
"Settings": "Настройки",
|
||||||
|
"Shared Mode": "Общий режим",
|
||||||
|
"View Only": "Просмотр",
|
||||||
|
"Clip to Window": "В окно",
|
||||||
|
"Scaling Mode:": "Масштаб:",
|
||||||
|
"None": "Нет",
|
||||||
|
"Local Scaling": "Локльный масштаб",
|
||||||
|
"Remote Resizing": "Удаленный масштаб",
|
||||||
|
"Advanced": "Дополнительно",
|
||||||
|
"Repeater ID:": "Идентификатор ID:",
|
||||||
|
"WebSocket": "WebSocket",
|
||||||
|
"Encrypt": "Шифрование",
|
||||||
|
"Host:": "Сервер:",
|
||||||
|
"Port:": "Порт:",
|
||||||
|
"Path:": "Путь:",
|
||||||
|
"Automatic Reconnect": "Автоматическое переподключение",
|
||||||
|
"Reconnect Delay (ms):": "Задержка переподключения (мс):",
|
||||||
|
"Show Dot when No Cursor": "Показать точку вместо курсора",
|
||||||
|
"Logging:": "Лог:",
|
||||||
|
"Disconnect": "Отключение",
|
||||||
|
"Connect": "Подключение",
|
||||||
|
"Password:": "Пароль:",
|
||||||
|
"Send Password": "Пароль: ",
|
||||||
|
"Cancel": "Выход"
|
||||||
|
}
|
|
@ -1,13 +1,17 @@
|
||||||
{
|
{
|
||||||
"Connecting...": "Ansluter...",
|
"Connecting...": "Ansluter...",
|
||||||
|
"Disconnecting...": "Kopplar ner...",
|
||||||
|
"Reconnecting...": "Återansluter...",
|
||||||
|
"Internal error": "Internt fel",
|
||||||
|
"Must set host": "Du måste specifiera en värd",
|
||||||
"Connected (encrypted) to ": "Ansluten (krypterat) till ",
|
"Connected (encrypted) to ": "Ansluten (krypterat) till ",
|
||||||
"Connected (unencrypted) to ": "Ansluten (okrypterat) till ",
|
"Connected (unencrypted) to ": "Ansluten (okrypterat) till ",
|
||||||
"Disconnecting...": "Kopplar ner...",
|
"Something went wrong, connection is closed": "Något gick fel, anslutningen avslutades",
|
||||||
|
"Failed to connect to server": "Misslyckades att ansluta till servern",
|
||||||
"Disconnected": "Frånkopplad",
|
"Disconnected": "Frånkopplad",
|
||||||
"Must set host": "Du måste specifiera en värd",
|
"New connection has been rejected with reason: ": "Ny anslutning har blivit nekad med följande skäl: ",
|
||||||
"Reconnecting...": "Återansluter...",
|
"New connection has been rejected": "Ny anslutning har blivit nekad",
|
||||||
"Password is required": "Lösenord krävs",
|
"Password is required": "Lösenord krävs",
|
||||||
"Disconnect timeout": "Det tog för lång tid att koppla ner",
|
|
||||||
"noVNC encountered an error:": "noVNC stötte på ett problem:",
|
"noVNC encountered an error:": "noVNC stötte på ett problem:",
|
||||||
"Hide/Show the control bar": "Göm/Visa kontrollbaren",
|
"Hide/Show the control bar": "Göm/Visa kontrollbaren",
|
||||||
"Move/Drag Viewport": "Flytta/Dra Vyn",
|
"Move/Drag Viewport": "Flytta/Dra Vyn",
|
||||||
|
@ -25,6 +29,8 @@
|
||||||
"Toggle Ctrl": "Växla Ctrl",
|
"Toggle Ctrl": "Växla Ctrl",
|
||||||
"Alt": "Alt",
|
"Alt": "Alt",
|
||||||
"Toggle Alt": "Växla Alt",
|
"Toggle Alt": "Växla Alt",
|
||||||
|
"Toggle Windows": "Växla Windows",
|
||||||
|
"Windows": "Windows",
|
||||||
"Send Tab": "Skicka Tab",
|
"Send Tab": "Skicka Tab",
|
||||||
"Tab": "Tab",
|
"Tab": "Tab",
|
||||||
"Esc": "Esc",
|
"Esc": "Esc",
|
||||||
|
@ -47,10 +53,8 @@
|
||||||
"Scaling Mode:": "Skalningsläge:",
|
"Scaling Mode:": "Skalningsläge:",
|
||||||
"None": "Ingen",
|
"None": "Ingen",
|
||||||
"Local Scaling": "Lokal Skalning",
|
"Local Scaling": "Lokal Skalning",
|
||||||
"Local Downscaling": "Lokal Nedskalning",
|
|
||||||
"Remote Resizing": "Ändra Storlek",
|
"Remote Resizing": "Ändra Storlek",
|
||||||
"Advanced": "Avancerat",
|
"Advanced": "Avancerat",
|
||||||
"Local Cursor": "Lokal Muspekare",
|
|
||||||
"Repeater ID:": "Repeater-ID:",
|
"Repeater ID:": "Repeater-ID:",
|
||||||
"WebSocket": "WebSocket",
|
"WebSocket": "WebSocket",
|
||||||
"Encrypt": "Kryptera",
|
"Encrypt": "Kryptera",
|
||||||
|
@ -59,10 +63,11 @@
|
||||||
"Path:": "Sökväg:",
|
"Path:": "Sökväg:",
|
||||||
"Automatic Reconnect": "Automatisk Återanslutning",
|
"Automatic Reconnect": "Automatisk Återanslutning",
|
||||||
"Reconnect Delay (ms):": "Fördröjning (ms):",
|
"Reconnect Delay (ms):": "Fördröjning (ms):",
|
||||||
|
"Show Dot when No Cursor": "Visa prick när ingen muspekare finns",
|
||||||
"Logging:": "Loggning:",
|
"Logging:": "Loggning:",
|
||||||
"Disconnect": "Koppla från",
|
"Disconnect": "Koppla från",
|
||||||
"Connect": "Anslut",
|
"Connect": "Anslut",
|
||||||
"Password:": "Lösenord:",
|
"Password:": "Lösenord:",
|
||||||
"Cancel": "Avbryt",
|
"Send Password": "Skicka lösenord",
|
||||||
"Canvas not supported.": "Canvas stöds ej"
|
"Cancel": "Avbryt"
|
||||||
}
|
}
|
69
static/js/novnc/app/locale/zh_CN.json
Executable file
69
static/js/novnc/app/locale/zh_CN.json
Executable file
|
@ -0,0 +1,69 @@
|
||||||
|
{
|
||||||
|
"Connecting...": "链接中...",
|
||||||
|
"Disconnecting...": "正在中断连接...",
|
||||||
|
"Reconnecting...": "重新链接中...",
|
||||||
|
"Internal error": "内部错误",
|
||||||
|
"Must set host": "请提供主机名",
|
||||||
|
"Connected (encrypted) to ": "已加密链接到",
|
||||||
|
"Connected (unencrypted) to ": "未加密链接到",
|
||||||
|
"Something went wrong, connection is closed": "发生错误,链接已关闭",
|
||||||
|
"Failed to connect to server": "无法链接到服务器",
|
||||||
|
"Disconnected": "链接已中断",
|
||||||
|
"New connection has been rejected with reason: ": "链接被拒绝,原因:",
|
||||||
|
"New connection has been rejected": "链接被拒绝",
|
||||||
|
"Password is required": "请提供密码",
|
||||||
|
"noVNC encountered an error:": "noVNC 遇到一个错误:",
|
||||||
|
"Hide/Show the control bar": "显示/隐藏控制列",
|
||||||
|
"Move/Drag Viewport": "拖放显示范围",
|
||||||
|
"viewport drag": "显示范围拖放",
|
||||||
|
"Active Mouse Button": "启动鼠标按鍵",
|
||||||
|
"No mousebutton": "禁用鼠标按鍵",
|
||||||
|
"Left mousebutton": "鼠标左鍵",
|
||||||
|
"Middle mousebutton": "鼠标中鍵",
|
||||||
|
"Right mousebutton": "鼠标右鍵",
|
||||||
|
"Keyboard": "键盘",
|
||||||
|
"Show Keyboard": "显示键盘",
|
||||||
|
"Extra keys": "额外按键",
|
||||||
|
"Show Extra Keys": "显示额外按键",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"Toggle Ctrl": "切换 Ctrl",
|
||||||
|
"Alt": "Alt",
|
||||||
|
"Toggle Alt": "切换 Alt",
|
||||||
|
"Send Tab": "发送 Tab 键",
|
||||||
|
"Tab": "Tab",
|
||||||
|
"Esc": "Esc",
|
||||||
|
"Send Escape": "发送 Escape 键",
|
||||||
|
"Ctrl+Alt+Del": "Ctrl-Alt-Del",
|
||||||
|
"Send Ctrl-Alt-Del": "发送 Ctrl-Alt-Del 键",
|
||||||
|
"Shutdown/Reboot": "关机/重新启动",
|
||||||
|
"Shutdown/Reboot...": "关机/重新启动...",
|
||||||
|
"Power": "电源",
|
||||||
|
"Shutdown": "关机",
|
||||||
|
"Reboot": "重新启动",
|
||||||
|
"Reset": "重置",
|
||||||
|
"Clipboard": "剪贴板",
|
||||||
|
"Clear": "清除",
|
||||||
|
"Fullscreen": "全屏幕",
|
||||||
|
"Settings": "设置",
|
||||||
|
"Shared Mode": "分享模式",
|
||||||
|
"View Only": "仅检视",
|
||||||
|
"Clip to Window": "限制/裁切窗口大小",
|
||||||
|
"Scaling Mode:": "缩放模式:",
|
||||||
|
"None": "无",
|
||||||
|
"Local Scaling": "本地缩放",
|
||||||
|
"Remote Resizing": "远程调整大小",
|
||||||
|
"Advanced": "高级",
|
||||||
|
"Repeater ID:": "中继站 ID",
|
||||||
|
"WebSocket": "WebSocket",
|
||||||
|
"Encrypt": "加密",
|
||||||
|
"Host:": "主机:",
|
||||||
|
"Port:": "端口:",
|
||||||
|
"Path:": "路径:",
|
||||||
|
"Automatic Reconnect": "自动重新链接",
|
||||||
|
"Reconnect Delay (ms):": "重新链接间隔 (ms):",
|
||||||
|
"Logging:": "日志级别:",
|
||||||
|
"Disconnect": "终端链接",
|
||||||
|
"Connect": "链接",
|
||||||
|
"Password:": "密码:",
|
||||||
|
"Cancel": "取消"
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2012 Joel Martin
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
*
|
*
|
||||||
* See README.md for usage and integration instructions.
|
* See README.md for usage and integration instructions.
|
||||||
|
@ -10,36 +10,35 @@
|
||||||
* Localization Utilities
|
* Localization Utilities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function Localizer() {
|
export class Localizer {
|
||||||
|
constructor() {
|
||||||
// Currently configured language
|
// Currently configured language
|
||||||
this.language = 'en';
|
this.language = 'en';
|
||||||
|
|
||||||
// Current dictionary of translations
|
// Current dictionary of translations
|
||||||
this.dictionary = undefined;
|
this.dictionary = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
Localizer.prototype = {
|
|
||||||
// Configure suitable language based on user preferences
|
// Configure suitable language based on user preferences
|
||||||
setup: function (supportedLanguages) {
|
setup(supportedLanguages) {
|
||||||
var userLanguages;
|
|
||||||
|
|
||||||
this.language = 'en'; // Default: US English
|
this.language = 'en'; // Default: US English
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Navigator.languages only available in Chrome (32+) and FireFox (32+)
|
* Navigator.languages only available in Chrome (32+) and FireFox (32+)
|
||||||
* Fall back to navigator.language for other browsers
|
* Fall back to navigator.language for other browsers
|
||||||
*/
|
*/
|
||||||
|
let userLanguages;
|
||||||
if (typeof window.navigator.languages == 'object') {
|
if (typeof window.navigator.languages == 'object') {
|
||||||
userLanguages = window.navigator.languages;
|
userLanguages = window.navigator.languages;
|
||||||
} else {
|
} else {
|
||||||
userLanguages = [navigator.language || navigator.userLanguage];
|
userLanguages = [navigator.language || navigator.userLanguage];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0;i < userLanguages.length;i++) {
|
for (let i = 0;i < userLanguages.length;i++) {
|
||||||
var userLang = userLanguages[i];
|
const userLang = userLanguages[i]
|
||||||
userLang = userLang.toLowerCase();
|
.toLowerCase()
|
||||||
userLang = userLang.replace("_", "-");
|
.replace("_", "-")
|
||||||
userLang = userLang.split("-");
|
.split("-");
|
||||||
|
|
||||||
// Built-in default?
|
// Built-in default?
|
||||||
if ((userLang[0] === 'en') &&
|
if ((userLang[0] === 'en') &&
|
||||||
|
@ -48,66 +47,69 @@ Localizer.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// First pass: perfect match
|
// First pass: perfect match
|
||||||
for (var j = 0;j < supportedLanguages.length;j++) {
|
for (let j = 0; j < supportedLanguages.length; j++) {
|
||||||
var supLang = supportedLanguages[j];
|
const supLang = supportedLanguages[j]
|
||||||
supLang = supLang.toLowerCase();
|
.toLowerCase()
|
||||||
supLang = supLang.replace("_", "-");
|
.replace("_", "-")
|
||||||
supLang = supLang.split("-");
|
.split("-");
|
||||||
|
|
||||||
if (userLang[0] !== supLang[0])
|
if (userLang[0] !== supLang[0]) {
|
||||||
continue;
|
continue;
|
||||||
if (userLang[1] !== supLang[1])
|
}
|
||||||
|
if (userLang[1] !== supLang[1]) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
this.language = supportedLanguages[j];
|
this.language = supportedLanguages[j];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second pass: fallback
|
// Second pass: fallback
|
||||||
for (var j = 0;j < supportedLanguages.length;j++) {
|
for (let j = 0;j < supportedLanguages.length;j++) {
|
||||||
supLang = supportedLanguages[j];
|
const supLang = supportedLanguages[j]
|
||||||
supLang = supLang.toLowerCase();
|
.toLowerCase()
|
||||||
supLang = supLang.replace("_", "-");
|
.replace("_", "-")
|
||||||
supLang = supLang.split("-");
|
.split("-");
|
||||||
|
|
||||||
if (userLang[0] !== supLang[0])
|
if (userLang[0] !== supLang[0]) {
|
||||||
continue;
|
continue;
|
||||||
if (supLang[1] !== undefined)
|
}
|
||||||
|
if (supLang[1] !== undefined) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
this.language = supportedLanguages[j];
|
this.language = supportedLanguages[j];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// Retrieve localised text
|
// Retrieve localised text
|
||||||
get: function (id) {
|
get(id) {
|
||||||
if (typeof this.dictionary !== 'undefined' && this.dictionary[id]) {
|
if (typeof this.dictionary !== 'undefined' && this.dictionary[id]) {
|
||||||
return this.dictionary[id];
|
return this.dictionary[id];
|
||||||
} else {
|
} else {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// Traverses the DOM and translates relevant fields
|
// Traverses the DOM and translates relevant fields
|
||||||
// See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
|
// See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
|
||||||
translateDOM: function () {
|
translateDOM() {
|
||||||
var self = this;
|
const self = this;
|
||||||
|
|
||||||
function process(elem, enabled) {
|
function process(elem, enabled) {
|
||||||
function isAnyOf(searchElement, items) {
|
function isAnyOf(searchElement, items) {
|
||||||
return items.indexOf(searchElement) !== -1;
|
return items.indexOf(searchElement) !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function translateAttribute(elem, attr) {
|
function translateAttribute(elem, attr) {
|
||||||
var str = elem.getAttribute(attr);
|
const str = self.get(elem.getAttribute(attr));
|
||||||
str = self.get(str);
|
|
||||||
elem.setAttribute(attr, str);
|
elem.setAttribute(attr, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
function translateTextNode(node) {
|
function translateTextNode(node) {
|
||||||
var str = node.data.trim();
|
const str = self.get(node.data.trim());
|
||||||
str = self.get(str);
|
|
||||||
node.data = str;
|
node.data = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,8 +154,8 @@ Localizer.prototype = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0;i < elem.childNodes.length;i++) {
|
for (let i = 0; i < elem.childNodes.length; i++) {
|
||||||
var node = elem.childNodes[i];
|
const node = elem.childNodes[i];
|
||||||
if (node.nodeType === node.ELEMENT_NODE) {
|
if (node.nodeType === node.ELEMENT_NODE) {
|
||||||
process(node, enabled);
|
process(node, enabled);
|
||||||
} else if (node.nodeType === node.TEXT_NODE && enabled) {
|
} else if (node.nodeType === node.TEXT_NODE && enabled) {
|
||||||
|
@ -163,8 +165,8 @@ Localizer.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
process(document.body, true);
|
process(document.body, true);
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export var l10n = new Localizer();
|
export const l10n = new Localizer();
|
||||||
export default l10n.get.bind(l10n);
|
export default l10n.get.bind(l10n);
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC base CSS
|
* noVNC base CSS
|
||||||
* Copyright (C) 2012 Joel Martin
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Copyright (C) 2016 Samuel Mannehed for Cendio AB
|
|
||||||
* Copyright (C) 2016 Pierre Ossman for Cendio AB
|
|
||||||
* noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
|
* noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
|
||||||
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
||||||
*/
|
*/
|
||||||
|
@ -30,6 +28,7 @@ body {
|
||||||
background-repeat:no-repeat;
|
background-repeat:no-repeat;
|
||||||
background-position:right bottom;
|
background-position:right bottom;
|
||||||
height:100%;
|
height:100%;
|
||||||
|
display: flex;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2012 Joel Martin
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Copyright (C) 2013 NTT corp.
|
|
||||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
*
|
*
|
||||||
* See README.md for usage and integration instructions.
|
* See README.md for usage and integration instructions.
|
||||||
|
@ -10,61 +9,65 @@
|
||||||
import { init_logging as main_init_logging } from '../core/util/logging.js';
|
import { init_logging as main_init_logging } from '../core/util/logging.js';
|
||||||
|
|
||||||
// init log level reading the logging HTTP param
|
// init log level reading the logging HTTP param
|
||||||
export function init_logging (level) {
|
export function init_logging(level) {
|
||||||
"use strict";
|
"use strict";
|
||||||
if (typeof level !== "undefined") {
|
if (typeof level !== "undefined") {
|
||||||
main_init_logging(level);
|
main_init_logging(level);
|
||||||
} else {
|
} else {
|
||||||
var param = document.location.href.match(/logging=([A-Za-z0-9\._\-]*)/);
|
const param = document.location.href.match(/logging=([A-Za-z0-9._-]*)/);
|
||||||
main_init_logging(param || undefined);
|
main_init_logging(param || undefined);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// Read a query string variable
|
// Read a query string variable
|
||||||
export function getQueryVar (name, defVal) {
|
export function getQueryVar(name, defVal) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
|
const re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
|
||||||
match = document.location.href.match(re);
|
match = document.location.href.match(re);
|
||||||
if (typeof defVal === 'undefined') { defVal = null; }
|
if (typeof defVal === 'undefined') { defVal = null; }
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
return decodeURIComponent(match[1]);
|
return decodeURIComponent(match[1]);
|
||||||
} else {
|
|
||||||
return defVal;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
return defVal;
|
||||||
|
}
|
||||||
|
|
||||||
// Read a hash fragment variable
|
// Read a hash fragment variable
|
||||||
export function getHashVar (name, defVal) {
|
export function getHashVar(name, defVal) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var re = new RegExp('.*[&#]' + name + '=([^&]*)'),
|
const re = new RegExp('.*[&#]' + name + '=([^&]*)'),
|
||||||
match = document.location.hash.match(re);
|
match = document.location.hash.match(re);
|
||||||
if (typeof defVal === 'undefined') { defVal = null; }
|
if (typeof defVal === 'undefined') { defVal = null; }
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
return decodeURIComponent(match[1]);
|
return decodeURIComponent(match[1]);
|
||||||
} else {
|
|
||||||
return defVal;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
return defVal;
|
||||||
|
}
|
||||||
|
|
||||||
// Read a variable from the fragment or the query string
|
// Read a variable from the fragment or the query string
|
||||||
// Fragment takes precedence
|
// Fragment takes precedence
|
||||||
export function getConfigVar (name, defVal) {
|
export function getConfigVar(name, defVal) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var val = getHashVar(name);
|
const val = getHashVar(name);
|
||||||
|
|
||||||
if (val === null) {
|
if (val === null) {
|
||||||
val = getQueryVar(name, defVal);
|
return getQueryVar(name, defVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
};
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
|
* Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// No days means only for this browser session
|
// No days means only for this browser session
|
||||||
export function createCookie (name, value, days) {
|
export function createCookie(name, value, days) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var date, expires;
|
let date, expires;
|
||||||
if (days) {
|
if (days) {
|
||||||
date = new Date();
|
date = new Date();
|
||||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||||
|
@ -73,115 +76,123 @@ export function createCookie (name, value, days) {
|
||||||
expires = "";
|
expires = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
var secure;
|
let secure;
|
||||||
if (document.location.protocol === "https:") {
|
if (document.location.protocol === "https:") {
|
||||||
secure = "; secure";
|
secure = "; secure";
|
||||||
} else {
|
} else {
|
||||||
secure = "";
|
secure = "";
|
||||||
}
|
}
|
||||||
document.cookie = name + "=" + value + expires + "; path=/" + secure;
|
document.cookie = name + "=" + value + expires + "; path=/" + secure;
|
||||||
};
|
}
|
||||||
|
|
||||||
export function readCookie (name, defaultValue) {
|
export function readCookie(name, defaultValue) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var nameEQ = name + "=",
|
const nameEQ = name + "=";
|
||||||
ca = document.cookie.split(';');
|
const ca = document.cookie.split(';');
|
||||||
|
|
||||||
for (var i = 0; i < ca.length; i += 1) {
|
for (let i = 0; i < ca.length; i += 1) {
|
||||||
var c = ca[i];
|
let c = ca[i];
|
||||||
while (c.charAt(0) === ' ') { c = c.substring(1, c.length); }
|
while (c.charAt(0) === ' ') {
|
||||||
if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length, c.length); }
|
c = c.substring(1, c.length);
|
||||||
|
}
|
||||||
|
if (c.indexOf(nameEQ) === 0) {
|
||||||
|
return c.substring(nameEQ.length, c.length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (typeof defaultValue !== 'undefined') ? defaultValue : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function eraseCookie (name) {
|
return (typeof defaultValue !== 'undefined') ? defaultValue : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function eraseCookie(name) {
|
||||||
"use strict";
|
"use strict";
|
||||||
createCookie(name, "", -1);
|
createCookie(name, "", -1);
|
||||||
};
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setting handling.
|
* Setting handling.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var settings = {};
|
let settings = {};
|
||||||
|
|
||||||
export function initSettings (callback /*, ...callbackArgs */) {
|
export function initSettings() {
|
||||||
"use strict";
|
if (!window.chrome || !window.chrome.storage) {
|
||||||
var callbackArgs = Array.prototype.slice.call(arguments, 1);
|
settings = {};
|
||||||
if (window.chrome && window.chrome.storage) {
|
return Promise.resolve();
|
||||||
window.chrome.storage.sync.get(function (cfg) {
|
|
||||||
settings = cfg;
|
|
||||||
if (callback) {
|
|
||||||
callback.apply(this, callbackArgs);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} else {
|
return new Promise(resolve => window.chrome.storage.sync.get(resolve))
|
||||||
// No-op
|
.then((cfg) => { settings = cfg; });
|
||||||
if (callback) {
|
}
|
||||||
callback.apply(this, callbackArgs);
|
|
||||||
}
|
// Update the settings cache, but do not write to permanent storage
|
||||||
}
|
export function setSetting(name, value) {
|
||||||
};
|
settings[name] = value;
|
||||||
|
}
|
||||||
|
|
||||||
// No days means only for this browser session
|
// No days means only for this browser session
|
||||||
export function writeSetting (name, value) {
|
export function writeSetting(name, value) {
|
||||||
"use strict";
|
"use strict";
|
||||||
if (window.chrome && window.chrome.storage) {
|
if (settings[name] === value) return;
|
||||||
if (settings[name] !== value) {
|
|
||||||
settings[name] = value;
|
settings[name] = value;
|
||||||
|
if (window.chrome && window.chrome.storage) {
|
||||||
window.chrome.storage.sync.set(settings);
|
window.chrome.storage.sync.set(settings);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
localStorage.setItem(name, value);
|
localStorage.setItem(name, value);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export function readSetting (name, defaultValue) {
|
export function readSetting(name, defaultValue) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var value;
|
let value;
|
||||||
if (window.chrome && window.chrome.storage) {
|
if ((name in settings) || (window.chrome && window.chrome.storage)) {
|
||||||
value = settings[name];
|
value = settings[name];
|
||||||
} else {
|
} else {
|
||||||
value = localStorage.getItem(name);
|
value = localStorage.getItem(name);
|
||||||
|
settings[name] = value;
|
||||||
}
|
}
|
||||||
if (typeof value === "undefined") {
|
if (typeof value === "undefined") {
|
||||||
value = null;
|
value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value === null && typeof defaultValue !== "undefined") {
|
if (value === null && typeof defaultValue !== "undefined") {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
export function eraseSetting (name) {
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function eraseSetting(name) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
// Deleting here means that next time the setting is read when using local
|
||||||
|
// storage, it will be pulled from local storage again.
|
||||||
|
// If the setting in local storage is changed (e.g. in another tab)
|
||||||
|
// between this delete and the next read, it could lead to an unexpected
|
||||||
|
// value change.
|
||||||
|
delete settings[name];
|
||||||
if (window.chrome && window.chrome.storage) {
|
if (window.chrome && window.chrome.storage) {
|
||||||
window.chrome.storage.sync.remove(name);
|
window.chrome.storage.sync.remove(name);
|
||||||
delete settings[name];
|
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem(name);
|
localStorage.removeItem(name);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export function injectParamIfMissing (path, param, value) {
|
export function injectParamIfMissing(path, param, value) {
|
||||||
// force pretend that we're dealing with a relative path
|
// force pretend that we're dealing with a relative path
|
||||||
// (assume that we wanted an extra if we pass one in)
|
// (assume that we wanted an extra if we pass one in)
|
||||||
path = "/" + path;
|
path = "/" + path;
|
||||||
|
|
||||||
var elem = document.createElement('a');
|
const elem = document.createElement('a');
|
||||||
elem.href = path;
|
elem.href = path;
|
||||||
|
|
||||||
var param_eq = encodeURIComponent(param) + "=";
|
const param_eq = encodeURIComponent(param) + "=";
|
||||||
var query;
|
let query;
|
||||||
if (elem.search) {
|
if (elem.search) {
|
||||||
query = elem.search.slice(1).split('&');
|
query = elem.search.slice(1).split('&');
|
||||||
} else {
|
} else {
|
||||||
query = [];
|
query = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!query.some(function (v) { return v.startsWith(param_eq); })) {
|
if (!query.some(v => v.startsWith(param_eq))) {
|
||||||
query.push(param_eq + encodeURIComponent(value));
|
query.push(param_eq + encodeURIComponent(value));
|
||||||
elem.search = "?" + query.join("&");
|
elem.search = "?" + query.join("&");
|
||||||
}
|
}
|
||||||
|
@ -190,27 +201,28 @@ export function injectParamIfMissing (path, param, value) {
|
||||||
// in the elem.pathname string. Handle that case gracefully.
|
// in the elem.pathname string. Handle that case gracefully.
|
||||||
if (elem.pathname.charAt(0) == "/") {
|
if (elem.pathname.charAt(0) == "/") {
|
||||||
return elem.pathname.slice(1) + elem.search + elem.hash;
|
return elem.pathname.slice(1) + elem.search + elem.hash;
|
||||||
} else {
|
|
||||||
return elem.pathname + elem.search + elem.hash;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
return elem.pathname + elem.search + elem.hash;
|
||||||
|
}
|
||||||
|
|
||||||
// sadly, we can't use the Fetch API until we decide to drop
|
// sadly, we can't use the Fetch API until we decide to drop
|
||||||
// IE11 support or polyfill promises and fetch in IE11.
|
// IE11 support or polyfill promises and fetch in IE11.
|
||||||
// resolve will receive an object on success, while reject
|
// resolve will receive an object on success, while reject
|
||||||
// will receive either an event or an error on failure.
|
// will receive either an event or an error on failure.
|
||||||
export function fetchJSON(path, resolve, reject) {
|
export function fetchJSON(path) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
// NB: IE11 doesn't support JSON as a responseType
|
// NB: IE11 doesn't support JSON as a responseType
|
||||||
var req = new XMLHttpRequest();
|
const req = new XMLHttpRequest();
|
||||||
req.open('GET', path);
|
req.open('GET', path);
|
||||||
|
|
||||||
req.onload = function () {
|
req.onload = () => {
|
||||||
if (req.status === 200) {
|
if (req.status === 200) {
|
||||||
|
let resObj;
|
||||||
try {
|
try {
|
||||||
var resObj = JSON.parse(req.responseText);
|
resObj = JSON.parse(req.responseText);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
resolve(resObj);
|
resolve(resObj);
|
||||||
} else {
|
} else {
|
||||||
|
@ -218,13 +230,10 @@ export function fetchJSON(path, resolve, reject) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
req.onerror = function (evt) {
|
req.onerror = evt => reject(new Error("XHR encountered an error while trying to load '" + path + "': " + evt.message));
|
||||||
reject(new Error("XHR encountered an error while trying to load '" + path + "': " + evt.message));
|
|
||||||
};
|
|
||||||
|
|
||||||
req.ontimeout = function (evt) {
|
req.ontimeout = evt => reject(new Error("XHR timed out while trying to load '" + path + "'"));
|
||||||
reject(new Error("XHR timed out while trying to load '" + path + "'"));
|
|
||||||
};
|
|
||||||
|
|
||||||
req.send();
|
req.send();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,45 +8,43 @@ import * as Log from './util/logging.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/* Convert data (an array of integers) to a Base64 string. */
|
/* Convert data (an array of integers) to a Base64 string. */
|
||||||
toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
|
toBase64Table: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
|
||||||
base64Pad : '=',
|
base64Pad: '=',
|
||||||
|
|
||||||
encode: function (data) {
|
encode(data) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var result = '';
|
let result = '';
|
||||||
var toBase64Table = this.toBase64Table;
|
const length = data.length;
|
||||||
var length = data.length;
|
const lengthpad = (length % 3);
|
||||||
var lengthpad = (length % 3);
|
|
||||||
// Convert every three bytes to 4 ascii characters.
|
// Convert every three bytes to 4 ascii characters.
|
||||||
|
|
||||||
for (var i = 0; i < (length - 2); i += 3) {
|
for (let i = 0; i < (length - 2); i += 3) {
|
||||||
result += toBase64Table[data[i] >> 2];
|
result += this.toBase64Table[data[i] >> 2];
|
||||||
result += toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
|
result += this.toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
|
||||||
result += toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
|
result += this.toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
|
||||||
result += toBase64Table[data[i + 2] & 0x3f];
|
result += this.toBase64Table[data[i + 2] & 0x3f];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the remaining 1 or 2 bytes, pad out to 4 characters.
|
// Convert the remaining 1 or 2 bytes, pad out to 4 characters.
|
||||||
var j = 0;
|
const j = length - lengthpad;
|
||||||
if (lengthpad === 2) {
|
if (lengthpad === 2) {
|
||||||
j = length - lengthpad;
|
result += this.toBase64Table[data[j] >> 2];
|
||||||
result += toBase64Table[data[j] >> 2];
|
result += this.toBase64Table[((data[j] & 0x03) << 4) + (data[j + 1] >> 4)];
|
||||||
result += toBase64Table[((data[j] & 0x03) << 4) + (data[j + 1] >> 4)];
|
result += this.toBase64Table[(data[j + 1] & 0x0f) << 2];
|
||||||
result += toBase64Table[(data[j + 1] & 0x0f) << 2];
|
result += this.toBase64Table[64];
|
||||||
result += toBase64Table[64];
|
|
||||||
} else if (lengthpad === 1) {
|
} else if (lengthpad === 1) {
|
||||||
j = length - lengthpad;
|
result += this.toBase64Table[data[j] >> 2];
|
||||||
result += toBase64Table[data[j] >> 2];
|
result += this.toBase64Table[(data[j] & 0x03) << 4];
|
||||||
result += toBase64Table[(data[j] & 0x03) << 4];
|
result += this.toBase64Table[64];
|
||||||
result += toBase64Table[64];
|
result += this.toBase64Table[64];
|
||||||
result += toBase64Table[64];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Convert Base64 data to a string */
|
/* Convert Base64 data to a string */
|
||||||
toBinaryTable : [
|
/* eslint-disable comma-spacing */
|
||||||
|
toBinaryTable: [
|
||||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
|
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
|
||||||
|
@ -56,27 +54,23 @@ export default {
|
||||||
-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
||||||
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
|
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
|
||||||
],
|
],
|
||||||
|
/* eslint-enable comma-spacing */
|
||||||
|
|
||||||
decode: function (data, offset) {
|
decode(data, offset = 0) {
|
||||||
"use strict";
|
let data_length = data.indexOf('=') - offset;
|
||||||
offset = typeof(offset) !== 'undefined' ? offset : 0;
|
|
||||||
var toBinaryTable = this.toBinaryTable;
|
|
||||||
var base64Pad = this.base64Pad;
|
|
||||||
var result, result_length;
|
|
||||||
var leftbits = 0; // number of bits decoded, but yet to be appended
|
|
||||||
var leftdata = 0; // bits decoded, but yet to be appended
|
|
||||||
var data_length = data.indexOf('=') - offset;
|
|
||||||
|
|
||||||
if (data_length < 0) { data_length = data.length - offset; }
|
if (data_length < 0) { data_length = data.length - offset; }
|
||||||
|
|
||||||
/* Every four characters is 3 resulting numbers */
|
/* Every four characters is 3 resulting numbers */
|
||||||
result_length = (data_length >> 2) * 3 + Math.floor((data_length % 4) / 1.5);
|
const result_length = (data_length >> 2) * 3 + Math.floor((data_length % 4) / 1.5);
|
||||||
result = new Array(result_length);
|
const result = new Array(result_length);
|
||||||
|
|
||||||
// Convert one by one.
|
// Convert one by one.
|
||||||
for (var idx = 0, i = offset; i < data.length; i++) {
|
|
||||||
var c = toBinaryTable[data.charCodeAt(i) & 0x7f];
|
let leftbits = 0; // number of bits decoded, but yet to be appended
|
||||||
var padding = (data.charAt(i) === base64Pad);
|
let leftdata = 0; // bits decoded, but yet to be appended
|
||||||
|
for (let idx = 0, i = offset; i < data.length; i++) {
|
||||||
|
const c = this.toBinaryTable[data.charCodeAt(i) & 0x7f];
|
||||||
|
const padding = (data.charAt(i) === this.base64Pad);
|
||||||
// Skip illegal characters and whitespace
|
// Skip illegal characters and whitespace
|
||||||
if (c === -1) {
|
if (c === -1) {
|
||||||
Log.Error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
|
Log.Error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
|
||||||
|
@ -100,7 +94,7 @@ export default {
|
||||||
|
|
||||||
// If there are any bits left, the base64 string was corrupted
|
// If there are any bits left, the base64 string was corrupted
|
||||||
if (leftbits) {
|
if (leftbits) {
|
||||||
err = new Error('Corrupted base64 string');
|
const err = new Error('Corrupted base64 string');
|
||||||
err.name = 'Base64-Error';
|
err.name = 'Base64-Error';
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
24
static/js/novnc/core/decoders/copyrect.js
Executable file
24
static/js/novnc/core/decoders/copyrect.js
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Copyright (C) 2012 Joel Martin
|
||||||
|
* Copyright (C) 2018 Samuel Mannehed for Cendio AB
|
||||||
|
* Copyright (C) 2018 Pierre Ossman for Cendio AB
|
||||||
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
|
*
|
||||||
|
* See README.md for usage and integration instructions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class CopyRectDecoder {
|
||||||
|
decodeRect(x, y, width, height, sock, display, depth) {
|
||||||
|
if (sock.rQwait("COPYRECT", 4)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let deltaX = sock.rQshift16();
|
||||||
|
let deltaY = sock.rQshift16();
|
||||||
|
display.copyImage(deltaX, deltaY, x, y, width, height);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
139
static/js/novnc/core/decoders/hextile.js
Executable file
139
static/js/novnc/core/decoders/hextile.js
Executable file
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Copyright (C) 2012 Joel Martin
|
||||||
|
* Copyright (C) 2018 Samuel Mannehed for Cendio AB
|
||||||
|
* Copyright (C) 2018 Pierre Ossman for Cendio AB
|
||||||
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
|
*
|
||||||
|
* See README.md for usage and integration instructions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Log from '../util/logging.js';
|
||||||
|
|
||||||
|
export default class HextileDecoder {
|
||||||
|
constructor() {
|
||||||
|
this._tiles = 0;
|
||||||
|
this._lastsubencoding = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeRect(x, y, width, height, sock, display, depth) {
|
||||||
|
if (this._tiles === 0) {
|
||||||
|
this._tiles_x = Math.ceil(width / 16);
|
||||||
|
this._tiles_y = Math.ceil(height / 16);
|
||||||
|
this._total_tiles = this._tiles_x * this._tiles_y;
|
||||||
|
this._tiles = this._total_tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (this._tiles > 0) {
|
||||||
|
let bytes = 1;
|
||||||
|
|
||||||
|
if (sock.rQwait("HEXTILE", bytes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rQ = sock.rQ;
|
||||||
|
let rQi = sock.rQi;
|
||||||
|
|
||||||
|
let subencoding = rQ[rQi]; // Peek
|
||||||
|
if (subencoding > 30) { // Raw
|
||||||
|
throw new Error("Illegal hextile subencoding (subencoding: " +
|
||||||
|
subencoding + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
const curr_tile = this._total_tiles - this._tiles;
|
||||||
|
const tile_x = curr_tile % this._tiles_x;
|
||||||
|
const tile_y = Math.floor(curr_tile / this._tiles_x);
|
||||||
|
const tx = x + tile_x * 16;
|
||||||
|
const ty = y + tile_y * 16;
|
||||||
|
const tw = Math.min(16, (x + width) - tx);
|
||||||
|
const th = Math.min(16, (y + height) - ty);
|
||||||
|
|
||||||
|
// Figure out how much we are expecting
|
||||||
|
if (subencoding & 0x01) { // Raw
|
||||||
|
bytes += tw * th * 4;
|
||||||
|
} else {
|
||||||
|
if (subencoding & 0x02) { // Background
|
||||||
|
bytes += 4;
|
||||||
|
}
|
||||||
|
if (subencoding & 0x04) { // Foreground
|
||||||
|
bytes += 4;
|
||||||
|
}
|
||||||
|
if (subencoding & 0x08) { // AnySubrects
|
||||||
|
bytes++; // Since we aren't shifting it off
|
||||||
|
|
||||||
|
if (sock.rQwait("HEXTILE", bytes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let subrects = rQ[rQi + bytes - 1]; // Peek
|
||||||
|
if (subencoding & 0x10) { // SubrectsColoured
|
||||||
|
bytes += subrects * (4 + 2);
|
||||||
|
} else {
|
||||||
|
bytes += subrects * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sock.rQwait("HEXTILE", bytes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We know the encoding and have a whole tile
|
||||||
|
rQi++;
|
||||||
|
if (subencoding === 0) {
|
||||||
|
if (this._lastsubencoding & 0x01) {
|
||||||
|
// Weird: ignore blanks are RAW
|
||||||
|
Log.Debug(" Ignoring blank after RAW");
|
||||||
|
} else {
|
||||||
|
display.fillRect(tx, ty, tw, th, this._background);
|
||||||
|
}
|
||||||
|
} else if (subencoding & 0x01) { // Raw
|
||||||
|
display.blitImage(tx, ty, tw, th, rQ, rQi);
|
||||||
|
rQi += bytes - 1;
|
||||||
|
} else {
|
||||||
|
if (subencoding & 0x02) { // Background
|
||||||
|
this._background = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
|
||||||
|
rQi += 4;
|
||||||
|
}
|
||||||
|
if (subencoding & 0x04) { // Foreground
|
||||||
|
this._foreground = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
|
||||||
|
rQi += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
display.startTile(tx, ty, tw, th, this._background);
|
||||||
|
if (subencoding & 0x08) { // AnySubrects
|
||||||
|
let subrects = rQ[rQi];
|
||||||
|
rQi++;
|
||||||
|
|
||||||
|
for (let s = 0; s < subrects; s++) {
|
||||||
|
let color;
|
||||||
|
if (subencoding & 0x10) { // SubrectsColoured
|
||||||
|
color = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
|
||||||
|
rQi += 4;
|
||||||
|
} else {
|
||||||
|
color = this._foreground;
|
||||||
|
}
|
||||||
|
const xy = rQ[rQi];
|
||||||
|
rQi++;
|
||||||
|
const sx = (xy >> 4);
|
||||||
|
const sy = (xy & 0x0f);
|
||||||
|
|
||||||
|
const wh = rQ[rQi];
|
||||||
|
rQi++;
|
||||||
|
const sw = (wh >> 4) + 1;
|
||||||
|
const sh = (wh & 0x0f) + 1;
|
||||||
|
|
||||||
|
display.subTile(sx, sy, sw, sh, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
display.finishTile();
|
||||||
|
}
|
||||||
|
sock.rQi = rQi;
|
||||||
|
this._lastsubencoding = subencoding;
|
||||||
|
this._tiles--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
58
static/js/novnc/core/decoders/raw.js
Executable file
58
static/js/novnc/core/decoders/raw.js
Executable file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Copyright (C) 2012 Joel Martin
|
||||||
|
* Copyright (C) 2018 Samuel Mannehed for Cendio AB
|
||||||
|
* Copyright (C) 2018 Pierre Ossman for Cendio AB
|
||||||
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
|
*
|
||||||
|
* See README.md for usage and integration instructions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class RawDecoder {
|
||||||
|
constructor() {
|
||||||
|
this._lines = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeRect(x, y, width, height, sock, display, depth) {
|
||||||
|
if (this._lines === 0) {
|
||||||
|
this._lines = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pixelSize = depth == 8 ? 1 : 4;
|
||||||
|
const bytesPerLine = width * pixelSize;
|
||||||
|
|
||||||
|
if (sock.rQwait("RAW", bytesPerLine)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cur_y = y + (height - this._lines);
|
||||||
|
const curr_height = Math.min(this._lines,
|
||||||
|
Math.floor(sock.rQlen / bytesPerLine));
|
||||||
|
let data = sock.rQ;
|
||||||
|
let index = sock.rQi;
|
||||||
|
|
||||||
|
// Convert data if needed
|
||||||
|
if (depth == 8) {
|
||||||
|
const pixels = width * curr_height;
|
||||||
|
const newdata = new Uint8Array(pixels * 4);
|
||||||
|
for (let i = 0; i < pixels; i++) {
|
||||||
|
newdata[i * 4 + 0] = ((data[index + i] >> 0) & 0x3) * 255 / 3;
|
||||||
|
newdata[i * 4 + 1] = ((data[index + i] >> 2) & 0x3) * 255 / 3;
|
||||||
|
newdata[i * 4 + 2] = ((data[index + i] >> 4) & 0x3) * 255 / 3;
|
||||||
|
newdata[i * 4 + 4] = 0;
|
||||||
|
}
|
||||||
|
data = newdata;
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
display.blitImage(x, cur_y, width, curr_height, data, index);
|
||||||
|
sock.rQskipBytes(curr_height * bytesPerLine);
|
||||||
|
this._lines -= curr_height;
|
||||||
|
if (this._lines > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
46
static/js/novnc/core/decoders/rre.js
Executable file
46
static/js/novnc/core/decoders/rre.js
Executable file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Copyright (C) 2012 Joel Martin
|
||||||
|
* Copyright (C) 2018 Samuel Mannehed for Cendio AB
|
||||||
|
* Copyright (C) 2018 Pierre Ossman for Cendio AB
|
||||||
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
|
*
|
||||||
|
* See README.md for usage and integration instructions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class RREDecoder {
|
||||||
|
constructor() {
|
||||||
|
this._subrects = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeRect(x, y, width, height, sock, display, depth) {
|
||||||
|
if (this._subrects === 0) {
|
||||||
|
if (sock.rQwait("RRE", 4 + 4)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._subrects = sock.rQshift32();
|
||||||
|
|
||||||
|
let color = sock.rQshiftBytes(4); // Background
|
||||||
|
display.fillRect(x, y, width, height, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (this._subrects > 0) {
|
||||||
|
if (sock.rQwait("RRE", 4 + 8)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let color = sock.rQshiftBytes(4);
|
||||||
|
let sx = sock.rQshift16();
|
||||||
|
let sy = sock.rQshift16();
|
||||||
|
let swidth = sock.rQshift16();
|
||||||
|
let sheight = sock.rQshift16();
|
||||||
|
display.fillRect(x + sx, y + sy, swidth, sheight, color);
|
||||||
|
|
||||||
|
this._subrects--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
319
static/js/novnc/core/decoders/tight.js
Executable file
319
static/js/novnc/core/decoders/tight.js
Executable file
|
@ -0,0 +1,319 @@
|
||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Copyright (C) 2012 Joel Martin
|
||||||
|
* (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca)
|
||||||
|
* Copyright (C) 2018 Samuel Mannehed for Cendio AB
|
||||||
|
* Copyright (C) 2018 Pierre Ossman for Cendio AB
|
||||||
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
|
*
|
||||||
|
* See README.md for usage and integration instructions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Log from '../util/logging.js';
|
||||||
|
import Inflator from "../inflator.js";
|
||||||
|
|
||||||
|
export default class TightDecoder {
|
||||||
|
constructor() {
|
||||||
|
this._ctl = null;
|
||||||
|
this._filter = null;
|
||||||
|
this._numColors = 0;
|
||||||
|
this._palette = new Uint8Array(1024); // 256 * 4 (max palette size * max bytes-per-pixel)
|
||||||
|
this._len = 0;
|
||||||
|
|
||||||
|
this._zlibs = [];
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
this._zlibs[i] = new Inflator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeRect(x, y, width, height, sock, display, depth) {
|
||||||
|
if (this._ctl === null) {
|
||||||
|
if (sock.rQwait("TIGHT compression-control", 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._ctl = sock.rQshift8();
|
||||||
|
|
||||||
|
// Reset streams if the server requests it
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
if ((this._ctl >> i) & 1) {
|
||||||
|
this._zlibs[i].reset();
|
||||||
|
Log.Info("Reset zlib stream " + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out filter
|
||||||
|
this._ctl = this._ctl >> 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret;
|
||||||
|
|
||||||
|
if (this._ctl === 0x08) {
|
||||||
|
ret = this._fillRect(x, y, width, height,
|
||||||
|
sock, display, depth);
|
||||||
|
} else if (this._ctl === 0x09) {
|
||||||
|
ret = this._jpegRect(x, y, width, height,
|
||||||
|
sock, display, depth);
|
||||||
|
} else if (this._ctl === 0x0A) {
|
||||||
|
ret = this._pngRect(x, y, width, height,
|
||||||
|
sock, display, depth);
|
||||||
|
} else if ((this._ctl & 0x80) == 0) {
|
||||||
|
ret = this._basicRect(this._ctl, x, y, width, height,
|
||||||
|
sock, display, depth);
|
||||||
|
} else {
|
||||||
|
throw new Error("Illegal tight compression received (ctl: " +
|
||||||
|
this._ctl + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
this._ctl = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fillRect(x, y, width, height, sock, display, depth) {
|
||||||
|
if (sock.rQwait("TIGHT", 3)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rQi = sock.rQi;
|
||||||
|
const rQ = sock.rQ;
|
||||||
|
|
||||||
|
display.fillRect(x, y, width, height,
|
||||||
|
[rQ[rQi + 2], rQ[rQi + 1], rQ[rQi]], false);
|
||||||
|
sock.rQskipBytes(3);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_jpegRect(x, y, width, height, sock, display, depth) {
|
||||||
|
let data = this._readData(sock);
|
||||||
|
if (data === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
display.imageRect(x, y, "image/jpeg", data);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pngRect(x, y, width, height, sock, display, depth) {
|
||||||
|
throw new Error("PNG received in standard Tight rect");
|
||||||
|
}
|
||||||
|
|
||||||
|
_basicRect(ctl, x, y, width, height, sock, display, depth) {
|
||||||
|
if (this._filter === null) {
|
||||||
|
if (ctl & 0x4) {
|
||||||
|
if (sock.rQwait("TIGHT", 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._filter = sock.rQshift8();
|
||||||
|
} else {
|
||||||
|
// Implicit CopyFilter
|
||||||
|
this._filter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let streamId = ctl & 0x3;
|
||||||
|
|
||||||
|
let ret;
|
||||||
|
|
||||||
|
switch (this._filter) {
|
||||||
|
case 0: // CopyFilter
|
||||||
|
ret = this._copyFilter(streamId, x, y, width, height,
|
||||||
|
sock, display, depth);
|
||||||
|
break;
|
||||||
|
case 1: // PaletteFilter
|
||||||
|
ret = this._paletteFilter(streamId, x, y, width, height,
|
||||||
|
sock, display, depth);
|
||||||
|
break;
|
||||||
|
case 2: // GradientFilter
|
||||||
|
ret = this._gradientFilter(streamId, x, y, width, height,
|
||||||
|
sock, display, depth);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Illegal tight filter received (ctl: " +
|
||||||
|
this._filter + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
this._filter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
_copyFilter(streamId, x, y, width, height, sock, display, depth) {
|
||||||
|
const uncompressedSize = width * height * 3;
|
||||||
|
let data;
|
||||||
|
|
||||||
|
if (uncompressedSize < 12) {
|
||||||
|
if (sock.rQwait("TIGHT", uncompressedSize)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = sock.rQshiftBytes(uncompressedSize);
|
||||||
|
} else {
|
||||||
|
data = this._readData(sock);
|
||||||
|
if (data === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = this._zlibs[streamId].inflate(data, true, uncompressedSize);
|
||||||
|
if (data.length != uncompressedSize) {
|
||||||
|
throw new Error("Incomplete zlib block");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display.blitRgbImage(x, y, width, height, data, 0, false);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_paletteFilter(streamId, x, y, width, height, sock, display, depth) {
|
||||||
|
if (this._numColors === 0) {
|
||||||
|
if (sock.rQwait("TIGHT palette", 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const numColors = sock.rQpeek8() + 1;
|
||||||
|
const paletteSize = numColors * 3;
|
||||||
|
|
||||||
|
if (sock.rQwait("TIGHT palette", 1 + paletteSize)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._numColors = numColors;
|
||||||
|
sock.rQskipBytes(1);
|
||||||
|
|
||||||
|
sock.rQshiftTo(this._palette, paletteSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bpp = (this._numColors <= 2) ? 1 : 8;
|
||||||
|
const rowSize = Math.floor((width * bpp + 7) / 8);
|
||||||
|
const uncompressedSize = rowSize * height;
|
||||||
|
|
||||||
|
let data;
|
||||||
|
|
||||||
|
if (uncompressedSize < 12) {
|
||||||
|
if (sock.rQwait("TIGHT", uncompressedSize)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = sock.rQshiftBytes(uncompressedSize);
|
||||||
|
} else {
|
||||||
|
data = this._readData(sock);
|
||||||
|
if (data === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = this._zlibs[streamId].inflate(data, true, uncompressedSize);
|
||||||
|
if (data.length != uncompressedSize) {
|
||||||
|
throw new Error("Incomplete zlib block");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert indexed (palette based) image data to RGB
|
||||||
|
if (this._numColors == 2) {
|
||||||
|
this._monoRect(x, y, width, height, data, this._palette, display);
|
||||||
|
} else {
|
||||||
|
this._paletteRect(x, y, width, height, data, this._palette, display);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._numColors = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_monoRect(x, y, width, height, data, palette, display) {
|
||||||
|
// Convert indexed (palette based) image data to RGB
|
||||||
|
// TODO: reduce number of calculations inside loop
|
||||||
|
const dest = this._getScratchBuffer(width * height * 4);
|
||||||
|
const w = Math.floor((width + 7) / 8);
|
||||||
|
const w1 = Math.floor(width / 8);
|
||||||
|
|
||||||
|
for (let y = 0; y < height; y++) {
|
||||||
|
let dp, sp, x;
|
||||||
|
for (x = 0; x < w1; x++) {
|
||||||
|
for (let b = 7; b >= 0; b--) {
|
||||||
|
dp = (y * width + x * 8 + 7 - b) * 4;
|
||||||
|
sp = (data[y * w + x] >> b & 1) * 3;
|
||||||
|
dest[dp] = palette[sp];
|
||||||
|
dest[dp + 1] = palette[sp + 1];
|
||||||
|
dest[dp + 2] = palette[sp + 2];
|
||||||
|
dest[dp + 3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let b = 7; b >= 8 - width % 8; b--) {
|
||||||
|
dp = (y * width + x * 8 + 7 - b) * 4;
|
||||||
|
sp = (data[y * w + x] >> b & 1) * 3;
|
||||||
|
dest[dp] = palette[sp];
|
||||||
|
dest[dp + 1] = palette[sp + 1];
|
||||||
|
dest[dp + 2] = palette[sp + 2];
|
||||||
|
dest[dp + 3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display.blitRgbxImage(x, y, width, height, dest, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_paletteRect(x, y, width, height, data, palette, display) {
|
||||||
|
// Convert indexed (palette based) image data to RGB
|
||||||
|
const dest = this._getScratchBuffer(width * height * 4);
|
||||||
|
const total = width * height * 4;
|
||||||
|
for (let i = 0, j = 0; i < total; i += 4, j++) {
|
||||||
|
const sp = data[j] * 3;
|
||||||
|
dest[i] = palette[sp];
|
||||||
|
dest[i + 1] = palette[sp + 1];
|
||||||
|
dest[i + 2] = palette[sp + 2];
|
||||||
|
dest[i + 3] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
display.blitRgbxImage(x, y, width, height, dest, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_gradientFilter(streamId, x, y, width, height, sock, display, depth) {
|
||||||
|
throw new Error("Gradient filter not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
_readData(sock) {
|
||||||
|
if (this._len === 0) {
|
||||||
|
if (sock.rQwait("TIGHT", 3)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let byte;
|
||||||
|
|
||||||
|
byte = sock.rQshift8();
|
||||||
|
this._len = byte & 0x7f;
|
||||||
|
if (byte & 0x80) {
|
||||||
|
byte = sock.rQshift8();
|
||||||
|
this._len |= (byte & 0x7f) << 7;
|
||||||
|
if (byte & 0x80) {
|
||||||
|
byte = sock.rQshift8();
|
||||||
|
this._len |= byte << 14;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sock.rQwait("TIGHT", this._len)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = sock.rQshiftBytes(this._len);
|
||||||
|
this._len = 0;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getScratchBuffer(size) {
|
||||||
|
if (!this._scratchBuffer || (this._scratchBuffer.length < size)) {
|
||||||
|
this._scratchBuffer = new Uint8Array(size);
|
||||||
|
}
|
||||||
|
return this._scratchBuffer;
|
||||||
|
}
|
||||||
|
}
|
29
static/js/novnc/core/decoders/tightpng.js
Executable file
29
static/js/novnc/core/decoders/tightpng.js
Executable file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Copyright (C) 2012 Joel Martin
|
||||||
|
* Copyright (C) 2018 Samuel Mannehed for Cendio AB
|
||||||
|
* Copyright (C) 2018 Pierre Ossman for Cendio AB
|
||||||
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
|
*
|
||||||
|
* See README.md for usage and integration instructions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TightDecoder from './tight.js';
|
||||||
|
|
||||||
|
export default class TightPNGDecoder extends TightDecoder {
|
||||||
|
_pngRect(x, y, width, height, sock, display, depth) {
|
||||||
|
let data = this._readData(sock);
|
||||||
|
if (data === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
display.imageRect(x, y, "image/png", data);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_basicRect(ctl, x, y, width, height, sock, display, depth) {
|
||||||
|
throw new Error("BasicCompression received in TightPNG rect");
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,84 +75,83 @@
|
||||||
* fine Java utilities: http://www.acme.com/java/
|
* fine Java utilities: http://www.acme.com/java/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default function DES(passwd) {
|
/* eslint-disable comma-spacing */
|
||||||
"use strict";
|
|
||||||
|
|
||||||
// Tables, permutations, S-boxes, etc.
|
// Tables, permutations, S-boxes, etc.
|
||||||
var PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3,
|
const PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3,
|
||||||
25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39,
|
25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39,
|
||||||
50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ],
|
50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ],
|
||||||
totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28],
|
totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28];
|
||||||
z = 0x0, a,b,c,d,e,f, SP1,SP2,SP3,SP4,SP5,SP6,SP7,SP8,
|
|
||||||
keys = [];
|
|
||||||
|
|
||||||
a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e;
|
const z = 0x0;
|
||||||
SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d,
|
let a,b,c,d,e,f;
|
||||||
|
a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e;
|
||||||
|
const SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d,
|
||||||
z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z,
|
z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z,
|
||||||
a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f,
|
a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f,
|
||||||
c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d];
|
c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d];
|
||||||
a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e;
|
a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e;
|
||||||
SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d,
|
const SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d,
|
||||||
a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f,
|
a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f,
|
||||||
z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z,
|
z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z,
|
||||||
z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e];
|
z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e];
|
||||||
a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e;
|
a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e;
|
||||||
SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f,
|
const SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f,
|
||||||
b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z,
|
b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z,
|
||||||
c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d,
|
c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d,
|
||||||
b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e];
|
b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e];
|
||||||
a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e;
|
a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e;
|
||||||
SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d,
|
const SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d,
|
||||||
z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f,
|
z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f,
|
||||||
b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e,
|
b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e,
|
||||||
c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e];
|
c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e];
|
||||||
a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e;
|
a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e;
|
||||||
SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z,
|
const SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z,
|
||||||
a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f,
|
a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f,
|
||||||
z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e,
|
z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e,
|
||||||
c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d];
|
c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d];
|
||||||
a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e;
|
a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e;
|
||||||
SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f,
|
const SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f,
|
||||||
z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z,
|
z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z,
|
||||||
b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z,
|
b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z,
|
||||||
a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f];
|
a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f];
|
||||||
a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e;
|
a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e;
|
||||||
SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f,
|
const SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f,
|
||||||
b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e,
|
b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e,
|
||||||
b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e,
|
b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e,
|
||||||
z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d];
|
z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d];
|
||||||
a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e;
|
a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e;
|
||||||
SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d,
|
const SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d,
|
||||||
c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z,
|
c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z,
|
||||||
a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f,
|
a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f,
|
||||||
z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e];
|
z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e];
|
||||||
|
|
||||||
|
/* eslint-enable comma-spacing */
|
||||||
|
|
||||||
|
export default class DES {
|
||||||
|
constructor(password) {
|
||||||
|
this.keys = [];
|
||||||
|
|
||||||
// Set the key.
|
// Set the key.
|
||||||
function setKeys(keyBlock) {
|
const pc1m = [], pcr = [], kn = [];
|
||||||
var i, j, l, m, n, o, pc1m = [], pcr = [], kn = [],
|
|
||||||
raw0, raw1, rawi, KnLi;
|
|
||||||
|
|
||||||
for (j = 0, l = 56; j < 56; ++j, l -= 8) {
|
for (let j = 0, l = 56; j < 56; ++j, l -= 8) {
|
||||||
l += l < -5 ? 65 : l < -3 ? 31 : l < -1 ? 63 : l === 27 ? 35 : 0; // PC1
|
l += l < -5 ? 65 : l < -3 ? 31 : l < -1 ? 63 : l === 27 ? 35 : 0; // PC1
|
||||||
m = l & 0x7;
|
const m = l & 0x7;
|
||||||
pc1m[j] = ((keyBlock[l >>> 3] & (1<<m)) !== 0) ? 1: 0;
|
pc1m[j] = ((password[l >>> 3] & (1<<m)) !== 0) ? 1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 16; ++i) {
|
for (let i = 0; i < 16; ++i) {
|
||||||
m = i << 1;
|
const m = i << 1;
|
||||||
n = m + 1;
|
const n = m + 1;
|
||||||
kn[m] = kn[n] = 0;
|
kn[m] = kn[n] = 0;
|
||||||
for (o = 28; o < 59; o += 28) {
|
for (let o = 28; o < 59; o += 28) {
|
||||||
for (j = o - 28; j < o; ++j) {
|
for (let j = o - 28; j < o; ++j) {
|
||||||
l = j + totrot[i];
|
const l = j + totrot[i];
|
||||||
if (l < o) {
|
pcr[j] = l < o ? pc1m[l] : pc1m[l - 28];
|
||||||
pcr[j] = pc1m[l];
|
|
||||||
} else {
|
|
||||||
pcr[j] = pc1m[l - 28];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for (let j = 0; j < 24; ++j) {
|
||||||
for (j = 0; j < 24; ++j) {
|
|
||||||
if (pcr[PC2[j]] !== 0) {
|
if (pcr[PC2[j]] !== 0) {
|
||||||
kn[m] |= 1 << (23 - j);
|
kn[m] |= 1 << (23 - j);
|
||||||
}
|
}
|
||||||
|
@ -163,26 +162,26 @@ export default function DES(passwd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// cookey
|
// cookey
|
||||||
for (i = 0, rawi = 0, KnLi = 0; i < 16; ++i) {
|
for (let i = 0, rawi = 0, KnLi = 0; i < 16; ++i) {
|
||||||
raw0 = kn[rawi++];
|
const raw0 = kn[rawi++];
|
||||||
raw1 = kn[rawi++];
|
const raw1 = kn[rawi++];
|
||||||
keys[KnLi] = (raw0 & 0x00fc0000) << 6;
|
this.keys[KnLi] = (raw0 & 0x00fc0000) << 6;
|
||||||
keys[KnLi] |= (raw0 & 0x00000fc0) << 10;
|
this.keys[KnLi] |= (raw0 & 0x00000fc0) << 10;
|
||||||
keys[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
|
this.keys[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
|
||||||
keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
|
this.keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
|
||||||
++KnLi;
|
++KnLi;
|
||||||
keys[KnLi] = (raw0 & 0x0003f000) << 12;
|
this.keys[KnLi] = (raw0 & 0x0003f000) << 12;
|
||||||
keys[KnLi] |= (raw0 & 0x0000003f) << 16;
|
this.keys[KnLi] |= (raw0 & 0x0000003f) << 16;
|
||||||
keys[KnLi] |= (raw1 & 0x0003f000) >>> 4;
|
this.keys[KnLi] |= (raw1 & 0x0003f000) >>> 4;
|
||||||
keys[KnLi] |= (raw1 & 0x0000003f);
|
this.keys[KnLi] |= (raw1 & 0x0000003f);
|
||||||
++KnLi;
|
++KnLi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt 8 bytes of text
|
// Encrypt 8 bytes of text
|
||||||
function enc8(text) {
|
enc8(text) {
|
||||||
var i = 0, b = text.slice(), fval, keysi = 0,
|
const b = text.slice();
|
||||||
l, r, x; // left, right, accumulator
|
let i = 0, l, r, x; // left, right, accumulator
|
||||||
|
|
||||||
// Squash 8 bytes to 2 ints
|
// Squash 8 bytes to 2 ints
|
||||||
l = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
|
l = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
|
||||||
|
@ -206,26 +205,26 @@ export default function DES(passwd) {
|
||||||
r ^= x;
|
r ^= x;
|
||||||
l = (l << 1) | ((l >>> 31) & 1);
|
l = (l << 1) | ((l >>> 31) & 1);
|
||||||
|
|
||||||
for (i = 0; i < 8; ++i) {
|
for (let i = 0, keysi = 0; i < 8; ++i) {
|
||||||
x = (r << 28) | (r >>> 4);
|
x = (r << 28) | (r >>> 4);
|
||||||
x ^= keys[keysi++];
|
x ^= this.keys[keysi++];
|
||||||
fval = SP7[x & 0x3f];
|
let fval = SP7[x & 0x3f];
|
||||||
fval |= SP5[(x >>> 8) & 0x3f];
|
fval |= SP5[(x >>> 8) & 0x3f];
|
||||||
fval |= SP3[(x >>> 16) & 0x3f];
|
fval |= SP3[(x >>> 16) & 0x3f];
|
||||||
fval |= SP1[(x >>> 24) & 0x3f];
|
fval |= SP1[(x >>> 24) & 0x3f];
|
||||||
x = r ^ keys[keysi++];
|
x = r ^ this.keys[keysi++];
|
||||||
fval |= SP8[x & 0x3f];
|
fval |= SP8[x & 0x3f];
|
||||||
fval |= SP6[(x >>> 8) & 0x3f];
|
fval |= SP6[(x >>> 8) & 0x3f];
|
||||||
fval |= SP4[(x >>> 16) & 0x3f];
|
fval |= SP4[(x >>> 16) & 0x3f];
|
||||||
fval |= SP2[(x >>> 24) & 0x3f];
|
fval |= SP2[(x >>> 24) & 0x3f];
|
||||||
l ^= fval;
|
l ^= fval;
|
||||||
x = (l << 28) | (l >>> 4);
|
x = (l << 28) | (l >>> 4);
|
||||||
x ^= keys[keysi++];
|
x ^= this.keys[keysi++];
|
||||||
fval = SP7[x & 0x3f];
|
fval = SP7[x & 0x3f];
|
||||||
fval |= SP5[(x >>> 8) & 0x3f];
|
fval |= SP5[(x >>> 8) & 0x3f];
|
||||||
fval |= SP3[(x >>> 16) & 0x3f];
|
fval |= SP3[(x >>> 16) & 0x3f];
|
||||||
fval |= SP1[(x >>> 24) & 0x3f];
|
fval |= SP1[(x >>> 24) & 0x3f];
|
||||||
x = l ^ keys[keysi++];
|
x = l ^ this.keys[keysi++];
|
||||||
fval |= SP8[x & 0x0000003f];
|
fval |= SP8[x & 0x0000003f];
|
||||||
fval |= SP6[(x >>> 8) & 0x3f];
|
fval |= SP6[(x >>> 8) & 0x3f];
|
||||||
fval |= SP4[(x >>> 16) & 0x3f];
|
fval |= SP4[(x >>> 16) & 0x3f];
|
||||||
|
@ -261,11 +260,7 @@ export default function DES(passwd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt 16 bytes of text using passwd as key
|
// Encrypt 16 bytes of text using passwd as key
|
||||||
function encrypt(t) {
|
encrypt(t) {
|
||||||
return enc8(t.slice(0, 8)).concat(enc8(t.slice(8, 16)));
|
return this.enc8(t.slice(0, 8)).concat(this.enc8(t.slice(8, 16)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
setKeys(passwd); // Setup keys
|
|
||||||
return {'encrypt': encrypt}; // Public interface
|
|
||||||
|
|
||||||
}; // function DES
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2012 Joel Martin
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Copyright (C) 2015 Samuel Mannehed for Cendio AB
|
|
||||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
*
|
*
|
||||||
* See README.md for usage and integration instructions.
|
* See README.md for usage and integration instructions.
|
||||||
|
@ -9,8 +8,10 @@
|
||||||
|
|
||||||
import * as Log from './util/logging.js';
|
import * as Log from './util/logging.js';
|
||||||
import Base64 from "./base64.js";
|
import Base64 from "./base64.js";
|
||||||
|
import { supportsImageMetadata } from './util/browser.js';
|
||||||
|
|
||||||
export default function Display(target) {
|
export default class Display {
|
||||||
|
constructor(target) {
|
||||||
this._drawCtx = null;
|
this._drawCtx = null;
|
||||||
this._c_forceCanvas = false;
|
this._c_forceCanvas = false;
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ export default function Display(target) {
|
||||||
this._backbuffer = document.createElement('canvas');
|
this._backbuffer = document.createElement('canvas');
|
||||||
this._drawCtx = this._backbuffer.getContext('2d');
|
this._drawCtx = this._backbuffer.getContext('2d');
|
||||||
|
|
||||||
this._damageBounds = { left:0, top:0,
|
this._damageBounds = { left: 0, top: 0,
|
||||||
right: this._backbuffer.width,
|
right: this._backbuffer.width,
|
||||||
bottom: this._backbuffer.height };
|
bottom: this._backbuffer.height };
|
||||||
|
|
||||||
|
@ -68,52 +69,46 @@ export default function Display(target) {
|
||||||
|
|
||||||
this._tile16x16 = this._drawCtx.createImageData(16, 16);
|
this._tile16x16 = this._drawCtx.createImageData(16, 16);
|
||||||
Log.Debug("<< Display.constructor");
|
Log.Debug("<< Display.constructor");
|
||||||
};
|
|
||||||
|
|
||||||
var SUPPORTS_IMAGEDATA_CONSTRUCTOR = false;
|
|
||||||
try {
|
|
||||||
new ImageData(new Uint8ClampedArray(4), 1, 1);
|
|
||||||
SUPPORTS_IMAGEDATA_CONSTRUCTOR = true;
|
|
||||||
} catch (ex) {
|
|
||||||
// ignore failure
|
|
||||||
}
|
|
||||||
|
|
||||||
Display.prototype = {
|
|
||||||
// ===== PROPERTIES =====
|
// ===== PROPERTIES =====
|
||||||
|
|
||||||
_scale: 1.0,
|
this._scale = 1.0;
|
||||||
get scale() { return this._scale; },
|
this._clipViewport = false;
|
||||||
set scale(scale) {
|
this.logo = null;
|
||||||
this._rescale(scale);
|
|
||||||
},
|
|
||||||
|
|
||||||
_clipViewport: false,
|
|
||||||
get clipViewport() { return this._clipViewport; },
|
|
||||||
set clipViewport(viewport) {
|
|
||||||
this._clipViewport = viewport;
|
|
||||||
// May need to readjust the viewport dimensions
|
|
||||||
var vp = this._viewportLoc;
|
|
||||||
this.viewportChangeSize(vp.w, vp.h);
|
|
||||||
this.viewportChangePos(0, 0);
|
|
||||||
},
|
|
||||||
|
|
||||||
get width() {
|
|
||||||
return this._fb_width;
|
|
||||||
},
|
|
||||||
get height() {
|
|
||||||
return this._fb_height;
|
|
||||||
},
|
|
||||||
|
|
||||||
logo: null,
|
|
||||||
|
|
||||||
// ===== EVENT HANDLERS =====
|
// ===== EVENT HANDLERS =====
|
||||||
|
|
||||||
onflush: function () {}, // A flush request has finished
|
this.onflush = () => {}; // A flush request has finished
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== PROPERTIES =====
|
||||||
|
|
||||||
|
get scale() { return this._scale; }
|
||||||
|
set scale(scale) {
|
||||||
|
this._rescale(scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
get clipViewport() { return this._clipViewport; }
|
||||||
|
set clipViewport(viewport) {
|
||||||
|
this._clipViewport = viewport;
|
||||||
|
// May need to readjust the viewport dimensions
|
||||||
|
const vp = this._viewportLoc;
|
||||||
|
this.viewportChangeSize(vp.w, vp.h);
|
||||||
|
this.viewportChangePos(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
get width() {
|
||||||
|
return this._fb_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
get height() {
|
||||||
|
return this._fb_height;
|
||||||
|
}
|
||||||
|
|
||||||
// ===== PUBLIC METHODS =====
|
// ===== PUBLIC METHODS =====
|
||||||
|
|
||||||
viewportChangePos: function (deltaX, deltaY) {
|
viewportChangePos(deltaX, deltaY) {
|
||||||
var vp = this._viewportLoc;
|
const vp = this._viewportLoc;
|
||||||
deltaX = Math.floor(deltaX);
|
deltaX = Math.floor(deltaX);
|
||||||
deltaY = Math.floor(deltaY);
|
deltaY = Math.floor(deltaY);
|
||||||
|
|
||||||
|
@ -122,8 +117,8 @@ Display.prototype = {
|
||||||
deltaY = -vp.h;
|
deltaY = -vp.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
var vx2 = vp.x + vp.w - 1;
|
const vx2 = vp.x + vp.w - 1;
|
||||||
var vy2 = vp.y + vp.h - 1;
|
const vy2 = vp.y + vp.h - 1;
|
||||||
|
|
||||||
// Position change
|
// Position change
|
||||||
|
|
||||||
|
@ -152,9 +147,9 @@ Display.prototype = {
|
||||||
this._damage(vp.x, vp.y, vp.w, vp.h);
|
this._damage(vp.x, vp.y, vp.w, vp.h);
|
||||||
|
|
||||||
this.flip();
|
this.flip();
|
||||||
},
|
}
|
||||||
|
|
||||||
viewportChangeSize: function(width, height) {
|
viewportChangeSize(width, height) {
|
||||||
|
|
||||||
if (!this._clipViewport ||
|
if (!this._clipViewport ||
|
||||||
typeof(width) === "undefined" ||
|
typeof(width) === "undefined" ||
|
||||||
|
@ -165,6 +160,9 @@ Display.prototype = {
|
||||||
height = this._fb_height;
|
height = this._fb_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
width = Math.floor(width);
|
||||||
|
height = Math.floor(height);
|
||||||
|
|
||||||
if (width > this._fb_width) {
|
if (width > this._fb_width) {
|
||||||
width = this._fb_width;
|
width = this._fb_width;
|
||||||
}
|
}
|
||||||
|
@ -172,12 +170,12 @@ Display.prototype = {
|
||||||
height = this._fb_height;
|
height = this._fb_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
var vp = this._viewportLoc;
|
const vp = this._viewportLoc;
|
||||||
if (vp.w !== width || vp.h !== height) {
|
if (vp.w !== width || vp.h !== height) {
|
||||||
vp.w = width;
|
vp.w = width;
|
||||||
vp.h = height;
|
vp.h = height;
|
||||||
|
|
||||||
var canvas = this._target;
|
const canvas = this._target;
|
||||||
canvas.width = width;
|
canvas.width = width;
|
||||||
canvas.height = height;
|
canvas.height = height;
|
||||||
|
|
||||||
|
@ -190,27 +188,33 @@ Display.prototype = {
|
||||||
// Update the visible size of the target canvas
|
// Update the visible size of the target canvas
|
||||||
this._rescale(this._scale);
|
this._rescale(this._scale);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
absX: function (x) {
|
absX(x) {
|
||||||
|
if (this._scale === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return x / this._scale + this._viewportLoc.x;
|
return x / this._scale + this._viewportLoc.x;
|
||||||
},
|
}
|
||||||
|
|
||||||
absY: function (y) {
|
absY(y) {
|
||||||
|
if (this._scale === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return y / this._scale + this._viewportLoc.y;
|
return y / this._scale + this._viewportLoc.y;
|
||||||
},
|
}
|
||||||
|
|
||||||
resize: function (width, height) {
|
resize(width, height) {
|
||||||
this._prevDrawStyle = "";
|
this._prevDrawStyle = "";
|
||||||
|
|
||||||
this._fb_width = width;
|
this._fb_width = width;
|
||||||
this._fb_height = height;
|
this._fb_height = height;
|
||||||
|
|
||||||
var canvas = this._backbuffer;
|
const canvas = this._backbuffer;
|
||||||
if (canvas.width !== width || canvas.height !== height) {
|
if (canvas.width !== width || canvas.height !== height) {
|
||||||
|
|
||||||
// We have to save the canvas data since changing the size will clear it
|
// We have to save the canvas data since changing the size will clear it
|
||||||
var saveImg = null;
|
let saveImg = null;
|
||||||
if (canvas.width > 0 && canvas.height > 0) {
|
if (canvas.width > 0 && canvas.height > 0) {
|
||||||
saveImg = this._drawCtx.getImageData(0, 0, canvas.width, canvas.height);
|
saveImg = this._drawCtx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
}
|
}
|
||||||
|
@ -229,13 +233,13 @@ Display.prototype = {
|
||||||
|
|
||||||
// Readjust the viewport as it may be incorrectly sized
|
// Readjust the viewport as it may be incorrectly sized
|
||||||
// and positioned
|
// and positioned
|
||||||
var vp = this._viewportLoc;
|
const vp = this._viewportLoc;
|
||||||
this.viewportChangeSize(vp.w, vp.h);
|
this.viewportChangeSize(vp.w, vp.h);
|
||||||
this.viewportChangePos(0, 0);
|
this.viewportChangePos(0, 0);
|
||||||
},
|
}
|
||||||
|
|
||||||
// Track what parts of the visible canvas that need updating
|
// Track what parts of the visible canvas that need updating
|
||||||
_damage: function(x, y, w, h) {
|
_damage(x, y, w, h) {
|
||||||
if (x < this._damageBounds.left) {
|
if (x < this._damageBounds.left) {
|
||||||
this._damageBounds.left = x;
|
this._damageBounds.left = x;
|
||||||
}
|
}
|
||||||
|
@ -248,25 +252,23 @@ Display.prototype = {
|
||||||
if ((y + h) > this._damageBounds.bottom) {
|
if ((y + h) > this._damageBounds.bottom) {
|
||||||
this._damageBounds.bottom = y + h;
|
this._damageBounds.bottom = y + h;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// Update the visible canvas with the contents of the
|
// Update the visible canvas with the contents of the
|
||||||
// rendering canvas
|
// rendering canvas
|
||||||
flip: function(from_queue) {
|
flip(from_queue) {
|
||||||
if (this._renderQ.length !== 0 && !from_queue) {
|
if (this._renderQ.length !== 0 && !from_queue) {
|
||||||
this._renderQ_push({
|
this._renderQ_push({
|
||||||
'type': 'flip'
|
'type': 'flip'
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var x, y, vx, vy, w, h;
|
let x = this._damageBounds.left;
|
||||||
|
let y = this._damageBounds.top;
|
||||||
|
let w = this._damageBounds.right - x;
|
||||||
|
let h = this._damageBounds.bottom - y;
|
||||||
|
|
||||||
x = this._damageBounds.left;
|
let vx = x - this._viewportLoc.x;
|
||||||
y = this._damageBounds.top;
|
let vy = y - this._viewportLoc.y;
|
||||||
w = this._damageBounds.right - x;
|
|
||||||
h = this._damageBounds.bottom - y;
|
|
||||||
|
|
||||||
vx = x - this._viewportLoc.x;
|
|
||||||
vy = y - this._viewportLoc.y;
|
|
||||||
|
|
||||||
if (vx < 0) {
|
if (vx < 0) {
|
||||||
w += vx;
|
w += vx;
|
||||||
|
@ -298,9 +300,9 @@ Display.prototype = {
|
||||||
this._damageBounds.left = this._damageBounds.top = 65535;
|
this._damageBounds.left = this._damageBounds.top = 65535;
|
||||||
this._damageBounds.right = this._damageBounds.bottom = 0;
|
this._damageBounds.right = this._damageBounds.bottom = 0;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
clear: function () {
|
clear() {
|
||||||
if (this._logo) {
|
if (this._logo) {
|
||||||
this.resize(this._logo.width, this._logo.height);
|
this.resize(this._logo.width, this._logo.height);
|
||||||
this.imageRect(0, 0, this._logo.type, this._logo.data);
|
this.imageRect(0, 0, this._logo.type, this._logo.data);
|
||||||
|
@ -309,21 +311,21 @@ Display.prototype = {
|
||||||
this._drawCtx.clearRect(0, 0, this._fb_width, this._fb_height);
|
this._drawCtx.clearRect(0, 0, this._fb_width, this._fb_height);
|
||||||
}
|
}
|
||||||
this.flip();
|
this.flip();
|
||||||
},
|
}
|
||||||
|
|
||||||
pending: function() {
|
pending() {
|
||||||
return this._renderQ.length > 0;
|
return this._renderQ.length > 0;
|
||||||
},
|
}
|
||||||
|
|
||||||
flush: function() {
|
flush() {
|
||||||
if (this._renderQ.length === 0) {
|
if (this._renderQ.length === 0) {
|
||||||
this.onflush();
|
this.onflush();
|
||||||
} else {
|
} else {
|
||||||
this._flushing = true;
|
this._flushing = true;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
fillRect: function (x, y, width, height, color, from_queue) {
|
fillRect(x, y, width, height, color, from_queue) {
|
||||||
if (this._renderQ.length !== 0 && !from_queue) {
|
if (this._renderQ.length !== 0 && !from_queue) {
|
||||||
this._renderQ_push({
|
this._renderQ_push({
|
||||||
'type': 'fill',
|
'type': 'fill',
|
||||||
|
@ -338,9 +340,9 @@ Display.prototype = {
|
||||||
this._drawCtx.fillRect(x, y, width, height);
|
this._drawCtx.fillRect(x, y, width, height);
|
||||||
this._damage(x, y, width, height);
|
this._damage(x, y, width, height);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
copyImage: function (old_x, old_y, new_x, new_y, w, h, from_queue) {
|
copyImage(old_x, old_y, new_x, new_y, w, h, from_queue) {
|
||||||
if (this._renderQ.length !== 0 && !from_queue) {
|
if (this._renderQ.length !== 0 && !from_queue) {
|
||||||
this._renderQ_push({
|
this._renderQ_push({
|
||||||
'type': 'copy',
|
'type': 'copy',
|
||||||
|
@ -369,10 +371,10 @@ Display.prototype = {
|
||||||
new_x, new_y, w, h);
|
new_x, new_y, w, h);
|
||||||
this._damage(new_x, new_y, w, h);
|
this._damage(new_x, new_y, w, h);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
imageRect: function(x, y, mime, arr) {
|
imageRect(x, y, mime, arr) {
|
||||||
var img = new Image();
|
const img = new Image();
|
||||||
img.src = "data: " + mime + ";base64," + Base64.encode(arr);
|
img.src = "data: " + mime + ";base64," + Base64.encode(arr);
|
||||||
this._renderQ_push({
|
this._renderQ_push({
|
||||||
'type': 'img',
|
'type': 'img',
|
||||||
|
@ -380,10 +382,10 @@ Display.prototype = {
|
||||||
'x': x,
|
'x': x,
|
||||||
'y': y
|
'y': y
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
// start updating a tile
|
// start updating a tile
|
||||||
startTile: function (x, y, width, height, color) {
|
startTile(x, y, width, height, color) {
|
||||||
this._tile_x = x;
|
this._tile_x = x;
|
||||||
this._tile_y = y;
|
this._tile_y = y;
|
||||||
if (width === 16 && height === 16) {
|
if (width === 16 && height === 16) {
|
||||||
|
@ -392,53 +394,53 @@ Display.prototype = {
|
||||||
this._tile = this._drawCtx.createImageData(width, height);
|
this._tile = this._drawCtx.createImageData(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
var red = color[2];
|
const red = color[2];
|
||||||
var green = color[1];
|
const green = color[1];
|
||||||
var blue = color[0];
|
const blue = color[0];
|
||||||
|
|
||||||
var data = this._tile.data;
|
const data = this._tile.data;
|
||||||
for (var i = 0; i < width * height * 4; i += 4) {
|
for (let i = 0; i < width * height * 4; i += 4) {
|
||||||
data[i] = red;
|
data[i] = red;
|
||||||
data[i + 1] = green;
|
data[i + 1] = green;
|
||||||
data[i + 2] = blue;
|
data[i + 2] = blue;
|
||||||
data[i + 3] = 255;
|
data[i + 3] = 255;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// update sub-rectangle of the current tile
|
// update sub-rectangle of the current tile
|
||||||
subTile: function (x, y, w, h, color) {
|
subTile(x, y, w, h, color) {
|
||||||
var red = color[2];
|
const red = color[2];
|
||||||
var green = color[1];
|
const green = color[1];
|
||||||
var blue = color[0];
|
const blue = color[0];
|
||||||
var xend = x + w;
|
const xend = x + w;
|
||||||
var yend = y + h;
|
const yend = y + h;
|
||||||
|
|
||||||
var data = this._tile.data;
|
const data = this._tile.data;
|
||||||
var width = this._tile.width;
|
const width = this._tile.width;
|
||||||
for (var j = y; j < yend; j++) {
|
for (let j = y; j < yend; j++) {
|
||||||
for (var i = x; i < xend; i++) {
|
for (let i = x; i < xend; i++) {
|
||||||
var p = (i + (j * width)) * 4;
|
const p = (i + (j * width)) * 4;
|
||||||
data[p] = red;
|
data[p] = red;
|
||||||
data[p + 1] = green;
|
data[p + 1] = green;
|
||||||
data[p + 2] = blue;
|
data[p + 2] = blue;
|
||||||
data[p + 3] = 255;
|
data[p + 3] = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// draw the current tile to the screen
|
// draw the current tile to the screen
|
||||||
finishTile: function () {
|
finishTile() {
|
||||||
this._drawCtx.putImageData(this._tile, this._tile_x, this._tile_y);
|
this._drawCtx.putImageData(this._tile, this._tile_x, this._tile_y);
|
||||||
this._damage(this._tile_x, this._tile_y,
|
this._damage(this._tile_x, this._tile_y,
|
||||||
this._tile.width, this._tile.height);
|
this._tile.width, this._tile.height);
|
||||||
},
|
}
|
||||||
|
|
||||||
blitImage: function (x, y, width, height, arr, offset, from_queue) {
|
blitImage(x, y, width, height, arr, offset, from_queue) {
|
||||||
if (this._renderQ.length !== 0 && !from_queue) {
|
if (this._renderQ.length !== 0 && !from_queue) {
|
||||||
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
||||||
// but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
|
// but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
|
||||||
// this probably isn't getting called *nearly* as much
|
// this probably isn't getting called *nearly* as much
|
||||||
var new_arr = new Uint8Array(width * height * 4);
|
const new_arr = new Uint8Array(width * height * 4);
|
||||||
new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
|
new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
|
||||||
this._renderQ_push({
|
this._renderQ_push({
|
||||||
'type': 'blit',
|
'type': 'blit',
|
||||||
|
@ -451,14 +453,14 @@ Display.prototype = {
|
||||||
} else {
|
} else {
|
||||||
this._bgrxImageData(x, y, width, height, arr, offset);
|
this._bgrxImageData(x, y, width, height, arr, offset);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
blitRgbImage: function (x, y , width, height, arr, offset, from_queue) {
|
blitRgbImage(x, y, width, height, arr, offset, from_queue) {
|
||||||
if (this._renderQ.length !== 0 && !from_queue) {
|
if (this._renderQ.length !== 0 && !from_queue) {
|
||||||
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
||||||
// but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
|
// but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
|
||||||
// this probably isn't getting called *nearly* as much
|
// this probably isn't getting called *nearly* as much
|
||||||
var new_arr = new Uint8Array(width * height * 3);
|
const new_arr = new Uint8Array(width * height * 3);
|
||||||
new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
|
new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
|
||||||
this._renderQ_push({
|
this._renderQ_push({
|
||||||
'type': 'blitRgb',
|
'type': 'blitRgb',
|
||||||
|
@ -471,14 +473,14 @@ Display.prototype = {
|
||||||
} else {
|
} else {
|
||||||
this._rgbImageData(x, y, width, height, arr, offset);
|
this._rgbImageData(x, y, width, height, arr, offset);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
blitRgbxImage: function (x, y, width, height, arr, offset, from_queue) {
|
blitRgbxImage(x, y, width, height, arr, offset, from_queue) {
|
||||||
if (this._renderQ.length !== 0 && !from_queue) {
|
if (this._renderQ.length !== 0 && !from_queue) {
|
||||||
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
||||||
// but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
|
// but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
|
||||||
// this probably isn't getting called *nearly* as much
|
// this probably isn't getting called *nearly* as much
|
||||||
var new_arr = new Uint8Array(width * height * 4);
|
const new_arr = new Uint8Array(width * height * 4);
|
||||||
new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
|
new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
|
||||||
this._renderQ_push({
|
this._renderQ_push({
|
||||||
'type': 'blitRgbx',
|
'type': 'blitRgbx',
|
||||||
|
@ -491,72 +493,67 @@ Display.prototype = {
|
||||||
} else {
|
} else {
|
||||||
this._rgbxImageData(x, y, width, height, arr, offset);
|
this._rgbxImageData(x, y, width, height, arr, offset);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
drawImage: function (img, x, y) {
|
drawImage(img, x, y) {
|
||||||
this._drawCtx.drawImage(img, x, y);
|
this._drawCtx.drawImage(img, x, y);
|
||||||
this._damage(x, y, img.width, img.height);
|
this._damage(x, y, img.width, img.height);
|
||||||
},
|
}
|
||||||
|
|
||||||
changeCursor: function (pixels, mask, hotx, hoty, w, h) {
|
autoscale(containerWidth, containerHeight) {
|
||||||
Display.changeCursor(this._target, pixels, mask, hotx, hoty, w, h);
|
let scaleRatio;
|
||||||
},
|
|
||||||
|
|
||||||
defaultCursor: function () {
|
if (containerWidth === 0 || containerHeight === 0) {
|
||||||
this._target.style.cursor = "default";
|
scaleRatio = 0;
|
||||||
},
|
|
||||||
|
|
||||||
disableLocalCursor: function () {
|
} else {
|
||||||
this._target.style.cursor = "none";
|
|
||||||
},
|
|
||||||
|
|
||||||
autoscale: function (containerWidth, containerHeight) {
|
const vp = this._viewportLoc;
|
||||||
var vp = this._viewportLoc;
|
const targetAspectRatio = containerWidth / containerHeight;
|
||||||
var targetAspectRatio = containerWidth / containerHeight;
|
const fbAspectRatio = vp.w / vp.h;
|
||||||
var fbAspectRatio = vp.w / vp.h;
|
|
||||||
|
|
||||||
var scaleRatio;
|
|
||||||
if (fbAspectRatio >= targetAspectRatio) {
|
if (fbAspectRatio >= targetAspectRatio) {
|
||||||
scaleRatio = containerWidth / vp.w;
|
scaleRatio = containerWidth / vp.w;
|
||||||
} else {
|
} else {
|
||||||
scaleRatio = containerHeight / vp.h;
|
scaleRatio = containerHeight / vp.h;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this._rescale(scaleRatio);
|
this._rescale(scaleRatio);
|
||||||
},
|
}
|
||||||
|
|
||||||
// ===== PRIVATE METHODS =====
|
// ===== PRIVATE METHODS =====
|
||||||
|
|
||||||
_rescale: function (factor) {
|
_rescale(factor) {
|
||||||
this._scale = factor;
|
this._scale = factor;
|
||||||
var vp = this._viewportLoc;
|
const vp = this._viewportLoc;
|
||||||
|
|
||||||
// NB(directxman12): If you set the width directly, or set the
|
// NB(directxman12): If you set the width directly, or set the
|
||||||
// style width to a number, the canvas is cleared.
|
// style width to a number, the canvas is cleared.
|
||||||
// However, if you set the style width to a string
|
// However, if you set the style width to a string
|
||||||
// ('NNNpx'), the canvas is scaled without clearing.
|
// ('NNNpx'), the canvas is scaled without clearing.
|
||||||
var width = Math.round(factor * vp.w) + 'px';
|
const width = factor * vp.w + 'px';
|
||||||
var height = Math.round(factor * vp.h) + 'px';
|
const height = factor * vp.h + 'px';
|
||||||
|
|
||||||
if ((this._target.style.width !== width) ||
|
if ((this._target.style.width !== width) ||
|
||||||
(this._target.style.height !== height)) {
|
(this._target.style.height !== height)) {
|
||||||
this._target.style.width = width;
|
this._target.style.width = width;
|
||||||
this._target.style.height = height;
|
this._target.style.height = height;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_setFillColor: function (color) {
|
_setFillColor(color) {
|
||||||
var newStyle = 'rgb(' + color[2] + ',' + color[1] + ',' + color[0] + ')';
|
const newStyle = 'rgb(' + color[2] + ',' + color[1] + ',' + color[0] + ')';
|
||||||
if (newStyle !== this._prevDrawStyle) {
|
if (newStyle !== this._prevDrawStyle) {
|
||||||
this._drawCtx.fillStyle = newStyle;
|
this._drawCtx.fillStyle = newStyle;
|
||||||
this._prevDrawStyle = newStyle;
|
this._prevDrawStyle = newStyle;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_rgbImageData: function (x, y, width, height, arr, offset) {
|
_rgbImageData(x, y, width, height, arr, offset) {
|
||||||
var img = this._drawCtx.createImageData(width, height);
|
const img = this._drawCtx.createImageData(width, height);
|
||||||
var data = img.data;
|
const data = img.data;
|
||||||
for (var i = 0, j = offset; i < width * height * 4; i += 4, j += 3) {
|
for (let i = 0, j = offset; i < width * height * 4; i += 4, j += 3) {
|
||||||
data[i] = arr[j];
|
data[i] = arr[j];
|
||||||
data[i + 1] = arr[j + 1];
|
data[i + 1] = arr[j + 1];
|
||||||
data[i + 2] = arr[j + 2];
|
data[i + 2] = arr[j + 2];
|
||||||
|
@ -564,12 +561,12 @@ Display.prototype = {
|
||||||
}
|
}
|
||||||
this._drawCtx.putImageData(img, x, y);
|
this._drawCtx.putImageData(img, x, y);
|
||||||
this._damage(x, y, img.width, img.height);
|
this._damage(x, y, img.width, img.height);
|
||||||
},
|
}
|
||||||
|
|
||||||
_bgrxImageData: function (x, y, width, height, arr, offset) {
|
_bgrxImageData(x, y, width, height, arr, offset) {
|
||||||
var img = this._drawCtx.createImageData(width, height);
|
const img = this._drawCtx.createImageData(width, height);
|
||||||
var data = img.data;
|
const data = img.data;
|
||||||
for (var i = 0, j = offset; i < width * height * 4; i += 4, j += 4) {
|
for (let i = 0, j = offset; i < width * height * 4; i += 4, j += 4) {
|
||||||
data[i] = arr[j + 2];
|
data[i] = arr[j + 2];
|
||||||
data[i + 1] = arr[j + 1];
|
data[i + 1] = arr[j + 1];
|
||||||
data[i + 2] = arr[j];
|
data[i + 2] = arr[j];
|
||||||
|
@ -577,12 +574,12 @@ Display.prototype = {
|
||||||
}
|
}
|
||||||
this._drawCtx.putImageData(img, x, y);
|
this._drawCtx.putImageData(img, x, y);
|
||||||
this._damage(x, y, img.width, img.height);
|
this._damage(x, y, img.width, img.height);
|
||||||
},
|
}
|
||||||
|
|
||||||
_rgbxImageData: function (x, y, width, height, arr, offset) {
|
_rgbxImageData(x, y, width, height, arr, offset) {
|
||||||
// NB(directxman12): arr must be an Type Array view
|
// NB(directxman12): arr must be an Type Array view
|
||||||
var img;
|
let img;
|
||||||
if (SUPPORTS_IMAGEDATA_CONSTRUCTOR) {
|
if (supportsImageMetadata) {
|
||||||
img = new ImageData(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4), width, height);
|
img = new ImageData(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4), width, height);
|
||||||
} else {
|
} else {
|
||||||
img = this._drawCtx.createImageData(width, height);
|
img = this._drawCtx.createImageData(width, height);
|
||||||
|
@ -590,28 +587,28 @@ Display.prototype = {
|
||||||
}
|
}
|
||||||
this._drawCtx.putImageData(img, x, y);
|
this._drawCtx.putImageData(img, x, y);
|
||||||
this._damage(x, y, img.width, img.height);
|
this._damage(x, y, img.width, img.height);
|
||||||
},
|
}
|
||||||
|
|
||||||
_renderQ_push: function (action) {
|
_renderQ_push(action) {
|
||||||
this._renderQ.push(action);
|
this._renderQ.push(action);
|
||||||
if (this._renderQ.length === 1) {
|
if (this._renderQ.length === 1) {
|
||||||
// If this can be rendered immediately it will be, otherwise
|
// If this can be rendered immediately it will be, otherwise
|
||||||
// the scanner will wait for the relevant event
|
// the scanner will wait for the relevant event
|
||||||
this._scan_renderQ();
|
this._scan_renderQ();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_resume_renderQ: function() {
|
_resume_renderQ() {
|
||||||
// "this" is the object that is ready, not the
|
// "this" is the object that is ready, not the
|
||||||
// display object
|
// display object
|
||||||
this.removeEventListener('load', this._noVNC_display._resume_renderQ);
|
this.removeEventListener('load', this._noVNC_display._resume_renderQ);
|
||||||
this._noVNC_display._scan_renderQ();
|
this._noVNC_display._scan_renderQ();
|
||||||
},
|
}
|
||||||
|
|
||||||
_scan_renderQ: function () {
|
_scan_renderQ() {
|
||||||
var ready = true;
|
let ready = true;
|
||||||
while (ready && this._renderQ.length > 0) {
|
while (ready && this._renderQ.length > 0) {
|
||||||
var a = this._renderQ[0];
|
const a = this._renderQ[0];
|
||||||
switch (a.type) {
|
switch (a.type) {
|
||||||
case 'flip':
|
case 'flip':
|
||||||
this.flip(true);
|
this.flip(true);
|
||||||
|
@ -653,46 +650,5 @@ Display.prototype = {
|
||||||
this._flushing = false;
|
this._flushing = false;
|
||||||
this.onflush();
|
this.onflush();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Class Methods
|
|
||||||
Display.changeCursor = function (target, pixels, mask, hotx, hoty, w, h) {
|
|
||||||
if ((w === 0) || (h === 0)) {
|
|
||||||
target.style.cursor = 'none';
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var cur = []
|
|
||||||
var y, x;
|
|
||||||
for (y = 0; y < h; y++) {
|
|
||||||
for (x = 0; x < w; x++) {
|
|
||||||
var idx = y * Math.ceil(w / 8) + Math.floor(x / 8);
|
|
||||||
var alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0;
|
|
||||||
idx = ((w * y) + x) * 4;
|
|
||||||
cur.push(pixels[idx + 2]); // red
|
|
||||||
cur.push(pixels[idx + 1]); // green
|
|
||||||
cur.push(pixels[idx]); // blue
|
|
||||||
cur.push(alpha); // alpha
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var canvas = document.createElement('canvas');
|
|
||||||
var ctx = canvas.getContext('2d');
|
|
||||||
|
|
||||||
canvas.width = w;
|
|
||||||
canvas.height = h;
|
|
||||||
|
|
||||||
var img;
|
|
||||||
if (SUPPORTS_IMAGEDATA_CONSTRUCTOR) {
|
|
||||||
img = new ImageData(new Uint8ClampedArray(cur), w, h);
|
|
||||||
} else {
|
|
||||||
img = ctx.createImageData(w, h);
|
|
||||||
img.data.set(new Uint8ClampedArray(cur));
|
|
||||||
}
|
|
||||||
ctx.clearRect(0, 0, w, h);
|
|
||||||
ctx.putImageData(img, 0, 0);
|
|
||||||
|
|
||||||
var url = canvas.toDataURL();
|
|
||||||
target.style.cursor = 'url(' + url + ')' + hotx + ' ' + hoty + ', default';
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2017 Pierre Ossman for Cendio AB
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
*
|
*
|
||||||
* See README.md for usage and integration instructions.
|
* See README.md for usage and integration instructions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export var encodings = {
|
export const encodings = {
|
||||||
encodingRaw: 0,
|
encodingRaw: 0,
|
||||||
encodingCopyRect: 1,
|
encodingCopyRect: 1,
|
||||||
encodingRRE: 2,
|
encodingRRE: 2,
|
||||||
encodingHextile: 5,
|
encodingHextile: 5,
|
||||||
encodingTight: 7,
|
encodingTight: 7,
|
||||||
|
encodingTightPNG: -260,
|
||||||
|
|
||||||
pseudoEncodingQualityLevel9: -23,
|
pseudoEncodingQualityLevel9: -23,
|
||||||
pseudoEncodingQualityLevel0: -32,
|
pseudoEncodingQualityLevel0: -32,
|
||||||
|
@ -19,7 +20,6 @@ export var encodings = {
|
||||||
pseudoEncodingLastRect: -224,
|
pseudoEncodingLastRect: -224,
|
||||||
pseudoEncodingCursor: -239,
|
pseudoEncodingCursor: -239,
|
||||||
pseudoEncodingQEMUExtendedKeyEvent: -258,
|
pseudoEncodingQEMUExtendedKeyEvent: -258,
|
||||||
pseudoEncodingTightPNG: -260,
|
|
||||||
pseudoEncodingExtendedDesktopSize: -308,
|
pseudoEncodingExtendedDesktopSize: -308,
|
||||||
pseudoEncodingXvp: -309,
|
pseudoEncodingXvp: -309,
|
||||||
pseudoEncodingFence: -312,
|
pseudoEncodingFence: -312,
|
||||||
|
@ -35,6 +35,7 @@ export function encodingName(num) {
|
||||||
case encodings.encodingRRE: return "RRE";
|
case encodings.encodingRRE: return "RRE";
|
||||||
case encodings.encodingHextile: return "Hextile";
|
case encodings.encodingHextile: return "Hextile";
|
||||||
case encodings.encodingTight: return "Tight";
|
case encodings.encodingTight: return "Tight";
|
||||||
|
case encodings.encodingTightPNG: return "TightPNG";
|
||||||
default: return "[unknown encoding " + num + "]";
|
default: return "[unknown encoding " + num + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
import { inflateInit, inflate, inflateReset } from "../vendor/pako/lib/zlib/inflate.js";
|
import { inflateInit, inflate, inflateReset } from "../vendor/pako/lib/zlib/inflate.js";
|
||||||
import ZStream from "../vendor/pako/lib/zlib/zstream.js";
|
import ZStream from "../vendor/pako/lib/zlib/zstream.js";
|
||||||
|
|
||||||
Inflate.prototype = {
|
export default class Inflate {
|
||||||
inflate: function (data, flush, expected) {
|
constructor() {
|
||||||
|
this.strm = new ZStream();
|
||||||
|
this.chunkSize = 1024 * 10 * 10;
|
||||||
|
this.strm.output = new Uint8Array(this.chunkSize);
|
||||||
|
this.windowBits = 5;
|
||||||
|
|
||||||
|
inflateInit(this.strm, this.windowBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
inflate(data, flush, expected) {
|
||||||
this.strm.input = data;
|
this.strm.input = data;
|
||||||
this.strm.avail_in = this.strm.input.length;
|
this.strm.avail_in = this.strm.input.length;
|
||||||
this.strm.next_in = 0;
|
this.strm.next_in = 0;
|
||||||
|
@ -21,18 +30,9 @@ Inflate.prototype = {
|
||||||
inflate(this.strm, flush);
|
inflate(this.strm, flush);
|
||||||
|
|
||||||
return new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
|
return new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
|
||||||
},
|
}
|
||||||
|
|
||||||
reset: function () {
|
reset() {
|
||||||
inflateReset(this.strm);
|
inflateReset(this.strm);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default function Inflate() {
|
|
||||||
this.strm = new ZStream();
|
|
||||||
this.chunkSize = 1024 * 10 * 10;
|
|
||||||
this.strm.output = new Uint8Array(this.chunkSize);
|
|
||||||
this.windowBits = 5;
|
|
||||||
|
|
||||||
inflateInit(this.strm, this.windowBits);
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2017 Pierre Ossman for Cendio AB
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -13,28 +13,25 @@ import KeyTable from "./keysym.js";
|
||||||
* See https://www.w3.org/TR/uievents-key/ for possible values.
|
* See https://www.w3.org/TR/uievents-key/ for possible values.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var DOMKeyTable = {};
|
const DOMKeyTable = {};
|
||||||
|
|
||||||
function addStandard(key, standard)
|
function addStandard(key, standard) {
|
||||||
{
|
if (standard === undefined) throw new Error("Undefined keysym for key \"" + key + "\"");
|
||||||
if (standard === undefined) throw "Undefined keysym for key \"" + key + "\"";
|
if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\"");
|
||||||
if (key in DOMKeyTable) throw "Duplicate entry for key \"" + key + "\"";
|
|
||||||
DOMKeyTable[key] = [standard, standard, standard, standard];
|
DOMKeyTable[key] = [standard, standard, standard, standard];
|
||||||
}
|
}
|
||||||
|
|
||||||
function addLeftRight(key, left, right)
|
function addLeftRight(key, left, right) {
|
||||||
{
|
if (left === undefined) throw new Error("Undefined keysym for key \"" + key + "\"");
|
||||||
if (left === undefined) throw "Undefined keysym for key \"" + key + "\"";
|
if (right === undefined) throw new Error("Undefined keysym for key \"" + key + "\"");
|
||||||
if (right === undefined) throw "Undefined keysym for key \"" + key + "\"";
|
if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\"");
|
||||||
if (key in DOMKeyTable) throw "Duplicate entry for key \"" + key + "\"";
|
|
||||||
DOMKeyTable[key] = [left, left, right, left];
|
DOMKeyTable[key] = [left, left, right, left];
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNumpad(key, standard, numpad)
|
function addNumpad(key, standard, numpad) {
|
||||||
{
|
if (standard === undefined) throw new Error("Undefined keysym for key \"" + key + "\"");
|
||||||
if (standard === undefined) throw "Undefined keysym for key \"" + key + "\"";
|
if (numpad === undefined) throw new Error("Undefined keysym for key \"" + key + "\"");
|
||||||
if (numpad === undefined) throw "Undefined keysym for key \"" + key + "\"";
|
if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\"");
|
||||||
if (key in DOMKeyTable) throw "Duplicate entry for key \"" + key + "\"";
|
|
||||||
DOMKeyTable[key] = [standard, standard, standard, numpad];
|
DOMKeyTable[key] = [standard, standard, standard, numpad];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +72,7 @@ addNumpad("PageUp", KeyTable.XK_Prior, KeyTable.XK_KP_Prior);
|
||||||
// 2.5. Editing Keys
|
// 2.5. Editing Keys
|
||||||
|
|
||||||
addStandard("Backspace", KeyTable.XK_BackSpace);
|
addStandard("Backspace", KeyTable.XK_BackSpace);
|
||||||
addStandard("Clear", KeyTable.XK_Clear);
|
addNumpad("Clear", KeyTable.XK_Clear, KeyTable.XK_KP_Begin);
|
||||||
addStandard("Copy", KeyTable.XF86XK_Copy);
|
addStandard("Copy", KeyTable.XF86XK_Copy);
|
||||||
// - CrSel
|
// - CrSel
|
||||||
addStandard("Cut", KeyTable.XF86XK_Cut);
|
addStandard("Cut", KeyTable.XF86XK_Cut);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2017 Pierre Ossman for Cendio AB
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@
|
||||||
* See https://www.w3.org/TR/uievents-key/ for possible values.
|
* See https://www.w3.org/TR/uievents-key/ for possible values.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable key-spacing */
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
// 3.1.1.1. Writing System Keys
|
// 3.1.1.1. Writing System Keys
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2012 Joel Martin
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Copyright (C) 2013 Samuel Mannehed for Cendio AB
|
|
||||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -15,63 +14,49 @@ import * as browser from "../util/browser.js";
|
||||||
// Keyboard event handler
|
// Keyboard event handler
|
||||||
//
|
//
|
||||||
|
|
||||||
export default function Keyboard(target) {
|
export default class Keyboard {
|
||||||
|
constructor(target) {
|
||||||
this._target = target || null;
|
this._target = target || null;
|
||||||
|
|
||||||
this._keyDownList = {}; // List of depressed keys
|
this._keyDownList = {}; // List of depressed keys
|
||||||
// (even if they are happy)
|
// (even if they are happy)
|
||||||
this._pendingKey = null; // Key waiting for keypress
|
this._pendingKey = null; // Key waiting for keypress
|
||||||
|
this._altGrArmed = false; // Windows AltGr detection
|
||||||
|
|
||||||
// keep these here so we can refer to them later
|
// keep these here so we can refer to them later
|
||||||
this._eventHandlers = {
|
this._eventHandlers = {
|
||||||
'keyup': this._handleKeyUp.bind(this),
|
'keyup': this._handleKeyUp.bind(this),
|
||||||
'keydown': this._handleKeyDown.bind(this),
|
'keydown': this._handleKeyDown.bind(this),
|
||||||
'keypress': this._handleKeyPress.bind(this),
|
'keypress': this._handleKeyPress.bind(this),
|
||||||
'blur': this._allKeysUp.bind(this)
|
'blur': this._allKeysUp.bind(this),
|
||||||
|
'checkalt': this._checkAlt.bind(this),
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
Keyboard.prototype = {
|
|
||||||
// ===== EVENT HANDLERS =====
|
// ===== EVENT HANDLERS =====
|
||||||
|
|
||||||
onkeyevent: function () {}, // Handler for key press/release
|
this.onkeyevent = () => {}; // Handler for key press/release
|
||||||
|
}
|
||||||
|
|
||||||
// ===== PRIVATE METHODS =====
|
// ===== PRIVATE METHODS =====
|
||||||
|
|
||||||
_sendKeyEvent: function (keysym, code, down) {
|
_sendKeyEvent(keysym, code, down) {
|
||||||
|
if (down) {
|
||||||
|
this._keyDownList[code] = keysym;
|
||||||
|
} else {
|
||||||
|
// Do we really think this key is down?
|
||||||
|
if (!(code in this._keyDownList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete this._keyDownList[code];
|
||||||
|
}
|
||||||
|
|
||||||
Log.Debug("onkeyevent " + (down ? "down" : "up") +
|
Log.Debug("onkeyevent " + (down ? "down" : "up") +
|
||||||
", keysym: " + keysym, ", code: " + code);
|
", keysym: " + keysym, ", code: " + code);
|
||||||
|
|
||||||
// Windows sends CtrlLeft+AltRight when you press
|
|
||||||
// AltGraph, which tends to confuse the hell out of
|
|
||||||
// remote systems. Fake a release of these keys until
|
|
||||||
// there is a way to detect AltGraph properly.
|
|
||||||
var fakeAltGraph = false;
|
|
||||||
if (down && browser.isWindows()) {
|
|
||||||
if ((code !== 'ControlLeft') &&
|
|
||||||
(code !== 'AltRight') &&
|
|
||||||
('ControlLeft' in this._keyDownList) &&
|
|
||||||
('AltRight' in this._keyDownList)) {
|
|
||||||
fakeAltGraph = true;
|
|
||||||
this.onkeyevent(this._keyDownList['AltRight'],
|
|
||||||
'AltRight', false);
|
|
||||||
this.onkeyevent(this._keyDownList['ControlLeft'],
|
|
||||||
'ControlLeft', false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.onkeyevent(keysym, code, down);
|
this.onkeyevent(keysym, code, down);
|
||||||
|
|
||||||
if (fakeAltGraph) {
|
|
||||||
this.onkeyevent(this._keyDownList['ControlLeft'],
|
|
||||||
'ControlLeft', true);
|
|
||||||
this.onkeyevent(this._keyDownList['AltRight'],
|
|
||||||
'AltRight', true);
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
_getKeyCode: function (e) {
|
_getKeyCode(e) {
|
||||||
var code = KeyboardUtil.getKeycode(e);
|
const code = KeyboardUtil.getKeycode(e);
|
||||||
if (code !== 'Unidentified') {
|
if (code !== 'Unidentified') {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -94,20 +79,42 @@ Keyboard.prototype = {
|
||||||
return e.keyIdentifier;
|
return e.keyIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
var codepoint = parseInt(e.keyIdentifier.substr(2), 16);
|
const codepoint = parseInt(e.keyIdentifier.substr(2), 16);
|
||||||
var char = String.fromCharCode(codepoint);
|
const char = String.fromCharCode(codepoint).toUpperCase();
|
||||||
// Some implementations fail to uppercase the symbols
|
|
||||||
char = char.toUpperCase();
|
|
||||||
|
|
||||||
return 'Platform' + char.charCodeAt();
|
return 'Platform' + char.charCodeAt();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Unidentified';
|
return 'Unidentified';
|
||||||
},
|
}
|
||||||
|
|
||||||
_handleKeyDown: function (e) {
|
_handleKeyDown(e) {
|
||||||
var code = this._getKeyCode(e);
|
const code = this._getKeyCode(e);
|
||||||
var keysym = KeyboardUtil.getKeysym(e);
|
let keysym = KeyboardUtil.getKeysym(e);
|
||||||
|
|
||||||
|
// Windows doesn't have a proper AltGr, but handles it using
|
||||||
|
// fake Ctrl+Alt. However the remote end might not be Windows,
|
||||||
|
// so we need to merge those in to a single AltGr event. We
|
||||||
|
// detect this case by seeing the two key events directly after
|
||||||
|
// each other with a very short time between them (<50ms).
|
||||||
|
if (this._altGrArmed) {
|
||||||
|
this._altGrArmed = false;
|
||||||
|
clearTimeout(this._altGrTimeout);
|
||||||
|
|
||||||
|
if ((code === "AltRight") &&
|
||||||
|
((e.timeStamp - this._altGrCtrlTime) < 50)) {
|
||||||
|
// FIXME: We fail to detect this if either Ctrl key is
|
||||||
|
// first manually pressed as Windows then no
|
||||||
|
// longer sends the fake Ctrl down event. It
|
||||||
|
// does however happily send real Ctrl events
|
||||||
|
// even when AltGr is already down. Some
|
||||||
|
// browsers detect this for us though and set the
|
||||||
|
// key to "AltGraph".
|
||||||
|
keysym = KeyTable.XK_ISO_Level3_Shift;
|
||||||
|
} else {
|
||||||
|
this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We cannot handle keys we cannot track, but we also need
|
// We cannot handle keys we cannot track, but we also need
|
||||||
// to deal with virtual keyboards which omit key info
|
// to deal with virtual keyboards which omit key info
|
||||||
|
@ -180,13 +187,20 @@ Keyboard.prototype = {
|
||||||
this._pendingKey = null;
|
this._pendingKey = null;
|
||||||
stopEvent(e);
|
stopEvent(e);
|
||||||
|
|
||||||
this._keyDownList[code] = keysym;
|
// Possible start of AltGr sequence? (see above)
|
||||||
|
if ((code === "ControlLeft") && browser.isWindows() &&
|
||||||
|
!("ControlLeft" in this._keyDownList)) {
|
||||||
|
this._altGrArmed = true;
|
||||||
|
this._altGrTimeout = setTimeout(this._handleAltGrTimeout.bind(this), 100);
|
||||||
|
this._altGrCtrlTime = e.timeStamp;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._sendKeyEvent(keysym, code, true);
|
this._sendKeyEvent(keysym, code, true);
|
||||||
},
|
}
|
||||||
|
|
||||||
// Legacy event for browsers without code/key
|
// Legacy event for browsers without code/key
|
||||||
_handleKeyPress: function (e) {
|
_handleKeyPress(e) {
|
||||||
stopEvent(e);
|
stopEvent(e);
|
||||||
|
|
||||||
// Are we expecting a keypress?
|
// Are we expecting a keypress?
|
||||||
|
@ -194,8 +208,8 @@ Keyboard.prototype = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var code = this._getKeyCode(e);
|
let code = this._getKeyCode(e);
|
||||||
var keysym = KeyboardUtil.getKeysym(e);
|
const keysym = KeyboardUtil.getKeysym(e);
|
||||||
|
|
||||||
// The key we were waiting for?
|
// The key we were waiting for?
|
||||||
if ((code !== 'Unidentified') && (code != this._pendingKey)) {
|
if ((code !== 'Unidentified') && (code != this._pendingKey)) {
|
||||||
|
@ -210,19 +224,18 @@ Keyboard.prototype = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._keyDownList[code] = keysym;
|
|
||||||
|
|
||||||
this._sendKeyEvent(keysym, code, true);
|
this._sendKeyEvent(keysym, code, true);
|
||||||
},
|
}
|
||||||
_handleKeyPressTimeout: function (e) {
|
|
||||||
|
_handleKeyPressTimeout(e) {
|
||||||
// Did someone manage to sort out the key already?
|
// Did someone manage to sort out the key already?
|
||||||
if (this._pendingKey === null) {
|
if (this._pendingKey === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var code, keysym;
|
let keysym;
|
||||||
|
|
||||||
code = this._pendingKey;
|
const code = this._pendingKey;
|
||||||
this._pendingKey = null;
|
this._pendingKey = null;
|
||||||
|
|
||||||
// We have no way of knowing the proper keysym with the
|
// We have no way of knowing the proper keysym with the
|
||||||
|
@ -233,27 +246,34 @@ Keyboard.prototype = {
|
||||||
keysym = e.keyCode;
|
keysym = e.keyCode;
|
||||||
} else if ((e.keyCode >= 0x41) && (e.keyCode <= 0x5a)) {
|
} else if ((e.keyCode >= 0x41) && (e.keyCode <= 0x5a)) {
|
||||||
// Character (A-Z)
|
// Character (A-Z)
|
||||||
var char = String.fromCharCode(e.keyCode);
|
let char = String.fromCharCode(e.keyCode);
|
||||||
// A feeble attempt at the correct case
|
// A feeble attempt at the correct case
|
||||||
if (e.shiftKey)
|
if (e.shiftKey) {
|
||||||
char = char.toUpperCase();
|
char = char.toUpperCase();
|
||||||
else
|
} else {
|
||||||
char = char.toLowerCase();
|
char = char.toLowerCase();
|
||||||
|
}
|
||||||
keysym = char.charCodeAt();
|
keysym = char.charCodeAt();
|
||||||
} else {
|
} else {
|
||||||
// Unknown, give up
|
// Unknown, give up
|
||||||
keysym = 0;
|
keysym = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._keyDownList[code] = keysym;
|
|
||||||
|
|
||||||
this._sendKeyEvent(keysym, code, true);
|
this._sendKeyEvent(keysym, code, true);
|
||||||
},
|
}
|
||||||
|
|
||||||
_handleKeyUp: function (e) {
|
_handleKeyUp(e) {
|
||||||
stopEvent(e);
|
stopEvent(e);
|
||||||
|
|
||||||
var code = this._getKeyCode(e);
|
const code = this._getKeyCode(e);
|
||||||
|
|
||||||
|
// We can't get a release in the middle of an AltGr sequence, so
|
||||||
|
// abort that detection
|
||||||
|
if (this._altGrArmed) {
|
||||||
|
this._altGrArmed = false;
|
||||||
|
clearTimeout(this._altGrTimeout);
|
||||||
|
this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
||||||
|
}
|
||||||
|
|
||||||
// See comment in _handleKeyDown()
|
// See comment in _handleKeyDown()
|
||||||
if (browser.isMac() && (code === 'CapsLock')) {
|
if (browser.isMac() && (code === 'CapsLock')) {
|
||||||
|
@ -262,53 +282,89 @@ Keyboard.prototype = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do we really think this key is down?
|
this._sendKeyEvent(this._keyDownList[code], code, false);
|
||||||
if (!(code in this._keyDownList)) {
|
}
|
||||||
|
|
||||||
|
_handleAltGrTimeout() {
|
||||||
|
this._altGrArmed = false;
|
||||||
|
clearTimeout(this._altGrTimeout);
|
||||||
|
this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_allKeysUp() {
|
||||||
|
Log.Debug(">> Keyboard.allKeysUp");
|
||||||
|
for (let code in this._keyDownList) {
|
||||||
|
this._sendKeyEvent(this._keyDownList[code], code, false);
|
||||||
|
}
|
||||||
|
Log.Debug("<< Keyboard.allKeysUp");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Firefox Alt workaround, see below
|
||||||
|
_checkAlt(e) {
|
||||||
|
if (e.altKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._sendKeyEvent(this._keyDownList[code], code, false);
|
const target = this._target;
|
||||||
|
const downList = this._keyDownList;
|
||||||
|
['AltLeft', 'AltRight'].forEach((code) => {
|
||||||
|
if (!(code in downList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
delete this._keyDownList[code];
|
const event = new KeyboardEvent('keyup',
|
||||||
},
|
{ key: downList[code],
|
||||||
|
code: code });
|
||||||
_allKeysUp: function () {
|
target.dispatchEvent(event);
|
||||||
Log.Debug(">> Keyboard.allKeysUp");
|
});
|
||||||
for (var code in this._keyDownList) {
|
}
|
||||||
this._sendKeyEvent(this._keyDownList[code], code, false);
|
|
||||||
};
|
|
||||||
this._keyDownList = {};
|
|
||||||
Log.Debug("<< Keyboard.allKeysUp");
|
|
||||||
},
|
|
||||||
|
|
||||||
// ===== PUBLIC METHODS =====
|
// ===== PUBLIC METHODS =====
|
||||||
|
|
||||||
grab: function () {
|
grab() {
|
||||||
//Log.Debug(">> Keyboard.grab");
|
//Log.Debug(">> Keyboard.grab");
|
||||||
var c = this._target;
|
|
||||||
|
|
||||||
c.addEventListener('keydown', this._eventHandlers.keydown);
|
this._target.addEventListener('keydown', this._eventHandlers.keydown);
|
||||||
c.addEventListener('keyup', this._eventHandlers.keyup);
|
this._target.addEventListener('keyup', this._eventHandlers.keyup);
|
||||||
c.addEventListener('keypress', this._eventHandlers.keypress);
|
this._target.addEventListener('keypress', this._eventHandlers.keypress);
|
||||||
|
|
||||||
// Release (key up) if window loses focus
|
// Release (key up) if window loses focus
|
||||||
window.addEventListener('blur', this._eventHandlers.blur);
|
window.addEventListener('blur', this._eventHandlers.blur);
|
||||||
|
|
||||||
|
// Firefox has broken handling of Alt, so we need to poll as
|
||||||
|
// best we can for releases (still doesn't prevent the menu
|
||||||
|
// from popping up though as we can't call preventDefault())
|
||||||
|
if (browser.isWindows() && browser.isFirefox()) {
|
||||||
|
const handler = this._eventHandlers.checkalt;
|
||||||
|
['mousedown', 'mouseup', 'mousemove', 'wheel',
|
||||||
|
'touchstart', 'touchend', 'touchmove',
|
||||||
|
'keydown', 'keyup'].forEach(type =>
|
||||||
|
document.addEventListener(type, handler,
|
||||||
|
{ capture: true,
|
||||||
|
passive: true }));
|
||||||
|
}
|
||||||
|
|
||||||
//Log.Debug("<< Keyboard.grab");
|
//Log.Debug("<< Keyboard.grab");
|
||||||
},
|
}
|
||||||
|
|
||||||
ungrab: function () {
|
ungrab() {
|
||||||
//Log.Debug(">> Keyboard.ungrab");
|
//Log.Debug(">> Keyboard.ungrab");
|
||||||
var c = this._target;
|
|
||||||
|
|
||||||
c.removeEventListener('keydown', this._eventHandlers.keydown);
|
if (browser.isWindows() && browser.isFirefox()) {
|
||||||
c.removeEventListener('keyup', this._eventHandlers.keyup);
|
const handler = this._eventHandlers.checkalt;
|
||||||
c.removeEventListener('keypress', this._eventHandlers.keypress);
|
['mousedown', 'mouseup', 'mousemove', 'wheel',
|
||||||
|
'touchstart', 'touchend', 'touchmove',
|
||||||
|
'keydown', 'keyup'].forEach(type => document.removeEventListener(type, handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._target.removeEventListener('keydown', this._eventHandlers.keydown);
|
||||||
|
this._target.removeEventListener('keyup', this._eventHandlers.keyup);
|
||||||
|
this._target.removeEventListener('keypress', this._eventHandlers.keypress);
|
||||||
window.removeEventListener('blur', this._eventHandlers.blur);
|
window.removeEventListener('blur', this._eventHandlers.blur);
|
||||||
|
|
||||||
// Release (key up) all keys that are in a down state
|
// Release (key up) all keys that are in a down state
|
||||||
this._allKeysUp();
|
this._allKeysUp();
|
||||||
|
|
||||||
//Log.Debug(">> Keyboard.ungrab");
|
//Log.Debug(">> Keyboard.ungrab");
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* eslint-disable key-spacing */
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
XK_VoidSymbol: 0xffffff, /* Void symbol */
|
XK_VoidSymbol: 0xffffff, /* Void symbol */
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
/* Functions at the bottom */
|
/* Functions at the bottom */
|
||||||
|
|
||||||
var codepoints = {
|
const codepoints = {
|
||||||
0x0100: 0x03c0, // XK_Amacron
|
0x0100: 0x03c0, // XK_Amacron
|
||||||
0x0101: 0x03e0, // XK_amacron
|
0x0101: 0x03e0, // XK_amacron
|
||||||
0x0102: 0x01c3, // XK_Abreve
|
0x0102: 0x01c3, // XK_Abreve
|
||||||
|
@ -670,14 +670,14 @@ var codepoints = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
lookup : function(u) {
|
lookup(u) {
|
||||||
// Latin-1 is one-to-one mapping
|
// Latin-1 is one-to-one mapping
|
||||||
if ((u >= 0x20) && (u <= 0xff)) {
|
if ((u >= 0x20) && (u <= 0xff)) {
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup table (fairly random)
|
// Lookup table (fairly random)
|
||||||
var keysym = codepoints[u];
|
const keysym = codepoints[u];
|
||||||
if (keysym !== undefined) {
|
if (keysym !== undefined) {
|
||||||
return keysym;
|
return keysym;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2012 Joel Martin
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Copyright (C) 2013 Samuel Mannehed for Cendio AB
|
|
||||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -9,11 +8,12 @@ import * as Log from '../util/logging.js';
|
||||||
import { isTouchDevice } from '../util/browser.js';
|
import { isTouchDevice } from '../util/browser.js';
|
||||||
import { setCapture, stopEvent, getPointerEvent } from '../util/events.js';
|
import { setCapture, stopEvent, getPointerEvent } from '../util/events.js';
|
||||||
|
|
||||||
var WHEEL_STEP = 10; // Delta threshold for a mouse wheel step
|
const WHEEL_STEP = 10; // Delta threshold for a mouse wheel step
|
||||||
var WHEEL_STEP_TIMEOUT = 50; // ms
|
const WHEEL_STEP_TIMEOUT = 50; // ms
|
||||||
var WHEEL_LINE_HEIGHT = 19;
|
const WHEEL_LINE_HEIGHT = 19;
|
||||||
|
|
||||||
export default function Mouse(target) {
|
export default class Mouse {
|
||||||
|
constructor(target) {
|
||||||
this._target = target || document;
|
this._target = target || document;
|
||||||
|
|
||||||
this._doubleClickTimer = null;
|
this._doubleClickTimer = null;
|
||||||
|
@ -32,29 +32,28 @@ export default function Mouse(target) {
|
||||||
'mousewheel': this._handleMouseWheel.bind(this),
|
'mousewheel': this._handleMouseWheel.bind(this),
|
||||||
'mousedisable': this._handleMouseDisable.bind(this)
|
'mousedisable': this._handleMouseDisable.bind(this)
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
Mouse.prototype = {
|
|
||||||
// ===== PROPERTIES =====
|
// ===== PROPERTIES =====
|
||||||
|
|
||||||
touchButton: 1, // Button mask (1, 2, 4) for touch devices (0 means ignore clicks)
|
this.touchButton = 1; // Button mask (1, 2, 4) for touch devices (0 means ignore clicks)
|
||||||
|
|
||||||
// ===== EVENT HANDLERS =====
|
// ===== EVENT HANDLERS =====
|
||||||
|
|
||||||
onmousebutton: function () {}, // Handler for mouse button click/release
|
this.onmousebutton = () => {}; // Handler for mouse button click/release
|
||||||
onmousemove: function () {}, // Handler for mouse movement
|
this.onmousemove = () => {}; // Handler for mouse movement
|
||||||
|
}
|
||||||
|
|
||||||
// ===== PRIVATE METHODS =====
|
// ===== PRIVATE METHODS =====
|
||||||
|
|
||||||
_resetDoubleClickTimer: function () {
|
_resetDoubleClickTimer() {
|
||||||
this._doubleClickTimer = null;
|
this._doubleClickTimer = null;
|
||||||
},
|
}
|
||||||
|
|
||||||
_handleMouseButton: function (e, down) {
|
_handleMouseButton(e, down) {
|
||||||
this._updateMousePosition(e);
|
this._updateMousePosition(e);
|
||||||
var pos = this._pos;
|
let pos = this._pos;
|
||||||
|
|
||||||
var bmask;
|
let bmask;
|
||||||
if (e.touches || e.changedTouches) {
|
if (e.touches || e.changedTouches) {
|
||||||
// Touch device
|
// Touch device
|
||||||
|
|
||||||
|
@ -70,13 +69,13 @@ Mouse.prototype = {
|
||||||
// force the position of the latter touch to the position of
|
// force the position of the latter touch to the position of
|
||||||
// the first.
|
// the first.
|
||||||
|
|
||||||
var xs = this._lastTouchPos.x - pos.x;
|
const xs = this._lastTouchPos.x - pos.x;
|
||||||
var ys = this._lastTouchPos.y - pos.y;
|
const ys = this._lastTouchPos.y - pos.y;
|
||||||
var d = Math.sqrt((xs * xs) + (ys * ys));
|
const d = Math.sqrt((xs * xs) + (ys * ys));
|
||||||
|
|
||||||
// The goal is to trigger on a certain physical width, the
|
// The goal is to trigger on a certain physical width, the
|
||||||
// devicePixelRatio brings us a bit closer but is not optimal.
|
// devicePixelRatio brings us a bit closer but is not optimal.
|
||||||
var threshold = 20 * (window.devicePixelRatio || 1);
|
const threshold = 20 * (window.devicePixelRatio || 1);
|
||||||
if (d < threshold) {
|
if (d < threshold) {
|
||||||
pos = this._lastTouchPos;
|
pos = this._lastTouchPos;
|
||||||
}
|
}
|
||||||
|
@ -100,25 +99,25 @@ Mouse.prototype = {
|
||||||
this.onmousebutton(pos.x, pos.y, down, bmask);
|
this.onmousebutton(pos.x, pos.y, down, bmask);
|
||||||
|
|
||||||
stopEvent(e);
|
stopEvent(e);
|
||||||
},
|
}
|
||||||
|
|
||||||
_handleMouseDown: function (e) {
|
_handleMouseDown(e) {
|
||||||
// Touch events have implicit capture
|
// Touch events have implicit capture
|
||||||
if (e.type === "mousedown") {
|
if (e.type === "mousedown") {
|
||||||
setCapture(this._target);
|
setCapture(this._target);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._handleMouseButton(e, 1);
|
this._handleMouseButton(e, 1);
|
||||||
},
|
}
|
||||||
|
|
||||||
_handleMouseUp: function (e) {
|
_handleMouseUp(e) {
|
||||||
this._handleMouseButton(e, 0);
|
this._handleMouseButton(e, 0);
|
||||||
},
|
}
|
||||||
|
|
||||||
// Mouse wheel events are sent in steps over VNC. This means that the VNC
|
// Mouse wheel events are sent in steps over VNC. This means that the VNC
|
||||||
// protocol can't handle a wheel event with specific distance or speed.
|
// protocol can't handle a wheel event with specific distance or speed.
|
||||||
// Therefor, if we get a lot of small mouse wheel events we combine them.
|
// Therefor, if we get a lot of small mouse wheel events we combine them.
|
||||||
_generateWheelStepX: function () {
|
_generateWheelStepX() {
|
||||||
|
|
||||||
if (this._accumulatedWheelDeltaX < 0) {
|
if (this._accumulatedWheelDeltaX < 0) {
|
||||||
this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 5);
|
this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 5);
|
||||||
|
@ -129,9 +128,9 @@ Mouse.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
this._accumulatedWheelDeltaX = 0;
|
this._accumulatedWheelDeltaX = 0;
|
||||||
},
|
}
|
||||||
|
|
||||||
_generateWheelStepY: function () {
|
_generateWheelStepY() {
|
||||||
|
|
||||||
if (this._accumulatedWheelDeltaY < 0) {
|
if (this._accumulatedWheelDeltaY < 0) {
|
||||||
this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 3);
|
this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 3);
|
||||||
|
@ -142,22 +141,22 @@ Mouse.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
this._accumulatedWheelDeltaY = 0;
|
this._accumulatedWheelDeltaY = 0;
|
||||||
},
|
}
|
||||||
|
|
||||||
_resetWheelStepTimers: function () {
|
_resetWheelStepTimers() {
|
||||||
window.clearTimeout(this._wheelStepXTimer);
|
window.clearTimeout(this._wheelStepXTimer);
|
||||||
window.clearTimeout(this._wheelStepYTimer);
|
window.clearTimeout(this._wheelStepYTimer);
|
||||||
this._wheelStepXTimer = null;
|
this._wheelStepXTimer = null;
|
||||||
this._wheelStepYTimer = null;
|
this._wheelStepYTimer = null;
|
||||||
},
|
}
|
||||||
|
|
||||||
_handleMouseWheel: function (e) {
|
_handleMouseWheel(e) {
|
||||||
this._resetWheelStepTimers();
|
this._resetWheelStepTimers();
|
||||||
|
|
||||||
this._updateMousePosition(e);
|
this._updateMousePosition(e);
|
||||||
|
|
||||||
var dX = e.deltaX;
|
let dX = e.deltaX;
|
||||||
var dY = e.deltaY;
|
let dY = e.deltaY;
|
||||||
|
|
||||||
// Pixel units unless it's non-zero.
|
// Pixel units unless it's non-zero.
|
||||||
// Note that if deltamode is line or page won't matter since we aren't
|
// Note that if deltamode is line or page won't matter since we aren't
|
||||||
|
@ -192,15 +191,15 @@ Mouse.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
stopEvent(e);
|
stopEvent(e);
|
||||||
},
|
}
|
||||||
|
|
||||||
_handleMouseMove: function (e) {
|
_handleMouseMove(e) {
|
||||||
this._updateMousePosition(e);
|
this._updateMousePosition(e);
|
||||||
this.onmousemove(this._pos.x, this._pos.y);
|
this.onmousemove(this._pos.x, this._pos.y);
|
||||||
stopEvent(e);
|
stopEvent(e);
|
||||||
},
|
}
|
||||||
|
|
||||||
_handleMouseDisable: function (e) {
|
_handleMouseDisable(e) {
|
||||||
/*
|
/*
|
||||||
* Stop propagation if inside canvas area
|
* Stop propagation if inside canvas area
|
||||||
* Note: This is only needed for the 'click' event as it fails
|
* Note: This is only needed for the 'click' event as it fails
|
||||||
|
@ -210,13 +209,14 @@ Mouse.prototype = {
|
||||||
if (e.target == this._target) {
|
if (e.target == this._target) {
|
||||||
stopEvent(e);
|
stopEvent(e);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// Update coordinates relative to target
|
// Update coordinates relative to target
|
||||||
_updateMousePosition: function(e) {
|
_updateMousePosition(e) {
|
||||||
e = getPointerEvent(e);
|
e = getPointerEvent(e);
|
||||||
var bounds = this._target.getBoundingClientRect();
|
const bounds = this._target.getBoundingClientRect();
|
||||||
var x, y;
|
let x;
|
||||||
|
let y;
|
||||||
// Clip to target bounds
|
// Clip to target bounds
|
||||||
if (e.clientX < bounds.left) {
|
if (e.clientX < bounds.left) {
|
||||||
x = 0;
|
x = 0;
|
||||||
|
@ -232,49 +232,45 @@ Mouse.prototype = {
|
||||||
} else {
|
} else {
|
||||||
y = e.clientY - bounds.top;
|
y = e.clientY - bounds.top;
|
||||||
}
|
}
|
||||||
this._pos = {x:x, y:y};
|
this._pos = {x: x, y: y};
|
||||||
},
|
}
|
||||||
|
|
||||||
// ===== PUBLIC METHODS =====
|
// ===== PUBLIC METHODS =====
|
||||||
|
|
||||||
grab: function () {
|
grab() {
|
||||||
var c = this._target;
|
|
||||||
|
|
||||||
if (isTouchDevice) {
|
if (isTouchDevice) {
|
||||||
c.addEventListener('touchstart', this._eventHandlers.mousedown);
|
this._target.addEventListener('touchstart', this._eventHandlers.mousedown);
|
||||||
c.addEventListener('touchend', this._eventHandlers.mouseup);
|
this._target.addEventListener('touchend', this._eventHandlers.mouseup);
|
||||||
c.addEventListener('touchmove', this._eventHandlers.mousemove);
|
this._target.addEventListener('touchmove', this._eventHandlers.mousemove);
|
||||||
}
|
}
|
||||||
c.addEventListener('mousedown', this._eventHandlers.mousedown);
|
this._target.addEventListener('mousedown', this._eventHandlers.mousedown);
|
||||||
c.addEventListener('mouseup', this._eventHandlers.mouseup);
|
this._target.addEventListener('mouseup', this._eventHandlers.mouseup);
|
||||||
c.addEventListener('mousemove', this._eventHandlers.mousemove);
|
this._target.addEventListener('mousemove', this._eventHandlers.mousemove);
|
||||||
c.addEventListener('wheel', this._eventHandlers.mousewheel);
|
this._target.addEventListener('wheel', this._eventHandlers.mousewheel);
|
||||||
|
|
||||||
/* Prevent middle-click pasting (see above for why we bind to document) */
|
/* Prevent middle-click pasting (see above for why we bind to document) */
|
||||||
document.addEventListener('click', this._eventHandlers.mousedisable);
|
document.addEventListener('click', this._eventHandlers.mousedisable);
|
||||||
|
|
||||||
/* preventDefault() on mousedown doesn't stop this event for some
|
/* preventDefault() on mousedown doesn't stop this event for some
|
||||||
reason so we have to explicitly block it */
|
reason so we have to explicitly block it */
|
||||||
c.addEventListener('contextmenu', this._eventHandlers.mousedisable);
|
this._target.addEventListener('contextmenu', this._eventHandlers.mousedisable);
|
||||||
},
|
}
|
||||||
|
|
||||||
ungrab: function () {
|
|
||||||
var c = this._target;
|
|
||||||
|
|
||||||
|
ungrab() {
|
||||||
this._resetWheelStepTimers();
|
this._resetWheelStepTimers();
|
||||||
|
|
||||||
if (isTouchDevice) {
|
if (isTouchDevice) {
|
||||||
c.removeEventListener('touchstart', this._eventHandlers.mousedown);
|
this._target.removeEventListener('touchstart', this._eventHandlers.mousedown);
|
||||||
c.removeEventListener('touchend', this._eventHandlers.mouseup);
|
this._target.removeEventListener('touchend', this._eventHandlers.mouseup);
|
||||||
c.removeEventListener('touchmove', this._eventHandlers.mousemove);
|
this._target.removeEventListener('touchmove', this._eventHandlers.mousemove);
|
||||||
}
|
}
|
||||||
c.removeEventListener('mousedown', this._eventHandlers.mousedown);
|
this._target.removeEventListener('mousedown', this._eventHandlers.mousedown);
|
||||||
c.removeEventListener('mouseup', this._eventHandlers.mouseup);
|
this._target.removeEventListener('mouseup', this._eventHandlers.mouseup);
|
||||||
c.removeEventListener('mousemove', this._eventHandlers.mousemove);
|
this._target.removeEventListener('mousemove', this._eventHandlers.mousemove);
|
||||||
c.removeEventListener('wheel', this._eventHandlers.mousewheel);
|
this._target.removeEventListener('wheel', this._eventHandlers.mousewheel);
|
||||||
|
|
||||||
document.removeEventListener('click', this._eventHandlers.mousedisable);
|
document.removeEventListener('click', this._eventHandlers.mousedisable);
|
||||||
|
|
||||||
c.removeEventListener('contextmenu', this._eventHandlers.mousedisable);
|
this._target.removeEventListener('contextmenu', this._eventHandlers.mousedisable);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import KeyTable from "./keysym.js";
|
|
||||||
import keysyms from "./keysymdef.js";
|
import keysyms from "./keysymdef.js";
|
||||||
import vkeys from "./vkeys.js";
|
import vkeys from "./vkeys.js";
|
||||||
import fixedkeys from "./fixedkeys.js";
|
import fixedkeys from "./fixedkeys.js";
|
||||||
|
@ -6,7 +5,7 @@ import DOMKeyTable from "./domkeytable.js";
|
||||||
import * as browser from "../util/browser.js";
|
import * as browser from "../util/browser.js";
|
||||||
|
|
||||||
// Get 'KeyboardEvent.code', handling legacy browsers
|
// Get 'KeyboardEvent.code', handling legacy browsers
|
||||||
export function getKeycode(evt){
|
export function getKeycode(evt) {
|
||||||
// Are we getting proper key identifiers?
|
// Are we getting proper key identifiers?
|
||||||
// (unfortunately Firefox and Chrome are crappy here and gives
|
// (unfortunately Firefox and Chrome are crappy here and gives
|
||||||
// us an empty string on some platforms, rather than leaving it
|
// us an empty string on some platforms, rather than leaving it
|
||||||
|
@ -25,7 +24,7 @@ export function getKeycode(evt){
|
||||||
// in the 'keyCode' field for non-printable characters. However
|
// in the 'keyCode' field for non-printable characters. However
|
||||||
// Webkit sets it to the same as charCode in 'keypress' events.
|
// Webkit sets it to the same as charCode in 'keypress' events.
|
||||||
if ((evt.type !== 'keypress') && (evt.keyCode in vkeys)) {
|
if ((evt.type !== 'keypress') && (evt.keyCode in vkeys)) {
|
||||||
var code = vkeys[evt.keyCode];
|
let code = vkeys[evt.keyCode];
|
||||||
|
|
||||||
// macOS has messed up this code for some reason
|
// macOS has messed up this code for some reason
|
||||||
if (browser.isMac() && (code === 'ContextMenu')) {
|
if (browser.isMac() && (code === 'ContextMenu')) {
|
||||||
|
@ -111,7 +110,7 @@ export function getKey(evt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to deduce it based on the physical key
|
// Try to deduce it based on the physical key
|
||||||
var code = getKeycode(evt);
|
const code = getKeycode(evt);
|
||||||
if (code in fixedkeys) {
|
if (code in fixedkeys) {
|
||||||
return fixedkeys[code];
|
return fixedkeys[code];
|
||||||
}
|
}
|
||||||
|
@ -126,8 +125,8 @@ export function getKey(evt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the most reliable keysym value we can get from a key event
|
// Get the most reliable keysym value we can get from a key event
|
||||||
export function getKeysym(evt){
|
export function getKeysym(evt) {
|
||||||
var key = getKey(evt);
|
const key = getKey(evt);
|
||||||
|
|
||||||
if (key === 'Unidentified') {
|
if (key === 'Unidentified') {
|
||||||
return null;
|
return null;
|
||||||
|
@ -135,7 +134,7 @@ export function getKeysym(evt){
|
||||||
|
|
||||||
// First look up special keys
|
// First look up special keys
|
||||||
if (key in DOMKeyTable) {
|
if (key in DOMKeyTable) {
|
||||||
var location = evt.location;
|
let location = evt.location;
|
||||||
|
|
||||||
// Safari screws up location for the right cmd key
|
// Safari screws up location for the right cmd key
|
||||||
if ((key === 'Meta') && (location === 0)) {
|
if ((key === 'Meta') && (location === 0)) {
|
||||||
|
@ -151,14 +150,12 @@ export function getKeysym(evt){
|
||||||
|
|
||||||
// Now we need to look at the Unicode symbol instead
|
// Now we need to look at the Unicode symbol instead
|
||||||
|
|
||||||
var codepoint;
|
|
||||||
|
|
||||||
// Special key? (FIXME: Should have been caught earlier)
|
// Special key? (FIXME: Should have been caught earlier)
|
||||||
if (key.length !== 1) {
|
if (key.length !== 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
codepoint = key.charCodeAt();
|
const codepoint = key.charCodeAt();
|
||||||
if (codepoint) {
|
if (codepoint) {
|
||||||
return keysyms.lookup(codepoint);
|
return keysyms.lookup(codepoint);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2017 Pierre Ossman for Cendio AB
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ export default {
|
||||||
0x08: 'Backspace',
|
0x08: 'Backspace',
|
||||||
0x09: 'Tab',
|
0x09: 'Tab',
|
||||||
0x0a: 'NumpadClear',
|
0x0a: 'NumpadClear',
|
||||||
|
0x0c: 'Numpad5', // IE11 sends evt.keyCode: 12 when numlock is off
|
||||||
0x0d: 'Enter',
|
0x0d: 'Enter',
|
||||||
0x10: 'ShiftLeft',
|
0x10: 'ShiftLeft',
|
||||||
0x11: 'ControlLeft',
|
0x11: 'ControlLeft',
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2012 Joel Martin
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
*
|
*
|
||||||
* See README.md for usage and integration instructions.
|
* See README.md for usage and integration instructions.
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
import * as Log from './logging.js';
|
import * as Log from './logging.js';
|
||||||
|
|
||||||
// Touch detection
|
// Touch detection
|
||||||
export var isTouchDevice = ('ontouchstart' in document.documentElement) ||
|
export let isTouchDevice = ('ontouchstart' in document.documentElement) ||
|
||||||
// requried for Chrome debugger
|
// requried for Chrome debugger
|
||||||
(document.ontouchstart !== undefined) ||
|
(document.ontouchstart !== undefined) ||
|
||||||
// required for MS Surface
|
// required for MS Surface
|
||||||
|
@ -20,42 +20,42 @@ window.addEventListener('touchstart', function onFirstTouch() {
|
||||||
window.removeEventListener('touchstart', onFirstTouch, false);
|
window.removeEventListener('touchstart', onFirstTouch, false);
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
var _cursor_uris_supported = null;
|
|
||||||
|
|
||||||
export function supportsCursorURIs () {
|
// The goal is to find a certain physical width, the devicePixelRatio
|
||||||
if (_cursor_uris_supported === null) {
|
// brings us a bit closer but is not optimal.
|
||||||
try {
|
export let dragThreshold = 10 * (window.devicePixelRatio || 1);
|
||||||
var target = document.createElement('canvas');
|
|
||||||
|
let _supportsCursorURIs = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const target = document.createElement('canvas');
|
||||||
target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default';
|
target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default';
|
||||||
|
|
||||||
if (target.style.cursor) {
|
if (target.style.cursor) {
|
||||||
Log.Info("Data URI scheme cursor supported");
|
Log.Info("Data URI scheme cursor supported");
|
||||||
_cursor_uris_supported = true;
|
_supportsCursorURIs = true;
|
||||||
} else {
|
} else {
|
||||||
Log.Warn("Data URI scheme cursor not supported");
|
Log.Warn("Data URI scheme cursor not supported");
|
||||||
_cursor_uris_supported = false;
|
|
||||||
}
|
}
|
||||||
} catch (exc) {
|
} catch (exc) {
|
||||||
Log.Error("Data URI scheme cursor test exception: " + exc);
|
Log.Error("Data URI scheme cursor test exception: " + exc);
|
||||||
_cursor_uris_supported = false;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _cursor_uris_supported;
|
export const supportsCursorURIs = _supportsCursorURIs;
|
||||||
};
|
|
||||||
|
let _supportsImageMetadata = false;
|
||||||
|
try {
|
||||||
|
new ImageData(new Uint8ClampedArray(4), 1, 1);
|
||||||
|
_supportsImageMetadata = true;
|
||||||
|
} catch (ex) {
|
||||||
|
// ignore failure
|
||||||
|
}
|
||||||
|
export const supportsImageMetadata = _supportsImageMetadata;
|
||||||
|
|
||||||
export function isMac() {
|
export function isMac() {
|
||||||
return navigator && !!(/mac/i).exec(navigator.platform);
|
return navigator && !!(/mac/i).exec(navigator.platform);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isIE() {
|
|
||||||
return navigator && !!(/trident/i).exec(navigator.userAgent);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isEdge() {
|
|
||||||
return navigator && !!(/edge/i).exec(navigator.userAgent);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isWindows() {
|
export function isWindows() {
|
||||||
return navigator && !!(/win/i).exec(navigator.platform);
|
return navigator && !!(/win/i).exec(navigator.platform);
|
||||||
}
|
}
|
||||||
|
@ -67,3 +67,24 @@ export function isIOS() {
|
||||||
!!(/ipod/i).exec(navigator.platform));
|
!!(/ipod/i).exec(navigator.platform));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAndroid() {
|
||||||
|
return navigator && !!(/android/i).exec(navigator.userAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSafari() {
|
||||||
|
return navigator && (navigator.userAgent.indexOf('Safari') !== -1 &&
|
||||||
|
navigator.userAgent.indexOf('Chrome') === -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isIE() {
|
||||||
|
return navigator && !!(/trident/i).exec(navigator.userAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isEdge() {
|
||||||
|
return navigator && !!(/edge/i).exec(navigator.userAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFirefox() {
|
||||||
|
return navigator && !!(/firefox/i).exec(navigator.userAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
221
static/js/novnc/core/util/cursor.js
Executable file
221
static/js/novnc/core/util/cursor.js
Executable file
|
@ -0,0 +1,221 @@
|
||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
|
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { supportsCursorURIs, isTouchDevice } from './browser.js';
|
||||||
|
|
||||||
|
const useFallback = !supportsCursorURIs || isTouchDevice;
|
||||||
|
|
||||||
|
export default class Cursor {
|
||||||
|
constructor() {
|
||||||
|
this._target = null;
|
||||||
|
|
||||||
|
this._canvas = document.createElement('canvas');
|
||||||
|
|
||||||
|
if (useFallback) {
|
||||||
|
this._canvas.style.position = 'fixed';
|
||||||
|
this._canvas.style.zIndex = '65535';
|
||||||
|
this._canvas.style.pointerEvents = 'none';
|
||||||
|
// Can't use "display" because of Firefox bug #1445997
|
||||||
|
this._canvas.style.visibility = 'hidden';
|
||||||
|
document.body.appendChild(this._canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._position = { x: 0, y: 0 };
|
||||||
|
this._hotSpot = { x: 0, y: 0 };
|
||||||
|
|
||||||
|
this._eventHandlers = {
|
||||||
|
'mouseover': this._handleMouseOver.bind(this),
|
||||||
|
'mouseleave': this._handleMouseLeave.bind(this),
|
||||||
|
'mousemove': this._handleMouseMove.bind(this),
|
||||||
|
'mouseup': this._handleMouseUp.bind(this),
|
||||||
|
'touchstart': this._handleTouchStart.bind(this),
|
||||||
|
'touchmove': this._handleTouchMove.bind(this),
|
||||||
|
'touchend': this._handleTouchEnd.bind(this),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
attach(target) {
|
||||||
|
if (this._target) {
|
||||||
|
this.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._target = target;
|
||||||
|
|
||||||
|
if (useFallback) {
|
||||||
|
// FIXME: These don't fire properly except for mouse
|
||||||
|
/// movement in IE. We want to also capture element
|
||||||
|
// movement, size changes, visibility, etc.
|
||||||
|
const options = { capture: true, passive: true };
|
||||||
|
this._target.addEventListener('mouseover', this._eventHandlers.mouseover, options);
|
||||||
|
this._target.addEventListener('mouseleave', this._eventHandlers.mouseleave, options);
|
||||||
|
this._target.addEventListener('mousemove', this._eventHandlers.mousemove, options);
|
||||||
|
this._target.addEventListener('mouseup', this._eventHandlers.mouseup, options);
|
||||||
|
|
||||||
|
// There is no "touchleave" so we monitor touchstart globally
|
||||||
|
window.addEventListener('touchstart', this._eventHandlers.touchstart, options);
|
||||||
|
this._target.addEventListener('touchmove', this._eventHandlers.touchmove, options);
|
||||||
|
this._target.addEventListener('touchend', this._eventHandlers.touchend, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
detach() {
|
||||||
|
if (useFallback) {
|
||||||
|
const options = { capture: true, passive: true };
|
||||||
|
this._target.removeEventListener('mouseover', this._eventHandlers.mouseover, options);
|
||||||
|
this._target.removeEventListener('mouseleave', this._eventHandlers.mouseleave, options);
|
||||||
|
this._target.removeEventListener('mousemove', this._eventHandlers.mousemove, options);
|
||||||
|
this._target.removeEventListener('mouseup', this._eventHandlers.mouseup, options);
|
||||||
|
|
||||||
|
window.removeEventListener('touchstart', this._eventHandlers.touchstart, options);
|
||||||
|
this._target.removeEventListener('touchmove', this._eventHandlers.touchmove, options);
|
||||||
|
this._target.removeEventListener('touchend', this._eventHandlers.touchend, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
change(rgba, hotx, hoty, w, h) {
|
||||||
|
if ((w === 0) || (h === 0)) {
|
||||||
|
this.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._position.x = this._position.x + this._hotSpot.x - hotx;
|
||||||
|
this._position.y = this._position.y + this._hotSpot.y - hoty;
|
||||||
|
this._hotSpot.x = hotx;
|
||||||
|
this._hotSpot.y = hoty;
|
||||||
|
|
||||||
|
let ctx = this._canvas.getContext('2d');
|
||||||
|
|
||||||
|
this._canvas.width = w;
|
||||||
|
this._canvas.height = h;
|
||||||
|
|
||||||
|
let img;
|
||||||
|
try {
|
||||||
|
// IE doesn't support this
|
||||||
|
img = new ImageData(new Uint8ClampedArray(rgba), w, h);
|
||||||
|
} catch (ex) {
|
||||||
|
img = ctx.createImageData(w, h);
|
||||||
|
img.data.set(new Uint8ClampedArray(rgba));
|
||||||
|
}
|
||||||
|
ctx.clearRect(0, 0, w, h);
|
||||||
|
ctx.putImageData(img, 0, 0);
|
||||||
|
|
||||||
|
if (useFallback) {
|
||||||
|
this._updatePosition();
|
||||||
|
} else {
|
||||||
|
let url = this._canvas.toDataURL();
|
||||||
|
this._target.style.cursor = 'url(' + url + ')' + hotx + ' ' + hoty + ', default';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this._target.style.cursor = 'none';
|
||||||
|
this._canvas.width = 0;
|
||||||
|
this._canvas.height = 0;
|
||||||
|
this._position.x = this._position.x + this._hotSpot.x;
|
||||||
|
this._position.y = this._position.y + this._hotSpot.y;
|
||||||
|
this._hotSpot.x = 0;
|
||||||
|
this._hotSpot.y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleMouseOver(event) {
|
||||||
|
// This event could be because we're entering the target, or
|
||||||
|
// moving around amongst its sub elements. Let the move handler
|
||||||
|
// sort things out.
|
||||||
|
this._handleMouseMove(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleMouseLeave(event) {
|
||||||
|
this._hideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleMouseMove(event) {
|
||||||
|
this._updateVisibility(event.target);
|
||||||
|
|
||||||
|
this._position.x = event.clientX - this._hotSpot.x;
|
||||||
|
this._position.y = event.clientY - this._hotSpot.y;
|
||||||
|
|
||||||
|
this._updatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleMouseUp(event) {
|
||||||
|
// We might get this event because of a drag operation that
|
||||||
|
// moved outside of the target. Check what's under the cursor
|
||||||
|
// now and adjust visibility based on that.
|
||||||
|
let target = document.elementFromPoint(event.clientX, event.clientY);
|
||||||
|
this._updateVisibility(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleTouchStart(event) {
|
||||||
|
// Just as for mouseover, we let the move handler deal with it
|
||||||
|
this._handleTouchMove(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleTouchMove(event) {
|
||||||
|
this._updateVisibility(event.target);
|
||||||
|
|
||||||
|
this._position.x = event.changedTouches[0].clientX - this._hotSpot.x;
|
||||||
|
this._position.y = event.changedTouches[0].clientY - this._hotSpot.y;
|
||||||
|
|
||||||
|
this._updatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleTouchEnd(event) {
|
||||||
|
// Same principle as for mouseup
|
||||||
|
let target = document.elementFromPoint(event.changedTouches[0].clientX,
|
||||||
|
event.changedTouches[0].clientY);
|
||||||
|
this._updateVisibility(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
_showCursor() {
|
||||||
|
if (this._canvas.style.visibility === 'hidden') {
|
||||||
|
this._canvas.style.visibility = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_hideCursor() {
|
||||||
|
if (this._canvas.style.visibility !== 'hidden') {
|
||||||
|
this._canvas.style.visibility = 'hidden';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should we currently display the cursor?
|
||||||
|
// (i.e. are we over the target, or a child of the target without a
|
||||||
|
// different cursor set)
|
||||||
|
_shouldShowCursor(target) {
|
||||||
|
// Easy case
|
||||||
|
if (target === this._target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Other part of the DOM?
|
||||||
|
if (!this._target.contains(target)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Has the child its own cursor?
|
||||||
|
// FIXME: How can we tell that a sub element has an
|
||||||
|
// explicit "cursor: none;"?
|
||||||
|
if (window.getComputedStyle(target).cursor !== 'none') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateVisibility(target) {
|
||||||
|
if (this._shouldShowCursor(target)) {
|
||||||
|
this._showCursor();
|
||||||
|
} else {
|
||||||
|
this._hideCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_updatePosition() {
|
||||||
|
this._canvas.style.left = this._position.x + "px";
|
||||||
|
this._canvas.style.top = this._position.y + "px";
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2012 Joel Martin
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
*
|
*
|
||||||
* See README.md for usage and integration instructions.
|
* See README.md for usage and integration instructions.
|
||||||
|
@ -10,24 +10,24 @@
|
||||||
* Cross-browser event and position routines
|
* Cross-browser event and position routines
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function getPointerEvent (e) {
|
export function getPointerEvent(e) {
|
||||||
return e.changedTouches ? e.changedTouches[0] : e.touches ? e.touches[0] : e;
|
return e.changedTouches ? e.changedTouches[0] : e.touches ? e.touches[0] : e;
|
||||||
};
|
}
|
||||||
|
|
||||||
export function stopEvent (e) {
|
export function stopEvent(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
}
|
||||||
|
|
||||||
// Emulate Element.setCapture() when not supported
|
// Emulate Element.setCapture() when not supported
|
||||||
var _captureRecursion = false;
|
let _captureRecursion = false;
|
||||||
var _captureElem = null;
|
let _captureElem = null;
|
||||||
function _captureProxy(e) {
|
function _captureProxy(e) {
|
||||||
// Recursion protection as we'll see our own event
|
// Recursion protection as we'll see our own event
|
||||||
if (_captureRecursion) return;
|
if (_captureRecursion) return;
|
||||||
|
|
||||||
// Clone the event as we cannot dispatch an already dispatched event
|
// Clone the event as we cannot dispatch an already dispatched event
|
||||||
var newEv = new e.constructor(e.type, e);
|
const newEv = new e.constructor(e.type, e);
|
||||||
|
|
||||||
_captureRecursion = true;
|
_captureRecursion = true;
|
||||||
_captureElem.dispatchEvent(newEv);
|
_captureElem.dispatchEvent(newEv);
|
||||||
|
@ -45,18 +45,19 @@ function _captureProxy(e) {
|
||||||
if (e.type === "mouseup") {
|
if (e.type === "mouseup") {
|
||||||
releaseCapture();
|
releaseCapture();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// Follow cursor style of target element
|
// Follow cursor style of target element
|
||||||
function _captureElemChanged() {
|
function _captureElemChanged() {
|
||||||
var captureElem = document.getElementById("noVNC_mouse_capture_elem");
|
const captureElem = document.getElementById("noVNC_mouse_capture_elem");
|
||||||
captureElem.style.cursor = window.getComputedStyle(_captureElem).cursor;
|
captureElem.style.cursor = window.getComputedStyle(_captureElem).cursor;
|
||||||
};
|
}
|
||||||
var _captureObserver = new MutationObserver(_captureElemChanged);
|
|
||||||
|
|
||||||
var _captureIndex = 0;
|
const _captureObserver = new MutationObserver(_captureElemChanged);
|
||||||
|
|
||||||
export function setCapture (elem) {
|
let _captureIndex = 0;
|
||||||
|
|
||||||
|
export function setCapture(elem) {
|
||||||
if (elem.setCapture) {
|
if (elem.setCapture) {
|
||||||
|
|
||||||
elem.setCapture();
|
elem.setCapture();
|
||||||
|
@ -69,7 +70,7 @@ export function setCapture (elem) {
|
||||||
// called multiple times without coordination
|
// called multiple times without coordination
|
||||||
releaseCapture();
|
releaseCapture();
|
||||||
|
|
||||||
var captureElem = document.getElementById("noVNC_mouse_capture_elem");
|
let captureElem = document.getElementById("noVNC_mouse_capture_elem");
|
||||||
|
|
||||||
if (captureElem === null) {
|
if (captureElem === null) {
|
||||||
captureElem = document.createElement("div");
|
captureElem = document.createElement("div");
|
||||||
|
@ -95,7 +96,7 @@ export function setCapture (elem) {
|
||||||
_captureIndex++;
|
_captureIndex++;
|
||||||
|
|
||||||
// Track cursor and get initial cursor
|
// Track cursor and get initial cursor
|
||||||
_captureObserver.observe(elem, {attributes:true});
|
_captureObserver.observe(elem, {attributes: true});
|
||||||
_captureElemChanged();
|
_captureElemChanged();
|
||||||
|
|
||||||
captureElem.style.display = "";
|
captureElem.style.display = "";
|
||||||
|
@ -105,9 +106,9 @@ export function setCapture (elem) {
|
||||||
window.addEventListener('mousemove', _captureProxy);
|
window.addEventListener('mousemove', _captureProxy);
|
||||||
window.addEventListener('mouseup', _captureProxy);
|
window.addEventListener('mouseup', _captureProxy);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export function releaseCapture () {
|
export function releaseCapture() {
|
||||||
if (document.releaseCapture) {
|
if (document.releaseCapture) {
|
||||||
|
|
||||||
document.releaseCapture();
|
document.releaseCapture();
|
||||||
|
@ -119,7 +120,7 @@ export function releaseCapture () {
|
||||||
|
|
||||||
// There might be events already queued, so we need to wait for
|
// There might be events already queued, so we need to wait for
|
||||||
// them to flush. E.g. contextmenu in Microsoft Edge
|
// them to flush. E.g. contextmenu in Microsoft Edge
|
||||||
window.setTimeout(function(expected) {
|
window.setTimeout((expected) => {
|
||||||
// Only clear it if it's the expected grab (i.e. no one
|
// Only clear it if it's the expected grab (i.e. no one
|
||||||
// else has initiated a new grab)
|
// else has initiated a new grab)
|
||||||
if (_captureIndex === expected) {
|
if (_captureIndex === expected) {
|
||||||
|
@ -129,10 +130,10 @@ export function releaseCapture () {
|
||||||
|
|
||||||
_captureObserver.disconnect();
|
_captureObserver.disconnect();
|
||||||
|
|
||||||
var captureElem = document.getElementById("noVNC_mouse_capture_elem");
|
const captureElem = document.getElementById("noVNC_mouse_capture_elem");
|
||||||
captureElem.style.display = "none";
|
captureElem.style.display = "none";
|
||||||
|
|
||||||
window.removeEventListener('mousemove', _captureProxy);
|
window.removeEventListener('mousemove', _captureProxy);
|
||||||
window.removeEventListener('mouseup', _captureProxy);
|
window.removeEventListener('mouseup', _captureProxy);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,40 +1,35 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright 2017 Pierre Ossman for Cendio AB
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
*
|
*
|
||||||
* See README.md for usage and integration instructions.
|
* See README.md for usage and integration instructions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var EventTargetMixin = {
|
export default class EventTargetMixin {
|
||||||
_listeners: null,
|
constructor() {
|
||||||
|
|
||||||
addEventListener: function(type, callback) {
|
|
||||||
if (!this._listeners) {
|
|
||||||
this._listeners = new Map();
|
this._listeners = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addEventListener(type, callback) {
|
||||||
if (!this._listeners.has(type)) {
|
if (!this._listeners.has(type)) {
|
||||||
this._listeners.set(type, new Set());
|
this._listeners.set(type, new Set());
|
||||||
}
|
}
|
||||||
this._listeners.get(type).add(callback);
|
this._listeners.get(type).add(callback);
|
||||||
},
|
|
||||||
|
|
||||||
removeEventListener: function(type, callback) {
|
|
||||||
if (!this._listeners || !this._listeners.has(type)) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
this._listeners.get(type).delete(callback);
|
|
||||||
},
|
|
||||||
|
|
||||||
dispatchEvent: function(event) {
|
removeEventListener(type, callback) {
|
||||||
if (!this._listeners || !this._listeners.has(event.type)) {
|
if (this._listeners.has(type)) {
|
||||||
|
this._listeners.get(type).delete(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchEvent(event) {
|
||||||
|
if (!this._listeners.has(event.type)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
this._listeners.get(event.type).forEach(function (callback) {
|
this._listeners.get(event.type)
|
||||||
callback.call(this, event);
|
.forEach(callback => callback.call(this, event));
|
||||||
}, this);
|
|
||||||
return !event.defaultPrevented;
|
return !event.defaultPrevented;
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default EventTargetMixin;
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2012 Joel Martin
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
*
|
*
|
||||||
* See README.md for usage and integration instructions.
|
* See README.md for usage and integration instructions.
|
||||||
|
@ -10,22 +10,24 @@
|
||||||
* Logging/debug routines
|
* Logging/debug routines
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var _log_level = 'warn';
|
let _log_level = 'warn';
|
||||||
|
|
||||||
var Debug = function (msg) {};
|
let Debug = () => {};
|
||||||
var Info = function (msg) {};
|
let Info = () => {};
|
||||||
var Warn = function (msg) {};
|
let Warn = () => {};
|
||||||
var Error = function (msg) {};
|
let Error = () => {};
|
||||||
|
|
||||||
export function init_logging (level) {
|
export function init_logging(level) {
|
||||||
if (typeof level === 'undefined') {
|
if (typeof level === 'undefined') {
|
||||||
level = _log_level;
|
level = _log_level;
|
||||||
} else {
|
} else {
|
||||||
_log_level = level;
|
_log_level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug = Info = Warn = Error = function (msg) {};
|
Debug = Info = Warn = Error = () => {};
|
||||||
|
|
||||||
if (typeof window.console !== "undefined") {
|
if (typeof window.console !== "undefined") {
|
||||||
|
/* eslint-disable no-console, no-fallthrough */
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case 'debug':
|
case 'debug':
|
||||||
Debug = console.debug.bind(window.console);
|
Debug = console.debug.bind(window.console);
|
||||||
|
@ -38,13 +40,16 @@ export function init_logging (level) {
|
||||||
case 'none':
|
case 'none':
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("invalid logging type '" + level + "'");
|
throw new window.Error("invalid logging type '" + level + "'");
|
||||||
}
|
}
|
||||||
|
/* eslint-enable no-console, no-fallthrough */
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
export function get_logging () {
|
|
||||||
|
export function get_logging() {
|
||||||
return _log_level;
|
return _log_level;
|
||||||
};
|
}
|
||||||
|
|
||||||
export { Debug, Info, Warn, Error };
|
export { Debug, Info, Warn, Error };
|
||||||
|
|
||||||
// Initialize logging level
|
// Initialize logging level
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright 2017 Pierre Ossman for noVNC
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -16,13 +16,13 @@ if (typeof Object.assign != 'function') {
|
||||||
throw new TypeError('Cannot convert undefined or null to object');
|
throw new TypeError('Cannot convert undefined or null to object');
|
||||||
}
|
}
|
||||||
|
|
||||||
var to = Object(target);
|
const to = Object(target);
|
||||||
|
|
||||||
for (var index = 1; index < arguments.length; index++) {
|
for (let index = 1; index < arguments.length; index++) {
|
||||||
var nextSource = arguments[index];
|
const nextSource = arguments[index];
|
||||||
|
|
||||||
if (nextSource != null) { // Skip over if undefined or null
|
if (nextSource != null) { // Skip over if undefined or null
|
||||||
for (var nextKey in nextSource) {
|
for (let nextKey in nextSource) {
|
||||||
// Avoid bugs when hasOwnProperty is shadowed
|
// Avoid bugs when hasOwnProperty is shadowed
|
||||||
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
|
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
|
||||||
to[nextKey] = nextSource[nextKey];
|
to[nextKey] = nextSource[nextKey];
|
||||||
|
@ -38,10 +38,10 @@ if (typeof Object.assign != 'function') {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CustomEvent constructor (taken from MDN) */
|
/* CustomEvent constructor (taken from MDN) */
|
||||||
(function () {
|
(() => {
|
||||||
function CustomEvent ( event, params ) {
|
function CustomEvent(event, params) {
|
||||||
params = params || { bubbles: false, cancelable: false, detail: undefined };
|
params = params || { bubbles: false, cancelable: false, detail: undefined };
|
||||||
var evt = document.createEvent( 'CustomEvent' );
|
const evt = document.createEvent( 'CustomEvent' );
|
||||||
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
|
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
|
||||||
return evt;
|
return evt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* noVNC: HTML5 VNC client
|
* noVNC: HTML5 VNC client
|
||||||
* Copyright (C) 2012 Joel Martin
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
*
|
*
|
||||||
* See README.md for usage and integration instructions.
|
* See README.md for usage and integration instructions.
|
||||||
|
@ -9,7 +9,6 @@
|
||||||
/*
|
/*
|
||||||
* Decode from UTF-8
|
* Decode from UTF-8
|
||||||
*/
|
*/
|
||||||
export function decodeUTF8 (utf8string) {
|
export function decodeUTF8(utf8string) {
|
||||||
"use strict";
|
|
||||||
return decodeURIComponent(escape(utf8string));
|
return decodeURIComponent(escape(utf8string));
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Websock: high-performance binary WebSockets
|
* Websock: high-performance binary WebSockets
|
||||||
* Copyright (C) 2012 Joel Martin
|
* Copyright (C) 2018 The noVNC Authors
|
||||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
*
|
*
|
||||||
* Websock is similar to the standard WebSocket object but with extra
|
* Websock is similar to the standard WebSocket object but with extra
|
||||||
|
@ -14,9 +14,14 @@
|
||||||
|
|
||||||
import * as Log from './util/logging.js';
|
import * as Log from './util/logging.js';
|
||||||
|
|
||||||
export default function Websock() {
|
// this has performance issues in some versions Chromium, and
|
||||||
"use strict";
|
// doesn't gain a tremendous amount of performance increase in Firefox
|
||||||
|
// at the moment. It may be valuable to turn it on in the future.
|
||||||
|
const ENABLE_COPYWITHIN = false;
|
||||||
|
const MAX_RQ_GROW_SIZE = 40 * 1024 * 1024; // 40 MiB
|
||||||
|
|
||||||
|
export default class Websock {
|
||||||
|
constructor() {
|
||||||
this._websocket = null; // WebSocket object
|
this._websocket = null; // WebSocket object
|
||||||
|
|
||||||
this._rQi = 0; // Receive queue index
|
this._rQi = 0; // Receive queue index
|
||||||
|
@ -32,125 +37,97 @@ export default function Websock() {
|
||||||
this._sQ = null; // Send queue
|
this._sQ = null; // Send queue
|
||||||
|
|
||||||
this._eventHandlers = {
|
this._eventHandlers = {
|
||||||
'message': function () {},
|
message: () => {},
|
||||||
'open': function () {},
|
open: () => {},
|
||||||
'close': function () {},
|
close: () => {},
|
||||||
'error': function () {}
|
error: () => {}
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// this has performance issues in some versions Chromium, and
|
|
||||||
// doesn't gain a tremendous amount of performance increase in Firefox
|
|
||||||
// at the moment. It may be valuable to turn it on in the future.
|
|
||||||
var ENABLE_COPYWITHIN = false;
|
|
||||||
|
|
||||||
var MAX_RQ_GROW_SIZE = 40 * 1024 * 1024; // 40 MiB
|
|
||||||
|
|
||||||
var typedArrayToString = (function () {
|
|
||||||
// This is only for PhantomJS, which doesn't like apply-ing
|
|
||||||
// with Typed Arrays
|
|
||||||
try {
|
|
||||||
var arr = new Uint8Array([1, 2, 3]);
|
|
||||||
String.fromCharCode.apply(null, arr);
|
|
||||||
return function (a) { return String.fromCharCode.apply(null, a); };
|
|
||||||
} catch (ex) {
|
|
||||||
return function (a) {
|
|
||||||
return String.fromCharCode.apply(
|
|
||||||
null, Array.prototype.slice.call(a));
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})();
|
|
||||||
|
|
||||||
Websock.prototype = {
|
|
||||||
// Getters and Setters
|
// Getters and Setters
|
||||||
get_sQ: function () {
|
get sQ() {
|
||||||
return this._sQ;
|
return this._sQ;
|
||||||
},
|
}
|
||||||
|
|
||||||
get_rQ: function () {
|
get rQ() {
|
||||||
return this._rQ;
|
return this._rQ;
|
||||||
},
|
}
|
||||||
|
|
||||||
get_rQi: function () {
|
get rQi() {
|
||||||
return this._rQi;
|
return this._rQi;
|
||||||
},
|
}
|
||||||
|
|
||||||
set_rQi: function (val) {
|
set rQi(val) {
|
||||||
this._rQi = val;
|
this._rQi = val;
|
||||||
},
|
}
|
||||||
|
|
||||||
// Receive Queue
|
// Receive Queue
|
||||||
rQlen: function () {
|
get rQlen() {
|
||||||
return this._rQlen - this._rQi;
|
return this._rQlen - this._rQi;
|
||||||
},
|
}
|
||||||
|
|
||||||
rQpeek8: function () {
|
rQpeek8() {
|
||||||
return this._rQ[this._rQi];
|
return this._rQ[this._rQi];
|
||||||
},
|
}
|
||||||
|
|
||||||
rQshift8: function () {
|
rQskipBytes(bytes) {
|
||||||
return this._rQ[this._rQi++];
|
this._rQi += bytes;
|
||||||
},
|
}
|
||||||
|
|
||||||
rQskip8: function () {
|
rQshift8() {
|
||||||
this._rQi++;
|
return this._rQshift(1);
|
||||||
},
|
}
|
||||||
|
|
||||||
rQskipBytes: function (num) {
|
rQshift16() {
|
||||||
this._rQi += num;
|
return this._rQshift(2);
|
||||||
},
|
}
|
||||||
|
|
||||||
|
rQshift32() {
|
||||||
|
return this._rQshift(4);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(directxman12): test performance with these vs a DataView
|
// TODO(directxman12): test performance with these vs a DataView
|
||||||
rQshift16: function () {
|
_rQshift(bytes) {
|
||||||
return (this._rQ[this._rQi++] << 8) +
|
let res = 0;
|
||||||
this._rQ[this._rQi++];
|
for (let byte = bytes - 1; byte >= 0; byte--) {
|
||||||
},
|
res += this._rQ[this._rQi++] << (byte * 8);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
rQshift32: function () {
|
rQshiftStr(len) {
|
||||||
return (this._rQ[this._rQi++] << 24) +
|
if (typeof(len) === 'undefined') { len = this.rQlen; }
|
||||||
(this._rQ[this._rQi++] << 16) +
|
let str = "";
|
||||||
(this._rQ[this._rQi++] << 8) +
|
// Handle large arrays in steps to avoid long strings on the stack
|
||||||
this._rQ[this._rQi++];
|
for (let i = 0; i < len; i += 4096) {
|
||||||
},
|
let part = this.rQshiftBytes(Math.min(4096, len - i));
|
||||||
|
str += String.fromCharCode.apply(null, part);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
rQshiftStr: function (len) {
|
rQshiftBytes(len) {
|
||||||
if (typeof(len) === 'undefined') { len = this.rQlen(); }
|
if (typeof(len) === 'undefined') { len = this.rQlen; }
|
||||||
var arr = new Uint8Array(this._rQ.buffer, this._rQi, len);
|
|
||||||
this._rQi += len;
|
|
||||||
return typedArrayToString(arr);
|
|
||||||
},
|
|
||||||
|
|
||||||
rQshiftBytes: function (len) {
|
|
||||||
if (typeof(len) === 'undefined') { len = this.rQlen(); }
|
|
||||||
this._rQi += len;
|
this._rQi += len;
|
||||||
return new Uint8Array(this._rQ.buffer, this._rQi - len, len);
|
return new Uint8Array(this._rQ.buffer, this._rQi - len, len);
|
||||||
},
|
}
|
||||||
|
|
||||||
rQshiftTo: function (target, len) {
|
rQshiftTo(target, len) {
|
||||||
if (len === undefined) { len = this.rQlen(); }
|
if (len === undefined) { len = this.rQlen; }
|
||||||
// TODO: make this just use set with views when using a ArrayBuffer to store the rQ
|
// TODO: make this just use set with views when using a ArrayBuffer to store the rQ
|
||||||
target.set(new Uint8Array(this._rQ.buffer, this._rQi, len));
|
target.set(new Uint8Array(this._rQ.buffer, this._rQi, len));
|
||||||
this._rQi += len;
|
this._rQi += len;
|
||||||
},
|
|
||||||
|
|
||||||
rQwhole: function () {
|
|
||||||
return new Uint8Array(this._rQ.buffer, 0, this._rQlen);
|
|
||||||
},
|
|
||||||
|
|
||||||
rQslice: function (start, end) {
|
|
||||||
if (end) {
|
|
||||||
return new Uint8Array(this._rQ.buffer, this._rQi + start, end - start);
|
|
||||||
} else {
|
|
||||||
return new Uint8Array(this._rQ.buffer, this._rQi + start, this._rQlen - this._rQi - start);
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
rQslice(start, end = this.rQlen) {
|
||||||
|
return new Uint8Array(this._rQ.buffer, this._rQi + start, end - start);
|
||||||
|
}
|
||||||
|
|
||||||
// Check to see if we must wait for 'num' bytes (default to FBU.bytes)
|
// Check to see if we must wait for 'num' bytes (default to FBU.bytes)
|
||||||
// to be available in the receive queue. Return true if we need to
|
// to be available in the receive queue. Return true if we need to
|
||||||
// wait (and possibly print a debug message), otherwise false.
|
// wait (and possibly print a debug message), otherwise false.
|
||||||
rQwait: function (msg, num, goback) {
|
rQwait(msg, num, goback) {
|
||||||
var rQlen = this._rQlen - this._rQi; // Skip rQlen() function call
|
if (this.rQlen < num) {
|
||||||
if (rQlen < num) {
|
|
||||||
if (goback) {
|
if (goback) {
|
||||||
if (this._rQi < goback) {
|
if (this._rQi < goback) {
|
||||||
throw new Error("rQwait cannot backup " + goback + " bytes");
|
throw new Error("rQwait cannot backup " + goback + " bytes");
|
||||||
|
@ -160,58 +137,55 @@ Websock.prototype = {
|
||||||
return true; // true means need more data
|
return true; // true means need more data
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
|
|
||||||
// Send Queue
|
// Send Queue
|
||||||
|
|
||||||
flush: function () {
|
flush() {
|
||||||
if (this._sQlen > 0 && this._websocket.readyState === WebSocket.OPEN) {
|
if (this._sQlen > 0 && this._websocket.readyState === WebSocket.OPEN) {
|
||||||
this._websocket.send(this._encode_message());
|
this._websocket.send(this._encode_message());
|
||||||
this._sQlen = 0;
|
this._sQlen = 0;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
send: function (arr) {
|
send(arr) {
|
||||||
this._sQ.set(arr, this._sQlen);
|
this._sQ.set(arr, this._sQlen);
|
||||||
this._sQlen += arr.length;
|
this._sQlen += arr.length;
|
||||||
this.flush();
|
this.flush();
|
||||||
},
|
}
|
||||||
|
|
||||||
send_string: function (str) {
|
send_string(str) {
|
||||||
this.send(str.split('').map(function (chr) {
|
this.send(str.split('').map(chr => chr.charCodeAt(0)));
|
||||||
return chr.charCodeAt(0);
|
}
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
// Event Handlers
|
// Event Handlers
|
||||||
off: function (evt) {
|
off(evt) {
|
||||||
this._eventHandlers[evt] = function () {};
|
this._eventHandlers[evt] = () => {};
|
||||||
},
|
}
|
||||||
|
|
||||||
on: function (evt, handler) {
|
on(evt, handler) {
|
||||||
this._eventHandlers[evt] = handler;
|
this._eventHandlers[evt] = handler;
|
||||||
},
|
}
|
||||||
|
|
||||||
_allocate_buffers: function () {
|
_allocate_buffers() {
|
||||||
this._rQ = new Uint8Array(this._rQbufferSize);
|
this._rQ = new Uint8Array(this._rQbufferSize);
|
||||||
this._sQ = new Uint8Array(this._sQbufferSize);
|
this._sQ = new Uint8Array(this._sQbufferSize);
|
||||||
},
|
}
|
||||||
|
|
||||||
init: function () {
|
init() {
|
||||||
this._allocate_buffers();
|
this._allocate_buffers();
|
||||||
this._rQi = 0;
|
this._rQi = 0;
|
||||||
this._websocket = null;
|
this._websocket = null;
|
||||||
},
|
}
|
||||||
|
|
||||||
open: function (uri, protocols) {
|
open(uri, protocols) {
|
||||||
var ws_schema = uri.match(/^([a-z]+):\/\//)[1];
|
|
||||||
this.init();
|
this.init();
|
||||||
|
|
||||||
this._websocket = new WebSocket(uri, protocols);
|
this._websocket = new WebSocket(uri, protocols);
|
||||||
this._websocket.binaryType = 'arraybuffer';
|
this._websocket.binaryType = 'arraybuffer';
|
||||||
|
|
||||||
this._websocket.onmessage = this._recv_message.bind(this);
|
this._websocket.onmessage = this._recv_message.bind(this);
|
||||||
this._websocket.onopen = (function () {
|
this._websocket.onopen = () => {
|
||||||
Log.Debug('>> WebSock.onopen');
|
Log.Debug('>> WebSock.onopen');
|
||||||
if (this._websocket.protocol) {
|
if (this._websocket.protocol) {
|
||||||
Log.Info("Server choose sub-protocol: " + this._websocket.protocol);
|
Log.Info("Server choose sub-protocol: " + this._websocket.protocol);
|
||||||
|
@ -219,20 +193,20 @@ Websock.prototype = {
|
||||||
|
|
||||||
this._eventHandlers.open();
|
this._eventHandlers.open();
|
||||||
Log.Debug("<< WebSock.onopen");
|
Log.Debug("<< WebSock.onopen");
|
||||||
}).bind(this);
|
};
|
||||||
this._websocket.onclose = (function (e) {
|
this._websocket.onclose = (e) => {
|
||||||
Log.Debug(">> WebSock.onclose");
|
Log.Debug(">> WebSock.onclose");
|
||||||
this._eventHandlers.close(e);
|
this._eventHandlers.close(e);
|
||||||
Log.Debug("<< WebSock.onclose");
|
Log.Debug("<< WebSock.onclose");
|
||||||
}).bind(this);
|
};
|
||||||
this._websocket.onerror = (function (e) {
|
this._websocket.onerror = (e) => {
|
||||||
Log.Debug(">> WebSock.onerror: " + e);
|
Log.Debug(">> WebSock.onerror: " + e);
|
||||||
this._eventHandlers.error(e);
|
this._eventHandlers.error(e);
|
||||||
Log.Debug("<< WebSock.onerror: " + e);
|
Log.Debug("<< WebSock.onerror: " + e);
|
||||||
}).bind(this);
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
close: function () {
|
close() {
|
||||||
if (this._websocket) {
|
if (this._websocket) {
|
||||||
if ((this._websocket.readyState === WebSocket.OPEN) ||
|
if ((this._websocket.readyState === WebSocket.OPEN) ||
|
||||||
(this._websocket.readyState === WebSocket.CONNECTING)) {
|
(this._websocket.readyState === WebSocket.CONNECTING)) {
|
||||||
|
@ -240,39 +214,39 @@ Websock.prototype = {
|
||||||
this._websocket.close();
|
this._websocket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._websocket.onmessage = function (e) { return; };
|
this._websocket.onmessage = () => {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
// private methods
|
// private methods
|
||||||
_encode_message: function () {
|
_encode_message() {
|
||||||
// Put in a binary arraybuffer
|
// Put in a binary arraybuffer
|
||||||
// according to the spec, you can send ArrayBufferViews with the send method
|
// according to the spec, you can send ArrayBufferViews with the send method
|
||||||
return new Uint8Array(this._sQ.buffer, 0, this._sQlen);
|
return new Uint8Array(this._sQ.buffer, 0, this._sQlen);
|
||||||
},
|
}
|
||||||
|
|
||||||
_expand_compact_rQ: function (min_fit) {
|
_expand_compact_rQ(min_fit) {
|
||||||
var resizeNeeded = min_fit || this._rQlen - this._rQi > this._rQbufferSize / 2;
|
const resizeNeeded = min_fit || this.rQlen > this._rQbufferSize / 2;
|
||||||
if (resizeNeeded) {
|
if (resizeNeeded) {
|
||||||
if (!min_fit) {
|
if (!min_fit) {
|
||||||
// just double the size if we need to do compaction
|
// just double the size if we need to do compaction
|
||||||
this._rQbufferSize *= 2;
|
this._rQbufferSize *= 2;
|
||||||
} else {
|
} else {
|
||||||
// otherwise, make sure we satisy rQlen - rQi + min_fit < rQbufferSize / 8
|
// otherwise, make sure we satisy rQlen - rQi + min_fit < rQbufferSize / 8
|
||||||
this._rQbufferSize = (this._rQlen - this._rQi + min_fit) * 8;
|
this._rQbufferSize = (this.rQlen + min_fit) * 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we don't want to grow unboundedly
|
// we don't want to grow unboundedly
|
||||||
if (this._rQbufferSize > MAX_RQ_GROW_SIZE) {
|
if (this._rQbufferSize > MAX_RQ_GROW_SIZE) {
|
||||||
this._rQbufferSize = MAX_RQ_GROW_SIZE;
|
this._rQbufferSize = MAX_RQ_GROW_SIZE;
|
||||||
if (this._rQbufferSize - this._rQlen - this._rQi < min_fit) {
|
if (this._rQbufferSize - this.rQlen < min_fit) {
|
||||||
throw new Exception("Receive Queue buffer exceeded " + MAX_RQ_GROW_SIZE + " bytes, and the new message could not fit");
|
throw new Error("Receive Queue buffer exceeded " + MAX_RQ_GROW_SIZE + " bytes, and the new message could not fit");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resizeNeeded) {
|
if (resizeNeeded) {
|
||||||
var old_rQbuffer = this._rQ.buffer;
|
const old_rQbuffer = this._rQ.buffer;
|
||||||
this._rQmax = this._rQbufferSize / 8;
|
this._rQmax = this._rQbufferSize / 8;
|
||||||
this._rQ = new Uint8Array(this._rQbufferSize);
|
this._rQ = new Uint8Array(this._rQbufferSize);
|
||||||
this._rQ.set(new Uint8Array(old_rQbuffer, this._rQi));
|
this._rQ.set(new Uint8Array(old_rQbuffer, this._rQi));
|
||||||
|
@ -286,21 +260,21 @@ Websock.prototype = {
|
||||||
|
|
||||||
this._rQlen = this._rQlen - this._rQi;
|
this._rQlen = this._rQlen - this._rQi;
|
||||||
this._rQi = 0;
|
this._rQi = 0;
|
||||||
},
|
}
|
||||||
|
|
||||||
_decode_message: function (data) {
|
_decode_message(data) {
|
||||||
// push arraybuffer values onto the end
|
// push arraybuffer values onto the end
|
||||||
var u8 = new Uint8Array(data);
|
const u8 = new Uint8Array(data);
|
||||||
if (u8.length > this._rQbufferSize - this._rQlen) {
|
if (u8.length > this._rQbufferSize - this._rQlen) {
|
||||||
this._expand_compact_rQ(u8.length);
|
this._expand_compact_rQ(u8.length);
|
||||||
}
|
}
|
||||||
this._rQ.set(u8, this._rQlen);
|
this._rQ.set(u8, this._rQlen);
|
||||||
this._rQlen += u8.length;
|
this._rQlen += u8.length;
|
||||||
},
|
}
|
||||||
|
|
||||||
_recv_message: function (e) {
|
_recv_message(e) {
|
||||||
this._decode_message(e.data);
|
this._decode_message(e.data);
|
||||||
if (this.rQlen() > 0) {
|
if (this.rQlen > 0) {
|
||||||
this._eventHandlers.message();
|
this._eventHandlers.message();
|
||||||
// Compact the receive queue
|
// Compact the receive queue
|
||||||
if (this._rQlen == this._rQi) {
|
if (this._rQlen == this._rQi) {
|
||||||
|
@ -313,4 +287,4 @@ Websock.prototype = {
|
||||||
Log.Debug("Ignoring empty message");
|
Log.Debug("Ignoring empty message");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -20,6 +20,8 @@ function createSymbol (name) {
|
||||||
return hasSymbol ? Symbol() : '@@' + name;
|
return hasSymbol ? Symbol() : '@@' + name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var toStringTag = hasSymbol && Symbol.toStringTag;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,7 +95,7 @@ function LoaderError__Check_error_message_for_loader_stack (childErr, newMessage
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
var resolvedPromise = Promise.resolve();
|
var resolvedPromise$1 = Promise.resolve();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Simple Array values shim
|
* Simple Array values shim
|
||||||
|
@ -140,7 +142,9 @@ function Loader () {
|
||||||
Loader.prototype.constructor = Loader;
|
Loader.prototype.constructor = Loader;
|
||||||
|
|
||||||
function ensureInstantiated (module) {
|
function ensureInstantiated (module) {
|
||||||
if (!(module instanceof ModuleNamespace))
|
if (module === undefined)
|
||||||
|
return;
|
||||||
|
if (module instanceof ModuleNamespace === false && module[toStringTag] !== 'module')
|
||||||
throw new TypeError('Module instantiation did not return a valid namespace object.');
|
throw new TypeError('Module instantiation did not return a valid namespace object.');
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
@ -151,7 +155,7 @@ Loader.prototype.import = function (key, parent) {
|
||||||
throw new TypeError('Loader import method must be passed a module key string');
|
throw new TypeError('Loader import method must be passed a module key string');
|
||||||
// custom resolveInstantiate combined hook for better perf
|
// custom resolveInstantiate combined hook for better perf
|
||||||
var loader = this;
|
var loader = this;
|
||||||
return resolvedPromise
|
return resolvedPromise$1
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return loader[RESOLVE_INSTANTIATE](key, parent);
|
return loader[RESOLVE_INSTANTIATE](key, parent);
|
||||||
})
|
})
|
||||||
|
@ -193,7 +197,7 @@ function ensureResolution (resolvedKey) {
|
||||||
|
|
||||||
Loader.prototype.resolve = function (key, parent) {
|
Loader.prototype.resolve = function (key, parent) {
|
||||||
var loader = this;
|
var loader = this;
|
||||||
return resolvedPromise
|
return resolvedPromise$1
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return loader[RESOLVE](key, parent);
|
return loader[RESOLVE](key, parent);
|
||||||
})
|
})
|
||||||
|
@ -261,7 +265,7 @@ Registry.prototype.get = function (key) {
|
||||||
};
|
};
|
||||||
// 4.4.7
|
// 4.4.7
|
||||||
Registry.prototype.set = function (key, namespace) {
|
Registry.prototype.set = function (key, namespace) {
|
||||||
if (!(namespace instanceof ModuleNamespace))
|
if (!(namespace instanceof ModuleNamespace || namespace[toStringTag] === 'module'))
|
||||||
throw new Error('Registry must be set with an instance of Module Namespace');
|
throw new Error('Registry must be set with an instance of Module Namespace');
|
||||||
this[REGISTRY][key] = namespace;
|
this[REGISTRY][key] = namespace;
|
||||||
return this;
|
return this;
|
||||||
|
@ -318,8 +322,8 @@ function ModuleNamespace (baseObject/*, evaluate*/) {
|
||||||
// 8.4.2
|
// 8.4.2
|
||||||
ModuleNamespace.prototype = Object.create(null);
|
ModuleNamespace.prototype = Object.create(null);
|
||||||
|
|
||||||
if (typeof Symbol !== 'undefined' && Symbol.toStringTag)
|
if (toStringTag)
|
||||||
Object.defineProperty(ModuleNamespace.prototype, Symbol.toStringTag, {
|
Object.defineProperty(ModuleNamespace.prototype, toStringTag, {
|
||||||
value: 'Module'
|
value: 'Module'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -366,7 +370,9 @@ Module.evaluate = function (ns) {
|
||||||
function throwResolveError (relUrl, parentUrl) {
|
function throwResolveError (relUrl, parentUrl) {
|
||||||
throw new RangeError('Unable to resolve "' + relUrl + '" to ' + parentUrl);
|
throw new RangeError('Unable to resolve "' + relUrl + '" to ' + parentUrl);
|
||||||
}
|
}
|
||||||
|
var backslashRegEx = /\\/g;
|
||||||
function resolveIfNotPlain (relUrl, parentUrl) {
|
function resolveIfNotPlain (relUrl, parentUrl) {
|
||||||
|
if (relUrl[0] === ' ' || relUrl[relUrl.length - 1] === ' ')
|
||||||
relUrl = relUrl.trim();
|
relUrl = relUrl.trim();
|
||||||
var parentProtocol = parentUrl && parentUrl.substr(0, parentUrl.indexOf(':') + 1);
|
var parentProtocol = parentUrl && parentUrl.substr(0, parentUrl.indexOf(':') + 1);
|
||||||
|
|
||||||
|
@ -377,12 +383,16 @@ function resolveIfNotPlain (relUrl, parentUrl) {
|
||||||
if (firstChar === '/' && secondChar === '/') {
|
if (firstChar === '/' && secondChar === '/') {
|
||||||
if (!parentProtocol)
|
if (!parentProtocol)
|
||||||
throwResolveError(relUrl, parentUrl);
|
throwResolveError(relUrl, parentUrl);
|
||||||
|
if (relUrl.indexOf('\\') !== -1)
|
||||||
|
relUrl = relUrl.replace(backslashRegEx, '/');
|
||||||
return parentProtocol + relUrl;
|
return parentProtocol + relUrl;
|
||||||
}
|
}
|
||||||
// relative-url
|
// relative-url
|
||||||
else if (firstChar === '.' && (secondChar === '/' || secondChar === '.' && (relUrl[2] === '/' || relUrl.length === 2 && (relUrl += '/')) ||
|
else if (firstChar === '.' && (secondChar === '/' || secondChar === '.' && (relUrl[2] === '/' || relUrl.length === 2 && (relUrl += '/')) ||
|
||||||
relUrl.length === 1 && (relUrl += '/')) ||
|
relUrl.length === 1 && (relUrl += '/')) ||
|
||||||
firstChar === '/') {
|
firstChar === '/') {
|
||||||
|
if (relUrl.indexOf('\\') !== -1)
|
||||||
|
relUrl = relUrl.replace(backslashRegEx, '/');
|
||||||
var parentIsPlain = !parentProtocol || parentUrl[parentProtocol.length] !== '/';
|
var parentIsPlain = !parentProtocol || parentUrl[parentProtocol.length] !== '/';
|
||||||
|
|
||||||
// read pathname from parent if a URL
|
// read pathname from parent if a URL
|
||||||
|
@ -475,12 +485,13 @@ function resolveIfNotPlain (relUrl, parentUrl) {
|
||||||
if (isNode) {
|
if (isNode) {
|
||||||
// C:\x becomes file:///c:/x (we don't support C|\x)
|
// C:\x becomes file:///c:/x (we don't support C|\x)
|
||||||
if (relUrl[1] === ':' && relUrl[2] === '\\' && relUrl[0].match(/[a-z]/i))
|
if (relUrl[1] === ':' && relUrl[2] === '\\' && relUrl[0].match(/[a-z]/i))
|
||||||
return 'file:///' + relUrl.replace(/\\/g, '/');
|
return 'file:///' + relUrl.replace(backslashRegEx, '/');
|
||||||
}
|
}
|
||||||
return relUrl;
|
return relUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var resolvedPromise = Promise.resolve();
|
||||||
/*
|
/*
|
||||||
* Register Loader
|
* Register Loader
|
||||||
*
|
*
|
||||||
|
@ -575,6 +586,9 @@ function createLoadRecord (state, key, registration) {
|
||||||
// will be the array of dependency load record or a module namespace
|
// will be the array of dependency load record or a module namespace
|
||||||
dependencyInstantiations: undefined,
|
dependencyInstantiations: undefined,
|
||||||
|
|
||||||
|
// top-level await!
|
||||||
|
evaluatePromise: undefined,
|
||||||
|
|
||||||
// NB optimization and way of ensuring module objects in setters
|
// NB optimization and way of ensuring module objects in setters
|
||||||
// indicates setters which should run pre-execution of that dependency
|
// indicates setters which should run pre-execution of that dependency
|
||||||
// setters is then just for completely executed module objects
|
// setters is then just for completely executed module objects
|
||||||
|
@ -592,7 +606,7 @@ RegisterLoader$1.prototype[Loader.resolveInstantiate] = function (key, parentKey
|
||||||
|
|
||||||
return resolveInstantiate(loader, key, parentKey, registry, state)
|
return resolveInstantiate(loader, key, parentKey, registry, state)
|
||||||
.then(function (instantiated) {
|
.then(function (instantiated) {
|
||||||
if (instantiated instanceof ModuleNamespace)
|
if (instantiated instanceof ModuleNamespace || instantiated[toStringTag] === 'module')
|
||||||
return instantiated;
|
return instantiated;
|
||||||
|
|
||||||
// resolveInstantiate always returns a load record with a link record and no module value
|
// resolveInstantiate always returns a load record with a link record and no module value
|
||||||
|
@ -607,7 +621,7 @@ RegisterLoader$1.prototype[Loader.resolveInstantiate] = function (key, parentKey
|
||||||
|
|
||||||
return deepInstantiateDeps(loader, instantiated, link, registry, state)
|
return deepInstantiateDeps(loader, instantiated, link, registry, state)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return ensureEvaluate(loader, instantiated, link, registry, state, undefined);
|
return ensureEvaluate(loader, instantiated, link, registry, state);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -672,14 +686,14 @@ function createProcessAnonRegister (loader, load, state) {
|
||||||
function instantiate (loader, load, link, registry, state) {
|
function instantiate (loader, load, link, registry, state) {
|
||||||
return link.instantiatePromise || (link.instantiatePromise =
|
return link.instantiatePromise || (link.instantiatePromise =
|
||||||
// if there is already an existing registration, skip running instantiate
|
// if there is already an existing registration, skip running instantiate
|
||||||
(load.registration ? Promise.resolve() : Promise.resolve().then(function () {
|
(load.registration ? resolvedPromise : resolvedPromise.then(function () {
|
||||||
state.lastRegister = undefined;
|
state.lastRegister = undefined;
|
||||||
return loader[INSTANTIATE](load.key, loader[INSTANTIATE].length > 1 && createProcessAnonRegister(loader, load, state));
|
return loader[INSTANTIATE](load.key, loader[INSTANTIATE].length > 1 && createProcessAnonRegister(loader, load, state));
|
||||||
}))
|
}))
|
||||||
.then(function (instantiation) {
|
.then(function (instantiation) {
|
||||||
// direct module return from instantiate -> we're done
|
// direct module return from instantiate -> we're done
|
||||||
if (instantiation !== undefined) {
|
if (instantiation !== undefined) {
|
||||||
if (!(instantiation instanceof ModuleNamespace))
|
if (!(instantiation instanceof ModuleNamespace || instantiation[toStringTag] === 'module'))
|
||||||
throw new TypeError('Instantiate did not return a valid Module object.');
|
throw new TypeError('Instantiate did not return a valid Module object.');
|
||||||
|
|
||||||
delete state.records[load.key];
|
delete state.records[load.key];
|
||||||
|
@ -826,7 +840,7 @@ function registerDeclarative (loader, load, link, declare) {
|
||||||
return value;
|
return value;
|
||||||
}, new ContextualLoader(loader, load.key));
|
}, new ContextualLoader(loader, load.key));
|
||||||
|
|
||||||
link.setters = declared.setters;
|
link.setters = declared.setters || [];
|
||||||
link.execute = declared.execute;
|
link.execute = declared.execute;
|
||||||
if (declared.exports) {
|
if (declared.exports) {
|
||||||
link.moduleObj = moduleObj = declared.exports;
|
link.moduleObj = moduleObj = declared.exports;
|
||||||
|
@ -854,7 +868,7 @@ function instantiateDeps (loader, load, link, registry, state) {
|
||||||
if (setter) {
|
if (setter) {
|
||||||
var instantiation = dependencyInstantiations[i];
|
var instantiation = dependencyInstantiations[i];
|
||||||
|
|
||||||
if (instantiation instanceof ModuleNamespace) {
|
if (instantiation instanceof ModuleNamespace || instantiation[toStringTag] === 'module') {
|
||||||
setter(instantiation);
|
setter(instantiation);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -890,37 +904,30 @@ function instantiateDeps (loader, load, link, registry, state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function deepInstantiateDeps (loader, load, link, registry, state) {
|
function deepInstantiateDeps (loader, load, link, registry, state) {
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
var seen = [];
|
var seen = [];
|
||||||
var loadCnt = 0;
|
function addDeps (load, link) {
|
||||||
function queueLoad (load) {
|
|
||||||
var link = load.linkRecord;
|
|
||||||
if (!link)
|
if (!link)
|
||||||
return;
|
return resolvedPromise;
|
||||||
|
|
||||||
if (seen.indexOf(load) !== -1)
|
if (seen.indexOf(load) !== -1)
|
||||||
return;
|
return resolvedPromise;
|
||||||
seen.push(load);
|
seen.push(load);
|
||||||
|
|
||||||
loadCnt++;
|
return instantiateDeps(loader, load, link, registry, state)
|
||||||
instantiateDeps(loader, load, link, registry, state)
|
.then(function () {
|
||||||
.then(processLoad, reject);
|
var depPromises;
|
||||||
}
|
|
||||||
function processLoad (load) {
|
|
||||||
loadCnt--;
|
|
||||||
var link = load.linkRecord;
|
|
||||||
if (link) {
|
|
||||||
for (var i = 0; i < link.dependencies.length; i++) {
|
for (var i = 0; i < link.dependencies.length; i++) {
|
||||||
var depLoad = link.dependencyInstantiations[i];
|
var depLoad = link.dependencyInstantiations[i];
|
||||||
if (!(depLoad instanceof ModuleNamespace))
|
if (!(depLoad instanceof ModuleNamespace || depLoad[toStringTag] === 'module')) {
|
||||||
queueLoad(depLoad);
|
depPromises = depPromises || [];
|
||||||
|
depPromises.push(addDeps(depLoad, depLoad.linkRecord));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (loadCnt === 0)
|
if (depPromises)
|
||||||
resolve();
|
return Promise.all(depPromises);
|
||||||
}
|
|
||||||
queueLoad(load);
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return addDeps(load, link);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -981,23 +988,22 @@ ContextualLoader.prototype.import = function (key) {
|
||||||
return this.loader.resolve(key, this.key);
|
return this.loader.resolve(key, this.key);
|
||||||
};*/
|
};*/
|
||||||
|
|
||||||
// this is the execution function bound to the Module namespace record
|
function ensureEvaluate (loader, load, link, registry, state) {
|
||||||
function ensureEvaluate (loader, load, link, registry, state, seen) {
|
|
||||||
if (load.module)
|
if (load.module)
|
||||||
return load.module;
|
return load.module;
|
||||||
|
|
||||||
if (load.evalError)
|
if (load.evalError)
|
||||||
throw load.evalError;
|
throw load.evalError;
|
||||||
|
if (link.evaluatePromise)
|
||||||
|
return link.evaluatePromise;
|
||||||
|
|
||||||
if (seen && seen.indexOf(load) !== -1)
|
if (link.setters) {
|
||||||
return load.linkRecord.moduleObj;
|
var evaluatePromise = doEvaluateDeclarative(loader, load, link, registry, state, [load]);
|
||||||
|
if (evaluatePromise)
|
||||||
// for ES loads we always run ensureEvaluate on top-level, so empty seen is passed regardless
|
return evaluatePromise;
|
||||||
// for dynamic loads, we pass seen if also dynamic
|
}
|
||||||
var err = doEvaluate(loader, load, link, registry, state, link.setters ? [] : seen || []);
|
else {
|
||||||
if (err)
|
doEvaluateDynamic(loader, load, link, registry, state, [load]);
|
||||||
throw err;
|
}
|
||||||
|
|
||||||
return load.module;
|
return load.module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1009,10 +1015,23 @@ function makeDynamicRequire (loader, key, dependencies, dependencyInstantiations
|
||||||
var depLoad = dependencyInstantiations[i];
|
var depLoad = dependencyInstantiations[i];
|
||||||
var module;
|
var module;
|
||||||
|
|
||||||
if (depLoad instanceof ModuleNamespace)
|
if (depLoad instanceof ModuleNamespace || depLoad[toStringTag] === 'module') {
|
||||||
module = depLoad;
|
module = depLoad;
|
||||||
else
|
}
|
||||||
module = ensureEvaluate(loader, depLoad, depLoad.linkRecord, registry, state, seen);
|
else {
|
||||||
|
if (depLoad.evalError)
|
||||||
|
throw depLoad.evalError;
|
||||||
|
if (depLoad.module === undefined && seen.indexOf(depLoad) === -1 && !depLoad.linkRecord.evaluatePromise) {
|
||||||
|
if (depLoad.linkRecord.setters) {
|
||||||
|
doEvaluateDeclarative(loader, depLoad, depLoad.linkRecord, registry, state, [depLoad]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
seen.push(depLoad);
|
||||||
|
doEvaluateDynamic(loader, depLoad, depLoad.linkRecord, registry, state, seen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module = depLoad.module || depLoad.linkRecord.moduleObj;
|
||||||
|
}
|
||||||
|
|
||||||
return '__useDefault' in module ? module.__useDefault : module;
|
return '__useDefault' in module ? module.__useDefault : module;
|
||||||
}
|
}
|
||||||
|
@ -1021,52 +1040,113 @@ function makeDynamicRequire (loader, key, dependencies, dependencyInstantiations
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensures the given es load is evaluated
|
function evalError (load, err) {
|
||||||
|
load.linkRecord = undefined;
|
||||||
|
var evalError = LoaderError__Check_error_message_for_loader_stack(err, 'Evaluating ' + load.key);
|
||||||
|
if (load.evalError === undefined)
|
||||||
|
load.evalError = evalError;
|
||||||
|
throw evalError;
|
||||||
|
}
|
||||||
|
|
||||||
|
// es modules evaluate dependencies first
|
||||||
// returns the error if any
|
// returns the error if any
|
||||||
function doEvaluate (loader, load, link, registry, state, seen) {
|
function doEvaluateDeclarative (loader, load, link, registry, state, seen) {
|
||||||
seen.push(load);
|
|
||||||
|
|
||||||
var err;
|
|
||||||
|
|
||||||
// es modules evaluate dependencies first
|
|
||||||
// non es modules explicitly call moduleEvaluate through require
|
|
||||||
if (link.setters) {
|
|
||||||
var depLoad, depLink;
|
var depLoad, depLink;
|
||||||
|
var depLoadPromises;
|
||||||
for (var i = 0; i < link.dependencies.length; i++) {
|
for (var i = 0; i < link.dependencies.length; i++) {
|
||||||
depLoad = link.dependencyInstantiations[i];
|
var depLoad = link.dependencyInstantiations[i];
|
||||||
|
if (depLoad instanceof ModuleNamespace || depLoad[toStringTag] === 'module')
|
||||||
if (depLoad instanceof ModuleNamespace)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// custom Module returned from instantiate
|
// custom Module returned from instantiate
|
||||||
depLink = depLoad.linkRecord;
|
depLink = depLoad.linkRecord;
|
||||||
if (depLink && seen.indexOf(depLoad) === -1) {
|
if (depLink) {
|
||||||
if (depLoad.evalError)
|
if (depLoad.evalError) {
|
||||||
err = depLoad.evalError;
|
evalError(load, depLoad.evalError);
|
||||||
else
|
}
|
||||||
// dynamic / declarative boundaries clear the "seen" list
|
else if (depLink.setters) {
|
||||||
// we just let cross format circular throw as would happen in real implementations
|
if (seen.indexOf(depLoad) === -1) {
|
||||||
err = doEvaluate(loader, depLoad, depLink, registry, state, depLink.setters ? seen : []);
|
seen.push(depLoad);
|
||||||
|
try {
|
||||||
|
var depLoadPromise = doEvaluateDeclarative(loader, depLoad, depLink, registry, state, seen);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
evalError(load, e);
|
||||||
|
}
|
||||||
|
if (depLoadPromise) {
|
||||||
|
depLoadPromises = depLoadPromises || [];
|
||||||
|
depLoadPromises.push(depLoadPromise.catch(function (err) {
|
||||||
|
evalError(load, err);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
doEvaluateDynamic(loader, depLoad, depLink, registry, state, [depLoad]);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
evalError(load, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
|
||||||
load.linkRecord = undefined;
|
|
||||||
load.evalError = LoaderError__Check_error_message_for_loader_stack(err, 'Evaluating ' + load.key);
|
|
||||||
return load.evalError;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// link.execute won't exist for Module returns from instantiate on top-level load
|
if (depLoadPromises)
|
||||||
|
return link.evaluatePromise = Promise.all(depLoadPromises)
|
||||||
|
.then(function () {
|
||||||
if (link.execute) {
|
if (link.execute) {
|
||||||
// ES System.register execute
|
// ES System.register execute
|
||||||
// "this" is null in ES
|
// "this" is null in ES
|
||||||
if (link.setters) {
|
try {
|
||||||
err = declarativeExecute(link.execute);
|
var execPromise = link.execute.call(nullContext);
|
||||||
}
|
}
|
||||||
|
catch (e) {
|
||||||
|
evalError(load, e);
|
||||||
|
}
|
||||||
|
if (execPromise)
|
||||||
|
return execPromise.catch(function (e) {
|
||||||
|
evalError(load, e);
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
load.linkRecord = undefined;
|
||||||
|
return registry[load.key] = load.module = new ModuleNamespace(link.moduleObj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// dispose link record
|
||||||
|
load.linkRecord = undefined;
|
||||||
|
registry[load.key] = load.module = new ModuleNamespace(link.moduleObj);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (link.execute) {
|
||||||
|
// ES System.register execute
|
||||||
|
// "this" is null in ES
|
||||||
|
try {
|
||||||
|
var execPromise = link.execute.call(nullContext);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
evalError(load, e);
|
||||||
|
}
|
||||||
|
if (execPromise)
|
||||||
|
return link.evaluatePromise = execPromise.catch(function (e) {
|
||||||
|
evalError(load, e);
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
load.linkRecord = undefined;
|
||||||
|
return registry[load.key] = load.module = new ModuleNamespace(link.moduleObj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// dispose link record
|
||||||
|
load.linkRecord = undefined;
|
||||||
|
registry[load.key] = load.module = new ModuleNamespace(link.moduleObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// non es modules explicitly call moduleEvaluate through require
|
||||||
|
function doEvaluateDynamic (loader, load, link, registry, state, seen) {
|
||||||
// System.registerDynamic execute
|
// System.registerDynamic execute
|
||||||
// "this" is "exports" in CJS
|
// "this" is "exports" in CJS
|
||||||
else {
|
|
||||||
var module = { id: load.key };
|
var module = { id: load.key };
|
||||||
var moduleObj = link.moduleObj;
|
var moduleObj = link.moduleObj;
|
||||||
Object.defineProperty(module, 'exports', {
|
Object.defineProperty(module, 'exports', {
|
||||||
|
@ -1086,7 +1166,16 @@ function doEvaluate (loader, load, link, registry, state, seen) {
|
||||||
for (var i = 0; i < link.dependencies.length; i++)
|
for (var i = 0; i < link.dependencies.length; i++)
|
||||||
require(link.dependencies[i]);
|
require(link.dependencies[i]);
|
||||||
|
|
||||||
err = dynamicExecute(link.execute, require, moduleObj.default, module);
|
try {
|
||||||
|
var output = link.execute.call(envGlobal, require, moduleObj.default, module);
|
||||||
|
if (output !== undefined)
|
||||||
|
module.exports = output;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
evalError(load, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
load.linkRecord = undefined;
|
||||||
|
|
||||||
// pick up defineProperty calls to module.exports when we can
|
// pick up defineProperty calls to module.exports when we can
|
||||||
if (module.exports !== moduleObj.__useDefault)
|
if (module.exports !== moduleObj.__useDefault)
|
||||||
|
@ -1101,53 +1190,23 @@ function doEvaluate (loader, load, link, registry, state, seen) {
|
||||||
moduleObj[p] = moduleDefault[p];
|
moduleObj[p] = moduleDefault[p];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// dispose link record
|
|
||||||
load.linkRecord = undefined;
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
return load.evalError = LoaderError__Check_error_message_for_loader_stack(err, 'Evaluating ' + load.key);
|
|
||||||
|
|
||||||
registry[load.key] = load.module = new ModuleNamespace(link.moduleObj);
|
registry[load.key] = load.module = new ModuleNamespace(link.moduleObj);
|
||||||
|
|
||||||
// if not an esm module, run importer setters and clear them
|
// run importer setters and clear them
|
||||||
// this allows dynamic modules to update themselves into es modules
|
// this allows dynamic modules to update themselves into es modules
|
||||||
// as soon as execution has completed
|
// as soon as execution has completed
|
||||||
if (!link.setters) {
|
|
||||||
if (load.importerSetters)
|
if (load.importerSetters)
|
||||||
for (var i = 0; i < load.importerSetters.length; i++)
|
for (var i = 0; i < load.importerSetters.length; i++)
|
||||||
load.importerSetters[i](load.module);
|
load.importerSetters[i](load.module);
|
||||||
load.importerSetters = undefined;
|
load.importerSetters = undefined;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// {} is the closest we can get to call(undefined)
|
// the closest we can get to call(undefined)
|
||||||
var nullContext = {};
|
var nullContext = Object.create(null);
|
||||||
if (Object.freeze)
|
if (Object.freeze)
|
||||||
Object.freeze(nullContext);
|
Object.freeze(nullContext);
|
||||||
|
|
||||||
function declarativeExecute (execute) {
|
|
||||||
try {
|
|
||||||
execute.call(nullContext);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dynamicExecute (execute, require, exports, module) {
|
|
||||||
try {
|
|
||||||
var output = execute.call(envGlobal, require, exports, module);
|
|
||||||
if (output !== undefined)
|
|
||||||
module.exports = output;
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var loader;
|
var loader;
|
||||||
|
|
||||||
// <script type="module"> support
|
// <script type="module"> support
|
||||||
|
@ -1210,7 +1269,7 @@ if (typeof document != 'undefined' && document.getElementsByTagName) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// simple DOM ready
|
// simple DOM ready
|
||||||
if (document.readyState === 'complete')
|
if (document.readyState !== 'loading')
|
||||||
setTimeout(ready);
|
setTimeout(ready);
|
||||||
else
|
else
|
||||||
document.addEventListener('DOMContentLoaded', ready, false);
|
document.addEventListener('DOMContentLoaded', ready, false);
|
||||||
|
@ -1284,9 +1343,16 @@ var WorkerPool = function (script, size) {
|
||||||
var current = document.currentScript;
|
var current = document.currentScript;
|
||||||
// IE doesn't support currentScript
|
// IE doesn't support currentScript
|
||||||
if (!current) {
|
if (!current) {
|
||||||
// We should be the last loaded script
|
// Find an entry with out basename
|
||||||
var scripts = document.getElementsByTagName('script');
|
var scripts = document.getElementsByTagName('script');
|
||||||
current = scripts[scripts.length - 1];
|
for (var i = 0; i < scripts.length; i++) {
|
||||||
|
if (scripts[i].src.indexOf("browser-es-module-loader.js") !== -1) {
|
||||||
|
current = scripts[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!current)
|
||||||
|
throw Error("Could not find own <script> element");
|
||||||
}
|
}
|
||||||
script = current.src.substr(0, current.src.lastIndexOf("/")) + "/" + script;
|
script = current.src.substr(0, current.src.lastIndexOf("/")) + "/" + script;
|
||||||
this._workers = new Array(size);
|
this._workers = new Array(size);
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -6,6 +6,7 @@ import babelTransformES2015ModulesSystemJS from 'babel-plugin-transform-es2015-m
|
||||||
var babelTransform = require('babel-core').transform;
|
var babelTransform = require('babel-core').transform;
|
||||||
var babelTransformDynamicImport = require('babel-plugin-syntax-dynamic-import');
|
var babelTransformDynamicImport = require('babel-plugin-syntax-dynamic-import');
|
||||||
var babelTransformES2015ModulesSystemJS = require('babel-plugin-transform-es2015-modules-systemjs');
|
var babelTransformES2015ModulesSystemJS = require('babel-plugin-transform-es2015-modules-systemjs');
|
||||||
|
var babelPresetES2015 = require('babel-preset-es2015');
|
||||||
|
|
||||||
self.onmessage = function (evt) {
|
self.onmessage = function (evt) {
|
||||||
// transform source with Babel
|
// transform source with Babel
|
||||||
|
@ -17,6 +18,7 @@ self.onmessage = function (evt) {
|
||||||
sourceMaps: 'inline',
|
sourceMaps: 'inline',
|
||||||
babelrc: false,
|
babelrc: false,
|
||||||
plugins: [babelTransformDynamicImport, babelTransformES2015ModulesSystemJS],
|
plugins: [babelTransformDynamicImport, babelTransformES2015ModulesSystemJS],
|
||||||
|
presets: [babelPresetES2015],
|
||||||
});
|
});
|
||||||
|
|
||||||
self.postMessage({key: evt.data.key, code: output.code, source: evt.data.source});
|
self.postMessage({key: evt.data.key, code: output.code, source: evt.data.source});
|
||||||
|
|
|
@ -66,7 +66,7 @@ if (typeof document != 'undefined' && document.getElementsByTagName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// simple DOM ready
|
// simple DOM ready
|
||||||
if (document.readyState === 'complete')
|
if (document.readyState !== 'loading')
|
||||||
setTimeout(ready);
|
setTimeout(ready);
|
||||||
else
|
else
|
||||||
document.addEventListener('DOMContentLoaded', ready, false);
|
document.addEventListener('DOMContentLoaded', ready, false);
|
||||||
|
@ -140,9 +140,16 @@ var WorkerPool = function (script, size) {
|
||||||
var current = document.currentScript;
|
var current = document.currentScript;
|
||||||
// IE doesn't support currentScript
|
// IE doesn't support currentScript
|
||||||
if (!current) {
|
if (!current) {
|
||||||
// We should be the last loaded script
|
// Find an entry with out basename
|
||||||
var scripts = document.getElementsByTagName('script');
|
var scripts = document.getElementsByTagName('script');
|
||||||
current = scripts[scripts.length - 1];
|
for (var i = 0; i < scripts.length; i++) {
|
||||||
|
if (scripts[i].src.indexOf("browser-es-module-loader.js") !== -1) {
|
||||||
|
current = scripts[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!current)
|
||||||
|
throw Error("Could not find own <script> element");
|
||||||
}
|
}
|
||||||
script = current.src.substr(0, current.src.lastIndexOf("/")) + "/" + script;
|
script = current.src.substr(0, current.src.lastIndexOf("/")) + "/" + script;
|
||||||
this._workers = new Array(size);
|
this._workers = new Array(size);
|
||||||
|
|
14043
static/js/novnc/vendor/sinon.js
vendored
14043
static/js/novnc/vendor/sinon.js
vendored
File diff suppressed because one or more lines are too long
|
@ -488,12 +488,11 @@ class wvmInstance(wvmConnect):
|
||||||
<target dev='%s' bus='%s'/>
|
<target dev='%s' bus='%s'/>
|
||||||
</disk>
|
</disk>
|
||||||
""" % (source, target, targetbus)
|
""" % (source, target, targetbus)
|
||||||
|
if self.get_status() == 1:
|
||||||
|
self.instance.attachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_LIVE)
|
||||||
|
self.instance.attachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_CONFIG)
|
||||||
if self.get_status() == 5:
|
if self.get_status() == 5:
|
||||||
devices = tree.find('devices')
|
self.instance.attachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_CONFIG)
|
||||||
elm_disk = ElementTree.fromstring(xml_disk)
|
|
||||||
devices.append(elm_disk)
|
|
||||||
xmldom = ElementTree.tostring(tree)
|
|
||||||
self._defineXML(xmldom)
|
|
||||||
|
|
||||||
def detach_disk(self, dev):
|
def detach_disk(self, dev):
|
||||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
|
|
Loading…
Reference in a new issue