mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	Merge remote-tracking branch 'origin/4.18'
This commit is contained in:
		
						commit
						52fa31b446
					
				| @ -6,21 +6,17 @@ | ||||
|  * See README.md for usage and integration instructions. | ||||
|  */ | ||||
| 
 | ||||
| // NB: this should *not* be included as a module until we have
 | ||||
| // native support in the browsers, so that our error handler
 | ||||
| // can catch script-loading errors.
 | ||||
| 
 | ||||
| // No ES6 can be used in this file since it's used for the translation
 | ||||
| /* eslint-disable prefer-arrow-callback */ | ||||
| 
 | ||||
| (function _scope() { | ||||
|     "use strict"; | ||||
| 
 | ||||
| // Fallback for all uncought errors
 | ||||
| function handleError(event, err) { | ||||
|     try { | ||||
|         const msg = document.getElementById('noVNC_fallback_errormsg'); | ||||
| 
 | ||||
|         // Work around Firefox bug:
 | ||||
|         // https://bugzilla.mozilla.org/show_bug.cgi?id=1685038
 | ||||
|         if (event.message === "ResizeObserver loop completed with undelivered notifications.") { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         // Only show the initial error
 | ||||
|         if (msg.hasChildNodes()) { | ||||
|             return false; | ||||
| @ -54,13 +50,30 @@ | ||||
| 
 | ||||
|         document.getElementById('noVNC_fallback_error') | ||||
|             .classList.add("noVNC_open"); | ||||
| 
 | ||||
|     } catch (exc) { | ||||
|         document.write("noVNC encountered an error."); | ||||
|     } | ||||
| 
 | ||||
|     // Try to disable keyboard interaction, best effort
 | ||||
|     try { | ||||
|         // Remove focus from the currently focused element in order to
 | ||||
|         // prevent keyboard interaction from continuing
 | ||||
|         if (document.activeElement) { document.activeElement.blur(); } | ||||
| 
 | ||||
|         // Don't let any element be focusable when showing the error
 | ||||
|         let keyboardFocusable = 'a[href], button, input, textarea, select, details, [tabindex]'; | ||||
|         document.querySelectorAll(keyboardFocusable).forEach((elem) => { | ||||
|             elem.setAttribute("tabindex", "-1"); | ||||
|         }); | ||||
|     } catch (exc) { | ||||
|         // Do nothing
 | ||||
|     } | ||||
| 
 | ||||
|     // Don't return true since this would prevent the error
 | ||||
|     // from being printed to the browser console.
 | ||||
|     return false; | ||||
| } | ||||
|     window.addEventListener('error', function onerror(evt) { handleError(evt, evt.error); }); | ||||
|     window.addEventListener('unhandledrejection', function onreject(evt) { handleError(evt.reason, evt.reason); }); | ||||
| })(); | ||||
| 
 | ||||
| window.addEventListener('error', evt => handleError(evt, evt.error)); | ||||
| window.addEventListener('unhandledrejection', evt => handleError(evt.reason, evt.reason)); | ||||
|  | ||||
| @ -1,42 +1,42 @@ | ||||
| ICONS := \
 | ||||
| 	novnc-16x16.png \
 | ||||
| 	novnc-24x24.png \
 | ||||
| 	novnc-32x32.png \
 | ||||
| 	novnc-48x48.png \
 | ||||
| 	novnc-64x64.png | ||||
| BROWSER_SIZES := 16 24 32 48 64 | ||||
| #ANDROID_SIZES := 72 96 144 192
 | ||||
| # FIXME: The ICO is limited to 8 icons due to a Chrome bug:
 | ||||
| #        https://bugs.chromium.org/p/chromium/issues/detail?id=1381393
 | ||||
| ANDROID_SIZES := 96 144 192 | ||||
| WEB_ICON_SIZES := $(BROWSER_SIZES) $(ANDROID_SIZES) | ||||
| 
 | ||||
| ANDROID_LAUNCHER := \
 | ||||
| 	novnc-48x48.png \
 | ||||
| 	novnc-72x72.png \
 | ||||
| 	novnc-96x96.png \
 | ||||
| 	novnc-144x144.png \
 | ||||
| 	novnc-192x192.png | ||||
| #IOS_1X_SIZES := 20 29 40 76 # No such devices exist anymore
 | ||||
| IOS_2X_SIZES := 40 58 80 120 152 167 | ||||
| IOS_3X_SIZES := 60 87 120 180 | ||||
| ALL_IOS_SIZES := $(IOS_1X_SIZES) $(IOS_2X_SIZES) $(IOS_3X_SIZES) | ||||
| 
 | ||||
| IPHONE_LAUNCHER := \
 | ||||
| 	novnc-60x60.png \
 | ||||
| 	novnc-120x120.png | ||||
| 
 | ||||
| IPAD_LAUNCHER := \
 | ||||
| 	novnc-76x76.png \
 | ||||
| 	novnc-152x152.png | ||||
| 
 | ||||
| ALL_ICONS := $(ICONS) $(ANDROID_LAUNCHER) $(IPHONE_LAUNCHER) $(IPAD_LAUNCHER) | ||||
| ALL_ICONS := \
 | ||||
| 	$(ALL_IOS_SIZES:%=novnc-ios-%.png) \
 | ||||
| 	novnc.ico | ||||
| 
 | ||||
| all: $(ALL_ICONS) | ||||
| 
 | ||||
| novnc-16x16.png: novnc-icon-sm.svg | ||||
| 	convert -density 90 \
 | ||||
| 		-background transparent "$<" "$@" | ||||
| novnc-24x24.png: novnc-icon-sm.svg | ||||
| 	convert -density 135 \
 | ||||
| 		-background transparent "$<" "$@" | ||||
| novnc-32x32.png: novnc-icon-sm.svg | ||||
| 	convert -density 180 \
 | ||||
| 		-background transparent "$<" "$@" | ||||
| # Our testing shows that the ICO file need to be sorted in largest to
 | ||||
| # smallest to get the apporpriate behviour
 | ||||
| WEB_ICON_SIZES_REVERSE := $(shell echo $(WEB_ICON_SIZES) | tr ' ' '\n' | sort -nr | tr '\n' ' ') | ||||
| WEB_BASE_ICONS := $(WEB_ICON_SIZES_REVERSE:%=novnc-%.png) | ||||
| .INTERMEDIATE: $(WEB_BASE_ICONS) | ||||
| 
 | ||||
| novnc.ico: $(WEB_BASE_ICONS) | ||||
| 	convert $(WEB_BASE_ICONS) "$@" | ||||
| 
 | ||||
| # General conversion
 | ||||
| novnc-%.png: novnc-icon.svg | ||||
| 	convert -density $$[`echo $* | cut -d x -f 1` * 90 / 48] \
 | ||||
| 		-background transparent "$<" "$@" | ||||
| 	convert -depth 8 -background transparent \
 | ||||
| 		-size $*x$* "$(lastword $^)" "$@" | ||||
| 
 | ||||
| # iOS icons use their own SVG
 | ||||
| novnc-ios-%.png: novnc-ios-icon.svg | ||||
| 	convert -depth 8 -background transparent \
 | ||||
| 		-size $*x$* "$(lastword $^)" "$@" | ||||
| 
 | ||||
| # The smallest sizes are generated using a different SVG
 | ||||
| novnc-16.png novnc-24.png novnc-32.png: novnc-icon-sm.svg | ||||
| 
 | ||||
| clean: | ||||
| 	rm -f *.png | ||||
|  | ||||
							
								
								
									
										183
									
								
								systemvm/agent/noVNC/app/images/icons/novnc-ios-icon.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								systemvm/agent/noVNC/app/images/icons/novnc-ios-icon.svg
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,183 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| 
 | ||||
| <svg | ||||
|    width="48" | ||||
|    height="48" | ||||
|    viewBox="0 0 48 48.000001" | ||||
|    id="svg2" | ||||
|    version="1.1" | ||||
|    inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" | ||||
|    sodipodi:docname="novnc-ios-icon.svg" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/"> | ||||
|   <defs | ||||
|      id="defs4" /> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="11.313708" | ||||
|      inkscape:cx="27.356195" | ||||
|      inkscape:cy="17.810253" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      units="px" | ||||
|      inkscape:object-nodes="true" | ||||
|      inkscape:snap-smooth-nodes="true" | ||||
|      inkscape:snap-midpoints="true" | ||||
|      inkscape:window-width="2560" | ||||
|      inkscape:window-height="1371" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="0" | ||||
|      inkscape:window-maximized="1" | ||||
|      inkscape:showpageshadow="2" | ||||
|      inkscape:pagecheckerboard="0" | ||||
|      inkscape:deskcolor="#d1d1d1"> | ||||
|     <inkscape:grid | ||||
|        type="xygrid" | ||||
|        id="grid4169" /> | ||||
|   </sodipodi:namedview> | ||||
|   <metadata | ||||
|      id="metadata7"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(0,-1004.3621)"> | ||||
|     <rect | ||||
|        style="opacity:1;fill:#494949;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||
|        id="rect4167" | ||||
|        width="48" | ||||
|        height="48" | ||||
|        x="0" | ||||
|        y="1004.3621" | ||||
|        inkscape:label="background" /> | ||||
|     <path | ||||
|        style="opacity:1;fill:#313131;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||
|        d="m 0,1004.3621 v 48 h 20 c 15.512,0 28,-16.948 28,-38 v -10 z" | ||||
|        id="rect4173" | ||||
|        inkscape:connector-curvature="0" | ||||
|        sodipodi:nodetypes="cccccc" | ||||
|        inkscape:label="darker_grey_plate" /> | ||||
|     <g | ||||
|        id="g4300" | ||||
|        style="display:inline;fill:#000000;fill-opacity:1;stroke:none" | ||||
|        transform="translate(0.5,0.5)" | ||||
|        inkscape:label="shadows"> | ||||
|       <g | ||||
|          id="g4302" | ||||
|          style="fill:#000000;fill-opacity:1;stroke:none" | ||||
|          inkscape:label="no"> | ||||
|         <path | ||||
|            sodipodi:nodetypes="scsccsssscccs" | ||||
|            d="m 11.986926,1016.3621 c 0.554325,0 1.025987,0.2121 1.414987,0.6362 0.398725,0.4138 0.600909,0.9155 0.598087,1.5052 v 6.8586 h -2 v -6.8914 c 0,-0.072 -0.03404,-0.1086 -0.102113,-0.1086 H 7.1021125 C 7.0340375,1018.3621 7,1018.3983 7,1018.4707 v 6.8914 H 5 v -9 z" | ||||
|            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|            id="path4304" | ||||
|            inkscape:connector-curvature="0" | ||||
|            inkscape:label="n" /> | ||||
|         <path | ||||
|            sodipodi:nodetypes="sscsscsscsscssssssssss" | ||||
|            d="m 17.013073,1016.3621 h 4.973854 c 0.554325,0 1.025987,0.2121 1.414986,0.6362 0.398725,0.4138 0.598087,0.9155 0.598087,1.5052 v 4.7172 c 0,0.5897 -0.199362,1.0966 -0.598087,1.5207 -0.388999,0.4138 -0.860661,0.6207 -1.414986,0.6207 h -4.973854 c -0.554325,0 -1.030849,-0.2069 -1.429574,-0.6207 C 15.1945,1024.3173 15,1023.8104 15,1023.2207 v -4.7172 c 0,-0.5897 0.1945,-1.0914 0.583499,-1.5052 0.398725,-0.4241 0.875249,-0.6362 1.429574,-0.6362 z m 4.884815,2 h -4.795776 c -0.06808,0 -0.102112,0.036 -0.102112,0.1086 v 4.7828 c 0,0.072 0.03404,0.1086 0.102112,0.1086 h 4.795776 c 0.06807,0 0.102112,-0.036 0.102112,-0.1086 v -4.7828 c 0,-0.072 -0.03404,-0.1086 -0.102112,-0.1086 z" | ||||
|            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|            id="path4306" | ||||
|            inkscape:connector-curvature="0" | ||||
|            inkscape:label="o" /> | ||||
|       </g> | ||||
|       <g | ||||
|          id="g4308" | ||||
|          style="fill:#000000;fill-opacity:1;stroke:none" | ||||
|          inkscape:label="VNC"> | ||||
|         <path | ||||
|            sodipodi:nodetypes="cccccccc" | ||||
|            d="m 12,1036.9177 4.768114,-8.5556 H 19 l -6,11 h -2 l -6,-11 h 2.2318854 z" | ||||
|            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|            id="path4310" | ||||
|            inkscape:connector-curvature="0" | ||||
|            inkscape:label="V" /> | ||||
|         <path | ||||
|            sodipodi:nodetypes="ccccccccccc" | ||||
|            d="m 29,1036.3621 v -8 h 2 v 11 h -2 l -7,-8 v 8 h -2 v -11 h 2 z" | ||||
|            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|            id="path4312" | ||||
|            inkscape:connector-curvature="0" | ||||
|            inkscape:label="N" /> | ||||
|         <path | ||||
|            sodipodi:nodetypes="cssssccscsscscc" | ||||
|            d="m 43,1030.3621 h -8.897887 c -0.06808,0 -0.102113,0.036 -0.102113,0.1069 v 6.7862 c 0,0.071 0.03404,0.1069 0.102113,0.1069 H 43 v 2 h -8.972339 c -0.56405,0 -1.045437,-0.2037 -1.444162,-0.6111 C 32.1945,1038.3334 32,1037.8292 32,1037.2385 v -6.7528 c 0,-0.5907 0.1945,-1.0898 0.583499,-1.4972 0.398725,-0.4176 0.880112,-0.6264 1.444162,-0.6264 H 43 Z" | ||||
|            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|            id="path4314" | ||||
|            inkscape:connector-curvature="0" | ||||
|            inkscape:label="C" /> | ||||
|       </g> | ||||
|     </g> | ||||
|     <g | ||||
|        id="g4291" | ||||
|        style="stroke:none" | ||||
|        inkscape:label="noVNC"> | ||||
|       <g | ||||
|          id="g4282" | ||||
|          style="stroke:none" | ||||
|          inkscape:label="no"> | ||||
|         <path | ||||
|            inkscape:connector-curvature="0" | ||||
|            id="path4143" | ||||
|            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|            d="m 11.986926,1016.3621 c 0.554325,0 1.025987,0.2121 1.414987,0.6362 0.398725,0.4138 0.600909,0.9155 0.598087,1.5052 l 0,6.8586 -2,0 0,-6.8914 c 0,-0.072 -0.03404,-0.1086 -0.102113,-0.1086 l -4.7957745,0 C 7.0340375,1018.3621 7,1018.3983 7,1018.4707 l 0,6.8914 -2,0 0,-9 z" | ||||
|            sodipodi:nodetypes="scsccsssscccs" | ||||
|            inkscape:label="n" /> | ||||
|         <path | ||||
|            inkscape:connector-curvature="0" | ||||
|            id="path4145" | ||||
|            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|            d="m 17.013073,1016.3621 4.973854,0 c 0.554325,0 1.025987,0.2121 1.414986,0.6362 0.398725,0.4138 0.598087,0.9155 0.598087,1.5052 l 0,4.7172 c 0,0.5897 -0.199362,1.0966 -0.598087,1.5207 -0.388999,0.4138 -0.860661,0.6207 -1.414986,0.6207 l -4.973854,0 c -0.554325,0 -1.030849,-0.2069 -1.429574,-0.6207 C 15.1945,1024.3173 15,1023.8104 15,1023.2207 l 0,-4.7172 c 0,-0.5897 0.1945,-1.0914 0.583499,-1.5052 0.398725,-0.4241 0.875249,-0.6362 1.429574,-0.6362 z m 4.884815,2 -4.795776,0 c -0.06808,0 -0.102112,0.036 -0.102112,0.1086 l 0,4.7828 c 0,0.072 0.03404,0.1086 0.102112,0.1086 l 4.795776,0 c 0.06807,0 0.102112,-0.036 0.102112,-0.1086 l 0,-4.7828 c 0,-0.072 -0.03404,-0.1086 -0.102112,-0.1086 z" | ||||
|            sodipodi:nodetypes="sscsscsscsscssssssssss" | ||||
|            inkscape:label="o" /> | ||||
|       </g> | ||||
|       <g | ||||
|          id="g4286" | ||||
|          style="stroke:none" | ||||
|          inkscape:label="VNC"> | ||||
|         <path | ||||
|            inkscape:connector-curvature="0" | ||||
|            id="path4147" | ||||
|            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|            d="m 12,1036.9177 4.768114,-8.5556 2.231886,0 -6,11 -2,0 -6,-11 2.2318854,0 z" | ||||
|            sodipodi:nodetypes="cccccccc" | ||||
|            inkscape:label="V" /> | ||||
|         <path | ||||
|            inkscape:connector-curvature="0" | ||||
|            id="path4149" | ||||
|            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|            d="m 29,1036.3621 0,-8 2,0 0,11 -2,0 -7,-8 0,8 -2,0 0,-11 2,0 z" | ||||
|            sodipodi:nodetypes="ccccccccccc" | ||||
|            inkscape:label="N" /> | ||||
|         <path | ||||
|            inkscape:connector-curvature="0" | ||||
|            id="path4151" | ||||
|            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|            d="m 43,1030.3621 -8.897887,0 c -0.06808,0 -0.102113,0.036 -0.102113,0.1069 l 0,6.7862 c 0,0.071 0.03404,0.1069 0.102113,0.1069 l 8.897887,0 0,2 -8.972339,0 c -0.56405,0 -1.045437,-0.2037 -1.444162,-0.6111 C 32.1945,1038.3334 32,1037.8292 32,1037.2385 l 0,-6.7528 c 0,-0.5907 0.1945,-1.0898 0.583499,-1.4972 0.398725,-0.4176 0.880112,-0.6264 1.444162,-0.6264 l 8.972339,0 z" | ||||
|            sodipodi:nodetypes="cssssccscsscscc" | ||||
|            inkscape:label="C" /> | ||||
|       </g> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										0
									
								
								systemvm/agent/noVNC/app/images/icons/novnc.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								systemvm/agent/noVNC/app/images/icons/novnc.ico
									
									
									
									
									
										Normal file
									
								
							| @ -4,9 +4,9 @@ | ||||
|     "Connected (unencrypted) to ": "Conectado (sin encriptación) a", | ||||
|     "Disconnecting...": "Desconectando...", | ||||
|     "Disconnected": "Desconectado", | ||||
|     "Must set host": "Debes configurar el host", | ||||
|     "Must set host": "Se debe configurar el host", | ||||
|     "Reconnecting...": "Reconectando...", | ||||
|     "Password is required": "Contraseña es obligatoria", | ||||
|     "Password is required": "La contraseña es obligatoria", | ||||
|     "Disconnect timeout": "Tiempo de desconexión agotado", | ||||
|     "noVNC encountered an error:": "noVNC ha encontrado un error:", | ||||
|     "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", | ||||
| @ -41,6 +41,7 @@ | ||||
|     "Clear": "Vaciar", | ||||
|     "Fullscreen": "Pantalla Completa", | ||||
|     "Settings": "Configuraciones", | ||||
|     "Encrypt": "Encriptar", | ||||
|     "Shared Mode": "Modo Compartido", | ||||
|     "View Only": "Solo visualización", | ||||
|     "Clip to Window": "Recortar al tamaño de la ventana", | ||||
| @ -51,18 +52,17 @@ | ||||
|     "Remote Resizing": "Cambio de tamaño remoto", | ||||
|     "Advanced": "Avanzado", | ||||
|     "Local Cursor": "Cursor Local", | ||||
|     "Repeater ID:": "ID del Repetidor", | ||||
|     "Repeater ID:": "ID del Repetidor:", | ||||
|     "WebSocket": "WebSocket", | ||||
|     "Encrypt": "", | ||||
|     "Host:": "Host", | ||||
|     "Port:": "Puesto", | ||||
|     "Path:": "Ruta", | ||||
|     "Host:": "Host:", | ||||
|     "Port:": "Puerto:", | ||||
|     "Path:": "Ruta:", | ||||
|     "Automatic Reconnect": "Reconexión automática", | ||||
|     "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", | ||||
|     "Logging:": "Logging", | ||||
|     "Reconnect Delay (ms):": "Retraso en la reconexión (ms):", | ||||
|     "Logging:": "Registrando:", | ||||
|     "Disconnect": "Desconectar", | ||||
|     "Connect": "Conectar", | ||||
|     "Password:": "Contraseña", | ||||
|     "Password:": "Contraseña:", | ||||
|     "Cancel": "Cancelar", | ||||
|     "Canvas not supported.": "Canvas no está soportado" | ||||
|     "Canvas not supported.": "Canvas no soportado." | ||||
| } | ||||
							
								
								
									
										78
									
								
								systemvm/agent/noVNC/app/locale/fr.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								systemvm/agent/noVNC/app/locale/fr.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,78 @@ | ||||
| { | ||||
|     "HTTPS is required for full functionality": "", | ||||
|     "Connecting...": "En cours de connexion...", | ||||
|     "Disconnecting...": "Déconnexion en cours...", | ||||
|     "Reconnecting...": "Reconnexion en cours...", | ||||
|     "Internal error": "Erreur interne", | ||||
|     "Must set host": "Doit définir l'hôte", | ||||
|     "Connected (encrypted) to ": "Connecté (chiffré) à ", | ||||
|     "Connected (unencrypted) to ": "Connecté (non chiffré) à ", | ||||
|     "Something went wrong, connection is closed": "Quelque chose s'est mal passé, la connexion a été fermée", | ||||
|     "Failed to connect to server": "Échec de connexion au serveur", | ||||
|     "Disconnected": "Déconnecté", | ||||
|     "New connection has been rejected with reason: ": "Une nouvelle connexion a été rejetée avec motif : ", | ||||
|     "New connection has been rejected": "Une nouvelle connexion a été rejetée", | ||||
|     "Credentials are required": "Les identifiants sont requis", | ||||
|     "noVNC encountered an error:": "noVNC a rencontré une erreur :", | ||||
|     "Hide/Show the control bar": "Masquer/Afficher la barre de contrôle", | ||||
|     "Drag": "Faire glisser", | ||||
|     "Move/Drag Viewport": "Déplacer/faire glisser le Viewport", | ||||
|     "Keyboard": "Clavier", | ||||
|     "Show Keyboard": "Afficher le clavier", | ||||
|     "Extra keys": "Touches supplémentaires", | ||||
|     "Show Extra Keys": "Afficher les touches supplémentaires", | ||||
|     "Ctrl": "Ctrl", | ||||
|     "Toggle Ctrl": "Basculer Ctrl", | ||||
|     "Alt": "Alt", | ||||
|     "Toggle Alt": "Basculer Alt", | ||||
|     "Toggle Windows": "Basculer Windows", | ||||
|     "Windows": "Windows", | ||||
|     "Send Tab": "Envoyer l'onglet", | ||||
|     "Tab": "l'onglet", | ||||
|     "Esc": "Esc", | ||||
|     "Send Escape": "Envoyer Escape", | ||||
|     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||
|     "Send Ctrl-Alt-Del": "Envoyer Ctrl-Alt-Del", | ||||
|     "Shutdown/Reboot": "Arrêter/Redémarrer", | ||||
|     "Shutdown/Reboot...": "Arrêter/Redémarrer...", | ||||
|     "Power": "Alimentation", | ||||
|     "Shutdown": "Arrêter", | ||||
|     "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", | ||||
|     "Clip to Window": "Clip à fenêtre", | ||||
|     "Scaling Mode:": "Mode mise à l'échelle :", | ||||
|     "None": "Aucun", | ||||
|     "Local Scaling": "Mise à l'échelle locale", | ||||
|     "Remote Resizing": "Redimensionnement à distance", | ||||
|     "Advanced": "Avancé", | ||||
|     "Quality:": "Qualité :", | ||||
|     "Compression level:": "Niveau de compression :", | ||||
|     "Repeater ID:": "ID Répéteur :", | ||||
|     "WebSocket": "WebSocket", | ||||
|     "Encrypt": "Chiffrer", | ||||
|     "Host:": "Hôte :", | ||||
|     "Port:": "Port :", | ||||
|     "Path:": "Chemin :", | ||||
|     "Automatic Reconnect": "Reconnecter automatiquemen", | ||||
|     "Reconnect Delay (ms):": "Délai de reconnexion (ms) :", | ||||
|     "Show Dot when No Cursor": "Afficher le point lorsqu'il n'y a pas de curseur", | ||||
|     "Logging:": "Se connecter :", | ||||
|     "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", | ||||
|     "Cancel": "Annuler" | ||||
| } | ||||
							
								
								
									
										72
									
								
								systemvm/agent/noVNC/app/locale/it.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								systemvm/agent/noVNC/app/locale/it.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | ||||
| { | ||||
|     "Connecting...": "Connessione in corso...", | ||||
|     "Disconnecting...": "Disconnessione...", | ||||
|     "Reconnecting...": "Riconnessione...", | ||||
|     "Internal error": "Errore interno", | ||||
|     "Must set host": "Devi impostare l'host", | ||||
|     "Connected (encrypted) to ": "Connesso (crittografato) a ", | ||||
|     "Connected (unencrypted) to ": "Connesso (non crittografato) a", | ||||
|     "Something went wrong, connection is closed": "Qualcosa è andato storto, la connessione è stata chiusa", | ||||
|     "Failed to connect to server": "Impossibile connettersi al server", | ||||
|     "Disconnected": "Disconnesso", | ||||
|     "New connection has been rejected with reason: ": "La nuova connessione è stata rifiutata con motivo: ", | ||||
|     "New connection has been rejected": "La nuova connessione è stata rifiutata", | ||||
|     "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", | ||||
|     "Show Extra Keys": "Mostra Tasti Aggiuntivi", | ||||
|     "Ctrl": "Ctrl", | ||||
|     "Toggle Ctrl": "Tieni premuto Ctrl", | ||||
|     "Alt": "Alt", | ||||
|     "Toggle Alt": "Tieni premuto Alt", | ||||
|     "Toggle Windows": "Tieni premuto Windows", | ||||
|     "Windows": "Windows", | ||||
|     "Send Tab": "Invia Tab", | ||||
|     "Tab": "Tab", | ||||
|     "Esc": "Esc", | ||||
|     "Send Escape": "Invia Esc", | ||||
|     "Ctrl+Alt+Del": "Ctrl+Alt+Canc", | ||||
|     "Send Ctrl-Alt-Del": "Invia Ctrl-Alt-Canc", | ||||
|     "Shutdown/Reboot": "Spegnimento/Riavvio", | ||||
|     "Shutdown/Reboot...": "Spegnimento/Riavvio...", | ||||
|     "Power": "Alimentazione", | ||||
|     "Shutdown": "Spegnimento", | ||||
|     "Reboot": "Riavvio", | ||||
|     "Reset": "Reset", | ||||
|     "Clipboard": "Clipboard", | ||||
|     "Clear": "Pulisci", | ||||
|     "Fullscreen": "Schermo intero", | ||||
|     "Settings": "Impostazioni", | ||||
|     "Shared Mode": "Modalità condivisa", | ||||
|     "View Only": "Sola Visualizzazione", | ||||
|     "Clip to Window": "", | ||||
|     "Scaling Mode:": "Modalità di ridimensionamento:", | ||||
|     "None": "Nessuna", | ||||
|     "Local Scaling": "Ridimensionamento Locale", | ||||
|     "Remote Resizing": "Ridimensionamento Remoto", | ||||
|     "Advanced": "Avanzate", | ||||
|     "Quality:": "Qualità:", | ||||
|     "Compression level:": "Livello Compressione:", | ||||
|     "Repeater ID:": "ID Ripetitore:", | ||||
|     "WebSocket": "WebSocket", | ||||
|     "Encrypt": "Crittografa", | ||||
|     "Host:": "Host:", | ||||
|     "Port:": "Porta:", | ||||
|     "Path:": "Percorso:", | ||||
|     "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", | ||||
|     "Username:": "Utente:", | ||||
|     "Password:": "Password:", | ||||
|     "Send Credentials": "Invia Credenziale", | ||||
|     "Cancel": "Annulla" | ||||
| } | ||||
| @ -6,21 +6,16 @@ | ||||
|     "Must set host": "ホストを設定する必要があります", | ||||
|     "Connected (encrypted) to ": "接続しました (暗号化済み): ", | ||||
|     "Connected (unencrypted) to ": "接続しました (暗号化されていません): ", | ||||
|     "Something went wrong, connection is closed": "何かが問題で、接続が閉じられました", | ||||
|     "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": "追加キー", | ||||
| @ -55,6 +50,8 @@ | ||||
|     "Local Scaling": "ローカルスケーリング", | ||||
|     "Remote Resizing": "リモートでリサイズ", | ||||
|     "Advanced": "高度", | ||||
|     "Quality:": "品質:", | ||||
|     "Compression level:": "圧縮レベル:", | ||||
|     "Repeater ID:": "リピーター ID:", | ||||
|     "WebSocket": "WebSocket", | ||||
|     "Encrypt": "暗号化", | ||||
| @ -65,9 +62,11 @@ | ||||
|     "Reconnect Delay (ms):": "再接続する遅延 (ミリ秒):", | ||||
|     "Show Dot when No Cursor": "カーソルがないときにドットを表示", | ||||
|     "Logging:": "ロギング:", | ||||
|     "Version:": "バージョン:", | ||||
|     "Disconnect": "切断", | ||||
|     "Connect": "接続", | ||||
|     "Username:": "ユーザー名:", | ||||
|     "Password:": "パスワード:", | ||||
|     "Send Password": "パスワードを送信", | ||||
|     "Send Credentials": "資格情報を送信", | ||||
|     "Cancel": "キャンセル" | ||||
| } | ||||
							
								
								
									
										72
									
								
								systemvm/agent/noVNC/app/locale/pt_BR.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								systemvm/agent/noVNC/app/locale/pt_BR.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | ||||
