clockwerk-guacamole – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 1  
2 // UI Definition
3 var GuacamoleUI = {
4  
5 "LOGOUT_PROMPT" : "Logging out will disconnect all of your active "
6 + "Guacamole sessions. Are you sure you wish to log out?",
7  
8 /* Detection Constants */
9  
10 "LONG_PRESS_DETECT_TIMEOUT" : 800, /* milliseconds */
11 "LONG_PRESS_MOVEMENT_THRESHOLD" : 10, /* pixels */
12 "MENU_CLOSE_DETECT_TIMEOUT" : 500, /* milliseconds */
13 "MENU_OPEN_DETECT_TIMEOUT" : 325, /* milliseconds */
14 "KEYBOARD_AUTO_RESIZE_INTERVAL" : 30, /* milliseconds */
15  
16 /* Animation Constants */
17  
18 "MENU_SHADE_STEPS" : 10, /* frames */
19 "MENU_SHADE_INTERVAL" : 30, /* milliseconds */
20 "MENU_SHOW_STEPS" : 5, /* frames */
21 "MENU_SHOW_INTERVAL" : 30, /* milliseconds */
22  
23 /* OSK Mode Constants */
24 "OSK_MODE_NATIVE" : 1, /* "Show Keyboard" will show the platform's native OSK */
25 "OSK_MODE_GUAC" : 2, /* "Show Keyboard" will show Guac's built-in OSK */
26  
27 /* UI Elements */
28  
29 "viewport" : document.getElementById("viewportClone"),
30 "display" : document.getElementById("display"),
31 "menu" : document.getElementById("menu"),
32 "menuControl" : document.getElementById("menuControl"),
33 "touchMenu" : document.getElementById("touchMenu"),
34 "logo" : document.getElementById("status-logo"),
35 "eventTarget" : document.getElementById("eventTarget"),
36  
37 "buttons": {
38  
39 "showClipboard": document.getElementById("showClipboard"),
40 "showKeyboard" : document.getElementById("showKeyboard"),
41 "ctrlAltDelete": document.getElementById("ctrlAltDelete"),
42 "reconnect" : document.getElementById("reconnect"),
43 "logout" : document.getElementById("logout"),
44  
45 "touchShowClipboard" : document.getElementById("touchShowClipboard"),
46 "touchShowKeyboard" : document.getElementById("touchShowKeyboard"),
47 "touchLogout" : document.getElementById("touchLogout")
48  
49 },
50  
51 "containers": {
52 "state" : document.getElementById("statusDialog"),
53 "clipboard" : document.getElementById("clipboardDiv"),
54 "touchClipboard": document.getElementById("touchClipboardDiv"),
55 "keyboard" : document.getElementById("keyboardContainer")
56 },
57  
58 "state" : document.getElementById("statusText"),
59 "clipboard" : document.getElementById("clipboard"),
60 "touchClipboard" : document.getElementById("touchClipboard")
61  
62 };
63  
64 // Constant UI initialization and behavior
65 (function() {
66  
67 var menu_shaded = false;
68  
69 var shade_interval = null;
70 var show_interval = null;
71  
72 // Cache error image (might not be available when error occurs)
73 var guacErrorImage = new Image();
74 guacErrorImage.src = "images/noguacamole-logo-24.png";
75  
76 // Function for adding a class to an element
77 var addClass;
78  
79 // Function for removing a class from an element
80 var removeClass;
81  
82 // If Node.classList is supported, implement addClass/removeClass using that
83 if (Node.classList) {
84  
85 addClass = function(element, classname) {
86 element.classList.add(classname);
87 };
88  
89 removeClass = function(element, classname) {
90 element.classList.remove(classname);
91 };
92  
93 }
94  
95 // Otherwise, implement own
96 else {
97  
98 addClass = function(element, classname) {
99  
100 // Simply add new class
101 element.className += " " + classname;
102  
103 };
104  
105 removeClass = function(element, classname) {
106  
107 // Filter out classes with given name
108 element.className = element.className.replace(/([^ ]+)[ ]*/g,
109 function(match, testClassname, spaces, offset, string) {
110  
111 // If same class, remove
112 if (testClassname == classname)
113 return "";
114  
115 // Otherwise, allow
116 return match;
117  
118 }
119 );
120  
121 };
122  
123 }
124  
125  
126 GuacamoleUI.hideStatus = function() {
127 removeClass(document.body, "guac-error");
128 GuacamoleUI.containers.state.style.visibility = "hidden";
129 GuacamoleUI.display.style.opacity = "1";
130 };
131  
132 GuacamoleUI.showStatus = function(text) {
133 removeClass(document.body, "guac-error");
134 GuacamoleUI.containers.state.style.visibility = "visible";
135 GuacamoleUI.state.textContent = text;
136 GuacamoleUI.display.style.opacity = "1";
137 };
138  
139 GuacamoleUI.showError = function(error) {
140 addClass(document.body, "guac-error");
141 GuacamoleUI.state.textContent = error;
142 GuacamoleUI.display.style.opacity = "0.1";
143 };
144  
145 GuacamoleUI.hideTouchMenu = function() {
146 GuacamoleUI.touchMenu.style.visibility = "hidden";
147 };
148  
149 function positionCentered(element) {
150 element.style.left =
151 ((GuacamoleUI.viewport.offsetWidth - element.offsetWidth) / 2
152 + window.pageXOffset)
153 + "px";
154  
155 element.style.top =
156 ((GuacamoleUI.viewport.offsetHeight - element.offsetHeight) / 2
157 + window.pageYOffset)
158 + "px";
159 }
160  
161 GuacamoleUI.showTouchMenu = function() {
162 positionCentered(GuacamoleUI.touchMenu);
163 GuacamoleUI.touchMenu.style.visibility = "visible";
164 };
165  
166 GuacamoleUI.hideTouchClipboard = function() {
167 GuacamoleUI.containers.touchClipboard.style.visibility = "hidden";
168 };
169  
170 GuacamoleUI.showTouchClipboard = function() {
171 positionCentered(GuacamoleUI.containers.touchClipboard);
172 GuacamoleUI.containers.touchClipboard.style.visibility = "visible";
173 };
174  
175 GuacamoleUI.shadeMenu = function() {
176  
177 if (!menu_shaded) {
178  
179 var step = Math.floor(GuacamoleUI.menu.offsetHeight / GuacamoleUI.MENU_SHADE_STEPS) + 1;
180 var offset = 0;
181 menu_shaded = true;
182  
183 window.clearInterval(show_interval);
184 shade_interval = window.setInterval(function() {
185  
186 offset -= step;
187  
188 GuacamoleUI.menu.style.transform =
189 GuacamoleUI.menu.style.WebkitTransform =
190 GuacamoleUI.menu.style.MozTransform =
191 GuacamoleUI.menu.style.OTransform =
192 GuacamoleUI.menu.style.msTransform =
193  
194 "translateY(" + offset + "px)";
195  
196 if (offset <= -GuacamoleUI.menu.offsetHeight) {
197 <= -GuacamoleUI.menu.offsetHeight) { window.clearInterval(shade_interval);
198 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.menu.style.visiblity = "hidden";
199 <= -GuacamoleUI.menu.offsetHeight) { }
200  
201 <= -GuacamoleUI.menu.offsetHeight) { }, GuacamoleUI.MENU_SHADE_INTERVAL);
202 <= -GuacamoleUI.menu.offsetHeight) { }
203  
204 <= -GuacamoleUI.menu.offsetHeight) { };
205  
206 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.showMenu = function() {
207  
208 <= -GuacamoleUI.menu.offsetHeight) { if (menu_shaded) {
209  
210 <= -GuacamoleUI.menu.offsetHeight) { var step = Math.floor(GuacamoleUI.menu.offsetHeight / GuacamoleUI.MENU_SHOW_STEPS) + 1;
211 <= -GuacamoleUI.menu.offsetHeight) { var offset = -GuacamoleUI.menu.offsetHeight;
212 <= -GuacamoleUI.menu.offsetHeight) { menu_shaded = false;
213 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.menu.style.visiblity = "";
214  
215 <= -GuacamoleUI.menu.offsetHeight) { window.clearInterval(shade_interval);
216 <= -GuacamoleUI.menu.offsetHeight) { show_interval = window.setInterval(function() {
217  
218 <= -GuacamoleUI.menu.offsetHeight) { offset += step;
219  
220 <= -GuacamoleUI.menu.offsetHeight) { if (offset >= 0) {
221 <= -GuacamoleUI.menu.offsetHeight) { offset = 0;
222 <= -GuacamoleUI.menu.offsetHeight) { window.clearInterval(show_interval);
223 <= -GuacamoleUI.menu.offsetHeight) { }
224  
225 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.menu.style.transform =
226 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.menu.style.WebkitTransform =
227 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.menu.style.MozTransform =
228 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.menu.style.OTransform =
229 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.menu.style.msTransform =
230  
231 <= -GuacamoleUI.menu.offsetHeight) { "translateY(" + offset + "px)";
232  
233 <= -GuacamoleUI.menu.offsetHeight) { }, GuacamoleUI.MENU_SHOW_INTERVAL);
234 <= -GuacamoleUI.menu.offsetHeight) { }
235  
236 <= -GuacamoleUI.menu.offsetHeight) { };
237  
238 <= -GuacamoleUI.menu.offsetHeight) { // Show/Hide clipboard
239 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.showClipboard.onclick = function() {
240  
241 <= -GuacamoleUI.menu.offsetHeight) { var displayed = GuacamoleUI.containers.clipboard.style.display;
242 <= -GuacamoleUI.menu.offsetHeight) { if (displayed != "block") {
243 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.containers.clipboard.style.display = "block";
244 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.showClipboard.innerHTML = "Hide Clipboard";
245 <= -GuacamoleUI.menu.offsetHeight) { }
246 <= -GuacamoleUI.menu.offsetHeight) { else {
247 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.containers.clipboard.style.display = "none";
248 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.showClipboard.innerHTML = "Show Clipboard";
249 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.clipboard.onchange();
250 <= -GuacamoleUI.menu.offsetHeight) { }
251  
252 <= -GuacamoleUI.menu.offsetHeight) { };
253  
254 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.touchShowClipboard.onclick = function() {
255 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.hideTouchMenu();
256 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.showTouchClipboard();
257 <= -GuacamoleUI.menu.offsetHeight) { };
258  
259 <= -GuacamoleUI.menu.offsetHeight) { // Show/Hide keyboard
260 <= -GuacamoleUI.menu.offsetHeight) { var keyboardResizeInterval = null;
261 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.showKeyboard.onclick = function() {
262  
263 <= -GuacamoleUI.menu.offsetHeight) { // If Guac OSK shown, hide it.
264 <= -GuacamoleUI.menu.offsetHeight) { var displayed = GuacamoleUI.containers.keyboard.style.display;
265 <= -GuacamoleUI.menu.offsetHeight) { if (displayed == "block") {
266 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.containers.keyboard.style.display = "none";
267 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.showKeyboard.textContent = "Show Keyboard";
268  
269 <= -GuacamoleUI.menu.offsetHeight) { window.onresize = null;
270 <= -GuacamoleUI.menu.offsetHeight) { window.clearInterval(keyboardResizeInterval);
271 <= -GuacamoleUI.menu.offsetHeight) { }
272  
273 <= -GuacamoleUI.menu.offsetHeight) { // Otherwise, show it
274 <= -GuacamoleUI.menu.offsetHeight) { else {
275  
276 <= -GuacamoleUI.menu.offsetHeight) { // Ensure event target is NOT focused if we are using the Guac OSK.
277 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.blur();
278  
279 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.containers.keyboard.style.display = "block";
280 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.showKeyboard.textContent = "Hide Keyboard";
281  
282 <= -GuacamoleUI.menu.offsetHeight) { // Automatically update size
283 <= -GuacamoleUI.menu.offsetHeight) { window.onresize = updateKeyboardSize;
284 <= -GuacamoleUI.menu.offsetHeight) { keyboardResizeInterval = window.setInterval(updateKeyboardSize,
285 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.KEYBOARD_AUTO_RESIZE_INTERVAL);
286  
287 <= -GuacamoleUI.menu.offsetHeight) { updateKeyboardSize();
288  
289 <= -GuacamoleUI.menu.offsetHeight) { }
290  
291 <= -GuacamoleUI.menu.offsetHeight) { };
292  
293 <= -GuacamoleUI.menu.offsetHeight) { // Touch-specific keyboard show
294 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.touchShowKeyboard.onclick =
295 <= -GuacamoleUI.menu.offsetHeight) { function(e) {
296  
297 <= -GuacamoleUI.menu.offsetHeight) { // Center event target in case browser automatically centers
298 <= -GuacamoleUI.menu.offsetHeight) { // input fields on focus.
299 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.style.left =
300 <= -GuacamoleUI.menu.offsetHeight) { (window.pageXOffset + GuacamoleUI.viewport.offsetWidth / 2) + "px";
301  
302 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.style.top =
303 <= -GuacamoleUI.menu.offsetHeight) { (window.pageYOffset + GuacamoleUI.viewport.offsetHeight / 2) + "px";
304  
305 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.focus();
306 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.hideTouchMenu();
307  
308 <= -GuacamoleUI.menu.offsetHeight) { };
309  
310 <= -GuacamoleUI.menu.offsetHeight) { // Logout
311 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.logout.onclick =
312 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.touchLogout.onclick =
313 <= -GuacamoleUI.menu.offsetHeight) { function() {
314  
315 <= -GuacamoleUI.menu.offsetHeight) { // Logout after warning user about session disconnect
316 <= -GuacamoleUI.menu.offsetHeight) { if (confirm(GuacamoleUI.LOGOUT_PROMPT)) {
317 <= -GuacamoleUI.menu.offsetHeight) { window.location.href = "logout";
318 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.hideTouchMenu();
319 <= -GuacamoleUI.menu.offsetHeight) { }
320  
321 <= -GuacamoleUI.menu.offsetHeight) { };
322  
323 <= -GuacamoleUI.menu.offsetHeight) { // Timeouts for detecting if users wants menu to open or close
324 <= -GuacamoleUI.menu.offsetHeight) { var detectMenuOpenTimeout = null;
325 <= -GuacamoleUI.menu.offsetHeight) { var detectMenuCloseTimeout = null;
326  
327 <= -GuacamoleUI.menu.offsetHeight) { // Clear detection timeouts
328 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.resetMenuDetect = function() {
329  
330 <= -GuacamoleUI.menu.offsetHeight) { if (detectMenuOpenTimeout != null) {
331 <= -GuacamoleUI.menu.offsetHeight) { window.clearTimeout(detectMenuOpenTimeout);
332 <= -GuacamoleUI.menu.offsetHeight) { detectMenuOpenTimeout = null;
333 <= -GuacamoleUI.menu.offsetHeight) { }
334  
335 <= -GuacamoleUI.menu.offsetHeight) { if (detectMenuCloseTimeout != null) {
336 <= -GuacamoleUI.menu.offsetHeight) { window.clearTimeout(detectMenuCloseTimeout);
337 <= -GuacamoleUI.menu.offsetHeight) { detectMenuCloseTimeout = null;
338 <= -GuacamoleUI.menu.offsetHeight) { }
339  
340 <= -GuacamoleUI.menu.offsetHeight) { };
341  
342 <= -GuacamoleUI.menu.offsetHeight) { // Initiate detection of menu open action. If not canceled through some
343 <= -GuacamoleUI.menu.offsetHeight) { // user event, menu will open.
344 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.startMenuOpenDetect = function() {
345  
346 <= -GuacamoleUI.menu.offsetHeight) { if (!detectMenuOpenTimeout) {
347  
348 <= -GuacamoleUI.menu.offsetHeight) { // Clear detection state
349 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.resetMenuDetect();
350  
351 <= -GuacamoleUI.menu.offsetHeight) { // Wait and then show menu
352 <= -GuacamoleUI.menu.offsetHeight) { detectMenuOpenTimeout = window.setTimeout(function() {
353  
354 <= -GuacamoleUI.menu.offsetHeight) { // If menu opened via mouse, do not show native OSK
355 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.oskMode = GuacamoleUI.OSK_MODE_GUAC;
356  
357 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.showMenu();
358 <= -GuacamoleUI.menu.offsetHeight) { detectMenuOpenTimeout = null;
359 <= -GuacamoleUI.menu.offsetHeight) { }, GuacamoleUI.MENU_OPEN_DETECT_TIMEOUT);
360  
361 <= -GuacamoleUI.menu.offsetHeight) { }
362  
363 <= -GuacamoleUI.menu.offsetHeight) { };
364  
365 <= -GuacamoleUI.menu.offsetHeight) { // Initiate detection of menu close action. If not canceled through some
366 <= -GuacamoleUI.menu.offsetHeight) { // user mouse event, menu will close.
367 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.startMenuCloseDetect = function() {
368  
369 <= -GuacamoleUI.menu.offsetHeight) { if (!detectMenuCloseTimeout) {
370  
371 <= -GuacamoleUI.menu.offsetHeight) { // Clear detection state
372 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.resetMenuDetect();
373  
374 <= -GuacamoleUI.menu.offsetHeight) { // Wait and then shade menu
375 <= -GuacamoleUI.menu.offsetHeight) { detectMenuCloseTimeout = window.setTimeout(function() {
376 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.shadeMenu();
377 <= -GuacamoleUI.menu.offsetHeight) { detectMenuCloseTimeout = null;
378 <= -GuacamoleUI.menu.offsetHeight) { }, GuacamoleUI.MENU_CLOSE_DETECT_TIMEOUT);
379  
380 <= -GuacamoleUI.menu.offsetHeight) { }
381  
382 <= -GuacamoleUI.menu.offsetHeight) { };
383  
384 <= -GuacamoleUI.menu.offsetHeight) { // Show menu if mouseover any part of menu
385 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.showMenu, true);
386  
387 <= -GuacamoleUI.menu.offsetHeight) { // Stop detecting menu state change intents if mouse is over menu
388 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.resetMenuDetect, true);
389  
390 <= -GuacamoleUI.menu.offsetHeight) { // When mouse hovers over top of screen, start detection of intent to open menu
391 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.menuControl.addEventListener('mousemove', GuacamoleUI.startMenuOpenDetect, true);
392  
393 <= -GuacamoleUI.menu.offsetHeight) { var long_press_start_x = 0;
394 <= -GuacamoleUI.menu.offsetHeight) { var long_press_start_y = 0;
395 <= -GuacamoleUI.menu.offsetHeight) { var menuShowLongPressTimeout = null;
396  
397 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.startLongPressDetect = function() {
398  
399 <= -GuacamoleUI.menu.offsetHeight) { if (!menuShowLongPressTimeout) {
400  
401 <= -GuacamoleUI.menu.offsetHeight) { menuShowLongPressTimeout = window.setTimeout(function() {
402  
403 <= -GuacamoleUI.menu.offsetHeight) { menuShowLongPressTimeout = null;
404  
405 <= -GuacamoleUI.menu.offsetHeight) { // Assume native OSK if menu shown via long-press
406 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.oskMode = GuacamoleUI.OSK_MODE_NATIVE;
407 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.showTouchMenu();
408  
409 <= -GuacamoleUI.menu.offsetHeight) { }, GuacamoleUI.LONG_PRESS_DETECT_TIMEOUT);
410  
411 <= -GuacamoleUI.menu.offsetHeight) { }
412 <= -GuacamoleUI.menu.offsetHeight) { };
413  
414 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.stopLongPressDetect = function() {
415 <= -GuacamoleUI.menu.offsetHeight) { window.clearTimeout(menuShowLongPressTimeout);
416 <= -GuacamoleUI.menu.offsetHeight) { menuShowLongPressTimeout = null;
417 <= -GuacamoleUI.menu.offsetHeight) { };
418  
419 <= -GuacamoleUI.menu.offsetHeight) { // Detect long-press at bottom of screen
420 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.display.addEventListener('touchstart', function(e) {
421  
422 <= -GuacamoleUI.menu.offsetHeight) { // Close menu if shown
423 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.shadeMenu();
424 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.hideTouchMenu();
425 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.hideTouchClipboard();
426  
427 <= -GuacamoleUI.menu.offsetHeight) { // Record touch location
428 <= -GuacamoleUI.menu.offsetHeight) { if (e.touches.length == 1) {
429 <= -GuacamoleUI.menu.offsetHeight) { var touch = e.touches[0];
430 <= -GuacamoleUI.menu.offsetHeight) { long_press_start_x = touch.screenX;
431 <= -GuacamoleUI.menu.offsetHeight) { long_press_start_y = touch.screenY;
432 <= -GuacamoleUI.menu.offsetHeight) { }
433  
434 <= -GuacamoleUI.menu.offsetHeight) { // Start detection
435 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.startLongPressDetect();
436  
437 <= -GuacamoleUI.menu.offsetHeight) { }, true);
438  
439 <= -GuacamoleUI.menu.offsetHeight) { // Stop detection if touch moves significantly
440 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.display.addEventListener('touchmove', function(e) {
441  
442 <= -GuacamoleUI.menu.offsetHeight) { // If touch distance from start exceeds threshold, cancel long press
443 <= -GuacamoleUI.menu.offsetHeight) { var touch = e.touches[0];
444 <= -GuacamoleUI.menu.offsetHeight) { if (Math.abs(touch.screenX - long_press_start_x) >= GuacamoleUI.LONG_PRESS_MOVEMENT_THRESHOLD
445 <= -GuacamoleUI.menu.offsetHeight) { || Math.abs(touch.screenY - long_press_start_y) >= GuacamoleUI.LONG_PRESS_MOVEMENT_THRESHOLD)
446 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.stopLongPressDetect();
447  
448 <= -GuacamoleUI.menu.offsetHeight) { }, true);
449  
450 <= -GuacamoleUI.menu.offsetHeight) { // Stop detection if press stops
451 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.display.addEventListener('touchend', GuacamoleUI.stopLongPressDetect, true);
452  
453 <= -GuacamoleUI.menu.offsetHeight) { // Close menu on mouse movement
454 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.display.addEventListener('mousemove', GuacamoleUI.startMenuCloseDetect, true);
455 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.display.addEventListener('mousedown', GuacamoleUI.startMenuCloseDetect, true);
456  
457 <= -GuacamoleUI.menu.offsetHeight) { // Reconnect button
458 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.reconnect.onclick = function() {
459 <= -GuacamoleUI.menu.offsetHeight) { window.location.reload();
460 <= -GuacamoleUI.menu.offsetHeight) { };
461  
462 <= -GuacamoleUI.menu.offsetHeight) { // On-screen keyboard
463 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.keyboard = new Guacamole.OnScreenKeyboard("layouts/en-us-qwerty.xml");
464 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.containers.keyboard.appendChild(GuacamoleUI.keyboard.getElement());
465  
466 <= -GuacamoleUI.menu.offsetHeight) { // Function for automatically updating keyboard size
467 <= -GuacamoleUI.menu.offsetHeight) { var lastKeyboardWidth;
468 <= -GuacamoleUI.menu.offsetHeight) { function updateKeyboardSize() {
469 <= -GuacamoleUI.menu.offsetHeight) { var currentSize = GuacamoleUI.keyboard.getElement().offsetWidth;
470 <= -GuacamoleUI.menu.offsetHeight) { if (lastKeyboardWidth != currentSize) {
471 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.keyboard.resize(currentSize);
472 <= -GuacamoleUI.menu.offsetHeight) { lastKeyboardWidth = currentSize;
473 <= -GuacamoleUI.menu.offsetHeight) { }
474 <= -GuacamoleUI.menu.offsetHeight) { };
475  
476 <= -GuacamoleUI.menu.offsetHeight) { // Turn off autocorrect and autocapitalization on eventTarget
477 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.setAttribute("autocorrect", "off");
478 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.setAttribute("autocapitalize", "off");
479  
480 <= -GuacamoleUI.menu.offsetHeight) { // Automatically reposition event target on scroll
481 <= -GuacamoleUI.menu.offsetHeight) { window.addEventListener("scroll", function() {
482 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.style.left = window.pageXOffset + "px";
483 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.style.top = window.pageYOffset + "px";
484 <= -GuacamoleUI.menu.offsetHeight) { });
485  
486 <= -GuacamoleUI.menu.offsetHeight) {})();
487  
488 <= -GuacamoleUI.menu.offsetHeight) {// Tie UI events / behavior to a specific Guacamole client
489 <= -GuacamoleUI.menu.offsetHeight) {GuacamoleUI.attach = function(guac) {
490  
491 <= -GuacamoleUI.menu.offsetHeight) { var title_prefix = null;
492 <= -GuacamoleUI.menu.offsetHeight) { var connection_name = "Guacamole";
493  
494 <= -GuacamoleUI.menu.offsetHeight) { var guac_display = guac.getDisplay();
495  
496 <= -GuacamoleUI.menu.offsetHeight) { // Set document title appropriately, based on prefix and connection name
497 <= -GuacamoleUI.menu.offsetHeight) { function updateTitle() {
498  
499 <= -GuacamoleUI.menu.offsetHeight) { // Use title prefix if present
500 <= -GuacamoleUI.menu.offsetHeight) { if (title_prefix) {
501  
502 <= -GuacamoleUI.menu.offsetHeight) { document.title = title_prefix;
503  
504 <= -GuacamoleUI.menu.offsetHeight) { // Include connection name, if present
505 <= -GuacamoleUI.menu.offsetHeight) { if (connection_name)
506 <= -GuacamoleUI.menu.offsetHeight) { document.title += " " + connection_name;
507  
508 <= -GuacamoleUI.menu.offsetHeight) { }
509  
510 <= -GuacamoleUI.menu.offsetHeight) { // Otherwise, just set to connection name
511 <= -GuacamoleUI.menu.offsetHeight) { else if (connection_name)
512 <= -GuacamoleUI.menu.offsetHeight) { document.title = connection_name;
513  
514 <= -GuacamoleUI.menu.offsetHeight) { }
515  
516 <= -GuacamoleUI.menu.offsetHeight) { // When mouse enters display, start detection of intent to close menu
517 <= -GuacamoleUI.menu.offsetHeight) { guac_display.addEventListener('mouseover', GuacamoleUI.startMenuCloseDetect, true);
518  
519 <= -GuacamoleUI.menu.offsetHeight) { guac_display.onclick = function(e) {
520 <= -GuacamoleUI.menu.offsetHeight) { e.preventDefault();
521 <= -GuacamoleUI.menu.offsetHeight) { return false;
522 <= -GuacamoleUI.menu.offsetHeight) { };
523  
524 <= -GuacamoleUI.menu.offsetHeight) { // Mouse
525 <= -GuacamoleUI.menu.offsetHeight) { var mouse = new Guacamole.Mouse(guac_display);
526 <= -GuacamoleUI.menu.offsetHeight) { mouse.onmousedown = mouse.onmouseup = mouse.onmousemove =
527 <= -GuacamoleUI.menu.offsetHeight) { function(mouseState) {
528  
529 <= -GuacamoleUI.menu.offsetHeight) { // Determine mouse position within view
530 <= -GuacamoleUI.menu.offsetHeight) { var mouse_view_x = mouseState.x + guac_display.offsetLeft - window.pageXOffset;
531 <= -GuacamoleUI.menu.offsetHeight) { var mouse_view_y = mouseState.y + guac_display.offsetTop - window.pageYOffset;
532  
533 <= -GuacamoleUI.menu.offsetHeight) { // Determine viewport dimensioins
534 <= -GuacamoleUI.menu.offsetHeight) { var view_width = GuacamoleUI.viewport.offsetWidth;
535 <= -GuacamoleUI.menu.offsetHeight) { var view_height = GuacamoleUI.viewport.offsetHeight;
536  
537 <= -GuacamoleUI.menu.offsetHeight) { // Determine scroll amounts based on mouse position relative to document
538  
539 <= -GuacamoleUI.menu.offsetHeight) { var scroll_amount_x;
540 <= -GuacamoleUI.menu.offsetHeight) { if (mouse_view_x > view_width)
541 <= -GuacamoleUI.menu.offsetHeight) { scroll_amount_x = mouse_view_x - view_width;
542 <= -GuacamoleUI.menu.offsetHeight) { else if (mouse_view_x < 0)
543 <= -GuacamoleUI.menu.offsetHeight) { scroll_amount_x = mouse_view_x;
544 <= -GuacamoleUI.menu.offsetHeight) { else
545 <= -GuacamoleUI.menu.offsetHeight) { scroll_amount_x = 0;
546  
547 <= -GuacamoleUI.menu.offsetHeight) { var scroll_amount_y;
548 <= -GuacamoleUI.menu.offsetHeight) { if (mouse_view_y > view_height)
549 <= -GuacamoleUI.menu.offsetHeight) { scroll_amount_y = mouse_view_y - view_height;
550 <= -GuacamoleUI.menu.offsetHeight) { else if (mouse_view_y < 0)
551 <= -GuacamoleUI.menu.offsetHeight) { scroll_amount_y = mouse_view_y;
552 <= -GuacamoleUI.menu.offsetHeight) { else
553 <= -GuacamoleUI.menu.offsetHeight) { scroll_amount_y = 0;
554  
555 <= -GuacamoleUI.menu.offsetHeight) { // Scroll (if necessary) to keep mouse on screen.
556 <= -GuacamoleUI.menu.offsetHeight) { window.scrollBy(scroll_amount_x, scroll_amount_y);
557  
558 <= -GuacamoleUI.menu.offsetHeight) { // Send mouse event
559 <= -GuacamoleUI.menu.offsetHeight) { guac.sendMouseState(mouseState);
560  
561 <= -GuacamoleUI.menu.offsetHeight) { };
562  
563 <= -GuacamoleUI.menu.offsetHeight) { // Keyboard
564 <= -GuacamoleUI.menu.offsetHeight) { var keyboard = new Guacamole.Keyboard(document);
565  
566 <= -GuacamoleUI.menu.offsetHeight) { // Monitor whether the event target is focused
567 <= -GuacamoleUI.menu.offsetHeight) { var eventTargetFocused = false;
568  
569 <= -GuacamoleUI.menu.offsetHeight) { // Save length for calculation of changed value
570 <= -GuacamoleUI.menu.offsetHeight) { var currentLength = GuacamoleUI.eventTarget.value.length;
571  
572 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.onfocus = function() {
573 <= -GuacamoleUI.menu.offsetHeight) { eventTargetFocused = true;
574 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.value = "";
575 <= -GuacamoleUI.menu.offsetHeight) { currentLength = 0;
576 <= -GuacamoleUI.menu.offsetHeight) { };
577  
578 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.onblur = function() {
579 <= -GuacamoleUI.menu.offsetHeight) { eventTargetFocused = false;
580 <= -GuacamoleUI.menu.offsetHeight) { };
581  
582 <= -GuacamoleUI.menu.offsetHeight) { // If text is input directly into event target without typing (as with
583 <= -GuacamoleUI.menu.offsetHeight) { // voice input, for example), type automatically.
584 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.eventTarget.oninput = function(e) {
585  
586 <= -GuacamoleUI.menu.offsetHeight) { // Calculate current length and change in length
587 <= -GuacamoleUI.menu.offsetHeight) { var oldLength = currentLength;
588 <= -GuacamoleUI.menu.offsetHeight) { currentLength = GuacamoleUI.eventTarget.value.length;
589  
590 <= -GuacamoleUI.menu.offsetHeight) { // If deleted or replaced text, ignore
591 <= -GuacamoleUI.menu.offsetHeight) { if (currentLength <= oldLength)
592 <= -GuacamoleUI.menu.offsetHeight) { return;
593  
594 <= -GuacamoleUI.menu.offsetHeight) { // Get changed text
595 <= -GuacamoleUI.menu.offsetHeight) { var text = GuacamoleUI.eventTarget.value.substring(oldLength);
596  
597 <= -GuacamoleUI.menu.offsetHeight) { // Send each character
598 <= -GuacamoleUI.menu.offsetHeight) { for (var i=0; i<text.length; i++) {
599  
600 <= -GuacamoleUI.menu.offsetHeight) { // Get char code
601 <= -GuacamoleUI.menu.offsetHeight) { var charCode = text.charCodeAt(i);
602  
603 <= -GuacamoleUI.menu.offsetHeight) { // Convert to keysym
604 <= -GuacamoleUI.menu.offsetHeight) { var keysym = 0x003F; // Default to a question mark
605 <= -GuacamoleUI.menu.offsetHeight) { if (charCode >= 0x0000 && charCode <= 0x00FF)
606 <= -GuacamoleUI.menu.offsetHeight) { keysym = charCode;
607 <= -GuacamoleUI.menu.offsetHeight) { else if (charCode >= 0x0100 && charCode <= 0x10FFFF)
608 <= -GuacamoleUI.menu.offsetHeight) { keysym = 0x01000000 | charCode;
609  
610 <= -GuacamoleUI.menu.offsetHeight) { // Send keysym only if not already pressed
611 <= -GuacamoleUI.menu.offsetHeight) { if (!keyboard.pressed[keysym]) {
612  
613 <= -GuacamoleUI.menu.offsetHeight) { // Press and release key
614 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(1, keysym);
615 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(0, keysym);
616  
617 <= -GuacamoleUI.menu.offsetHeight) { }
618  
619 <= -GuacamoleUI.menu.offsetHeight) { }
620  
621 <= -GuacamoleUI.menu.offsetHeight) { }
622  
623 <= -GuacamoleUI.menu.offsetHeight) { function isTypableCharacter(keysym) {
624 <= -GuacamoleUI.menu.offsetHeight) { return (keysym & 0xFFFF00) != 0xFF00;
625 <= -GuacamoleUI.menu.offsetHeight) { }
626  
627 <= -GuacamoleUI.menu.offsetHeight) { function disableKeyboard() {
628 <= -GuacamoleUI.menu.offsetHeight) { keyboard.onkeydown = null;
629 <= -GuacamoleUI.menu.offsetHeight) { keyboard.onkeyup = null;
630 <= -GuacamoleUI.menu.offsetHeight) { }
631  
632 <= -GuacamoleUI.menu.offsetHeight) { function enableKeyboard() {
633  
634 <= -GuacamoleUI.menu.offsetHeight) { keyboard.onkeydown = function (keysym) {
635 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(1, keysym);
636 <= -GuacamoleUI.menu.offsetHeight) { return eventTargetFocused && isTypableCharacter(keysym);
637 <= -GuacamoleUI.menu.offsetHeight) { };
638  
639 <= -GuacamoleUI.menu.offsetHeight) { keyboard.onkeyup = function (keysym) {
640 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(0, keysym);
641 <= -GuacamoleUI.menu.offsetHeight) { return eventTargetFocused && isTypableCharacter(keysym);
642 <= -GuacamoleUI.menu.offsetHeight) { };
643  
644 <= -GuacamoleUI.menu.offsetHeight) { }
645  
646 <= -GuacamoleUI.menu.offsetHeight) { // Enable keyboard by default
647 <= -GuacamoleUI.menu.offsetHeight) { enableKeyboard();
648  
649 <= -GuacamoleUI.menu.offsetHeight) { // Handle client state change
650 <= -GuacamoleUI.menu.offsetHeight) { guac.onstatechange = function(clientState) {
651  
652 <= -GuacamoleUI.menu.offsetHeight) { switch (clientState) {
653  
654 <= -GuacamoleUI.menu.offsetHeight) { // Idle
655 <= -GuacamoleUI.menu.offsetHeight) { case 0:
656 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.showStatus("Idle.");
657 <= -GuacamoleUI.menu.offsetHeight) { title_prefix = "[Idle]";
658 <= -GuacamoleUI.menu.offsetHeight) { break;
659  
660 <= -GuacamoleUI.menu.offsetHeight) { // Connecting
661 <= -GuacamoleUI.menu.offsetHeight) { case 1:
662 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.shadeMenu();
663 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.showStatus("Connecting...");
664 <= -GuacamoleUI.menu.offsetHeight) { title_prefix = "[Connecting...]";
665 <= -GuacamoleUI.menu.offsetHeight) { break;
666  
667 <= -GuacamoleUI.menu.offsetHeight) { // Connected + waiting
668 <= -GuacamoleUI.menu.offsetHeight) { case 2:
669 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.showStatus("Connected, waiting for first update...");
670 <= -GuacamoleUI.menu.offsetHeight) { title_prefix = "[Waiting...]";
671 <= -GuacamoleUI.menu.offsetHeight) { break;
672  
673 <= -GuacamoleUI.menu.offsetHeight) { // Connected
674 <= -GuacamoleUI.menu.offsetHeight) { case 3:
675 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.hideStatus();
676 <= -GuacamoleUI.menu.offsetHeight) { title_prefix = null;
677 <= -GuacamoleUI.menu.offsetHeight) { break;
678  
679 <= -GuacamoleUI.menu.offsetHeight) { // Disconnecting
680 <= -GuacamoleUI.menu.offsetHeight) { case 4:
681 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.showStatus("Disconnecting...");
682 <= -GuacamoleUI.menu.offsetHeight) { title_prefix = "[Disconnecting...]";
683 <= -GuacamoleUI.menu.offsetHeight) { break;
684  
685 <= -GuacamoleUI.menu.offsetHeight) { // Disconnected
686 <= -GuacamoleUI.menu.offsetHeight) { case 5:
687 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.showStatus("Disconnected.");
688 <= -GuacamoleUI.menu.offsetHeight) { title_prefix = "[Disconnected]";
689 <= -GuacamoleUI.menu.offsetHeight) { break;
690  
691 <= -GuacamoleUI.menu.offsetHeight) { // Unknown status code
692 <= -GuacamoleUI.menu.offsetHeight) { default:
693 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.showStatus("[UNKNOWN STATUS]");
694  
695 <= -GuacamoleUI.menu.offsetHeight) { }
696  
697 <= -GuacamoleUI.menu.offsetHeight) { updateTitle();
698 <= -GuacamoleUI.menu.offsetHeight) { };
699  
700 <= -GuacamoleUI.menu.offsetHeight) { // Name instruction handler
701 <= -GuacamoleUI.menu.offsetHeight) { guac.onname = function(name) {
702 <= -GuacamoleUI.menu.offsetHeight) { connection_name = name;
703 <= -GuacamoleUI.menu.offsetHeight) { updateTitle();
704 <= -GuacamoleUI.menu.offsetHeight) { };
705  
706 <= -GuacamoleUI.menu.offsetHeight) { // Error handler
707 <= -GuacamoleUI.menu.offsetHeight) { guac.onerror = function(error) {
708  
709 <= -GuacamoleUI.menu.offsetHeight) { // Disconnect, if connected
710 <= -GuacamoleUI.menu.offsetHeight) { guac.disconnect();
711  
712 <= -GuacamoleUI.menu.offsetHeight) { // Display error message
713 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.showError(error);
714  
715 <= -GuacamoleUI.menu.offsetHeight) { };
716  
717 <= -GuacamoleUI.menu.offsetHeight) { // Disconnect on close
718 <= -GuacamoleUI.menu.offsetHeight) { window.onunload = function() {
719 <= -GuacamoleUI.menu.offsetHeight) { guac.disconnect();
720 <= -GuacamoleUI.menu.offsetHeight) { };
721  
722 <= -GuacamoleUI.menu.offsetHeight) { // Handle clipboard events
723 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.clipboard.onchange = function() {
724  
725 <= -GuacamoleUI.menu.offsetHeight) { var text = GuacamoleUI.clipboard.value;
726 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.touchClipboard.value = text;
727 <= -GuacamoleUI.menu.offsetHeight) { guac.setClipboard(text);
728  
729 <= -GuacamoleUI.menu.offsetHeight) { };
730  
731 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.touchClipboard.onchange = function() {
732  
733 <= -GuacamoleUI.menu.offsetHeight) { var text = GuacamoleUI.touchClipboard.value;
734 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.clipboard.value = text;
735 <= -GuacamoleUI.menu.offsetHeight) { guac.setClipboard(text);
736  
737 <= -GuacamoleUI.menu.offsetHeight) { };
738  
739 <= -GuacamoleUI.menu.offsetHeight) { // Ignore keypresses when clipboard is focused
740 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.clipboard.onfocus =
741 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.touchClipboard.onfocus = function() {
742 <= -GuacamoleUI.menu.offsetHeight) { disableKeyboard();
743 <= -GuacamoleUI.menu.offsetHeight) { };
744  
745 <= -GuacamoleUI.menu.offsetHeight) { // Capture keypresses when clipboard is not focused
746 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.clipboard.onblur =
747 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.touchClipboard.onblur = function() {
748 <= -GuacamoleUI.menu.offsetHeight) { enableKeyboard();
749 <= -GuacamoleUI.menu.offsetHeight) { };
750  
751 <= -GuacamoleUI.menu.offsetHeight) { // Server copy handler
752 <= -GuacamoleUI.menu.offsetHeight) { guac.onclipboard = function(data) {
753 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.clipboard.value = data;
754 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.touchClipboard.value = data;
755 <= -GuacamoleUI.menu.offsetHeight) { };
756  
757 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.keyboard.onkeydown = function(keysym) {
758 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(1, keysym);
759 <= -GuacamoleUI.menu.offsetHeight) { };
760  
761 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.keyboard.onkeyup = function(keysym) {
762 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(0, keysym);
763 <= -GuacamoleUI.menu.offsetHeight) { };
764  
765 <= -GuacamoleUI.menu.offsetHeight) { // Send Ctrl-Alt-Delete
766 <= -GuacamoleUI.menu.offsetHeight) { GuacamoleUI.buttons.ctrlAltDelete.onclick = function() {
767  
768 <= -GuacamoleUI.menu.offsetHeight) { var KEYSYM_CTRL = 0xFFE3;
769 <= -GuacamoleUI.menu.offsetHeight) { var KEYSYM_ALT = 0xFFE9;
770 <= -GuacamoleUI.menu.offsetHeight) { var KEYSYM_DELETE = 0xFFFF;
771  
772 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(1, KEYSYM_CTRL);
773 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(1, KEYSYM_ALT);
774 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(1, KEYSYM_DELETE);
775 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(0, KEYSYM_DELETE);
776 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(0, KEYSYM_ALT);
777 <= -GuacamoleUI.menu.offsetHeight) { guac.sendKeyEvent(0, KEYSYM_CTRL);
778 <= -GuacamoleUI.menu.offsetHeight) { };
779  
780 <= -GuacamoleUI.menu.offsetHeight) {};