From 92c8a91964313e51008c6c9bd73234d508d2584b Mon Sep 17 00:00:00 2001 From: Bubble Date: Wed, 24 Apr 2024 22:54:24 +0800 Subject: [PATCH 01/22] Update zh_CN.po (#1851) Update Chinese translation --- po/zh_CN.po | 132 ++++++++++++++++++++++++++-------------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/po/zh_CN.po b/po/zh_CN.po index ede9d4414..caae28504 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -15,58 +15,42 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../app/ui.js:395 +#: ../app/ui.js:430 msgid "Connecting..." msgstr "连接中..." -#: ../app/ui.js:402 -msgid "Disconnecting..." -msgstr "正在断开连接..." - -#: ../app/ui.js:408 -msgid "Reconnecting..." -msgstr "重新连接中..." - -#: ../app/ui.js:413 -msgid "Internal error" -msgstr "内部错误" - -#: ../app/ui.js:1015 -msgid "Must set host" -msgstr "请提供主机名" - -#: ../app/ui.js:1097 +#: ../app/ui.js:438 msgid "Connected (encrypted) to " -msgstr "已连接到(加密)" +msgstr "已连接(已加密)到" -#: ../app/ui.js:1099 +#: ../app/ui.js:440 msgid "Connected (unencrypted) to " -msgstr "已连接到(未加密)" +msgstr "已连接(未加密)到" -#: ../app/ui.js:1120 -msgid "Something went wrong, connection is closed" -msgstr "发生错误,连接已关闭" - -#: ../app/ui.js:1123 -msgid "Failed to connect to server" -msgstr "无法连接到服务器" +#: ../app/ui.js:446 +msgid "Disconnecting..." +msgstr "正在断开连接..." -#: ../app/ui.js:1133 +#: ../app/ui.js:450 msgid "Disconnected" msgstr "已断开连接" -#: ../app/ui.js:1146 -msgid "New connection has been rejected with reason: " -msgstr "连接被拒绝,原因:" +#: ../app/ui.js:1052 ../core/rfb.js:248 +msgid "Must set host" +msgstr "必须设置主机" -#: ../app/ui.js:1149 -msgid "New connection has been rejected" -msgstr "连接被拒绝" +#: ../app/ui.js:1101 +msgid "Reconnecting..." +msgstr "重新连接中..." -#: ../app/ui.js:1170 +#: ../app/ui.js:1140 msgid "Password is required" msgstr "请提供密码" +#: ../core/rfb.js:548 +msgid "Disconnect timeout" +msgstr "超时断开" + #: ../vnc.html:89 msgid "noVNC encountered an error:" msgstr "noVNC 遇到一个错误:" @@ -77,31 +61,31 @@ msgstr "显示/隐藏控制栏" #: ../vnc.html:106 msgid "Move/Drag Viewport" -msgstr "拖放显示范围" +msgstr "移动/拖动窗口" #: ../vnc.html:106 msgid "viewport drag" -msgstr "显示范围拖放" +msgstr "窗口拖动" #: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121 msgid "Active Mouse Button" -msgstr "启动鼠标按鍵" +msgstr "启动鼠标按键" #: ../vnc.html:112 msgid "No mousebutton" -msgstr "禁用鼠标按鍵" +msgstr "禁用鼠标按键" #: ../vnc.html:115 msgid "Left mousebutton" -msgstr "鼠标左鍵" +msgstr "鼠标左键" #: ../vnc.html:118 msgid "Middle mousebutton" -msgstr "鼠标中鍵" +msgstr "鼠标中键" #: ../vnc.html:121 msgid "Right mousebutton" -msgstr "鼠标右鍵" +msgstr "鼠标右键" #: ../vnc.html:124 msgid "Keyboard" @@ -127,6 +111,10 @@ msgstr "Ctrl" msgid "Toggle Ctrl" msgstr "切换 Ctrl" +#: ../vnc.html:136 +msgid "Edit clipboard content in the textarea below." +msgstr "在下面的文本区域中编辑剪贴板内容。" + #: ../vnc.html:139 msgid "Alt" msgstr "Alt" @@ -153,19 +141,19 @@ msgstr "发送 Escape 键" #: ../vnc.html:148 msgid "Ctrl+Alt+Del" -msgstr "Ctrl-Alt-Del" +msgstr "Ctrl+Alt+Del" #: ../vnc.html:148 msgid "Send Ctrl-Alt-Del" -msgstr "发送 Ctrl-Alt-Del 键" +msgstr "发送 Ctrl+Alt+Del 键" #: ../vnc.html:156 msgid "Shutdown/Reboot" -msgstr "关机/重新启动" +msgstr "关机/重启" #: ../vnc.html:156 msgid "Shutdown/Reboot..." -msgstr "关机/重新启动..." +msgstr "关机/重启..." #: ../vnc.html:162 msgid "Power" @@ -177,7 +165,7 @@ msgstr "关机" #: ../vnc.html:165 msgid "Reboot" -msgstr "重新启动" +msgstr "重启" #: ../vnc.html:166 msgid "Reset" @@ -199,6 +187,10 @@ msgstr "全屏" msgid "Settings" msgstr "设置" +#: ../vnc.html:200 +msgid "Encrypt" +msgstr "加密" + #: ../vnc.html:202 msgid "Shared Mode" msgstr "分享模式" @@ -224,61 +216,69 @@ msgid "Local Scaling" msgstr "本地缩放" #: ../vnc.html:216 +msgid "Local Downscaling" +msgstr "降低本地尺寸" + +#: ../vnc.html:217 msgid "Remote Resizing" msgstr "远程调整大小" -#: ../vnc.html:221 +#: ../vnc.html:222 msgid "Advanced" msgstr "高级" -#: ../vnc.html:224 +#: ../vnc.html:225 +msgid "Local Cursor" +msgstr "本地光标" + +#: ../vnc.html:229 msgid "Repeater ID:" msgstr "中继站 ID" -#: ../vnc.html:228 +#: ../vnc.html:233 msgid "WebSocket" msgstr "WebSocket" -#: ../vnc.html:231 -msgid "Encrypt" -msgstr "加密" - -#: ../vnc.html:234 +#: ../vnc.html:239 msgid "Host:" msgstr "主机:" -#: ../vnc.html:238 +#: ../vnc.html:243 msgid "Port:" msgstr "端口:" -#: ../vnc.html:242 +#: ../vnc.html:247 msgid "Path:" msgstr "路径:" -#: ../vnc.html:249 +#: ../vnc.html:254 msgid "Automatic Reconnect" msgstr "自动重新连接" -#: ../vnc.html:252 +#: ../vnc.html:257 msgid "Reconnect Delay (ms):" msgstr "重新连接间隔 (ms):" -#: ../vnc.html:258 +#: ../vnc.html:263 msgid "Logging:" msgstr "日志级别:" -#: ../vnc.html:270 +#: ../vnc.html:275 msgid "Disconnect" -msgstr "中断连接" +msgstr "断开连接" -#: ../vnc.html:289 +#: ../vnc.html:294 msgid "Connect" msgstr "连接" -#: ../vnc.html:299 +#: ../vnc.html:304 msgid "Password:" msgstr "密码:" -#: ../vnc.html:313 +#: ../vnc.html:318 msgid "Cancel" msgstr "取消" + +#: ../vnc.html:334 +msgid "Canvas not supported." +msgstr "不支持 Canvas。" \ No newline at end of file From 9d293f1ababd710d4ebc225300ef075b78d637c5 Mon Sep 17 00:00:00 2001 From: Giannis Kosmas Date: Wed, 24 Apr 2024 19:53:49 +0300 Subject: [PATCH 02/22] Updated el.po --- po/el.po | 262 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 169 insertions(+), 93 deletions(-) diff --git a/po/el.po b/po/el.po index 5213ae542..de690fe93 100644 --- a/po/el.po +++ b/po/el.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: noVNC 0.6.1\n" "Report-Msgid-Bugs-To: novnc@googlegroups.com\n" -"POT-Creation-Date: 2017-11-17 21:40+0200\n" +"POT-Creation-Date: 2022-12-27 15:24+0100\n" "PO-Revision-Date: 2017-10-11 16:16+0200\n" "Last-Translator: Giannis Kosmas \n" "Language-Team: none\n" @@ -17,273 +17,349 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../app/ui.js:404 +#: ../app/ui.js:69 +msgid "HTTPS is required for full functionality" +msgstr "Το HTTPS είναι απαιτούμενο για πλήρη λειτουργικότητα" + +#: ../app/ui.js:410 msgid "Connecting..." msgstr "Συνδέεται..." -#: ../app/ui.js:411 +#: ../app/ui.js:417 msgid "Disconnecting..." msgstr "Aποσυνδέεται..." -#: ../app/ui.js:417 +#: ../app/ui.js:423 msgid "Reconnecting..." msgstr "Επανασυνδέεται..." -#: ../app/ui.js:422 +#: ../app/ui.js:428 msgid "Internal error" msgstr "Εσωτερικό σφάλμα" -#: ../app/ui.js:1019 +#: ../app/ui.js:1026 msgid "Must set host" msgstr "Πρέπει να οριστεί ο διακομιστής" -#: ../app/ui.js:1099 +#: ../app/ui.js:1110 msgid "Connected (encrypted) to " msgstr "Συνδέθηκε (κρυπτογραφημένα) με το " -#: ../app/ui.js:1101 +#: ../app/ui.js:1112 msgid "Connected (unencrypted) to " msgstr "Συνδέθηκε (μη κρυπτογραφημένα) με το " -#: ../app/ui.js:1119 +#: ../app/ui.js:1135 msgid "Something went wrong, connection is closed" msgstr "Κάτι πήγε στραβά, η σύνδεση διακόπηκε" -#: ../app/ui.js:1129 +#: ../app/ui.js:1138 +msgid "Failed to connect to server" +msgstr "Αποτυχία στη σύνδεση με το διακομιστή" + +#: ../app/ui.js:1150 msgid "Disconnected" msgstr "Αποσυνδέθηκε" -#: ../app/ui.js:1142 +#: ../app/ui.js:1165 msgid "New connection has been rejected with reason: " msgstr "Η νέα σύνδεση απορρίφθηκε διότι: " -#: ../app/ui.js:1145 +#: ../app/ui.js:1168 msgid "New connection has been rejected" msgstr "Η νέα σύνδεση απορρίφθηκε " -#: ../app/ui.js:1166 -msgid "Password is required" -msgstr "Απαιτείται ο κωδικός πρόσβασης" +#: ../app/ui.js:1234 +msgid "Credentials are required" +msgstr "Απαιτούνται διαπιστευτήρια" -#: ../vnc.html:89 +#: ../vnc.html:57 msgid "noVNC encountered an error:" msgstr "το noVNC αντιμετώπισε ένα σφάλμα:" -#: ../vnc.html:99 +#: ../vnc.html:67 msgid "Hide/Show the control bar" msgstr "Απόκρυψη/Εμφάνιση γραμμής ελέγχου" -#: ../vnc.html:106 +#: ../vnc.html:76 +msgid "Drag" +msgstr "Σύρσιμο" + +#: ../vnc.html:76 msgid "Move/Drag Viewport" msgstr "Μετακίνηση/Σύρσιμο Θεατού πεδίου" -#: ../vnc.html:106 -msgid "viewport drag" -msgstr "σύρσιμο θεατού πεδίου" - -#: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121 -msgid "Active Mouse Button" -msgstr "Ενεργό Πλήκτρο Ποντικιού" - -#: ../vnc.html:112 -msgid "No mousebutton" -msgstr "Χωρίς Πλήκτρο Ποντικιού" - -#: ../vnc.html:115 -msgid "Left mousebutton" -msgstr "Αριστερό Πλήκτρο Ποντικιού" - -#: ../vnc.html:118 -msgid "Middle mousebutton" -msgstr "Μεσαίο Πλήκτρο Ποντικιού" - -#: ../vnc.html:121 -msgid "Right mousebutton" -msgstr "Δεξί Πλήκτρο Ποντικιού" - -#: ../vnc.html:124 +#: ../vnc.html:82 msgid "Keyboard" msgstr "Πληκτρολόγιο" -#: ../vnc.html:124 +#: ../vnc.html:82 msgid "Show Keyboard" msgstr "Εμφάνιση Πληκτρολογίου" -#: ../vnc.html:131 +#: ../vnc.html:87 msgid "Extra keys" msgstr "Επιπλέον πλήκτρα" -#: ../vnc.html:131 +#: ../vnc.html:87 msgid "Show Extra Keys" msgstr "Εμφάνιση Επιπλέον Πλήκτρων" -#: ../vnc.html:136 +#: ../vnc.html:92 msgid "Ctrl" msgstr "Ctrl" -#: ../vnc.html:136 +#: ../vnc.html:92 msgid "Toggle Ctrl" msgstr "Εναλλαγή Ctrl" -#: ../vnc.html:139 +#: ../vnc.html:95 msgid "Alt" msgstr "Alt" -#: ../vnc.html:139 +#: ../vnc.html:95 msgid "Toggle Alt" msgstr "Εναλλαγή Alt" -#: ../vnc.html:142 +#: ../vnc.html:98 +msgid "Toggle Windows" +msgstr "Εναλλαγή Παράθυρων" + +#: ../vnc.html:98 +msgid "Windows" +msgstr "Παράθυρα" + +#: ../vnc.html:101 msgid "Send Tab" msgstr "Αποστολή Tab" -#: ../vnc.html:142 +#: ../vnc.html:101 msgid "Tab" msgstr "Tab" -#: ../vnc.html:145 +#: ../vnc.html:104 msgid "Esc" msgstr "Esc" -#: ../vnc.html:145 +#: ../vnc.html:104 msgid "Send Escape" msgstr "Αποστολή Escape" -#: ../vnc.html:148 +#: ../vnc.html:107 msgid "Ctrl+Alt+Del" msgstr "Ctrl+Alt+Del" -#: ../vnc.html:148 +#: ../vnc.html:107 msgid "Send Ctrl-Alt-Del" msgstr "Αποστολή Ctrl-Alt-Del" -#: ../vnc.html:156 +#: ../vnc.html:114 msgid "Shutdown/Reboot" msgstr "Κλείσιμο/Επανεκκίνηση" -#: ../vnc.html:156 +#: ../vnc.html:114 msgid "Shutdown/Reboot..." msgstr "Κλείσιμο/Επανεκκίνηση..." -#: ../vnc.html:162 +#: ../vnc.html:120 msgid "Power" msgstr "Απενεργοποίηση" -#: ../vnc.html:164 +#: ../vnc.html:122 msgid "Shutdown" msgstr "Κλείσιμο" -#: ../vnc.html:165 +#: ../vnc.html:123 msgid "Reboot" msgstr "Επανεκκίνηση" -#: ../vnc.html:166 +#: ../vnc.html:124 msgid "Reset" msgstr "Επαναφορά" -#: ../vnc.html:171 ../vnc.html:177 +#: ../vnc.html:129 ../vnc.html:135 msgid "Clipboard" msgstr "Πρόχειρο" -#: ../vnc.html:181 -msgid "Clear" -msgstr "Καθάρισμα" +#: ../vnc.html:137 +msgid "Edit clipboard content in the textarea below." +msgstr "Επεξεργαστείτε το περιεχόμενο του πρόχειρου στην περιοχή κειμένου παρακάτω." -#: ../vnc.html:187 -msgid "Fullscreen" +#: ../vnc.html:145 +#, fuzzy +msgid "Full Screen" msgstr "Πλήρης Οθόνη" -#: ../vnc.html:192 ../vnc.html:199 +#: ../vnc.html:150 ../vnc.html:156 msgid "Settings" msgstr "Ρυθμίσεις" -#: ../vnc.html:202 +#: ../vnc.html:160 msgid "Shared Mode" msgstr "Κοινόχρηστη Λειτουργία" -#: ../vnc.html:205 +#: ../vnc.html:163 msgid "View Only" msgstr "Μόνο Θέαση" -#: ../vnc.html:209 +#: ../vnc.html:167 msgid "Clip to Window" msgstr "Αποκοπή στο όριο του Παράθυρου" -#: ../vnc.html:212 +#: ../vnc.html:170 msgid "Scaling Mode:" msgstr "Λειτουργία Κλιμάκωσης:" -#: ../vnc.html:214 +#: ../vnc.html:172 msgid "None" msgstr "Καμία" -#: ../vnc.html:215 +#: ../vnc.html:173 msgid "Local Scaling" msgstr "Τοπική Κλιμάκωση" -#: ../vnc.html:216 +#: ../vnc.html:174 msgid "Remote Resizing" msgstr "Απομακρυσμένη Αλλαγή μεγέθους" -#: ../vnc.html:221 +#: ../vnc.html:179 msgid "Advanced" msgstr "Για προχωρημένους" -#: ../vnc.html:224 +#: ../vnc.html:182 +msgid "Quality:" +msgstr "Ποιότητα:" + +#: ../vnc.html:186 +msgid "Compression level:" +msgstr "Επίπεδο συμπίεσης:" + +#: ../vnc.html:191 msgid "Repeater ID:" msgstr "Repeater ID:" -#: ../vnc.html:228 +#: ../vnc.html:195 msgid "WebSocket" msgstr "WebSocket" -#: ../vnc.html:231 +#: ../vnc.html:198 msgid "Encrypt" msgstr "Κρυπτογράφηση" -#: ../vnc.html:234 +#: ../vnc.html:201 msgid "Host:" msgstr "Όνομα διακομιστή:" -#: ../vnc.html:238 +#: ../vnc.html:205 msgid "Port:" msgstr "Πόρτα διακομιστή:" -#: ../vnc.html:242 +#: ../vnc.html:209 msgid "Path:" msgstr "Διαδρομή:" -#: ../vnc.html:249 +#: ../vnc.html:216 msgid "Automatic Reconnect" msgstr "Αυτόματη επανασύνδεση" -#: ../vnc.html:252 +#: ../vnc.html:219 msgid "Reconnect Delay (ms):" msgstr "Καθυστέρηση επανασύνδεσης (ms):" -#: ../vnc.html:258 +#: ../vnc.html:224 +msgid "Show Dot when No Cursor" +msgstr "Εμφάνιση Τελείας όταν δεν υπάρχει Δρομέας" + +#: ../vnc.html:229 msgid "Logging:" msgstr "Καταγραφή:" -#: ../vnc.html:270 +#: ../vnc.html:238 +msgid "Version:" +msgstr "Έκδοση:" + +#: ../vnc.html:246 msgid "Disconnect" msgstr "Αποσύνδεση" -#: ../vnc.html:289 +#: ../vnc.html:269 msgid "Connect" msgstr "Σύνδεση" -#: ../vnc.html:299 +#: ../vnc.html:278 +msgid "Server identity" +msgstr "Ταυτότητα Διακομιστή" + +#: ../vnc.html:281 +msgid "The server has provided the following identifying information:" +msgstr "Ο διακομιστής παρείχε την ακόλουθη πληροφορία ταυτοποίησης:" + +#: ../vnc.html:285 +msgid "Fingerprint:" +msgstr "Δακτυλικό αποτύπωμα:" + +#: ../vnc.html:288 +msgid "" +"Please verify that the information is correct and press \"Approve\". " +"Otherwise press \"Reject\"." +msgstr "" +"Παρακαλώ επαληθεύσετε ότι η πληροφορία είναι σωστή και πιέστε \"Αποδοχή\". " +"Αλλιώς πιέστε \"Απόρριψη\"." + +#: ../vnc.html:293 +msgid "Approve" +msgstr "Αποδοχή" + +#: ../vnc.html:294 +msgid "Reject" +msgstr "Απόρριψη" + +#: ../vnc.html:302 +msgid "Credentials" +msgstr "Διαπιστευτήρια" + +#: ../vnc.html:306 +msgid "Username:" +msgstr "Κωδικός Χρήστη:" + +#: ../vnc.html:310 msgid "Password:" msgstr "Κωδικός Πρόσβασης:" -#: ../vnc.html:313 +#: ../vnc.html:314 +msgid "Send Credentials" +msgstr "Αποστολή Διαπιστευτηρίων" + +#: ../vnc.html:323 msgid "Cancel" msgstr "Ακύρωση" -#: ../vnc.html:329 -msgid "Canvas not supported." -msgstr "Δεν υποστηρίζεται το στοιχείο Canvas" +#~ msgid "Password is required" +#~ msgstr "Απαιτείται ο κωδικός πρόσβασης" + +#~ msgid "viewport drag" +#~ msgstr "σύρσιμο θεατού πεδίου" + +#~ msgid "Active Mouse Button" +#~ msgstr "Ενεργό Πλήκτρο Ποντικιού" + +#~ msgid "No mousebutton" +#~ msgstr "Χωρίς Πλήκτρο Ποντικιού" + +#~ msgid "Left mousebutton" +#~ msgstr "Αριστερό Πλήκτρο Ποντικιού" + +#~ msgid "Middle mousebutton" +#~ msgstr "Μεσαίο Πλήκτρο Ποντικιού" + +#~ msgid "Right mousebutton" +#~ msgstr "Δεξί Πλήκτρο Ποντικιού" + +#~ msgid "Clear" +#~ msgstr "Καθάρισμα" + +#~ msgid "Canvas not supported." +#~ msgstr "Δεν υποστηρίζεται το στοιχείο Canvas" #~ msgid "Disconnect timeout" #~ msgstr "Παρέλευση χρονικού ορίου αποσύνδεσης" From 8d1b665808ce3da8307c5597d821f31eb925cb99 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Mon, 22 Apr 2024 08:49:30 +0200 Subject: [PATCH 03/22] Migrate deprecated eslint config to to new format The .eslintrc and .eslintignore formats are deprecated. The new format uses a single eslint.config.js (or .mjs) file at the top. --- .eslintignore | 1 - .eslintrc | 54 -------------------------- eslint.config.mjs | 98 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + po/.eslintrc | 5 --- tests/.eslintrc | 15 -------- utils/.eslintrc | 8 ---- 7 files changed, 99 insertions(+), 83 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc create mode 100644 eslint.config.mjs delete mode 100644 po/.eslintrc delete mode 100644 tests/.eslintrc delete mode 100644 utils/.eslintrc diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index d38162800..000000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -**/xtscancodes.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 10e15cec3..000000000 --- a/.eslintrc +++ /dev/null @@ -1,54 +0,0 @@ -{ - "env": { - "browser": true, - "es2020": true - }, - "parserOptions": { - "sourceType": "module", - "ecmaVersion": 2020 - }, - "extends": "eslint:recommended", - "rules": { - // Unsafe or confusing stuff that we forbid - - "no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }], - "no-constant-condition": ["error", { "checkLoops": false }], - "no-var": "error", - "no-useless-constructor": "error", - "object-shorthand": ["error", "methods", { "avoidQuotes": true }], - "prefer-arrow-callback": "error", - "arrow-body-style": ["error", "as-needed", { "requireReturnForObjectLiteral": false } ], - "arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }], - "arrow-spacing": ["error"], - "no-confusing-arrow": ["error", { "allowParens": true }], - - // Enforced coding style - - "brace-style": ["error", "1tbs", { "allowSingleLine": true }], - "indent": ["error", 4, { "SwitchCase": 1, - "VariableDeclarator": "first", - "FunctionDeclaration": { "parameters": "first" }, - "FunctionExpression": { "parameters": "first" }, - "CallExpression": { "arguments": "first" }, - "ArrayExpression": "first", - "ObjectExpression": "first", - "ImportDeclaration": "first", - "ignoreComments": true }], - "comma-spacing": ["error"], - "comma-style": ["error"], - "curly": ["error", "multi-line"], - "func-call-spacing": ["error"], - "func-names": ["error"], - "func-style": ["error", "declaration", { "allowArrowFunctions": true }], - "key-spacing": ["error"], - "keyword-spacing": ["error"], - "no-trailing-spaces": ["error"], - "semi": ["error"], - "space-before-blocks": ["error"], - "space-before-function-paren": ["error", { "anonymous": "always", - "named": "never", - "asyncArrow": "always" }], - "switch-colon-spacing": ["error"], - "camelcase": ["error", { allow: ["^XK_", "^XF86XK_"] }], - } -} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..e3bfcd78a --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,98 @@ +import globals from "globals"; +import js from "@eslint/js"; + +export default [ + js.configs.recommended, + { + languageOptions: { + ecmaVersion: 2020, + sourceType: "module", + globals: { + ...globals.browser, + ...globals.es2020, + } + }, + ignores: ["**/xtscancodes.js"], + rules: { + // Unsafe or confusing stuff that we forbid + + "no-unused-vars": ["error", { "vars": "all", + "args": "none", + "ignoreRestSiblings": true, + "caughtErrors": "none" }], + "no-constant-condition": ["error", { "checkLoops": false }], + "no-var": "error", + "no-useless-constructor": "error", + "object-shorthand": ["error", "methods", { "avoidQuotes": true }], + "prefer-arrow-callback": "error", + "arrow-body-style": ["error", "as-needed", { "requireReturnForObjectLiteral": false } ], + "arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }], + "arrow-spacing": ["error"], + "no-confusing-arrow": ["error", { "allowParens": true }], + + // Enforced coding style + + "brace-style": ["error", "1tbs", { "allowSingleLine": true }], + "indent": ["error", 4, { "SwitchCase": 1, + "VariableDeclarator": "first", + "FunctionDeclaration": { "parameters": "first" }, + "FunctionExpression": { "parameters": "first" }, + "CallExpression": { "arguments": "first" }, + "ArrayExpression": "first", + "ObjectExpression": "first", + "ImportDeclaration": "first", + "ignoreComments": true }], + "comma-spacing": ["error"], + "comma-style": ["error"], + "curly": ["error", "multi-line"], + "func-call-spacing": ["error"], + "func-names": ["error"], + "func-style": ["error", "declaration", { "allowArrowFunctions": true }], + "key-spacing": ["error"], + "keyword-spacing": ["error"], + "no-trailing-spaces": ["error"], + "semi": ["error"], + "space-before-blocks": ["error"], + "space-before-function-paren": ["error", { "anonymous": "always", + "named": "never", + "asyncArrow": "always" }], + "switch-colon-spacing": ["error"], + "camelcase": ["error", { "allow": ["^XK_", "^XF86XK_"] }], + } + }, + { + files: ["po/po2js", "po/xgettext-html"], + languageOptions: { + globals: { + ...globals.node, + } + }, + }, + { + files: ["tests/*"], + languageOptions: { + globals: { + ...globals.node, + ...globals.mocha, + sinon: false, + chai: false, + } + }, + rules: { + "prefer-arrow-callback": 0, + // Too many anonymous callbacks + "func-names": "off", + }, + }, + { + files: ["utils/*"], + languageOptions: { + globals: { + ...globals.node, + } + }, + rules: { + "no-console": 0, + }, + }, +]; diff --git a/package.json b/package.json index 482b86eb3..9f22165bc 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "commander": "latest", "eslint": "latest", "fs-extra": "latest", + "globals": "latest", "jsdom": "latest", "karma": "latest", "karma-mocha": "latest", diff --git a/po/.eslintrc b/po/.eslintrc deleted file mode 100644 index a0157e2a8..000000000 --- a/po/.eslintrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "env": { - "node": true, - }, -} diff --git a/tests/.eslintrc b/tests/.eslintrc deleted file mode 100644 index 545fa2ed2..000000000 --- a/tests/.eslintrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "env": { - "node": true, - "mocha": true - }, - "globals": { - "chai": false, - "sinon": false - }, - "rules": { - "prefer-arrow-callback": 0, - // Too many anonymous callbacks - "func-names": "off", - } -} diff --git a/utils/.eslintrc b/utils/.eslintrc deleted file mode 100644 index b7dc129f1..000000000 --- a/utils/.eslintrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "env": { - "node": true - }, - "rules": { - "no-console": 0 - } -} \ No newline at end of file From 10ee10ce56d5b7aaf642457bfb99b56a13d56ad6 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Tue, 30 Apr 2024 15:25:03 +0200 Subject: [PATCH 04/22] Cleanup "no-console" eslint rules Removes unexpected exceptions and clarifies where we want to avoid console calls. --- eslint.config.mjs | 4 ++++ tests/test.browser.js | 1 - tests/test.deflator.js | 1 - tests/test.inflator.js | 1 - tests/test.int.js | 1 - 5 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index e3bfcd78a..c88e7b758 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -58,6 +58,7 @@ export default [ "asyncArrow": "always" }], "switch-colon-spacing": ["error"], "camelcase": ["error", { "allow": ["^XK_", "^XF86XK_"] }], + "no-console": ["error"], } }, { @@ -67,6 +68,9 @@ export default [ ...globals.node, } }, + rules: { + "no-console": 0, + }, }, { files: ["tests/*"], diff --git a/tests/test.browser.js b/tests/test.browser.js index 3b2299f63..1beeb48d5 100644 --- a/tests/test.browser.js +++ b/tests/test.browser.js @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ const expect = chai.expect; import { isMac, isWindows, isIOS, isAndroid, isChromeOS, diff --git a/tests/test.deflator.js b/tests/test.deflator.js index 12e8a46bf..a7e972ec0 100644 --- a/tests/test.deflator.js +++ b/tests/test.deflator.js @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ const expect = chai.expect; import { inflateInit, inflate } from "../vendor/pako/lib/zlib/inflate.js"; diff --git a/tests/test.inflator.js b/tests/test.inflator.js index 533bcd865..304e7a0fd 100644 --- a/tests/test.inflator.js +++ b/tests/test.inflator.js @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ const expect = chai.expect; import { deflateInit, deflate, Z_FULL_FLUSH } from "../vendor/pako/lib/zlib/deflate.js"; diff --git a/tests/test.int.js b/tests/test.int.js index 954fd279f..084d68abd 100644 --- a/tests/test.int.js +++ b/tests/test.int.js @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ const expect = chai.expect; import { toUnsigned32bit, toSigned32bit } from '../core/util/int.js'; From c187b2e5e0e44b4157f5e6220b263940f600bbca Mon Sep 17 00:00:00 2001 From: Jiang XueQian Date: Thu, 2 May 2024 20:41:38 +0800 Subject: [PATCH 05/22] Implement gradient filter of tight decoder, fixing issue #1767 This commit is a basic implementation of the gradient filter required by qemu `lossy` option. --- core/decoders/tight.js | 68 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/core/decoders/tight.js b/core/decoders/tight.js index 45622080f..8bc977a79 100644 --- a/core/decoders/tight.js +++ b/core/decoders/tight.js @@ -285,7 +285,73 @@ export default class TightDecoder { } _gradientFilter(streamId, x, y, width, height, sock, display, depth) { - throw new Error("Gradient filter not implemented"); + // assume the TPIXEL is 3 bytes long + const uncompressedSize = width * height * 3; + let data; + + if (uncompressedSize === 0) { + return true; + } + + if (uncompressedSize < 12) { + if (sock.rQwait("TIGHT", uncompressedSize)) { + return false; + } + + data = sock.rQshiftBytes(uncompressedSize); + } else { + data = this._readData(sock); + if (data === null) { + return false; + } + + this._zlibs[streamId].setInput(data); + data = this._zlibs[streamId].inflate(uncompressedSize); + this._zlibs[streamId].setInput(null); + } + + let rgbx = new Uint8Array(4 * width * height); + + let rgbxIndex = 0, dataIndex = 0; + let left = new Uint8Array(3); + for (let x = 0; x < width; x++) { + for (let c = 0; c < 3; c++) { + const prediction = left[c]; + const value = data[dataIndex++] + prediction; + rgbx[rgbxIndex++] = value; + left[c] = value; + } + rgbx[rgbxIndex++] = 255; + } + + let upperIndex = 0; + let upper = new Uint8Array(3), + upperleft = new Uint8Array(3); + for (let y = 1; y < height; y++) { + left.fill(0); + upperleft.fill(0); + for (let x = 0; x < width; x++) { + for (let c = 0; c < 3; c++) { + upper[c] = rgbx[upperIndex++]; + let prediction = left[c] + upper[c] - upperleft[c]; + if (prediction < 0) { + prediction = 0; + } else if (prediction > 255) { + prediction = 255; + } + const value = data[dataIndex++] + prediction; + rgbx[rgbxIndex++] = value; + upperleft[c] = upper[c]; + left[c] = value; + } + rgbx[rgbxIndex++] = 255; + upperIndex++; + } + } + + display.blitImage(x, y, width, height, rgbx, 0, false); + + return true; } _readData(sock) { From d80e3bfa2f372e2b210f46b8c46796a9754abf27 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 16 May 2024 16:53:49 +0200 Subject: [PATCH 06/22] Add unit tests for Tight gradient filter --- tests/test.tight.js | 74 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/tests/test.tight.js b/tests/test.tight.js index b3457a88b..141d7b6e2 100644 --- a/tests/test.tight.js +++ b/tests/test.tight.js @@ -228,12 +228,59 @@ describe('Tight Decoder', function () { expect(display).to.have.displayed(targetData); }); - it.skip('should handle uncompressed gradient rects', function () { - // Not implemented yet + it('should handle uncompressed gradient rects', function () { + let done; + let blueData = [ 0x40, 0x02, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00 ]; + let greenData = [ 0x40, 0x02, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 ]; + + done = testDecodeRect(decoder, 0, 0, 2, 1, blueData, display, 24); + expect(done).to.be.true; + done = testDecodeRect(decoder, 0, 1, 2, 1, blueData, display, 24); + expect(done).to.be.true; + done = testDecodeRect(decoder, 2, 0, 2, 1, greenData, display, 24); + expect(done).to.be.true; + done = testDecodeRect(decoder, 2, 1, 2, 1, greenData, display, 24); + expect(done).to.be.true; + done = testDecodeRect(decoder, 0, 2, 2, 1, greenData, display, 24); + expect(done).to.be.true; + done = testDecodeRect(decoder, 0, 3, 2, 1, greenData, display, 24); + expect(done).to.be.true; + done = testDecodeRect(decoder, 2, 2, 2, 1, blueData, display, 24); + expect(done).to.be.true; + done = testDecodeRect(decoder, 2, 3, 2, 1, blueData, display, 24); + expect(done).to.be.true; + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); }); - it.skip('should handle compressed gradient rects', function () { - // Not implemented yet + it('should handle compressed gradient rects', function () { + let data = [ + // Control byte + 0x40, 0x02, + // Pixels (compressed) + 0x18, + 0x78, 0x9c, 0x62, 0x60, 0xf8, 0xcf, 0x00, 0x04, + 0xff, 0x19, 0x19, 0xd0, 0x00, 0x44, 0x84, 0xf1, + 0x3f, 0x9a, 0x30, 0x00, 0x00, 0x00, 0xff, 0xff ]; + + let done = testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(done).to.be.true; + expect(display).to.have.displayed(targetData); }); it('should handle empty copy rects', function () { @@ -275,6 +322,25 @@ describe('Tight Decoder', function () { expect(display).to.have.displayed(targetData); }); + it('should handle empty gradient rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + let done = testDecodeRect(decoder, 1, 2, 0, 0, + [ 0x40, 0x02 ], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(done).to.be.true; + expect(display).to.have.displayed(targetData); + }); + it('should handle empty fill rects', function () { display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); From fc11b9d2b095b0dd0db106ca0f80a47d6e262f6c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 3 Jun 2024 14:09:00 +0200 Subject: [PATCH 07/22] Remove Twitter links These are not updated anymore as they are not under the control of the current team. --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index a771cb438..b95d15e65 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,6 @@ for a more complete list with additional info and links. ### News/help/contact The project website is found at [novnc.com](http://novnc.com). -Notable commits, announcements and news are posted to -[@noVNC](http://www.twitter.com/noVNC). If you are a noVNC developer/integrator/user (or want to be) please join the [noVNC discussion group](https://groups.google.com/forum/?fromgroups#!forum/novnc). @@ -59,7 +57,6 @@ profits such as: [Electronic Frontier Foundation](https://www.eff.org/), [Against Malaria Foundation](http://www.againstmalaria.com/), [Nothing But Nets](http://www.nothingbutnets.net/), etc. -Please tweet [@noVNC](http://www.twitter.com/noVNC) if you do. ### Features From f28e9daec387c681a70b10b1328f1a365ef51363 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 3 Jun 2024 14:10:47 +0200 Subject: [PATCH 08/22] Update translation template file --- po/noVNC.pot | 155 ++++++++++++++++++++++++++------------------------- 1 file changed, 80 insertions(+), 75 deletions(-) diff --git a/po/noVNC.pot b/po/noVNC.pot index 3641e3bc9..0f85a82e5 100644 --- a/po/noVNC.pot +++ b/po/noVNC.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: noVNC 1.4.0\n" +"Project-Id-Version: noVNC 1.5.0\n" "Report-Msgid-Bugs-To: novnc@googlegroups.com\n" -"POT-Creation-Date: 2022-12-27 15:24+0100\n" +"POT-Creation-Date: 2024-06-03 14:10+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,7 +18,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #: ../app/ui.js:69 -msgid "HTTPS is required for full functionality" +msgid "" +"Running without HTTPS is not recommended, crashes or other issues are likely." msgstr "" #: ../app/ui.js:410 @@ -41,292 +42,296 @@ msgstr "" msgid "Must set host" msgstr "" -#: ../app/ui.js:1110 +#: ../app/ui.js:1052 +msgid "Failed to connect to server: " +msgstr "" + +#: ../app/ui.js:1118 msgid "Connected (encrypted) to " msgstr "" -#: ../app/ui.js:1112 +#: ../app/ui.js:1120 msgid "Connected (unencrypted) to " msgstr "" -#: ../app/ui.js:1135 +#: ../app/ui.js:1143 msgid "Something went wrong, connection is closed" msgstr "" -#: ../app/ui.js:1138 +#: ../app/ui.js:1146 msgid "Failed to connect to server" msgstr "" -#: ../app/ui.js:1150 +#: ../app/ui.js:1158 msgid "Disconnected" msgstr "" -#: ../app/ui.js:1165 +#: ../app/ui.js:1173 msgid "New connection has been rejected with reason: " msgstr "" -#: ../app/ui.js:1168 +#: ../app/ui.js:1176 msgid "New connection has been rejected" msgstr "" -#: ../app/ui.js:1234 +#: ../app/ui.js:1242 msgid "Credentials are required" msgstr "" -#: ../vnc.html:57 +#: ../vnc.html:55 msgid "noVNC encountered an error:" msgstr "" -#: ../vnc.html:67 +#: ../vnc.html:65 msgid "Hide/Show the control bar" msgstr "" -#: ../vnc.html:76 +#: ../vnc.html:74 msgid "Drag" msgstr "" -#: ../vnc.html:76 +#: ../vnc.html:74 msgid "Move/Drag Viewport" msgstr "" -#: ../vnc.html:82 +#: ../vnc.html:80 msgid "Keyboard" msgstr "" -#: ../vnc.html:82 +#: ../vnc.html:80 msgid "Show Keyboard" msgstr "" -#: ../vnc.html:87 +#: ../vnc.html:85 msgid "Extra keys" msgstr "" -#: ../vnc.html:87 +#: ../vnc.html:85 msgid "Show Extra Keys" msgstr "" -#: ../vnc.html:92 +#: ../vnc.html:90 msgid "Ctrl" msgstr "" -#: ../vnc.html:92 +#: ../vnc.html:90 msgid "Toggle Ctrl" msgstr "" -#: ../vnc.html:95 +#: ../vnc.html:93 msgid "Alt" msgstr "" -#: ../vnc.html:95 +#: ../vnc.html:93 msgid "Toggle Alt" msgstr "" -#: ../vnc.html:98 +#: ../vnc.html:96 msgid "Toggle Windows" msgstr "" -#: ../vnc.html:98 +#: ../vnc.html:96 msgid "Windows" msgstr "" -#: ../vnc.html:101 +#: ../vnc.html:99 msgid "Send Tab" msgstr "" -#: ../vnc.html:101 +#: ../vnc.html:99 msgid "Tab" msgstr "" -#: ../vnc.html:104 +#: ../vnc.html:102 msgid "Esc" msgstr "" -#: ../vnc.html:104 +#: ../vnc.html:102 msgid "Send Escape" msgstr "" -#: ../vnc.html:107 +#: ../vnc.html:105 msgid "Ctrl+Alt+Del" msgstr "" -#: ../vnc.html:107 +#: ../vnc.html:105 msgid "Send Ctrl-Alt-Del" msgstr "" -#: ../vnc.html:114 +#: ../vnc.html:112 msgid "Shutdown/Reboot" msgstr "" -#: ../vnc.html:114 +#: ../vnc.html:112 msgid "Shutdown/Reboot..." msgstr "" -#: ../vnc.html:120 +#: ../vnc.html:118 msgid "Power" msgstr "" -#: ../vnc.html:122 +#: ../vnc.html:120 msgid "Shutdown" msgstr "" -#: ../vnc.html:123 +#: ../vnc.html:121 msgid "Reboot" msgstr "" -#: ../vnc.html:124 +#: ../vnc.html:122 msgid "Reset" msgstr "" -#: ../vnc.html:129 ../vnc.html:135 +#: ../vnc.html:127 ../vnc.html:133 msgid "Clipboard" msgstr "" -#: ../vnc.html:137 +#: ../vnc.html:135 msgid "Edit clipboard content in the textarea below." msgstr "" -#: ../vnc.html:145 +#: ../vnc.html:143 msgid "Full Screen" msgstr "" -#: ../vnc.html:150 ../vnc.html:156 +#: ../vnc.html:148 ../vnc.html:154 msgid "Settings" msgstr "" -#: ../vnc.html:160 +#: ../vnc.html:158 msgid "Shared Mode" msgstr "" -#: ../vnc.html:163 +#: ../vnc.html:161 msgid "View Only" msgstr "" -#: ../vnc.html:167 +#: ../vnc.html:165 msgid "Clip to Window" msgstr "" -#: ../vnc.html:170 +#: ../vnc.html:168 msgid "Scaling Mode:" msgstr "" -#: ../vnc.html:172 +#: ../vnc.html:170 msgid "None" msgstr "" -#: ../vnc.html:173 +#: ../vnc.html:171 msgid "Local Scaling" msgstr "" -#: ../vnc.html:174 +#: ../vnc.html:172 msgid "Remote Resizing" msgstr "" -#: ../vnc.html:179 +#: ../vnc.html:177 msgid "Advanced" msgstr "" -#: ../vnc.html:182 +#: ../vnc.html:180 msgid "Quality:" msgstr "" -#: ../vnc.html:186 +#: ../vnc.html:184 msgid "Compression level:" msgstr "" -#: ../vnc.html:191 +#: ../vnc.html:189 msgid "Repeater ID:" msgstr "" -#: ../vnc.html:195 +#: ../vnc.html:193 msgid "WebSocket" msgstr "" -#: ../vnc.html:198 +#: ../vnc.html:196 msgid "Encrypt" msgstr "" -#: ../vnc.html:201 +#: ../vnc.html:199 msgid "Host:" msgstr "" -#: ../vnc.html:205 +#: ../vnc.html:203 msgid "Port:" msgstr "" -#: ../vnc.html:209 +#: ../vnc.html:207 msgid "Path:" msgstr "" -#: ../vnc.html:216 +#: ../vnc.html:214 msgid "Automatic Reconnect" msgstr "" -#: ../vnc.html:219 +#: ../vnc.html:217 msgid "Reconnect Delay (ms):" msgstr "" -#: ../vnc.html:224 +#: ../vnc.html:222 msgid "Show Dot when No Cursor" msgstr "" -#: ../vnc.html:229 +#: ../vnc.html:227 msgid "Logging:" msgstr "" -#: ../vnc.html:238 +#: ../vnc.html:236 msgid "Version:" msgstr "" -#: ../vnc.html:246 +#: ../vnc.html:244 msgid "Disconnect" msgstr "" -#: ../vnc.html:269 +#: ../vnc.html:267 msgid "Connect" msgstr "" -#: ../vnc.html:278 +#: ../vnc.html:276 msgid "Server identity" msgstr "" -#: ../vnc.html:281 +#: ../vnc.html:279 msgid "The server has provided the following identifying information:" msgstr "" -#: ../vnc.html:285 +#: ../vnc.html:283 msgid "Fingerprint:" msgstr "" -#: ../vnc.html:288 +#: ../vnc.html:286 msgid "" "Please verify that the information is correct and press \"Approve\". " "Otherwise press \"Reject\"." msgstr "" -#: ../vnc.html:293 +#: ../vnc.html:291 msgid "Approve" msgstr "" -#: ../vnc.html:294 +#: ../vnc.html:292 msgid "Reject" msgstr "" -#: ../vnc.html:302 +#: ../vnc.html:300 msgid "Credentials" msgstr "" -#: ../vnc.html:306 +#: ../vnc.html:304 msgid "Username:" msgstr "" -#: ../vnc.html:310 +#: ../vnc.html:308 msgid "Password:" msgstr "" -#: ../vnc.html:314 +#: ../vnc.html:312 msgid "Send Credentials" msgstr "" -#: ../vnc.html:323 +#: ../vnc.html:321 msgid "Cancel" msgstr "" From 68e09ee8b3f06dac37a08725b9ccc2a64b2fda4f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 3 Jun 2024 14:45:11 +0200 Subject: [PATCH 09/22] Upgrade to websockify 0.12.0 in snap package --- snap/snapcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index ccf618930..82d52de4d 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -42,7 +42,7 @@ parts: - jq websockify: - source: https://github.com/novnc/websockify/archive/v0.11.0.tar.gz + source: https://github.com/novnc/websockify/archive/v0.12.0.tar.gz plugin: python stage-packages: - python3-numpy From aead0b2f891732687b970225350419ae62f1942c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 3 Jun 2024 14:14:24 +0200 Subject: [PATCH 10/22] noVNC 1.5.0 beta --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9f22165bc..af6cfc742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@novnc/novnc", - "version": "1.4.0", + "version": "1.5.0-beta", "description": "An HTML5 VNC client", "browser": "lib/rfb", "directories": { From fb1817c99fdf71180e8d05bdb6f9595be2b5541b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 13 Jun 2024 08:38:00 +0200 Subject: [PATCH 11/22] Remove Chrome timeout workaround This is a revert of fca48df85d394b2c1e9d26ed6e9d10d33db9f4f4. The issue seems to be fixed in the current version of Chrome, so let's keep things simple again. --- karma.conf.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index faa8beea2..1ea17475a 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -81,12 +81,5 @@ module.exports = (config) => { singleRun: true, }; - if (process.env.TEST_BROWSER_NAME === 'ChromeHeadless') { - let os = require('os'); - if (os.platform() === 'win32') { - my_conf.client.mocha['timeout'] = 5000; - } - } - config.set(my_conf); }; From 1a62eb7d3e769e21bf9894e7808ee8143c07080f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Jun 2024 14:01:40 +0200 Subject: [PATCH 12/22] Don't include missing translation in .js It just adds size and confusion. Instead, omit any lines where no translation is available. --- app/locale/fr.json | 8 -------- app/locale/it.json | 4 ---- po/po2js | 12 +++++++----- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/app/locale/fr.json b/app/locale/fr.json index 22531f73b..e25f34ece 100644 --- a/app/locale/fr.json +++ b/app/locale/fr.json @@ -1,5 +1,4 @@ { - "HTTPS is required for full functionality": "", "Connecting...": "En cours de connexion...", "Disconnecting...": "Déconnexion en cours...", "Reconnecting...": "Reconnexion en cours...", @@ -40,7 +39,6 @@ "Reboot": "Redémarrer", "Reset": "Réinitialiser", "Clipboard": "Presse-papiers", - "Edit clipboard content in the textarea below.": "", "Settings": "Paramètres", "Shared Mode": "Mode partagé", "View Only": "Afficher uniquement", @@ -65,12 +63,6 @@ "Version:": "Version :", "Disconnect": "Déconnecter", "Connect": "Connecter", - "Server identity": "", - "The server has provided the following identifying information:": "", - "Fingerprint:": "", - "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "", - "Approve": "", - "Reject": "", "Username:": "Nom d'utilisateur :", "Password:": "Mot de passe :", "Send Credentials": "Envoyer les identifiants", diff --git a/app/locale/it.json b/app/locale/it.json index 6fd25702b..18a7f7447 100644 --- a/app/locale/it.json +++ b/app/locale/it.json @@ -14,8 +14,6 @@ "Credentials are required": "Le credenziali sono obbligatorie", "noVNC encountered an error:": "noVNC ha riscontrato un errore:", "Hide/Show the control bar": "Nascondi/Mostra la barra di controllo", - "Drag": "", - "Move/Drag Viewport": "", "Keyboard": "Tastiera", "Show Keyboard": "Mostra tastiera", "Extra keys": "Tasti Aggiuntivi", @@ -44,7 +42,6 @@ "Settings": "Impostazioni", "Shared Mode": "Modalità condivisa", "View Only": "Sola Visualizzazione", - "Clip to Window": "", "Scaling Mode:": "Modalità di ridimensionamento:", "None": "Nessuna", "Local Scaling": "Ridimensionamento Locale", @@ -61,7 +58,6 @@ "Automatic Reconnect": "Riconnessione Automatica", "Reconnect Delay (ms):": "Ritardo Riconnessione (ms):", "Show Dot when No Cursor": "Mostra Punto quando Nessun Cursore", - "Logging:": "", "Version:": "Versione:", "Disconnect": "Disconnetti", "Connect": "Connetti", diff --git a/po/po2js b/po/po2js index fc6e88103..e293deda6 100755 --- a/po/po2js +++ b/po/po2js @@ -32,11 +32,13 @@ if (opt.argv.length != 2) { const data = po2json.parseFileSync(opt.argv[0]); -const bodyPart = Object.keys(data).filter(msgid => msgid !== "").map((msgid) => { - if (msgid === "") return; - const msgstr = data[msgid][1]; - return " " + JSON.stringify(msgid) + ": " + JSON.stringify(msgstr); -}).join(",\n"); +const bodyPart = Object.keys(data) + .filter(msgid => msgid !== "") + .filter(msgid => data[msgid][1] !== "") + .map((msgid) => { + const msgstr = data[msgid][1]; + return " " + JSON.stringify(msgid) + ": " + JSON.stringify(msgstr); + }).join(",\n"); const output = "{\n" + bodyPart + "\n}"; From 7f364a173d1875ba029b6f7be1bd41f89d8ca00c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Jun 2024 14:02:34 +0200 Subject: [PATCH 13/22] Update Swedish translation --- app/locale/sv.json | 3 ++- po/sv.po | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/app/locale/sv.json b/app/locale/sv.json index 077ef42c8..80a400bfa 100644 --- a/app/locale/sv.json +++ b/app/locale/sv.json @@ -1,10 +1,11 @@ { - "HTTPS is required for full functionality": "HTTPS krävs för full funktionalitet", + "Running without HTTPS is not recommended, crashes or other issues are likely.": "Det är ej rekommenderat att köra utan HTTPS, krascher och andra problem är troliga.", "Connecting...": "Ansluter...", "Disconnecting...": "Kopplar ner...", "Reconnecting...": "Återansluter...", "Internal error": "Internt fel", "Must set host": "Du måste specifiera en värd", + "Failed to connect to server: ": "Misslyckades att ansluta till servern: ", "Connected (encrypted) to ": "Ansluten (krypterat) till ", "Connected (unencrypted) to ": "Ansluten (okrypterat) till ", "Something went wrong, connection is closed": "Något gick fel, anslutningen avslutades", diff --git a/po/sv.po b/po/sv.po index 972e40004..85c4e3054 100644 --- a/po/sv.po +++ b/po/sv.po @@ -8,20 +8,23 @@ msgid "" msgstr "" "Project-Id-Version: noVNC 1.3.0\n" "Report-Msgid-Bugs-To: novnc@googlegroups.com\n" -"POT-Creation-Date: 2023-01-20 12:54+0100\n" -"PO-Revision-Date: 2023-01-20 12:58+0100\n" -"Last-Translator: Samuel Mannehed \n" +"POT-Creation-Date: 2024-06-03 14:10+0200\n" +"PO-Revision-Date: 2024-06-18 13:52+0200\n" +"Last-Translator: Pierre Ossman \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" -"X-Generator: Poedit 3.2.2\n" +"X-Generator: Poedit 3.4.4\n" #: ../app/ui.js:69 -msgid "HTTPS is required for full functionality" -msgstr "HTTPS krävs för full funktionalitet" +msgid "" +"Running without HTTPS is not recommended, crashes or other issues are likely." +msgstr "" +"Det är ej rekommenderat att köra utan HTTPS, krascher och andra problem är " +"troliga." #: ../app/ui.js:410 msgid "Connecting..." @@ -43,35 +46,39 @@ msgstr "Internt fel" msgid "Must set host" msgstr "Du måste specifiera en värd" -#: ../app/ui.js:1110 +#: ../app/ui.js:1052 +msgid "Failed to connect to server: " +msgstr "Misslyckades att ansluta till servern: " + +#: ../app/ui.js:1118 msgid "Connected (encrypted) to " msgstr "Ansluten (krypterat) till " -#: ../app/ui.js:1112 +#: ../app/ui.js:1120 msgid "Connected (unencrypted) to " msgstr "Ansluten (okrypterat) till " -#: ../app/ui.js:1135 +#: ../app/ui.js:1143 msgid "Something went wrong, connection is closed" msgstr "Något gick fel, anslutningen avslutades" -#: ../app/ui.js:1138 +#: ../app/ui.js:1146 msgid "Failed to connect to server" msgstr "Misslyckades att ansluta till servern" -#: ../app/ui.js:1150 +#: ../app/ui.js:1158 msgid "Disconnected" msgstr "Frånkopplad" -#: ../app/ui.js:1165 +#: ../app/ui.js:1173 msgid "New connection has been rejected with reason: " msgstr "Ny anslutning har blivit nekad med följande skäl: " -#: ../app/ui.js:1168 +#: ../app/ui.js:1176 msgid "New connection has been rejected" msgstr "Ny anslutning har blivit nekad" -#: ../app/ui.js:1234 +#: ../app/ui.js:1242 msgid "Credentials are required" msgstr "Användaruppgifter krävs" @@ -304,8 +311,8 @@ msgid "" "Please verify that the information is correct and press \"Approve\". " "Otherwise press \"Reject\"." msgstr "" -"Kontrollera att informationen är korrekt och tryck sedan " -"\"Godkänn\". Tryck annars \"Neka\"." +"Kontrollera att informationen är korrekt och tryck sedan \"Godkänn\". Tryck " +"annars \"Neka\"." #: ../vnc.html:291 msgid "Approve" @@ -335,5 +342,8 @@ msgstr "Skicka Användaruppgifter" msgid "Cancel" msgstr "Avbryt" +#~ msgid "HTTPS is required for full functionality" +#~ msgstr "HTTPS krävs för full funktionalitet" + #~ msgid "Clear" #~ msgstr "Rensa" From aaadec4f1343e73a3bc9766305544ab896c04ced Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Jun 2024 14:03:30 +0200 Subject: [PATCH 14/22] Update json files for new translations --- app/locale/el.json | 32 +++++++++++++++++++---------- app/locale/fr.json | 2 ++ app/locale/ja.json | 22 +++++++++++++------- app/locale/zh_CN.json | 48 +++++++++++++++++++++---------------------- 4 files changed, 62 insertions(+), 42 deletions(-) diff --git a/app/locale/el.json b/app/locale/el.json index f801251c5..4df3e03c4 100644 --- a/app/locale/el.json +++ b/app/locale/el.json @@ -1,4 +1,5 @@ { + "HTTPS is required for full functionality": "Το HTTPS είναι απαιτούμενο για πλήρη λειτουργικότητα", "Connecting...": "Συνδέεται...", "Disconnecting...": "Aποσυνδέεται...", "Reconnecting...": "Επανασυνδέεται...", @@ -7,19 +8,15 @@ "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": "Απαιτείται ο κωδικός πρόσβασης", + "Credentials are required": "Απαιτούνται διαπιστευτήρια", "noVNC encountered an error:": "το noVNC αντιμετώπισε ένα σφάλμα:", "Hide/Show the control bar": "Απόκρυψη/Εμφάνιση γραμμής ελέγχου", + "Drag": "Σύρσιμο", "Move/Drag Viewport": "Μετακίνηση/Σύρσιμο Θεατού πεδίου", - "viewport drag": "σύρσιμο θεατού πεδίου", - "Active Mouse Button": "Ενεργό Πλήκτρο Ποντικιού", - "No mousebutton": "Χωρίς Πλήκτρο Ποντικιού", - "Left mousebutton": "Αριστερό Πλήκτρο Ποντικιού", - "Middle mousebutton": "Μεσαίο Πλήκτρο Ποντικιού", - "Right mousebutton": "Δεξί Πλήκτρο Ποντικιού", "Keyboard": "Πληκτρολόγιο", "Show Keyboard": "Εμφάνιση Πληκτρολογίου", "Extra keys": "Επιπλέον πλήκτρα", @@ -28,6 +25,8 @@ "Toggle Ctrl": "Εναλλαγή Ctrl", "Alt": "Alt", "Toggle Alt": "Εναλλαγή Alt", + "Toggle Windows": "Εναλλαγή Παράθυρων", + "Windows": "Παράθυρα", "Send Tab": "Αποστολή Tab", "Tab": "Tab", "Esc": "Esc", @@ -41,8 +40,7 @@ "Reboot": "Επανεκκίνηση", "Reset": "Επαναφορά", "Clipboard": "Πρόχειρο", - "Clear": "Καθάρισμα", - "Fullscreen": "Πλήρης Οθόνη", + "Edit clipboard content in the textarea below.": "Επεξεργαστείτε το περιεχόμενο του πρόχειρου στην περιοχή κειμένου παρακάτω.", "Settings": "Ρυθμίσεις", "Shared Mode": "Κοινόχρηστη Λειτουργία", "View Only": "Μόνο Θέαση", @@ -52,6 +50,8 @@ "Local Scaling": "Τοπική Κλιμάκωση", "Remote Resizing": "Απομακρυσμένη Αλλαγή μεγέθους", "Advanced": "Για προχωρημένους", + "Quality:": "Ποιότητα:", + "Compression level:": "Επίπεδο συμπίεσης:", "Repeater ID:": "Repeater ID:", "WebSocket": "WebSocket", "Encrypt": "Κρυπτογράφηση", @@ -60,10 +60,20 @@ "Path:": "Διαδρομή:", "Automatic Reconnect": "Αυτόματη επανασύνδεση", "Reconnect Delay (ms):": "Καθυστέρηση επανασύνδεσης (ms):", + "Show Dot when No Cursor": "Εμφάνιση Τελείας όταν δεν υπάρχει Δρομέας", "Logging:": "Καταγραφή:", + "Version:": "Έκδοση:", "Disconnect": "Αποσύνδεση", "Connect": "Σύνδεση", + "Server identity": "Ταυτότητα Διακομιστή", + "The server has provided the following identifying information:": "Ο διακομιστής παρείχε την ακόλουθη πληροφορία ταυτοποίησης:", + "Fingerprint:": "Δακτυλικό αποτύπωμα:", + "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "Παρακαλώ επαληθεύσετε ότι η πληροφορία είναι σωστή και πιέστε \"Αποδοχή\". Αλλιώς πιέστε \"Απόρριψη\".", + "Approve": "Αποδοχή", + "Reject": "Απόρριψη", + "Credentials": "Διαπιστευτήρια", + "Username:": "Κωδικός Χρήστη:", "Password:": "Κωδικός Πρόσβασης:", - "Cancel": "Ακύρωση", - "Canvas not supported.": "Δεν υποστηρίζεται το στοιχείο Canvas" + "Send Credentials": "Αποστολή Διαπιστευτηρίων", + "Cancel": "Ακύρωση" } \ No newline at end of file diff --git a/app/locale/fr.json b/app/locale/fr.json index e25f34ece..c0eeec7d3 100644 --- a/app/locale/fr.json +++ b/app/locale/fr.json @@ -39,6 +39,8 @@ "Reboot": "Redémarrer", "Reset": "Réinitialiser", "Clipboard": "Presse-papiers", + "Clear": "Effacer", + "Fullscreen": "Plein écran", "Settings": "Paramètres", "Shared Mode": "Mode partagé", "View Only": "Afficher uniquement", diff --git a/app/locale/ja.json b/app/locale/ja.json index 43fc5bf38..70fd7a5d1 100644 --- a/app/locale/ja.json +++ b/app/locale/ja.json @@ -1,4 +1,5 @@ { + "HTTPS is required for full functionality": "すべての機能を使用するにはHTTPS接続が必要です", "Connecting...": "接続しています...", "Disconnecting...": "切断しています...", "Reconnecting...": "再接続しています...", @@ -21,10 +22,10 @@ "Extra keys": "追加キー", "Show Extra Keys": "追加キーを表示", "Ctrl": "Ctrl", - "Toggle Ctrl": "Ctrl キーを切り替え", + "Toggle Ctrl": "Ctrl キーをトグル", "Alt": "Alt", - "Toggle Alt": "Alt キーを切り替え", - "Toggle Windows": "Windows キーを切り替え", + "Toggle Alt": "Alt キーをトグル", + "Toggle Windows": "Windows キーをトグル", "Windows": "Windows", "Send Tab": "Tab キーを送信", "Tab": "Tab", @@ -39,11 +40,11 @@ "Reboot": "再起動", "Reset": "リセット", "Clipboard": "クリップボード", - "Clear": "クリア", - "Fullscreen": "全画面表示", + "Edit clipboard content in the textarea below.": "以下の入力欄からクリップボードの内容を編集できます。", + "Full Screen": "全画面表示", "Settings": "設定", "Shared Mode": "共有モード", - "View Only": "表示のみ", + "View Only": "表示専用", "Clip to Window": "ウィンドウにクリップ", "Scaling Mode:": "スケーリングモード:", "None": "なし", @@ -60,11 +61,18 @@ "Path:": "パス:", "Automatic Reconnect": "自動再接続", "Reconnect Delay (ms):": "再接続する遅延 (ミリ秒):", - "Show Dot when No Cursor": "カーソルがないときにドットを表示", + "Show Dot when No Cursor": "カーソルがないときにドットを表示する", "Logging:": "ロギング:", "Version:": "バージョン:", "Disconnect": "切断", "Connect": "接続", + "Server identity": "サーバーの識別情報", + "The server has provided the following identifying information:": "サーバーは以下の識別情報を提供しています:", + "Fingerprint:": "フィンガープリント:", + "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "この情報が正しい場合は「承認」を、そうでない場合は「拒否」を押してください。", + "Approve": "承認", + "Reject": "拒否", + "Credentials": "資格情報", "Username:": "ユーザー名:", "Password:": "パスワード:", "Send Credentials": "資格情報を送信", diff --git a/app/locale/zh_CN.json b/app/locale/zh_CN.json index f0aea9af3..3679eaddd 100644 --- a/app/locale/zh_CN.json +++ b/app/locale/zh_CN.json @@ -1,69 +1,69 @@ { "Connecting...": "连接中...", + "Connected (encrypted) to ": "已连接(已加密)到", + "Connected (unencrypted) to ": "已连接(未加密)到", "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": "连接被拒绝", + "Must set host": "必须设置主机", + "Reconnecting...": "重新连接中...", "Password is required": "请提供密码", + "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": "鼠标右鍵", + "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", + "Edit clipboard content in the textarea below.": "在下面的文本区域中编辑剪贴板内容。", "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...": "关机/重新启动...", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "发送 Ctrl+Alt+Del 键", + "Shutdown/Reboot": "关机/重启", + "Shutdown/Reboot...": "关机/重启...", "Power": "电源", "Shutdown": "关机", - "Reboot": "重新启动", + "Reboot": "重启", "Reset": "重置", "Clipboard": "剪贴板", "Clear": "清除", "Fullscreen": "全屏", "Settings": "设置", + "Encrypt": "加密", "Shared Mode": "分享模式", "View Only": "仅查看", "Clip to Window": "限制/裁切窗口大小", "Scaling Mode:": "缩放模式:", "None": "无", "Local Scaling": "本地缩放", + "Local Downscaling": "降低本地尺寸", "Remote Resizing": "远程调整大小", "Advanced": "高级", + "Local Cursor": "本地光标", "Repeater ID:": "中继站 ID", "WebSocket": "WebSocket", - "Encrypt": "加密", "Host:": "主机:", "Port:": "端口:", "Path:": "路径:", "Automatic Reconnect": "自动重新连接", "Reconnect Delay (ms):": "重新连接间隔 (ms):", "Logging:": "日志级别:", - "Disconnect": "中断连接", + "Disconnect": "断开连接", "Connect": "连接", "Password:": "密码:", - "Cancel": "取消" + "Cancel": "取消", + "Canvas not supported.": "不支持 Canvas。" } \ No newline at end of file From 7fcf9dcfe0cc5b14e3841a4429dc091a6ffca861 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Jun 2024 14:05:35 +0200 Subject: [PATCH 15/22] noVNC 1.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index af6cfc742..9fa8c312d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@novnc/novnc", - "version": "1.5.0-beta", + "version": "1.5.0", "description": "An HTML5 VNC client", "browser": "lib/rfb", "directories": { From 1230a4ce738ebccce80fc08ee6172bc3a19fadba Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Tue, 23 Jul 2024 00:19:26 +0200 Subject: [PATCH 16/22] Use theme-color to color address bar in browsers This makes the address bar on mobile browsers match the background. Note that it requires a valid certificate and a non-dark mode set on the device. Not supported on desktop browsers. --- vnc.html | 1 + 1 file changed, 1 insertion(+) diff --git a/vnc.html b/vnc.html index 24a118dbd..89ee11e36 100644 --- a/vnc.html +++ b/vnc.html @@ -16,6 +16,7 @@ noVNC + From 6c07136169830d70a1db2d67f7b955b6bc834d6f Mon Sep 17 00:00:00 2001 From: leedagee <61650578+leedagee@users.noreply.github.com> Date: Thu, 1 Aug 2024 01:31:47 +0800 Subject: [PATCH 17/22] Interrupt AltGr sequence detection on focus lost, fixes #1880 --- core/input/keyboard.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/core/input/keyboard.js b/core/input/keyboard.js index 68da2312b..ff14de849 100644 --- a/core/input/keyboard.js +++ b/core/input/keyboard.js @@ -203,7 +203,7 @@ export default class Keyboard { if ((code === "ControlLeft") && browser.isWindows() && !("ControlLeft" in this._keyDownList)) { this._altGrArmed = true; - this._altGrTimeout = setTimeout(this._handleAltGrTimeout.bind(this), 100); + this._altGrTimeout = setTimeout(this._interruptAltGrSequence.bind(this), 100); this._altGrCtrlTime = e.timeStamp; return; } @@ -218,11 +218,7 @@ export default class Keyboard { // 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); - } + this._interruptAltGrSequence(); // See comment in _handleKeyDown() if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) { @@ -249,14 +245,20 @@ export default class Keyboard { } } - _handleAltGrTimeout() { - this._altGrArmed = false; - clearTimeout(this._altGrTimeout); - this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); + _interruptAltGrSequence() { + if (this._altGrArmed) { + this._altGrArmed = false; + clearTimeout(this._altGrTimeout); + this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); + } } _allKeysUp() { Log.Debug(">> Keyboard.allKeysUp"); + + // Prevent control key being processed after losing focus. + this._interruptAltGrSequence(); + for (let code in this._keyDownList) { this._sendKeyEvent(this._keyDownList[code], code, false); } From bc31e4e8a274c0218de010c0d37b5e684e739ac4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 5 Aug 2024 15:44:07 +0200 Subject: [PATCH 18/22] Stop creating sinon sandbox early sinon might not be loaded at this point, which can cause tests to fail. We could create the sandbox in one of the hooks instead, but let's remove the sandbox completely to stay consistent with our other tests. --- tests/test.webutil.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/test.webutil.js b/tests/test.webutil.js index df8227aef..11d093092 100644 --- a/tests/test.webutil.js +++ b/tests/test.webutil.js @@ -182,16 +182,15 @@ describe('WebUtil', function () { window.chrome = chrome; }); - const csSandbox = sinon.createSandbox(); - beforeEach(function () { settings = {}; - csSandbox.spy(window.chrome.storage.sync, 'set'); - csSandbox.spy(window.chrome.storage.sync, 'remove'); + sinon.spy(window.chrome.storage.sync, 'set'); + sinon.spy(window.chrome.storage.sync, 'remove'); return WebUtil.initSettings(); }); afterEach(function () { - csSandbox.restore(); + window.chrome.storage.sync.set.restore(); + window.chrome.storage.sync.remove.restore(); }); describe('writeSetting', function () { From 1b2fe3321bface82604f2c5034cbc2ad8396560a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 5 Aug 2024 14:23:54 +0200 Subject: [PATCH 19/22] Manually load sinon and chai karma-sinon-chai is not compatible with Chai 5+, and Karma is no longer being updated. Load sinon and chai manually instead, until we can have a long term plan in place. --- eslint.config.mjs | 2 +- karma.conf.js | 11 +++++++++-- package.json | 1 - tests/assertions.js | 9 +++++++++ tests/test.base64.js | 2 -- tests/test.browser.js | 2 -- tests/test.copyrect.js | 2 -- tests/test.deflator.js | 2 -- tests/test.display.js | 2 -- tests/test.gesturehandler.js | 2 -- tests/test.helper.js | 2 -- tests/test.hextile.js | 2 -- tests/test.inflator.js | 2 -- tests/test.int.js | 2 -- tests/test.jpeg.js | 2 -- tests/test.keyboard.js | 2 -- tests/test.localization.js | 1 - tests/test.raw.js | 2 -- tests/test.rfb.js | 2 -- tests/test.rre.js | 2 -- tests/test.tight.js | 2 -- tests/test.tightpng.js | 2 -- tests/test.util.js | 2 -- tests/test.websock.js | 2 -- tests/test.webutil.js | 2 -- tests/test.zrle.js | 2 -- 26 files changed, 19 insertions(+), 47 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index c88e7b758..13b1a32a4 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -79,7 +79,7 @@ export default [ ...globals.node, ...globals.mocha, sinon: false, - chai: false, + expect: false, } }, rules: { diff --git a/karma.conf.js b/karma.conf.js index 1ea17475a..54380ebd2 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -27,15 +27,22 @@ module.exports = (config) => { // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['mocha', 'sinon-chai'], + frameworks: ['mocha'], - // list of files / patterns to load in the browser (loaded in order) + // list of files / patterns to load in the browser files: [ + // node modules + { pattern: 'node_modules/chai/**', included: false }, + { pattern: 'node_modules/sinon/**', included: false }, + { pattern: 'node_modules/sinon-chai/**', included: false }, + // modules to test { pattern: 'app/localization.js', included: false, type: 'module' }, { pattern: 'app/webutil.js', included: false, type: 'module' }, { pattern: 'core/**/*.js', included: false, type: 'module' }, { pattern: 'vendor/pako/**/*.js', included: false, type: 'module' }, + // tests { pattern: 'tests/test.*.js', type: 'module' }, + // test support files { pattern: 'tests/fake.*.js', included: false, type: 'module' }, { pattern: 'tests/assertions.js', type: 'module' }, ], diff --git a/package.json b/package.json index 9fa8c312d..e28850a8d 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,6 @@ "karma-mocha-reporter": "latest", "karma-safari-launcher": "latest", "karma-script-launcher": "latest", - "karma-sinon-chai": "latest", "mocha": "latest", "node-getopt": "latest", "po2json": "latest", diff --git a/tests/assertions.js b/tests/assertions.js index 739f63753..a70122717 100644 --- a/tests/assertions.js +++ b/tests/assertions.js @@ -1,3 +1,12 @@ +import * as chai from '../node_modules/chai/chai.js'; +import sinon from '../node_modules/sinon/pkg/sinon-esm.js'; +import sinonChai from '../node_modules/sinon-chai/lib/sinon-chai.js'; + +window.expect = chai.expect; + +window.sinon = sinon; +chai.use(sinonChai); + // noVNC specific assertions chai.use(function (_chai, utils) { function _equal(a, b) { diff --git a/tests/test.base64.js b/tests/test.base64.js index 04bd207b7..e5644dcdb 100644 --- a/tests/test.base64.js +++ b/tests/test.base64.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Base64 from '../core/base64.js'; describe('Base64 Tools', function () { diff --git a/tests/test.browser.js b/tests/test.browser.js index 1beeb48d5..692cc23b2 100644 --- a/tests/test.browser.js +++ b/tests/test.browser.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import { isMac, isWindows, isIOS, isAndroid, isChromeOS, isSafari, isFirefox, isChrome, isChromium, isOpera, isEdge, isGecko, isWebKit, isBlink } from '../core/util/browser.js'; diff --git a/tests/test.copyrect.js b/tests/test.copyrect.js index a10cddce7..60c395287 100644 --- a/tests/test.copyrect.js +++ b/tests/test.copyrect.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Websock from '../core/websock.js'; import Display from '../core/display.js'; diff --git a/tests/test.deflator.js b/tests/test.deflator.js index a7e972ec0..b565b9075 100644 --- a/tests/test.deflator.js +++ b/tests/test.deflator.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import { inflateInit, inflate } from "../vendor/pako/lib/zlib/inflate.js"; import ZStream from "../vendor/pako/lib/zlib/zstream.js"; import Deflator from "../core/deflator.js"; diff --git a/tests/test.display.js b/tests/test.display.js index e6c0406f9..d2c51793b 100644 --- a/tests/test.display.js +++ b/tests/test.display.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Base64 from '../core/base64.js'; import Display from '../core/display.js'; diff --git a/tests/test.gesturehandler.js b/tests/test.gesturehandler.js index 73356be36..d2e27ed2a 100644 --- a/tests/test.gesturehandler.js +++ b/tests/test.gesturehandler.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import EventTargetMixin from '../core/util/eventtarget.js'; import GestureHandler from '../core/input/gesturehandler.js'; diff --git a/tests/test.helper.js b/tests/test.helper.js index 9995973fd..2c8720c77 100644 --- a/tests/test.helper.js +++ b/tests/test.helper.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import keysyms from '../core/input/keysymdef.js'; import * as KeyboardUtil from "../core/input/util.js"; diff --git a/tests/test.hextile.js b/tests/test.hextile.js index cbe6f7b5a..f788fd4dc 100644 --- a/tests/test.hextile.js +++ b/tests/test.hextile.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Websock from '../core/websock.js'; import Display from '../core/display.js'; diff --git a/tests/test.inflator.js b/tests/test.inflator.js index 304e7a0fd..11a02f2f4 100644 --- a/tests/test.inflator.js +++ b/tests/test.inflator.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import { deflateInit, deflate, Z_FULL_FLUSH } from "../vendor/pako/lib/zlib/deflate.js"; import ZStream from "../vendor/pako/lib/zlib/zstream.js"; import Inflator from "../core/inflator.js"; diff --git a/tests/test.int.js b/tests/test.int.js index 084d68abd..378ebd589 100644 --- a/tests/test.int.js +++ b/tests/test.int.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import { toUnsigned32bit, toSigned32bit } from '../core/util/int.js'; describe('Integer casting', function () { diff --git a/tests/test.jpeg.js b/tests/test.jpeg.js index 8dee48912..5cc153f90 100644 --- a/tests/test.jpeg.js +++ b/tests/test.jpeg.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Websock from '../core/websock.js'; import Display from '../core/display.js'; diff --git a/tests/test.keyboard.js b/tests/test.keyboard.js index efc84c306..135c5981b 100644 --- a/tests/test.keyboard.js +++ b/tests/test.keyboard.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Keyboard from '../core/input/keyboard.js'; describe('Key Event Handling', function () { diff --git a/tests/test.localization.js b/tests/test.localization.js index 916ff8462..a1cb45474 100644 --- a/tests/test.localization.js +++ b/tests/test.localization.js @@ -1,4 +1,3 @@ -const expect = chai.expect; import _, { Localizer, l10n } from '../app/localization.js'; describe('Localization', function () { diff --git a/tests/test.raw.js b/tests/test.raw.js index 4a634ccd0..19b2377f7 100644 --- a/tests/test.raw.js +++ b/tests/test.raw.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Websock from '../core/websock.js'; import Display from '../core/display.js'; diff --git a/tests/test.rfb.js b/tests/test.rfb.js index 62b80ca3f..2be3bfbfc 100644 --- a/tests/test.rfb.js +++ b/tests/test.rfb.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import RFB from '../core/rfb.js'; import Websock from '../core/websock.js'; import ZStream from "../vendor/pako/lib/zlib/zstream.js"; diff --git a/tests/test.rre.js b/tests/test.rre.js index c55d7f397..7b5f73d0e 100644 --- a/tests/test.rre.js +++ b/tests/test.rre.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Websock from '../core/websock.js'; import Display from '../core/display.js'; diff --git a/tests/test.tight.js b/tests/test.tight.js index 141d7b6e2..3d6b555da 100644 --- a/tests/test.tight.js +++ b/tests/test.tight.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Websock from '../core/websock.js'; import Display from '../core/display.js'; diff --git a/tests/test.tightpng.js b/tests/test.tightpng.js index 02c66d93b..e7edc8fa6 100644 --- a/tests/test.tightpng.js +++ b/tests/test.tightpng.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Websock from '../core/websock.js'; import Display from '../core/display.js'; diff --git a/tests/test.util.js b/tests/test.util.js index cd61f248a..eb7240951 100644 --- a/tests/test.util.js +++ b/tests/test.util.js @@ -1,6 +1,4 @@ /* eslint-disable no-console */ -const expect = chai.expect; - import * as Log from '../core/util/logging.js'; import { encodeUTF8, decodeUTF8 } from '../core/util/strings.js'; diff --git a/tests/test.websock.js b/tests/test.websock.js index dc361b749..53145b360 100644 --- a/tests/test.websock.js +++ b/tests/test.websock.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Websock from '../core/websock.js'; import FakeWebSocket from './fake.websocket.js'; diff --git a/tests/test.webutil.js b/tests/test.webutil.js index 11d093092..9151a0603 100644 --- a/tests/test.webutil.js +++ b/tests/test.webutil.js @@ -1,7 +1,5 @@ /* jshint expr: true */ -const expect = chai.expect; - import * as WebUtil from '../app/webutil.js'; describe('WebUtil', function () { diff --git a/tests/test.zrle.js b/tests/test.zrle.js index be0464093..f7c6089d5 100644 --- a/tests/test.zrle.js +++ b/tests/test.zrle.js @@ -1,5 +1,3 @@ -const expect = chai.expect; - import Websock from '../core/websock.js'; import Display from '../core/display.js'; From 06f14a5cd3c188c63ad2060b7532a914c0d8f7f6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 5 Aug 2024 16:31:59 +0200 Subject: [PATCH 20/22] Add test for AltGr abort on blur --- tests/test.keyboard.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test.keyboard.js b/tests/test.keyboard.js index 135c5981b..11c8b6eb7 100644 --- a/tests/test.keyboard.js +++ b/tests/test.keyboard.js @@ -478,6 +478,22 @@ describe('Key Event Handling', function () { expect(kbd.onkeyevent).to.not.have.been.called; }); + it('should release ControlLeft on blur', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); + expect(kbd.onkeyevent).to.not.have.been.called; + kbd._allKeysUp(); + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffe3, "ControlLeft", false); + + // Check that the timer is properly dead + kbd.onkeyevent.resetHistory(); + this.clock.tick(100); + expect(kbd.onkeyevent).to.not.have.been.called; + }); + it('should generate AltGraph for quick Ctrl+Alt sequence', function () { const kbd = new Keyboard(document); kbd.onkeyevent = sinon.spy(); From 074fa1a40f6e3f65bd61109de3f404796e266524 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 8 Aug 2024 14:40:04 +0200 Subject: [PATCH 21/22] Let browser construct URL string for us Likely a lot safer for corner cases than us trying to figure this out ourselves. --- app/ui.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/ui.js b/app/ui.js index f27dfe28e..1a9571dc2 100644 --- a/app/ui.js +++ b/app/ui.js @@ -1033,16 +1033,17 @@ const UI = { let url; - url = UI.getSetting('encrypt') ? 'wss' : 'ws'; + url = new URL("https://" + host); - url += '://' + host; + url.protocol = UI.getSetting('encrypt') ? 'wss:' : 'ws:'; if (port) { - url += ':' + port; + url.port = port; } - url += '/' + path; + url.pathname = '/' + path; try { - UI.rfb = new RFB(document.getElementById('noVNC_container'), url, + UI.rfb = new RFB(document.getElementById('noVNC_container'), + url.href, { shared: UI.getSetting('shared'), repeaterID: UI.getSetting('repeaterID'), credentials: { password: password } }); From 96c76f7709037956e760ae5f58dbde1bc1308bba Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 8 Aug 2024 14:53:42 +0200 Subject: [PATCH 22/22] Allow relative WebSocket URLs This can be very useful if you have multiple instances of noVNC, and you want to redirect them to different VNC servers. The new default settings will have the same behaviour as before for systems where noVNC is deployed in the root web folder. --- app/ui.js | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/app/ui.js b/app/ui.js index 1a9571dc2..90dc71893 100644 --- a/app/ui.js +++ b/app/ui.js @@ -158,20 +158,7 @@ const UI = { UI.initSetting('logging', 'warn'); UI.updateLogging(); - // if port == 80 (or 443) then it won't be present and should be - // set manually - let port = window.location.port; - if (!port) { - if (window.location.protocol.substring(0, 5) == 'https') { - port = 443; - } else if (window.location.protocol.substring(0, 4) == 'http') { - port = 80; - } - } - /* Populate the controls if defaults are provided in the URL */ - UI.initSetting('host', window.location.hostname); - UI.initSetting('port', port); UI.initSetting('encrypt', (window.location.protocol === "https:")); UI.initSetting('view_clip', false); UI.initSetting('resize', 'off'); @@ -1021,25 +1008,27 @@ const UI = { UI.hideStatus(); - if (!host) { - Log.Error("Can't connect when host is: " + host); - UI.showStatus(_("Must set host"), 'error'); - return; - } - UI.closeConnectPanel(); UI.updateVisualState('connecting'); let url; - url = new URL("https://" + host); + if (host) { + url = new URL("https://" + host); - url.protocol = UI.getSetting('encrypt') ? 'wss:' : 'ws:'; - if (port) { - url.port = port; + url.protocol = UI.getSetting('encrypt') ? 'wss:' : 'ws:'; + if (port) { + url.port = port; + } + url.pathname = '/' + path; + } else { + // Current (May 2024) browsers support relative WebSocket + // URLs natively, but we need to support older browsers for + // some time. + url = new URL(path, location.href); + url.protocol = (window.location.protocol === "https:") ? 'wss:' : 'ws:'; } - url.pathname = '/' + path; try { UI.rfb = new RFB(document.getElementById('noVNC_container'),