| { | ||||
|     "Connecting...": "Conectando...", | ||||
|     "Disconnecting...": "Desconectando...", | ||||
|     "Reconnecting...": "Reconectando...", | ||||
|     "Internal error": "Erro interno", | ||||
|     "Must set host": "É necessário definir o host", | ||||
|     "Connected (encrypted) to ": "Conectado (com criptografia) a ", | ||||
|     "Connected (unencrypted) to ": "Conectado (sem criptografia) a ", | ||||
|     "Something went wrong, connection is closed": "Algo deu errado. A conexão foi encerrada.", | ||||
|     "Failed to connect to server": "Falha ao conectar-se ao servidor", | ||||
|     "Disconnected": "Desconectado", | ||||
|     "New connection has been rejected with reason: ": "A nova conexão foi rejeitada pelo motivo: ", | ||||
|     "New connection has been rejected": "A nova conexão foi rejeitada", | ||||
|     "Credentials are required": "Credenciais são obrigatórias", | ||||
|     "noVNC encountered an error:": "O noVNC encontrou um erro:", | ||||
|     "Hide/Show the control bar": "Esconder/mostrar a barra de controles", | ||||
|     "Drag": "Arrastar", | ||||
|     "Move/Drag Viewport": "Mover/arrastar a janela", | ||||
|     "Keyboard": "Teclado", | ||||
|     "Show Keyboard": "Mostrar teclado", | ||||
|     "Extra keys": "Teclas adicionais", | ||||
|     "Show Extra Keys": "Mostar teclas adicionais", | ||||
|     "Ctrl": "Ctrl", | ||||
|     "Toggle Ctrl": "Pressionar/soltar Ctrl", | ||||
|     "Alt": "Alt", | ||||
|     "Toggle Alt": "Pressionar/soltar Alt", | ||||
|     "Toggle Windows": "Pressionar/soltar Windows", | ||||
|     "Windows": "Windows", | ||||
|     "Send Tab": "Enviar Tab", | ||||
|     "Tab": "Tab", | ||||
|     "Esc": "Esc", | ||||
|     "Send Escape": "Enviar Esc", | ||||
|     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||
|     "Send Ctrl-Alt-Del": "Enviar Ctrl-Alt-Del", | ||||
|     "Shutdown/Reboot": "Desligar/reiniciar", | ||||
|     "Shutdown/Reboot...": "Desligar/reiniciar...", | ||||
|     "Power": "Ligar", | ||||
|     "Shutdown": "Desligar", | ||||
|     "Reboot": "Reiniciar", | ||||
|     "Reset": "Reiniciar (forçado)", | ||||
|     "Clipboard": "Área de transferência", | ||||
|     "Clear": "Limpar", | ||||
|     "Fullscreen": "Tela cheia", | ||||
|     "Settings": "Configurações", | ||||
|     "Shared Mode": "Modo compartilhado", | ||||
|     "View Only": "Apenas visualizar", | ||||
|     "Clip to Window": "Recortar à janela", | ||||
|     "Scaling Mode:": "Modo de dimensionamento:", | ||||
|     "None": "Nenhum", | ||||
|     "Local Scaling": "Local", | ||||
|     "Remote Resizing": "Remoto", | ||||
|     "Advanced": "Avançado", | ||||
|     "Quality:": "Qualidade:", | ||||
|     "Compression level:": "Nível de compressão:", | ||||
|     "Repeater ID:": "ID do repetidor:", | ||||
|     "WebSocket": "WebSocket", | ||||
|     "Encrypt": "Criptografar", | ||||
|     "Host:": "Host:", | ||||
|     "Port:": "Porta:", | ||||
|     "Path:": "Caminho:", | ||||
|     "Automatic Reconnect": "Reconexão automática", | ||||
|     "Reconnect Delay (ms):": "Atraso da reconexão (ms)", | ||||
|     "Show Dot when No Cursor": "Mostrar ponto quando não há cursor", | ||||
|     "Logging:": "Registros:", | ||||
|     "Version:": "Versão:", | ||||
|     "Disconnect": "Desconectar", | ||||
|     "Connect": "Conectar", | ||||
|     "Username:": "Nome de usuário:", | ||||
|     "Password:": "Senha:", | ||||
|     "Send Credentials": "Enviar credenciais", | ||||
|     "Cancel": "Cancelar" | ||||
| } | ||||
| @ -9,26 +9,21 @@ | ||||
|     "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": "Требуется пароль", | ||||
|     "New connection has been rejected with reason: ": "Новое соединение отклонено по причине: ", | ||||
|     "New connection has been rejected": "Новое соединение отклонено", | ||||
|     "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": "Доп. кнопки", | ||||
|     "Show Extra Keys": "Показать дополнительные кнопки", | ||||
|     "Extra keys": "Дополнительные Кнопки", | ||||
|     "Show Extra Keys": "Показать Дополнительные Кнопки", | ||||
|     "Ctrl": "Ctrl", | ||||
|     "Toggle Ctrl": "Передать нажатие Ctrl", | ||||
|     "Toggle Ctrl": "Переключение нажатия Ctrl", | ||||
|     "Alt": "Alt", | ||||
|     "Toggle Alt": "Передать нажатие Alt", | ||||
|     "Toggle Alt": "Переключение нажатия Alt", | ||||
|     "Toggle Windows": "Переключение вкладок", | ||||
|     "Windows": "Вкладка", | ||||
|     "Send Tab": "Передать нажатие Tab", | ||||
| @ -48,13 +43,15 @@ | ||||
|     "Fullscreen": "Во весь экран", | ||||
|     "Settings": "Настройки", | ||||
|     "Shared Mode": "Общий режим", | ||||
|     "View Only": "Просмотр", | ||||
|     "View Only": "Только Просмотр", | ||||
|     "Clip to Window": "В окно", | ||||
|     "Scaling Mode:": "Масштаб:", | ||||
|     "None": "Нет", | ||||
|     "Local Scaling": "Локльный масштаб", | ||||
|     "Remote Resizing": "Удаленный масштаб", | ||||
|     "Remote Resizing": "Удаленная перенастройка размера", | ||||
|     "Advanced": "Дополнительно", | ||||
|     "Quality:": "Качество", | ||||
|     "Compression level:": "Уровень Сжатия", | ||||
|     "Repeater ID:": "Идентификатор ID:", | ||||
|     "WebSocket": "WebSocket", | ||||
|     "Encrypt": "Шифрование", | ||||
| @ -65,9 +62,11 @@ | ||||
|     "Reconnect Delay (ms):": "Задержка переподключения (мс):", | ||||
|     "Show Dot when No Cursor": "Показать точку вместо курсора", | ||||
|     "Logging:": "Лог:", | ||||
|     "Version:": "Версия", | ||||
|     "Disconnect": "Отключение", | ||||
|     "Connect": "Подключение", | ||||
|     "Username:": "Имя Пользователя", | ||||
|     "Password:": "Пароль:", | ||||
|     "Send Password": "Пароль: ", | ||||
|     "Send Credentials": "Передача Учетных Данных", | ||||
|     "Cancel": "Выход" | ||||
| } | ||||
| @ -1,4 +1,5 @@ | ||||
| { | ||||
|     "HTTPS is required for full functionality": "HTTPS krävs för full funktionalitet", | ||||
|     "Connecting...": "Ansluter...", | ||||
|     "Disconnecting...": "Kopplar ner...", | ||||
|     "Reconnecting...": "Återansluter...", | ||||
| @ -39,8 +40,8 @@ | ||||
|     "Reboot": "Boota om", | ||||
|     "Reset": "Återställ", | ||||
|     "Clipboard": "Urklipp", | ||||
|     "Clear": "Rensa", | ||||
|     "Fullscreen": "Fullskärm", | ||||
|     "Edit clipboard content in the textarea below.": "Redigera urklippets innehåll i fältet nedan.", | ||||
|     "Full Screen": "Fullskärm", | ||||
|     "Settings": "Inställningar", | ||||
|     "Shared Mode": "Delat Läge", | ||||
|     "View Only": "Endast Visning", | ||||
| @ -65,6 +66,13 @@ | ||||
|     "Version:": "Version:", | ||||
|     "Disconnect": "Koppla från", | ||||
|     "Connect": "Anslut", | ||||
|     "Server identity": "Server-identitet", | ||||
|     "The server has provided the following identifying information:": "Servern har gett följande identifierande information:", | ||||
|     "Fingerprint:": "Fingeravtryck:", | ||||
|     "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "Kontrollera att informationen är korrekt och tryck sedan \"Godkänn\". Tryck annars \"Neka\".", | ||||
|     "Approve": "Godkänn", | ||||
|     "Reject": "Neka", | ||||
|     "Credentials": "Användaruppgifter", | ||||
|     "Username:": "Användarnamn:", | ||||
|     "Password:": "Lösenord:", | ||||
|     "Send Credentials": "Skicka Användaruppgifter", | ||||
|  | ||||
| @ -103,13 +103,20 @@ export class Localizer { | ||||
|                 return items.indexOf(searchElement) !== -1; | ||||
|             } | ||||
| 
 | ||||
|             function translateString(str) { | ||||
|                 // We assume surrounding whitespace, and whitespace around line
 | ||||
|                 // breaks is just for source formatting
 | ||||
|                 str = str.split("\n").map(s => s.trim()).join(" ").trim(); | ||||
|                 return self.get(str); | ||||
|             } | ||||
| 
 | ||||
|             function translateAttribute(elem, attr) { | ||||
|                 const str = self.get(elem.getAttribute(attr)); | ||||
|                 const str = translateString(elem.getAttribute(attr)); | ||||
|                 elem.setAttribute(attr, str); | ||||
|             } | ||||
| 
 | ||||
|             function translateTextNode(node) { | ||||
|                 const str = self.get(node.data.trim()); | ||||
|                 const str = translateString(node.data); | ||||
|                 node.data = str; | ||||
|             } | ||||
| 
 | ||||
|  | ||||
| @ -19,10 +19,23 @@ | ||||
|  * 10000: Max (used for polyfills) | ||||
|  */ | ||||
| 
 | ||||
| /* | ||||
|  * State variables (set on :root): | ||||
|  * | ||||
|  * noVNC_loading: Page is still loading | ||||
|  * noVNC_connecting: Connecting to server | ||||
|  * noVNC_reconnecting: Re-establishing a connection | ||||
|  * noVNC_connected: Connected to server (most common state) | ||||
|  * noVNC_disconnecting: Disconnecting from server | ||||
|  */ | ||||
| 
 | ||||
| :root { | ||||
|   font-family: sans-serif; | ||||
| } | ||||
| 
 | ||||
| body { | ||||
|   margin:0; | ||||
|   padding:0; | ||||
|   font-family: Helvetica; | ||||
|   /*Background image with light grey curve.*/ | ||||
|   background-color:#494949; | ||||
|   background-repeat:no-repeat; | ||||
| @ -78,144 +91,6 @@ html { | ||||
|   50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; } | ||||
| } | ||||
| 
 | ||||
| /* ---------------------------------------- | ||||
|  * Input Elements | ||||
|  * ---------------------------------------- | ||||
|  */ | ||||
| 
 | ||||
| input:not([type]), | ||||
| input[type=date], | ||||
| input[type=datetime-local], | ||||
| input[type=email], | ||||
| input[type=month], | ||||
| input[type=number], | ||||
| input[type=password], | ||||
| input[type=search], | ||||
| input[type=tel], | ||||
| input[type=text], | ||||
| input[type=time], | ||||
| input[type=url], | ||||
| input[type=week], | ||||
| textarea { | ||||
|   /* Disable default rendering */ | ||||
|   -webkit-appearance: none; | ||||
|   -moz-appearance: none; | ||||
|   background: none; | ||||
| 
 | ||||
|   margin: 2px; | ||||
|   padding: 2px; | ||||
|   border: 1px solid rgb(192, 192, 192); | ||||
|   border-radius: 5px; | ||||
|   color: black; | ||||
|   background: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); | ||||
| } | ||||
| 
 | ||||
| input[type=button], | ||||
| input[type=color], | ||||
| input[type=reset], | ||||
| input[type=submit], | ||||
| select { | ||||
|   /* Disable default rendering */ | ||||
|   -webkit-appearance: none; | ||||
|   -moz-appearance: none; | ||||
|   background: none; | ||||
| 
 | ||||
|   margin: 2px; | ||||
|   padding: 2px; | ||||
|   border: 1px solid rgb(192, 192, 192); | ||||
|   border-bottom-width: 2px; | ||||
|   border-radius: 5px; | ||||
|   color: black; | ||||
|   background: linear-gradient(to top, rgb(255, 255, 255), rgb(240, 240, 240)); | ||||
| 
 | ||||
|   /* This avoids it jumping around when :active */ | ||||
|   vertical-align: middle; | ||||
| } | ||||
| 
 | ||||
| input[type=button], | ||||
| input[type=color], | ||||
| input[type=reset], | ||||
| input[type=submit] { | ||||
|   padding-left: 20px; | ||||
|   padding-right: 20px; | ||||
| } | ||||
| 
 | ||||
| option { | ||||
|   color: black; | ||||
|   background: white; | ||||
| } | ||||
| 
 | ||||
| input:not([type]):focus, | ||||
| input[type=button]:focus, | ||||
| input[type=color]:focus, | ||||
| input[type=date]:focus, | ||||
| input[type=datetime-local]:focus, | ||||
| input[type=email]:focus, | ||||
| input[type=month]:focus, | ||||
| input[type=number]:focus, | ||||
| input[type=password]:focus, | ||||
| input[type=reset]:focus, | ||||
| input[type=search]:focus, | ||||
| input[type=submit]:focus, | ||||
| input[type=tel]:focus, | ||||
| input[type=text]:focus, | ||||
| input[type=time]:focus, | ||||
| input[type=url]:focus, | ||||
| input[type=week]:focus, | ||||
| select:focus, | ||||
| textarea:focus { | ||||
|   box-shadow: 0px 0px 3px rgba(74, 144, 217, 0.5); | ||||
|   border-color: rgb(74, 144, 217); | ||||
|   outline: none; | ||||
| } | ||||
| 
 | ||||
| input[type=button]::-moz-focus-inner, | ||||
| input[type=color]::-moz-focus-inner, | ||||
| input[type=reset]::-moz-focus-inner, | ||||
| input[type=submit]::-moz-focus-inner { | ||||
|   border: none; | ||||
| } | ||||
| 
 | ||||
| input:not([type]):disabled, | ||||
| input[type=button]:disabled, | ||||
| input[type=color]:disabled, | ||||
| input[type=date]:disabled, | ||||
| input[type=datetime-local]:disabled, | ||||
| input[type=email]:disabled, | ||||
| input[type=month]:disabled, | ||||
| input[type=number]:disabled, | ||||
| input[type=password]:disabled, | ||||
| input[type=reset]:disabled, | ||||
| input[type=search]:disabled, | ||||
| input[type=submit]:disabled, | ||||
| input[type=tel]:disabled, | ||||
| input[type=text]:disabled, | ||||
| input[type=time]:disabled, | ||||
| input[type=url]:disabled, | ||||
| input[type=week]:disabled, | ||||
| select:disabled, | ||||
| textarea:disabled { | ||||
|   color: rgb(128, 128, 128); | ||||
|   background: rgb(240, 240, 240); | ||||
| } | ||||
| 
 | ||||
| input[type=button]:active, | ||||
| input[type=color]:active, | ||||
| input[type=reset]:active, | ||||
| input[type=submit]:active, | ||||
| select:active { | ||||
|   border-bottom-width: 1px; | ||||
|   margin-top: 3px; | ||||
| } | ||||
| 
 | ||||
| :root:not(.noVNC_touch) input[type=button]:hover:not(:disabled), | ||||
| :root:not(.noVNC_touch) input[type=color]:hover:not(:disabled), | ||||
| :root:not(.noVNC_touch) input[type=reset]:hover:not(:disabled), | ||||
| :root:not(.noVNC_touch) input[type=submit]:hover:not(:disabled), | ||||
| :root:not(.noVNC_touch) select:hover:not(:disabled) { | ||||
|   background: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250)); | ||||
| } | ||||
| 
 | ||||
| /* ---------------------------------------- | ||||
|  * WebKit centering hacks | ||||
|  * ---------------------------------------- | ||||
| @ -242,13 +117,15 @@ select:active { | ||||
|   pointer-events: auto; | ||||
| } | ||||
| .noVNC_vcenter { | ||||
|   display: flex; | ||||
|   display: flex !important; | ||||
|   flex-direction: column; | ||||
|   justify-content: center; | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   height: 100%; | ||||
|   margin: 0 !important; | ||||
|   padding: 0 !important; | ||||
|   pointer-events: none; | ||||
| } | ||||
| .noVNC_vcenter > * { | ||||
| @ -272,13 +149,20 @@ select:active { | ||||
| #noVNC_fallback_error { | ||||
|   z-index: 1000; | ||||
|   visibility: hidden; | ||||
|   /* Put a dark background in front of everything but the error, | ||||
|      and don't let mouse events pass through */ | ||||
|   background: rgba(0, 0, 0, 0.8); | ||||
|   pointer-events: all; | ||||
| } | ||||
| #noVNC_fallback_error.noVNC_open { | ||||
|   visibility: visible; | ||||
| } | ||||
| 
 | ||||
| #noVNC_fallback_error > div { | ||||
|   max-width: 90%; | ||||
|   max-width: calc(100vw - 30px - 30px); | ||||
|   max-height: calc(100vh - 30px - 30px); | ||||
|   overflow: auto; | ||||
| 
 | ||||
|   padding: 15px; | ||||
| 
 | ||||
|   transition: 0.5s ease-in-out; | ||||
| @ -317,7 +201,6 @@ select:active { | ||||
| } | ||||
| 
 | ||||
| #noVNC_fallback_error .noVNC_stack { | ||||
|   max-height: 50vh; | ||||
|   padding: 10px; | ||||
|   margin: 10px; | ||||
|   font-size: 0.8em; | ||||
| @ -361,6 +244,9 @@ select:active { | ||||
|   background-color: rgb(110, 132, 163); | ||||
|   border-radius: 0 10px 10px 0; | ||||
| 
 | ||||
|   user-select: none; | ||||
|   -webkit-user-select: none; | ||||
|   -webkit-touch-callout: none; /* Disable iOS image long-press popup */ | ||||
| } | ||||
| #noVNC_control_bar.noVNC_open { | ||||
|   box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); | ||||
| @ -401,7 +287,7 @@ select:active { | ||||
|   cursor: pointer; | ||||
|   border-radius: 5px; | ||||
|   background-color: rgb(83, 99, 122); | ||||
|   background-image: url("../images/handle_bg.svg"); | ||||
|   background-image: url("../images/handle_bg.png"); | ||||
|   background-repeat: no-repeat; | ||||
|   background-position: right; | ||||
|   box-shadow: 3px 3px 0px rgba(0, 0, 0, 0.5); | ||||
| @ -409,7 +295,7 @@ select:active { | ||||
| #noVNC_control_bar_handle:after { | ||||
|   content: ""; | ||||
|   transition: transform 0.5s ease-in-out; | ||||
|   background: url("../images/handle.svg"); | ||||
|   background: url("../images/handle.png"); | ||||
|   position: absolute; | ||||
|   top: 22px; /* (50px-6px)/2 */ | ||||
|   right: 5px; | ||||
| @ -433,38 +319,50 @@ select:active { | ||||
| .noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { | ||||
|   transform: none; | ||||
| } | ||||
| /* Larger touch area for the handle, used when a touch screen is available */ | ||||
| #noVNC_control_bar_handle div { | ||||
|   position: absolute; | ||||
|   right: -35px; | ||||
|   top: 0; | ||||
|   width: 50px; | ||||
|   height: 50px; | ||||
| } | ||||
| :root:not(.noVNC_touch) #noVNC_control_bar_handle div { | ||||
|   height: 100%; | ||||
|   display: none; | ||||
| } | ||||
| @media (any-pointer: coarse) { | ||||
|   #noVNC_control_bar_handle div { | ||||
|     display: initial; | ||||
|   } | ||||
| } | ||||
| .noVNC_right #noVNC_control_bar_handle div { | ||||
|   left: -35px; | ||||
|   right: auto; | ||||
| } | ||||
| 
 | ||||
| #noVNC_control_bar .noVNC_scroll { | ||||
| #noVNC_control_bar > .noVNC_scroll { | ||||
|   max-height: 100vh; /* Chrome is buggy with 100% */ | ||||
|   overflow-x: hidden; | ||||
|   overflow-y: auto; | ||||
|   padding: 0 10px 0 5px; | ||||
|   padding: 0 10px; | ||||
| } | ||||
| .noVNC_right #noVNC_control_bar .noVNC_scroll { | ||||
|   padding: 0 5px 0 10px; | ||||
| 
 | ||||
| #noVNC_control_bar > .noVNC_scroll > * { | ||||
|   display: block; | ||||
|   margin: 10px auto; | ||||
| } | ||||
| 
 | ||||
| /* Control bar hint */ | ||||
| #noVNC_control_bar_hint { | ||||
| #noVNC_hint_anchor { | ||||
|   position: fixed; | ||||
|   left: calc(100vw - 50px); | ||||
|   right: -50px; | ||||
|   left: auto; | ||||
| } | ||||
| #noVNC_control_bar_anchor.noVNC_right + #noVNC_hint_anchor { | ||||
|   left: -50px; | ||||
|   right: auto; | ||||
|   top: 50%; | ||||
|   transform: translateY(-50%) scale(0); | ||||
| } | ||||
| #noVNC_control_bar_hint { | ||||
|   position: relative; | ||||
|   transform: scale(0); | ||||
|   width: 100px; | ||||
|   height: 50%; | ||||
|   max-height: 600px; | ||||
| @ -477,54 +375,56 @@ select:active { | ||||
|   border-radius: 10px; | ||||
|   transition-delay: 0s; | ||||
| } | ||||
| #noVNC_control_bar_anchor.noVNC_right #noVNC_control_bar_hint{ | ||||
|   left: auto; | ||||
|   right: calc(100vw - 50px); | ||||
| } | ||||
| #noVNC_control_bar_hint.noVNC_active { | ||||
|   visibility: visible; | ||||
|   opacity: 1; | ||||
|   transition-delay: 0.2s; | ||||
|   transform: translateY(-50%) scale(1); | ||||
|   transform: scale(1); | ||||
| } | ||||
| #noVNC_control_bar_hint.noVNC_notransition { | ||||
|   transition: none !important; | ||||
| } | ||||
| 
 | ||||
| /* General button style */ | ||||
| .noVNC_button { | ||||
|   display: block; | ||||
| /* Control bar buttons */ | ||||
| #noVNC_control_bar .noVNC_button { | ||||
|   padding: 4px 4px; | ||||
|   margin: 10px 0; | ||||
|   vertical-align: middle; | ||||
|   border:1px solid rgba(255, 255, 255, 0.2); | ||||
|   border-radius: 6px; | ||||
|   background-color: transparent; | ||||
|   background-image: unset; /* we don't want the gradiant from input.css */ | ||||
| } | ||||
| .noVNC_button.noVNC_selected { | ||||
| #noVNC_control_bar .noVNC_button.noVNC_selected { | ||||
|   border-color: rgba(0, 0, 0, 0.8); | ||||
|   background: rgba(0, 0, 0, 0.5); | ||||
|   background-color: rgba(0, 0, 0, 0.5); | ||||
| } | ||||
| .noVNC_button:disabled { | ||||
|   opacity: 0.4; | ||||
| #noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { | ||||
|   border-color: rgba(0, 0, 0, 0.4); | ||||
|   background-color: rgba(0, 0, 0, 0.2); | ||||
| } | ||||
| .noVNC_button:focus { | ||||
|   outline: none; | ||||
| #noVNC_control_bar .noVNC_button:not(:disabled):hover { | ||||
|   background-color: rgba(255, 255, 255, 0.2); | ||||
| } | ||||
| .noVNC_button:active { | ||||
| #noVNC_control_bar .noVNC_button:not(:disabled):active { | ||||
|   padding-top: 5px; | ||||
|   padding-bottom: 3px; | ||||
| } | ||||
| /* Android browsers don't properly update hover state if touch events | ||||
|  * are intercepted, but focus should be safe to display */ | ||||
| :root:not(.noVNC_touch) .noVNC_button.noVNC_selected:hover, | ||||
| .noVNC_button.noVNC_selected:focus { | ||||
|   border-color: rgba(0, 0, 0, 0.4); | ||||
|   background: rgba(0, 0, 0, 0.2); | ||||
| #noVNC_control_bar .noVNC_button.noVNC_hidden { | ||||
|   display: none !important; | ||||
| } | ||||
| :root:not(.noVNC_touch) .noVNC_button:hover, | ||||
| .noVNC_button:focus { | ||||
|   background: rgba(255, 255, 255, 0.2); | ||||
| 
 | ||||
| /* Android browsers don't properly update hover state if touch events are | ||||
|  * intercepted, like they are when clicking on the remote screen. */ | ||||
| @media (any-pointer: coarse) { | ||||
|   #noVNC_control_bar .noVNC_button:not(:disabled):hover { | ||||
|     background-color: transparent; | ||||
|   } | ||||
| .noVNC_button.noVNC_hidden { | ||||
|   display: none; | ||||
|   #noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { | ||||
|     border-color: rgba(0, 0, 0, 0.8); | ||||
|     background-color: rgba(0, 0, 0, 0.5); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Panels */ | ||||
| .noVNC_panel { | ||||
| @ -532,6 +432,8 @@ select:active { | ||||
| 
 | ||||
|   transition: 0.5s ease-in-out; | ||||
| 
 | ||||
|   box-sizing: border-box; /* so max-width don't have to care about padding */ | ||||
|   max-width: calc(100vw - 75px - 25px); /* minus left and right margins */ | ||||
|   max-height: 100vh; /* Chrome is buggy with 100% */ | ||||
|   overflow-x: hidden; | ||||
|   overflow-y: auto; | ||||
| @ -563,6 +465,17 @@ select:active { | ||||
|   transform: translateX(-75px); | ||||
| } | ||||
| 
 | ||||
| .noVNC_panel > * { | ||||
|   display: block; | ||||
|   margin: 10px auto; | ||||
| } | ||||
| .noVNC_panel > *:first-child { | ||||
|   margin-top: 0 !important; | ||||
| } | ||||
| .noVNC_panel > *:last-child { | ||||
|   margin-bottom: 0 !important; | ||||
| } | ||||
| 
 | ||||
| .noVNC_panel hr { | ||||
|   border: none; | ||||
|   border-top: 1px solid rgb(192, 192, 192); | ||||
| @ -571,6 +484,11 @@ select:active { | ||||
| .noVNC_panel label { | ||||
|   display: block; | ||||
|   white-space: nowrap; | ||||
|   margin: 5px; | ||||
| } | ||||
| 
 | ||||
| .noVNC_panel li { | ||||
|   margin: 5px; | ||||
| } | ||||
| 
 | ||||
| .noVNC_panel .noVNC_heading { | ||||
| @ -581,7 +499,6 @@ select:active { | ||||
|   padding-right: 8px; | ||||
|   color: white; | ||||
|   font-size: 20px; | ||||
|   margin-bottom: 10px; | ||||
|   white-space: nowrap; | ||||
| } | ||||
| .noVNC_panel .noVNC_heading img { | ||||
| @ -597,7 +514,7 @@ select:active { | ||||
|   cursor: pointer; | ||||
| } | ||||
| .noVNC_expander::before { | ||||
|   content: url("../images/expander.svg"); | ||||
|   content: url("../images/expander.png"); | ||||
|   display: inline-block; | ||||
|   margin-right: 5px; | ||||
|   transition: 0.2s ease-in-out; | ||||
| @ -622,6 +539,12 @@ select:active { | ||||
|   font-size: 13px; | ||||
| } | ||||
| 
 | ||||
| .noVNC_logo + hr { | ||||
|     /* Remove all but top border */ | ||||
|     border: none; | ||||
|     border-top: 1px solid rgba(255, 255, 255, 0.2); | ||||
| } | ||||
| 
 | ||||
| :root:not(.noVNC_connected) #noVNC_view_drag_button { | ||||
|   display: none; | ||||
| } | ||||
| @ -630,9 +553,16 @@ select:active { | ||||
| :root:not(.noVNC_connected) #noVNC_mobile_buttons { | ||||
|   display: none; | ||||
| } | ||||
| :root:not(.noVNC_touch) #noVNC_mobile_buttons { | ||||
| @media not all and (any-pointer: coarse) { | ||||
|   /* FIXME: The button for the virtual keyboard is the only button in this | ||||
|             group of "mobile buttons". It is bad to assume that no touch | ||||
|             devices have physical keyboards available. Hopefully we can get | ||||
|             a media query for this: | ||||
|             https://github.com/w3c/csswg-drafts/issues/3871 */ | ||||
|   :root.noVNC_connected #noVNC_mobile_buttons { | ||||
|     display: none; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /* Extra manual keys */ | ||||
| :root:not(.noVNC_connected) #noVNC_toggle_extra_keys_button { | ||||
| @ -642,7 +572,7 @@ select:active { | ||||
| #noVNC_modifiers { | ||||
|   background-color: rgb(92, 92, 92); | ||||
|   border: none; | ||||
|   padding: 0 10px; | ||||
|   padding: 10px; | ||||
| } | ||||
| 
 | ||||
| /* Shutdown/Reboot */ | ||||
| @ -663,13 +593,16 @@ select:active { | ||||
| :root:not(.noVNC_connected) #noVNC_clipboard_button { | ||||
|   display: none; | ||||
| } | ||||
| #noVNC_clipboard { | ||||
|   /* Full screen, minus padding and left and right margins */ | ||||
|   max-width: calc(100vw - 2*15px - 75px - 25px); | ||||
| } | ||||
| #noVNC_clipboard_text { | ||||
|   width: 500px; | ||||
|   width: 360px; | ||||
|   min-width: 150px; | ||||
|   height: 160px; | ||||
|   min-height: 70px; | ||||
| 
 | ||||
|   box-sizing: border-box; | ||||
|   max-width: 100%; | ||||
|   /* minus approximate height of title, height of subtitle, and margin */ | ||||
|   max-height: calc(100vh - 10em - 25px); | ||||
| } | ||||
| 
 | ||||
| :root:not(.noVNC_connected) #noVNC_fullscreen_button { | ||||
| @ -681,7 +614,6 @@ select:active { | ||||
| } | ||||
| #noVNC_settings ul { | ||||
|   list-style: none; | ||||
|   margin: 0px; | ||||
|   padding: 0px; | ||||
| } | ||||
| #noVNC_setting_port { | ||||
| @ -757,25 +689,25 @@ select:active { | ||||
|   background: rgba(128,128,128,0.9); | ||||
| } | ||||
| #noVNC_status.noVNC_status_normal::before { | ||||
|   content: url("../images/info.svg") " "; | ||||
|   content: url("../images/info.png") " "; | ||||
| } | ||||
| #noVNC_status.noVNC_status_error { | ||||
|   background: rgba(200,55,55,0.9); | ||||
| } | ||||
| #noVNC_status.noVNC_status_error::before { | ||||
|   content: url("../images/error.svg") " "; | ||||
|   content: url("../images/error.png") " "; | ||||
| } | ||||
| #noVNC_status.noVNC_status_warn { | ||||
|   background: rgba(180,180,30,0.9); | ||||
| } | ||||
| #noVNC_status.noVNC_status_warn::before { | ||||
|   content: url("../images/warning.svg") " "; | ||||
|   content: url("../images/warning.png") " "; | ||||
| } | ||||
| #noVNC_status.noVNC_status_tls_success { | ||||
|   background: rgba(6, 199, 38, 0.9); | ||||
| } | ||||
| #noVNC_status.noVNC_status_tls_success::before { | ||||
|   content: url("../images/connect.svg") " "; | ||||
|   content: url("../images/connect.png") " "; | ||||
| } | ||||
| 
 | ||||
| /* ---------------------------------------- | ||||
| @ -813,36 +745,32 @@ select:active { | ||||
|     font-size: calc(25vw - 30px); | ||||
|   } | ||||
| } | ||||
| #noVNC_connect_button { | ||||
|   cursor: pointer; | ||||
| #noVNC_connect_dlg div { | ||||
|   padding: 12px; | ||||
| 
 | ||||
|   padding: 10px; | ||||
| 
 | ||||
|   color: white; | ||||
|   background-color: rgb(110, 132, 163); | ||||
|   border-radius: 12px; | ||||
| 
 | ||||
|   text-align: center; | ||||
|   font-size: 20px; | ||||
| 
 | ||||
|   box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); | ||||
| } | ||||
| #noVNC_connect_button div { | ||||
|   margin: 2px; | ||||
| #noVNC_connect_button { | ||||
|   width: 100%; | ||||
|   padding: 5px 30px; | ||||
|   border: 1px solid rgb(83, 99, 122); | ||||
|   border-bottom-width: 2px; | ||||
| 
 | ||||
|   cursor: pointer; | ||||
| 
 | ||||
|   border-color: rgb(83, 99, 122); | ||||
|   border-radius: 5px; | ||||
| 
 | ||||
|   background: linear-gradient(to top, rgb(110, 132, 163), rgb(99, 119, 147)); | ||||
|   color: white; | ||||
| 
 | ||||
|   /* This avoids it jumping around when :active */ | ||||
|   vertical-align: middle; | ||||
| } | ||||
| #noVNC_connect_button div:active { | ||||
|   border-bottom-width: 1px; | ||||
|   margin-top: 3px; | ||||
| } | ||||
| :root:not(.noVNC_touch) #noVNC_connect_button div:hover { | ||||
| #noVNC_connect_button:hover { | ||||
|   background: linear-gradient(to top, rgb(110, 132, 163), rgb(105, 125, 155)); | ||||
| } | ||||
| 
 | ||||
| @ -851,6 +779,23 @@ select:active { | ||||
|   height: 1.3em; | ||||
| } | ||||
| 
 | ||||
| /* ---------------------------------------- | ||||
|  * Server verification Dialog | ||||
|  * ---------------------------------------- | ||||
|  */ | ||||
| 
 | ||||
| #noVNC_verify_server_dlg { | ||||
|   position: relative; | ||||
| 
 | ||||
|   transform: translateY(-50px); | ||||
| } | ||||
| #noVNC_verify_server_dlg.noVNC_open { | ||||
|   transform: translateY(0); | ||||
| } | ||||
| #noVNC_fingerprint_block { | ||||
|   margin: 10px; | ||||
| } | ||||
| 
 | ||||
| /* ---------------------------------------- | ||||
|  * Password Dialog | ||||
|  * ---------------------------------------- | ||||
| @ -864,12 +809,8 @@ select:active { | ||||
| #noVNC_credentials_dlg.noVNC_open { | ||||
|   transform: translateY(0); | ||||
| } | ||||
| #noVNC_credentials_dlg ul { | ||||
|   list-style: none; | ||||
|   margin: 0px; | ||||
|   padding: 0px; | ||||
| } | ||||
| .noVNC_hidden { | ||||
| #noVNC_username_block.noVNC_hidden, | ||||
| #noVNC_password_block.noVNC_hidden { | ||||
|   display: none; | ||||
| } | ||||
| 
 | ||||
| @ -881,7 +822,11 @@ select:active { | ||||
| 
 | ||||
| /* Transition screen */ | ||||
| #noVNC_transition { | ||||
|   display: none; | ||||
|   transition: 0.5s ease-in-out; | ||||
| 
 | ||||
|   display: flex; | ||||
|   opacity: 0; | ||||
|   visibility: hidden; | ||||
| 
 | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
| @ -902,7 +847,8 @@ select:active { | ||||
| :root.noVNC_connecting #noVNC_transition, | ||||
| :root.noVNC_disconnecting #noVNC_transition, | ||||
| :root.noVNC_reconnecting #noVNC_transition { | ||||
|   display: flex; | ||||
|   opacity: 1; | ||||
|   visibility: visible; | ||||
| } | ||||
| :root:not(.noVNC_reconnecting) #noVNC_cancel_reconnect_button { | ||||
|   display: none; | ||||
| @ -918,6 +864,12 @@ select:active { | ||||
|   background-color: #313131; | ||||
|   border-bottom-right-radius: 800px 600px; | ||||
|   /*border-top-left-radius: 800px 600px;*/ | ||||
| 
 | ||||
|   /* If selection isn't disabled, long-pressing stuff in the sidebar | ||||
|      can accidentally select the container or the canvas. This can | ||||
|      happen when attempting to move the handle. */ | ||||
|   user-select: none; | ||||
|   -webkit-user-select: none; | ||||
| } | ||||
| 
 | ||||
| #noVNC_keyboardinput { | ||||
|  | ||||
							
								
								
									
										281
									
								
								systemvm/agent/noVNC/app/styles/input.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								systemvm/agent/noVNC/app/styles/input.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,281 @@ | ||||
| /* | ||||
|  * noVNC general input element CSS | ||||
|  * Copyright (C) 2022 The noVNC Authors | ||||
|  * noVNC is licensed under the MPL 2.0 (see LICENSE.txt) | ||||
|  * This file is licensed under the 2-Clause BSD license (see LICENSE.txt). | ||||
|  */ | ||||
| 
 | ||||
