Added name handler
[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-icon-64.png"/>
25         <link rel="stylesheet" type="text/css" href="guacamole.css"/>
26         <link rel="stylesheet" type="text/css" href="guac-web-lib/css/guacamole.css"/>
27         <link rel="stylesheet" type="text/css" href="keyboard.css"/>
28         <title>Guacamole</title>
29     </head>
30
31     <body>
32
33         <div id="login-ui">
34             <div id="login-dialog-middle">
35
36                 <div id="login-logo">
37                     <img src="images/login-logo.png" alt="\_GUAC_/"/>
38                 </div>
39
40                 <div id="login-dialog">
41
42                     <h1>Guacamole Login</h1>
43
44                     <p id="login-error"></p>
45
46                     <form id="login-form" action="login" method="post">
47                         <table id="login-fields">
48                             <tr>
49                                 <th>Username</th>
50                                 <td><input type="text" name="username" id="username"/></td>
51                             </tr>
52                             <tr>
53                                 <th>Password</th>
54                                 <td><input type="password" name="password" id="password"/></td>
55                             </tr>
56                         </table>
57
58                         <div id="buttons">
59                             <input type="submit" name="login" id="login" value="Login"/>
60                         </div>
61                     </form>
62                 </div>
63
64             </div>
65         </div>
66
67         <!-- Main UI - hidden until login succeeds -->
68         <div id="main-guacamole-ui" style="display: none">
69
70             <!-- Menu -->
71             <div id="menu">
72
73                 <!-- Clipboard -->
74                 <button id="showClipboard">Show Clipboard</button>
75                 <div id="clipboardDiv">
76                     <h2>Clipboard</h2>
77                     <p>
78                     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.
79                     </p>
80                     <textarea rows="10" cols="40" id="clipboard"></textarea>
81                 </div>
82
83                 <button id="showKeyboard">Show Keyboard</button>
84                 <button id="CtrlAltDelete">Ctrl-Alt-Delete</button>
85
86                 <!-- Logo and status -->
87                 <img id="logo" src="images/guacamole-logo.png" alt="Guacamole" title="__GUAC_VERSION"/>
88                 <span id="state"></span>
89
90                 <a href="agpl-3.0-standalone.html"><img id="license" src="images/agpl-logo.png" alt="AGPLv3"/></a>
91             </div>
92
93
94             <!-- Display -->
95             <div id="display" class="guac-display guac-loading">
96                 <!-- On-screen keyboard -->
97                 <div id="keyboardContainer"></div>
98             </div>
99
100
101             <!-- Error Dialog-->
102             <div id="errorDialog" class="errorDialogOuter">
103                 <div class="errorDialogMiddle">
104                     <div class="errorDialog">
105                         <h1>Error</h1>
106                         <p id="errorText"></p>
107                         <div class="buttons"><button id="reconnect">Reconnect</button></div>
108                     </div>
109                 </div>
110             </div>
111         </div>
112
113
114         <!-- Scripts -->
115         <script type="text/javascript" src="guac-web-lib/javascript/keymap.js"></script>
116         <script type="text/javascript" src="guac-web-lib/javascript/keyboard.js"></script>
117         <script type="text/javascript" src="guac-web-lib/javascript/mouse.js"></script>
118         <script type="text/javascript" src="guac-web-lib/javascript/layer.js"></script>
119         <script type="text/javascript" src="guac-web-lib/javascript/guacamole.js"></script>
120         <script type="text/javascript" src="guac-web-lib/javascript/oskeyboard.js"></script>
121
122         <!-- Init -->
123         <script type="text/javascript"> /* <![CDATA[ */
124
125             var loginForm = document.getElementById("login-form");
126             var loginUI = document.getElementById("login-ui");
127
128             loginForm.onsubmit = function() {
129
130                 var username = document.getElementById("username");
131                 var password = document.getElementById("password");
132
133                 var data =
134                        "username=" + encodeURIComponent(username.value)
135                     + "&password=" + encodeURIComponent(password.value)
136
137                 var xmlhttprequest = new XMLHttpRequest();
138                 xmlhttprequest.open("POST", "login", false);
139                 xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
140                 xmlhttprequest.setRequestHeader("Content-length", data.length);
141                 xmlhttprequest.send(data);
142
143                 if (xmlhttprequest.status == 200) {
144                     loginUI.style.display = "none";
145                     startGuacamole();
146                 }
147                 else {
148
149                     var loginError = document.getElementById("login-error");
150
151                     // Display error, reset and refocus password field
152                     loginError.textContent = "Invalid login. Please try again.";
153                     password.value = "";
154                     password.focus();
155
156                 }
157
158                 return false;
159
160             }
161
162             // Shows guacamole interface and initiates connection to guacamole
163             function startGuacamole() {
164
165                 document.getElementById("main-guacamole-ui").style.display = "block";
166
167                 var menu = document.getElementById("menu");
168                 var display = document.getElementById("display");
169                 var logo = document.getElementById("logo");
170
171                 var errorDialog = document.getElementById("errorDialog");
172                 var errorDialogText = document.getElementById("errorText");
173
174                 // Position display correctly
175                 window.onresize = function() {
176                     display.style.top = menu.offsetHeight + "px";
177                 };
178
179                 window.onresize();
180
181                 // Instantiate client
182                 var guac = new GuacamoleClient(display);
183
184                 var state = document.getElementById("state");
185                 guac.setOnStateChangeHandler(function(clientState) {
186
187                         switch (clientState) {
188                             case 0:
189                                 state.textContent = "Idle."
190                                 break;
191                             case 1:
192                                 state.textContent = "Connecting...";
193                                 break;
194                             case 2:
195                                 state.textContent = "Connected, waiting for first update...";
196                                 break;
197                             case 3:
198                                 display.className = display.className.replace(/guac-loading/, '');
199                                 menu.className = "connected";
200                                 state.textContent = "Connected.";
201                                 break;
202                             case 4:
203                                 state.textContent = "Disconnecting...";
204                                 break;
205                             case 5:
206                                 state.textContent = "Disconnected.";
207                                 break;
208                             default:
209                                 state.textContent = "Unknown";
210                         }
211                 });
212
213                 // Cache error image (might not be available when error occurs)
214                 var guacErrorImage = new Image();
215                 guacErrorImage.src = "images/noguacamole-logo.png";
216
217                 guac.setNameHandler(function(name) {
218                     document.title = name;
219                 });
220
221                 guac.setErrorHandler(function(error) {
222                     menu.className = "error";
223                     logo.src = guacErrorImage.src;
224                     errorDialogText.textContent = error;
225                     errorDialog.style.visibility = "visible";
226                 });
227
228                 // Reconnect button
229                 var reconnect = document.getElementById("reconnect");
230                 reconnect.onclick = function() {
231                     window.location.reload();
232                 };
233
234                 // Connect
235                 guac.connect();
236
237                 // Disconnect on close
238                 window.onunload = function() {
239                     guac.disconnect();
240                 }
241
242                 // Handle clipboard events
243                 var clipboardElement = document.getElementById("clipboard");
244                 clipboardElement.onchange = function() {
245
246                     var text = clipboardElement.value;
247                     guac.setClipboard(text);
248
249                 };
250
251                 // Ignore keypresses when clipboard is focused
252                 clipboardElement.onfocus = function() {
253                     guac.disableKeyboard();
254                 };
255
256                 // Capture keypresses when clipboard is not focused
257                 clipboardElement.onblur = function() {
258                     guac.enableKeyboard();
259                 };
260
261                 // Server copy handler
262                 guac.setClipboardHandler(
263                     function(data) {
264                         clipboardElement.value = data;
265                     }
266                 );
267
268
269                 // Show/Hide clipboard
270                 var clipboardDiv = document.getElementById("clipboardDiv");
271                 var showClipboard = document.getElementById("showClipboard");
272                 showClipboard.onclick = function() {
273
274                     var displayed = clipboardDiv.style.display;
275                     if (displayed != "block") {
276                         clipboardDiv.style.display = "block";
277                         showClipboard.innerHTML = "Hide Clipboard";
278                     }
279                     else {
280                         clipboardDiv.style.display = "none";
281                         showClipboard.innerHTML = "Show Clipboard";
282                         clipboardElement.onchange();
283                     }
284
285                 };
286
287
288                 // Show/Hide keyboard
289                 var keyboardContainer = document.getElementById("keyboardContainer");
290                 var showKeyboard = document.getElementById("showKeyboard");
291                 showKeyboard.onclick = function() {
292
293                     var displayed = keyboardContainer.style.display;
294                     if (displayed != "block") {
295                         keyboardContainer.style.display = "block";
296                         showKeyboard.textContent = "Hide Keyboard";
297                     }
298                     else {
299                         keyboardContainer.style.display = "none";
300                         showKeyboard.textContent = "Show Keyboard";
301                     }
302
303                 };
304
305                 // On-screen keyboard
306                 var osKeyboard = new GuacamoleOnScreenKeyboard("layouts/en-us-qwerty.xml");
307                 keyboardContainer.appendChild(osKeyboard);
308
309                 osKeyboard.setKeyPressedHandler(
310                         function(keysym) {
311                             guac.pressKey(keysym);
312                         }
313                 );
314
315                 osKeyboard.setKeyReleasedHandler(
316                         function(keysym) {
317                             guac.releaseKey(keysym);
318                         }
319                 );
320
321                 // Send Ctrl-Alt-Delete
322                 var CtrlAltDelete = document.getElementById("CtrlAltDelete");
323
324                 CtrlAltDelete.onclick = function() {
325                     guac.pressKey(KEYSYM_CTRL);
326                     guac.pressKey(KEYSYM_ALT);
327                     guac.pressKey(KEYSYM_DELETE);
328                     guac.releaseKey(KEYSYM_DELETE);
329                     guac.releaseKey(KEYSYM_ALT);
330                     guac.releaseKey(KEYSYM_CTRL);
331                 }
332
333             }
334
335             /* ]]> */ </script>
336
337     </body>
338
339 </html>