directories:
- node_modules
node_js:
-- '0.11.13'
+- '6.1'
env:
matrix:
- TEST_BROWSER_NAME=PhantomJS
- - TEST_BROWSER_NAME=chrome TEST_BROWSER_OS='Windows 7,Linux'
- - TEST_BROWSER_NAME=firefox TEST_BROWSER_OS='Windows 7,Linux' TEST_BROWSER_VERSION='30,26'
- - TEST_BROWSER_NAME='internet explorer' TEST_BROWSER_OS='Windows 7' TEST_BROWSER_VERSION=10
- - TEST_BROWSER_NAME='internet explorer' TEST_BROWSER_OS='Windows 8.1' TEST_BROWSER_VERSION=11
- - TEST_BROWSER_NAME=safari TEST_BROWSER_OS='OS X 10.8' TEST_BROWSER_VERSION=6
- - TEST_BROWSER_NAME=safari TEST_BROWSER_OS='OS X 10.9' TEST_BROWSER_VERSION=7
+ - TEST_BROWSER_NAME=chrome TEST_BROWSER_OS='Windows 10,Linux,OS X 10.11'
+ - TEST_BROWSER_NAME=firefox TEST_BROWSER_OS='Windows 10,Linux,OS X 10.11'
+ - TEST_BROWSER_NAME='internet explorer' TEST_BROWSER_OS='Windows 10'
+ - TEST_BROWSER_NAME=safari TEST_BROWSER_OS='OS X 10.11'
global:
- secure: QE5GqGd2hrpQsIgd8dlv3oRUUHqZayomzzQjNXOB81VQi241uz/ru+3GtBZLB5WLZCq/Gj89vbLnR0LN4ixlmPaWv3/WJQGyDGuRD/vMnccVl+rBUP/Hh2zdYwiISIGcrywNAE+KLus/lyt/ahVgzbaRaDSzrM1HaZFT/rndGck=
- secure: g75sdctEwj0hoLW0Y08Tdv8s5scNzplB6a9EtaJ2vJD9S/bK+AsPqbWesGv1UlrFPCWdbV7Vg61vkmoUjcmb5xhqFIjcM9TlYJoKWeOTsOmnQoSIkIq6gMF1k02+LmKInbPgIzrp3m3jluS1qaOs/EzFpDnJp9hWBiAfXa12Jxk=
### Description
-noVNC is a HTML5 VNC client that runs well in any modern browser
-including mobile browsers (iPhone/iPad and Android).
+noVNC is a HTML5 VNC client that runs well in any modern browser including
+mobile browsers (iOS and Android).
-Many companies/projects have integrated noVNC including [Ganeti Web
-Manager](http://code.osuosl.org/projects/ganeti-webmgr),
+Many companies, projects and products have integrated noVNC including
+[Ganeti Web Manager](http://code.osuosl.org/projects/ganeti-webmgr),
[OpenStack](http://www.openstack.org),
-[OpenNebula](http://opennebula.org/), and
-[LibVNCServer](http://libvncserver.sourceforge.net). See [the Projects
-and Companies wiki
-page](https://github.com/kanaka/noVNC/wiki/ProjectsCompanies-using-noVNC)
+[OpenNebula](http://opennebula.org/),
+[LibVNCServer](http://libvncserver.sourceforge.net), and
+[ThinLinc](https://cendio.com/thinlinc). See
+[the Projects and Companies wiki page](https://github.com/kanaka/noVNC/wiki/Projects-and-companies-using-noVNC)
for a more complete list with additional info and links.
### News/help/contact
Notable commits, announcements and news are posted to
-<a href="http://www.twitter.com/noVNC">@noVNC</a>
+<a href="http://www.twitter.com/noVNC">@noVNC</a>.
-If you are a noVNC developer/integrator/user (or want to be) please
-join the <a
-href="https://groups.google.com/forum/?fromgroups#!forum/novnc">noVNC
-discussion group</a>
+If you are a noVNC developer/integrator/user (or want to be) please join the
+<a href="https://groups.google.com/forum/?fromgroups#!forum/novnc">
+noVNC discussion group</a>.
-Bugs and feature requests can be submitted via [github
-issues](https://github.com/kanaka/noVNC/issues). If you are looking
-for a place to start contributing to noVNC, a good place to start
-would be the issues that are marked as
+Bugs and feature requests can be submitted via
+[github issues](https://github.com/kanaka/noVNC/issues).
+If you are looking for a place to start contributing to noVNC, a good place to
+start would be the issues that are marked as
["patchwelcome"](https://github.com/kanaka/noVNC/issues?labels=patchwelcome).
-If you want to show appreciation for noVNC you could donate to a great
-non-profits such as: [Compassion
-International](http://www.compassion.com/), [SIL](http://www.sil.org),
-[Habitat for Humanity](http://www.habitat.org), [Electronic Frontier
-Foundation](https://www.eff.org/), [Against Malaria
-Foundation](http://www.againstmalaria.com/), [Nothing But
-Nets](http://www.nothingbutnets.net/), etc. Please tweet <a
-href="http://www.twitter.com/noVNC">@noVNC</a> if you do.
+If you want to show appreciation for noVNC you could donate to a great non-
+profits such as:
+[Compassion International](http://www.compassion.com/),
+[SIL](http://www.sil.org),
+[Habitat for Humanity](http://www.habitat.org),
+[Electronic Frontier Foundation](https://www.eff.org/),
+[Against Malaria Foundation](http://www.againstmalaria.com/),
+[Nothing But Nets](http://www.nothingbutnets.net/), etc.
+Please tweet <a href="http://www.twitter.com/noVNC">@noVNC</a> if you do.
### Features
Running in Chrome before and after connecting:
-<img src="http://kanaka.github.com/noVNC/img/noVNC-5.png" width=400> <img src="http://kanaka.github.com/noVNC/img/noVNC-7.jpg" width=400>
+<img src="http://kanaka.github.com/noVNC/img/noVNC-5.png" width=400>
+<img src="http://kanaka.github.com/noVNC/img/noVNC-7.jpg" width=400>
-See more screenshots <a href="http://kanaka.github.com/noVNC/screenshots.html">here</a>.
+See more screenshots
+<a href="http://kanaka.github.com/noVNC/screenshots.html">here</a>.
### Browser Requirements
-* HTML5 Canvas (with createImageData): Chrome, Firefox 3.6+, iOS
- Safari, Opera 11+, Internet Explorer 9+, etc.
+* Chrome 8, Firefox 4, Safari 6, Opera 12, IE 11, Edge 12, etc.
-* HTML5 WebSockets and Typed Arrays
+* HTML5 Canvas, WebSockets and Typed Arrays
-* Fast Javascript Engine: this is not strictly a requirement, but
- without a fast Javascript engine, noVNC might be painfully slow.
+* Fast Javascript Engine: this is not strictly a requirement, but without a
+ fast Javascript engine, noVNC might be painfully slow.
-* See the more detailed [browser compatibility wiki page](https://github.com/kanaka/noVNC/wiki/Browser-support).
+* See the more detailed
+[browser compatibility wiki page](https://github.com/kanaka/noVNC/wiki/Browser-support).
### Server Requirements
-Unless you are using a VNC server with support for WebSockets
-connections (such as
-[x11vnc/libvncserver](http://libvncserver.sourceforge.net/),
+Unless you are using a VNC server with support for WebSockets connections (such
+as [x11vnc/libvncserver](http://libvncserver.sourceforge.net/),
[QEMU](http://www.qemu.org/), or
-[PocketVNC](http://www.pocketvnc.com/blog/?page_id=866)), you need to
-use a WebSockets to TCP socket proxy. There is a python proxy included
+[PocketVNC](http://www.pocketvnc.com/blog/?page_id=866)), you need to use a
+WebSockets to TCP socket proxy. There is a python proxy included
('websockify').
### Quick Start
-* Use the launch script to start a mini-webserver and the WebSockets
- proxy (websockify). The `--vnc` option is used to specify the location of
- a running VNC server:
+* Use the launch script to start a mini-webserver and the WebSockets proxy
+ (websockify). The `--vnc` option is used to specify the location of a running
+ VNC server:
`./utils/launch.sh --vnc localhost:5901`
-* Point your browser to the cut-and-paste URL that is output by the
- launch script. Enter a password if the VNC server has one
- configured. Hit the Connect button and enjoy!
+* Point your browser to the cut-and-paste URL that is output by the launch
+ script. Enter a password if the VNC server has one configured. Hit the
+ Connect button and enjoy!
### Other Pages
-* [Encrypted Connections](https://github.com/kanaka/websockify/wiki/Encrypted-Connections). How to setup websockify so that you can use encrypted connections from noVNC.
+* [Modules/API](https://github.com/kanaka/noVNC/wiki/Modules-API) - The library
+ modules and their Javascript API.
-* [Advanced Usage](https://github.com/kanaka/noVNC/wiki/Advanced-usage). Starting a VNC server, advanced websockify usage, etc.
+* [Integration](https://github.com/kanaka/noVNC/wiki/Integration) - Get noVNC
+ to work in existing projects.
-* [Integrating noVNC](https://github.com/kanaka/noVNC/wiki/Integration) into existing projects.
+* [Troubleshooting](https://github.com/kanaka/noVNC/wiki/Troubleshooting) - How
+ to troubleshoot problems.
-* [Troubleshooting noVNC](https://github.com/kanaka/noVNC/wiki/Troubleshooting) problems.
+* [Encrypted Connections](https://github.com/kanaka/websockify/wiki/Encrypted-Connections) -
+ Setup websockify so that you can use encrypted connections from noVNC.
+
+* [Advanced Usage](https://github.com/kanaka/noVNC/wiki/Advanced-usage) -
+ Generating an SSL certificate, starting a VNC server, advanced websockify
+ usage, etc.
+
+* [Testing](https://github.com/kanaka/noVNC/wiki/Testing) - Run and write
+ tests.
+
+* [Translations](https://github.com/kanaka/noVNC/wiki/Translations) - Add and
+ modify localization for JavaScript and HTML.
### Authors/Contributors
* [Solly Ross](https://github.com/DirectXMan12) (Red Hat / OpenStack)
* Notable contributions:
- * UI and Icons : Chris Gordon
+ * UI and Icons : Pierre Ossman, Chris Gordon
* Original Logo : Michael Sersen
* tight encoding : Michael Tinglof (Mercuri.ca)
* base64 : Martijn Pieters (Digital Creations 2), Samuel Sieb (sieb.net)
* DES : Dave Zimmerman (Widget Workshop), Jef Poskanzer (ACME Labs)
* Pako : Vitaly Puzrin (https://github.com/nodeca/pako)
+
+* [Contribution guide](https://github.com/kanaka/noVNC/wiki/Contributing)
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"
- width="20"
+ width="15"
height="50"
- viewBox="0 0 20 50"
+ viewBox="0 0 15 50"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="16"
- inkscape:cx="10.515997"
- inkscape:cy="22.863737"
+ inkscape:cx="-10.001409"
+ inkscape:cy="24.512566"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
+ <dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
id="rect4249"
width="1"
height="1.0000174"
- x="14.5"
+ x="9.5"
y="1008.8622"
ry="1.7382812e-05" />
<rect
ry="1.7382812e-05"
y="1013.8622"
- x="14.5"
+ x="9.5"
height="1.0000174"
width="1"
id="rect4255"
<rect
ry="1.7382812e-05"
y="1008.8622"
- x="9.5"
+ x="4.5"
height="1.0000174"
width="1"
id="rect4261"
id="rect4263"
width="1"
height="1.0000174"
- x="9.5"
+ x="4.5"
y="1013.8622"
ry="1.7382812e-05" />
<rect
ry="1.7382812e-05"
y="1039.8622"
- x="14.5"
+ x="9.5"
height="1.0000174"
width="1"
id="rect4265"
id="rect4267"
width="1"
height="1.0000174"
- x="14.5"
+ x="9.5"
y="1044.8622"
ry="1.7382812e-05" />
<rect
id="rect4269"
width="1"
height="1.0000174"
- x="9.5"
+ x="4.5"
y="1039.8622"
ry="1.7382812e-05" />
<rect
ry="1.7382812e-05"
y="1044.8622"
- x="9.5"
+ x="4.5"
height="1.0000174"
width="1"
id="rect4271"
id="rect4273"
width="1"
height="1.0000174"
- x="14.5"
+ x="9.5"
y="1018.8622"
ry="1.7382812e-05" />
<rect
ry="1.7382812e-05"
y="1018.8622"
- x="9.5"
+ x="4.5"
height="1.0000174"
width="1"
id="rect4275"
id="rect4277"
width="1"
height="1.0000174"
- x="14.5"
+ x="9.5"
y="1034.8622"
ry="1.7382812e-05" />
<rect
ry="1.7382812e-05"
y="1034.8622"
- x="9.5"
+ x="4.5"
height="1.0000174"
width="1"
id="rect4279"
--- /dev/null
+/*
+ * Translations for de
+ *
+ * This file was autotomatically generated from de.po
+ * DO NOT EDIT!
+ */
+
+Language = {
+ "Connecting...": "Verbunden...",
+ "Connected (encrypted) to ": "Verbunden mit (verschlรผsselt) ",
+ "Connected (unencrypted) to ": "Verbunden mit (unverschlรผsselt) ",
+ "Disconnecting...": "Verbindung trennen...",
+ "Disconnected": "Verbindung zum Server getrennt",
+ "Must set host and port": "Richten Sie Host und Port ein",
+ "Password is required": "Passwort ist erforderlich",
+ "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "'Clipping-Modus' aktiviert, Scrollbalken in 'IE-Vollbildmodus' werden nicht unterstรผtzt",
+ "Disconnect timeout": "Timeout beim trennen",
+};
--- /dev/null
+/*
+ * Translations for el
+ *
+ * This file was autotomatically generated from el.po
+ * DO NOT EDIT!
+ */
+
+Language = {
+ "Connecting...": "ฮฃฯ
ฮฝฮดฮญฮตฯฮฑฮน...",
+ "Connected (encrypted) to ": "ฮฃฯ
ฮฝฮดฮญฮธฮทฮบฮต (ฮบฯฯ
ฯฯฮฟฮณฯฮฑฯฮทฮผฮญฮฝฮฑ) ฮผฮต ฯฮฟ ",
+ "Connected (unencrypted) to ": "ฮฃฯ
ฮฝฮดฮญฮธฮทฮบฮต (ฮผฮท ฮบฯฯ
ฯฯฮฟฮณฯฮฑฯฮทฮผฮญฮฝฮฑ) ฮผฮต ฯฮฟ ",
+ "Disconnecting...": "Aฯฮฟฯฯ
ฮฝฮดฮญฮตฯฮฑฮน...",
+ "Disconnected": "ฮฯฮฟฯฯ
ฮฝฮดฮญฮธฮทฮบฮต",
+ "Must set host and port": "ฮ ฯฮญฯฮตฮน ฮฝฮฑ ฮฟฯฮนฯฯฮตฮฏ ฯฮฟ ฯฮฝฮฟฮผฮฑ ฮบฮฑฮน ฮท ฯฯฯฯฮฑ ฯฮฟฯ
ฮดฮนฮฑฮบฮฟฮผฮนฯฯฮฎ",
+ "Password is required": "ฮฯฮฑฮนฯฮตฮฏฯฮฑฮน ฮฟ ฮบฯฮดฮนฮบฯฯ ฯฯฯฯฮฒฮฑฯฮทฯ",
+ "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "ฮฯฮฑฯฮผฮฟฮณฮฎ ฮปฮตฮนฯฮฟฯ
ฯฮณฮฏฮฑฯ ฮฑฯฮฟฮบฮฟฯฮฎฯ ฮฑฯฮฟฯ ฮดฮตฮฝ ฯ
ฯฮฟฯฯฮทฯฮฏฮถฮฟฮฝฯฮฑฮน ฮฟฮน ฮปฯฯฮฏฮดฮตฯ ฮบฯฮปฮนฯฮทฯ ฯฮต ฯฮปฮฎฯฮท ฮฟฮธฯฮฝฮท ฯฯฮฟฮฝ IE",
+ "Disconnect timeout": "ฮ ฮฑฯฮญฮปฮตฯ
ฯฮท ฯฯฮฟฮฝฮนฮบฮฟฯ ฮฟฯฮฏฮฟฯ
ฮฑฯฮฟฯฯฮฝฮดฮตฯฮทฯ",
+ "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": "ฮกฯ
ฮธฮผฮฏฯฮตฮนฯ",
+ "Encrypt": "ฮฯฯ
ฯฯฮฟฮณฯฮฌฯฮทฯฮท",
+ "True Color": "ฮ ฯฮฑฮณฮผฮฑฯฮนฮบฮฌ ฮงฯฯฮผฮฑฯฮฑ",
+ "Local Cursor": "ฮคฮฟฯฮนฮบฯฯ ฮฯฮฟฮผฮญฮฑฯ",
+ "Clip to Window": "ฮฯฮฟฮบฮฟฯฮฎ ฯฯฮฟ ฯฯฮนฮฟ ฯฮฟฯ
ฮ ฮฑฯฮฌฮธฯ
ฯฮฟฯ
",
+ "Shared Mode": "ฮฮฟฮนฮฝฯฯฯฮทฯฯฮท ฮฮตฮนฯฮฟฯ
ฯฮณฮฏฮฑ",
+ "View Only": "ฮฯฮฝฮฟ ฮฮญฮฑฯฮท",
+ "Path:": "ฮฮนฮฑฮดฯฮฟฮผฮฎ:",
+ "Scaling Mode:": "ฮฮตฮนฯฮฟฯ
ฯฮณฮฏฮฑ ฮฮปฮนฮผฮฌฮบฯฯฮทฯ:",
+ "None": "ฮฮฑฮผฮฏฮฑ",
+ "Local Scaling": "ฮคฮฟฯฮนฮบฮฎ ฮฮปฮนฮผฮฌฮบฯฯฮท",
+ "Local Downscaling": "ฮคฮฟฯฮนฮบฮฎ ฮฃฯ
ฯฯฮฏฮบฮฝฯฯฮท",
+ "Remote Resizing": "ฮฯฮฟฮผฮฑฮบฯฯ
ฯฮผฮญฮฝฮท ฮฮปฮปฮฑฮณฮฎ ฮผฮตฮณฮญฮธฮฟฯ
ฯ",
+ "Repeater ID:": "Repeater ID:",
+ "Style:": "ฮฃฯฯ
ฮป:",
+ "default": "ฯฯฮฟฮตฯฮนฮปฮตฮณฮผฮญฮฝฮฟ",
+ "Logging:": "ฮฮฑฯฮฑฮณฯฮฑฯฮฎ:",
+ "Apply": "ฮฯฮฑฯฮผฮฟฮณฮฎ",
+ "Host:": "ฮฮฝฮฟฮผฮฑ ฮดฮนฮฑฮบฮฟฮผฮนฯฯฮฎ:",
+ "Port:": "ฮ ฯฯฯฮฑ ฮดฮนฮฑฮบฮฟฮผฮนฯฯฮฎ:",
+ "Password:": "ฮฯฮดฮนฮบฯฯ ฮ ฯฯฯฮฒฮฑฯฮทฯ:",
+ "Token:": "ฮฮนฮฑฮบฯฮนฯฮนฮบฯ:",
+ "Send Password": "ฮฯฮฟฯฯฮฟฮปฮฎ ฮฯฮดฮนฮบฮฟฯ ฮ ฯฯฯฮฒฮฑฯฮทฯ",
+ "Canvas not supported.": "ฮฮตฮฝ ฯ
ฯฮฟฯฯฮทฯฮฏฮถฮตฯฮฑฮน ฯฮฟ ฯฯฮฟฮนฯฮตฮฏฮฟ Canvas",
+};
--- /dev/null
+/*
+ * Translations for nl
+ *
+ * This file was autotomatically generated from nl.po
+ * DO NOT EDIT!
+ */
+
+Language = {
+ "Connecting...": "Verbinden...",
+ "Connected (encrypted) to ": "Verbonden (versleuteld) met ",
+ "Connected (unencrypted) to ": "Verbonden (onversleuteld) met ",
+ "Disconnecting...": "Verbinding verbreken...",
+ "Disconnected": "Verbinding verbroken",
+ "Must set host and port": "Host en poort moeten worden ingesteld",
+ "Password is required": "Wachtwoord is vereist",
+ "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "''Clipping mode' ingeschakeld, omdat schuifbalken in volledige-scherm-modus in IE niet worden ondersteund",
+ "Disconnect timeout": "Timeout tijdens verbreken van verbinding",
+};
--- /dev/null
+/*
+ * Translations for sv
+ *
+ * This file was autotomatically generated from sv.po
+ * DO NOT EDIT!
+ */
+
+Language = {
+ "Connecting...": "Ansluter...",
+ "Connected (encrypted) to ": "Ansluten (krypterat) till ",
+ "Connected (unencrypted) to ": "Ansluten (okrypterat) till ",
+ "Disconnecting...": "Kopplar ner...",
+ "Disconnected": "Frรฅnkopplad",
+ "Must set host and port": "Du mรฅste specifiera en host och port",
+ "Password is required": "Lรถsenord krรคvs",
+ "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "Tvingar 'Clipping mode' eftersom skrollning inte stรถdjs av IE i fullskรคrm",
+ "Disconnect timeout": "Det tog fรถr lรฅng tid att koppla ner",
+ "noVNC encountered an error:": "noVNC stรถtte pรฅ ett problem:",
+ "Hide/Show the control bar": "Gรถm/Visa kontrollbaren",
+ "Move/Drag Viewport": "Flytta/Dra Vyn",
+ "viewport drag": "dra vy",
+ "Active Mouse Button": "Aktiv musknapp",
+ "No mousebutton": "Ingen musknapp",
+ "Left mousebutton": "Vรคnster musknapp",
+ "Middle mousebutton": "Mitten-musknapp",
+ "Right mousebutton": "Hรถger musknapp",
+ "Keyboard": "Tangentbord",
+ "Show Keyboard": "Visa Tangentbord",
+ "Extra keys": "Extraknappar",
+ "Show Extra Keys": "Visa Extraknappar",
+ "Ctrl": "Ctrl",
+ "Toggle Ctrl": "Vรคxla Ctrl",
+ "Alt": "Alt",
+ "Toggle Alt": "Vรคxla Alt",
+ "Send Tab": "Skicka Tab",
+ "Tab": "Tab",
+ "Esc": "Esc",
+ "Send Escape": "Skicka Escape",
+ "Ctrl+Alt+Del": "Ctrl+Alt+Del",
+ "Send Ctrl-Alt-Del": "Skicka Ctrl-Alt-Del",
+ "Shutdown/Reboot": "Stรคng av/Boota om",
+ "Shutdown/Reboot...": "Stรคng av/Boota om...",
+ "Power": "Strรถm",
+ "Shutdown": "Stรคng av",
+ "Reboot": "Boota om",
+ "Reset": "ร
terstรคll",
+ "Clipboard": "Urklipp",
+ "Clear": "Rensa",
+ "Fullscreen": "Fullskรคrm",
+ "Settings": "Instรคllningar",
+ "Encrypt": "Kryptera",
+ "True Color": "Fullfรคrg",
+ "Local Cursor": "Lokal Muspekare",
+ "Clip to Window": "Begrรคnsa till Fรถnster",
+ "Shared Mode": "Delat Lรคge",
+ "View Only": "Endast Visning",
+ "Path:": "Sรถkvรคg:",
+ "Scaling Mode:": "Skalningslรคge:",
+ "None": "Ingen",
+ "Local Scaling": "Lokal Skalning",
+ "Local Downscaling": "Lokal Nedskalning",
+ "Remote Resizing": "รndra Storlek",
+ "Repeater ID:": "Repeater-ID:",
+ "Style:": "Stil:",
+ "default": "standard",
+ "Logging:": "Loggning:",
+ "Apply": "Verkstรคll",
+ "Connect": "Anslut",
+ "Disconnect": "Koppla frรฅn",
+ "Connection": "Uppkoppling",
+ "Host:": "Vรคrd:",
+ "Port:": "Port:",
+ "Password:": "Lรถsenord:",
+ "Token:": "Token:",
+ "Send Password": "Skicka Lรถsenord",
+ "Canvas not supported.": "Canvas stรถds ej",
+};
background-repeat:no-repeat;
background-position:right bottom;
height:100%;
+ touch-action: none;
}
html {
display: none;
}
+/* ----------------------------------------
+ * Spinner
+ * ----------------------------------------
+ */
+
+.noVNC_spinner {
+ position: relative;
+}
+.noVNC_spinner, .noVNC_spinner::before, .noVNC_spinner::after {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ animation: noVNC_spinner 1.0s ease-in-out alternate infinite;
+}
+.noVNC_spinner::before {
+ content: "";
+ position: absolute;
+ left: -20px;
+ animation-delay: -0.2s;
+}
+.noVNC_spinner::after {
+ content: "";
+ position: absolute;
+ left: 20px;
+ animation-delay: 0.2s;
+}
+@keyframes noVNC_spinner {
+ 0% { box-shadow: 0 10px 0 white; }
+ 100% { box-shadow: 0 30px 0 white; }
+}
+
/* ----------------------------------------
* Input Elements
* ----------------------------------------
pointer-events: auto;
}
+/* ----------------------------------------
+ * Fallback error
+ * ----------------------------------------
+ */
+
+#noVNC_fallback_error {
+ position: fixed;
+ z-index: 3;
+ left: 50%;
+ transform: translate(-50%, -50px);
+ transition: 0.5s ease-in-out;
+
+ visibility: hidden;
+ opacity: 0;
+
+ top: 60px;
+ padding: 15px;
+ width: auto;
+
+ text-align: center;
+ font-weight: bold;
+ word-wrap: break-word;
+ color: #fff;
+
+ border-radius: 10px;
+ box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
+ background: rgba(200,55,55,0.8);
+}
+#noVNC_fallback_error.noVNC_open {
+ transform: translate(-50%, 0);
+ visibility: visible;
+ opacity: 1;
+}
+
+#noVNC_fallback_errormsg {
+ font-weight: normal;
+}
+
+#noVNC_fallback_error .noVNC_location {
+ font-style: italic;
+ font-size: 0.8em;
+ color: rgba(255, 255, 255, 0.8);
+}
+
+#noVNC_fallback_error .noVNC_stack {
+ padding: 10px;
+ margin: 10px;
+ font-size: 0.8em;
+ text-align: left;
+ white-space: pre;
+ border: 1px solid rgba(0, 0, 0, 0.5);
+ background: rgba(0, 0, 0, 0.2);
+}
+
/* ----------------------------------------
* Control Bar
* ----------------------------------------
:root.noVNC_connected #noVNC_control_bar_anchor.noVNC_idle {
opacity: 0.8;
}
+#noVNC_control_bar_anchor.noVNC_right {
+ left: auto;
+ right: 0;
+}
#noVNC_control_bar {
position: relative;
- /* left: calc(-35px - 10px - 5px - 30px), but IE doesn't animate calc */
- left: -80px;
+ left: -100%;
transition: 0.5s ease-in-out;
background-color: rgb(110, 132, 163);
border-radius: 0 10px 10px 0;
- /* The extra border is to get a proper shadow */
- border-color: rgb(110, 132, 163);
- border-style: solid;
- border-width: 0 0 0 30px;
}
#noVNC_control_bar.noVNC_open {
box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
+ left: 0;
+}
+#noVNC_control_bar::before {
+ /* This extra element is to get a proper shadow */
+ content: "";
+ position: absolute;
+ z-index: -1;
+ height: 100%;
+ width: 30px;
left: -30px;
+ transition: box-shadow 0.5s ease-in-out;
+}
+#noVNC_control_bar.noVNC_open::before {
+ box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
+}
+.noVNC_right #noVNC_control_bar {
+ left: 100%;
+ border-radius: 10px 0 0 10px;
+}
+.noVNC_right #noVNC_control_bar.noVNC_open {
+ left: 0;
+}
+.noVNC_right #noVNC_control_bar::before {
+ visibility: hidden;
}
#noVNC_control_bar_handle {
position: absolute;
- right: -15px;
+ left: -15px;
top: 0;
transform: translateY(35px);
- width: 50px;
+ width: calc(100% + 30px);
height: 50px;
z-index: -2;
cursor: pointer;
- border-radius: 0 5px 5px 0;
+ border-radius: 5px;
background-color: rgb(83, 99, 122);
background-image: url("../images/handle_bg.svg");
background-repeat: no-repeat;
}
#noVNC_control_bar_handle:after {
content: "";
- transition: 0.5s ease-in-out;
+ transition: transform 0.5s ease-in-out;
background: url("../images/handle.svg");
position: absolute;
top: 22px; /* (50px-6px)/2 */
:root:not(.noVNC_connected) #noVNC_control_bar_handle {
display: none;
}
+.noVNC_right #noVNC_control_bar_handle {
+ background-position: left;
+}
+.noVNC_right #noVNC_control_bar_handle:after {
+ left: 5px;
+ right: 0;
+ transform: translateX(1px) rotate(180deg);
+}
+.noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after {
+ transform: none;
+}
#noVNC_control_bar_handle div {
position: absolute;
right: -35px;
:root:not(.noVNC_touch) #noVNC_control_bar_handle div {
display: none;
}
+.noVNC_right #noVNC_control_bar_handle div {
+ left: -35px;
+ right: auto;
+}
#noVNC_control_bar .noVNC_scroll {
max-height: 100vh; /* Chrome is buggy with 100% */
overflow-y: auto;
padding: 0 10px 0 5px;
}
+.noVNC_right #noVNC_control_bar .noVNC_scroll {
+ padding: 0 5px 0 10px;
+}
/* General button style */
.noVNC_button {
opacity: 1;
transform: translateX(75px);
}
+.noVNC_right .noVNC_vcenter {
+ left: auto;
+ right: 0;
+}
+.noVNC_right .noVNC_panel {
+ transform: translateX(-25px);
+}
+.noVNC_right .noVNC_panel.noVNC_open {
+ transform: translateX(-75px);
+}
.noVNC_panel hr {
border: none;
* ----------------------------------------
*/
+/* Transition screen */
+#noVNC_transition {
+ display: none;
+
+ position: fixed;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+
+ color: white;
+ background: rgba(0, 0, 0, 0.5);
+ z-index: 1000;
+
+ /*display: flex;*/
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+}
+:root.noVNC_connecting #noVNC_transition,
+:root.noVNC_disconnecting #noVNC_transition {
+ display: flex;
+}
+#noVNC_transition_text {
+ font-size: 1.5em;
+}
+
+/* Main container */
#noVNC_container {
display: table;
width: 100%;
* scaling will occur. Canvas size depends on remote VNC
* settings and noVNC settings. */
#noVNC_canvas {
- touch-action: none;
position: absolute;
left: 0;
right: 0;
/* [module]
* import Util from "../core/util";
* import KeyTable from "../core/input/keysym";
+ * import keysyms from "./keysymdef";
* import RFB from "../core/rfb";
* import Display from "../core/display";
* import WebUtil from "./webutil";
(function () {
"use strict";
+ // Fallback for all uncought errors
+ window.addEventListener('error', function(event) {
+ try {
+ var msg = "";
+
+ msg += "<div>";
+ msg += event.message;
+ msg += "</div>";
+
+ msg += " <div class=\"noVNC_location\">";
+ msg += event.filename;
+ msg += ":" + event.lineno + ":" + event.colno;
+ msg += "</div>";
+
+ if ((event.error !== undefined) &&
+ (event.error.stack !== undefined)) {
+ msg += "<div class=\"noVNC_stack\">";
+ msg += event.error.stack;
+ msg += "</div>";
+ }
+
+ document.getElementById('noVNC_fallback_error')
+ .classList.add("noVNC_open");
+ document.getElementById('noVNC_fallback_errormsg').innerHTML = msg;
+ } catch (exc) {
+ document.write("noVNC encountered an error.");
+ }
+ // Don't return true since this would prevent the error
+ // from being printed to the browser console.
+ return false;
+ });
+
+ // Set up translations
+ var LINGUAS = ["de", "el", "nl", "sv"];
+ Util.Localisation.setup(LINGUAS);
+ if (Util.Localisation.language !== "en") {
+ WebUtil.load_scripts(
+ {'app': ["locale/" + Util.Localisation.language + ".js"]});
+ }
+
/* [begin skip-as-module] */
// Load supporting scripts
WebUtil.load_scripts(
window.onscriptsload = function () { UI.load(); };
/* [end skip-as-module] */
+ var _ = Util.Localisation.get;
+
UI = {
connected: false,
controlbarDrag: false,
controlbarMouseDownClientY: 0,
controlbarMouseDownOffsetY: 0,
- keyboardVisible: false,
isSafari: false,
rememberedClipSetting: null,
UI.initSettings();
+ // Translate the DOM
+ Util.Localisation.translateDOM();
+
// Adapt the interface for touch screen devices
if (Util.isTouchDevice) {
document.documentElement.classList.add("noVNC_touch");
UI.initSetting('clip', false);
}
+ // Restore control bar position
+ if (WebUtil.readSetting('controlbar_pos') === 'right') {
+ UI.toggleControlbarSide();
+ }
+
// Setup and initialize event handlers
UI.setupWindowEvents();
UI.setupFullscreen();
document.getElementById("noVNC_keyboardinput")
.addEventListener('input', UI.keyInput);
+ document.getElementById("noVNC_keyboardinput")
+ .addEventListener('focus', UI.onfocusVirtualKeyboard);
document.getElementById("noVNC_keyboardinput")
.addEventListener('blur', UI.onblurVirtualKeyboard);
document.getElementById("noVNC_keyboardinput")
.addEventListener('submit', function () { return false; });
+ document.documentElement
+ .addEventListener('mousedown', UI.keepVirtualKeyboard, true);
+
document.getElementById("noVNC_control_bar")
.addEventListener('touchstart', UI.activateControlbar);
document.getElementById("noVNC_control_bar")
'onDesktopName': UI.updateDesktopName});
return true;
} catch (exc) {
- var msg = 'Unable to create RFB client -- ' + exc;
+ var msg = "Unable to create RFB client -- " + exc;
Util.Error(msg);
UI.showStatus(msg, 'error');
return false;
updateState: function(rfb, state, oldstate) {
var msg;
+
+ document.documentElement.classList.remove("noVNC_connecting");
+ document.documentElement.classList.remove("noVNC_connected");
+ document.documentElement.classList.remove("noVNC_disconnecting");
+
switch (state) {
case 'connecting':
- UI.showStatus("Connecting");
+ document.getElementById("noVNC_transition_text").innerHTML = _("Connecting...");
+ document.documentElement.classList.add("noVNC_connecting");
break;
case 'connected':
UI.connected = true;
+ document.documentElement.classList.add("noVNC_connected");
if (rfb && rfb.get_encrypt()) {
- msg = "Connected (encrypted) to " + UI.desktopName;
+ msg = _("Connected (encrypted) to ") + UI.desktopName;
} else {
- msg = "Connected (unencrypted) to " + UI.desktopName;
+ msg = _("Connected (unencrypted) to ") + UI.desktopName;
}
UI.showStatus(msg);
break;
case 'disconnecting':
- UI.showStatus("Disconnecting");
+ UI.connected = false;
+ document.getElementById("noVNC_transition_text").innerHTML = _("Disconnecting...");
+ document.documentElement.classList.add("noVNC_disconnecting");
break;
case 'disconnected':
- UI.connected = false;
- UI.showStatus("Disconnected");
+ UI.showStatus(_("Disconnected"));
break;
default:
msg = "Invalid UI state";
document.getElementById('noVNC_setting_repeaterID').disabled = UI.connected;
if (UI.connected) {
- document.documentElement.classList.add("noVNC_connected");
UI.updateViewClip();
UI.setMouseButton(1);
// Hide the controlbar after 2 seconds
UI.closeControlbarTimeout = setTimeout(UI.closeControlbar, 2000);
} else {
- document.documentElement.classList.remove("noVNC_connected");
UI.updateXvpButton(0);
UI.keepControlbar();
}
}
},
+ toggleControlbarSide: function () {
+ // Temporarily disable animation to avoid weird movement
+ var bar = document.getElementById('noVNC_control_bar');
+ bar.style.transitionDuration = '0s';
+ bar.addEventListener('transitionend', function () { this.style.transitionDuration = ""; });
+
+ var anchor = document.getElementById('noVNC_control_bar_anchor');
+ if (anchor.classList.contains("noVNC_right")) {
+ WebUtil.writeSetting('controlbar_pos', 'left');
+ anchor.classList.remove("noVNC_right");
+ } else {
+ WebUtil.writeSetting('controlbar_pos', 'right');
+ anchor.classList.add("noVNC_right");
+ }
+
+ // Consider this a movement of the handle
+ UI.controlbarDrag = true;
+ },
+
dragControlbarHandle: function (e) {
if (!UI.controlbarGrabbed) return;
var ptr = Util.getPointerEvent(e);
+ var anchor = document.getElementById('noVNC_control_bar_anchor');
+ if (ptr.clientX < (window.innerWidth * 0.1)) {
+ if (anchor.classList.contains("noVNC_right")) {
+ UI.toggleControlbarSide();
+ }
+ } else if (ptr.clientX > (window.innerWidth * 0.9)) {
+ if (!anchor.classList.contains("noVNC_right")) {
+ UI.toggleControlbarSide();
+ }
+ }
+
if (!UI.controlbarDrag) {
// The goal is to trigger on a certain physical width, the
// devicePixelRatio brings us a bit closer but is not optimal.
e.preventDefault();
e.stopPropagation();
+ UI.keepControlbar();
+ UI.activateControlbar();
},
// Move the handle but don't allow any position outside the bounds
UI.toggleControlbar();
e.preventDefault();
e.stopPropagation();
+ UI.keepControlbar();
+ UI.activateControlbar();
}
UI.controlbarGrabbed = false;
},
UI.controlbarMouseDownOffsetY = ptr.clientY - bounds.top;
e.preventDefault();
e.stopPropagation();
+ UI.keepControlbar();
+ UI.activateControlbar();
},
/* ------^-------
}
if ((!host) || (!port)) {
- var msg = "Must set host and port";
+ var msg = _("Must set host and port");
Util.Error(msg);
UI.showStatus(msg, 'error');
return;
}, 100);
if (typeof msg === 'undefined') {
- msg = "Password is required";
+ msg = _("Password is required");
}
Util.Warn(msg);
UI.showStatus(msg, "warning");
// The browser is IE and we are in fullscreen mode.
// - We need to force clipping while in fullscreen since
// scrollbars doesn't work.
- var msg = "Forcing clipping mode since scrollbars aren't" +
- "supported by IE in fullscreen";
+ var msg = _("Forcing clipping mode since " +
+ "scrollbars aren't supported " +
+ "by IE in fullscreen");
Util.Debug(msg);
UI.showStatus(msg);
UI.rememberedClipSetting = UI.getSetting('clip');
if (document.activeElement == input) return;
- UI.keyboardVisible = true;
- document.getElementById('noVNC_keyboard_button')
- .classList.add("noVNC_selected");
input.focus();
try {
},
toggleVirtualKeyboard: function () {
- if (UI.keyboardVisible) {
+ if (document.getElementById('noVNC_keyboard_button')
+ .classList.contains("noVNC_selected")) {
UI.hideVirtualKeyboard();
} else {
UI.showVirtualKeyboard();
}
},
- onblurVirtualKeyboard: function() {
- //Weird bug in iOS if you change keyboardVisible
- //here it does not actually occur so next time
- //you click keyboard icon it doesnt work.
- UI.hideKeyboardTimeout = setTimeout(function() {
- UI.keyboardVisible = false;
- document.getElementById('noVNC_keyboard_button')
- .classList.remove("noVNC_selected");
- },100);
+ onfocusVirtualKeyboard: function(event) {
+ document.getElementById('noVNC_keyboard_button')
+ .classList.add("noVNC_selected");
},
- keepKeyboard: function() {
- clearTimeout(UI.hideKeyboardTimeout);
- if(UI.keyboardVisible === true) {
- UI.showVirtualKeyboard();
- } else if(UI.keyboardVisible === false) {
- UI.hideVirtualKeyboard();
+ onblurVirtualKeyboard: function(event) {
+ document.getElementById('noVNC_keyboard_button')
+ .classList.remove("noVNC_selected");
+ },
+
+ keepVirtualKeyboard: function(event) {
+ var input = document.getElementById('noVNC_keyboardinput');
+
+ // Only prevent focus change if the virtual keyboard is active
+ if (document.activeElement != input) {
+ return;
+ }
+
+ // Allow clicking on links
+ if (event.target.tagName === "A") {
+ return;
+ }
+
+ // And form elements, except standard noVNC buttons
+ if ((event.target.form !== undefined) &&
+ !event.target.classList.contains("noVNC_button")) {
+ return;
}
+
+ event.preventDefault();
},
keyboardinputReset: function() {
UI.rfb.sendKey(KeyTable.XK_BackSpace);
}
for (i = newLen - inputs; i < newLen; i++) {
- UI.rfb.sendKey(newValue.charCodeAt(i));
+ UI.rfb.sendKey(keysyms.fromUnicode(newValue.charCodeAt(i)).keysym);
}
// Control the text content length in the keyboardinput element
// text has been added to the field
event.target.blur();
// This has to be ran outside of the input handler in order to work
- setTimeout(UI.keepKeyboard, 0);
+ setTimeout(event.target.focus.bind(event.target), 0);
} else {
UI.lastKeyboardinput = newValue;
}
},
toggleExtraKeys: function() {
- UI.keepKeyboard();
if(document.getElementById('noVNC_modifiers')
.classList.contains("noVNC_open")) {
UI.closeExtraKeys();
},
sendEsc: function() {
- UI.keepKeyboard();
UI.rfb.sendKey(KeyTable.XK_Escape);
},
sendTab: function() {
- UI.keepKeyboard();
UI.rfb.sendKey(KeyTable.XK_Tab);
},
toggleCtrl: function() {
- UI.keepKeyboard();
var btn = document.getElementById('noVNC_toggle_ctrl_button');
if (btn.classList.contains("noVNC_selected")) {
UI.rfb.sendKey(KeyTable.XK_Control_L, false);
},
toggleAlt: function() {
- UI.keepKeyboard();
var btn = document.getElementById('noVNC_toggle_alt_button');
if (btn.classList.contains("noVNC_selected")) {
UI.rfb.sendKey(KeyTable.XK_Alt_L, false);
},
sendCtrlAltDel: function() {
- UI.keepKeyboard();
UI.rfb.sendCtrlAltDel();
},
}
};
+
// Dynamically load scripts without using document.write()
// Reference: http://unixpapa.com/js/dyna.html
//
function lookup(k) { return k ? {keysym: k, keyname: keynames ? keynames[k] : k} : undefined; }
return {
- fromUnicode : function(u) { return lookup(codepoints[u]); },
+ fromUnicode : function(u) {
+ var keysym = codepoints[u];
+ if (keysym === undefined) {
+ keysym = 0x01000000 | u;
+ }
+ return lookup(keysym);
+ },
lookup : lookup
};
})();
codepoint = evt.keyCode;
}
if (codepoint) {
- var res = keysyms.fromUnicode(substituteCodepoint(codepoint));
- if (res) {
- return res;
- }
+ return keysyms.fromUnicode(substituteCodepoint(codepoint));
}
// we could check evt.key here.
// Legal values are defined in http://www.w3.org/TR/DOM-Level-3-Events/#key-values-list,
this._rfb_init_state = 'ProtocolVersion';
Util.Debug("Starting VNC handshake");
} else {
- this._fail("Got unexpected WebSocket connection");
+ this._fail("Unexpected server connection");
}
}.bind(this));
this._sock.on('close', function (e) {
this._updateConnectionState('disconnected');
break;
case 'connecting':
- this._fail('Failed to connect to server' + msg);
+ this._fail('Failed to connect to server', msg);
+ break;
+ case 'connected':
+ // Handle disconnects that were initiated server-side
+ this._updateConnectionState('disconnecting');
+ this._updateConnectionState('disconnected');
break;
case 'disconnected':
- Util.Error("Received onclose while disconnected" + msg);
+ this._fail("Unexpected server disconnect",
+ "Already disconnected: " + msg);
break;
default:
- this._fail("Server disconnected" + msg);
+ this._fail("Unexpected server disconnect",
+ "Not in any state yet: " + msg);
break;
}
this._sock.off('close');
};
(function() {
+ var _ = Util.Localisation.get;
+
RFB.prototype = {
// Public methods
connect: function (host, port, password, path) {
this._rfb_path = (path !== undefined) ? path : "";
if (!this._rfb_host || !this._rfb_port) {
- return this._fail("Must set host and port");
+ return this._fail(
+ _("Must set host and port"));
}
this._rfb_init_state = '';
// Send a key press. If 'down' is not specified then send a down key
// followed by an up key.
- sendKey: function (code, down) {
+ sendKey: function (keysym, down) {
if (this._rfb_connection_state !== 'connected' || this._view_only) { return false; }
if (typeof down !== 'undefined') {
- Util.Info("Sending key code (" + (down ? "down" : "up") + "): " + code);
- RFB.messages.keyEvent(this._sock, code, down ? 1 : 0);
+ Util.Info("Sending keysym (" + (down ? "down" : "up") + "): " + keysym);
+ RFB.messages.keyEvent(this._sock, keysym, down ? 1 : 0);
} else {
- Util.Info("Sending key code (down + up): " + code);
- RFB.messages.keyEvent(this._sock, code, 1);
- RFB.messages.keyEvent(this._sock, code, 0);
+ Util.Info("Sending keysym (down + up): " + keysym);
+ RFB.messages.keyEvent(this._sock, keysym, 1);
+ RFB.messages.keyEvent(this._sock, keysym, 0);
}
return true;
},
requestDesktopSize: function (width, height) {
if (this._rfb_connection_state !== 'connected' ||
this._view_only) {
- return;
+ return false;
}
if (this._supportsSetDesktopSize) {
_connect: function () {
Util.Debug(">> RFB.connect");
+ this._init_vars();
var uri;
if (typeof UsingSocketIO !== 'undefined') {
uri += '://' + this._rfb_host + ':' + this._rfb_port + '/' + this._rfb_path;
Util.Info("connecting to " + uri);
- this._sock.open(uri, this._wsProtocols);
+ try {
+ // WebSocket.onopen transitions to the RFB init states
+ this._sock.open(uri, this._wsProtocols);
+ } catch (e) {
+ if (e.name === 'SyntaxError') {
+ this._fail("Invalid host or port value given", e);
+ } else {
+ this._fail("Error while connecting", e);
+ }
+ }
Util.Debug("<< RFB.connect");
},
+ _disconnect: function () {
+ Util.Debug(">> RFB.disconnect");
+ this._cleanup();
+ this._sock.close();
+ this._print_stats();
+ Util.Debug("<< RFB.disconnect");
+ },
+
_init_vars: function () {
// reset state
this._FBU.rects = 0;
return;
}
- this._rfb_connection_state = state;
-
- var smsg = "New state '" + state + "', was '" + oldstate + "'.";
- Util.Debug(smsg);
-
- if (this._disconnTimer && state !== 'disconnecting') {
- Util.Debug("Clearing disconnect timer");
- clearTimeout(this._disconnTimer);
- this._disconnTimer = null;
- this._sock.off('close'); // make sure we don't get a double event
- }
-
- this._onUpdateState(this, state, oldstate);
+ // Ensure proper transitions before doing anything
switch (state) {
case 'connected':
if (oldstate !== 'connecting') {
"previous connection state: " + oldstate);
return;
}
+ break;
+ case 'connecting':
+ if (oldstate !== '') {
+ Util.Error("Bad transition to connecting state, " +
+ "previous connection state: " + oldstate);
+ return;
+ }
+ break;
+
+ case 'disconnecting':
+ if (oldstate !== 'connected' && oldstate !== 'connecting') {
+ Util.Error("Bad transition to disconnecting state, " +
+ "previous connection state: " + oldstate);
+ return;
+ }
+ break;
+
+ default:
+ Util.Error("Unknown connection state: " + state);
+ return;
+ }
+
+ // State change actions
+
+ this._rfb_connection_state = state;
+ this._onUpdateState(this, state, oldstate);
+
+ var smsg = "New state '" + state + "', was '" + oldstate + "'.";
+ Util.Debug(smsg);
+
+ if (this._disconnTimer && state !== 'disconnecting') {
+ Util.Debug("Clearing disconnect timer");
+ clearTimeout(this._disconnTimer);
+ this._disconnTimer = null;
+
+ // make sure we don't get a double event
+ this._sock.off('close');
+ }
+
+ switch (state) {
+ case 'disconnected':
+ // Call onDisconnected callback after onUpdateState since
+ // we don't know if the UI only displays the latest message
if (this._rfb_disconnect_reason !== "") {
this._onDisconnected(this, this._rfb_disconnect_reason);
} else {
break;
case 'connecting':
- this._init_vars();
-
- // WebSocket.onopen transitions to the RFB init states
this._connect();
break;
case 'disconnecting':
- this._cleanup();
- this._sock.close(); // transitions to 'disconnected'
+ this._disconnect();
this._disconnTimer = setTimeout(function () {
- this._rfb_disconnect_reason = "Disconnect timeout";
+ this._rfb_disconnect_reason = _("Disconnect timeout");
this._updateConnectionState('disconnected');
}.bind(this), this._disconnectTimeout * 1000);
-
- this._print_stats();
break;
-
- default:
- Util.Error("Unknown connection state: " + state);
- return;
}
},
- _fail: function (msg) {
+ /* Print errors and disconnect
+ *
+ * The optional parameter 'details' is used for information that
+ * should be logged but not sent to the user interface.
+ */
+ _fail: function (msg, details) {
+ var fullmsg = msg;
+ if (typeof details !== 'undefined') {
+ fullmsg = msg + " (" + details + ")";
+ }
switch (this._rfb_connection_state) {
case 'disconnecting':
- Util.Error("Error while disconnecting: " + msg);
+ Util.Error("Failed when disconnecting: " + fullmsg);
break;
case 'connected':
- Util.Error("Error while connected: " + msg);
+ Util.Error("Failed while connected: " + fullmsg);
break;
case 'connecting':
- Util.Error("Error while connecting: " + msg);
+ Util.Error("Failed when connecting: " + fullmsg);
break;
default:
- Util.Error("RFB error: " + msg);
+ Util.Error("RFB failure: " + fullmsg);
break;
}
- this._rfb_disconnect_reason = msg;
+ this._rfb_disconnect_reason = msg; //This is sent to the UI
+
+ // Transition to disconnected without waiting for socket to close
this._updateConnectionState('disconnecting');
+ this._updateConnectionState('disconnected');
+
return false;
},
_negotiate_protocol_version: function () {
if (this._sock.rQlen() < 12) {
- return this._fail("Incomplete protocol version");
+ return this._fail("Error while negotiating with server",
+ "Incomplete protocol version");
}
var sversion = this._sock.rQshiftStr(12).substr(4, 7);
this._rfb_version = 3.8;
break;
default:
- return this._fail("Invalid server version " + sversion);
+ return this._fail("Unsupported server",
+ "Invalid server version: " + sversion);
}
if (is_repeater) {
if (num_types === 0) {
var strlen = this._sock.rQshift32();
var reason = this._sock.rQshiftStr(strlen);
- return this._fail("Security failure: " + reason);
+ return this._fail("Error while negotiating with server",
+ "Security failure: " + reason);
}
this._rfb_auth_scheme = 0;
}
if (this._rfb_auth_scheme === 0) {
- return this._fail("Unsupported security types: " + types);
+ return this._fail("Unsupported server",
+ "Unsupported security types: " + types);
}
this._sock.send([this._rfb_auth_scheme]);
if (serverSupportedTunnelTypes[0]) {
if (serverSupportedTunnelTypes[0].vendor != clientSupportedTunnelTypes[0].vendor ||
serverSupportedTunnelTypes[0].signature != clientSupportedTunnelTypes[0].signature) {
- return this._fail("Client's tunnel type had the incorrect vendor or signature");
+ return this._fail("Unsupported server",
+ "Client's tunnel type had the incorrect " +
+ "vendor or signature");
}
this._sock.send([0, 0, 0, 0]); // use NOTUNNEL
return false; // wait until we receive the sub auth count to continue
} else {
- return this._fail("Server wanted tunnels, but doesn't support the notunnel type");
+ return this._fail("Unsupported server",
+ "Server wanted tunnels, but doesn't support " +
+ "the notunnel type");
}
},
this._rfb_auth_scheme = 2;
return this._init_msg();
default:
- return this._fail("Unsupported tiny auth scheme: " + authType);
+ return this._fail("Unsupported server",
+ "Unsupported tiny auth scheme: " +
+ authType);
}
}
}
- return this._fail("No supported sub-auth types!");
+ return this._fail("Unsupported server",
+ "No supported sub-auth types!");
},
_negotiate_authentication: function () {
if (this._sock.rQwait("auth reason", 4)) { return false; }
var strlen = this._sock.rQshift32();
var reason = this._sock.rQshiftStr(strlen);
- return this._fail("Auth failure: " + reason);
+ return this._fail("Authentication failure", reason);
case 1: // no auth
if (this._rfb_version >= 3.8) {
return this._negotiate_tight_auth();
default:
- return this._fail("Unsupported auth scheme: " + this._rfb_auth_scheme);
+ return this._fail("Unsupported server",
+ "Unsupported auth scheme: " +
+ this._rfb_auth_scheme);
}
},
var length = this._sock.rQshift32();
if (this._sock.rQwait("SecurityResult reason", length, 8)) { return false; }
var reason = this._sock.rQshiftStr(length);
- return this._fail(reason);
+ return this._fail("Authentication failure", reason);
} else {
return this._fail("Authentication failure");
}
return false;
case 2:
- return this._fail("Too many auth attempts");
+ return this._fail("Too many authentication attempts");
default:
- return this._fail("Unknown SecurityResult");
+ return this._fail("Unsupported server",
+ "Unknown SecurityResult");
}
},
return this._negotiate_server_init();
default:
- return this._fail("Unknown init state: " +
+ return this._fail("Internal error", "Unknown init state: " +
this._rfb_init_state);
}
},
*/
if (!(flags & (1<<31))) {
- return this._fail("Unexpected fence response");
+ return this._fail("Internal error",
+ "Unexpected fence response");
}
// Filter out unsupported flags
this._onXvpInit(this._rfb_xvp_ver);
break;
default:
- this._fail("Disconnected: illegal server XVP message " + xvp_msg);
+ this._fail("Unexpected server message",
+ "Illegal server XVP message " + xvp_msg);
break;
}
return this._handle_xvp_msg();
default:
- this._fail("Disconnected: illegal server message type " + msg_type);
+ this._fail("Unexpected server message", "Type:" + msg_type);
Util.Debug("sock.rQslice(0, 30): " + this._sock.rQslice(0, 30));
return true;
}
'encodingName': this._encNames[this._FBU.encoding]});
if (!this._encNames[this._FBU.encoding]) {
- this._fail("Disconnected: unsupported encoding " +
+ this._fail("Unexpected server message",
+ "Unsupported encoding " +
this._FBU.encoding);
return false;
}
if (this._sock.rQwait("HEXTILE subencoding", this._FBU.bytes)) { return false; }
var subencoding = rQ[rQi]; // Peek
if (subencoding > 30) { // Raw
- this._fail("Disconnected: illegal hextile subencoding " + subencoding);
+ this._fail("Unexpected server message",
+ "Illegal hextile subencoding: " + subencoding);
return false;
}
display_tight: function (isTightPNG) {
if (this._fb_depth === 1) {
- this._fail("Tight protocol handler only implements true color mode");
+ this._fail("Internal error",
+ "Tight protocol handler only implements " +
+ "true color mode");
}
this._FBU.bytes = 1; // compression-control byte
else if (ctl === 0x0A) cmode = "png";
else if (ctl & 0x04) cmode = "filter";
else if (ctl < 0x04) cmode = "copy";
- else return this._fail("Illegal tight compression received, ctl: " + ctl);
+ else return this._fail("Unexpected server message",
+ "Illegal tight compression received, " +
+ "ctl: " + ctl);
if (isTightPNG && (cmode === "filter" || cmode === "copy")) {
- return this._fail("filter/copy received in tightPNG mode");
+ return this._fail("Unexpected server message",
+ "filter/copy received in tightPNG mode");
}
switch (cmode) {
} else {
// Filter 0, Copy could be valid here, but servers don't send it as an explicit filter
// Filter 2, Gradient is valid but not use if jpeg is enabled
- this._fail("Unsupported tight subencoding received, filter: " + filterId);
+ this._fail("Unexpected server message",
+ "Unsupported tight subencoding received, " +
+ "filter: " + filterId);
}
break;
case "copy":
return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
}());
+
+Util.Localisation = {
+ // Currently configured language
+ language: 'en',
+
+ // Configure suitable language based on user preferences
+ setup: function (supportedLanguages) {
+ var userLanguages;
+
+ Util.Localisation.language = 'en'; // Default: US English
+
+ /*
+ * Navigator.languages only available in Chrome (32+) and FireFox (32+)
+ * Fall back to navigator.language for other browsers
+ */
+ if (typeof window.navigator.languages == 'object') {
+ userLanguages = window.navigator.languages;
+ } else {
+ userLanguages = [navigator.language || navigator.userLanguage];
+ }
+
+ for (var i = 0;i < userLanguages.length;i++) {
+ var userLang = userLanguages[i];
+ userLang = userLang.toLowerCase();
+ userLang = userLang.replace("_", "-");
+ userLang = userLang.split("-");
+
+ // Built-in default?
+ if ((userLang[0] === 'en') &&
+ ((userLang[1] === undefined) || (userLang[1] === 'us'))) {
+ return;
+ }
+
+ // First pass: perfect match
+ for (var j = 0;j < supportedLanguages.length;j++) {
+ var supLang = supportedLanguages[j];
+ supLang = supLang.toLowerCase();
+ supLang = supLang.replace("_", "-");
+ supLang = supLang.split("-");
+
+ if (userLang[0] !== supLang[0])
+ continue;
+ if (userLang[1] !== supLang[1])
+ continue;
+
+ Util.Localisation.language = supportedLanguages[j];
+ return;
+ }
+
+ // Second pass: fallback
+ for (var j = 0;j < supportedLanguages.length;j++) {
+ supLang = supportedLanguages[j];
+ supLang = supLang.toLowerCase();
+ supLang = supLang.replace("_", "-");
+ supLang = supLang.split("-");
+
+ if (userLang[0] !== supLang[0])
+ continue;
+ if (supLang[1] !== undefined)
+ continue;
+
+ Util.Localisation.language = supportedLanguages[j];
+ return;
+ }
+ }
+ },
+
+ // Retrieve localised text
+ get: function (id) {
+ if (typeof Language !== 'undefined' && Language[id]) {
+ return Language[id];
+ } else {
+ return id;
+ }
+ },
+
+ // Traverses the DOM and translates relevant fields
+ // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
+ translateDOM: function () {
+ function process(elem, enabled) {
+ function isAnyOf(searchElement, items) {
+ return items.indexOf(searchElement) !== -1;
+ }
+
+ function translateAttribute(elem, attr) {
+ var str = elem.getAttribute(attr);
+ str = Util.Localisation.get(str);
+ elem.setAttribute(attr, str);
+ }
+
+ function translateTextNode(node) {
+ var str = node.data.trim();
+ str = Util.Localisation.get(str);
+ node.data = str;
+ }
+
+ if (elem.hasAttribute("translate")) {
+ if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) {
+ enabled = true;
+ } else if (isAnyOf(elem.getAttribute("translate"), ["no"])) {
+ enabled = false;
+ }
+ }
+
+ if (enabled) {
+ if (elem.hasAttribute("abbr") &&
+ elem.tagName === "TH") {
+ translateAttribute(elem, "abbr");
+ }
+ if (elem.hasAttribute("alt") &&
+ isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) {
+ translateAttribute(elem, "alt");
+ }
+ if (elem.hasAttribute("download") &&
+ isAnyOf(elem.tagName, ["A", "AREA"])) {
+ translateAttribute(elem, "download");
+ }
+ if (elem.hasAttribute("label") &&
+ isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP",
+ "OPTION", "TRACK"])) {
+ translateAttribute(elem, "label");
+ }
+ // FIXME: Should update "lang"
+ if (elem.hasAttribute("placeholder") &&
+ isAnyOf(elem.tagName in ["INPUT", "TEXTAREA"])) {
+ translateAttribute(elem, "placeholder");
+ }
+ if (elem.hasAttribute("title")) {
+ translateAttribute(elem, "title");
+ }
+ if (elem.hasAttribute("value") &&
+ elem.tagName === "INPUT" &&
+ isAnyOf(elem.getAttribute("type"), ["reset", "button"])) {
+ translateAttribute(elem, "value");
+ }
+ }
+
+ for (var i = 0;i < elem.childNodes.length;i++) {
+ node = elem.childNodes[i];
+ if (node.nodeType === node.ELEMENT_NODE) {
+ process(node, enabled);
+ } else if (node.nodeType === node.TEXT_NODE && enabled) {
+ translateTextNode(node);
+ }
+ }
+ }
+
+ process(document.body, true);
+ },
+};
+
/* [module] export default Util; */
},
"homepage": "https://github.com/kanaka/noVNC",
"devDependencies": {
- "ansi": "^0.3.0",
+ "ansi": "^0.3.1",
"babel-plugin-add-module-exports": "^0.2.1",
- "babel-plugin-transform-es2015-modules-commonjs": "^6.14.0",
+ "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
"babelify": "^7.3.0",
"browserify": "^13.1.0",
- "casperjs": "^1.1.0-beta3",
- "chai": "^2.1.0",
- "commander": "^2.8.1",
- "fs-extra": "^0.30.0",
- "karma": "^0.12.31",
+ "casperjs": "^1.1.3",
+ "chai": "^3.5.0",
+ "commander": "^2.9.0",
+ "fs-extra": "^1.0.0",
+ "jsdom": "*",
+ "karma": "^1.3.0",
"karma-chai": "^0.1.0",
- "karma-mocha": "^0.1.10",
- "karma-mocha-reporter": "^1.0.0",
- "karma-phantomjs-launcher": "^1.0.0",
- "karma-sauce-launcher": "^0.2.10",
- "karma-sinon": "^1.0.4",
+ "karma-mocha": "^1.3.0",
+ "karma-mocha-reporter": "^2.2.0",
+ "karma-phantomjs-launcher": "^1.0.2",
+ "karma-sauce-launcher": "^1.0.0",
+ "karma-sinon": "^1.0.5",
"karma-sinon-chai-latest": "^0.1.0",
- "mocha": "^2.1.0",
+ "mocha": "^3.1.2",
+ "node-getopt": "*",
"open": "^0.0.5",
- "phantomjs-prebuilt": "^2.1.4",
- "sinon": "^1.12.2",
- "sinon-chai": "^2.7.0",
+ "phantomjs-prebuilt": "^2.1.13",
+ "po2json": "*",
+ "sinon": "^1.17.6",
+ "sinon-chai": "^2.8.0",
"spooky": "^0.2.5",
- "temp": "^0.8.1",
+ "temp": "^0.8.3",
"through2": "^2.0.1"
},
"dependencies": {
--- /dev/null
+all:
+.PHONY: update-po update-js update-pot
+
+LINGUAS := de el nl sv
+
+VERSION := $(shell grep '"version"' ../package.json | cut -d '"' -f 4)
+
+POFILES := $(addsuffix .po,$(LINGUAS))
+JSFILES := $(addprefix ../app/locale/,$(addsuffix .js,$(LINGUAS)))
+
+update-po: $(POFILES)
+update-js: $(JSFILES)
+
+%.po: noVNC.pot
+ msgmerge --update --lang=$* $@ $<
+../app/locale/%.js: %.po
+ ./po2js $< $@
+
+update-pot:
+ xgettext --output=noVNC.js.pot \
+ --copyright-holder="Various Authors" \
+ --package-name="noVNC" \
+ --package-version="$(VERSION)" \
+ --msgid-bugs-address="novnc@googlegroups.com" \
+ --add-comments=TRANSLATORS: \
+ --sort-by-file \
+ ../app/*.js \
+ ../core/*.js \
+ ../core/input/*.js
+ ./xgettext-html --output=noVNC.html.pot \
+ ../vnc.html
+ msgcat --output-file=noVNC.pot \
+ --sort-by-file noVNC.js.pot noVNC.html.pot
+ rm -f noVNC.js.pot noVNC.html.pot
--- /dev/null
+# German translations for noVNC package
+# German translation for noVNC.
+# Copyright (C) 2016 Various Authors
+# This file is distributed under the same license as the noVNC package.
+# Loek Janssen <loekjanssen@gmail.com>, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: noVNC 0.6.1\n"
+"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
+"POT-Creation-Date: 2016-11-15 08:11+0100\n"
+"PO-Revision-Date: 2016-11-15 07:51+0100\n"
+"Last-Translator: Loek Janssen <loekjanssen@gmail.com>\n"
+"Language-Team: none\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: ../app/ui.js:402
+msgid "Connecting..."
+msgstr "Verbunden..."
+
+#: ../app/ui.js:409
+msgid "Connected (encrypted) to "
+msgstr "Verbunden mit (verschlรผsselt) "
+
+#: ../app/ui.js:411
+msgid "Connected (unencrypted) to "
+msgstr "Verbunden mit (unverschlรผsselt) "
+
+#: ../app/ui.js:416
+msgid "Disconnecting..."
+msgstr "Verbindung trennen..."
+
+#: ../app/ui.js:421
+msgid "Disconnected"
+msgstr "Verbindung zum Server getrennt"
+
+#: ../app/ui.js:1006 ../core/rfb.js:278
+msgid "Must set host and port"
+msgstr "Richten Sie Host und Port ein"
+
+#: ../app/ui.js:1059
+msgid "Password is required"
+msgstr "Passwort ist erforderlich"
+
+#: ../app/ui.js:1272
+msgid ""
+"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen"
+msgstr ""
+"'Clipping-Modus' aktiviert, Scrollbalken in 'IE-Vollbildmodus' werden nicht "
+"unterstรผtzt"
+
+#: ../core/rfb.js:556
+msgid "Disconnect timeout"
+msgstr "Timeout beim trennen"
--- /dev/null
+# Greek translations for noVNC package.
+# Copyright (C) 2016 Various Authors
+# This file is distributed under the same license as the noVNC package.
+# Giannis Kosmas <kosmasgiannis@gmail.com>, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: noVNC 0.6.1\n"
+"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
+"POT-Creation-Date: 2016-11-24 08:53+0200\n"
+"PO-Revision-Date: 2016-11-15 07:51+0100\n"
+"Last-Translator: Giannis Kosmas <kosmasgiannis@gmail.com>\n"
+"Language-Team: none\n"
+"Language: el\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: ../app/ui.js:405
+msgid "Connecting..."
+msgstr "ฮฃฯ
ฮฝฮดฮญฮตฯฮฑฮน..."
+
+#: ../app/ui.js:412
+msgid "Connected (encrypted) to "
+msgstr "ฮฃฯ
ฮฝฮดฮญฮธฮทฮบฮต (ฮบฯฯ
ฯฯฮฟฮณฯฮฑฯฮทฮผฮญฮฝฮฑ) ฮผฮต ฯฮฟ "
+
+#: ../app/ui.js:414
+msgid "Connected (unencrypted) to "
+msgstr "ฮฃฯ
ฮฝฮดฮญฮธฮทฮบฮต (ฮผฮท ฮบฯฯ
ฯฯฮฟฮณฯฮฑฯฮทฮผฮญฮฝฮฑ) ฮผฮต ฯฮฟ "
+
+#: ../app/ui.js:419
+msgid "Disconnecting..."
+msgstr "Aฯฮฟฯฯ
ฮฝฮดฮญฮตฯฮฑฮน..."
+
+#: ../app/ui.js:424
+msgid "Disconnected"
+msgstr "ฮฯฮฟฯฯ
ฮฝฮดฮญฮธฮทฮบฮต"
+
+#: ../app/ui.js:1009 ../core/rfb.js:278
+msgid "Must set host and port"
+msgstr "ฮ ฯฮญฯฮตฮน ฮฝฮฑ ฮฟฯฮนฯฯฮตฮฏ ฯฮฟ ฯฮฝฮฟฮผฮฑ ฮบฮฑฮน ฮท ฯฯฯฯฮฑ ฯฮฟฯ
ฮดฮนฮฑฮบฮฟฮผฮนฯฯฮฎ"
+
+#: ../app/ui.js:1062
+msgid "Password is required"
+msgstr "ฮฯฮฑฮนฯฮตฮฏฯฮฑฮน ฮฟ ฮบฯฮดฮนฮบฯฯ ฯฯฯฯฮฒฮฑฯฮทฯ"
+
+#: ../app/ui.js:1275
+msgid ""
+"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen"
+msgstr ""
+"ฮฯฮฑฯฮผฮฟฮณฮฎ ฮปฮตฮนฯฮฟฯ
ฯฮณฮฏฮฑฯ ฮฑฯฮฟฮบฮฟฯฮฎฯ ฮฑฯฮฟฯ ฮดฮตฮฝ ฯ
ฯฮฟฯฯฮทฯฮฏฮถฮฟฮฝฯฮฑฮน ฮฟฮน ฮปฯฯฮฏฮดฮตฯ ฮบฯฮปฮนฯฮทฯ ฯฮต "
+"ฯฮปฮฎฯฮท ฮฟฮธฯฮฝฮท ฯฯฮฟฮฝ IE"
+
+#: ../core/rfb.js:556
+msgid "Disconnect timeout"
+msgstr "ฮ ฮฑฯฮญฮปฮตฯ
ฯฮท ฯฯฮฟฮฝฮนฮบฮฟฯ ฮฟฯฮฏฮฟฯ
ฮฑฯฮฟฯฯฮฝฮดฮตฯฮทฯ"
+
+#: ../vnc.html:70
+msgid "noVNC encountered an error:"
+msgstr "ฯฮฟ noVNC ฮฑฮฝฯฮนฮผฮตฯฯฯฮนฯฮต ฮญฮฝฮฑ ฯฯฮฌฮปฮผฮฑ:"
+
+#: ../vnc.html:78
+msgid "Hide/Show the control bar"
+msgstr "ฮฯฯฮบฯฯ
ฯฮท/ฮฮผฯฮฌฮฝฮนฯฮท ฮณฯฮฑฮผฮผฮฎฯ ฮตฮปฮญฮณฯฮฟฯ
"
+
+#: ../vnc.html:85
+msgid "Move/Drag Viewport"
+msgstr "ฮฮตฯฮฑฮบฮฏฮฝฮทฯฮท/ฮฃฯฯฯฮนฮผฮฟ ฮฮตฮฑฯฮฟฯ ฯฮตฮดฮฏฮฟฯ
"
+
+#: ../vnc.html:85
+msgid "viewport drag"
+msgstr "ฯฯฯฯฮนฮผฮฟ ฮธฮตฮฑฯฮฟฯ ฯฮตฮดฮฏฮฟฯ
"
+
+#: ../vnc.html:91 ../vnc.html:94 ../vnc.html:97 ../vnc.html:100
+msgid "Active Mouse Button"
+msgstr "ฮฮฝฮตฯฮณฯ ฮ ฮปฮฎฮบฯฯฮฟ ฮ ฮฟฮฝฯฮนฮบฮนฮฟฯ"
+
+#: ../vnc.html:91
+msgid "No mousebutton"
+msgstr "ฮงฯฯฮฏฯ ฮ ฮปฮฎฮบฯฯฮฟ ฮ ฮฟฮฝฯฮนฮบฮนฮฟฯ"
+
+#: ../vnc.html:94
+msgid "Left mousebutton"
+msgstr "ฮฯฮนฯฯฮตฯฯ ฮ ฮปฮฎฮบฯฯฮฟ ฮ ฮฟฮฝฯฮนฮบฮนฮฟฯ"
+
+#: ../vnc.html:97
+msgid "Middle mousebutton"
+msgstr "ฮฮตฯฮฑฮฏฮฟ ฮ ฮปฮฎฮบฯฯฮฟ ฮ ฮฟฮฝฯฮนฮบฮนฮฟฯ"
+
+#: ../vnc.html:100
+msgid "Right mousebutton"
+msgstr "ฮฮตฮพฮฏ ฮ ฮปฮฎฮบฯฯฮฟ ฮ ฮฟฮฝฯฮนฮบฮนฮฟฯ"
+
+#: ../vnc.html:103
+msgid "Keyboard"
+msgstr "ฮ ฮปฮทฮบฯฯฮฟฮปฯฮณฮนฮฟ"
+
+#: ../vnc.html:103
+msgid "Show Keyboard"
+msgstr "ฮฮผฯฮฌฮฝฮนฯฮท ฮ ฮปฮทฮบฯฯฮฟฮปฮฟฮณฮฏฮฟฯ
"
+
+#: ../vnc.html:110
+msgid "Extra keys"
+msgstr "ฮฯฮนฯฮปฮญฮฟฮฝ ฯฮปฮฎฮบฯฯฮฑ"
+
+#: ../vnc.html:110
+msgid "Show Extra Keys"
+msgstr "ฮฮผฯฮฌฮฝฮนฯฮท ฮฯฮนฯฮปฮญฮฟฮฝ ฮ ฮปฮฎฮบฯฯฯฮฝ"
+
+#: ../vnc.html:115
+msgid "Ctrl"
+msgstr "Ctrl"
+
+#: ../vnc.html:115
+msgid "Toggle Ctrl"
+msgstr "ฮฮฝฮฑฮปฮปฮฑฮณฮฎ Ctrl"
+
+#: ../vnc.html:118
+msgid "Alt"
+msgstr "Alt"
+
+#: ../vnc.html:118
+msgid "Toggle Alt"
+msgstr "ฮฮฝฮฑฮปฮปฮฑฮณฮฎ Alt"
+
+#: ../vnc.html:121
+msgid "Send Tab"
+msgstr "ฮฯฮฟฯฯฮฟฮปฮฎ Tab"
+
+#: ../vnc.html:121
+msgid "Tab"
+msgstr "Tab"
+
+#: ../vnc.html:124
+msgid "Esc"
+msgstr "Esc"
+
+#: ../vnc.html:124
+msgid "Send Escape"
+msgstr "ฮฯฮฟฯฯฮฟฮปฮฎ Escape"
+
+#: ../vnc.html:127
+msgid "Ctrl+Alt+Del"
+msgstr "Ctrl+Alt+Del"
+
+#: ../vnc.html:127
+msgid "Send Ctrl-Alt-Del"
+msgstr "ฮฯฮฟฯฯฮฟฮปฮฎ Ctrl-Alt-Del"
+
+#: ../vnc.html:135
+msgid "Shutdown/Reboot"
+msgstr "ฮฮปฮตฮฏฯฮนฮผฮฟ/ฮฯฮฑฮฝฮตฮบฮบฮฏฮฝฮทฯฮท"
+
+#: ../vnc.html:135
+msgid "Shutdown/Reboot..."
+msgstr "ฮฮปฮตฮฏฯฮนฮผฮฟ/ฮฯฮฑฮฝฮตฮบฮบฮฏฮฝฮทฯฮท..."
+
+#: ../vnc.html:141
+msgid "Power"
+msgstr "ฮฯฮตฮฝฮตฯฮณฮฟฯฮฟฮฏฮทฯฮท"
+
+#: ../vnc.html:143
+msgid "Shutdown"
+msgstr "ฮฮปฮตฮฏฯฮนฮผฮฟ"
+
+#: ../vnc.html:144
+msgid "Reboot"
+msgstr "ฮฯฮฑฮฝฮตฮบฮบฮฏฮฝฮทฯฮท"
+
+#: ../vnc.html:145
+msgid "Reset"
+msgstr "ฮฯฮฑฮฝฮฑฯฮฟฯฮฌ"
+
+#: ../vnc.html:150 ../vnc.html:156
+msgid "Clipboard"
+msgstr "ฮ ฯฯฯฮตฮนฯฮฟ"
+
+#: ../vnc.html:160
+msgid "Clear"
+msgstr "ฮฮฑฮธฮฌฯฮนฯฮผฮฑ"
+
+#: ../vnc.html:166
+msgid "Fullscreen"
+msgstr "ฮ ฮปฮฎฯฮทฯ ฮฮธฯฮฝฮท"
+
+#: ../vnc.html:171 ../vnc.html:178
+msgid "Settings"
+msgstr "ฮกฯ
ฮธฮผฮฏฯฮตฮนฯ"
+
+#: ../vnc.html:181
+msgid "Encrypt"
+msgstr "ฮฯฯ
ฯฯฮฟฮณฯฮฌฯฮทฯฮท"
+
+#: ../vnc.html:184
+msgid "True Color"
+msgstr "ฮ ฯฮฑฮณฮผฮฑฯฮนฮบฮฌ ฮงฯฯฮผฮฑฯฮฑ"
+
+#: ../vnc.html:187
+msgid "Local Cursor"
+msgstr "ฮคฮฟฯฮนฮบฯฯ ฮฯฮฟฮผฮญฮฑฯ"
+
+#: ../vnc.html:190
+msgid "Clip to Window"
+msgstr "ฮฯฮฟฮบฮฟฯฮฎ ฯฯฮฟ ฯฯฮนฮฟ ฯฮฟฯ
ฮ ฮฑฯฮฌฮธฯ
ฯฮฟฯ
"
+
+#: ../vnc.html:193
+msgid "Shared Mode"
+msgstr "ฮฮฟฮนฮฝฯฯฯฮทฯฯฮท ฮฮตฮนฯฮฟฯ
ฯฮณฮฏฮฑ"
+
+#: ../vnc.html:196
+msgid "View Only"
+msgstr "ฮฯฮฝฮฟ ฮฮญฮฑฯฮท"
+
+#: ../vnc.html:200
+msgid "Path:"
+msgstr "ฮฮนฮฑฮดฯฮฟฮผฮฎ:"
+
+#: ../vnc.html:204
+msgid "Scaling Mode:"
+msgstr "ฮฮตฮนฯฮฟฯ
ฯฮณฮฏฮฑ ฮฮปฮนฮผฮฌฮบฯฯฮทฯ:"
+
+#: ../vnc.html:206
+msgid "None"
+msgstr "ฮฮฑฮผฮฏฮฑ"
+
+#: ../vnc.html:207
+msgid "Local Scaling"
+msgstr "ฮคฮฟฯฮนฮบฮฎ ฮฮปฮนฮผฮฌฮบฯฯฮท"
+
+#: ../vnc.html:208
+msgid "Local Downscaling"
+msgstr "ฮคฮฟฯฮนฮบฮฎ ฮฃฯ
ฯฯฮฏฮบฮฝฯฯฮท"
+
+#: ../vnc.html:209
+msgid "Remote Resizing"
+msgstr "ฮฯฮฟฮผฮฑฮบฯฯ
ฯฮผฮญฮฝฮท ฮฮปฮปฮฑฮณฮฎ ฮผฮตฮณฮญฮธฮฟฯ
ฯ"
+
+#: ../vnc.html:213
+msgid "Repeater ID:"
+msgstr "Repeater ID:"
+
+#: ../vnc.html:219
+msgid "Style:"
+msgstr "ฮฃฯฯ
ฮป:"
+
+#: ../vnc.html:221
+msgid "default"
+msgstr "ฯฯฮฟฮตฯฮนฮปฮตฮณฮผฮญฮฝฮฟ"
+
+#: ../vnc.html:227
+msgid "Logging:"
+msgstr "ฮฮฑฯฮฑฮณฯฮฑฯฮฎ:"
+
+#: ../vnc.html:234
+msgid "Apply"
+msgstr "ฮฯฮฑฯฮผฮฟฮณฮฎ"
+
+#: ../vnc.html:241 ../vnc.html:271
+msgid "Connect"
+msgstr "ฮฃฯฮฝฮดฮตฯฮท"
+
+#: ../vnc.html:244
+msgid "Disconnect"
+msgstr "ฮฯฮฟฯฯฮฝฮดฮตฯฮท"
+
+#: ../vnc.html:251
+msgid "Connection"
+msgstr "ฮฃฯฮฝฮดฮตฯฮท"
+
+#: ../vnc.html:254
+msgid "Host:"
+msgstr "ฮฮฝฮฟฮผฮฑ ฮดฮนฮฑฮบฮฟฮผฮนฯฯฮฎ:"
+
+#: ../vnc.html:258
+msgid "Port:"
+msgstr "ฮ ฯฯฯฮฑ ฮดฮนฮฑฮบฮฟฮผฮนฯฯฮฎ:"
+
+#: ../vnc.html:262 ../vnc.html:290
+msgid "Password:"
+msgstr "ฮฯฮดฮนฮบฯฯ ฮ ฯฯฯฮฒฮฑฯฮทฯ:"
+
+#: ../vnc.html:266
+msgid "Token:"
+msgstr "ฮฮนฮฑฮบฯฮนฯฮนฮบฯ:"
+
+#: ../vnc.html:294
+msgid "Send Password"
+msgstr "ฮฯฮฟฯฯฮฟฮปฮฎ ฮฯฮดฮนฮบฮฟฯ ฮ ฯฯฯฮฒฮฑฯฮทฯ"
+
+#: ../vnc.html:319
+msgid "Canvas not supported."
+msgstr "ฮฮตฮฝ ฯ
ฯฮฟฯฯฮทฯฮฏฮถฮตฯฮฑฮน ฯฮฟ ฯฯฮฟฮนฯฮตฮฏฮฟ Canvas"
--- /dev/null
+# Dutch translations for noVNC package
+# Nederlandse vertalingen voor het pakket noVNC.
+# Copyright (C) 2016 Various Authors
+# This file is distributed under the same license as the noVNC package.
+# Loek Janssen <loekjanssen@gmail.com>, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: noVNC 0.6.1\n"
+"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
+"POT-Creation-Date: 2016-11-15 08:11+0100\n"
+"PO-Revision-Date: 2016-11-15 07:51+0100\n"
+"Last-Translator: Loek Janssen <loekjanssen@gmail.com>\n"
+"Language-Team: none\n"
+"Language: nl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: ../app/ui.js:402
+msgid "Connecting..."
+msgstr "Verbinden..."
+
+#: ../app/ui.js:409
+msgid "Connected (encrypted) to "
+msgstr "Verbonden (versleuteld) met "
+
+#: ../app/ui.js:411
+msgid "Connected (unencrypted) to "
+msgstr "Verbonden (onversleuteld) met "
+
+#: ../app/ui.js:416
+msgid "Disconnecting..."
+msgstr "Verbinding verbreken..."
+
+#: ../app/ui.js:421
+msgid "Disconnected"
+msgstr "Verbinding verbroken"
+
+#: ../app/ui.js:1006 ../core/rfb.js:278
+msgid "Must set host and port"
+msgstr "Host en poort moeten worden ingesteld"
+
+#: ../app/ui.js:1059
+msgid "Password is required"
+msgstr "Wachtwoord is vereist"
+
+#: ../app/ui.js:1272
+msgid ""
+"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen"
+msgstr ""
+"''Clipping mode' ingeschakeld, omdat schuifbalken in volledige-scherm-modus "
+"in IE niet worden ondersteund"
+
+#: ../core/rfb.js:556
+msgid "Disconnect timeout"
+msgstr "Timeout tijdens verbreken van verbinding"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Various Authors
+# This file is distributed under the same license as the noVNC package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: noVNC 0.6.1\n"
+"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
+"POT-Creation-Date: 2016-11-15 19:32+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../app/ui.js:405
+msgid "Connecting..."
+msgstr ""
+
+#: ../app/ui.js:412
+msgid "Connected (encrypted) to "
+msgstr ""
+
+#: ../app/ui.js:414
+msgid "Connected (unencrypted) to "
+msgstr ""
+
+#: ../app/ui.js:419
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../app/ui.js:424
+msgid "Disconnected"
+msgstr ""
+
+#: ../app/ui.js:1009 ../core/rfb.js:278
+msgid "Must set host and port"
+msgstr ""
+
+#: ../app/ui.js:1062
+msgid "Password is required"
+msgstr ""
+
+#: ../app/ui.js:1275
+msgid ""
+"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen"
+msgstr ""
+
+#: ../core/rfb.js:556
+msgid "Disconnect timeout"
+msgstr ""
+
+#: ../vnc.html:70
+msgid "noVNC encountered an error:"
+msgstr ""
+
+#: ../vnc.html:78
+msgid "Hide/Show the control bar"
+msgstr ""
+
+#: ../vnc.html:85
+msgid "Move/Drag Viewport"
+msgstr ""
+
+#: ../vnc.html:85
+msgid "viewport drag"
+msgstr ""
+
+#: ../vnc.html:91 ../vnc.html:94 ../vnc.html:97 ../vnc.html:100
+msgid "Active Mouse Button"
+msgstr ""
+
+#: ../vnc.html:91
+msgid "No mousebutton"
+msgstr ""
+
+#: ../vnc.html:94
+msgid "Left mousebutton"
+msgstr ""
+
+#: ../vnc.html:97
+msgid "Middle mousebutton"
+msgstr ""
+
+#: ../vnc.html:100
+msgid "Right mousebutton"
+msgstr ""
+
+#: ../vnc.html:103
+msgid "Keyboard"
+msgstr ""
+
+#: ../vnc.html:103
+msgid "Show Keyboard"
+msgstr ""
+
+#: ../vnc.html:110
+msgid "Extra keys"
+msgstr ""
+
+#: ../vnc.html:110
+msgid "Show Extra Keys"
+msgstr ""
+
+#: ../vnc.html:115
+msgid "Ctrl"
+msgstr ""
+
+#: ../vnc.html:115
+msgid "Toggle Ctrl"
+msgstr ""
+
+#: ../vnc.html:118
+msgid "Alt"
+msgstr ""
+
+#: ../vnc.html:118
+msgid "Toggle Alt"
+msgstr ""
+
+#: ../vnc.html:121
+msgid "Send Tab"
+msgstr ""
+
+#: ../vnc.html:121
+msgid "Tab"
+msgstr ""
+
+#: ../vnc.html:124
+msgid "Esc"
+msgstr ""
+
+#: ../vnc.html:124
+msgid "Send Escape"
+msgstr ""
+
+#: ../vnc.html:127
+msgid "Ctrl+Alt+Del"
+msgstr ""
+
+#: ../vnc.html:127
+msgid "Send Ctrl-Alt-Del"
+msgstr ""
+
+#: ../vnc.html:135
+msgid "Shutdown/Reboot"
+msgstr ""
+
+#: ../vnc.html:135
+msgid "Shutdown/Reboot..."
+msgstr ""
+
+#: ../vnc.html:141
+msgid "Power"
+msgstr ""
+
+#: ../vnc.html:143
+msgid "Shutdown"
+msgstr ""
+
+#: ../vnc.html:144
+msgid "Reboot"
+msgstr ""
+
+#: ../vnc.html:145
+msgid "Reset"
+msgstr ""
+
+#: ../vnc.html:150 ../vnc.html:156
+msgid "Clipboard"
+msgstr ""
+
+#: ../vnc.html:160
+msgid "Clear"
+msgstr ""
+
+#: ../vnc.html:166
+msgid "Fullscreen"
+msgstr ""
+
+#: ../vnc.html:171 ../vnc.html:178
+msgid "Settings"
+msgstr ""
+
+#: ../vnc.html:181
+msgid "Encrypt"
+msgstr ""
+
+#: ../vnc.html:184
+msgid "True Color"
+msgstr ""
+
+#: ../vnc.html:187
+msgid "Local Cursor"
+msgstr ""
+
+#: ../vnc.html:190
+msgid "Clip to Window"
+msgstr ""
+
+#: ../vnc.html:193
+msgid "Shared Mode"
+msgstr ""
+
+#: ../vnc.html:196
+msgid "View Only"
+msgstr ""
+
+#: ../vnc.html:200
+msgid "Path:"
+msgstr ""
+
+#: ../vnc.html:204
+msgid "Scaling Mode:"
+msgstr ""
+
+#: ../vnc.html:206
+msgid "None"
+msgstr ""
+
+#: ../vnc.html:207
+msgid "Local Scaling"
+msgstr ""
+
+#: ../vnc.html:208
+msgid "Local Downscaling"
+msgstr ""
+
+#: ../vnc.html:209
+msgid "Remote Resizing"
+msgstr ""
+
+#: ../vnc.html:213
+msgid "Repeater ID:"
+msgstr ""
+
+#: ../vnc.html:219
+msgid "Style:"
+msgstr ""
+
+#: ../vnc.html:221
+msgid "default"
+msgstr ""
+
+#: ../vnc.html:227
+msgid "Logging:"
+msgstr ""
+
+#: ../vnc.html:234
+msgid "Apply"
+msgstr ""
+
+#: ../vnc.html:241 ../vnc.html:271
+msgid "Connect"
+msgstr ""
+
+#: ../vnc.html:244
+msgid "Disconnect"
+msgstr ""
+
+#: ../vnc.html:251
+msgid "Connection"
+msgstr ""
+
+#: ../vnc.html:254
+msgid "Host:"
+msgstr ""
+
+#: ../vnc.html:258
+msgid "Port:"
+msgstr ""
+
+#: ../vnc.html:262 ../vnc.html:290
+msgid "Password:"
+msgstr ""
+
+#: ../vnc.html:266
+msgid "Token:"
+msgstr ""
+
+#: ../vnc.html:294
+msgid "Send Password"
+msgstr ""
+
+#: ../vnc.html:319
+msgid "Canvas not supported."
+msgstr ""
--- /dev/null
+#!/usr/bin/env node
+/*
+ * ps2js: gettext .po to noVNC .js converter
+ * Copyright (C) 2016 Pierre Ossman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+var getopt = require('node-getopt');
+var fs = require('fs');
+var po2json = require("po2json");
+
+opt = getopt.create([
+ ['h' , 'help' , 'display this help'],
+]).bindHelp().parseSystem();
+
+if (opt.argv.length != 2) {
+ console.error("Incorrect number of arguments given");
+ process.exit(1);
+}
+
+var data = po2json.parseFileSync(opt.argv[0]);
+
+var output =
+"/*\n" +
+" * Translations for " + data[""]["language"] + "\n" +
+" *\n" +
+" * This file was autotomatically generated from " + opt.argv[0] + "\n" +
+" * DO NOT EDIT!\n" +
+" */\n" +
+"\n" +
+"Language = {\n";
+
+for (msgid in data) {
+ if (msgid === "")
+ continue;
+
+ msgstr = data[msgid][1];
+ output += " " + JSON.stringify(msgid) + ": " +
+ JSON.stringify(msgstr) + ",\n";
+}
+
+output += "};\n";
+
+fs.writeFileSync(opt.argv[1], output);
--- /dev/null
+# Swedish translations for noVNC package
+# Svenska รถversรคttningar fรถr paket noVNC.
+# Copyright (C) 2016 Various Authors
+# This file is distributed under the same license as the noVNC package.
+# Samuel Mannehed <samuel@cendio.se>, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: noVNC 0.6.1\n"
+"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
+"POT-Creation-Date: 2016-11-15 19:32+0100\n"
+"PO-Revision-Date: 2016-11-15 07:51+0100\n"
+"Last-Translator: Pierre Ossman <pierre@ossman.eu>\n"
+"Language-Team: none\n"
+"Language: sv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: ../app/ui.js:405
+msgid "Connecting..."
+msgstr "Ansluter..."
+
+#: ../app/ui.js:412
+msgid "Connected (encrypted) to "
+msgstr "Ansluten (krypterat) till "
+
+#: ../app/ui.js:414
+msgid "Connected (unencrypted) to "
+msgstr "Ansluten (okrypterat) till "
+
+#: ../app/ui.js:419
+msgid "Disconnecting..."
+msgstr "Kopplar ner..."
+
+#: ../app/ui.js:424
+msgid "Disconnected"
+msgstr "Frรฅnkopplad"
+
+#: ../app/ui.js:1009 ../core/rfb.js:278
+msgid "Must set host and port"
+msgstr "Du mรฅste specifiera en host och port"
+
+#: ../app/ui.js:1062
+msgid "Password is required"
+msgstr "Lรถsenord krรคvs"
+
+#: ../app/ui.js:1275
+msgid ""
+"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen"
+msgstr ""
+"Tvingar 'Clipping mode' eftersom skrollning inte stรถdjs av IE i fullskรคrm"
+
+#: ../core/rfb.js:556
+msgid "Disconnect timeout"
+msgstr "Det tog fรถr lรฅng tid att koppla ner"
+
+#: ../vnc.html:70
+msgid "noVNC encountered an error:"
+msgstr "noVNC stรถtte pรฅ ett problem:"
+
+#: ../vnc.html:78
+msgid "Hide/Show the control bar"
+msgstr "Gรถm/Visa kontrollbaren"
+
+#: ../vnc.html:85
+msgid "Move/Drag Viewport"
+msgstr "Flytta/Dra Vyn"
+
+#: ../vnc.html:85
+msgid "viewport drag"
+msgstr "dra vy"
+
+#: ../vnc.html:91 ../vnc.html:94 ../vnc.html:97 ../vnc.html:100
+msgid "Active Mouse Button"
+msgstr "Aktiv musknapp"
+
+#: ../vnc.html:91
+msgid "No mousebutton"
+msgstr "Ingen musknapp"
+
+#: ../vnc.html:94
+msgid "Left mousebutton"
+msgstr "Vรคnster musknapp"
+
+#: ../vnc.html:97
+msgid "Middle mousebutton"
+msgstr "Mitten-musknapp"
+
+#: ../vnc.html:100
+msgid "Right mousebutton"
+msgstr "Hรถger musknapp"
+
+#: ../vnc.html:103
+msgid "Keyboard"
+msgstr "Tangentbord"
+
+#: ../vnc.html:103
+msgid "Show Keyboard"
+msgstr "Visa Tangentbord"
+
+#: ../vnc.html:110
+msgid "Extra keys"
+msgstr "Extraknappar"
+
+#: ../vnc.html:110
+msgid "Show Extra Keys"
+msgstr "Visa Extraknappar"
+
+#: ../vnc.html:115
+msgid "Ctrl"
+msgstr "Ctrl"
+
+#: ../vnc.html:115
+msgid "Toggle Ctrl"
+msgstr "Vรคxla Ctrl"
+
+#: ../vnc.html:118
+msgid "Alt"
+msgstr "Alt"
+
+#: ../vnc.html:118
+msgid "Toggle Alt"
+msgstr "Vรคxla Alt"
+
+#: ../vnc.html:121
+msgid "Send Tab"
+msgstr "Skicka Tab"
+
+#: ../vnc.html:121
+msgid "Tab"
+msgstr "Tab"
+
+#: ../vnc.html:124
+msgid "Esc"
+msgstr "Esc"
+
+#: ../vnc.html:124
+msgid "Send Escape"
+msgstr "Skicka Escape"
+
+#: ../vnc.html:127
+msgid "Ctrl+Alt+Del"
+msgstr "Ctrl+Alt+Del"
+
+#: ../vnc.html:127
+msgid "Send Ctrl-Alt-Del"
+msgstr "Skicka Ctrl-Alt-Del"
+
+#: ../vnc.html:135
+msgid "Shutdown/Reboot"
+msgstr "Stรคng av/Boota om"
+
+#: ../vnc.html:135
+msgid "Shutdown/Reboot..."
+msgstr "Stรคng av/Boota om..."
+
+#: ../vnc.html:141
+msgid "Power"
+msgstr "Strรถm"
+
+#: ../vnc.html:143
+msgid "Shutdown"
+msgstr "Stรคng av"
+
+#: ../vnc.html:144
+msgid "Reboot"
+msgstr "Boota om"
+
+#: ../vnc.html:145
+msgid "Reset"
+msgstr "ร
terstรคll"
+
+#: ../vnc.html:150 ../vnc.html:156
+msgid "Clipboard"
+msgstr "Urklipp"
+
+#: ../vnc.html:160
+msgid "Clear"
+msgstr "Rensa"
+
+#: ../vnc.html:166
+msgid "Fullscreen"
+msgstr "Fullskรคrm"
+
+#: ../vnc.html:171 ../vnc.html:178
+msgid "Settings"
+msgstr "Instรคllningar"
+
+#: ../vnc.html:181
+msgid "Encrypt"
+msgstr "Kryptera"
+
+#: ../vnc.html:184
+msgid "True Color"
+msgstr "Fullfรคrg"
+
+#: ../vnc.html:187
+msgid "Local Cursor"
+msgstr "Lokal Muspekare"
+
+#: ../vnc.html:190
+msgid "Clip to Window"
+msgstr "Begrรคnsa till Fรถnster"
+
+#: ../vnc.html:193
+msgid "Shared Mode"
+msgstr "Delat Lรคge"
+
+#: ../vnc.html:196
+msgid "View Only"
+msgstr "Endast Visning"
+
+#: ../vnc.html:200
+msgid "Path:"
+msgstr "Sรถkvรคg:"
+
+#: ../vnc.html:204
+msgid "Scaling Mode:"
+msgstr "Skalningslรคge:"
+
+#: ../vnc.html:206
+msgid "None"
+msgstr "Ingen"
+
+#: ../vnc.html:207
+msgid "Local Scaling"
+msgstr "Lokal Skalning"
+
+#: ../vnc.html:208
+msgid "Local Downscaling"
+msgstr "Lokal Nedskalning"
+
+#: ../vnc.html:209
+msgid "Remote Resizing"
+msgstr "รndra Storlek"
+
+#: ../vnc.html:213
+msgid "Repeater ID:"
+msgstr "Repeater-ID:"
+
+#: ../vnc.html:219
+msgid "Style:"
+msgstr "Stil:"
+
+#: ../vnc.html:221
+msgid "default"
+msgstr "standard"
+
+#: ../vnc.html:227
+msgid "Logging:"
+msgstr "Loggning:"
+
+#: ../vnc.html:234
+msgid "Apply"
+msgstr "Verkstรคll"
+
+#: ../vnc.html:241 ../vnc.html:271
+msgid "Connect"
+msgstr "Anslut"
+
+#: ../vnc.html:244
+msgid "Disconnect"
+msgstr "Koppla frรฅn"
+
+#: ../vnc.html:251
+msgid "Connection"
+msgstr "Uppkoppling"
+
+#: ../vnc.html:254
+msgid "Host:"
+msgstr "Vรคrd:"
+
+#: ../vnc.html:258
+msgid "Port:"
+msgstr "Port:"
+
+#: ../vnc.html:262 ../vnc.html:290
+msgid "Password:"
+msgstr "Lรถsenord:"
+
+#: ../vnc.html:266
+msgid "Token:"
+msgstr "Token:"
+
+#: ../vnc.html:294
+msgid "Send Password"
+msgstr "Skicka Lรถsenord"
+
+#: ../vnc.html:319
+msgid "Canvas not supported."
+msgstr "Canvas stรถds ej"
--- /dev/null
+#!/usr/bin/env node
+/*
+ * xgettext-html: HTML gettext parser
+ * Copyright (C) 2016 Pierre Ossman
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ */
+
+var getopt = require('node-getopt');
+
+var jsdom = require("jsdom");
+var fs = require("fs");
+
+opt = getopt.create([
+ ['o' , 'output=FILE' , 'write output to specified file'],
+ ['h' , 'help' , 'display this help'],
+]).bindHelp().parseSystem();
+
+var strings = {};
+
+function addString(str, location) {
+ if (str.length == 0) {
+ return;
+ }
+
+ if (strings[str] === undefined) {
+ strings[str] = {}
+ }
+ strings[str][location] = null;
+}
+
+// See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
+function process(elem, locator, enabled) {
+ function isAnyOf(searchElement, items) {
+ return items.indexOf(searchElement) !== -1;
+ }
+
+ if (elem.hasAttribute("translate")) {
+ if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) {
+ enabled = true;
+ } else if (isAnyOf(elem.getAttribute("translate"), ["no"])) {
+ enabled = false;
+ }
+ }
+
+ if (enabled) {
+ if (elem.hasAttribute("abbr") &&
+ elem.tagName === "TH") {
+ addString(elem.getAttribute("abbr"), locator(elem));
+ }
+ if (elem.hasAttribute("alt") &&
+ isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) {
+ addString(elem.getAttribute("alt"), locator(elem));
+ }
+ if (elem.hasAttribute("download") &&
+ isAnyOf(elem.tagName, ["A", "AREA"])) {
+ addString(elem.getAttribute("download"), locator(elem));
+ }
+ if (elem.hasAttribute("label") &&
+ isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP",
+ "OPTION", "TRACK"])) {
+ addString(elem.getAttribute("label"), locator(elem));
+ }
+ if (elem.hasAttribute("placeholder") &&
+ isAnyOf(elem.tagName in ["INPUT", "TEXTAREA"])) {
+ addString(elem.getAttribute("placeholder"), locator(elem));
+ }
+ if (elem.hasAttribute("title")) {
+ addString(elem.getAttribute("title"), locator(elem));
+ }
+ if (elem.hasAttribute("value") &&
+ elem.tagName === "INPUT" &&
+ isAnyOf(elem.getAttribute("type"), ["reset", "button"])) {
+ addString(elem.getAttribute("value"), locator(elem));
+ }
+ }
+
+ for (var i = 0;i < elem.childNodes.length;i++) {
+ node = elem.childNodes[i];
+ if (node.nodeType === node.ELEMENT_NODE) {
+ process(node, locator, enabled);
+ } else if (node.nodeType === node.TEXT_NODE && enabled) {
+ addString(node.data.trim(), locator(node));
+ }
+ }
+}
+
+for (var i = 0;i < opt.argv.length;i++) {
+ var file;
+
+ fn = opt.argv[i];
+ file = fs.readFileSync(fn, "utf8");
+ doc = jsdom.jsdom(file);
+
+ locator = function (elem) {
+ offset = jsdom.nodeLocation(elem).start;
+ line = file.slice(0, offset).split("\n").length;
+ return fn + ":" + line;
+ };
+
+ process(doc.body, locator, true);
+}
+
+var output = "";
+
+for (str in strings) {
+ output += "#:";
+ for (location in strings[str]) {
+ output += " " + location;
+ }
+ output += "\n";
+
+ output += "msgid " + JSON.stringify(str) + "\n";
+ output += "msgstr \"\"\n";
+ output += "\n";
+}
+
+fs.writeFileSync(opt.options.output, output);
template.header += "\n" + template.script_tag(get_path('node_modules/mocha/mocha.js'));
template.header += "\n" + template.script_tag(get_path('node_modules/sinon/pkg/sinon.js'));
template.header += "\n" + template.script_tag(get_path('node_modules/sinon-chai/lib/sinon-chai.js'));
- template.header += "\n" + template.script_tag(get_path('node_modules/sinon-chai/lib/sinon-chai.js'));
template.header += "\n<script>mocha.setup('bdd');</script>";
it('should map characters which aren\'t in Latin1 *or* Windows-1252 to keysyms', function() {
expect(keysyms.fromUnicode('ลต'.charCodeAt())).to.have.property('keysym', 0x1000175);
});
- it('should return undefined for unknown codepoints', function() {
- expect(keysyms.fromUnicode('\n'.charCodeAt())).to.be.undefined;
- expect(keysyms.fromUnicode('\u1F686'.charCodeAt())).to.be.undefined;
+ it('should map unknown codepoints to the Unicode range', function() {
+ expect(keysyms.fromUnicode('\n'.charCodeAt())).to.have.property('keysym', 0x100000a);
+ expect(keysyms.fromUnicode('\u262D'.charCodeAt())).to.have.property('keysym', 0x100262d);
+ });
+ // This requires very recent versions of most browsers... skipping for now
+ it.skip('should map UCS-4 codepoints to the Unicode range', function() {
+ //expect(keysyms.fromUnicode('\u{1F686}'.codePointAt())).to.have.property('keysym', 0x101f686);
});
});
it('should clear the disconnect timer if the state is not "disconnecting"', function () {
var spy = sinon.spy();
client._disconnTimer = setTimeout(spy, 50);
- client._updateConnectionState('connected');
+ client._updateConnectionState('connecting');
this.clock.tick(51);
expect(spy).to.not.have.been.called;
expect(client._disconnTimer).to.be.null;
it('should call the updateState callback', function () {
client.set_onUpdateState(sinon.spy());
- client._updateConnectionState('a specific state');
+ client._updateConnectionState('connecting');
var spy = client.get_onUpdateState();
expect(spy).to.have.been.calledOnce;
- expect(spy.args[0][1]).to.equal('a specific state');
+ expect(spy.args[0][1]).to.equal('connecting');
});
it('should set the rfb_connection_state', function () {
- client._updateConnectionState('a specific state');
- expect(client._rfb_connection_state).to.equal('a specific state');
+ client._rfb_connection_state = 'disconnecting';
+ client._updateConnectionState('disconnected');
+ expect(client._rfb_connection_state).to.equal('disconnected');
});
it('should not change the state when we are disconnected', function () {
client._rfb_connection_state = 'disconnected';
- client._updateConnectionState('a specific state');
- expect(client._rfb_connection_state).to.not.equal('a specific state');
+ client._updateConnectionState('connecting');
+ expect(client._rfb_connection_state).to.not.equal('connecting');
});
it('should ignore state changes to the same state', function () {
client.set_onUpdateState(sinon.spy());
- client._rfb_connection_state = 'a specific state';
- client._updateConnectionState('a specific state');
+ client._rfb_connection_state = 'connecting';
+ client._updateConnectionState('connecting');
+ var spy = client.get_onUpdateState();
+ expect(spy).to.not.have.been.called;
+ });
+
+ it('should ignore illegal state changes', function () {
+ client.set_onUpdateState(sinon.spy());
+ client._rfb_connection_state = 'connected';
+ client._updateConnectionState('disconnected');
+ expect(client._rfb_connection_state).to.not.equal('disconnected');
var spy = client.get_onUpdateState();
expect(spy).to.not.have.been.called;
});
});
it('should set disconnect_reason', function () {
+ client._rfb_connection_state = 'connected';
client._fail('a reason');
expect(client._rfb_disconnect_reason).to.equal('a reason');
});
+ it('should not include details in disconnect_reason', function () {
+ client._rfb_connection_state = 'connected';
+ client._fail('a reason', 'details');
+ expect(client._rfb_disconnect_reason).to.equal('a reason');
+ });
+
it('should result in disconnect callback with message when reason given', function () {
+ client._rfb_connection_state = 'connected';
client.set_onDisconnected(sinon.spy());
client._fail('a reason');
var spy = client.get_onDisconnected();
it('should call the updateState callback before the disconnect callback', function () {
client.set_onDisconnected(sinon.spy());
client.set_onUpdateState(sinon.spy());
- client._rfb_connection_state = 'other state';
+ client._rfb_connection_state = 'disconnecting';
client._updateConnectionState('disconnected');
var updateStateSpy = client.get_onUpdateState();
var disconnectSpy = client.get_onDisconnected();
client._sock._websocket._receive_data(failure_data);
expect(client._fail).to.have.been.calledOnce;
- expect(client._fail).to.have.been.calledWith('Security failure: whoops');
+ expect(client._fail).to.have.been.calledWith(
+ 'Error while negotiating with server','Security failure: whoops');
});
it('should transition to the Authentication state and continue on successful negotiation', function () {
sinon.spy(client, '_fail');
client._sock._websocket._receive_data(new Uint8Array(data));
- expect(client._fail).to.have.been.calledWith('Auth failure: Whoopsies');
+ expect(client._fail).to.have.been.calledWith(
+ 'Authentication failure', 'Whoopsies');
});
it('should transition straight to SecurityResult on "no auth" (1) for versions >= 3.8', function () {
sinon.spy(client, '_fail');
var failure_data = [0, 0, 0, 1, 0, 0, 0, 6, 119, 104, 111, 111, 112, 115];
client._sock._websocket._receive_data(new Uint8Array(failure_data));
- expect(client._fail).to.have.been.calledWith('whoops');
+ expect(client._fail).to.have.been.calledWith(
+ 'Authentication failure', 'whoops');
});
it('should fail on an error code of 1 with a standard message for version < 3.8', function () {
expect(client._rfb_connection_state).to.equal('disconnected');
});
- it('should transition to failed if we get a close event from any non-"disconnection" state', function () {
+ it('should fail if we get a close event while connecting', function () {
sinon.spy(client, "_fail");
client.connect('host', 8675);
- client._rfb_connection_state = 'connected';
+ client._rfb_connection_state = 'connecting';
+ client._sock._websocket.close();
+ expect(client._fail).to.have.been.calledOnce;
+ });
+
+ it('should fail if we get a close event while disconnected', function () {
+ sinon.spy(client, "_fail");
+ client.connect('host', 8675);
+ client._rfb_connection_state = 'disconnected';
client._sock._websocket.close();
expect(client._fail).to.have.been.calledOnce;
});
});
});
+ describe('language selection', function () {
+ var origNavigator;
+ beforeEach(function () {
+ // window.navigator is a protected read-only property in many
+ // environments, so we need to redefine it whilst running these
+ // tests.
+ origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
+ if (origNavigator === undefined) {
+ // Object.getOwnPropertyDescriptor() doesn't work
+ // properly in any version of IE
+ this.skip();
+ }
+
+ Object.defineProperty(window, "navigator", {value: {}});
+ if (window.navigator.languages !== undefined) {
+ // Object.defineProperty() doesn't work properly in old
+ // versions of Chrome
+ this.skip();
+ }
+
+ window.navigator.languages = [];
+ });
+ afterEach(function () {
+ Object.defineProperty(window, "navigator", origNavigator);
+ });
+
+ it('should use English by default', function() {
+ expect(Util.Localisation.language).to.equal('en');
+ });
+ it('should use English if no user language matches', function() {
+ window.navigator.languages = ["nl", "de"];
+ Util.Localisation.setup(["es", "fr"]);
+ expect(Util.Localisation.language).to.equal('en');
+ });
+ it('should use the most preferred user language', function() {
+ window.navigator.languages = ["nl", "de", "fr"];
+ Util.Localisation.setup(["es", "fr", "de"]);
+ expect(Util.Localisation.language).to.equal('de');
+ });
+ it('should prefer sub-languages languages', function() {
+ window.navigator.languages = ["pt-BR"];
+ Util.Localisation.setup(["pt", "pt-BR"]);
+ expect(Util.Localisation.language).to.equal('pt-BR');
+ });
+ it('should fall back to language "parents"', function() {
+ window.navigator.languages = ["pt-BR"];
+ Util.Localisation.setup(["fr", "pt", "de"]);
+ expect(Util.Localisation.language).to.equal('pt');
+ });
+ it('should not use specific language when user asks for a generic language', function() {
+ window.navigator.languages = ["pt", "de"];
+ Util.Localisation.setup(["fr", "pt-BR", "de"]);
+ expect(Util.Localisation.language).to.equal('de');
+ });
+ it('should handle underscore as a separator', function() {
+ window.navigator.languages = ["pt-BR"];
+ Util.Localisation.setup(["pt_BR"]);
+ expect(Util.Localisation.language).to.equal('pt_BR');
+ });
+ it('should handle difference in case', function() {
+ window.navigator.languages = ["pt-br"];
+ Util.Localisation.setup(["pt-BR"]);
+ expect(Util.Localisation.language).to.equal('pt-BR');
+ });
+ });
+
// TODO(directxman12): test the conf_default and conf_defaults methods
// TODO(directxman12): test decodeUTF8
// TODO(directxman12): test the event methods (addEvent, removeEvent, stopEvent)
"\n" +
" function lookup(k) { return k ? {keysym: k, keyname: keynames ? keynames[k] : k} : undefined; }\n" +
" return {\n" +
-" fromUnicode : function(u) { return lookup(codepoints[u]); },\n" +
+" fromUnicode : function(u) {\n" +
+" var keysym = codepoints[u];\n" +
+" if (keysym === undefined) {\n" +
+" keysym = 0x01000000 | u;\n" +
+" }\n" +
+" return lookup(keysym);\n" +
+" },\n" +
" lookup : lookup\n" +
" };\n" +
"})();\n";
</head>
<body>
+
+ <div id="noVNC_fallback_error">
+ <div>noVNC encountered an error:</div>
+ <br>
+ <div id="noVNC_fallback_errormsg"></div>
+ </div>
+
<!-- noVNC Control Bar -->
<div id="noVNC_control_bar_anchor" class="noVNC_vcenter">
<div class="noVNC_scroll">
- <h1 class="noVNC_logo"><span>no</span><br />VNC</h1>
+ <h1 class="noVNC_logo" translate="no"><span>no</span><br />VNC</h1>
<!-- Drag/Pan the viewport -->
<input type="image" alt="viewport drag" src="app/images/drag.svg"
</div>
</div>
+ <!-- Transition Screens -->
+ <div id="noVNC_transition">
+ <div id="noVNC_transition_text"></div>
+ <div class="noVNC_spinner"></div>
+ </div>
+
<div id="noVNC_container">
- <h1 id="noVNC_logo" class="noVNC_logo"><span>no</span><br />VNC</h1>
+ <h1 id="noVNC_logo" class="noVNC_logo" translate="no"><span>no</span><br />VNC</h1>
<!-- HTML5 Canvas -->
<div id="noVNC_screen">
WebUtil.load_scripts({
'core': ["base64.js", "websock.js", "des.js", "input/keysymdef.js",
"input/xtscancodes.js", "input/util.js", "input/devices.js",
- "display.js", "inflator.js", "rfb.js", "input/keysym.js"],
- 'app': ["webutil.js"]});
+ "display.js", "inflator.js", "rfb.js", "input/keysym.js"]});
var rfb;
var resizeTimeout;
}
function updateState(rfb, state, oldstate) {
var cad = document.getElementById('sendCtrlAltDelButton');
- var encrypt = (rfb && rfb.get_encrypt()) ? 'encrypted' : 'unencrypted';
switch (state) {
case 'connecting':
status("Connecting", "normal");
break;
case 'connected':
- status("Connected (" + encrypt + ") to: " + desktopName, "normal");
+ if (rfb && rfb.get_encrypt()) {
+ status("Connected (encrypted) to " +
+ desktopName, "normal");
+ } else {
+ status("Connected (unencrypted) to " +
+ desktopName, "normal");
+ }
break;
case 'disconnecting':
status("Disconnecting", "normal");