5 "display" : document.getElementById("display"),
6 "menu" : document.getElementById("menu"),
7 "menuControl" : document.getElementById("menuControl"),
8 "logo" : document.getElementById("status-logo"),
9 "state" : document.getElementById("state"),
13 "showClipboard": document.getElementById("showClipboard"),
14 "showKeyboard" : document.getElementById("showKeyboard"),
15 "ctrlAltDelete": document.getElementById("ctrlAltDelete"),
16 "reconnect" : document.getElementById("reconnect"),
17 "logout" : document.getElementById("logout")
22 "error" : document.getElementById("errorDialog"),
23 "clipboard": document.getElementById("clipboardDiv"),
24 "keyboard" : document.getElementById("keyboardContainer")
27 "error" : document.getElementById("errorText"),
28 "clipboard" : document.getElementById("clipboard")
32 // Constant UI initialization and behavior
35 var menu_shaded = false;
37 var shade_interval = null;
38 var show_interval = null;
40 // Cache error image (might not be available when error occurs)
41 var guacErrorImage = new Image();
42 guacErrorImage.src = "images/noguacamole-logo-24.png";
44 GuacamoleUI.showError = function(error) {
46 GuacamoleUI.menu.className = "error";
47 GuacamoleUI.display.className += " guac-error";
49 GuacamoleUI.logo.src = guacErrorImage.src;
50 GuacamoleUI.error.textContent = error;
51 GuacamoleUI.containers.error.style.visibility = "visible";
55 GuacamoleUI.shadeMenu = function() {
59 var step = Math.floor(GuacamoleUI.menu.offsetHeight / 10) + 1;
63 window.clearInterval(show_interval);
64 shade_interval = window.setInterval(function() {
67 GuacamoleUI.menu.style.top = offset + "px";
69 if (offset <= -GuacamoleUI.menu.offsetHeight) {
70 window.clearInterval(shade_interval);
71 GuacamoleUI.menu.style.visiblity = "hidden";
79 GuacamoleUI.showMenu = function() {
83 var step = Math.floor(GuacamoleUI.menu.offsetHeight / 5) + 1;
84 var offset = -GuacamoleUI.menu.offsetHeight;
86 GuacamoleUI.menu.style.visiblity = "";
88 window.clearInterval(shade_interval);
89 show_interval = window.setInterval(function() {
95 window.clearInterval(show_interval);
98 GuacamoleUI.menu.style.top = offset + "px";
105 // Show/Hide clipboard
106 GuacamoleUI.buttons.showClipboard.onclick = function() {
108 var displayed = GuacamoleUI.containers.clipboard.style.display;
109 if (displayed != "block") {
110 GuacamoleUI.containers.clipboard.style.display = "block";
111 GuacamoleUI.buttons.showClipboard.innerHTML = "Hide Clipboard";
114 GuacamoleUI.containers.clipboard.style.display = "none";
115 GuacamoleUI.buttons.showClipboard.innerHTML = "Show Clipboard";
116 GuacamoleUI.clipboard.onchange();
121 // Show/Hide keyboard
122 GuacamoleUI.buttons.showKeyboard.onclick = function() {
124 var displayed = GuacamoleUI.containers.keyboard.style.display;
125 if (displayed != "block") {
126 GuacamoleUI.containers.keyboard.style.display = "block";
127 GuacamoleUI.buttons.showKeyboard.textContent = "Hide Keyboard";
130 GuacamoleUI.containers.keyboard.style.display = "none";
131 GuacamoleUI.buttons.showKeyboard.textContent = "Show Keyboard";
137 GuacamoleUI.buttons.logout.onclick = function() {
138 window.location.href = "logout";
141 var detectMenuOpenTimeout = null;
142 var detectMenuCloseTimeout = null;
144 GuacamoleUI.menu.addEventListener('mouseover', function() {
146 // If we were waiting for menu close, we're not anymore
147 if (detectMenuCloseTimeout != null) {
148 window.clearTimeout(detectMenuCloseTimeout);
149 detectMenuCloseTimeout = null;
154 function menuShowHandler() {
156 // If we were waiting for menu close, we're not anymore
157 if (detectMenuCloseTimeout != null) {
158 window.clearTimeout(detectMenuCloseTimeout);
159 detectMenuCloseTimeout = null;
162 // Clear old timeout if mouse moved while we were waiting
163 if (detectMenuOpenTimeout != null) {
164 window.clearTimeout(detectMenuOpenTimeout);
165 detectMenuOpenTimeout = null;
168 // If not alread waiting, wait before showing menu
169 detectMenuOpenTimeout = window.setTimeout(function() {
170 GuacamoleUI.showMenu();
171 detectMenuOpenTimeout = null;
176 // Show menu of mouseover any part of menu
177 GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.showMenu, true);
179 // When mouse hovers over top of screen, start detection of mouse hover
180 GuacamoleUI.menuControl.addEventListener('mousemove', menuShowHandler, true);
181 document.addEventListener('mouseout', function(e) {
183 // Get parent of the element the mouse pointer is leaving
184 if (!e) e = window.event;
185 var target = e.relatedTarget || e.toElement;
187 // Ensure target is not menu nor child of menu
188 var targetParent = target;
189 while (targetParent != null) {
190 if (targetParent == document) return;
191 targetParent = targetParent.parentNode;
198 GuacamoleUI.display.addEventListener('mouseover', function() {
200 // If we were detecting menu open, stop it
201 if (detectMenuOpenTimeout != null) {
202 window.clearTimeout(detectMenuOpenTimeout);
203 detectMenuOpenTimeout = null;
206 // If not already waiting, start detection of mouse leave
207 if (detectMenuCloseTimeout == null) {
208 detectMenuCloseTimeout = window.setTimeout(function() {
209 GuacamoleUI.shadeMenu();
210 detectMenuCloseTimeout = null;
217 GuacamoleUI.buttons.reconnect.onclick = function() {
218 window.location.reload();
221 // On-screen keyboard
222 GuacamoleUI.keyboard = new Guacamole.OnScreenKeyboard("layouts/en-us-qwerty.xml");
223 GuacamoleUI.containers.keyboard.appendChild(GuacamoleUI.keyboard);
227 // Tie UI events / behavior to a specific Guacamole client
228 GuacamoleUI.attach = function(guac) {
231 var mouse = new Guacamole.Mouse(GuacamoleUI.display);
232 mouse.onmousedown = mouse.onmouseup = mouse.onmousemove =
233 function(mouseState) {
234 guac.sendMouseState(mouseState);
238 var keyboard = new Guacamole.Keyboard(document);
240 function disableKeyboard() {
241 keyboard.onkeydown = null;
242 keyboard.onkeyup = null;
245 function enableKeyboard() {
248 guac.sendKeyEvent(1, keysym);
253 guac.sendKeyEvent(0, keysym);
257 // Enable keyboard by default
260 // Handle client state change
261 guac.onstatechange = function(clientState) {
262 switch (clientState) {
266 GuacamoleUI.state.textContent = "Idle."
271 GuacamoleUI.state.textContent = "Connecting...";
274 // Connected + waiting
276 GuacamoleUI.state.textContent = "Connected, waiting for first update...";
282 GuacamoleUI.display.className =
283 GuacamoleUI.display.className.replace(/guac-loading/, '');
285 GuacamoleUI.menu.className = "connected";
286 GuacamoleUI.state.textContent = "Connected.";
287 GuacamoleUI.shadeMenu();
292 GuacamoleUI.state.textContent = "Disconnecting...";
297 GuacamoleUI.state.textContent = "Disconnected.";
300 // Unknown status code
302 GuacamoleUI.state.textContent = "Unknown";
307 // Name instruction handler
308 guac.onname = function(name) {
309 document.title = name;
313 guac.onerror = function(error) {
315 // Disconnect, if connected
318 // Display error message
319 GuacamoleUI.showError(error);
321 // Show error by desaturating display
322 var layers = guac.getLayers();
323 for (var i=0; i<layers.length; i++) {
324 layers[i].filter(desaturateFilter);
327 // Filter for desaturation
328 function desaturateFilter(data, width, height) {
330 for (var i=0; i<data.length; i+=4) {
338 var v = Math.max(r, g, b) / 2;
349 // Disconnect on close
350 window.onunload = function() {
354 // Handle clipboard events
355 GuacamoleUI.clipboard.onchange = function() {
357 var text = GuacamoleUI.clipboard.value;
358 guac.setClipboard(text);
362 // Ignore keypresses when clipboard is focused
363 GuacamoleUI.clipboard.onfocus = function() {
367 // Capture keypresses when clipboard is not focused
368 GuacamoleUI.clipboard.onblur = function() {
372 // Server copy handler
373 guac.onclipboard = function(data) {
374 GuacamoleUI.clipboard.value = data;
377 GuacamoleUI.keyboard.setKeyPressedHandler(
379 guac.sendKeyEvent(1, keysym);
383 GuacamoleUI.keyboard.setKeyReleasedHandler(
385 guac.sendKeyEvent(0, keysym);
389 // Send Ctrl-Alt-Delete
390 GuacamoleUI.buttons.ctrlAltDelete.onclick = function() {
392 var KEYSYM_CTRL = 0xFFE3;
393 var KEYSYM_ALT = 0xFFE9;
394 var KEYSYM_DELETE = 0xFFFF;
396 guac.sendKeyEvent(1, KEYSYM_CTRL);
397 guac.sendKeyEvent(1, KEYSYM_ALT);
398 guac.sendKeyEvent(1, KEYSYM_DELETE);
399 guac.sendKeyEvent(0, KEYSYM_DELETE);
400 guac.sendKeyEvent(0, KEYSYM_ALT);
401 guac.sendKeyEvent(0, KEYSYM_CTRL);