UI cleanup, removing unused images.
[guacamole.git] / src / main / webapp / index.html
1 <!DOCTYPE HTML>
2
3 <!--
4     Guacamole - Clientless Remote Desktop
5     Copyright (C) 2010  Michael Jumper
6
7     This program is free software: you can redistribute it and/or modify
8     it under the terms of the GNU Affero General Public License as published by
9     the Free Software Foundation, either version 3 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU Affero General Public License for more details.
16
17     You should have received a copy of the GNU Affero General Public License
18     along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 -->
20
21 <html>
22
23     <head>
24         <link rel="icon" type="image/png" href="images/guacamole-logo-64.png"/>
25         <link rel="stylesheet" type="text/css" href="styles/guacamole.css"/>
26         <link rel="stylesheet" type="text/css" href="styles/keyboard.css"/>
27         <title>Guacamole</title>
28     </head>
29
30     <body>
31
32         <div id="login-ui">
33             <div id="login-dialog-middle">
34
35                 <div id="login-dialog">
36
37                     <p id="login-error"></p>
38
39                     <form id="login-form" action="#" method="post">
40
41                         <div id="login-fields">
42                             <table>
43                                 <tr>
44                                     <th>Username</th>
45                                     <td><input type="text" name="username" id="username"/></td>
46                                 </tr>
47                                 <tr>
48                                     <th>Password</th>
49                                     <td><input type="password" name="password" id="password"/></td>
50                                 </tr>
51                             </table>
52
53                             <img class="logo" src="images/guacamole-logo-64.png" alt=""/>
54                         </div>
55
56                         <div id="buttons">
57                             <input type="submit" name="login" id="login" value="Login"/>
58                         </div>
59
60                     </form>
61                 </div>
62
63                 <div id="version-dialog">
64                     Guacamole ${project.version}
65                 </div>
66
67             </div>
68         </div>
69
70         <!-- Main UI - hidden until login succeeds -->
71         <div id="main-guacamole-ui" style="display: none">
72
73             <!-- Menu -->
74             <div id="menu">
75
76                 <!-- Clipboard -->
77                 <button id="showClipboard">Show Clipboard</button>
78                 <div id="clipboardDiv">
79                     <h2>Clipboard</h2>
80                     <p>
81                     Text copied/cut within Guacamole will appear here. Changes to the text will affect the remote clipboard, and will be pastable within the remote desktop. Use the textbox below as an interface between the client and server clipboards.
82                     </p>
83                     <textarea rows="10" cols="40" id="clipboard"></textarea>
84                 </div>
85
86                 <button id="showKeyboard">Show Keyboard</button>
87                 <button id="CtrlAltDelete">Ctrl-Alt-Delete</button>
88
89                 <!-- Logo and status -->
90                 <img id="status-logo" class="logo" src="images/guacamole-logo-24.png" alt="Guacamole" title="Guacamole ${project.version}"/>
91                 <span id="state"></span>
92
93                 <a href="agpl-3.0-standalone.html"><img id="license" src="images/agpl-logo.png" alt="AGPLv3"/></a>
94             </div>
95
96
97             <!-- Display -->
98             <div id="display" class="guac-display guac-loading">
99                 <!-- On-screen keyboard -->
100                 <div id="keyboardContainer"></div>
101             </div>
102
103
104             <!-- Error Dialog-->
105             <div id="errorDialog" class="errorDialogOuter">
106                 <div class="errorDialogMiddle">
107                     <div class="errorDialog">
108                         <h1>Error</h1>
109                         <p id="errorText"></p>
110                         <div class="buttons"><button id="reconnect">Reconnect</button></div>
111                     </div>
112                 </div>
113             </div>
114         </div>
115
116
117         <!-- Scripts -->
118         <script type="text/javascript" src="guacamole-common-js/keymap.js"></script>
119         <script type="text/javascript" src="guacamole-common-js/keyboard.js"></script>
120         <script type="text/javascript" src="guacamole-common-js/mouse.js"></script>
121         <script type="text/javascript" src="guacamole-common-js/layer.js"></script>
122         <script type="text/javascript" src="guacamole-common-js/tunnel.js"></script>
123         <script type="text/javascript" src="guacamole-common-js/guacamole.js"></script>
124         <script type="text/javascript" src="guacamole-common-js/oskeyboard.js"></script>
125
126         <!-- Init -->
127         <script type="text/javascript"> /* <![CDATA[ */
128
129             var loginForm = document.getElementById("login-form");
130             var loginUI = document.getElementById("login-ui");
131             var display = document.getElementById("display");
132
133             loginForm.onsubmit = function() {
134
135                 var username = document.getElementById("username");
136                 var password = document.getElementById("password");
137
138                 var data =
139                        "username=" + encodeURIComponent(username.value)
140                     + "&password=" + encodeURIComponent(password.value)
141
142                 // Instantiate client
143                 var guac = new GuacamoleClient(
144                     display,
145                     new GuacamoleHTTPTunnel("tunnel")
146                 );
147
148                 try {
149
150                     // Connect client
151                     guac.connect(data);
152
153                 }
154                 catch (e) {
155
156                     var loginError = document.getElementById("login-error");
157
158                     // Display error, reset and refocus password field
159                     loginError.textContent = e.message;
160                     password.value = "";
161                     password.focus();
162
163                     return false;
164
165                 }
166
167                 // On success, display UI
168                 startGuacamole(guac);
169                 return false;
170
171             }
172
173             // Shows guacamole interface and initiates connection to guacamole
174             function startGuacamole(guac) {
175
176                 loginUI.style.display = "none";
177                 document.getElementById("main-guacamole-ui").style.display = "block";
178
179                 var menu = document.getElementById("menu");
180                 var logo = document.getElementById("status-logo");
181
182                 var errorDialog = document.getElementById("errorDialog");
183                 var errorDialogText = document.getElementById("errorText");
184
185                 // Position display correctly
186                 window.onresize = function() {
187                     display.style.top = menu.offsetHeight + "px";
188                 };
189
190                 window.onresize();
191
192                 var state = document.getElementById("state");
193                 guac.setOnStateChangeHandler(function(clientState) {
194
195                         switch (clientState) {
196                             case 0:
197                                 state.textContent = "Idle."
198                                 break;
199                             case 1:
200                                 state.textContent = "Connecting...";
201                                 break;
202                             case 2:
203                                 state.textContent = "Connected, waiting for first update...";
204                                 break;
205                             case 3:
206                                 display.className = display.className.replace(/guac-loading/, '');
207                                 menu.className = "connected";
208                                 state.textContent = "Connected.";
209                                 break;
210                             case 4:
211                                 state.textContent = "Disconnecting...";
212                                 break;
213                             case 5:
214                                 state.textContent = "Disconnected.";
215                                 break;
216                             default:
217                                 state.textContent = "Unknown";
218                         }
219                 });
220
221                 // Cache error image (might not be available when error occurs)
222                 var guacErrorImage = new Image();
223                 guacErrorImage.src = "images/noguacamole-logo-24.png";
224
225                 guac.setNameHandler(function(name) {
226                     document.title = name;
227                 });
228
229                 guac.setErrorHandler(function(error) {
230
231                     guac.disconnect();
232
233                     menu.className = "error";
234                     display.className += " guac-error";
235
236                     logo.src = guacErrorImage.src;
237                     errorDialogText.textContent = error;
238                     errorDialog.style.visibility = "visible";
239
240                     // Show error by desaturating display
241                     var layers = guac.getLayers();
242                     for (var i=0; i<layers.length; i++) {
243                         layers[i].filter(desaturateFilter);
244                     }
245
246                     // Filter for desaturation
247                     function desaturateFilter(data, width, height) {
248
249                         for (var i=0; i<data.length; i+=4) {
250
251                             // Get RGB values
252                             var r = data[i];
253                             var g = data[i+1];
254                             var b = data[i+2];
255
256                             // Desaturate
257                             var v = Math.max(r, g, b) / 2;
258                             data[i]   = v;
259                             data[i+1] = v;
260                             data[i+2] = v;
261
262                         }
263
264                     }
265
266                 });
267
268                 // Mouse
269                 var mouse = new GuacamoleMouse(display);
270                 mouse.setButtonPressedHandler(
271                     function(mouseState) {
272                         guac.sendMouseState(mouseState);
273                     }
274                 );
275
276                 mouse.setButtonReleasedHandler(
277                     function(mouseState) {
278                         guac.sendMouseState(mouseState);
279                     }
280                 );
281
282                 mouse.setMovementHandler(
283                     function(mouseState) {
284                         guac.sendMouseState(mouseState);
285                     }
286                 );
287
288                 // Keyboard
289                 var keyboard = new GuacamoleKeyboard(document);
290
291                 function disableKeyboard() {
292                     keyboard.setKeyPressedHandler(null);
293                     keyboard.setKeyReleasedHandler(null);
294                 }
295
296                 function enableKeyboard() {
297                     keyboard.setKeyPressedHandler(
298                         function (keysym) {
299                             guac.sendKeyEvent(1, keysym);
300                         }
301                     );
302
303                     keyboard.setKeyReleasedHandler(
304                         function (keysym) {
305                             guac.sendKeyEvent(0, keysym);
306                         }
307                     );
308                 }
309
310                 // Enable keyboard by default
311                 enableKeyboard();
312
313                 // Reconnect button
314                 var reconnect = document.getElementById("reconnect");
315                 reconnect.onclick = function() {
316                     window.location.reload();
317                 };
318
319                 // Disconnect on close
320                 window.onunload = function() {
321                     guac.disconnect();
322                 }
323
324                 // Handle clipboard events
325                 var clipboardElement = document.getElementById("clipboard");
326                 clipboardElement.onchange = function() {
327
328                     var text = clipboardElement.value;
329                     guac.setClipboard(text);
330
331                 };
332
333                 // Ignore keypresses when clipboard is focused
334                 clipboardElement.onfocus = function() {
335                     disableKeyboard();
336                 };
337
338                 // Capture keypresses when clipboard is not focused
339                 clipboardElement.onblur = function() {
340                     enableKeyboard();
341                 };
342
343                 // Server copy handler
344                 guac.setClipboardHandler(
345                     function(data) {
346                         clipboardElement.value = data;
347                     }
348                 );
349
350
351                 // Show/Hide clipboard
352                 var clipboardDiv = document.getElementById("clipboardDiv");
353                 var showClipboard = document.getElementById("showClipboard");
354                 showClipboard.onclick = function() {
355
356                     var displayed = clipboardDiv.style.display;
357                     if (displayed != "block") {
358                         clipboardDiv.style.display = "block";
359                         showClipboard.innerHTML = "Hide Clipboard";
360                     }
361                     else {
362                         clipboardDiv.style.display = "none";
363                         showClipboard.innerHTML = "Show Clipboard";
364                         clipboardElement.onchange();
365                     }
366
367                 };
368
369
370                 // Show/Hide keyboard
371                 var keyboardContainer = document.getElementById("keyboardContainer");
372                 var showKeyboard = document.getElementById("showKeyboard");
373                 showKeyboard.onclick = function() {
374
375                     var displayed = keyboardContainer.style.display;
376                     if (displayed != "block") {
377                         keyboardContainer.style.display = "block";
378                         showKeyboard.textContent = "Hide Keyboard";
379                     }
380                     else {
381                         keyboardContainer.style.display = "none";
382                         showKeyboard.textContent = "Show Keyboard";
383                     }
384
385                 };
386
387                 // On-screen keyboard
388                 var osKeyboard = new GuacamoleOnScreenKeyboard("layouts/en-us-qwerty.xml");
389                 keyboardContainer.appendChild(osKeyboard);
390
391                 osKeyboard.setKeyPressedHandler(
392                         function(keysym) {
393                             guac.sendKeyEvent(1, keysym);
394                         }
395                 );
396
397                 osKeyboard.setKeyReleasedHandler(
398                         function(keysym) {
399                             guac.sendKeyEvent(0, keysym);
400                         }
401                 );
402
403                 // Send Ctrl-Alt-Delete
404                 var CtrlAltDelete = document.getElementById("CtrlAltDelete");
405
406                 CtrlAltDelete.onclick = function() {
407                     guac.sendKeyEvent(1, KEYSYM_CTRL);
408                     guac.sendKeyEvent(1, KEYSYM_ALT);
409                     guac.sendKeyEvent(1, KEYSYM_DELETE);
410                     guac.sendKeyEvent(0, KEYSYM_DELETE);
411                     guac.sendKeyEvent(0, KEYSYM_ALT);
412                     guac.sendKeyEvent(0, KEYSYM_CTRL);
413                 }
414
415             }
416
417             /* ]]> */ </script>
418
419     </body>
420
421 </html>