| /* | ||||
|  * Common for all inputs | ||||
|  */ | ||||
| input, input::file-selector-button, button, select, textarea { | ||||
|   /* Respect standard font settings */ | ||||
|   font: inherit; | ||||
| 
 | ||||
|   /* Disable default rendering */ | ||||
|   appearance: none; | ||||
|   background: none; | ||||
| 
 | ||||
|   padding: 5px; | ||||
|   border: 1px solid rgb(192, 192, 192); | ||||
|   border-radius: 5px; | ||||
|   color: black; | ||||
|   --bg-gradient: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); | ||||
|   background-image: var(--bg-gradient); | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Buttons | ||||
|  */ | ||||
| input[type=button], | ||||
| input[type=color], | ||||
| input[type=image], | ||||
| input[type=reset], | ||||
| input[type=submit], | ||||
| input::file-selector-button, | ||||
| button, | ||||
| select { | ||||
|   border-bottom-width: 2px; | ||||
| 
 | ||||
|   /* This avoids it jumping around when :active */ | ||||
|   vertical-align: middle; | ||||
|   margin-top: 0; | ||||
| 
 | ||||
|   padding-left: 20px; | ||||
|   padding-right: 20px; | ||||
| 
 | ||||
|   /* Disable Chrome's touch tap highlight */ | ||||
|   -webkit-tap-highlight-color: transparent; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Select dropdowns | ||||
|  */ | ||||
| select { | ||||
|   --select-arrow: url('data:image/svg+xml;utf8, \ | ||||
|       <svg width="8" height="6" version="1.1" viewBox="0 0 8 6" \ | ||||
|            xmlns="http://www.w3.org/2000/svg"> \ | ||||
|           <path d="m6.5 1.5 -2.5 3 -2.5 -3 5 0" stroke-width="3" \ | ||||
|                 stroke="rgb(31,31,31)" fill="none" \ | ||||
|                 stroke-linecap="round" stroke-linejoin="round" /> \ | ||||
|       </svg>'); | ||||
|   background-image: var(--select-arrow), var(--bg-gradient); | ||||
|   background-position: calc(100% - 7px), left top; | ||||
|   background-repeat: no-repeat; | ||||
|   padding-right: calc(2*7px + 8px); | ||||
|   padding-left: 7px; | ||||
| } | ||||
| /* FIXME: :active isn't set when the <select> is opened in Firefox: | ||||
|           https://bugzilla.mozilla.org/show_bug.cgi?id=1805406 */ | ||||
| select:active { | ||||
|   /* Rotated arrow */ | ||||
|   background-image: url('data:image/svg+xml;utf8, \ | ||||
|       <svg width="8" height="6" version="1.1" viewBox="0 0 8 6" \ | ||||
|            xmlns="http://www.w3.org/2000/svg" transform="rotate(180)" > \ | ||||
|           <path d="m6.5 1.5 -2.5 3 -2.5 -3 5 0" stroke-width="3" \ | ||||
|                 stroke="rgb(31,31,31)" fill="none" \ | ||||
|                 stroke-linecap="round" stroke-linejoin="round" /> \ | ||||
|       </svg>'), var(--bg-gradient); | ||||
| } | ||||
| option { | ||||
|   color: black; | ||||
|   background: white; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Checkboxes | ||||
|  */ | ||||
| input[type=checkbox] { | ||||
|   background-color: white; | ||||
|   background-image: unset; | ||||
|   border: 1px solid dimgrey; | ||||
|   border-radius: 3px; | ||||
|   width: 13px; | ||||
|   height: 13px; | ||||
|   padding: 0; | ||||
|   margin-right: 6px; | ||||
|   vertical-align: bottom; | ||||
|   transition: 0.2s background-color linear; | ||||
| } | ||||
| input[type=checkbox]:checked { | ||||
|   background-color: rgb(110, 132, 163); | ||||
|   border-color: rgb(110, 132, 163); | ||||
| } | ||||
| input[type=checkbox]:checked::after { | ||||
|   content: ""; | ||||
|   display: block; /* width & height doesn't work on inline elements */ | ||||
|   position: relative; | ||||
|   top: 0; | ||||
|   left: 3px; | ||||
|   width: 3px; | ||||
|   height: 7px; | ||||
|   border: 1px solid white; | ||||
|   border-width: 0 2px 2px 0; | ||||
|   transform: rotate(40deg); | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Radiobuttons | ||||
|  */ | ||||
| input[type=radio] { | ||||
|   border-radius: 50%; | ||||
|   border: 1px solid dimgrey; | ||||
|   width: 12px; | ||||
|   height: 12px; | ||||
|   padding: 0; | ||||
|   margin-right: 6px; | ||||
|   transition: 0.2s border linear; | ||||
| } | ||||
| input[type=radio]:checked { | ||||
|   border: 6px solid rgb(110, 132, 163); | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Range sliders | ||||
|  */ | ||||
| input[type=range] { | ||||
|   border: unset; | ||||
|   border-radius: 3px; | ||||
|   height: 20px; | ||||
|   padding: 0; | ||||
|   background: transparent; | ||||
| } | ||||
| /* -webkit-slider.. & -moz-range.. cant be in selector lists: | ||||
|    https://bugs.chromium.org/p/chromium/issues/detail?id=1154623 */ | ||||
| input[type=range]::-webkit-slider-runnable-track { | ||||
|   background-color: rgb(110, 132, 163); | ||||
|   height: 6px; | ||||
|   border-radius: 3px; | ||||
| } | ||||
| input[type=range]::-moz-range-track { | ||||
|   background-color: rgb(110, 132, 163); | ||||
|   height: 6px; | ||||
|   border-radius: 3px; | ||||
| } | ||||
| input[type=range]::-webkit-slider-thumb { | ||||
|   appearance: none; | ||||
|   width: 18px; | ||||
|   height: 20px; | ||||
|   border-radius: 5px; | ||||
|   background-color: white; | ||||
|   border: 1px solid dimgray; | ||||
|   margin-top: -7px; | ||||
| } | ||||
| input[type=range]::-moz-range-thumb { | ||||
|   appearance: none; | ||||
|   width: 18px; | ||||
|   height: 20px; | ||||
|   border-radius: 5px; | ||||
|   background-color: white; | ||||
|   border: 1px solid dimgray; | ||||
|   margin-top: -7px; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * File choosers | ||||
|  */ | ||||
| input[type=file] { | ||||
|   background-image: none; | ||||
|   border: none; | ||||
| } | ||||
| input::file-selector-button { | ||||
|   margin-right: 6px; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Hover | ||||
|  */ | ||||
| input[type=button]:hover, | ||||
| input[type=color]:hover, | ||||
| input[type=image]:hover, | ||||
| input[type=reset]:hover, | ||||
| input[type=submit]:hover, | ||||
| input::file-selector-button:hover, | ||||
| button:hover { | ||||
|   background-image: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250)); | ||||
| } | ||||
| select:hover { | ||||
|   background-image: var(--select-arrow), | ||||
|     linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250)); | ||||
|   background-position: calc(100% - 7px), left top; | ||||
|   background-repeat: no-repeat; | ||||
| } | ||||
| @media (any-pointer: coarse) { | ||||
|   /* We don't want a hover style after touch input */ | ||||
|   input[type=button]:hover, | ||||
|   input[type=color]:hover, | ||||
|   input[type=image]:hover, | ||||
|   input[type=reset]:hover, | ||||
|   input[type=submit]:hover, | ||||
|   input::file-selector-button:hover, | ||||
|   button:hover { | ||||
|     background-image: var(--bg-gradient); | ||||
|   } | ||||
|   select:hover { | ||||
|     background-image: var(--select-arrow), var(--bg-gradient); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Active (clicked) | ||||
|  */ | ||||
| input[type=button]:active, | ||||
| input[type=color]:active, | ||||
| input[type=image]:active, | ||||
| input[type=reset]:active, | ||||
| input[type=submit]:active, | ||||
| input::file-selector-button:active, | ||||
| button:active, | ||||
| select:active { | ||||
|   border-bottom-width: 1px; | ||||
|   margin-top: 1px; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Focus (tab) | ||||
|  */ | ||||
| input:focus-visible, | ||||
| input:focus-visible::file-selector-button, | ||||
| button:focus-visible, | ||||
| select:focus-visible, | ||||
| textarea:focus-visible { | ||||
|   outline: 2px solid rgb(74, 144, 217); | ||||
|   outline-offset: 1px; | ||||
| } | ||||
| input[type=file]:focus-visible { | ||||
|   outline: none; /* We outline the button instead of the entire element */ | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Disabled | ||||
|  */ | ||||
| input:disabled, | ||||
| input:disabled::file-selector-button, | ||||
| button:disabled, | ||||
| select:disabled, | ||||
| textarea:disabled { | ||||
|   opacity: 0.4; | ||||
| } | ||||
| input[type=button]:disabled, | ||||
| input[type=color]:disabled, | ||||
| input[type=image]:disabled, | ||||
| input[type=reset]:disabled, | ||||
| input[type=submit]:disabled, | ||||
| input:disabled::file-selector-button, | ||||
| button:disabled, | ||||
| select:disabled { | ||||
|   background-image: var(--bg-gradient); | ||||
|   border-bottom-width: 2px; | ||||
|   margin-top: 0; | ||||
| } | ||||
| input[type=file]:disabled { | ||||
|   background-image: none; | ||||
| } | ||||
| select:disabled { | ||||
|   background-image: var(--select-arrow), var(--bg-gradient); | ||||
| } | ||||
| input[type=image]:disabled { | ||||
|   /* See Firefox bug: | ||||
|      https://bugzilla.mozilla.org/show_bug.cgi?id=1798304 */ | ||||
|   cursor: default; | ||||
| } | ||||
| @ -8,7 +8,8 @@ | ||||
| 
 | ||||
| import * as Log from '../core/util/logging.js'; | ||||
| import _, { l10n } from './localization.js'; | ||||
| import { isTouchDevice, isSafari, hasScrollbarGutter, dragThreshold } | ||||
| import { isTouchDevice, isMac, isIOS, isAndroid, isChromeOS, isSafari, | ||||
|          hasScrollbarGutter, dragThreshold } | ||||
|     from '../core/util/browser.js'; | ||||
| import { setCapture, getPointerEvent } from '../core/util/events.js'; | ||||
| import KeyTable from "../core/input/keysym.js"; | ||||
| @ -63,7 +64,21 @@ const UI = { | ||||
|         // Translate the DOM
 | ||||
|         l10n.translateDOM(); | ||||
| 
 | ||||
|         WebUtil.fetchJSON('./package.json') | ||||
|         // We rely on modern APIs which might not be available in an
 | ||||
|         // insecure context
 | ||||
|         if (!window.isSecureContext) { | ||||
|             // FIXME: This gets hidden when connecting
 | ||||
|             UI.showStatus(_("HTTPS is required for full functionality"), 'error'); | ||||
|         } | ||||
| 
 | ||||
|         // Try to fetch version number
 | ||||
|         fetch('./package.json') | ||||
|             .then((response) => { | ||||
|                 if (!response.ok) { | ||||
|                     throw Error("" + response.status + " " + response.statusText); | ||||
|                 } | ||||
|                 return response.json(); | ||||
|             }) | ||||
|             .then((packageInfo) => { | ||||
|                 Array.from(document.getElementsByClassName('noVNC_version')).forEach(el => el.innerText = packageInfo.version); | ||||
|             }) | ||||
| @ -76,7 +91,6 @@ const UI = { | ||||
| 
 | ||||
|         // Adapt the interface for touch screen devices
 | ||||
|         if (isTouchDevice) { | ||||
|             document.documentElement.classList.add("noVNC_touch"); | ||||
|             // Remove the address bar
 | ||||
|             setTimeout(() => window.scrollTo(0, 1), 100); | ||||
|         } | ||||
| @ -316,6 +330,10 @@ const UI = { | ||||
|         document.getElementById("noVNC_cancel_reconnect_button") | ||||
|             .addEventListener('click', UI.cancelReconnect); | ||||
| 
 | ||||
|         document.getElementById("noVNC_approve_server_button") | ||||
|             .addEventListener('click', UI.approveServer); | ||||
|         document.getElementById("noVNC_reject_server_button") | ||||
|             .addEventListener('click', UI.rejectServer); | ||||
|         document.getElementById("noVNC_credentials_button") | ||||
|             .addEventListener('click', UI.setCredentials); | ||||
|     }, | ||||
| @ -445,6 +463,8 @@ const UI = { | ||||
|         // State change closes dialogs as they may not be relevant
 | ||||
|         // anymore
 | ||||
|         UI.closeAllPanels(); | ||||
|         document.getElementById('noVNC_verify_server_dlg') | ||||
|             .classList.remove('noVNC_open'); | ||||
|         document.getElementById('noVNC_credentials_dlg') | ||||
|             .classList.remove('noVNC_open'); | ||||
|     }, | ||||
| @ -589,10 +609,20 @@ const UI = { | ||||
| 
 | ||||
|         // Consider this a movement of the handle
 | ||||
|         UI.controlbarDrag = true; | ||||
| 
 | ||||
|         // The user has "followed" hint, let's hide it until the next drag
 | ||||
|         UI.showControlbarHint(false, false); | ||||
|     }, | ||||
| 
 | ||||
|     showControlbarHint(show) { | ||||
|     showControlbarHint(show, animate=true) { | ||||
|         const hint = document.getElementById('noVNC_control_bar_hint'); | ||||
| 
 | ||||
|         if (animate) { | ||||
|             hint.classList.remove("noVNC_notransition"); | ||||
|         } else { | ||||
|             hint.classList.add("noVNC_notransition"); | ||||
|         } | ||||
| 
 | ||||
|         if (show) { | ||||
|             hint.classList.add("noVNC_active"); | ||||
|         } else { | ||||
| @ -773,11 +803,6 @@ const UI = { | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             /*Weird IE9 error leads to 'null' appearring | ||||
|             in textboxes instead of ''.*/ | ||||
|             if (value === null) { | ||||
|                 value = ""; | ||||
|             } | ||||
|             ctrl.value = value; | ||||
|         } | ||||
|     }, | ||||
| @ -1055,8 +1080,10 @@ const UI = { | ||||
|                            credentials: { password: password } }); | ||||
|         UI.rfb.addEventListener("connect", UI.connectFinished); | ||||
|         UI.rfb.addEventListener("disconnect", UI.disconnectFinished); | ||||
|         UI.rfb.addEventListener("serververification", UI.serverVerify); | ||||
|         UI.rfb.addEventListener("credentialsrequired", UI.credentials); | ||||
|         UI.rfb.addEventListener("securityfailure", UI.securityFailed); | ||||
|         UI.rfb.addEventListener("clippingviewport", UI.updateViewDrag); | ||||
|         UI.rfb.addEventListener("capabilities", UI.updatePowerButton); | ||||
|         UI.rfb.addEventListener("clipboard", UI.clipboardReceive); | ||||
|         UI.rfb.addEventListener("bell", UI.bell); | ||||
| @ -1142,7 +1169,9 @@ const UI = { | ||||
|             } else { | ||||
|                 UI.showStatus(_("Failed to connect to server / access token has expired"), 'error'); | ||||
|             } | ||||
|         } else if (UI.getSetting('reconnect', false) === true && !UI.inhibitReconnect) { | ||||
|         } | ||||
|         // If reconnecting is allowed process it now
 | ||||
|         if (UI.getSetting('reconnect', false) === true && !UI.inhibitReconnect) { | ||||
|             UI.updateVisualState('reconnecting'); | ||||
| 
 | ||||
|             const delay = parseInt(UI.getSetting('reconnect_delay')); | ||||
| @ -1176,6 +1205,37 @@ const UI = { | ||||
| /* ------^------- | ||||
|  *  /CONNECTION | ||||
|  * ============== | ||||
|  * SERVER VERIFY | ||||
|  * ------v------*/ | ||||
| 
 | ||||
|     async serverVerify(e) { | ||||
|         const type = e.detail.type; | ||||
|         if (type === 'RSA') { | ||||
|             const publickey = e.detail.publickey; | ||||
|             let fingerprint = await window.crypto.subtle.digest("SHA-1", publickey); | ||||
|             // The same fingerprint format as RealVNC
 | ||||
|             fingerprint = Array.from(new Uint8Array(fingerprint).slice(0, 8)).map( | ||||
|                 x => x.toString(16).padStart(2, '0')).join('-'); | ||||
|             document.getElementById('noVNC_verify_server_dlg').classList.add('noVNC_open'); | ||||
|             document.getElementById('noVNC_fingerprint').innerHTML = fingerprint; | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     approveServer(e) { | ||||
|         e.preventDefault(); | ||||
|         document.getElementById('noVNC_verify_server_dlg').classList.remove('noVNC_open'); | ||||
|         UI.rfb.approveServer(); | ||||
|     }, | ||||
| 
 | ||||
|     rejectServer(e) { | ||||
|         e.preventDefault(); | ||||
|         document.getElementById('noVNC_verify_server_dlg').classList.remove('noVNC_open'); | ||||
|         UI.disconnect(); | ||||
|     }, | ||||
| 
 | ||||
| /* ------^------- | ||||
|  * /SERVER VERIFY | ||||
|  * ============== | ||||
|  *   PASSWORD | ||||
|  * ------v------*/ | ||||
| 
 | ||||
| @ -1275,13 +1335,25 @@ const UI = { | ||||
| 
 | ||||
|         const scaling = UI.getSetting('resize') === 'scale'; | ||||
| 
 | ||||
|         // Some platforms have overlay scrollbars that are difficult
 | ||||
|         // to use in our case, which means we have to force panning
 | ||||
|         // FIXME: Working scrollbars can still be annoying to use with
 | ||||
|         //        touch, so we should ideally be able to have both
 | ||||
|         //        panning and scrollbars at the same time
 | ||||
| 
 | ||||
|         let brokenScrollbars = false; | ||||
| 
 | ||||
|         if (!hasScrollbarGutter) { | ||||
|             if (isIOS() || isAndroid() || isMac() || isChromeOS()) { | ||||
|                 brokenScrollbars = true; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (scaling) { | ||||
|             // Can't be clipping if viewport is scaled to fit
 | ||||
|             UI.forceSetting('view_clip', false); | ||||
|             UI.rfb.clipViewport  = false; | ||||
|         } else if (!hasScrollbarGutter) { | ||||
|             // Some platforms have scrollbars that are difficult
 | ||||
|             // to use in our case, so we always use our own panning
 | ||||
|         } else if (brokenScrollbars) { | ||||
|             UI.forceSetting('view_clip', true); | ||||
|             UI.rfb.clipViewport = true; | ||||
|         } else { | ||||
| @ -1312,7 +1384,8 @@ const UI = { | ||||
| 
 | ||||
|         const viewDragButton = document.getElementById('noVNC_view_drag_button'); | ||||
| 
 | ||||
|         if (!UI.rfb.clipViewport && UI.rfb.dragViewport) { | ||||
|         if ((!UI.rfb.clipViewport || !UI.rfb.clippingViewport) && | ||||
|             UI.rfb.dragViewport) { | ||||
|             // We are no longer clipping the viewport. Make sure
 | ||||
|             // viewport drag isn't active when it can't be used.
 | ||||
|             UI.rfb.dragViewport = false; | ||||
| @ -1329,6 +1402,8 @@ const UI = { | ||||
|         } else { | ||||
|             viewDragButton.classList.add("noVNC_hidden"); | ||||
|         } | ||||
| 
 | ||||
|         viewDragButton.disabled = !UI.rfb.clippingViewport; | ||||
|     }, | ||||
| 
 | ||||
| /* ------^------- | ||||
| @ -1713,12 +1788,18 @@ const UI = { | ||||
| }; | ||||
| 
 | ||||
| // Set up translations
 | ||||
| const LINGUAS = ["cs", "de", "el", "es", "ja", "ko", "nl", "pl", "ru", "sv", "tr", "zh_CN", "zh_TW"]; | ||||
| const LINGUAS = ["cs", "de", "el", "es", "fr", "it", "ja", "ko", "nl", "pl", "pt_BR", "ru", "sv", "tr", "zh_CN", "zh_TW"]; | ||||
| l10n.setup(LINGUAS); | ||||
| if (l10n.language === "en" || l10n.dictionary !== undefined) { | ||||
|     UI.prime(); | ||||
| } else { | ||||
|     WebUtil.fetchJSON('app/locale/' + l10n.language + '.json') | ||||
|     fetch('app/locale/' + l10n.language + '.json') | ||||
|         .then((response) => { | ||||
|             if (!response.ok) { | ||||
|                 throw Error("" + response.status + " " + response.statusText); | ||||
|             } | ||||
|             return response.json(); | ||||
|         }) | ||||
|         .then((translations) => { l10n.dictionary = translations; }) | ||||
|         .catch(err => Log.Error("Failed to load translations: " + err)) | ||||
|         .then(UI.prime); | ||||
|  | ||||
| @ -20,10 +20,19 @@ export function initLogging(level) { | ||||
| } | ||||
| 
 | ||||
| // Read a query string variable
 | ||||
| // A URL with a query parameter can look like this (But will most probably get logged on the http server):
 | ||||
| // https://www.example.com?myqueryparam=myvalue
 | ||||
| //
 | ||||
| // For privacy (Using a hastag #, the parameters will not be sent to the server)
 | ||||
| // the url can be requested in the following way:
 | ||||
| // https://www.example.com#myqueryparam=myvalue&password=secreatvalue
 | ||||
| //
 | ||||
| // Even Mixing public and non public parameters will work:
 | ||||
| // https://www.example.com?nonsecretparam=example.com#password=secreatvalue
 | ||||
| export function getQueryVar(name, defVal) { | ||||
|     "use strict"; | ||||
|     const re = new RegExp('.*[?&]' + name + '=([^&#]*)'), | ||||
|         match = document.location.href.match(re); | ||||
|           match = ''.concat(document.location.href, window.location.hash).match(re); | ||||
|     if (typeof defVal === 'undefined') { defVal = null; } | ||||
| 
 | ||||
|     if (match) { | ||||
| @ -156,65 +165,3 @@ export function eraseSetting(name) { | ||||
|     // value change.
 | ||||
|     delete settings[name]; | ||||
| } | ||||
| 
 | ||||
| export function injectParamIfMissing(path, param, value) { | ||||
|     // force pretend that we're dealing with a relative path
 | ||||
|     // (assume that we wanted an extra if we pass one in)
 | ||||
|     path = "/" + path; | ||||
| 
 | ||||
|     const elem = document.createElement('a'); | ||||
|     elem.href = path; | ||||
| 
 | ||||
|     const paramEq = encodeURIComponent(param) + "="; | ||||
|     let query; | ||||
|     if (elem.search) { | ||||
|         query = elem.search.slice(1).split('&'); | ||||
|     } else { | ||||
|         query = []; | ||||
|     } | ||||
| 
 | ||||
|     if (!query.some(v => v.startsWith(paramEq))) { | ||||
|         query.push(paramEq + encodeURIComponent(value)); | ||||
|         elem.search = "?" + query.join("&"); | ||||
|     } | ||||
| 
 | ||||
|     // some browsers (e.g. IE11) may occasionally omit the leading slash
 | ||||
|     // in the elem.pathname string. Handle that case gracefully.
 | ||||
|     if (elem.pathname.charAt(0) == "/") { | ||||
|         return elem.pathname.slice(1) + elem.search + elem.hash; | ||||
|     } | ||||
| 
 | ||||
|     return elem.pathname + elem.search + elem.hash; | ||||
| } | ||||
| 
 | ||||
| // sadly, we can't use the Fetch API until we decide to drop
 | ||||
| // IE11 support or polyfill promises and fetch in IE11.
 | ||||
| // resolve will receive an object on success, while reject
 | ||||
| // will receive either an event or an error on failure.
 | ||||
| export function fetchJSON(path) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|         // NB: IE11 doesn't support JSON as a responseType
 | ||||
|         const req = new XMLHttpRequest(); | ||||
|         req.open('GET', path); | ||||
| 
 | ||||
|         req.onload = () => { | ||||
|             if (req.status === 200) { | ||||
|                 let resObj; | ||||
|                 try { | ||||
|                     resObj = JSON.parse(req.responseText); | ||||
|                 } catch (err) { | ||||
|                     reject(err); | ||||
|                 } | ||||
|                 resolve(resObj); | ||||
|             } else { | ||||
|                 reject(new Error("XHR got non-200 status while trying to load '" + path + "': " + req.status)); | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         req.onerror = evt => reject(new Error("XHR encountered an error while trying to load '" + path + "': " + evt.message)); | ||||
| 
 | ||||
|         req.ontimeout = evt => reject(new Error("XHR timed out while trying to load '" + path + "'")); | ||||
| 
 | ||||
|         req.send(); | ||||
|     }); | ||||
| } | ||||
|  | ||||
							
								
								
									
										141
									
								
								systemvm/agent/noVNC/core/decoders/jpeg.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								systemvm/agent/noVNC/core/decoders/jpeg.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,141 @@ | ||||
| /* | ||||
|  * noVNC: HTML5 VNC client | ||||
|  * Copyright (C) 2019 The noVNC Authors | ||||
|  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||
|  * | ||||
|  * See README.md for usage and integration instructions. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| export default class JPEGDecoder { | ||||
|     constructor() { | ||||
|         // RealVNC will reuse the quantization tables
 | ||||
|         // and Huffman tables, so we need to cache them.
 | ||||
|         this._quantTables = []; | ||||
|         this._huffmanTables = []; | ||||
|         this._cachedQuantTables = []; | ||||
|         this._cachedHuffmanTables = []; | ||||
| 
 | ||||
|         this._jpegLength = 0; | ||||
|         this._segments = []; | ||||
|     } | ||||
| 
 | ||||
|     decodeRect(x, y, width, height, sock, display, depth) { | ||||
|         // A rect of JPEG encodings is simply a JPEG file
 | ||||
|         if (!this._parseJPEG(sock.rQslice(0))) { | ||||
|             return false; | ||||
|         } | ||||
|         const data = sock.rQshiftBytes(this._jpegLength); | ||||
|         if (this._quantTables.length != 0 && this._huffmanTables.length != 0) { | ||||
|             // If there are quantization tables and Huffman tables in the JPEG
 | ||||
|             // image, we can directly render it.
 | ||||
|             display.imageRect(x, y, width, height, "image/jpeg", data); | ||||
|             return true; | ||||
|         } else { | ||||
|             // Otherwise we need to insert cached tables.
 | ||||
|             const sofIndex = this._segments.findIndex( | ||||
|                 x => x[1] == 0xC0 || x[1] == 0xC2 | ||||
|             ); | ||||
|             if (sofIndex == -1) { | ||||
|                 throw new Error("Illegal JPEG image without SOF"); | ||||
|             } | ||||
|             let segments = this._segments.slice(0, sofIndex); | ||||
|             segments = segments.concat(this._quantTables.length ? | ||||
|                 this._quantTables : | ||||
|                 this._cachedQuantTables); | ||||
|             segments.push(this._segments[sofIndex]); | ||||
|             segments = segments.concat(this._huffmanTables.length ? | ||||
|                 this._huffmanTables : | ||||
|                 this._cachedHuffmanTables, | ||||
|                                        this._segments.slice(sofIndex + 1)); | ||||
|             let length = 0; | ||||
|             for (let i = 0; i < segments.length; i++) { | ||||
|                 length += segments[i].length; | ||||
|             } | ||||
|             const data = new Uint8Array(length); | ||||
|             length = 0; | ||||
|             for (let i = 0; i < segments.length; i++) { | ||||
|                 data.set(segments[i], length); | ||||
|                 length += segments[i].length; | ||||
|             } | ||||
|             display.imageRect(x, y, width, height, "image/jpeg", data); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     _parseJPEG(buffer) { | ||||
|         if (this._quantTables.length != 0) { | ||||
|             this._cachedQuantTables = this._quantTables; | ||||
|         } | ||||
|         if (this._huffmanTables.length != 0) { | ||||
|             this._cachedHuffmanTables = this._huffmanTables; | ||||
|         } | ||||
|         this._quantTables = []; | ||||
|         this._huffmanTables = []; | ||||
|         this._segments = []; | ||||
|         let i = 0; | ||||
|         let bufferLength = buffer.length; | ||||
|         while (true) { | ||||
|             let j = i; | ||||
|             if (j + 2 > bufferLength) { | ||||
|                 return false; | ||||
|             } | ||||
|             if (buffer[j] != 0xFF) { | ||||
|                 throw new Error("Illegal JPEG marker received (byte: " + | ||||
|                                    buffer[j] + ")"); | ||||
|             } | ||||
|             const type = buffer[j+1]; | ||||
|             j += 2; | ||||
|             if (type == 0xD9) { | ||||
|                 this._jpegLength = j; | ||||
|                 this._segments.push(buffer.slice(i, j)); | ||||
|                 return true; | ||||
|             } else if (type == 0xDA) { | ||||
|                 // start of scan
 | ||||
|                 let hasFoundEndOfScan = false; | ||||
|                 for (let k = j + 3; k + 1 < bufferLength; k++) { | ||||
|                     if (buffer[k] == 0xFF && buffer[k+1] != 0x00 && | ||||
|                         !(buffer[k+1] >= 0xD0 && buffer[k+1] <= 0xD7)) { | ||||
|                         j = k; | ||||
|                         hasFoundEndOfScan = true; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                 if (!hasFoundEndOfScan) { | ||||
|                     return false; | ||||
|                 } | ||||
|                 this._segments.push(buffer.slice(i, j)); | ||||
|                 i = j; | ||||
|                 continue; | ||||
|             } else if (type >= 0xD0 && type < 0xD9 || type == 0x01) { | ||||
|                 // No length after marker
 | ||||
|                 this._segments.push(buffer.slice(i, j)); | ||||
|                 i = j; | ||||
|                 continue; | ||||
|             } | ||||
|             if (j + 2 > bufferLength) { | ||||
|                 return false; | ||||
|             } | ||||
|             const length = (buffer[j] << 8) + buffer[j+1] - 2; | ||||
|             if (length < 0) { | ||||
|                 throw new Error("Illegal JPEG length received (length: " + | ||||
|                                    length + ")"); | ||||
|             } | ||||
|             j += 2; | ||||
|             if (j + length > bufferLength) { | ||||
|                 return false; | ||||
|             } | ||||
|             j += length; | ||||
|             const segment = buffer.slice(i, j); | ||||
|             if (type == 0xC4) { | ||||
|                 // Huffman tables
 | ||||
|                 this._huffmanTables.push(segment); | ||||
|             } else if (type == 0xDB) { | ||||
|                 // Quantization tables
 | ||||
|                 this._quantTables.push(segment); | ||||
|             } | ||||
|             this._segments.push(segment); | ||||
|             i = j; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -51,7 +51,7 @@ export default class RawDecoder { | ||||
| 
 | ||||
|         // Max sure the image is fully opaque
 | ||||
|         for (let i = 0; i < pixels; i++) { | ||||
|             data[i * 4 + 3] = 255; | ||||
|             data[index + i * 4 + 3] = 255; | ||||
|         } | ||||
| 
 | ||||
|         display.blitImage(x, curY, width, currHeight, data, index); | ||||
|  | ||||
							
								
								
									
										185
									
								
								systemvm/agent/noVNC/core/decoders/zrle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								systemvm/agent/noVNC/core/decoders/zrle.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,185 @@ | ||||
| /* | ||||
|  * noVNC: HTML5 VNC client | ||||
|  * Copyright (C) 2021 The noVNC Authors | ||||
|  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||
|  * | ||||
|  * See README.md for usage and integration instructions. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| import Inflate from "../inflator.js"; | ||||
| 
 | ||||
| const ZRLE_TILE_WIDTH = 64; | ||||
| const ZRLE_TILE_HEIGHT = 64; | ||||
| 
 | ||||
| export default class ZRLEDecoder { | ||||
|     constructor() { | ||||
|         this._length = 0; | ||||
|         this._inflator = new Inflate(); | ||||
| 
 | ||||
|         this._pixelBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4); | ||||
|         this._tileBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4); | ||||
|     } | ||||
| 
 | ||||
|     decodeRect(x, y, width, height, sock, display, depth) { | ||||
|         if (this._length === 0) { | ||||
|             if (sock.rQwait("ZLib data length", 4)) { | ||||
|                 return false; | ||||
|             } | ||||
|             this._length = sock.rQshift32(); | ||||
|         } | ||||
|         if (sock.rQwait("Zlib data", this._length)) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         const data = sock.rQshiftBytes(this._length); | ||||
| 
 | ||||
|         this._inflator.setInput(data); | ||||
| 
 | ||||
|         for (let ty = y; ty < y + height; ty += ZRLE_TILE_HEIGHT) { | ||||
|             let th = Math.min(ZRLE_TILE_HEIGHT, y + height - ty); | ||||
| 
 | ||||
|             for (let tx = x; tx < x + width; tx += ZRLE_TILE_WIDTH) { | ||||
|                 let tw = Math.min(ZRLE_TILE_WIDTH, x + width - tx); | ||||
| 
 | ||||
|                 const tileSize = tw * th; | ||||
|                 const subencoding = this._inflator.inflate(1)[0]; | ||||
|                 if (subencoding === 0) { | ||||
|                     // raw data
 | ||||
|                     const data = this._readPixels(tileSize); | ||||
|                     display.blitImage(tx, ty, tw, th, data, 0, false); | ||||
|                 } else if (subencoding === 1) { | ||||
|                     // solid
 | ||||
|                     const background = this._readPixels(1); | ||||
|                     display.fillRect(tx, ty, tw, th, [background[0], background[1], background[2]]); | ||||
|                 } else if (subencoding >= 2 && subencoding <= 16) { | ||||
|                     const data = this._decodePaletteTile(subencoding, tileSize, tw, th); | ||||
|                     display.blitImage(tx, ty, tw, th, data, 0, false); | ||||
|                 } else if (subencoding === 128) { | ||||
|                     const data = this._decodeRLETile(tileSize); | ||||
|                     display.blitImage(tx, ty, tw, th, data, 0, false); | ||||
|                 } else if (subencoding >= 130 && subencoding <= 255) { | ||||
|                     const data = this._decodeRLEPaletteTile(subencoding - 128, tileSize); | ||||
|                     display.blitImage(tx, ty, tw, th, data, 0, false); | ||||
|                 } else { | ||||
|                     throw new Error('Unknown subencoding: ' + subencoding); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         this._length = 0; | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     _getBitsPerPixelInPalette(paletteSize) { | ||||
|         if (paletteSize <= 2) { | ||||
|             return 1; | ||||
|         } else if (paletteSize <= 4) { | ||||
|             return 2; | ||||
|         } else if (paletteSize <= 16) { | ||||
|             return 4; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     _readPixels(pixels) { | ||||
|         let data = this._pixelBuffer; | ||||
|         const buffer = this._inflator.inflate(3*pixels); | ||||
|         for (let i = 0, j = 0; i < pixels*4; i += 4, j += 3) { | ||||
|             data[i]     = buffer[j]; | ||||
|             data[i + 1] = buffer[j + 1]; | ||||
|             data[i + 2] = buffer[j + 2]; | ||||
|             data[i + 3] = 255;  // Add the Alpha
 | ||||
|         } | ||||
|         return data; | ||||
|     } | ||||
| 
 | ||||
|     _decodePaletteTile(paletteSize, tileSize, tilew, tileh) { | ||||
|         const data = this._tileBuffer; | ||||
|         const palette = this._readPixels(paletteSize); | ||||
|         const bitsPerPixel = this._getBitsPerPixelInPalette(paletteSize); | ||||
|         const mask = (1 << bitsPerPixel) - 1; | ||||
| 
 | ||||
|         let offset = 0; | ||||
|         let encoded = this._inflator.inflate(1)[0]; | ||||
| 
 | ||||
|         for (let y=0; y<tileh; y++) { | ||||
|             let shift = 8-bitsPerPixel; | ||||
|             for (let x=0; x<tilew; x++) { | ||||
|                 if (shift<0) { | ||||
|                     shift=8-bitsPerPixel; | ||||
|                     encoded = this._inflator.inflate(1)[0]; | ||||
|                 } | ||||
|                 let indexInPalette = (encoded>>shift) & mask; | ||||
| 
 | ||||
|                 data[offset] = palette[indexInPalette * 4]; | ||||
|                 data[offset + 1] = palette[indexInPalette * 4 + 1]; | ||||
|                 data[offset + 2] = palette[indexInPalette * 4 + 2]; | ||||
|                 data[offset + 3] = palette[indexInPalette * 4 + 3]; | ||||
|                 offset += 4; | ||||
|                 shift-=bitsPerPixel; | ||||
|             } | ||||
|             if (shift<8-bitsPerPixel && y<tileh-1) { | ||||
|                 encoded =  this._inflator.inflate(1)[0]; | ||||
|             } | ||||
|         } | ||||
|         return data; | ||||
|     } | ||||
| 
 | ||||
|     _decodeRLETile(tileSize) { | ||||
|         const data = this._tileBuffer; | ||||
|         let i = 0; | ||||
|         while (i < tileSize) { | ||||
|             const pixel = this._readPixels(1); | ||||
|             const length = this._readRLELength(); | ||||
|             for (let j = 0; j < length; j++) { | ||||
|                 data[i * 4] = pixel[0]; | ||||
|                 data[i * 4 + 1] = pixel[1]; | ||||
|                 data[i * 4 + 2] = pixel[2]; | ||||
|                 data[i * 4 + 3] = pixel[3]; | ||||
|                 i++; | ||||
|             } | ||||
|         } | ||||
|         return data; | ||||
|     } | ||||
| 
 | ||||
|     _decodeRLEPaletteTile(paletteSize, tileSize) { | ||||
|         const data = this._tileBuffer; | ||||
| 
 | ||||
|         // palette
 | ||||
|         const palette = this._readPixels(paletteSize); | ||||
| 
 | ||||
|         let offset = 0; | ||||
|         while (offset < tileSize) { | ||||
|             let indexInPalette = this._inflator.inflate(1)[0]; | ||||
|             let length = 1; | ||||
|             if (indexInPalette >= 128) { | ||||
|                 indexInPalette -= 128; | ||||
|                 length = this._readRLELength(); | ||||
|             } | ||||
|             if (indexInPalette > paletteSize) { | ||||
|                 throw new Error('Too big index in palette: ' + indexInPalette + ', palette size: ' + paletteSize); | ||||
|             } | ||||
|             if (offset + length > tileSize) { | ||||
|                 throw new Error('Too big rle length in palette mode: ' + length + ', allowed length is: ' + (tileSize - offset)); | ||||
|             } | ||||
| 
 | ||||
|             for (let j = 0; j < length; j++) { | ||||
|                 data[offset * 4] = palette[indexInPalette * 4]; | ||||
|                 data[offset * 4 + 1] = palette[indexInPalette * 4 + 1]; | ||||
|                 data[offset * 4 + 2] = palette[indexInPalette * 4 + 2]; | ||||
|                 data[offset * 4 + 3] = palette[indexInPalette * 4 + 3]; | ||||
|                 offset++; | ||||
|             } | ||||
|         } | ||||
|         return data; | ||||
|     } | ||||
| 
 | ||||
|     _readRLELength() { | ||||
|         let length = 0; | ||||
|         let current = 0; | ||||
|         do { | ||||
|             current = this._inflator.inflate(1)[0]; | ||||
|             length += current; | ||||
|         } while (current === 255); | ||||
|         return length + 1; | ||||
|     } | ||||
| } | ||||
| @ -8,7 +8,6 @@ | ||||
| 
 | ||||
| import * as Log from './util/logging.js'; | ||||
| import Base64 from "./base64.js"; | ||||
| import { supportsImageMetadata } from './util/browser.js'; | ||||
| import { toSigned32bit } from './util/int.js'; | ||||
| 
 | ||||
| export default class Display { | ||||
| @ -56,11 +55,6 @@ export default class Display { | ||||
| 
 | ||||
|         Log.Debug("User Agent: " + navigator.userAgent); | ||||
| 
 | ||||
|         // Check canvas features
 | ||||
|         if (!('createImageData' in this._drawCtx)) { | ||||
|             throw new Error("Canvas does not support createImageData"); | ||||
|         } | ||||
| 
 | ||||
|         Log.Debug("<< Display.constructor"); | ||||
| 
 | ||||
|         // ===== PROPERTIES =====
 | ||||
| @ -230,6 +224,18 @@ export default class Display { | ||||
|         this.viewportChangePos(0, 0); | ||||
|     } | ||||
| 
 | ||||
|     getImageData() { | ||||
|         return this._drawCtx.getImageData(0, 0, this.width, this.height); | ||||
|     } | ||||
| 
 | ||||
|     toDataURL(type, encoderOptions) { | ||||
|         return this._backbuffer.toDataURL(type, encoderOptions); | ||||
|     } | ||||
| 
 | ||||
|     toBlob(callback, type, quality) { | ||||
|         return this._backbuffer.toBlob(callback, type, quality); | ||||
|     } | ||||
| 
 | ||||
|     // Track what parts of the visible canvas that need updating
 | ||||
|     _damage(x, y, w, h) { | ||||
|         if (x < this._damageBounds.left) { | ||||
| @ -393,13 +399,7 @@ export default class Display { | ||||
|             let data = new Uint8ClampedArray(arr.buffer, | ||||
|                                              arr.byteOffset + offset, | ||||
|                                              width * height * 4); | ||||
|             let img; | ||||
|             if (supportsImageMetadata) { | ||||
|                 img = new ImageData(data, width, height); | ||||
|             } else { | ||||
|                 img = this._drawCtx.createImageData(width, height); | ||||
|                 img.data.set(data); | ||||
|             } | ||||
|             let img = new ImageData(data, width, height); | ||||
|             this._drawCtx.putImageData(img, x, y); | ||||
|             this._damage(x, y, width, height); | ||||
|         } | ||||
| @ -494,8 +494,7 @@ export default class Display { | ||||
|                     this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, true); | ||||
|                     break; | ||||
|                 case 'img': | ||||
|                     /* IE tends to set "complete" prematurely, so check dimensions */ | ||||
|                     if (a.img.complete && (a.img.width !== 0) && (a.img.height !== 0)) { | ||||
|                     if (a.img.complete) { | ||||
|                         if (a.img.width !== a.width || a.img.height !== a.height) { | ||||
|                             Log.Error("Decoded image has incorrect dimensions. Got " + | ||||
|                                       a.img.width + "x" + a.img.height + ". Expected " + | ||||
|  | ||||
| @ -12,7 +12,9 @@ export const encodings = { | ||||
|     encodingRRE: 2, | ||||
|     encodingHextile: 5, | ||||
|     encodingTight: 7, | ||||
|     encodingZRLE: 16, | ||||
|     encodingTightPNG: -260, | ||||
|     encodingJPEG: 21, | ||||
| 
 | ||||
|     pseudoEncodingQualityLevel9: -23, | ||||
|     pseudoEncodingQualityLevel0: -32, | ||||
| @ -38,7 +40,9 @@ export function encodingName(num) { | ||||
|         case encodings.encodingRRE:      return "RRE"; | ||||
|         case encodings.encodingHextile:  return "Hextile"; | ||||
|         case encodings.encodingTight:    return "Tight"; | ||||
|         case encodings.encodingZRLE:     return "ZRLE"; | ||||
|         case encodings.encodingTightPNG: return "TightPNG"; | ||||
|         case encodings.encodingJPEG:     return "JPEG"; | ||||
|         default:                         return "[unknown encoding " + num + "]"; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -35,7 +35,7 @@ function addNumpad(key, standard, numpad) { | ||||
|     DOMKeyTable[key] = [standard, standard, standard, numpad]; | ||||
| } | ||||
| 
 | ||||
| // 2.2. Modifier Keys
 | ||||
| // 3.2. Modifier Keys
 | ||||
| 
 | ||||
| addLeftRight("Alt", KeyTable.XK_Alt_L, KeyTable.XK_Alt_R); | ||||
| addStandard("AltGraph", KeyTable.XK_ISO_Level3_Shift); | ||||
| @ -49,25 +49,27 @@ addStandard("ScrollLock", KeyTable.XK_Scroll_Lock); | ||||
| addLeftRight("Shift", KeyTable.XK_Shift_L, KeyTable.XK_Shift_R); | ||||
| // - Symbol
 | ||||
| // - SymbolLock
 | ||||
| // - Hyper
 | ||||
| // - Super
 | ||||
| 
 | ||||
| // 2.3. Whitespace Keys
 | ||||
| // 3.3. Whitespace Keys
 | ||||
| 
 | ||||
| addNumpad("Enter", KeyTable.XK_Return, KeyTable.XK_KP_Enter); | ||||
| addStandard("Tab", KeyTable.XK_Tab); | ||||
| addNumpad(" ", KeyTable.XK_space, KeyTable.XK_KP_Space); | ||||
| 
 | ||||
| // 2.4. Navigation Keys
 | ||||
| // 3.4. Navigation Keys
 | ||||
| 
 | ||||
| addNumpad("ArrowDown", KeyTable.XK_Down, KeyTable.XK_KP_Down); | ||||
| addNumpad("ArrowUp", KeyTable.XK_Up, KeyTable.XK_KP_Up); | ||||
| addNumpad("ArrowLeft", KeyTable.XK_Left, KeyTable.XK_KP_Left); | ||||
| addNumpad("ArrowRight", KeyTable.XK_Right, KeyTable.XK_KP_Right); | ||||
| addNumpad("ArrowUp", KeyTable.XK_Up, KeyTable.XK_KP_Up); | ||||
| addNumpad("End", KeyTable.XK_End, KeyTable.XK_KP_End); | ||||
| addNumpad("Home", KeyTable.XK_Home, KeyTable.XK_KP_Home); | ||||
| addNumpad("PageDown", KeyTable.XK_Next, KeyTable.XK_KP_Next); | ||||
| addNumpad("PageUp", KeyTable.XK_Prior, KeyTable.XK_KP_Prior); | ||||
| 
 | ||||
| // 2.5. Editing Keys
 | ||||
| // 3.5. Editing Keys
 | ||||
| 
 | ||||
| addStandard("Backspace", KeyTable.XK_BackSpace); | ||||
| // Browsers send "Clear" for the numpad 5 without NumLock because
 | ||||
| @ -85,7 +87,7 @@ addStandard("Paste", KeyTable.XF86XK_Paste); | ||||
| addStandard("Redo", KeyTable.XK_Redo); | ||||
| addStandard("Undo", KeyTable.XK_Undo); | ||||
| 
 | ||||
| // 2.6. UI Keys
 | ||||
| // 3.6. UI Keys
 | ||||
| 
 | ||||
| // - Accept
 | ||||
| // - Again (could just be XK_Redo)
 | ||||
| @ -103,7 +105,7 @@ addStandard("Select", KeyTable.XK_Select); | ||||
| addStandard("ZoomIn", KeyTable.XF86XK_ZoomIn); | ||||
| addStandard("ZoomOut", KeyTable.XF86XK_ZoomOut); | ||||
| 
 | ||||
| // 2.7. Device Keys
 | ||||
| // 3.7. Device Keys
 | ||||
| 
 | ||||
| addStandard("BrightnessDown", KeyTable.XF86XK_MonBrightnessDown); | ||||
| addStandard("BrightnessUp", KeyTable.XF86XK_MonBrightnessUp); | ||||
| @ -116,10 +118,10 @@ addStandard("Hibernate", KeyTable.XF86XK_Hibernate); | ||||
| addStandard("Standby", KeyTable.XF86XK_Standby); | ||||
| addStandard("WakeUp", KeyTable.XF86XK_WakeUp); | ||||
| 
 | ||||
| // 2.8. IME and Composition Keys
 | ||||
| // 3.8. IME and Composition Keys
 | ||||
| 
 | ||||
| addStandard("AllCandidates", KeyTable.XK_MultipleCandidate); | ||||
| addStandard("Alphanumeric", KeyTable.XK_Eisu_Shift); // could also be _Eisu_Toggle
 | ||||
| addStandard("Alphanumeric", KeyTable.XK_Eisu_toggle); | ||||
| addStandard("CodeInput", KeyTable.XK_Codeinput); | ||||
| addStandard("Compose", KeyTable.XK_Multi_key); | ||||
| addStandard("Convert", KeyTable.XK_Henkan); | ||||
| @ -137,7 +139,7 @@ addStandard("PreviousCandidate", KeyTable.XK_PreviousCandidate); | ||||
| addStandard("SingleCandidate", KeyTable.XK_SingleCandidate); | ||||
| addStandard("HangulMode", KeyTable.XK_Hangul); | ||||
| addStandard("HanjaMode", KeyTable.XK_Hangul_Hanja); | ||||
| addStandard("JunjuaMode", KeyTable.XK_Hangul_Jeonja); | ||||
| addStandard("JunjaMode", KeyTable.XK_Hangul_Jeonja); | ||||
| addStandard("Eisu", KeyTable.XK_Eisu_toggle); | ||||
| addStandard("Hankaku", KeyTable.XK_Hankaku); | ||||
| addStandard("Hiragana", KeyTable.XK_Hiragana); | ||||
| @ -147,9 +149,9 @@ addStandard("KanjiMode", KeyTable.XK_Kanji); | ||||
| addStandard("Katakana", KeyTable.XK_Katakana); | ||||
| addStandard("Romaji", KeyTable.XK_Romaji); | ||||
| addStandard("Zenkaku", KeyTable.XK_Zenkaku); | ||||
| addStandard("ZenkakuHanaku", KeyTable.XK_Zenkaku_Hankaku); | ||||
| addStandard("ZenkakuHankaku", KeyTable.XK_Zenkaku_Hankaku); | ||||
| 
 | ||||
| // 2.9. General-Purpose Function Keys
 | ||||
| // 3.9. General-Purpose Function Keys
 | ||||
| 
 | ||||
| addStandard("F1", KeyTable.XK_F1); | ||||
| addStandard("F2", KeyTable.XK_F2); | ||||
| @ -188,7 +190,7 @@ addStandard("F34", KeyTable.XK_F34); | ||||
| addStandard("F35", KeyTable.XK_F35); | ||||
| // - Soft1...
 | ||||
| 
 | ||||
| // 2.10. Multimedia Keys
 | ||||
| // 3.10. Multimedia Keys
 | ||||
| 
 | ||||
| // - ChannelDown
 | ||||
| // - ChannelUp
 | ||||
| @ -200,6 +202,7 @@ addStandard("MailSend", KeyTable.XF86XK_Send); | ||||
| addStandard("MediaFastForward", KeyTable.XF86XK_AudioForward); | ||||
| addStandard("MediaPause", KeyTable.XF86XK_AudioPause); | ||||
| addStandard("MediaPlay", KeyTable.XF86XK_AudioPlay); | ||||
| // - MediaPlayPause
 | ||||
| addStandard("MediaRecord", KeyTable.XF86XK_AudioRecord); | ||||
| addStandard("MediaRewind", KeyTable.XF86XK_AudioRewind); | ||||
| addStandard("MediaStop", KeyTable.XF86XK_AudioStop); | ||||
| @ -211,12 +214,12 @@ addStandard("Print", KeyTable.XK_Print); | ||||
| addStandard("Save", KeyTable.XF86XK_Save); | ||||
| addStandard("SpellCheck", KeyTable.XF86XK_Spell); | ||||
| 
 | ||||
| // 2.11. Multimedia Numpad Keys
 | ||||
| // 3.11. Multimedia Numpad Keys
 | ||||
| 
 | ||||
| // - Key11
 | ||||
| // - Key12
 | ||||
| 
 | ||||
| // 2.12. Audio Keys
 | ||||
| // 3.12. Audio Keys
 | ||||
| 
 | ||||
| // - AudioBalanceLeft
 | ||||
| // - AudioBalanceRight
 | ||||
| @ -236,16 +239,17 @@ addStandard("AudioVolumeMute", KeyTable.XF86XK_AudioMute); | ||||
| // - MicrophoneVolumeUp
 | ||||
| addStandard("MicrophoneVolumeMute", KeyTable.XF86XK_AudioMicMute); | ||||
| 
 | ||||
| // 2.13. Speech Keys
 | ||||
| // 3.13. Speech Keys
 | ||||
| 
 | ||||
| // - SpeechCorrectionList
 | ||||
| // - SpeechInputToggle
 | ||||
| 
 | ||||
| // 2.14. Application Keys
 | ||||
| // 3.14. Application Keys
 | ||||
| 
 | ||||
| addStandard("LaunchApplication1", KeyTable.XF86XK_MyComputer); | ||||
| addStandard("LaunchApplication2", KeyTable.XF86XK_Calculator); | ||||
| addStandard("LaunchCalendar", KeyTable.XF86XK_Calendar); | ||||
| // - LaunchContacts
 | ||||
| addStandard("LaunchMail", KeyTable.XF86XK_Mail); | ||||
| addStandard("LaunchMediaPlayer", KeyTable.XF86XK_AudioMedia); | ||||
| addStandard("LaunchMusicPlayer", KeyTable.XF86XK_Music); | ||||
| @ -256,7 +260,7 @@ addStandard("LaunchWebBrowser", KeyTable.XF86XK_WWW); | ||||
| addStandard("LaunchWebCam", KeyTable.XF86XK_WebCam); | ||||
| addStandard("LaunchWordProcessor", KeyTable.XF86XK_Word); | ||||
| 
 | ||||
| // 2.15. Browser Keys
 | ||||
| // 3.15. Browser Keys
 | ||||
| 
 | ||||
| addStandard("BrowserBack", KeyTable.XF86XK_Back); | ||||
| addStandard("BrowserFavorites", KeyTable.XF86XK_Favorites); | ||||
| @ -266,15 +270,15 @@ addStandard("BrowserRefresh", KeyTable.XF86XK_Refresh); | ||||
| addStandard("BrowserSearch", KeyTable.XF86XK_Search); | ||||
| addStandard("BrowserStop", KeyTable.XF86XK_Stop); | ||||
| 
 | ||||
| // 2.16. Mobile Phone Keys
 | ||||
| // 3.16. Mobile Phone Keys
 | ||||
| 
 | ||||
| // - A whole bunch...
 | ||||
| 
 | ||||
| // 2.17. TV Keys
 | ||||
| // 3.17. TV Keys
 | ||||
| 
 | ||||
| // - A whole bunch...
 | ||||
| 
 | ||||
| // 2.18. Media Controller Keys
 | ||||
| // 3.18. Media Controller Keys
 | ||||
| 
 | ||||
| // - A whole bunch...
 | ||||
| addStandard("Dimmer", KeyTable.XF86XK_BrightnessAdjust); | ||||
|  | ||||
| @ -20,16 +20,13 @@ export default class Keyboard { | ||||
| 
 | ||||
|         this._keyDownList = {};         // List of depressed keys
 | ||||
|                                         // (even if they are happy)
 | ||||
|         this._pendingKey = null;        // Key waiting for keypress
 | ||||
|         this._altGrArmed = false;       // Windows AltGr detection
 | ||||
| 
 | ||||
|         // keep these here so we can refer to them later
 | ||||
|         this._eventHandlers = { | ||||
|             'keyup': this._handleKeyUp.bind(this), | ||||
|             'keydown': this._handleKeyDown.bind(this), | ||||
|             'keypress': this._handleKeyPress.bind(this), | ||||
|             'blur': this._allKeysUp.bind(this), | ||||
|             'checkalt': this._checkAlt.bind(this), | ||||
|         }; | ||||
| 
 | ||||
|         // ===== EVENT HANDLERS =====
 | ||||
| @ -62,9 +59,7 @@ export default class Keyboard { | ||||
|         } | ||||
| 
 | ||||
|         // Unstable, but we don't have anything else to go on
 | ||||
|         // (don't use it for 'keypress' events thought since
 | ||||
|         // WebKit sets it to the same as charCode)
 | ||||
|         if (e.keyCode && (e.type !== 'keypress')) { | ||||
|         if (e.keyCode) { | ||||
|             // 229 is used for composition events
 | ||||
|             if (e.keyCode !== 229) { | ||||
|                 return 'Platform' + e.keyCode; | ||||
| @ -158,6 +153,16 @@ export default class Keyboard { | ||||
|             keysym = this._keyDownList[code]; | ||||
|         } | ||||
| 
 | ||||
|         // macOS doesn't send proper key releases if a key is pressed
 | ||||
|         // while meta is held down
 | ||||
|         if ((browser.isMac() || browser.isIOS()) && | ||||
|             (e.metaKey && code !== 'MetaLeft' && code !== 'MetaRight')) { | ||||
|             this._sendKeyEvent(keysym, code, true); | ||||
|             this._sendKeyEvent(keysym, code, false); | ||||
|             stopEvent(e); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // macOS doesn't send proper key events for modifiers, only
 | ||||
|         // state change events. That gets extra confusing for CapsLock
 | ||||
|         // which toggles on each press, but not on release. So pretend
 | ||||
| @ -169,20 +174,20 @@ export default class Keyboard { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // If this is a legacy browser then we'll need to wait for
 | ||||
|         // a keypress event as well
 | ||||
|         // (IE and Edge has a broken KeyboardEvent.key, so we can't
 | ||||
|         // just check for the presence of that field)
 | ||||
|         if (!keysym && (!e.key || browser.isIE() || browser.isEdge())) { | ||||
|             this._pendingKey = code; | ||||
|             // However we might not get a keypress event if the key
 | ||||
|             // is non-printable, which needs some special fallback
 | ||||
|             // handling
 | ||||
|             setTimeout(this._handleKeyPressTimeout.bind(this), 10, e); | ||||
|         // Windows doesn't send proper key releases for a bunch of
 | ||||
|         // Japanese IM keys so we have to fake the release right away
 | ||||
|         const jpBadKeys = [ KeyTable.XK_Zenkaku_Hankaku, | ||||
|                             KeyTable.XK_Eisu_toggle, | ||||
|                             KeyTable.XK_Katakana, | ||||
|                             KeyTable.XK_Hiragana, | ||||
|                             KeyTable.XK_Romaji ]; | ||||
|         if (browser.isWindows() && jpBadKeys.includes(keysym)) { | ||||
|             this._sendKeyEvent(keysym, code, true); | ||||
|             this._sendKeyEvent(keysym, code, false); | ||||
|             stopEvent(e); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this._pendingKey = null; | ||||
|         stopEvent(e); | ||||
| 
 | ||||
|         // Possible start of AltGr sequence? (see above)
 | ||||
| @ -197,69 +202,6 @@ export default class Keyboard { | ||||
|         this._sendKeyEvent(keysym, code, true); | ||||
|     } | ||||
| 
 | ||||
|     // Legacy event for browsers without code/key
 | ||||
|     _handleKeyPress(e) { | ||||
|         stopEvent(e); | ||||
| 
 | ||||
|         // Are we expecting a keypress?
 | ||||
|         if (this._pendingKey === null) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         let code = this._getKeyCode(e); | ||||
|         const keysym = KeyboardUtil.getKeysym(e); | ||||
| 
 | ||||
|         // The key we were waiting for?
 | ||||
|         if ((code !== 'Unidentified') && (code != this._pendingKey)) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         code = this._pendingKey; | ||||
|         this._pendingKey = null; | ||||
| 
 | ||||
|         if (!keysym) { | ||||
|             Log.Info('keypress with no keysym:', e); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this._sendKeyEvent(keysym, code, true); | ||||
|     } | ||||
| 
 | ||||
|     _handleKeyPressTimeout(e) { | ||||
|         // Did someone manage to sort out the key already?
 | ||||
|         if (this._pendingKey === null) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         let keysym; | ||||
| 
 | ||||
|         const code = this._pendingKey; | ||||
|         this._pendingKey = null; | ||||
| 
 | ||||
|         // We have no way of knowing the proper keysym with the
 | ||||
|         // information given, but the following are true for most
 | ||||
|         // layouts
 | ||||
|         if ((e.keyCode >= 0x30) && (e.keyCode <= 0x39)) { | ||||
|             // Digit
 | ||||
|             keysym = e.keyCode; | ||||
|         } else if ((e.keyCode >= 0x41) && (e.keyCode <= 0x5a)) { | ||||
|             // Character (A-Z)
 | ||||
|             let char = String.fromCharCode(e.keyCode); | ||||
|             // A feeble attempt at the correct case
 | ||||
|             if (e.shiftKey) { | ||||
|                 char = char.toUpperCase(); | ||||
|             } else { | ||||
|                 char = char.toLowerCase(); | ||||
|             } | ||||
|             keysym = char.charCodeAt(); | ||||
|         } else { | ||||
|             // Unknown, give up
 | ||||
|             keysym = 0; | ||||
|         } | ||||
| 
 | ||||
|         this._sendKeyEvent(keysym, code, true); | ||||
|     } | ||||
| 
 | ||||
|     _handleKeyUp(e) { | ||||
|         stopEvent(e); | ||||
| 
 | ||||
| @ -312,30 +254,6 @@ export default class Keyboard { | ||||
|         Log.Debug("<< Keyboard.allKeysUp"); | ||||
|     } | ||||
| 
 | ||||
|     // Alt workaround for Firefox on Windows, see below
 | ||||
|     _checkAlt(e) { | ||||
|         if (e.skipCheckAlt) { | ||||
|             return; | ||||
|         } | ||||
|         if (e.altKey) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const target = this._target; | ||||
|         const downList = this._keyDownList; | ||||
|         ['AltLeft', 'AltRight'].forEach((code) => { | ||||
|             if (!(code in downList)) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             const event = new KeyboardEvent('keyup', | ||||
|                                             { key: downList[code], | ||||
|                                               code: code }); | ||||
|             event.skipCheckAlt = true; | ||||
|             target.dispatchEvent(event); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     // ===== PUBLIC METHODS =====
 | ||||
| 
 | ||||
|     grab() { | ||||
| @ -343,41 +261,18 @@ export default class Keyboard { | ||||
| 
 | ||||
|         this._target.addEventListener('keydown', this._eventHandlers.keydown); | ||||
|         this._target.addEventListener('keyup', this._eventHandlers.keyup); | ||||
|         this._target.addEventListener('keypress', this._eventHandlers.keypress); | ||||
| 
 | ||||
|         // Release (key up) if window loses focus
 | ||||
|         window.addEventListener('blur', this._eventHandlers.blur); | ||||
| 
 | ||||
|         // Firefox on Windows has broken handling of Alt, so we need to
 | ||||
|         // poll as best we can for releases (still doesn't prevent the
 | ||||
|         // menu from popping up though as we can't call
 | ||||
|         // preventDefault())
 | ||||
|         if (browser.isWindows() && browser.isFirefox()) { | ||||
|             const handler = this._eventHandlers.checkalt; | ||||
|             ['mousedown', 'mouseup', 'mousemove', 'wheel', | ||||
|              'touchstart', 'touchend', 'touchmove', | ||||
|              'keydown', 'keyup'].forEach(type => | ||||
|                 document.addEventListener(type, handler, | ||||
|                                           { capture: true, | ||||
|                                             passive: true })); | ||||
|         } | ||||
| 
 | ||||
|         //Log.Debug("<< Keyboard.grab");
 | ||||
|     } | ||||
| 
 | ||||
|     ungrab() { | ||||
|         //Log.Debug(">> Keyboard.ungrab");
 | ||||
| 
 | ||||
|         if (browser.isWindows() && browser.isFirefox()) { | ||||
|             const handler = this._eventHandlers.checkalt; | ||||
|             ['mousedown', 'mouseup', 'mousemove', 'wheel', | ||||
|              'touchstart', 'touchend', 'touchmove', | ||||
|              'keydown', 'keyup'].forEach(type => document.removeEventListener(type, handler)); | ||||
|         } | ||||
| 
 | ||||
|         this._target.removeEventListener('keydown', this._eventHandlers.keydown); | ||||
|         this._target.removeEventListener('keyup', this._eventHandlers.keyup); | ||||
|         this._target.removeEventListener('keypress', this._eventHandlers.keypress); | ||||
|         window.removeEventListener('blur', this._eventHandlers.blur); | ||||
| 
 | ||||
|         // Release (key up) all keys that are in a down state
 | ||||
|  | ||||
| @ -22,9 +22,8 @@ export function getKeycode(evt) { | ||||
|     } | ||||
| 
 | ||||
|     // The de-facto standard is to use Windows Virtual-Key codes
 | ||||
|     // in the 'keyCode' field for non-printable characters. However
 | ||||
|     // Webkit sets it to the same as charCode in 'keypress' events.
 | ||||
|     if ((evt.type !== 'keypress') && (evt.keyCode in vkeys)) { | ||||
|     // in the 'keyCode' field for non-printable characters
 | ||||
|     if (evt.keyCode in vkeys) { | ||||
|         let code = vkeys[evt.keyCode]; | ||||
| 
 | ||||
|         // macOS has messed up this code for some reason
 | ||||
| @ -69,26 +68,6 @@ export function getKeycode(evt) { | ||||
| export function getKey(evt) { | ||||
|     // Are we getting a proper key value?
 | ||||
|     if (evt.key !== undefined) { | ||||
|         // IE and Edge use some ancient version of the spec
 | ||||
|         // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/
 | ||||
|         switch (evt.key) { | ||||
|             case 'Spacebar': return ' '; | ||||
|             case 'Esc': return 'Escape'; | ||||
|             case 'Scroll': return 'ScrollLock'; | ||||
|             case 'Win': return 'Meta'; | ||||
|             case 'Apps': return 'ContextMenu'; | ||||
|             case 'Up': return 'ArrowUp'; | ||||
|             case 'Left': return 'ArrowLeft'; | ||||
|             case 'Right': return 'ArrowRight'; | ||||
|             case 'Down': return 'ArrowDown'; | ||||
|             case 'Del': return 'Delete'; | ||||
|             case 'Divide': return '/'; | ||||
|             case 'Multiply': return '*'; | ||||
|             case 'Subtract': return '-'; | ||||
|             case 'Add': return '+'; | ||||
|             case 'Decimal': return evt.char; | ||||
|         } | ||||
| 
 | ||||
|         // Mozilla isn't fully in sync with the spec yet
 | ||||
|         switch (evt.key) { | ||||
|             case 'OS': return 'Meta'; | ||||
| @ -110,20 +89,9 @@ export function getKey(evt) { | ||||
|             return 'Delete'; | ||||
|         } | ||||
| 
 | ||||
|         // IE and Edge need special handling, but for everyone else we
 | ||||
|         // can trust the value provided
 | ||||
|         if (!browser.isIE() && !browser.isEdge()) { | ||||
|         return evt.key; | ||||
|     } | ||||
| 
 | ||||
|         // IE and Edge have broken handling of AltGraph so we can only
 | ||||
|         // trust them for non-printable characters (and unfortunately
 | ||||
|         // they also specify 'Unidentified' for some problem keys)
 | ||||
|         if ((evt.key.length !== 1) && (evt.key !== 'Unidentified')) { | ||||
|             return evt.key; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Try to deduce it based on the physical key
 | ||||
|     const code = getKeycode(evt); | ||||
|     if (code in fixedkeys) { | ||||
| @ -189,6 +157,21 @@ export function getKeysym(evt) { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Windows sends alternating symbols for some keys when using a
 | ||||
|         // Japanese layout. We have no way of synchronising with the IM
 | ||||
|         // running on the remote system, so we send some combined keysym
 | ||||
|         // instead and hope for the best.
 | ||||
|         if (browser.isWindows()) { | ||||
|             switch (key) { | ||||
|                 case 'Zenkaku': | ||||
|                 case 'Hankaku': | ||||
|                     return KeyTable.XK_Zenkaku_Hankaku; | ||||
|                 case 'Romaji': | ||||
|                 case 'KanaMode': | ||||
|                     return KeyTable.XK_Romaji; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return DOMKeyTable[key][location]; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -13,7 +13,6 @@ export default { | ||||
|     0x08: 'Backspace', | ||||
|     0x09: 'Tab', | ||||
|     0x0a: 'NumpadClear', | ||||
|     0x0c: 'Numpad5', // IE11 sends evt.keyCode: 12 when numlock is off
 | ||||
|     0x0d: 'Enter', | ||||
|     0x10: 'ShiftLeft', | ||||
|     0x11: 'ControlLeft', | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| /* | ||||
|  * This file is auto-generated from keymaps.csv on 2017-05-31 16:20 | ||||
|  * Database checksum sha256(92fd165507f2a3b8c5b3fa56e425d45788dbcb98cf067a307527d91ce22cab94) | ||||
|  * This file is auto-generated from keymaps.csv | ||||
|  * Database checksum sha256(76d68c10e97d37fe2ea459e210125ae41796253fb217e900bf2983ade13a7920) | ||||
|  * To re-generate, run: | ||||
|  *   keymap-gen --lang=js code-map keymaps.csv html atset1 | ||||
|  *   keymap-gen code-map --lang=js keymaps.csv html atset1 | ||||
| */ | ||||
| export default { | ||||
|   "Again": 0xe005, /* html:Again (Again) -> linux:129 (KEY_AGAIN) -> atset1:57349 */ | ||||
| @ -111,6 +111,8 @@ export default { | ||||
|   "KeyX": 0x2d, /* html:KeyX (KeyX) -> linux:45 (KEY_X) -> atset1:45 */ | ||||
|   "KeyY": 0x15, /* html:KeyY (KeyY) -> linux:21 (KEY_Y) -> atset1:21 */ | ||||
|   "KeyZ": 0x2c, /* html:KeyZ (KeyZ) -> linux:44 (KEY_Z) -> atset1:44 */ | ||||
|   "Lang1": 0x72, /* html:Lang1 (Lang1) -> linux:122 (KEY_HANGEUL) -> atset1:114 */ | ||||
|   "Lang2": 0x71, /* html:Lang2 (Lang2) -> linux:123 (KEY_HANJA) -> atset1:113 */ | ||||
|   "Lang3": 0x78, /* html:Lang3 (Lang3) -> linux:90 (KEY_KATAKANA) -> atset1:120 */ | ||||
|   "Lang4": 0x77, /* html:Lang4 (Lang4) -> linux:91 (KEY_HIRAGANA) -> atset1:119 */ | ||||
|   "Lang5": 0x76, /* html:Lang5 (Lang5) -> linux:85 (KEY_ZENKAKUHANKAKU) -> atset1:118 */ | ||||
|  | ||||
							
								
								
									
										567
									
								
								systemvm/agent/noVNC/core/ra2.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										567
									
								
								systemvm/agent/noVNC/core/ra2.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,567 @@ | ||||
| import Base64 from './base64.js'; | ||||
| import { encodeUTF8 } from './util/strings.js'; | ||||
| import EventTargetMixin from './util/eventtarget.js'; | ||||
| 
 | ||||
| export class AESEAXCipher { | ||||
|     constructor() { | ||||
|         this._rawKey = null; | ||||
|         this._ctrKey = null; | ||||
|         this._cbcKey = null; | ||||
|         this._zeroBlock = new Uint8Array(16); | ||||
|         this._prefixBlock0 = this._zeroBlock; | ||||
|         this._prefixBlock1 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); | ||||
|         this._prefixBlock2 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]); | ||||
|     } | ||||
| 
 | ||||
|     async _encryptBlock(block) { | ||||
|         const encrypted = await window.crypto.subtle.encrypt({ | ||||
|             name: "AES-CBC", | ||||
|             iv: this._zeroBlock, | ||||
|         }, this._cbcKey, block); | ||||
|         return new Uint8Array(encrypted).slice(0, 16); | ||||
|     } | ||||
| 
 | ||||
|     async _initCMAC() { | ||||
|         const k1 = await this._encryptBlock(this._zeroBlock); | ||||
|         const k2 = new Uint8Array(16); | ||||
|         const v = k1[0] >>> 6; | ||||
|         for (let i = 0; i < 15; i++) { | ||||
|             k2[i] = (k1[i + 1] >> 6) | (k1[i] << 2); | ||||
|             k1[i] = (k1[i + 1] >> 7) | (k1[i] << 1); | ||||
|         } | ||||
|         const lut = [0x0, 0x87, 0x0e, 0x89]; | ||||
|         k2[14] ^= v >>> 1; | ||||
|         k2[15] = (k1[15] << 2) ^ lut[v]; | ||||
|         k1[15] = (k1[15] << 1) ^ lut[v >> 1]; | ||||
|         this._k1 = k1; | ||||
|         this._k2 = k2; | ||||
|     } | ||||
| 
 | ||||
|     async _encryptCTR(data, counter) { | ||||
|         const encrypted = await window.crypto.subtle.encrypt({ | ||||
|             "name": "AES-CTR", | ||||
|             counter: counter, | ||||
|             length: 128 | ||||
|         }, this._ctrKey, data); | ||||
|         return new Uint8Array(encrypted); | ||||
|     } | ||||
| 
 | ||||
|     async _decryptCTR(data, counter) { | ||||
|         const decrypted = await window.crypto.subtle.decrypt({ | ||||
|             "name": "AES-CTR", | ||||
|             counter: counter, | ||||
|             length: 128 | ||||
|         }, this._ctrKey, data); | ||||
|         return new Uint8Array(decrypted); | ||||
|     } | ||||
| 
 | ||||
|     async _computeCMAC(data, prefixBlock) { | ||||
|         if (prefixBlock.length !== 16) { | ||||
|             return null; | ||||
|         } | ||||
|         const n = Math.floor(data.length / 16); | ||||
|         const m = Math.ceil(data.length / 16); | ||||
|         const r = data.length - n * 16; | ||||
|         const cbcData = new Uint8Array((m + 1) * 16); | ||||
|         cbcData.set(prefixBlock); | ||||
|         cbcData.set(data, 16); | ||||
|         if (r === 0) { | ||||
|             for (let i = 0; i < 16; i++) { | ||||
|                 cbcData[n * 16 + i] ^= this._k1[i]; | ||||
|             } | ||||
|         } else { | ||||
|             cbcData[(n + 1) * 16 + r] = 0x80; | ||||
|             for (let i = 0; i < 16; i++) { | ||||
|                 cbcData[(n + 1) * 16 + i] ^= this._k2[i]; | ||||
|             } | ||||
|         } | ||||
|         let cbcEncrypted = await window.crypto.subtle.encrypt({ | ||||
|             name: "AES-CBC", | ||||
|             iv: this._zeroBlock, | ||||
|         }, this._cbcKey, cbcData); | ||||
| 
 | ||||
|         cbcEncrypted = new Uint8Array(cbcEncrypted); | ||||
|         const mac = cbcEncrypted.slice(cbcEncrypted.length - 32, cbcEncrypted.length - 16); | ||||
|         return mac; | ||||
|     } | ||||
| 
 | ||||
|     async setKey(key) { | ||||
|         this._rawKey = key; | ||||
|         this._ctrKey = await window.crypto.subtle.importKey( | ||||
|             "raw", key, {"name": "AES-CTR"}, false, ["encrypt", "decrypt"]); | ||||
|         this._cbcKey = await window.crypto.subtle.importKey( | ||||
|             "raw", key, {"name": "AES-CBC"}, false, ["encrypt", "decrypt"]); | ||||
|         await this._initCMAC(); | ||||
|     } | ||||
| 
 | ||||
|     async encrypt(message, associatedData, nonce) { | ||||
|         const nCMAC = await this._computeCMAC(nonce, this._prefixBlock0); | ||||
|         const encrypted = await this._encryptCTR(message, nCMAC); | ||||
|         const adCMAC = await this._computeCMAC(associatedData, this._prefixBlock1); | ||||
|         const mac = await this._computeCMAC(encrypted, this._prefixBlock2); | ||||
|         for (let i = 0; i < 16; i++) { | ||||
|             mac[i] ^= nCMAC[i] ^ adCMAC[i]; | ||||
|         } | ||||
|         const res = new Uint8Array(16 + encrypted.length); | ||||
|         res.set(encrypted); | ||||
|         res.set(mac, encrypted.length); | ||||
|         return res; | ||||
|     } | ||||
| 
 | ||||
|     async decrypt(encrypted, associatedData, nonce, mac) { | ||||
|         const nCMAC = await this._computeCMAC(nonce, this._prefixBlock0); | ||||
|         const adCMAC = await this._computeCMAC(associatedData, this._prefixBlock1); | ||||
|         const computedMac = await this._computeCMAC(encrypted, this._prefixBlock2); | ||||
|         for (let i = 0; i < 16; i++) { | ||||
|             computedMac[i] ^= nCMAC[i] ^ adCMAC[i]; | ||||
|         } | ||||
|         if (computedMac.length !== mac.length) { | ||||
|             return null; | ||||
|         } | ||||
|         for (let i = 0; i < mac.length; i++) { | ||||
|             if (computedMac[i] !== mac[i]) { | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|         const res = await this._decryptCTR(encrypted, nCMAC); | ||||
|         return res; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export class RA2Cipher { | ||||
|     constructor() { | ||||
|         this._cipher = new AESEAXCipher(); | ||||
|         this._counter = new Uint8Array(16); | ||||
|     } | ||||
| 
 | ||||
|     async setKey(key) { | ||||
|         await this._cipher.setKey(key); | ||||
|     } | ||||
| 
 | ||||
|     async makeMessage(message) { | ||||
|         const ad = new Uint8Array([(message.length & 0xff00) >>> 8, message.length & 0xff]); | ||||
|         const encrypted = await this._cipher.encrypt(message, ad, this._counter); | ||||
|         for (let i = 0; i < 16 && this._counter[i]++ === 255; i++); | ||||
|         const res = new Uint8Array(message.length + 2 + 16); | ||||
|         res.set(ad); | ||||
|         res.set(encrypted, 2); | ||||
|         return res; | ||||
|     } | ||||
| 
 | ||||
|     async receiveMessage(length, encrypted, mac) { | ||||
|         const ad = new Uint8Array([(length & 0xff00) >>> 8, length & 0xff]); | ||||
|         const res = await this._cipher.decrypt(encrypted, ad, this._counter, mac); | ||||
|         for (let i = 0; i < 16 && this._counter[i]++ === 255; i++); | ||||
|         return res; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export class RSACipher { | ||||
|     constructor(keyLength) { | ||||
|         this._key = null; | ||||
|         this._keyLength = keyLength; | ||||
|         this._keyBytes = Math.ceil(keyLength / 8); | ||||
|         this._n = null; | ||||
|         this._e = null; | ||||
|         this._d = null; | ||||
|         this._nBigInt = null; | ||||
|         this._eBigInt = null; | ||||
|         this._dBigInt = null; | ||||
|     } | ||||
| 
 | ||||
|     _base64urlDecode(data) { | ||||
|         data = data.replace(/-/g, "+").replace(/_/g, "/"); | ||||
|         data = data.padEnd(Math.ceil(data.length / 4) * 4, "="); | ||||
|         return Base64.decode(data); | ||||
|     } | ||||
| 
 | ||||
|     _u8ArrayToBigInt(arr) { | ||||
|         let hex = '0x'; | ||||
|         for (let i = 0; i < arr.length; i++) { | ||||
|             hex += arr[i].toString(16).padStart(2, '0'); | ||||
|         } | ||||
|         return BigInt(hex); | ||||
|     } | ||||
| 
 | ||||
|     _padArray(arr, length) { | ||||
|         const res = new Uint8Array(length); | ||||
|         res.set(arr, length - arr.length); | ||||
|         return res; | ||||
|     } | ||||
| 
 | ||||
|     _bigIntToU8Array(bigint, padLength=0) { | ||||
|         let hex = bigint.toString(16); | ||||
|         if (padLength === 0) { | ||||
|             padLength = Math.ceil(hex.length / 2) * 2; | ||||
|         } | ||||
|         hex = hex.padStart(padLength * 2, '0'); | ||||
|         const length = hex.length / 2; | ||||
|         const arr = new Uint8Array(length); | ||||
|         for (let i = 0; i < length; i++) { | ||||
|             arr[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16); | ||||
|         } | ||||
|         return arr; | ||||
|     } | ||||
| 
 | ||||
|     _modPow(b, e, m) { | ||||
|         if (m === 1n) { | ||||
|             return 0; | ||||
|         } | ||||
|         let r = 1n; | ||||
|         b = b % m; | ||||
|         while (e > 0) { | ||||
|             if (e % 2n === 1n) { | ||||
|                 r = (r * b) % m; | ||||
|             } | ||||
|             e = e / 2n; | ||||
|             b = (b * b) % m; | ||||
|         } | ||||
|         return r; | ||||
|     } | ||||
| 
 | ||||
|     async generateKey() { | ||||
|         this._key = await window.crypto.subtle.generateKey( | ||||
|             { | ||||
|                 name: "RSA-OAEP", | ||||
|                 modulusLength: this._keyLength, | ||||
|                 publicExponent: new Uint8Array([0x01, 0x00, 0x01]), | ||||
|                 hash: {name: "SHA-256"}, | ||||
|             }, | ||||
|             true, ["encrypt", "decrypt"]); | ||||
|         const privateKey = await window.crypto.subtle.exportKey("jwk", this._key.privateKey); | ||||
|         this._n = this._padArray(this._base64urlDecode(privateKey.n), this._keyBytes); | ||||
|         this._nBigInt = this._u8ArrayToBigInt(this._n); | ||||
|         this._e = this._padArray(this._base64urlDecode(privateKey.e), this._keyBytes); | ||||
|         this._eBigInt = this._u8ArrayToBigInt(this._e); | ||||
|         this._d = this._padArray(this._base64urlDecode(privateKey.d), this._keyBytes); | ||||
|         this._dBigInt = this._u8ArrayToBigInt(this._d); | ||||
|     } | ||||
| 
 | ||||
|     setPublicKey(n, e) { | ||||
|         if (n.length !== this._keyBytes || e.length !== this._keyBytes) { | ||||
|             return; | ||||
|         } | ||||
|         this._n = new Uint8Array(this._keyBytes); | ||||
|         this._e = new Uint8Array(this._keyBytes); | ||||
|         this._n.set(n); | ||||
|         this._e.set(e); | ||||
|         this._nBigInt = this._u8ArrayToBigInt(this._n); | ||||
|         this._eBigInt = this._u8ArrayToBigInt(this._e); | ||||
|     } | ||||
| 
 | ||||
|     encrypt(message) { | ||||
|         if (message.length > this._keyBytes - 11) { | ||||
|             return null; | ||||
|         } | ||||
|         const ps = new Uint8Array(this._keyBytes - message.length - 3); | ||||
|         window.crypto.getRandomValues(ps); | ||||
|         for (let i = 0; i < ps.length; i++) { | ||||
|             ps[i] = Math.floor(ps[i] * 254 / 255 + 1); | ||||
|         } | ||||
|         const em = new Uint8Array(this._keyBytes); | ||||
|         em[1] = 0x02; | ||||
|         em.set(ps, 2); | ||||
|         em.set(message, ps.length + 3); | ||||
|         const emBigInt = this._u8ArrayToBigInt(em); | ||||
|         const c = this._modPow(emBigInt, this._eBigInt, this._nBigInt); | ||||
|         return this._bigIntToU8Array(c, this._keyBytes); | ||||
|     } | ||||
| 
 | ||||
|     decrypt(message) { | ||||
|         if (message.length !== this._keyBytes) { | ||||
|             return null; | ||||
|         } | ||||
|         const msgBigInt = this._u8ArrayToBigInt(message); | ||||
|         const emBigInt = this._modPow(msgBigInt, this._dBigInt, this._nBigInt); | ||||
|         const em = this._bigIntToU8Array(emBigInt, this._keyBytes); | ||||
|         if (em[0] !== 0x00 || em[1] !== 0x02) { | ||||
|             return null; | ||||
|         } | ||||
|         let i = 2; | ||||
|         for (; i < em.length; i++) { | ||||
|             if (em[i] === 0x00) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         if (i === em.length) { | ||||
|             return null; | ||||
|         } | ||||
|         return em.slice(i + 1, em.length); | ||||
|     } | ||||
| 
 | ||||
|     get keyLength() { | ||||
|         return this._keyLength; | ||||
|     } | ||||
| 
 | ||||
|     get n() { | ||||
|         return this._n; | ||||
|     } | ||||
| 
 | ||||
|     get e() { | ||||
|         return this._e; | ||||
|     } | ||||
| 
 | ||||
|     get d() { | ||||
|         return this._d; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export default class RSAAESAuthenticationState extends EventTargetMixin { | ||||
|     constructor(sock, getCredentials) { | ||||
|         super(); | ||||
|         this._hasStarted = false; | ||||
|         this._checkSock = null; | ||||
|         this._checkCredentials = null; | ||||
|         this._approveServerResolve = null; | ||||
|         this._sockReject = null; | ||||
|         this._credentialsReject = null; | ||||
|         this._approveServerReject = null; | ||||
|         this._sock = sock; | ||||
|         this._getCredentials = getCredentials; | ||||
|     } | ||||
| 
 | ||||
|     _waitSockAsync(len) { | ||||
|         return new Promise((resolve, reject) => { | ||||
|             const hasData = () => !this._sock.rQwait('RA2', len); | ||||
|             if (hasData()) { | ||||
|                 resolve(); | ||||
|             } else { | ||||
|                 this._checkSock = () => { | ||||
|                     if (hasData()) { | ||||
|                         resolve(); | ||||
|                         this._checkSock = null; | ||||
|                         this._sockReject = null; | ||||
|                     } | ||||
|                 }; | ||||
|                 this._sockReject = reject; | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     _waitApproveKeyAsync() { | ||||
|         return new Promise((resolve, reject) => { | ||||
|             this._approveServerResolve = resolve; | ||||
|             this._approveServerReject = reject; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     _waitCredentialsAsync(subtype) { | ||||
|         const hasCredentials = () => { | ||||
|             if (subtype === 1 && this._getCredentials().username !== undefined && | ||||
|                 this._getCredentials().password !== undefined) { | ||||
|                 return true; | ||||
|             } else if (subtype === 2 && this._getCredentials().password !== undefined) { | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|         }; | ||||
|         return new Promise((resolve, reject) => { | ||||
|             if (hasCredentials()) { | ||||
|                 resolve(); | ||||
|             } else { | ||||
|                 this._checkCredentials = () => { | ||||
|                     if (hasCredentials()) { | ||||
|                         resolve(); | ||||
|                         this._checkCredentials = null; | ||||
|                         this._credentialsReject = null; | ||||
|                     } | ||||
|                 }; | ||||
|                 this._credentialsReject = reject; | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     checkInternalEvents() { | ||||
|         if (this._checkSock !== null) { | ||||
|             this._checkSock(); | ||||
|         } | ||||
|         if (this._checkCredentials !== null) { | ||||
|             this._checkCredentials(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     approveServer() { | ||||
|         if (this._approveServerResolve !== null) { | ||||
|             this._approveServerResolve(); | ||||
|             this._approveServerResolve = null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     disconnect() { | ||||
|         if (this._sockReject !== null) { | ||||
|             this._sockReject(new Error("disconnect normally")); | ||||
|             this._sockReject = null; | ||||
|         } | ||||
|         if (this._credentialsReject !== null) { | ||||
|             this._credentialsReject(new Error("disconnect normally")); | ||||
|             this._credentialsReject = null; | ||||
|         } | ||||
|         if (this._approveServerReject !== null) { | ||||
|             this._approveServerReject(new Error("disconnect normally")); | ||||
|             this._approveServerReject = null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     async negotiateRA2neAuthAsync() { | ||||
|         this._hasStarted = true; | ||||
|         // 1: Receive server public key
 | ||||
|         await this._waitSockAsync(4); | ||||
|         const serverKeyLengthBuffer = this._sock.rQslice(0, 4); | ||||
|         const serverKeyLength = this._sock.rQshift32(); | ||||
|         if (serverKeyLength < 1024) { | ||||
|             throw new Error("RA2: server public key is too short: " + serverKeyLength); | ||||
|         } else if (serverKeyLength > 8192) { | ||||
|             throw new Error("RA2: server public key is too long: " + serverKeyLength); | ||||
|         } | ||||
|         const serverKeyBytes = Math.ceil(serverKeyLength / 8); | ||||
|         await this._waitSockAsync(serverKeyBytes * 2); | ||||
|         const serverN = this._sock.rQshiftBytes(serverKeyBytes); | ||||
|         const serverE = this._sock.rQshiftBytes(serverKeyBytes); | ||||
|         const serverRSACipher = new RSACipher(serverKeyLength); | ||||
|         serverRSACipher.setPublicKey(serverN, serverE); | ||||
|         const serverPublickey = new Uint8Array(4 + serverKeyBytes * 2); | ||||
|         serverPublickey.set(serverKeyLengthBuffer); | ||||
|         serverPublickey.set(serverN, 4); | ||||
|         serverPublickey.set(serverE, 4 + serverKeyBytes); | ||||
| 
 | ||||
|         // verify server public key
 | ||||
|         this.dispatchEvent(new CustomEvent("serververification", { | ||||
|             detail: { type: "RSA", publickey: serverPublickey } | ||||
|         })); | ||||
|         await this._waitApproveKeyAsync(); | ||||
| 
 | ||||
|         // 2: Send client public key
 | ||||
|         const clientKeyLength = 2048; | ||||
|         const clientKeyBytes = Math.ceil(clientKeyLength / 8); | ||||
|         const clientRSACipher = new RSACipher(clientKeyLength); | ||||
|         await clientRSACipher.generateKey(); | ||||
|         const clientN = clientRSACipher.n; | ||||
|         const clientE = clientRSACipher.e; | ||||
|         const clientPublicKey = new Uint8Array(4 + clientKeyBytes * 2); | ||||
|         clientPublicKey[0] = (clientKeyLength & 0xff000000) >>> 24; | ||||
|         clientPublicKey[1] = (clientKeyLength & 0xff0000) >>> 16; | ||||
|         clientPublicKey[2] = (clientKeyLength & 0xff00) >>> 8; | ||||
|         clientPublicKey[3] = clientKeyLength & 0xff; | ||||
|         clientPublicKey.set(clientN, 4); | ||||
|         clientPublicKey.set(clientE, 4 + clientKeyBytes); | ||||
|         this._sock.send(clientPublicKey); | ||||
| 
 | ||||
|         // 3: Send client random
 | ||||
|         const clientRandom = new Uint8Array(16); | ||||
|         window.crypto.getRandomValues(clientRandom); | ||||
|         const clientEncryptedRandom = serverRSACipher.encrypt(clientRandom); | ||||
|         const clientRandomMessage = new Uint8Array(2 + serverKeyBytes); | ||||
|         clientRandomMessage[0] = (serverKeyBytes & 0xff00) >>> 8; | ||||
|         clientRandomMessage[1] = serverKeyBytes & 0xff; | ||||
|         clientRandomMessage.set(clientEncryptedRandom, 2); | ||||
|         this._sock.send(clientRandomMessage); | ||||
| 
 | ||||
|         // 4: Receive server random
 | ||||
|         await this._waitSockAsync(2); | ||||
|         if (this._sock.rQshift16() !== clientKeyBytes) { | ||||
|             throw new Error("RA2: wrong encrypted message length"); | ||||
|         } | ||||
|         const serverEncryptedRandom = this._sock.rQshiftBytes(clientKeyBytes); | ||||
|         const serverRandom = clientRSACipher.decrypt(serverEncryptedRandom); | ||||
|         if (serverRandom === null || serverRandom.length !== 16) { | ||||
|             throw new Error("RA2: corrupted server encrypted random"); | ||||
|         } | ||||
| 
 | ||||
|         // 5: Compute session keys and set ciphers
 | ||||
|         let clientSessionKey = new Uint8Array(32); | ||||
|         let serverSessionKey = new Uint8Array(32); | ||||
|         clientSessionKey.set(serverRandom); | ||||
|         clientSessionKey.set(clientRandom, 16); | ||||
|         serverSessionKey.set(clientRandom); | ||||
|         serverSessionKey.set(serverRandom, 16); | ||||
|         clientSessionKey = await window.crypto.subtle.digest("SHA-1", clientSessionKey); | ||||
|         clientSessionKey = new Uint8Array(clientSessionKey).slice(0, 16); | ||||
|         serverSessionKey = await window.crypto.subtle.digest("SHA-1", serverSessionKey); | ||||
|         serverSessionKey = new Uint8Array(serverSessionKey).slice(0, 16); | ||||
|         const clientCipher = new RA2Cipher(); | ||||
|         await clientCipher.setKey(clientSessionKey); | ||||
|         const serverCipher = new RA2Cipher(); | ||||
|         await serverCipher.setKey(serverSessionKey); | ||||
| 
 | ||||
|         // 6: Compute and exchange hashes
 | ||||
|         let serverHash = new Uint8Array(8 + serverKeyBytes * 2 + clientKeyBytes * 2); | ||||
|         let clientHash = new Uint8Array(8 + serverKeyBytes * 2 + clientKeyBytes * 2); | ||||
|         serverHash.set(serverPublickey); | ||||
|         serverHash.set(clientPublicKey, 4 + serverKeyBytes * 2); | ||||
|         clientHash.set(clientPublicKey); | ||||
|         clientHash.set(serverPublickey, 4 + clientKeyBytes * 2); | ||||
|         serverHash = await window.crypto.subtle.digest("SHA-1", serverHash); | ||||
|         clientHash = await window.crypto.subtle.digest("SHA-1", clientHash); | ||||
|         serverHash = new Uint8Array(serverHash); | ||||
|         clientHash = new Uint8Array(clientHash); | ||||
|         this._sock.send(await clientCipher.makeMessage(clientHash)); | ||||
|         await this._waitSockAsync(2 + 20 + 16); | ||||
|         if (this._sock.rQshift16() !== 20) { | ||||
|             throw new Error("RA2: wrong server hash"); | ||||
|         } | ||||
|         const serverHashReceived = await serverCipher.receiveMessage( | ||||
|             20, this._sock.rQshiftBytes(20), this._sock.rQshiftBytes(16)); | ||||
|         if (serverHashReceived === null) { | ||||
|             throw new Error("RA2: failed to authenticate the message"); | ||||
|         } | ||||
|         for (let i = 0; i < 20; i++) { | ||||
|             if (serverHashReceived[i] !== serverHash[i]) { | ||||
|                 throw new Error("RA2: wrong server hash"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 7: Receive subtype
 | ||||
|         await this._waitSockAsync(2 + 1 + 16); | ||||
|         if (this._sock.rQshift16() !== 1) { | ||||
|             throw new Error("RA2: wrong subtype"); | ||||
|         } | ||||
|         let subtype = (await serverCipher.receiveMessage( | ||||
|             1, this._sock.rQshiftBytes(1), this._sock.rQshiftBytes(16))); | ||||
|         if (subtype === null) { | ||||
|             throw new Error("RA2: failed to authenticate the message"); | ||||
|         } | ||||
|         subtype = subtype[0]; | ||||
|         if (subtype === 1) { | ||||
|             if (this._getCredentials().username === undefined || | ||||
|                 this._getCredentials().password === undefined) { | ||||
|                 this.dispatchEvent(new CustomEvent( | ||||
|                     "credentialsrequired", | ||||
|                     { detail: { types: ["username", "password"] } })); | ||||
|             } | ||||
|         } else if (subtype === 2) { | ||||
|             if (this._getCredentials().password === undefined) { | ||||
|                 this.dispatchEvent(new CustomEvent( | ||||
|                     "credentialsrequired", | ||||
|                     { detail: { types: ["password"] } })); | ||||
|             } | ||||
|         } else { | ||||
|             throw new Error("RA2: wrong subtype"); | ||||
|         } | ||||
|         await this._waitCredentialsAsync(subtype); | ||||
|         let username; | ||||
|         if (subtype === 1) { | ||||
|             username = encodeUTF8(this._getCredentials().username).slice(0, 255); | ||||
|         } else { | ||||
|             username = ""; | ||||
|         } | ||||
|         const password = encodeUTF8(this._getCredentials().password).slice(0, 255); | ||||
|         const credentials = new Uint8Array(username.length + password.length + 2); | ||||
|         credentials[0] = username.length; | ||||
|         credentials[username.length + 1] = password.length; | ||||
|         for (let i = 0; i < username.length; i++) { | ||||
|             credentials[i + 1] = username.charCodeAt(i); | ||||
|         } | ||||
|         for (let i = 0; i < password.length; i++) { | ||||
|             credentials[username.length + 2 + i] = password.charCodeAt(i); | ||||
|         } | ||||
|         this._sock.send(await clientCipher.makeMessage(credentials)); | ||||
|     } | ||||
| 
 | ||||
|     get hasStarted() { | ||||
|         return this._hasStarted; | ||||
|     } | ||||
| 
 | ||||
|     set hasStarted(s) { | ||||
|         this._hasStarted = s; | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -45,15 +45,6 @@ try { | ||||
| 
 | ||||
| export const supportsCursorURIs = _supportsCursorURIs; | ||||
| 
 | ||||
| let _supportsImageMetadata = false; | ||||
| try { | ||||
|     new ImageData(new Uint8ClampedArray(4), 1, 1); | ||||
|     _supportsImageMetadata = true; | ||||
| } catch (ex) { | ||||
|     // ignore failure
 | ||||
| } | ||||
| export const supportsImageMetadata = _supportsImageMetadata; | ||||
| 
 | ||||
| let _hasScrollbarGutter = true; | ||||
| try { | ||||
|     // Create invisible container
 | ||||
| @ -86,35 +77,76 @@ export const hasScrollbarGutter = _hasScrollbarGutter; | ||||
|  * It's better to use feature detection than platform detection. | ||||
|  */ | ||||
| 
 | ||||
| /* OS */ | ||||
| 
 | ||||
| export function isMac() { | ||||
|     return navigator && !!(/mac/i).exec(navigator.platform); | ||||
|     return !!(/mac/i).exec(navigator.platform); | ||||
| } | ||||
| 
 | ||||
| export function isWindows() { | ||||
|     return navigator && !!(/win/i).exec(navigator.platform); | ||||
|     return !!(/win/i).exec(navigator.platform); | ||||
| } | ||||
| 
 | ||||
| export function isIOS() { | ||||
|     return navigator && | ||||
|            (!!(/ipad/i).exec(navigator.platform) || | ||||
|     return (!!(/ipad/i).exec(navigator.platform) || | ||||
|             !!(/iphone/i).exec(navigator.platform) || | ||||
|             !!(/ipod/i).exec(navigator.platform)); | ||||
| } | ||||
| 
 | ||||
| export function isAndroid() { | ||||
|     /* Android sets navigator.platform to Linux :/ */ | ||||
|     return !!navigator.userAgent.match('Android '); | ||||
| } | ||||
| 
 | ||||
| export function isChromeOS() { | ||||
|     /* ChromeOS sets navigator.platform to Linux :/ */ | ||||
|     return !!navigator.userAgent.match(' CrOS '); | ||||
| } | ||||
| 
 | ||||
| /* Browser */ | ||||
| 
 | ||||
| export function isSafari() { | ||||
|     return navigator && (navigator.userAgent.indexOf('Safari') !== -1 && | ||||
|                          navigator.userAgent.indexOf('Chrome') === -1); | ||||
| } | ||||
| 
 | ||||
| export function isIE() { | ||||
|     return navigator && !!(/trident/i).exec(navigator.userAgent); | ||||
| } | ||||
| 
 | ||||
| export function isEdge() { | ||||
|     return navigator && !!(/edge/i).exec(navigator.userAgent); | ||||
|     return !!navigator.userAgent.match('Safari/...') && | ||||
|            !navigator.userAgent.match('Chrome/...') && | ||||
|            !navigator.userAgent.match('Chromium/...') && | ||||
|            !navigator.userAgent.match('Epiphany/...'); | ||||
| } | ||||
| 
 | ||||
| export function isFirefox() { | ||||
|     return navigator && !!(/firefox/i).exec(navigator.userAgent); | ||||
|     return !!navigator.userAgent.match('Firefox/...') && | ||||
|            !navigator.userAgent.match('Seamonkey/...'); | ||||
| } | ||||
| 
 | ||||
| export function isChrome() { | ||||
|     return !!navigator.userAgent.match('Chrome/...') && | ||||
|            !navigator.userAgent.match('Chromium/...') && | ||||
|            !navigator.userAgent.match('Edg/...') && | ||||
|            !navigator.userAgent.match('OPR/...'); | ||||
| } | ||||
| 
 | ||||
| export function isChromium() { | ||||
|     return !!navigator.userAgent.match('Chromium/...'); | ||||
| } | ||||
| 
 | ||||
| export function isOpera() { | ||||
|     return !!navigator.userAgent.match('OPR/...'); | ||||
| } | ||||
| 
 | ||||
| export function isEdge() { | ||||
|     return !!navigator.userAgent.match('Edg/...'); | ||||
| } | ||||
| 
 | ||||
| /* Engine */ | ||||
| 
 | ||||
| export function isGecko() { | ||||
|     return !!navigator.userAgent.match('Gecko/...'); | ||||
| } | ||||
| 
 | ||||
| export function isWebKit() { | ||||
|     return !!navigator.userAgent.match('AppleWebKit/...') && | ||||
|            !navigator.userAgent.match('Chrome/...'); | ||||
| } | ||||
| 
 | ||||
| export function isBlink() { | ||||
|     return !!navigator.userAgent.match('Chrome/...'); | ||||
| } | ||||
|  | ||||
| @ -18,6 +18,10 @@ export default class Cursor { | ||||
|             this._canvas.style.position = 'fixed'; | ||||
|             this._canvas.style.zIndex = '65535'; | ||||
|             this._canvas.style.pointerEvents = 'none'; | ||||
|             // Safari on iOS can select the cursor image
 | ||||
|             // https://bugs.webkit.org/show_bug.cgi?id=249223
 | ||||
|             this._canvas.style.userSelect = 'none'; | ||||
|             this._canvas.style.WebkitUserSelect = 'none'; | ||||
|             // Can't use "display" because of Firefox bug #1445997
 | ||||
|             this._canvas.style.visibility = 'hidden'; | ||||
|         } | ||||
| @ -43,9 +47,6 @@ export default class Cursor { | ||||
|         if (useFallback) { | ||||
|             document.body.appendChild(this._canvas); | ||||
| 
 | ||||
|             // FIXME: These don't fire properly except for mouse
 | ||||
|             ///       movement in IE. We want to also capture element
 | ||||
|             //        movement, size changes, visibility, etc.
 | ||||
|             const options = { capture: true, passive: true }; | ||||
|             this._target.addEventListener('mouseover', this._eventHandlers.mouseover, options); | ||||
|             this._target.addEventListener('mouseleave', this._eventHandlers.mouseleave, options); | ||||
| @ -90,14 +91,7 @@ export default class Cursor { | ||||
|         this._canvas.width = w; | ||||
|         this._canvas.height = h; | ||||
| 
 | ||||
|         let img; | ||||
|         try { | ||||
|             // IE doesn't support this
 | ||||
|             img = new ImageData(new Uint8ClampedArray(rgba), w, h); | ||||
|         } catch (ex) { | ||||
|             img = ctx.createImageData(w, h); | ||||
|             img.data.set(new Uint8ClampedArray(rgba)); | ||||
|         } | ||||
|         let img = new ImageData(new Uint8ClampedArray(rgba), w, h); | ||||
|         ctx.clearRect(0, 0, w, h); | ||||
|         ctx.putImageData(img, 0, 0); | ||||
| 
 | ||||
|  | ||||
| @ -65,10 +65,6 @@ export function setCapture(target) { | ||||
| 
 | ||||
|         target.setCapture(); | ||||
|         document.captureElement = target; | ||||
| 
 | ||||
|         // IE releases capture on 'click' events which might not trigger
 | ||||
|         target.addEventListener('mouseup', releaseCapture); | ||||
| 
 | ||||
|     } else { | ||||
|         // Release any existing capture in case this method is
 | ||||
|         // called multiple times without coordination
 | ||||
|  | ||||
							
								
								
									
										79
									
								
								systemvm/agent/noVNC/core/util/md5.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								systemvm/agent/noVNC/core/util/md5.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | ||||
| /* | ||||
|  * noVNC: HTML5 VNC client | ||||
|  * Copyright (C) 2021 The noVNC Authors | ||||
|  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||
|  * | ||||
|  * See README.md for usage and integration instructions. | ||||
|  */ | ||||
| 
 | ||||
| /* | ||||
|  * Performs MD5 hashing on a string of binary characters, returns an array of bytes | ||||
|  */ | ||||
| 
 | ||||
| export function MD5(d) { | ||||
|     let r = M(V(Y(X(d), 8 * d.length))); | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| function M(d) { | ||||
|     let f = new Uint8Array(d.length); | ||||
|     for (let i=0;i<d.length;i++) { | ||||
|         f[i] = d.charCodeAt(i); | ||||
|     } | ||||
|     return f; | ||||
| } | ||||
| 
 | ||||
| function X(d) { | ||||
|     let r = Array(d.length >> 2); | ||||
|     for (let m = 0; m < r.length; m++) r[m] = 0; | ||||
|     for (let m = 0; m < 8 * d.length; m += 8) r[m >> 5] |= (255 & d.charCodeAt(m / 8)) << m % 32; | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| function V(d) { | ||||
|     let r = ""; | ||||
|     for (let m = 0; m < 32 * d.length; m += 8) r += String.fromCharCode(d[m >> 5] >>> m % 32 & 255); | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| function Y(d, g) { | ||||
|     d[g >> 5] |= 128 << g % 32, d[14 + (g + 64 >>> 9 << 4)] = g; | ||||
|     let m = 1732584193, f = -271733879, r = -1732584194, i = 271733878; | ||||
|     for (let n = 0; n < d.length; n += 16) { | ||||
|         let h = m, | ||||
|             t = f, | ||||
|             g = r, | ||||
|             e = i; | ||||
|         f = ii(f = ii(f = ii(f = ii(f = hh(f = hh(f = hh(f = hh(f = gg(f = gg(f = gg(f = gg(f = ff(f = ff(f = ff(f = ff(f, r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 0], 7, -680876936), f, r, d[n + 1], 12, -389564586), m, f, d[n + 2], 17, 606105819), i, m, d[n + 3], 22, -1044525330), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 4], 7, -176418897), f, r, d[n + 5], 12, 1200080426), m, f, d[n + 6], 17, -1473231341), i, m, d[n + 7], 22, -45705983), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 8], 7, 1770035416), f, r, d[n + 9], 12, -1958414417), m, f, d[n + 10], 17, -42063), i, m, d[n + 11], 22, -1990404162), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 12], 7, 1804603682), f, r, d[n + 13], 12, -40341101), m, f, d[n + 14], 17, -1502002290), i, m, d[n + 15], 22, 1236535329), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 1], 5, -165796510), f, r, d[n + 6], 9, -1069501632), m, f, d[n + 11], 14, 643717713), i, m, d[n + 0], 20, -373897302), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 5], 5, -701558691), f, r, d[n + 10], 9, 38016083), m, f, d[n + 15], 14, -660478335), i, m, d[n + 4], 20, -405537848), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 9], 5, 568446438), f, r, d[n + 14], 9, -1019803690), m, f, d[n + 3], 14, -187363961), i, m, d[n + 8], 20, 1163531501), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 13], 5, -1444681467), f, r, d[n + 2], 9, -51403784), m, f, d[n + 7], 14, 1735328473), i, m, d[n + 12], 20, -1926607734), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 5], 4, -378558), f, r, d[n + 8], 11, -2022574463), m, f, d[n + 11], 16, 1839030562), i, m, d[n + 14], 23, -35309556), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 1], 4, -1530992060), f, r, d[n + 4], 11, 1272893353), m, f, d[n + 7], 16, -155497632), i, m, d[n + 10], 23, -1094730640), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 13], 4, 681279174), f, r, d[n + 0], 11, -358537222), m, f, d[n + 3], 16, -722521979), i, m, d[n + 6], 23, 76029189), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 9], 4, -640364487), f, r, d[n + 12], 11, -421815835), m, f, d[n + 15], 16, 530742520), i, m, d[n + 2], 23, -995338651), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 0], 6, -198630844), f, r, d[n + 7], 10, 1126891415), m, f, d[n + 14], 15, -1416354905), i, m, d[n + 5], 21, -57434055), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 12], 6, 1700485571), f, r, d[n + 3], 10, -1894986606), m, f, d[n + 10], 15, -1051523), i, m, d[n + 1], 21, -2054922799), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 8], 6, 1873313359), f, r, d[n + 15], 10, -30611744), m, f, d[n + 6], 15, -1560198380), i, m, d[n + 13], 21, 1309151649), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 4], 6, -145523070), f, r, d[n + 11], 10, -1120210379), m, f, d[n + 2], 15, 718787259), i, m, d[n + 9], 21, -343485551), m = add(m, h), f = add(f, t), r = add(r, g), i = add(i, e); | ||||
|     } | ||||
|     return Array(m, f, r, i); | ||||
| } | ||||
| 
 | ||||
| function cmn(d, g, m, f, r, i) { | ||||
|     return add(rol(add(add(g, d), add(f, i)), r), m); | ||||
| } | ||||
| 
 | ||||
| function ff(d, g, m, f, r, i, n) { | ||||
|     return cmn(g & m | ~g & f, d, g, r, i, n); | ||||
| } | ||||
| 
 | ||||
| function gg(d, g, m, f, r, i, n) { | ||||
|     return cmn(g & f | m & ~f, d, g, r, i, n); | ||||
| } | ||||
| 
 | ||||
| function hh(d, g, m, f, r, i, n) { | ||||
|     return cmn(g ^ m ^ f, d, g, r, i, n); | ||||
| } | ||||
| 
 | ||||
| function ii(d, g, m, f, r, i, n) { | ||||
|     return cmn(m ^ (g | ~f), d, g, r, i, n); | ||||
| } | ||||
| 
 | ||||
| function add(d, g) { | ||||
|     let m = (65535 & d) + (65535 & g); | ||||
|     return (d >> 16) + (g >> 16) + (m >> 16) << 16 | 65535 & m; | ||||
| } | ||||
| 
 | ||||
| function rol(d, g) { | ||||
|     return d << g | d >>> 32 - g; | ||||
| } | ||||
| @ -1,61 +0,0 @@ | ||||
| /* | ||||
|  * noVNC: HTML5 VNC client | ||||
|  * Copyright (C) 2020 The noVNC Authors | ||||
|  * Licensed under MPL 2.0 or any later version (see LICENSE.txt) | ||||
|  */ | ||||
| 
 | ||||
| /* Polyfills to provide new APIs in old browsers */ | ||||
| 
 | ||||
| /* Object.assign() (taken from MDN) */ | ||||
| if (typeof Object.assign != 'function') { | ||||
|     // Must be writable: true, enumerable: false, configurable: true
 | ||||
|     Object.defineProperty(Object, "assign", { | ||||
|         value: function assign(target, varArgs) { // .length of function is 2
 | ||||
|             'use strict'; | ||||
|             if (target == null) { // TypeError if undefined or null
 | ||||
|                 throw new TypeError('Cannot convert undefined or null to object'); | ||||
|             } | ||||
| 
 | ||||
|             const to = Object(target); | ||||
| 
 | ||||
|             for (let index = 1; index < arguments.length; index++) { | ||||
|                 const nextSource = arguments[index]; | ||||
| 
 | ||||
|                 if (nextSource != null) { // Skip over if undefined or null
 | ||||
|                     for (let nextKey in nextSource) { | ||||
|                         // Avoid bugs when hasOwnProperty is shadowed
 | ||||
|                         if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { | ||||
|                             to[nextKey] = nextSource[nextKey]; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             return to; | ||||
|         }, | ||||
|         writable: true, | ||||
|         configurable: true | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| /* CustomEvent constructor (taken from MDN) */ | ||||
| (() => { | ||||
|     function CustomEvent(event, params) { | ||||
|         params = params || { bubbles: false, cancelable: false, detail: undefined }; | ||||
|         const evt = document.createEvent( 'CustomEvent' ); | ||||
|         evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); | ||||
|         return evt; | ||||
|     } | ||||
| 
 | ||||
|     CustomEvent.prototype = window.Event.prototype; | ||||
| 
 | ||||
|     if (typeof window.CustomEvent !== "function") { | ||||
|         window.CustomEvent = CustomEvent; | ||||
|     } | ||||
| })(); | ||||
| 
 | ||||
| /* Number.isInteger() (taken from MDN) */ | ||||
| Number.isInteger = Number.isInteger || function isInteger(value) { | ||||
|     return typeof value === 'number' && | ||||
|       isFinite(value) && | ||||
|       Math.floor(value) === value; | ||||
| }; | ||||
| @ -1,10 +1,10 @@ | ||||
| /* | ||||
|  * Websock: high-performance binary WebSockets | ||||
|  * Websock: high-performance buffering wrapper | ||||
|  * Copyright (C) 2019 The noVNC Authors | ||||
|  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||
|  * | ||||
|  * Websock is similar to the standard WebSocket object but with extra | ||||
|  * buffer handling. | ||||
|  * Websock is similar to the standard WebSocket / RTCDataChannel object | ||||
|  * but with extra buffer handling. | ||||
|  * | ||||
|  * Websock has built-in receive queue buffering; the message event | ||||
|  * does not contain actual data but is simply a notification that | ||||
| @ -17,14 +17,39 @@ import * as Log from './util/logging.js'; | ||||
| // this has performance issues in some versions Chromium, and
 | ||||
| // doesn't gain a tremendous amount of performance increase in Firefox
 | ||||
| // at the moment.  It may be valuable to turn it on in the future.
 | ||||
| // Also copyWithin() for TypedArrays is not supported in IE 11 or
 | ||||
| // Safari 13 (at the moment we want to support Safari 11).
 | ||||
| const ENABLE_COPYWITHIN = false; | ||||
| const MAX_RQ_GROW_SIZE = 40 * 1024 * 1024;  // 40 MiB
 | ||||
| 
 | ||||
| // Constants pulled from RTCDataChannelState enum
 | ||||
| // https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/readyState#RTCDataChannelState_enum
 | ||||
| const DataChannel = { | ||||
|     CONNECTING: "connecting", | ||||
|     OPEN: "open", | ||||
|     CLOSING: "closing", | ||||
|     CLOSED: "closed" | ||||
| }; | ||||
| 
 | ||||
| const ReadyStates = { | ||||
|     CONNECTING: [WebSocket.CONNECTING, DataChannel.CONNECTING], | ||||
|     OPEN: [WebSocket.OPEN, DataChannel.OPEN], | ||||
|     CLOSING: [WebSocket.CLOSING, DataChannel.CLOSING], | ||||
|     CLOSED: [WebSocket.CLOSED, DataChannel.CLOSED], | ||||
| }; | ||||
| 
 | ||||
| // Properties a raw channel must have, WebSocket and RTCDataChannel are two examples
 | ||||
| const rawChannelProps = [ | ||||
|     "send", | ||||
|     "close", | ||||
|     "binaryType", | ||||
|     "onerror", | ||||
|     "onmessage", | ||||
|     "onopen", | ||||
|     "protocol", | ||||
|     "readyState", | ||||
| ]; | ||||
| 
 | ||||
| export default class Websock { | ||||
|     constructor() { | ||||
|         this._websocket = null;  // WebSocket object
 | ||||
|         this._websocket = null;  // WebSocket or RTCDataChannel object
 | ||||
| 
 | ||||
|         this._rQi = 0;           // Receive queue index
 | ||||
|         this._rQlen = 0;         // Next write position in the receive queue
 | ||||
| @ -46,6 +71,29 @@ export default class Websock { | ||||
|     } | ||||
| 
 | ||||
|     // Getters and Setters
 | ||||
| 
 | ||||
|     get readyState() { | ||||
|         let subState; | ||||
| 
 | ||||
|         if (this._websocket === null) { | ||||
|             return "unused"; | ||||
|         } | ||||
| 
 | ||||
|         subState = this._websocket.readyState; | ||||
| 
 | ||||
|         if (ReadyStates.CONNECTING.includes(subState)) { | ||||
|             return "connecting"; | ||||
|         } else if (ReadyStates.OPEN.includes(subState)) { | ||||
|             return "open"; | ||||
|         } else if (ReadyStates.CLOSING.includes(subState)) { | ||||
|             return "closing"; | ||||
|         } else if (ReadyStates.CLOSED.includes(subState)) { | ||||
|             return "closed"; | ||||
|         } | ||||
| 
 | ||||
|         return "unknown"; | ||||
|     } | ||||
| 
 | ||||
|     get sQ() { | ||||
|         return this._sQ; | ||||
|     } | ||||
| @ -143,7 +191,7 @@ export default class Websock { | ||||
|     // Send Queue
 | ||||
| 
 | ||||
|     flush() { | ||||
|         if (this._sQlen > 0 && this._websocket.readyState === WebSocket.OPEN) { | ||||
|         if (this._sQlen > 0 && this.readyState === 'open') { | ||||
|             this._websocket.send(this._encodeMessage()); | ||||
|             this._sQlen = 0; | ||||
|         } | ||||
| @ -180,12 +228,25 @@ export default class Websock { | ||||
|     } | ||||
| 
 | ||||
|     open(uri, protocols) { | ||||
|         this.attach(new WebSocket(uri, protocols)); | ||||
|     } | ||||
| 
 | ||||
|     attach(rawChannel) { | ||||
|         this.init(); | ||||
| 
 | ||||
|         this._websocket = new WebSocket(uri, protocols); | ||||
|         this._websocket.binaryType = 'arraybuffer'; | ||||
|         // Must get object and class methods to be compatible with the tests.
 | ||||
|         const channelProps = [...Object.keys(rawChannel), ...Object.getOwnPropertyNames(Object.getPrototypeOf(rawChannel))]; | ||||
|         for (let i = 0; i < rawChannelProps.length; i++) { | ||||
|             const prop = rawChannelProps[i]; | ||||
|             if (channelProps.indexOf(prop) < 0) { | ||||
|                 throw new Error('Raw channel missing property: ' + prop); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         this._websocket = rawChannel; | ||||
|         this._websocket.binaryType = "arraybuffer"; | ||||
|         this._websocket.onmessage = this._recvMessage.bind(this); | ||||
| 
 | ||||
|         this._websocket.onopen = () => { | ||||
|             Log.Debug('>> WebSock.onopen'); | ||||
|             if (this._websocket.protocol) { | ||||
| @ -195,11 +256,13 @@ export default class Websock { | ||||
|             this._eventHandlers.open(); | ||||
|             Log.Debug("<< WebSock.onopen"); | ||||
|         }; | ||||
| 
 | ||||
|         this._websocket.onclose = (e) => { | ||||
|             Log.Debug(">> WebSock.onclose"); | ||||
|             this._eventHandlers.close(e); | ||||
|             Log.Debug("<< WebSock.onclose"); | ||||
|         }; | ||||
| 
 | ||||
|         this._websocket.onerror = (e) => { | ||||
|             Log.Debug(">> WebSock.onerror: " + e); | ||||
|             this._eventHandlers.error(e); | ||||
| @ -209,8 +272,8 @@ export default class Websock { | ||||
| 
 | ||||
|     close() { | ||||
|         if (this._websocket) { | ||||
|             if ((this._websocket.readyState === WebSocket.OPEN) || | ||||
|                     (this._websocket.readyState === WebSocket.CONNECTING)) { | ||||
|             if (this.readyState === 'connecting' || | ||||
|                 this.readyState === 'open') { | ||||
|                 Log.Info("Closing WebSocket connection"); | ||||
|                 this._websocket.close(); | ||||
|             } | ||||
| @ -256,11 +319,7 @@ export default class Websock { | ||||
|             this._rQ = new Uint8Array(this._rQbufferSize); | ||||
|             this._rQ.set(new Uint8Array(oldRQbuffer, this._rQi, this._rQlen - this._rQi)); | ||||
|         } else { | ||||
|             if (ENABLE_COPYWITHIN) { | ||||
|             this._rQ.copyWithin(0, this._rQi, this._rQlen); | ||||
|             } else { | ||||
|                 this._rQ.set(new Uint8Array(this._rQ.buffer, this._rQi, this._rQlen - this._rQi)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         this._rQlen = this._rQlen - this._rQi; | ||||
|  | ||||
							
								
								
									
										37
									
								
								systemvm/agent/noVNC/docs/novnc_proxy.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								systemvm/agent/noVNC/docs/novnc_proxy.1
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| .TH novnc_proxy 1  "June 25, 2020" "version 1.2.0" "USER COMMANDS" | ||||
| 
 | ||||
| .SH NAME | ||||
| novnc_proxy - noVNC proxy server | ||||
| .SH SYNOPSIS | ||||
| .B novnc_proxy [--listen PORT] [--vnc VNC_HOST:PORT] [--cert CERT] [--ssl-only] | ||||
| 
 | ||||
| Starts the WebSockets proxy and a mini-webserver and | ||||
| provides a cut-and-paste URL to go to. | ||||
| 
 | ||||
|     --listen PORT         Port for proxy/webserver to listen on | ||||
|                           Default: 6080 | ||||
|     --vnc VNC_HOST:PORT   VNC server host:port proxy target | ||||
|                           Default: localhost:5900 | ||||
|     --cert CERT           Path to combined cert/key file, or just | ||||
|                           the cert file if used with --key | ||||
|                           Default: self.pem | ||||
|     --key KEY             Path to key file, when not combined with cert | ||||
|     --web WEB             Path to web files (e.g. vnc.html) | ||||
|                           Default: ./ | ||||
|     --ssl-only            Disable non-https connections. | ||||
| 
 | ||||
|     --record FILE         Record traffic to FILE.session.js | ||||
| 
 | ||||
|     --syslog SERVER       Can be local socket such as /dev/log, or a UDP host:port pair. | ||||
| 
 | ||||
|     --heartbeat SEC       send a ping to the client every SEC seconds | ||||
|     --timeout SEC         after SEC seconds exit when not connected | ||||
|     --idle-timeout SEC    server exits after SEC seconds if there are no | ||||
|                           active connections | ||||
| 
 | ||||
| .SH AUTHOR | ||||
| The noVNC Authors | ||||
| https://github.com/novnc/noVNC | ||||
| 
 | ||||
| .SH SEE ALSO | ||||
| websockify(1), nova-novncproxy(1) | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "@novnc/novnc", | ||||
|   "version": "1.2.0", | ||||
|   "version": "1.4.0", | ||||
|   "description": "An HTML5 VNC client", | ||||
|   "browser": "lib/rfb", | ||||
|   "directories": { | ||||
| @ -21,7 +21,7 @@ | ||||
|   "scripts": { | ||||
|     "lint": "eslint app core po/po2js po/xgettext-html tests utils", | ||||
|     "test": "karma start karma.conf.js", | ||||
|     "prepublish": "node ./utils/use_require.js --as commonjs --clean" | ||||
|     "prepublish": "node ./utils/convert.js --clean" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
| @ -29,8 +29,6 @@ | ||||
|   }, | ||||
|   "author": "Joel Martin <github@martintribe.org> (https://github.com/kanaka)", | ||||
|   "contributors": [ | ||||
|     "Solly Ross <sross@redhat.com> (https://github.com/directxman12)", | ||||
|     "Peter Åstrand <astrand@cendio.se> (https://github.com/astrand)", | ||||
|     "Samuel Mannehed <samuel@cendio.se> (https://github.com/samhed)", | ||||
|     "Pierre Ossman <ossman@cendio.se> (https://github.com/CendioOssman)" | ||||
|   ], | ||||
| @ -40,42 +38,36 @@ | ||||
|   }, | ||||
|   "homepage": "https://github.com/novnc/noVNC", | ||||
|   "devDependencies": { | ||||
|     "@babel/core": "*", | ||||
|     "@babel/plugin-syntax-dynamic-import": "*", | ||||
|     "@babel/plugin-transform-modules-amd": "*", | ||||
|     "@babel/plugin-transform-modules-commonjs": "*", | ||||
|     "@babel/plugin-transform-modules-systemjs": "*", | ||||
|     "@babel/plugin-transform-modules-umd": "*", | ||||
|     "@babel/preset-env": "*", | ||||
|     "@babel/cli": "*", | ||||
|     "babel-plugin-import-redirect": "*", | ||||
|     "browserify": "*", | ||||
|     "babelify": "*", | ||||
|     "core-js": "*", | ||||
|     "chai": "*", | ||||
|     "commander": "*", | ||||
|     "es-module-loader": "*", | ||||
|     "eslint": "*", | ||||
|     "fs-extra": "*", | ||||
|     "jsdom": "*", | ||||
|     "karma": "*", | ||||
|     "karma-mocha": "*", | ||||
|     "karma-chrome-launcher": "*", | ||||
|     "@chiragrupani/karma-chromium-edge-launcher": "*", | ||||
|     "karma-firefox-launcher": "*", | ||||
|     "karma-ie-launcher": "*", | ||||
|     "karma-mocha-reporter": "*", | ||||
|     "karma-safari-launcher": "*", | ||||
|     "karma-script-launcher": "*", | ||||
|     "karma-sinon-chai": "*", | ||||
|     "mocha": "*", | ||||
|     "node-getopt": "*", | ||||
|     "po2json": "*", | ||||
|     "requirejs": "*", | ||||
|     "rollup": "*", | ||||
|     "rollup-plugin-node-resolve": "*", | ||||
|     "sinon": "*", | ||||
|     "sinon-chai": "*" | ||||
|     "@babel/core": "latest", | ||||
|     "@babel/plugin-syntax-dynamic-import": "latest", | ||||
|     "@babel/plugin-transform-modules-commonjs": "latest", | ||||
|     "@babel/preset-env": "latest", | ||||
|     "@babel/cli": "latest", | ||||
|     "babel-plugin-import-redirect": "latest", | ||||
|     "browserify": "latest", | ||||
|     "babelify": "latest", | ||||
|     "core-js": "latest", | ||||
|     "chai": "latest", | ||||
|     "commander": "latest", | ||||
|     "es-module-loader": "latest", | ||||
|     "eslint": "latest", | ||||
|     "fs-extra": "latest", | ||||
|     "jsdom": "latest", | ||||
|     "karma": "latest", | ||||
|     "karma-mocha": "latest", | ||||
|     "karma-chrome-launcher": "latest", | ||||
|     "@chiragrupani/karma-chromium-edge-launcher": "latest", | ||||
|     "karma-firefox-launcher": "latest", | ||||
|     "karma-ie-launcher": "latest", | ||||
|     "karma-mocha-reporter": "latest", | ||||
|     "karma-safari-launcher": "latest", | ||||
|     "karma-script-launcher": "latest", | ||||
|     "karma-sinon-chai": "latest", | ||||
|     "mocha": "latest", | ||||
|     "node-getopt": "latest", | ||||
|     "po2json": "latest", | ||||
|     "sinon": "latest", | ||||
|     "sinon-chai": "latest" | ||||
|   }, | ||||
|   "dependencies": {}, | ||||
|   "keywords": [ | ||||
|  | ||||
							
								
								
									
										300
									
								
								systemvm/agent/noVNC/po/fr.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								systemvm/agent/noVNC/po/fr.po
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,300 @@ | ||||
| # French translations for noVNC package | ||||
| # Traductions françaises du paquet noVNC. | ||||
| # Copyright (C) 2021 The noVNC Authors | ||||
| # This file is distributed under the same license as the noVNC package. | ||||
| # Jose <jose.matsuda@canada.ca>, 2021. | ||||
| # Lowxorx <lowxorx@lahan.fr>, 2022. | ||||
| # | ||||
| msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: noVNC 1.2.0\n" | ||||
| "Report-Msgid-Bugs-To: novnc@googlegroups.com\n" | ||||
| "POT-Creation-Date: 2020-07-03 16:11+0200\n" | ||||
| "PO-Revision-Date: 2022-04-25 23:40+0200\n" | ||||
| "Last-Translator: Lowxorx <lowxorx@lahan.fr>\n" | ||||
| "Language-Team: French\n" | ||||
| "Language: fr\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:394 | ||||
| msgid "Connecting..." | ||||
| msgstr "En cours de connexion..." | ||||
| 
 | ||||
| #: ../app/ui.js:401 | ||||
| msgid "Disconnecting..." | ||||
| msgstr "Déconnexion en cours..." | ||||
| 
 | ||||
| #: ../app/ui.js:407 | ||||
| msgid "Reconnecting..." | ||||
| msgstr "Reconnexion en cours..." | ||||
| 
 | ||||
| #: ../app/ui.js:412 | ||||
| msgid "Internal error" | ||||
| msgstr "Erreur interne" | ||||
| 
 | ||||
| #: ../app/ui.js:1008 | ||||
| msgid "Must set host" | ||||
| msgstr "Doit définir l'hôte" | ||||
| 
 | ||||
| #: ../app/ui.js:1090 | ||||
| msgid "Connected (encrypted) to " | ||||
| msgstr "Connecté (chiffré) à " | ||||
| 
 | ||||
| #: ../app/ui.js:1092 | ||||
| msgid "Connected (unencrypted) to " | ||||
| msgstr "Connecté (non chiffré) à " | ||||
| 
 | ||||
| #: ../app/ui.js:1115 | ||||
| msgid "Something went wrong, connection is closed" | ||||
| msgstr "Quelque chose s'est mal passé, la connexion a été fermée" | ||||
| 
 | ||||
| #: ../app/ui.js:1118 | ||||
| msgid "Failed to connect to server" | ||||
| msgstr "Échec de connexion au serveur" | ||||
| 
 | ||||
| #: ../app/ui.js:1128 | ||||
| msgid "Disconnected" | ||||
| msgstr "Déconnecté" | ||||
| 
 | ||||
| #: ../app/ui.js:1143 | ||||
| msgid "New connection has been rejected with reason: " | ||||
| msgstr "Une nouvelle connexion a été rejetée avec motif : " | ||||
| 
 | ||||
| #: ../app/ui.js:1146 | ||||
| msgid "New connection has been rejected" | ||||
| msgstr "Une nouvelle connexion a été rejetée" | ||||
| 
 | ||||
| #: ../app/ui.js:1181 | ||||
| msgid "Credentials are required" | ||||
| msgstr "Les identifiants sont requis" | ||||
| 
 | ||||
| #: ../vnc.html:74 | ||||
| msgid "noVNC encountered an error:" | ||||
| msgstr "noVNC a rencontré une erreur :" | ||||
| 
 | ||||
| #: ../vnc.html:84 | ||||
| msgid "Hide/Show the control bar" | ||||
| msgstr "Masquer/Afficher la barre de contrôle" | ||||
| 
 | ||||
| #: ../vnc.html:91 | ||||
| msgid "Drag" | ||||
| msgstr "Faire glisser" | ||||
| 
 | ||||
| #: ../vnc.html:91 | ||||
| msgid "Move/Drag Viewport" | ||||
| msgstr "Déplacer/faire glisser le Viewport" | ||||
| 
 | ||||
| #: ../vnc.html:97 | ||||
| msgid "Keyboard" | ||||
| msgstr "Clavier" | ||||
| 
 | ||||
| #: ../vnc.html:97 | ||||
| msgid "Show Keyboard" | ||||
| msgstr "Afficher le clavier" | ||||
| 
 | ||||
| #: ../vnc.html:102 | ||||
| msgid "Extra keys" | ||||
| msgstr "Touches supplémentaires" | ||||
| 
 | ||||
| #: ../vnc.html:102 | ||||
| msgid "Show Extra Keys" | ||||
| msgstr "Afficher les touches supplémentaires" | ||||
| 
 | ||||
| #: ../vnc.html:107 | ||||
| msgid "Ctrl" | ||||
| msgstr "Ctrl" | ||||
| 
 | ||||
| #: ../vnc.html:107 | ||||
| msgid "Toggle Ctrl" | ||||
| msgstr "Basculer Ctrl" | ||||
| 
 | ||||
| #: ../vnc.html:110 | ||||
| msgid "Alt" | ||||
| msgstr "Alt" | ||||
| 
 | ||||
| #: ../vnc.html:110 | ||||
| msgid "Toggle Alt" | ||||
| msgstr "Basculer Alt" | ||||
| 
 | ||||
| #: ../vnc.html:113 | ||||
| msgid "Toggle Windows" | ||||
| msgstr "Basculer Windows" | ||||
| 
 | ||||
| #: ../vnc.html:113 | ||||
| msgid "Windows" | ||||
| msgstr "Windows" | ||||
| 
 | ||||
| #: ../vnc.html:116 | ||||
| msgid "Send Tab" | ||||
| msgstr "Envoyer l'onglet" | ||||
| 
 | ||||
| #: ../vnc.html:116 | ||||
| msgid "Tab" | ||||
| msgstr "l'onglet" | ||||
| 
 | ||||
| #: ../vnc.html:119 | ||||
| msgid "Esc" | ||||
| msgstr "Esc" | ||||
| 
 | ||||
| #: ../vnc.html:119 | ||||
| msgid "Send Escape" | ||||
| msgstr "Envoyer Escape" | ||||
| 
 | ||||
| #: ../vnc.html:122 | ||||
| msgid "Ctrl+Alt+Del" | ||||
| msgstr "Ctrl+Alt+Del" | ||||
| 
 | ||||
| #: ../vnc.html:122 | ||||
| msgid "Send Ctrl-Alt-Del" | ||||
| msgstr "Envoyer Ctrl-Alt-Del" | ||||
| 
 | ||||
| #: ../vnc.html:129 | ||||
| msgid "Shutdown/Reboot" | ||||
| msgstr "Arrêter/Redémarrer" | ||||
| 
 | ||||
| #: ../vnc.html:129 | ||||
| msgid "Shutdown/Reboot..." | ||||
| msgstr "Arrêter/Redémarrer..." | ||||
| 
 | ||||
| #: ../vnc.html:135 | ||||
| msgid "Power" | ||||
| msgstr "Alimentation" | ||||
| 
 | ||||
| #: ../vnc.html:137 | ||||
| msgid "Shutdown" | ||||
| msgstr "Arrêter" | ||||
| 
 | ||||
| #: ../vnc.html:138 | ||||
| msgid "Reboot" | ||||
| msgstr "Redémarrer" | ||||
| 
 | ||||
| #: ../vnc.html:139 | ||||
| msgid "Reset" | ||||
| msgstr "Réinitialiser" | ||||
| 
 | ||||
| #: ../vnc.html:144 ../vnc.html:150 | ||||
| msgid "Clipboard" | ||||
| msgstr "Presse-papiers" | ||||
| 
 | ||||
| #: ../vnc.html:154 | ||||
| msgid "Clear" | ||||
| msgstr "Effacer" | ||||
| 
 | ||||
| #: ../vnc.html:160 | ||||
| msgid "Fullscreen" | ||||
| msgstr "Plein écran" | ||||
| 
 | ||||
| #: ../vnc.html:165 ../vnc.html:172 | ||||
| msgid "Settings" | ||||
| msgstr "Paramètres" | ||||
| 
 | ||||
| #: ../vnc.html:175 | ||||
| msgid "Shared Mode" | ||||
| msgstr "Mode partagé" | ||||
| 
 | ||||
| #: ../vnc.html:178 | ||||
| msgid "View Only" | ||||
| msgstr "Afficher uniquement" | ||||
| 
 | ||||
| #: ../vnc.html:182 | ||||
| msgid "Clip to Window" | ||||
| msgstr "Clip à fenêtre" | ||||
| 
 | ||||
| #: ../vnc.html:185 | ||||
| msgid "Scaling Mode:" | ||||
| msgstr "Mode mise à l'échelle :" | ||||
| 
 | ||||
| #: ../vnc.html:187 | ||||
| msgid "None" | ||||
| msgstr "Aucun" | ||||
| 
 | ||||
| #: ../vnc.html:188 | ||||
| msgid "Local Scaling" | ||||
| msgstr "Mise à l'échelle locale" | ||||
| 
 | ||||
| #: ../vnc.html:189 | ||||
| msgid "Remote Resizing" | ||||
| msgstr "Redimensionnement à distance" | ||||
| 
 | ||||
| #: ../vnc.html:194 | ||||
| msgid "Advanced" | ||||
| msgstr "Avancé" | ||||
| 
 | ||||
| #: ../vnc.html:197 | ||||
| msgid "Quality:" | ||||
| msgstr "Qualité :" | ||||
| 
 | ||||
| #: ../vnc.html:201 | ||||
| msgid "Compression level:" | ||||
| msgstr "Niveau de compression :" | ||||
| 
 | ||||
| #: ../vnc.html:206 | ||||
| msgid "Repeater ID:" | ||||
| msgstr "ID Répéteur :" | ||||
| 
 | ||||
| #: ../vnc.html:210 | ||||
| msgid "WebSocket" | ||||
| msgstr "WebSocket" | ||||
| 
 | ||||
| #: ../vnc.html:213 | ||||
| msgid "Encrypt" | ||||
| msgstr "Chiffrer" | ||||
| 
 | ||||
| #: ../vnc.html:216 | ||||
| msgid "Host:" | ||||
| msgstr "Hôte :" | ||||
| 
 | ||||
| #: ../vnc.html:220 | ||||
| msgid "Port:" | ||||
| msgstr "Port :" | ||||
| 
 | ||||
| #: ../vnc.html:224 | ||||
| msgid "Path:" | ||||
| msgstr "Chemin :" | ||||
| 
 | ||||
| #: ../vnc.html:231 | ||||
| msgid "Automatic Reconnect" | ||||
| msgstr "Reconnecter automatiquemen" | ||||
| 
 | ||||
| #: ../vnc.html:234 | ||||
| msgid "Reconnect Delay (ms):" | ||||
| msgstr "Délai de reconnexion (ms) :" | ||||
| 
 | ||||
| #: ../vnc.html:239 | ||||
| msgid "Show Dot when No Cursor" | ||||
| msgstr "Afficher le point lorsqu'il n'y a pas de curseur" | ||||
| 
 | ||||
| #: ../vnc.html:244 | ||||
| msgid "Logging:" | ||||
| msgstr "Se connecter :" | ||||
| 
 | ||||
| #: ../vnc.html:253 | ||||
| msgid "Version:" | ||||
| msgstr "Version :" | ||||
| 
 | ||||
| #: ../vnc.html:261 | ||||
| msgid "Disconnect" | ||||
| msgstr "Déconnecter" | ||||
| 
 | ||||
| #: ../vnc.html:280 | ||||
| msgid "Connect" | ||||
| msgstr "Connecter" | ||||
| 
 | ||||
| #: ../vnc.html:290 | ||||
| msgid "Username:" | ||||
| msgstr "Nom d'utilisateur :" | ||||
| 
 | ||||
| #: ../vnc.html:294 | ||||
| msgid "Password:" | ||||
| msgstr "Mot de passe :" | ||||
| 
 | ||||
| #: ../vnc.html:298 | ||||
| msgid "Send Credentials" | ||||
| msgstr "Envoyer les identifiants" | ||||
| 
 | ||||
| #: ../vnc.html:308 | ||||
| msgid "Cancel" | ||||
| msgstr "Annuler" | ||||
							
								
								
									
										300
									
								
								systemvm/agent/noVNC/po/it.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								systemvm/agent/noVNC/po/it.po
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,300 @@ | ||||
| # Italian translations for noVNC | ||||
| # Traduzione italiana di noVNC | ||||
| # Copyright (C) 2022 The noVNC Authors | ||||
| # This file is distributed under the same license as the noVNC package. | ||||
| # Fabio Fantoni <fabio.fantoni@m2r.biz>, 2022. | ||||
| # | ||||
| msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: noVNC 1.3.0\n" | ||||
| "Report-Msgid-Bugs-To: novnc@googlegroups.com\n" | ||||
| "POT-Creation-Date: 2021-08-27 16:03+0200\n" | ||||
| "PO-Revision-Date: 2022-09-08 13:27+0200\n" | ||||
| "Last-Translator: Fabio Fantoni <fabio.fantoni@m2r.biz>\n" | ||||
| "Language-Team: Italian\n" | ||||
| "Language: it\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.1.1\n" | ||||
| 
 | ||||
| #: ../app/ui.js:400 | ||||
| msgid "Connecting..." | ||||
| msgstr "Connessione in corso..." | ||||
| 
 | ||||
| #: ../app/ui.js:407 | ||||
| msgid "Disconnecting..." | ||||
| msgstr "Disconnessione..." | ||||
| 
 | ||||
| #: ../app/ui.js:413 | ||||
| msgid "Reconnecting..." | ||||
| msgstr "Riconnessione..." | ||||
| 
 | ||||
| #: ../app/ui.js:418 | ||||
| msgid "Internal error" | ||||
| msgstr "Errore interno" | ||||
| 
 | ||||
| #: ../app/ui.js:1009 | ||||
| msgid "Must set host" | ||||
| msgstr "Devi impostare l'host" | ||||
| 
 | ||||
| #: ../app/ui.js:1091 | ||||
| msgid "Connected (encrypted) to " | ||||
| msgstr "Connesso (crittografato) a " | ||||
| 
 | ||||
| #: ../app/ui.js:1093 | ||||
| msgid "Connected (unencrypted) to " | ||||
| msgstr "Connesso (non crittografato) a" | ||||
| 
 | ||||
| #: ../app/ui.js:1116 | ||||
| msgid "Something went wrong, connection is closed" | ||||
| msgstr "Qualcosa è andato storto, la connessione è stata chiusa" | ||||
| 
 | ||||
| #: ../app/ui.js:1119 | ||||
| msgid "Failed to connect to server" | ||||
| msgstr "Impossibile connettersi al server" | ||||
| 
 | ||||
| #: ../app/ui.js:1129 | ||||
| msgid "Disconnected" | ||||
| msgstr "Disconnesso" | ||||
| 
 | ||||
| #: ../app/ui.js:1144 | ||||
| msgid "New connection has been rejected with reason: " | ||||
| msgstr "La nuova connessione è stata rifiutata con motivo: " | ||||
| 
 | ||||
| #: ../app/ui.js:1147 | ||||
| msgid "New connection has been rejected" | ||||
| msgstr "La nuova connessione è stata rifiutata" | ||||
| 
 | ||||
| #: ../app/ui.js:1182 | ||||
| msgid "Credentials are required" | ||||
| msgstr "Le credenziali sono obbligatorie" | ||||
| 
 | ||||
| #: ../vnc.html:61 | ||||
| msgid "noVNC encountered an error:" | ||||
| msgstr "noVNC ha riscontrato un errore:" | ||||
| 
 | ||||
| #: ../vnc.html:71 | ||||
| msgid "Hide/Show the control bar" | ||||
| msgstr "Nascondi/Mostra la barra di controllo" | ||||
| 
 | ||||
| #: ../vnc.html:78 | ||||
| msgid "Drag" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../vnc.html:78 | ||||
| msgid "Move/Drag Viewport" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../vnc.html:84 | ||||
| msgid "Keyboard" | ||||
| msgstr "Tastiera" | ||||
| 
 | ||||
| #: ../vnc.html:84 | ||||
| msgid "Show Keyboard" | ||||
| msgstr "Mostra tastiera" | ||||
| 
 | ||||
| #: ../vnc.html:89 | ||||
| msgid "Extra keys" | ||||
| msgstr "Tasti Aggiuntivi" | ||||
| 
 | ||||
| #: ../vnc.html:89 | ||||
| msgid "Show Extra Keys" | ||||
| msgstr "Mostra Tasti Aggiuntivi" | ||||
| 
 | ||||
| #: ../vnc.html:94 | ||||
| msgid "Ctrl" | ||||
| msgstr "Ctrl" | ||||
| 
 | ||||
| #: ../vnc.html:94 | ||||
| msgid "Toggle Ctrl" | ||||
| msgstr "Tieni premuto Ctrl" | ||||
| 
 | ||||
| #: ../vnc.html:97 | ||||
| msgid "Alt" | ||||
| msgstr "Alt" | ||||
| 
 | ||||
| #: ../vnc.html:97 | ||||
| msgid "Toggle Alt" | ||||
| msgstr "Tieni premuto Alt" | ||||
| 
 | ||||
| #: ../vnc.html:100 | ||||
| msgid "Toggle Windows" | ||||
| msgstr "Tieni premuto Windows" | ||||
| 
 | ||||
| #: ../vnc.html:100 | ||||
| msgid "Windows" | ||||
| msgstr "Windows" | ||||
| 
 | ||||
| #: ../vnc.html:103 | ||||
| msgid "Send Tab" | ||||
| msgstr "Invia Tab" | ||||
| 
 | ||||
| #: ../vnc.html:103 | ||||
| msgid "Tab" | ||||
| msgstr "Tab" | ||||
| 
 | ||||
| #: ../vnc.html:106 | ||||
| msgid "Esc" | ||||
| msgstr "Esc" | ||||
| 
 | ||||
| #: ../vnc.html:106 | ||||
| msgid "Send Escape" | ||||
| msgstr "Invia Esc" | ||||
| 
 | ||||
| #: ../vnc.html:109 | ||||
| msgid "Ctrl+Alt+Del" | ||||
| msgstr "Ctrl+Alt+Canc" | ||||
| 
 | ||||
| #: ../vnc.html:109 | ||||
| msgid "Send Ctrl-Alt-Del" | ||||
| msgstr "Invia Ctrl-Alt-Canc" | ||||
| 
 | ||||
| #: ../vnc.html:116 | ||||
| msgid "Shutdown/Reboot" | ||||
| msgstr "Spegnimento/Riavvio" | ||||
| 
 | ||||
| #: ../vnc.html:116 | ||||
| msgid "Shutdown/Reboot..." | ||||
| msgstr "Spegnimento/Riavvio..." | ||||
| 
 | ||||
| #: ../vnc.html:122 | ||||
| msgid "Power" | ||||
| msgstr "Alimentazione" | ||||
| 
 | ||||
| #: ../vnc.html:124 | ||||
| msgid "Shutdown" | ||||
| msgstr "Spegnimento" | ||||
| 
 | ||||
| #: ../vnc.html:125 | ||||
| msgid "Reboot" | ||||
| msgstr "Riavvio" | ||||
| 
 | ||||
| #: ../vnc.html:126 | ||||
| msgid "Reset" | ||||
| msgstr "Reset" | ||||
| 
 | ||||
| #: ../vnc.html:131 ../vnc.html:137 | ||||
| msgid "Clipboard" | ||||
| msgstr "Clipboard" | ||||
| 
 | ||||
| #: ../vnc.html:141 | ||||
| msgid "Clear" | ||||
| msgstr "Pulisci" | ||||
| 
 | ||||
| #: ../vnc.html:147 | ||||
| msgid "Fullscreen" | ||||
| msgstr "Schermo intero" | ||||
| 
 | ||||
| #: ../vnc.html:152 ../vnc.html:159 | ||||
| msgid "Settings" | ||||
| msgstr "Impostazioni" | ||||
| 
 | ||||
| #: ../vnc.html:162 | ||||
| msgid "Shared Mode" | ||||
| msgstr "Modalità condivisa" | ||||
| 
 | ||||
| #: ../vnc.html:165 | ||||
| msgid "View Only" | ||||
| msgstr "Sola Visualizzazione" | ||||
| 
 | ||||
| #: ../vnc.html:169 | ||||
| msgid "Clip to Window" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../vnc.html:172 | ||||
| msgid "Scaling Mode:" | ||||
| msgstr "Modalità di ridimensionamento:" | ||||
| 
 | ||||
| #: ../vnc.html:174 | ||||
| msgid "None" | ||||
| msgstr "Nessuna" | ||||
| 
 | ||||
| #: ../vnc.html:175 | ||||
| msgid "Local Scaling" | ||||
| msgstr "Ridimensionamento Locale" | ||||
| 
 | ||||
| #: ../vnc.html:176 | ||||
| msgid "Remote Resizing" | ||||
| msgstr "Ridimensionamento Remoto" | ||||
| 
 | ||||
| #: ../vnc.html:181 | ||||
| msgid "Advanced" | ||||
| msgstr "Avanzate" | ||||
| 
 | ||||
| #: ../vnc.html:184 | ||||
| msgid "Quality:" | ||||
| msgstr "Qualità:" | ||||
| 
 | ||||
| #: ../vnc.html:188 | ||||
| msgid "Compression level:" | ||||
| msgstr "Livello Compressione:" | ||||
| 
 | ||||
| #: ../vnc.html:193 | ||||
| msgid "Repeater ID:" | ||||
| msgstr "ID Ripetitore:" | ||||
| 
 | ||||
| #: ../vnc.html:197 | ||||
| msgid "WebSocket" | ||||
| msgstr "WebSocket" | ||||
| 
 | ||||
| #: ../vnc.html:200 | ||||
| msgid "Encrypt" | ||||
| msgstr "Crittografa" | ||||
| 
 | ||||
| #: ../vnc.html:203 | ||||
| msgid "Host:" | ||||
| msgstr "Host:" | ||||
| 
 | ||||
| #: ../vnc.html:207 | ||||
| msgid "Port:" | ||||
| msgstr "Porta:" | ||||
| 
 | ||||
| #: ../vnc.html:211 | ||||
| msgid "Path:" | ||||
| msgstr "Percorso:" | ||||
| 
 | ||||
| #: ../vnc.html:218 | ||||
| msgid "Automatic Reconnect" | ||||
| msgstr "Riconnessione Automatica" | ||||
| 
 | ||||
| #: ../vnc.html:221 | ||||
| msgid "Reconnect Delay (ms):" | ||||
| msgstr "Ritardo Riconnessione (ms):" | ||||
| 
 | ||||
| #: ../vnc.html:226 | ||||
| msgid "Show Dot when No Cursor" | ||||
| msgstr "Mostra Punto quando Nessun Cursore" | ||||
| 
 | ||||
| #: ../vnc.html:231 | ||||
| msgid "Logging:" | ||||
| msgstr "" | ||||
| 
 | ||||
| #: ../vnc.html:240 | ||||
| msgid "Version:" | ||||
| msgstr "Versione:" | ||||
| 
 | ||||
| #: ../vnc.html:248 | ||||
| msgid "Disconnect" | ||||
| msgstr "Disconnetti" | ||||
| 
 | ||||
| #: ../vnc.html:267 | ||||
| msgid "Connect" | ||||
| msgstr "Connetti" | ||||
| 
 | ||||
| #: ../vnc.html:277 | ||||
| msgid "Username:" | ||||
| msgstr "Utente:" | ||||
| 
 | ||||
| #: ../vnc.html:281 | ||||
| msgid "Password:" | ||||
| msgstr "Password:" | ||||
| 
 | ||||
| #: ../vnc.html:285 | ||||
| msgid "Send Credentials" | ||||
| msgstr "Invia Credenziale" | ||||
| 
 | ||||
| #: ../vnc.html:295 | ||||
| msgid "Cancel" | ||||
| msgstr "Annulla" | ||||
							
								
								
									
										299
									
								
								systemvm/agent/noVNC/po/pt_BR.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								systemvm/agent/noVNC/po/pt_BR.po
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,299 @@ | ||||
| # Portuguese translations for noVNC package. | ||||
| # Copyright (C) 2021 The noVNC Authors | ||||
| # This file is distributed under the same license as the noVNC package. | ||||
| #  <liddack@outlook.com>, 2021. | ||||
| # | ||||
| msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: noVNC 1.2.0\n" | ||||
| "Report-Msgid-Bugs-To: novnc@googlegroups.com\n" | ||||
| "POT-Creation-Date: 2021-03-15 21:55-0300\n" | ||||
| "PO-Revision-Date: 2021-03-15 22:09-0300\n" | ||||
| "Last-Translator: <liddack@outlook.com>\n" | ||||
| "Language-Team: Brazilian Portuguese\n" | ||||
| "Language: pt_BR\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 2.4.1\n" | ||||
| 
 | ||||
| #: ../app/ui.js:400 | ||||
| msgid "Connecting..." | ||||
| msgstr "Conectando..." | ||||
| 
 | ||||
| #: ../app/ui.js:407 | ||||
| msgid "Disconnecting..." | ||||
| msgstr "Desconectando..." | ||||
| 
 | ||||
| #: ../app/ui.js:413 | ||||
| msgid "Reconnecting..." | ||||
| msgstr "Reconectando..." | ||||
| 
 | ||||
| #: ../app/ui.js:418 | ||||
| msgid "Internal error" | ||||
| msgstr "Erro interno" | ||||
| 
 | ||||
| #: ../app/ui.js:1009 | ||||
| msgid "Must set host" | ||||
| msgstr "É necessário definir o host" | ||||
| 
 | ||||
| #: ../app/ui.js:1091 | ||||
| msgid "Connected (encrypted) to " | ||||
| msgstr "Conectado (com criptografia) a " | ||||
| 
 | ||||
| #: ../app/ui.js:1093 | ||||
| msgid "Connected (unencrypted) to " | ||||
| msgstr "Conectado (sem criptografia) a " | ||||
| 
 | ||||
| #: ../app/ui.js:1116 | ||||
| msgid "Something went wrong, connection is closed" | ||||
| msgstr "Algo deu errado. A conexão foi encerrada." | ||||
| 
 | ||||
| #: ../app/ui.js:1119 | ||||
| msgid "Failed to connect to server" | ||||
| msgstr "Falha ao conectar-se ao servidor" | ||||
| 
 | ||||
| #: ../app/ui.js:1129 | ||||
| msgid "Disconnected" | ||||
| msgstr "Desconectado" | ||||
| 
 | ||||
| #: ../app/ui.js:1144 | ||||
| msgid "New connection has been rejected with reason: " | ||||
| msgstr "A nova conexão foi rejeitada pelo motivo: " | ||||
| 
 | ||||
| #: ../app/ui.js:1147 | ||||
| msgid "New connection has been rejected" | ||||
| msgstr "A nova conexão foi rejeitada" | ||||
| 
 | ||||
| #: ../app/ui.js:1182 | ||||
| msgid "Credentials are required" | ||||
| msgstr "Credenciais são obrigatórias" | ||||
| 
 | ||||
| #: ../vnc.html:61 | ||||
| msgid "noVNC encountered an error:" | ||||
| msgstr "O noVNC encontrou um erro:" | ||||
| 
 | ||||
| #: ../vnc.html:71 | ||||
| msgid "Hide/Show the control bar" | ||||
| msgstr "Esconder/mostrar a barra de controles" | ||||
| 
 | ||||
| #: ../vnc.html:78 | ||||
| msgid "Drag" | ||||
| msgstr "Arrastar" | ||||
| 
 | ||||
| #: ../vnc.html:78 | ||||
| msgid "Move/Drag Viewport" | ||||
| msgstr "Mover/arrastar a janela" | ||||
| 
 | ||||
| #: ../vnc.html:84 | ||||
| msgid "Keyboard" | ||||
| msgstr "Teclado" | ||||
| 
 | ||||
| #: ../vnc.html:84 | ||||
| msgid "Show Keyboard" | ||||
| msgstr "Mostrar teclado" | ||||
| 
 | ||||
| #: ../vnc.html:89 | ||||
| msgid "Extra keys" | ||||
| msgstr "Teclas adicionais" | ||||
| 
 | ||||
| #: ../vnc.html:89 | ||||
| msgid "Show Extra Keys" | ||||
| msgstr "Mostar teclas adicionais" | ||||
| 
 | ||||
| #: ../vnc.html:94 | ||||
| msgid "Ctrl" | ||||
| msgstr "Ctrl" | ||||
| 
 | ||||
| #: ../vnc.html:94 | ||||
| msgid "Toggle Ctrl" | ||||
| msgstr "Pressionar/soltar Ctrl" | ||||
| 
 | ||||
| #: ../vnc.html:97 | ||||
| msgid "Alt" | ||||
| msgstr "Alt" | ||||
| 
 | ||||
| #: ../vnc.html:97 | ||||
| msgid "Toggle Alt" | ||||
| msgstr "Pressionar/soltar Alt" | ||||
| 
 | ||||
| #: ../vnc.html:100 | ||||
| msgid "Toggle Windows" | ||||
| msgstr "Pressionar/soltar Windows" | ||||
| 
 | ||||
| #: ../vnc.html:100 | ||||
| msgid "Windows" | ||||
| msgstr "Windows" | ||||
| 
 | ||||
| #: ../vnc.html:103 | ||||
| msgid "Send Tab" | ||||
| msgstr "Enviar Tab" | ||||
| 
 | ||||
| #: ../vnc.html:103 | ||||
| msgid "Tab" | ||||
| msgstr "Tab" | ||||
| 
 | ||||
| #: ../vnc.html:106 | ||||
| msgid "Esc" | ||||
| msgstr "Esc" | ||||
| 
 | ||||
| #: ../vnc.html:106 | ||||
| msgid "Send Escape" | ||||
| msgstr "Enviar Esc" | ||||
| 
 | ||||
| #: ../vnc.html:109 | ||||
| msgid "Ctrl+Alt+Del" | ||||
| msgstr "Ctrl+Alt+Del" | ||||
| 
 | ||||
| #: ../vnc.html:109 | ||||
| msgid "Send Ctrl-Alt-Del" | ||||
| msgstr "Enviar Ctrl-Alt-Del" | ||||
| 
 | ||||
| #: ../vnc.html:116 | ||||
| msgid "Shutdown/Reboot" | ||||
| msgstr "Desligar/reiniciar" | ||||
| 
 | ||||
| #: ../vnc.html:116 | ||||
| msgid "Shutdown/Reboot..." | ||||
| msgstr "Desligar/reiniciar..." | ||||
| 
 | ||||
| #: ../vnc.html:122 | ||||
| msgid "Power" | ||||
| msgstr "Ligar" | ||||
| 
 | ||||
| #: ../vnc.html:124 | ||||
| msgid "Shutdown" | ||||
| msgstr "Desligar" | ||||
| 
 | ||||
| #: ../vnc.html:125 | ||||
| msgid "Reboot" | ||||
| msgstr "Reiniciar" | ||||
| 
 | ||||
| #: ../vnc.html:126 | ||||
| msgid "Reset" | ||||
| msgstr "Reiniciar (forçado)" | ||||
| 
 | ||||
| #: ../vnc.html:131 ../vnc.html:137 | ||||
| msgid "Clipboard" | ||||
| msgstr "Área de transferência" | ||||
| 
 | ||||
| #: ../vnc.html:141 | ||||
| msgid "Clear" | ||||
| msgstr "Limpar" | ||||
| 
 | ||||
| #: ../vnc.html:147 | ||||
| msgid "Fullscreen" | ||||
| msgstr "Tela cheia" | ||||
| 
 | ||||
| #: ../vnc.html:152 ../vnc.html:159 | ||||
| msgid "Settings" | ||||
| msgstr "Configurações" | ||||
| 
 | ||||
| #: ../vnc.html:162 | ||||
| msgid "Shared Mode" | ||||
| msgstr "Modo compartilhado" | ||||
| 
 | ||||
| #: ../vnc.html:165 | ||||
| msgid "View Only" | ||||
| msgstr "Apenas visualizar" | ||||
| 
 | ||||
| #: ../vnc.html:169 | ||||
| msgid "Clip to Window" | ||||
| msgstr "Recortar à janela" | ||||
| 
 | ||||
| #: ../vnc.html:172 | ||||
| msgid "Scaling Mode:" | ||||
| msgstr "Modo de dimensionamento:" | ||||
| 
 | ||||
| #: ../vnc.html:174 | ||||
| msgid "None" | ||||
| msgstr "Nenhum" | ||||
| 
 | ||||
| #: ../vnc.html:175 | ||||
| msgid "Local Scaling" | ||||
| msgstr "Local" | ||||
| 
 | ||||
| #: ../vnc.html:176 | ||||
| msgid "Remote Resizing" | ||||
| msgstr "Remoto" | ||||
| 
 | ||||
| #: ../vnc.html:181 | ||||
| msgid "Advanced" | ||||
| msgstr "Avançado" | ||||
| 
 | ||||
| #: ../vnc.html:184 | ||||
| msgid "Quality:" | ||||
| msgstr "Qualidade:" | ||||
| 
 | ||||
| #: ../vnc.html:188 | ||||
| msgid "Compression level:" | ||||
| msgstr "Nível de compressão:" | ||||
| 
 | ||||
| #: ../vnc.html:193 | ||||
| msgid "Repeater ID:" | ||||
| msgstr "ID do repetidor:" | ||||
| 
 | ||||
| #: ../vnc.html:197 | ||||
| msgid "WebSocket" | ||||
| msgstr "WebSocket" | ||||
| 
 | ||||
| #: ../vnc.html:200 | ||||
| msgid "Encrypt" | ||||
| msgstr "Criptografar" | ||||
| 
 | ||||
| #: ../vnc.html:203 | ||||
| msgid "Host:" | ||||
| msgstr "Host:" | ||||
| 
 | ||||
| #: ../vnc.html:207 | ||||
| msgid "Port:" | ||||
| msgstr "Porta:" | ||||
| 
 | ||||
| #: ../vnc.html:211 | ||||
| msgid "Path:" | ||||
| msgstr "Caminho:" | ||||
| 
 | ||||
| #: ../vnc.html:218 | ||||
| msgid "Automatic Reconnect" | ||||
| msgstr "Reconexão automática" | ||||
| 
 | ||||
| #: ../vnc.html:221 | ||||
| msgid "Reconnect Delay (ms):" | ||||
| msgstr "Atraso da reconexão (ms)" | ||||
| 
 | ||||
| #: ../vnc.html:226 | ||||
| msgid "Show Dot when No Cursor" | ||||
| msgstr "Mostrar ponto quando não há cursor" | ||||
| 
 | ||||
| #: ../vnc.html:231 | ||||
| msgid "Logging:" | ||||
| msgstr "Registros:" | ||||
| 
 | ||||
| #: ../vnc.html:240 | ||||
| msgid "Version:" | ||||
| msgstr "Versão:" | ||||
| 
 | ||||
| #: ../vnc.html:248 | ||||
| msgid "Disconnect" | ||||
| msgstr "Desconectar" | ||||
| 
 | ||||
| #: ../vnc.html:267 | ||||
| msgid "Connect" | ||||
| msgstr "Conectar" | ||||
| 
 | ||||
| #: ../vnc.html:277 | ||||
| msgid "Username:" | ||||
| msgstr "Nome de usuário:" | ||||
| 
 | ||||
| #: ../vnc.html:281 | ||||
| msgid "Password:" | ||||
| msgstr "Senha:" | ||||
| 
 | ||||
| #: ../vnc.html:285 | ||||
| msgid "Send Credentials" | ||||
| msgstr "Enviar credenciais" | ||||
| 
 | ||||
| #: ../vnc.html:295 | ||||
| msgid "Cancel" | ||||
| msgstr "Cancelar" | ||||
							
								
								
									
										140
									
								
								systemvm/agent/noVNC/utils/convert.js
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										140
									
								
								systemvm/agent/noVNC/utils/convert.js
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,140 @@ | ||||
| #!/usr/bin/env node
 | ||||
| 
 | ||||
| const path = require('path'); | ||||
| const program = require('commander'); | ||||
| const fs = require('fs'); | ||||
| const fse = require('fs-extra'); | ||||
| const babel = require('@babel/core'); | ||||
| 
 | ||||
| program | ||||
|     .option('-m, --with-source-maps [type]', 'output source maps when not generating a bundled app (type may be empty for external source maps, inline for inline source maps, or both) ') | ||||
|     .option('--clean', 'clear the lib folder before building') | ||||
|     .parse(process.argv); | ||||
| 
 | ||||
| // the various important paths
 | ||||
| const paths = { | ||||
|     main: path.resolve(__dirname, '..'), | ||||
|     core: path.resolve(__dirname, '..', 'core'), | ||||
|     vendor: path.resolve(__dirname, '..', 'vendor'), | ||||
|     libDirBase: path.resolve(__dirname, '..', 'lib'), | ||||
| }; | ||||
| 
 | ||||
| // util.promisify requires Node.js 8.x, so we have our own
 | ||||
| function promisify(original) { | ||||
|     return function promiseWrap() { | ||||
|         const args = Array.prototype.slice.call(arguments); | ||||
|         return new Promise((resolve, reject) => { | ||||
|             original.apply(this, args.concat((err, value) => { | ||||
|                 if (err) return reject(err); | ||||
|                 resolve(value); | ||||
|             })); | ||||
|         }); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| const writeFile = promisify(fs.writeFile); | ||||
| 
 | ||||
| const readdir = promisify(fs.readdir); | ||||
| const lstat = promisify(fs.lstat); | ||||
| 
 | ||||
| const ensureDir = promisify(fse.ensureDir); | ||||
| 
 | ||||
| const babelTransformFile = promisify(babel.transformFile); | ||||
| 
 | ||||
| // walkDir *recursively* walks directories trees,
 | ||||
| // calling the callback for all normal files found.
 | ||||
| function walkDir(basePath, cb, filter) { | ||||
|     return readdir(basePath) | ||||
|         .then((files) => { | ||||
|             const paths = files.map(filename => path.join(basePath, filename)); | ||||
|             return Promise.all(paths.map(filepath => lstat(filepath) | ||||
|                 .then((stats) => { | ||||
|                     if (filter !== undefined && !filter(filepath, stats)) return; | ||||
| 
 | ||||
|                     if (stats.isSymbolicLink()) return; | ||||
|                     if (stats.isFile()) return cb(filepath); | ||||
|                     if (stats.isDirectory()) return walkDir(filepath, cb, filter); | ||||
|                 }))); | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| function makeLibFiles(sourceMaps) { | ||||
|     // NB: we need to make a copy of babelOpts, since babel sets some defaults on it
 | ||||
|     const babelOpts = () => ({ | ||||
|         plugins: [], | ||||
|         presets: [ | ||||
|             [ '@babel/preset-env', | ||||
|               { modules: 'commonjs' } ] | ||||
|         ], | ||||
|         ast: false, | ||||
|         sourceMaps: sourceMaps, | ||||
|     }); | ||||
| 
 | ||||
|     fse.ensureDirSync(paths.libDirBase); | ||||
| 
 | ||||
|     const outFiles = []; | ||||
| 
 | ||||
|     const handleDir = (vendorRewrite, inPathBase, filename) => Promise.resolve() | ||||
|         .then(() => { | ||||
|             const outPath = path.join(paths.libDirBase, path.relative(inPathBase, filename)); | ||||
| 
 | ||||
|             if (path.extname(filename) !== '.js') { | ||||
|                 return;  // skip non-javascript files
 | ||||
|             } | ||||
|             return Promise.resolve() | ||||
|                 .then(() => ensureDir(path.dirname(outPath))) | ||||
|                 .then(() => { | ||||
|                     const opts = babelOpts(); | ||||
|             // Adjust for the fact that we move the core files relative
 | ||||
|             // to the vendor directory
 | ||||
|                     if (vendorRewrite) { | ||||
|                         opts.plugins.push(["import-redirect", | ||||
|                                            {"root": paths.libDirBase, | ||||
|                                             "redirect": { "vendor/(.+)": "./vendor/$1"}}]); | ||||
|                     } | ||||
| 
 | ||||
|                     return babelTransformFile(filename, opts) | ||||
|                         .then((res) => { | ||||
|                             console.log(`Writing ${outPath}`); | ||||
|                             const {map} = res; | ||||
|                             let {code} = res; | ||||
|                             if (sourceMaps === true) { | ||||
|                     // append URL for external source map
 | ||||
|                                 code += `\n//# sourceMappingURL=${path.basename(outPath)}.map\n`; | ||||
|                             } | ||||
|                             outFiles.push(`${outPath}`); | ||||
|                             return writeFile(outPath, code) | ||||
|                                 .then(() => { | ||||
|                                     if (sourceMaps === true || sourceMaps === 'both') { | ||||
|                                         console.log(`  and ${outPath}.map`); | ||||
|                                         outFiles.push(`${outPath}.map`); | ||||
|                                         return writeFile(`${outPath}.map`, JSON.stringify(map)); | ||||
|                                     } | ||||
|                                 }); | ||||
|                         }); | ||||
|                 }); | ||||
|         }); | ||||
| 
 | ||||
|     Promise.resolve() | ||||
|         .then(() => { | ||||
|             const handler = handleDir.bind(null, false, paths.main); | ||||
|             return walkDir(paths.vendor, handler); | ||||
|         }) | ||||
|         .then(() => { | ||||
|             const handler = handleDir.bind(null, true, paths.core); | ||||
|             return walkDir(paths.core, handler); | ||||
|         }) | ||||
|         .catch((err) => { | ||||
|             console.error(`Failure converting modules: ${err}`); | ||||
|             process.exit(1); | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| let options = program.opts(); | ||||
| 
 | ||||
| if (options.clean) { | ||||
|     console.log(`Removing ${paths.libDirBase}`); | ||||
|     fse.removeSync(paths.libDirBase); | ||||
| } | ||||
| 
 | ||||
| makeLibFiles(options.withSourceMaps); | ||||
| @ -1,15 +0,0 @@ | ||||
| Custom Browser ES Module Loader | ||||
| =============================== | ||||
| 
 | ||||
| This is a module loader using babel and the ES Module Loader polyfill. | ||||
| It's based heavily on | ||||
| https://github.com/ModuleLoader/browser-es-module-loader, but uses | ||||
| WebWorkers to compile the modules in the background. | ||||
| 
 | ||||
| To generate, run `npx rollup -c` in this directory, and then run | ||||
| `./genworker.js`. | ||||
| 
 | ||||
| LICENSE | ||||
| ------- | ||||
| 
 | ||||
| MIT | ||||
| @ -1,13 +0,0 @@ | ||||
| #!/usr/bin/env node
 | ||||
| 
 | ||||
| var fs = require("fs"); | ||||
| var browserify = require("browserify"); | ||||
| 
 | ||||
| browserify("src/babel-worker.js") | ||||
|   .transform("babelify", { | ||||
|     presets: [ [ "@babel/preset-env", { targets: "ie >= 11" } ] ], | ||||
|     global: true, | ||||
|     ignore: [ "../../node_modules/core-js" ] | ||||
|   }) | ||||
|   .bundle() | ||||
|   .pipe(fs.createWriteStream("dist/babel-worker.js")); | ||||
| @ -1,15 +0,0 @@ | ||||
| import nodeResolve from 'rollup-plugin-node-resolve'; | ||||
| 
 | ||||
| export default { | ||||
|   input: 'src/browser-es-module-loader.js', | ||||
|   output: { | ||||
|     file: 'dist/browser-es-module-loader.js', | ||||
|     format: 'umd', | ||||
|     name: 'BrowserESModuleLoader', | ||||
|     sourcemap: true, | ||||
|   }, | ||||
| 
 | ||||
|   plugins: [ | ||||
|     nodeResolve(), | ||||
|   ], | ||||
| }; | ||||
| @ -1,23 +0,0 @@ | ||||
| // Polyfills needed for Babel to function
 | ||||
| require("core-js"); | ||||
| 
 | ||||
| var babelTransform = require('@babel/core').transform; | ||||
| var babelTransformDynamicImport = require('@babel/plugin-syntax-dynamic-import'); | ||||
| var babelTransformModulesSystemJS = require('@babel/plugin-transform-modules-systemjs'); | ||||
| var babelPresetEnv = require('@babel/preset-env'); | ||||
| 
 | ||||
| self.onmessage = function (evt) { | ||||
|     // transform source with Babel
 | ||||
|     var output = babelTransform(evt.data.source, { | ||||
|       compact: false, | ||||
|       filename: evt.data.key + '!transpiled', | ||||
|       sourceFileName: evt.data.key, | ||||
|       moduleIds: false, | ||||
|       sourceMaps: 'inline', | ||||
|       babelrc: false, | ||||
|       plugins: [babelTransformDynamicImport, babelTransformModulesSystemJS], | ||||
|       presets: [ [ babelPresetEnv, { targets: 'ie >= 11' } ] ], | ||||
|     }); | ||||
| 
 | ||||
|     self.postMessage({key: evt.data.key, code: output.code, source: evt.data.source}); | ||||
| }; | ||||
| @ -1,279 +0,0 @@ | ||||
| import RegisterLoader from 'es-module-loader/core/register-loader.js'; | ||||
| 
 | ||||
| import { baseURI, global, isBrowser } from 'es-module-loader/core/common.js'; | ||||
| import { resolveIfNotPlain } from 'es-module-loader/core/resolve.js'; | ||||
| 
 | ||||
| var loader; | ||||
| 
 | ||||
| // <script type="module"> support
 | ||||
| var anonSources = {}; | ||||
| if (typeof document != 'undefined' && document.getElementsByTagName) { | ||||
|   var handleError = function(err) { | ||||
|     // dispatch an error event so that we can display in errors in browsers
 | ||||
|     // that don't yet support unhandledrejection
 | ||||
|     if (window.onunhandledrejection === undefined) { | ||||
|       try { | ||||
|         var evt = new Event('error'); | ||||
|       } catch (_eventError) { | ||||
|         var evt = document.createEvent('Event'); | ||||
|         evt.initEvent('error', true, true); | ||||
|       } | ||||
|       evt.message = err.message; | ||||
|       if (err.fileName) { | ||||
|         evt.filename = err.fileName; | ||||
|         evt.lineno = err.lineNumber; | ||||
|         evt.colno = err.columnNumber; | ||||
|       } else if (err.sourceURL) { | ||||
|         evt.filename = err.sourceURL; | ||||
|         evt.lineno = err.line; | ||||
|         evt.colno = err.column; | ||||
|       } | ||||
|       evt.error = err; | ||||
|       window.dispatchEvent(evt); | ||||
|     } | ||||
| 
 | ||||
|     // throw so it still shows up in the console
 | ||||
|     throw err; | ||||
|   } | ||||
| 
 | ||||
|   var ready = function() { | ||||
|     document.removeEventListener('DOMContentLoaded', ready, false ); | ||||
| 
 | ||||
|     var anonCnt = 0; | ||||
| 
 | ||||
|     var scripts = document.getElementsByTagName('script'); | ||||
|     for (var i = 0; i < scripts.length; i++) { | ||||
|       var script = scripts[i]; | ||||
|       if (script.type == 'module' && !script.loaded) { | ||||
|         script.loaded = true; | ||||
|         if (script.src) { | ||||
|           loader.import(script.src).catch(handleError); | ||||
|         } | ||||
|         // anonymous modules supported via a custom naming scheme and registry
 | ||||
|         else { | ||||
|           var uri = './<anon' + ++anonCnt + '>.js'; | ||||
|           if (script.id !== ""){ | ||||
|             uri = "./" + script.id; | ||||
|           } | ||||
| 
 | ||||
|           var anonName = resolveIfNotPlain(uri, baseURI); | ||||
|           anonSources[anonName] = script.innerHTML; | ||||
|           loader.import(anonName).catch(handleError); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // simple DOM ready
 | ||||
|   if (document.readyState !== 'loading') | ||||
|     setTimeout(ready); | ||||
|   else | ||||
|     document.addEventListener('DOMContentLoaded', ready, false); | ||||
| } | ||||
| 
 | ||||
| function BrowserESModuleLoader(baseKey) { | ||||
|   if (baseKey) | ||||
|     this.baseKey = resolveIfNotPlain(baseKey, baseURI) || resolveIfNotPlain('./' + baseKey, baseURI); | ||||
| 
 | ||||
|   RegisterLoader.call(this); | ||||
| 
 | ||||
|   var loader = this; | ||||
| 
 | ||||
|   // ensure System.register is available
 | ||||
|   global.System = global.System || {}; | ||||
|   if (typeof global.System.register == 'function') | ||||
|     var prevRegister = global.System.register; | ||||
|   global.System.register = function() { | ||||
|     loader.register.apply(loader, arguments); | ||||
|     if (prevRegister) | ||||
|       prevRegister.apply(this, arguments); | ||||
|   }; | ||||
| } | ||||
| BrowserESModuleLoader.prototype = Object.create(RegisterLoader.prototype); | ||||
| 
 | ||||
| // normalize is never given a relative name like "./x", that part is already handled
 | ||||
| BrowserESModuleLoader.prototype[RegisterLoader.resolve] = function(key, parent) { | ||||
|   var resolved = RegisterLoader.prototype[RegisterLoader.resolve].call(this, key, parent || this.baseKey) || key; | ||||
|   if (!resolved) | ||||
|     throw new RangeError('ES module loader does not resolve plain module names, resolving "' + key + '" to ' + parent); | ||||
| 
 | ||||
|   return resolved; | ||||
| }; | ||||
| 
 | ||||
| function xhrFetch(url, resolve, reject) { | ||||
|   var xhr = new XMLHttpRequest(); | ||||
|   var load = function(source) { | ||||
|     resolve(xhr.responseText); | ||||
|   } | ||||
|   var error = function() { | ||||
|     reject(new Error('XHR error' + (xhr.status ? ' (' + xhr.status + (xhr.statusText ? ' ' + xhr.statusText  : '') + ')' : '') + ' loading ' + url)); | ||||
|   } | ||||
| 
 | ||||
|   xhr.onreadystatechange = function () { | ||||
|     if (xhr.readyState === 4) { | ||||
|       // in Chrome on file:/// URLs, status is 0
 | ||||
|       if (xhr.status == 0) { | ||||
|         if (xhr.responseText) { | ||||
|           load(); | ||||
|         } | ||||
|         else { | ||||
|           // when responseText is empty, wait for load or error event
 | ||||
|           // to inform if it is a 404 or empty file
 | ||||
|           xhr.addEventListener('error', error); | ||||
|           xhr.addEventListener('load', load); | ||||
|         } | ||||
|       } | ||||
|       else if (xhr.status === 200) { | ||||
|         load(); | ||||
|       } | ||||
|       else { | ||||
|         error(); | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
|   xhr.open("GET", url, true); | ||||
|   xhr.send(null); | ||||
| } | ||||
| 
 | ||||
| var WorkerPool = function (script, size) { | ||||
|   var current = document.currentScript; | ||||
|   // IE doesn't support currentScript
 | ||||
|   if (!current) { | ||||
|     // Find an entry with out basename
 | ||||
|     var scripts = document.getElementsByTagName('script'); | ||||
|     for (var i = 0; i < scripts.length; i++) { | ||||
|       if (scripts[i].src.indexOf("browser-es-module-loader.js") !== -1) { | ||||
|         current = scripts[i]; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     if (!current) | ||||
|       throw Error("Could not find own <script> element"); | ||||
|   } | ||||
|   script = current.src.substr(0, current.src.lastIndexOf("/")) + "/" + script; | ||||
|   this._workers = new Array(size); | ||||
|   this._ind = 0; | ||||
|   this._size = size; | ||||
|   this._jobs = 0; | ||||
|   this.onmessage = undefined; | ||||
|   this._stopTimeout = undefined; | ||||
|   for (var i = 0; i < size; i++) { | ||||
|     var wrkr = new Worker(script); | ||||
|     wrkr._count = 0; | ||||
|     wrkr._ind = i; | ||||
|     wrkr.onmessage = this._onmessage.bind(this, wrkr); | ||||
|     wrkr.onerror = this._onerror.bind(this); | ||||
|     this._workers[i] = wrkr; | ||||
|   } | ||||
| 
 | ||||
|   this._checkJobs(); | ||||
| }; | ||||
| WorkerPool.prototype = { | ||||
|   postMessage: function (msg) { | ||||
|     if (this._stopTimeout !== undefined) { | ||||
|       clearTimeout(this._stopTimeout); | ||||
|       this._stopTimeout = undefined; | ||||
|     } | ||||
|     var wrkr = this._workers[this._ind % this._size]; | ||||
|     wrkr._count++; | ||||
|     this._jobs++; | ||||
|     wrkr.postMessage(msg); | ||||
|     this._ind++; | ||||
|   }, | ||||
| 
 | ||||
|   _onmessage: function (wrkr, evt) { | ||||
|     wrkr._count--; | ||||
|     this._jobs--; | ||||
|     this.onmessage(evt, wrkr); | ||||
|     this._checkJobs(); | ||||
|   }, | ||||
| 
 | ||||
|   _onerror: function(err) { | ||||
|     try { | ||||
|         var evt = new Event('error'); | ||||
|     } catch (_eventError) { | ||||
|         var evt = document.createEvent('Event'); | ||||
|         evt.initEvent('error', true, true); | ||||
|     } | ||||
|     evt.message = err.message; | ||||
|     evt.filename = err.filename; | ||||
|     evt.lineno = err.lineno; | ||||
|     evt.colno = err.colno; | ||||
|     evt.error = err.error; | ||||
|     window.dispatchEvent(evt); | ||||
|   }, | ||||
| 
 | ||||
|   _checkJobs: function () { | ||||
|     if (this._jobs === 0 && this._stopTimeout === undefined) { | ||||
|       // wait for 2s of inactivity before stopping (that should be enough for local loading)
 | ||||
|       this._stopTimeout = setTimeout(this._stop.bind(this), 2000); | ||||
|     } | ||||
|   }, | ||||
| 
 | ||||
|   _stop: function () { | ||||
|     this._workers.forEach(function(wrkr) { | ||||
|       wrkr.terminate(); | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| var promiseMap = new Map(); | ||||
| var babelWorker = new WorkerPool('babel-worker.js', 3); | ||||
| babelWorker.onmessage = function (evt) { | ||||
|     var promFuncs = promiseMap.get(evt.data.key); | ||||
|     promFuncs.resolve(evt.data); | ||||
|     promiseMap.delete(evt.data.key); | ||||
| }; | ||||
| 
 | ||||
| // instantiate just needs to run System.register
 | ||||
| // so we fetch the source, convert into the Babel System module format, then evaluate it
 | ||||
| BrowserESModuleLoader.prototype[RegisterLoader.instantiate] = function(key, processAnonRegister) { | ||||
|   var loader = this; | ||||
| 
 | ||||
|   // load as ES with Babel converting into System.register
 | ||||
|   return new Promise(function(resolve, reject) { | ||||
|     // anonymous module
 | ||||
|     if (anonSources[key]) { | ||||
|       resolve(anonSources[key]) | ||||
|       anonSources[key] = undefined; | ||||
|     } | ||||
|     // otherwise we fetch
 | ||||
|     else { | ||||
|       xhrFetch(key, resolve, reject); | ||||
|     } | ||||
|   }) | ||||
|   .then(function(source) { | ||||
|     // check our cache first
 | ||||
|     var cacheEntry = localStorage.getItem(key); | ||||
|     if (cacheEntry) { | ||||
|       cacheEntry = JSON.parse(cacheEntry); | ||||
|       // TODO: store a hash instead
 | ||||
|       if (cacheEntry.source === source) { | ||||
|         return Promise.resolve({key: key, code: cacheEntry.code, source: cacheEntry.source}); | ||||
|       } | ||||
|     } | ||||
|     return new Promise(function (resolve, reject) { | ||||
|       promiseMap.set(key, {resolve: resolve, reject: reject}); | ||||
|       babelWorker.postMessage({key: key, source: source}); | ||||
|     }); | ||||
|   }).then(function (data) { | ||||
|     // evaluate without require, exports and module variables
 | ||||
|     // we leave module in for now to allow module.require access
 | ||||
|     try { | ||||
|       var cacheEntry = JSON.stringify({source: data.source, code: data.code}); | ||||
|       localStorage.setItem(key, cacheEntry); | ||||
|     } catch (e) { | ||||
|       if (window.console) { | ||||
|         window.console.warn('Unable to cache transpiled version of ' + key + ': ' + e); | ||||
|       } | ||||
|     } | ||||
|     (0, eval)(data.code + '\n//# sourceURL=' + data.key + '!transpiled'); | ||||
|     processAnonRegister(); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| // create a default loader instance in the browser
 | ||||
| if (isBrowser) | ||||
|   loader = new BrowserESModuleLoader(); | ||||
| 
 | ||||
| export default BrowserESModuleLoader; | ||||
							
								
								
									
										255
									
								
								systemvm/agent/noVNC/vendor/promise.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										255
									
								
								systemvm/agent/noVNC/vendor/promise.js
									
									
									
									
										vendored
									
									
								
							| @ -1,255 +0,0 @@ | ||||
| /* Copyright (c) 2014 Taylor Hakes | ||||
|  * Copyright (c) 2014 Forbes Lindesay | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| (function (root) { | ||||
| 
 | ||||
|   // Store setTimeout reference so promise-polyfill will be unaffected by
 | ||||
|   // other code modifying setTimeout (like sinon.useFakeTimers())
 | ||||
|   var setTimeoutFunc = setTimeout; | ||||
| 
 | ||||
|   function noop() {} | ||||
|    | ||||
|   // Polyfill for Function.prototype.bind
 | ||||
|   function bind(fn, thisArg) { | ||||
|     return function () { | ||||
|       fn.apply(thisArg, arguments); | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   function Promise(fn) { | ||||
|     if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new'); | ||||
|     if (typeof fn !== 'function') throw new TypeError('not a function'); | ||||
|     this._state = 0; | ||||
|     this._handled = false; | ||||
|     this._value = undefined; | ||||
|     this._deferreds = []; | ||||
| 
 | ||||
|     doResolve(fn, this); | ||||
|   } | ||||
| 
 | ||||
|   function handle(self, deferred) { | ||||
|     while (self._state === 3) { | ||||
|       self = self._value; | ||||
|     } | ||||
|     if (self._state === 0) { | ||||
|       self._deferreds.push(deferred); | ||||
|       return; | ||||
|     } | ||||
|     self._handled = true; | ||||
|     Promise._immediateFn(function () { | ||||
|       var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; | ||||
|       if (cb === null) { | ||||
|         (self._state === 1 ? resolve : reject)(deferred.promise, self._value); | ||||
|         return; | ||||
|       } | ||||
|       var ret; | ||||
|       try { | ||||
|         ret = cb(self._value); | ||||
|       } catch (e) { | ||||
|         reject(deferred.promise, e); | ||||
|         return; | ||||
|       } | ||||
|       resolve(deferred.promise, ret); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   function resolve(self, newValue) { | ||||
|     try { | ||||
|       // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
 | ||||
|       if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.'); | ||||
|       if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { | ||||
|         var then = newValue.then; | ||||
|         if (newValue instanceof Promise) { | ||||
|           self._state = 3; | ||||
|           self._value = newValue; | ||||
|           finale(self); | ||||
|           return; | ||||
|         } else if (typeof then === 'function') { | ||||
|           doResolve(bind(then, newValue), self); | ||||
|           return; | ||||
|         } | ||||
|       } | ||||
|       self._state = 1; | ||||
|       self._value = newValue; | ||||
|       finale(self); | ||||
|     } catch (e) { | ||||
|       reject(self, e); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   function reject(self, newValue) { | ||||
|     self._state = 2; | ||||
|     self._value = newValue; | ||||
|     finale(self); | ||||
|   } | ||||
| 
 | ||||
|   function finale(self) { | ||||
|     if (self._state === 2 && self._deferreds.length === 0) { | ||||
|       Promise._immediateFn(function() { | ||||
|         if (!self._handled) { | ||||
|           Promise._unhandledRejectionFn(self._value); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     for (var i = 0, len = self._deferreds.length; i < len; i++) { | ||||
|       handle(self, self._deferreds[i]); | ||||
|     } | ||||
|     self._deferreds = null; | ||||
|   } | ||||
| 
 | ||||
|   function Handler(onFulfilled, onRejected, promise) { | ||||
|     this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; | ||||
|     this.onRejected = typeof onRejected === 'function' ? onRejected : null; | ||||
|     this.promise = promise; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Take a potentially misbehaving resolver function and make sure | ||||
|    * onFulfilled and onRejected are only called once. | ||||
|    * | ||||
|    * Makes no guarantees about asynchrony. | ||||
|    */ | ||||
|   function doResolve(fn, self) { | ||||
|     var done = false; | ||||
|     try { | ||||
|       fn(function (value) { | ||||
|         if (done) return; | ||||
|         done = true; | ||||
|         resolve(self, value); | ||||
|       }, function (reason) { | ||||
|         if (done) return; | ||||
|         done = true; | ||||
|         reject(self, reason); | ||||
|       }); | ||||
|     } catch (ex) { | ||||
|       if (done) return; | ||||
|       done = true; | ||||
|       reject(self, ex); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Promise.prototype['catch'] = function (onRejected) { | ||||
|     return this.then(null, onRejected); | ||||
|   }; | ||||
| 
 | ||||
|   Promise.prototype.then = function (onFulfilled, onRejected) { | ||||
|     var prom = new (this.constructor)(noop); | ||||
| 
 | ||||
|     handle(this, new Handler(onFulfilled, onRejected, prom)); | ||||
|     return prom; | ||||
|   }; | ||||
| 
 | ||||
|   Promise.all = function (arr) { | ||||
|     var args = Array.prototype.slice.call(arr); | ||||
| 
 | ||||
|     return new Promise(function (resolve, reject) { | ||||
|       if (args.length === 0) return resolve([]); | ||||
|       var remaining = args.length; | ||||
| 
 | ||||
|       function res(i, val) { | ||||
|         try { | ||||
|           if (val && (typeof val === 'object' || typeof val === 'function')) { | ||||
|             var then = val.then; | ||||
|             if (typeof then === 'function') { | ||||
|               then.call(val, function (val) { | ||||
|                 res(i, val); | ||||
|               }, reject); | ||||
|               return; | ||||
|             } | ||||
|           } | ||||
|           args[i] = val; | ||||
|           if (--remaining === 0) { | ||||
|             resolve(args); | ||||
|           } | ||||
|         } catch (ex) { | ||||
|           reject(ex); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       for (var i = 0; i < args.length; i++) { | ||||
|         res(i, args[i]); | ||||
|       } | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   Promise.resolve = function (value) { | ||||
|     if (value && typeof value === 'object' && value.constructor === Promise) { | ||||
|       return value; | ||||
|     } | ||||
| 
 | ||||
|     return new Promise(function (resolve) { | ||||
|       resolve(value); | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   Promise.reject = function (value) { | ||||
|     return new Promise(function (resolve, reject) { | ||||
|       reject(value); | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   Promise.race = function (values) { | ||||
|     return new Promise(function (resolve, reject) { | ||||
|       for (var i = 0, len = values.length; i < len; i++) { | ||||
|         values[i].then(resolve, reject); | ||||
|       } | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   // Use polyfill for setImmediate for performance gains
 | ||||
|   Promise._immediateFn = (typeof setImmediate === 'function' && function (fn) { setImmediate(fn); }) || | ||||
|     function (fn) { | ||||
|       setTimeoutFunc(fn, 0); | ||||
|     }; | ||||
| 
 | ||||
|   Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) { | ||||
|     if (typeof console !== 'undefined' && console) { | ||||
|       console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
 | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   /** | ||||
|    * Set the immediate function to execute callbacks | ||||
|    * @param fn {function} Function to execute | ||||
|    * @deprecated | ||||
|    */ | ||||
|   Promise._setImmediateFn = function _setImmediateFn(fn) { | ||||
|     Promise._immediateFn = fn; | ||||
|   }; | ||||
| 
 | ||||
|   /** | ||||
|    * Change the function to execute on unhandled rejection | ||||
|    * @param {function} fn Function to execute on unhandled rejection | ||||
|    * @deprecated | ||||
|    */ | ||||
|   Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) { | ||||
|     Promise._unhandledRejectionFn = fn; | ||||
|   }; | ||||
|    | ||||
|   if (typeof module !== 'undefined' && module.exports) { | ||||
|     module.exports = Promise; | ||||
|   } else if (!root.Promise) { | ||||
|     root.Promise = Promise; | ||||
|   } | ||||
| 
 | ||||
| })(this); | ||||
| @ -15,56 +15,37 @@ | ||||
|     --> | ||||
|     <title>noVNC</title> | ||||
| 
 | ||||
|     <meta charset="utf-8"> | ||||
| 
 | ||||
|     <!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame | ||||
|                 Remove this if you use the .htaccess --> | ||||
|     <meta http-equiv="X-UA-Compatible" content="IE=edge" /> | ||||
| 
 | ||||
|     <!-- Icons (see app/images/icons/Makefile for what the sizes are for) --> | ||||
|     <link rel="icon" sizes="16x16" type="image/png" href="app/images/icons/novnc-16x16.png"> | ||||
|     <link rel="icon" sizes="24x24" type="image/png" href="app/images/icons/novnc-24x24.png"> | ||||
|     <link rel="icon" sizes="32x32" type="image/png" href="app/images/icons/novnc-32x32.png"> | ||||
|     <link rel="icon" sizes="48x48" type="image/png" href="app/images/icons/novnc-48x48.png"> | ||||
|     <link rel="icon" sizes="60x60" type="image/png" href="app/images/icons/novnc-60x60.png"> | ||||
|     <link rel="icon" sizes="64x64" type="image/png" href="app/images/icons/novnc-64x64.png"> | ||||
|     <link rel="icon" sizes="72x72" type="image/png" href="app/images/icons/novnc-72x72.png"> | ||||
|     <link rel="icon" sizes="76x76" type="image/png" href="app/images/icons/novnc-76x76.png"> | ||||
|     <link rel="icon" sizes="96x96" type="image/png" href="app/images/icons/novnc-96x96.png"> | ||||
|     <link rel="icon" sizes="120x120" type="image/png" href="app/images/icons/novnc-120x120.png"> | ||||
|     <link rel="icon" sizes="144x144" type="image/png" href="app/images/icons/novnc-144x144.png"> | ||||
|     <link rel="icon" sizes="152x152" type="image/png" href="app/images/icons/novnc-152x152.png"> | ||||
|     <link rel="icon" sizes="192x192" type="image/png" href="app/images/icons/novnc-192x192.png"> | ||||
|     <!-- Firefox currently mishandles SVG, see #1419039 | ||||
|     <link rel="icon" sizes="any" type="image/svg+xml" href="app/images/icons/novnc-icon.svg"> | ||||
|     --> | ||||
|     <!-- Repeated last so that legacy handling will pick this --> | ||||
|     <link rel="icon" sizes="16x16" type="image/png" href="app/images/icons/novnc-16x16.png"> | ||||
|     <link rel="icon" type="image/x-icon" href="app/images/icons/novnc.ico"> | ||||
| 
 | ||||
|     <!-- Apple iOS Safari settings --> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | ||||
|     <meta name="apple-mobile-web-app-capable" content="yes"> | ||||
|     <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> | ||||
|     <!-- Home Screen Icons (favourites and bookmarks use the normal icons) --> | ||||
|     <link rel="apple-touch-icon" sizes="60x60" type="image/png" href="app/images/icons/novnc-60x60.png"> | ||||
|     <link rel="apple-touch-icon" sizes="76x76" type="image/png" href="app/images/icons/novnc-76x76.png"> | ||||
|     <link rel="apple-touch-icon" sizes="120x120" type="image/png" href="app/images/icons/novnc-120x120.png"> | ||||
|     <link rel="apple-touch-icon" sizes="152x152" type="image/png" href="app/images/icons/novnc-152x152.png"> | ||||
| 
 | ||||
|     <!-- @2x --> | ||||
|     <link rel="apple-touch-icon" sizes="40x40" type="image/png" href="app/images/icons/novnc-ios-40.png"> | ||||
|     <link rel="apple-touch-icon" sizes="58x58" type="image/png" href="app/images/icons/novnc-ios-58.png"> | ||||
|     <link rel="apple-touch-icon" sizes="80x80" type="image/png" href="app/images/icons/novnc-ios-80.png"> | ||||
|     <link rel="apple-touch-icon" sizes="120x120" type="image/png" href="app/images/icons/novnc-ios-120.png"> | ||||
|     <link rel="apple-touch-icon" sizes="152x152" type="image/png" href="app/images/icons/novnc-ios-152.png"> | ||||
|     <link rel="apple-touch-icon" sizes="167x167" type="image/png" href="app/images/icons/novnc-ios-167.png"> | ||||
|     <!-- @3x --> | ||||
|     <link rel="apple-touch-icon" sizes="60x60" type="image/png" href="app/images/icons/novnc-ios-60.png"> | ||||
|     <link rel="apple-touch-icon" sizes="87x87" type="image/png" href="app/images/icons/novnc-ios-87.png"> | ||||
|     <link rel="apple-touch-icon" sizes="120x120" type="image/png" href="app/images/icons/novnc-ios-120.png"> | ||||
|     <link rel="apple-touch-icon" sizes="180x180" type="image/png" href="app/images/icons/novnc-ios-180.png"> | ||||
| 
 | ||||
|     <!-- Stylesheets --> | ||||
|     <link rel="stylesheet" href="app/styles/base.css"> | ||||
|     <link rel="stylesheet" href="app/styles/input.css"> | ||||
| 
 | ||||
|     <!-- this is included as a normal file in order to catch script-loading errors as well --> | ||||
|     <script src="app/error-handler.js"></script> | ||||
|     <!-- Images that will later appear via CSS --> | ||||
|     <link rel="preload" as="image" href="app/images/info.png"> | ||||
|     <link rel="preload" as="image" href="app/images/error.png"> | ||||
|     <link rel="preload" as="image" href="app/images/warning.png"> | ||||
| 
 | ||||
|     <!-- begin scripts --> | ||||
|     <!-- promise polyfills promises for IE11 --> | ||||
|     <script src="vendor/promise.js"></script> | ||||
|     <!-- ES2015/ES6 modules polyfill --> | ||||
|     <script nomodule src="vendor/browser-es-module-loader/dist/browser-es-module-loader.js"></script> | ||||
|     <!-- actual script modules --> | ||||
|     <script type="module" crossorigin="anonymous" src="app/error-handler.js"></script> | ||||
|     <script type="module" crossorigin="anonymous" src="app/ui.js"></script> | ||||
|     <!-- end scripts --> | ||||
| </head> | ||||
| 
 | ||||
| <body id="body"> | ||||
| @ -87,6 +68,8 @@ | ||||
| 
 | ||||
|             <h1 class="noVNC_logo" translate="no" style="display: none;"><span>no</span><br>VNC</h1> | ||||
| 
 | ||||
|             <hr> | ||||
| 
 | ||||
|             <!-- Drag/Pan the viewport --> | ||||
|             <input type="image" alt="Drag" src="app/images/drag.png" | ||||
|                 id="noVNC_view_drag_button" class="noVNC_button noVNC_hidden" | ||||
| @ -152,6 +135,9 @@ | ||||
|                 <div class="noVNC_heading"> | ||||
|                     <img alt="" src="app/images/clipboard.png"> Clipboard | ||||
|                 </div> | ||||
|                 <p class="noVNC_subheading"> | ||||
|                     Edit clipboard content in the textarea below. | ||||
|                 </p> | ||||
|                 <textarea id="noVNC_clipboard_text" rows=5></textarea> | ||||
|                 <br> | ||||
|                 <input id="noVNC_clipboard_send_button" type="button" | ||||
| @ -162,9 +148,9 @@ | ||||
|             </div> | ||||
| 
 | ||||
|             <!-- Toggle fullscreen --> | ||||
|             <input type="image" alt="Fullscreen" src="app/images/fullscreen.png" | ||||
|             <input type="image" alt="Full Screen" src="app/images/fullscreen.png" | ||||
|                 id="noVNC_fullscreen_button" class="noVNC_button noVNC_hidden" | ||||
|                 title="Fullscreen"> | ||||
|                 title="Full Screen"> | ||||
| 
 | ||||
|             <!-- Settings --> | ||||
|             <span style="display: none;"> | ||||
| @ -173,10 +159,10 @@ | ||||
|                     title="Settings"> | ||||
|                 <div class="noVNC_vcenter"> | ||||
|                 <div id="noVNC_settings" class="noVNC_panel"> | ||||
|                     <ul> | ||||
|                         <li class="noVNC_heading"> | ||||
|                     <div class="noVNC_heading"> | ||||
|                         <img alt="" src="app/images/settings.png"> Settings | ||||
|                         </li> | ||||
|                     </div> | ||||
|                     <ul> | ||||
|                         <li> | ||||
|                             <label><input id="noVNC_setting_shared" type="checkbox"> Shared Mode</label> | ||||
|                         </li> | ||||
| @ -280,39 +266,69 @@ | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div id="noVNC_control_bar_hint"></div> | ||||
| 
 | ||||
|     </div> <!-- End of noVNC_control_bar --> | ||||
| 
 | ||||
|     <div id="noVNC_hint_anchor" class="noVNC_vcenter"> | ||||
|         <div id="noVNC_control_bar_hint"> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <!-- Status Dialog --> | ||||
|     <div id="noVNC_status"></div> | ||||
| 
 | ||||
|     <!-- Connect button --> | ||||
|     <div class="noVNC_center" style="display: none;"> | ||||
|         <div id="noVNC_connect_dlg"> | ||||
|             <div class="noVNC_logo" translate="no"><span>no</span>VNC</div> | ||||
|             <div id="noVNC_connect_button"><div> | ||||
|             <p class="noVNC_logo" translate="no"><span>no</span>VNC</p> | ||||
|             <div> | ||||
|                 <button id="noVNC_connect_button"> | ||||
|                     <img alt="" src="app/images/connect.png"> Connect | ||||
|             </div></div> | ||||
|                 </button> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <!-- Server Key Verification Dialog --> | ||||
|     <div class="noVNC_center noVNC_connect_layer"> | ||||
|     <div id="noVNC_verify_server_dlg" class="noVNC_panel"><form> | ||||
|         <div class="noVNC_heading"> | ||||
|             Server identity | ||||
|         </div> | ||||
|         <div> | ||||
|             The server has provided the following identifying information: | ||||
|         </div> | ||||
|         <div id="noVNC_fingerprint_block"> | ||||
|             <b>Fingerprint:</b> | ||||
|             <span id="noVNC_fingerprint"></span> | ||||
|         </div> | ||||
|         <div> | ||||
|             Please verify that the information is correct and press | ||||
|             "Approve". Otherwise press "Reject". | ||||
|         </div> | ||||
|         <div> | ||||
|             <input id="noVNC_approve_server_button" type="submit" value="Approve" class="noVNC_submit"> | ||||
|             <input id="noVNC_reject_server_button" type="button" value="Reject" class="noVNC_submit"> | ||||
|         </div> | ||||
|     </form></div> | ||||
|     </div> | ||||
| 
 | ||||
|     <!-- Password Dialog --> | ||||
|     <div class="noVNC_center noVNC_connect_layer"> | ||||
|     <div id="noVNC_credentials_dlg" class="noVNC_panel"><form> | ||||
|         <ul> | ||||
|             <li id="noVNC_username_block"> | ||||
|                 <label>Username:</label> | ||||
|         <div class="noVNC_heading"> | ||||
|             Credentials | ||||
|         </div> | ||||
|         <div id="noVNC_username_block"> | ||||
|             <label for="noVNC_username_input">Username:</label> | ||||
|             <input id="noVNC_username_input"> | ||||
|             </li> | ||||
|             <li id="noVNC_password_block"> | ||||
|                 <label>Password:</label> | ||||
|         </div> | ||||
|         <div id="noVNC_password_block"> | ||||
|             <label for="noVNC_password_input">Password:</label> | ||||
|             <input id="noVNC_password_input" type="password"> | ||||
|             </li> | ||||
|             <li> | ||||
|         </div> | ||||
|         <div> | ||||
|             <input id="noVNC_credentials_button" type="submit" value="Send Credentials" class="noVNC_submit"> | ||||
|             </li> | ||||
|         </ul> | ||||
|         </div> | ||||
|     </form></div> | ||||
|     </div> | ||||
| 
 | ||||
|  | ||||
| @ -16,12 +16,6 @@ | ||||
|     --> | ||||
|     <title>noVNC</title> | ||||
| 
 | ||||
|     <meta charset="utf-8"> | ||||
| 
 | ||||
|     <!-- Always force latest IE rendering engine (even in intranet) & | ||||
|                 Chrome Frame. Remove this if you use the .htaccess --> | ||||
|     <meta http-equiv="X-UA-Compatible" content="IE=edge" /> | ||||
| 
 | ||||
|     <style> | ||||
| 
 | ||||
|         body { | ||||
| @ -68,13 +62,6 @@ | ||||
| 
 | ||||
|     </style> | ||||
| 
 | ||||
|     <!-- Promise polyfill for IE11 --> | ||||
|     <script src="vendor/promise.js"></script> | ||||
| 
 | ||||
|     <!-- ES2015/ES6 modules polyfill --> | ||||
|     <script nomodule src="vendor/browser-es-module-loader/dist/browser-es-module-loader.js"></script> | ||||
| 
 | ||||
|     <!-- actual script modules --> | ||||
|     <script type="module" crossorigin="anonymous"> | ||||
|         // RFB holds the API to connect and communicate with a VNC server | ||||
|         import RFB from './core/rfb.js'; | ||||
| @ -132,13 +119,20 @@ | ||||
|         // query string. If the variable isn't defined in the URL | ||||
|         // it returns the default value instead. | ||||
|         function readQueryVariable(name, defaultValue) { | ||||
|             // A URL with a query parameter can look like this: | ||||
|             // A URL with a query parameter can look like this (But will most probably get logged on the http server): | ||||
|             // https://www.example.com?myqueryparam=myvalue | ||||
|             // | ||||
|             // For privacy (Using a hastag #, the parameters will not be sent to the server) | ||||
|             // the url can be requested in the following way: | ||||
|             // https://www.example.com#myqueryparam=myvalue&password=secreatvalue | ||||
|             // | ||||
|             // Even Mixing public and non public parameters will work: | ||||
|             // https://www.example.com?nonsecretparam=example.com#password=secreatvalue | ||||
|             // | ||||
|             // Note that we use location.href instead of location.search | ||||
|             // because Firefox < 53 has a bug w.r.t location.search | ||||
|             const re = new RegExp('.*[?&]' + name + '=([^&#]*)'), | ||||
|                   match = document.location.href.match(re); | ||||
|                   match = ''.concat(document.location.href, window.location.hash).match(re); | ||||
|             if (typeof defaultValue === 'undefined') { defaultValue = null; } | ||||
| 
 | ||||
|             if (match) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user