source: OpenRLabs-Git/web2py/applications/rlabs/static/scripts/root-ui.js

main
Last change on this file was 42bd667, checked in by David Fuertes <dfuertes@…>, 4 years ago

Historial Limpio

  • Property mode set to 100644
File size: 13.9 KB
Line 
1
2/*
3 *  Guacamole - Clientless Remote Desktop
4 *  Copyright (C) 2010  Michael Jumper
5 *
6 *  This program is free software: you can redistribute it and/or modify
7 *  it under the terms of the GNU Affero General Public License as published by
8 *  the Free Software Foundation, either version 3 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU Affero General Public License for more details.
15 *
16 *  You should have received a copy of the GNU Affero General Public License
17 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/**
21 * General set of UI elements and UI-related functions regarding user login and
22 * connection management.
23 */
24var GuacamoleRootUI = {
25
26    "sections": {
27        "login_form"         : document.getElementById("login-form"),
28        "recent_connections" : document.getElementById("recent-connections"),
29        "all_connections"  : document.getElementById("all-connections")
30    },
31
32    "messages": {
33        "login_error"           : document.getElementById("login-error"),
34        "no_recent_connections" : document.getElementById("no-recent")
35    },
36
37    "fields": {
38        "username"  : document.getElementById("username"),
39        "password"  : document.getElementById("password"),
40        "clipboard" : document.getElementById("clipboard")
41    },
42   
43    "buttons": {
44        "login"  : document.getElementById("login"),
45        "logout" : document.getElementById("logout")
46    },
47
48    "settings": {
49        "auto_fit"      : document.getElementById("auto-fit"),
50        "disable_sound" : document.getElementById("disable-sound")
51    },
52
53    "views": {
54        "login"       : document.getElementById("login-ui"),
55        "connections" : document.getElementById("connection-list-ui")
56    },
57
58    "session_state" :  new GuacamoleSessionState()
59
60};
61
62/**
63 * Attempts to login the given user using the given password, throwing an
64 * error if the process fails.
65 *
66 * @param {String} username The name of the user to login as.
67 * @param {String} password The password to use to authenticate the user.
68 */
69GuacamoleRootUI.login = function(username, password) {
70
71    // Get parameters from query string
72    var parameters = window.location.search.substring(1);
73
74    // Get username and password from form
75    var data =
76           "username=" + encodeURIComponent(username)
77        + "&password=" + encodeURIComponent(password)
78
79    // Include query parameters in submission data
80    if (parameters) data += "&" + parameters;
81
82    // Log in
83    var xhr = new XMLHttpRequest();
84    xhr.open("POST", "login", false);
85    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
86    xhr.send(data);
87
88    // Handle failures
89    if (xhr.status != 200)
90        throw new Error("Invalid login");
91
92};
93
94/**
95 * An arbitrary Guacamole configuration, consisting of an ID/protocol pair.
96 *
97 * @constructor
98 * @param {String} protocol The protocol used by this configuration.
99 * @param {String} id The ID associated with this configuration.
100 */
101GuacamoleRootUI.Configuration = function(protocol, id) {
102
103    /**
104     * The protocol associated with this configuration.
105     */
106    this.protocol = protocol;
107
108    /**
109     * The ID associated with this configuration.
110     */
111    this.id = id;
112
113};
114
115GuacamoleRootUI.getConfigurations = function(parameters) {
116
117    // Construct request URL
118    var configs_url = "configs";
119    if (parameters) configs_url += "?" + parameters;
120
121    // Get config list
122    var xhr = new XMLHttpRequest();
123    xhr.open("GET", configs_url, false);
124    xhr.send(null);
125
126    // If fail, throw error
127    if (xhr.status != 200)
128        throw new Error(xhr.statusText);
129
130    // Otherwise, get list
131    var configs = new Array();
132
133    var configElements = xhr.responseXML.getElementsByTagName("config");
134    for (var i=0; i<configElements.length; i++) {
135        configs.push(new Config(
136            configElements[i].getAttribute("protocol"),
137            configElements[i].getAttribute("id")
138        ));
139    }
140
141    return configs;
142 
143};
144
145/**
146 * A connection UI object which can be easily added to a list of connections
147 * for sake of display.
148 */
149GuacamoleRootUI.Connection = function(config) {
150
151    /**
152     * The configuration associated with this connection.
153     */
154    this.configuration = config;
155
156    function element(tagname, classname) {
157        var new_element = document.createElement(tagname);
158        new_element.className = classname;
159        return new_element;
160    }
161
162    // Create connection display elements
163    var connection    = element("div",  "connection");
164    var caption       = element("div",  "caption");
165    var protocol      = element("div",  "protocol");
166    var name          = element("span", "name");
167    var protocol_icon = element("div",  "icon " + config.protocol);
168    var thumbnail     = element("div",  "thumbnail");
169    var thumb_img;
170
171    // Get URL
172    var url = "client.xhtml?id=" + encodeURIComponent(config.id);
173
174    // Create link to client
175    connection.onclick = function() {
176
177        // Attempt to focus existing window
178        var current = window.open(null, config.id);
179
180        // If window did not already exist, set up as
181        // Guacamole client
182        if (!current.GuacUI)
183            window.open(url, config.id);
184
185    };
186
187    // Add icon
188    protocol.appendChild(protocol_icon);
189
190    // Set name
191    name.textContent = config.id;
192
193    // Assemble caption
194    caption.appendChild(protocol);
195    caption.appendChild(name);
196
197    // Assemble connection icon
198    connection.appendChild(thumbnail);
199    connection.appendChild(caption);
200
201    // Add screenshot if available
202    var thumbnail_url = GuacamoleHistory.get(config.id).thumbnail;
203    if (thumbnail_url) {
204
205        // Create thumbnail element
206        thumb_img = document.createElement("img");
207        thumb_img.src = thumbnail_url;
208        thumbnail.appendChild(thumb_img);
209
210    }
211
212    /**
213     * Returns the DOM element representing this connection.
214     */
215    this.getElement = function() {
216        return connection;
217    };
218
219    /**
220     * Returns whether this connection has an associated thumbnail.
221     */
222    this.hasThumbnail = function() {
223        return thumb_img && true;
224    };
225
226    /**
227     * Sets the thumbnail URL of this existing connection. Note that this will
228     * only work if the connection already had a thumbnail associated with it.
229     */
230    this.setThumbnail = function(url) {
231
232        // If no image element, create it
233        if (!thumb_img) {
234            thumb_img = document.createElement("img");
235            thumb_img.src = url;
236            thumbnail.appendChild(thumb_img);
237        }
238
239        // Otherwise, set source of existing
240        else
241            thumb_img.src = url;
242
243    };
244
245};
246
247/**
248 * Set of all thumbnailed connections, indexed by ID.
249 */
250GuacamoleRootUI.thumbnailConnections = {};
251
252/**
253 * Set of all configurations, indexed by ID.
254 */
255GuacamoleRootUI.configurations = {};
256
257/**
258 * Adds the given connection to the recent connections list.
259 */
260GuacamoleRootUI.addRecentConnection = function(connection) {
261
262    // Add connection object to list of thumbnailed connections
263    GuacamoleRootUI.thumbnailConnections[connection.configuration.id] =
264        connection;
265   
266    // Add connection to recent list
267    GuacamoleRootUI.sections.recent_connections.appendChild(
268        connection.getElement());
269
270    // Hide "No recent connections" message
271    GuacamoleRootUI.messages.no_recent_connections.style.display = "none";
272
273};
274
275
276/**
277 * Resets the interface such that the login UI is displayed if
278 * the user is not authenticated (or authentication fails) and
279 * the connection list UI (or the client for the only available
280 * connection, if there is only one) is displayed if the user is
281 * authenticated.
282 */
283GuacamoleRootUI.reset = function() {
284
285    // Get parameters from query string
286    var parameters = window.location.search.substring(1);
287
288    // Read configs
289    var configs;
290    try {
291        configs = GuacamoleRootUI.getConfigurations(parameters);
292    }
293    catch (e) {
294
295        // Show login UI if unable to get configs
296        GuacamoleRootUI.views.login.style.display = "";
297        GuacamoleRootUI.views.connections.style.display = "none";
298
299        return;
300
301    }
302
303    // Add connection icons
304    for (var i=0; i<configs.length; i++) {
305
306        // Add configuration to set
307        GuacamoleRootUI.configurations[configs[i].id] = configs[i];
308
309        // Get connection element
310        var connection = new GuacamoleRootUI.Connection(configs[i]);
311
312        // If screenshot present, add to recent connections
313        if (connection.hasThumbnail())
314            GuacamoleRootUI.addRecentConnection(connection);
315
316        // Add connection to connection list
317        GuacamoleRootUI.sections.all_connections.appendChild(
318            new GuacamoleRootUI.Connection(configs[i]).getElement());
319
320    }
321
322    // If configs could be retrieved, display list
323    GuacamoleRootUI.views.login.style.display = "none";
324    GuacamoleRootUI.views.connections.style.display = "";
325
326};
327
328GuacamoleHistory.onchange = function(id, old_entry, new_entry) {
329
330    // Get existing connection, if any
331    var connection = GuacamoleRootUI.thumbnailConnections[id];
332
333    // If we are adding or updating a connection
334    if (new_entry) {
335
336        // Ensure connection is added
337        if (!connection) {
338
339            // Create new connection
340            connection = new GuacamoleRootUI.Connection(
341                GuacamoleRootUI.configurations[id]
342            );
343
344            GuacamoleRootUI.addRecentConnection(connection);
345
346        }
347
348        // Set new thumbnail
349        connection.setThumbnail(new_entry.thumbnail);
350
351    }
352
353    // Otherwise, delete existing connection
354    else {
355
356        GuacamoleRootUI.sections.recent_connections.removeChild(
357            connection.getElement());
358
359        delete GuacamoleRootUI.thumbnailConnections[id];
360
361        // Display "No recent connections" message if none left
362        if (GuacamoleRootUI.thumbnailConnections.length == 0)
363            GuacamoleRootUI.messages.no_recent_connections.style.display = "";
364
365    }
366   
367};
368
369/*
370 * This window has no name. We need it to have no name. If someone navigates
371 * to the root UI within the same window as a previous connection, we need to
372 * remove the name from that window such that new attempts to use that previous
373 * connection do not replace the contents of this very window.
374 */
375window.name = "";
376
377/*
378 * Update session state when auto-fit checkbox is changed
379 */
380
381GuacamoleRootUI.settings.auto_fit.onchange =
382GuacamoleRootUI.settings.auto_fit.onclick  = function() {
383
384    GuacamoleRootUI.session_state.setProperty(
385        "auto-fit", GuacamoleRootUI.settings.auto_fit.checked);
386
387};
388
389/*
390 * Update session state when disable-sound checkbox is changed
391 */
392
393GuacamoleRootUI.settings.disable_sound.onchange =
394GuacamoleRootUI.settings.disable_sound.onclick  = function() {
395
396    GuacamoleRootUI.session_state.setProperty(
397        "disable-sound", GuacamoleRootUI.settings.disable_sound.checked);
398
399};
400
401/*
402 * Update clipboard contents when changed
403 */
404
405window.onblur =
406GuacamoleRootUI.fields.clipboard.onchange = function() {
407
408    // Set value if changed
409    var new_value = GuacamoleRootUI.fields.clipboard.value;
410    if (GuacamoleRootUI.session_state.getProperty("clipboard") != new_value)
411        GuacamoleRootUI.session_state.setProperty("clipboard", new_value);
412
413};
414
415/*
416 * Update element states when session state changes
417 */
418
419GuacamoleRootUI.session_state.onchange =
420function(old_state, new_state, name) {
421
422    // Clipboard
423    if (name == "clipboard")
424        GuacamoleRootUI.fields.clipboard.value = new_state[name];
425
426    // Auto-fit display
427    else if (name == "auto-fit")
428        GuacamoleRootUI.fields.auto_fit.checked = new_state[name];
429
430    // Disable Sound
431    else if (name == "disable-sound")
432        GuacamoleRootUI.fields.disable_sound.checked = new_state[name];
433
434};
435
436/*
437 * Initialize clipboard with current data
438 */
439
440if (GuacamoleRootUI.session_state.getProperty("clipboard"))
441    GuacamoleRootUI.fields.clipboard.value =
442        GuacamoleRootUI.session_state.getProperty("clipboard");
443
444/*
445 * Default to true if auto-fit not specified
446 */
447
448if (GuacamoleRootUI.session_state.getProperty("auto-fit") === undefined)
449    GuacamoleRootUI.session_state.setProperty("auto-fit", true);
450
451/*
452 * Initialize auto-fit setting in UI
453 */
454
455GuacamoleRootUI.settings.auto_fit.checked =
456    GuacamoleRootUI.session_state.getProperty("auto-fit");
457
458/*
459 * Initialize disable-sound setting in UI
460 */
461GuacamoleRootUI.settings.disable_sound.checked =
462    GuacamoleRootUI.session_state.getProperty("disable-sound");
463
464/*
465 * Set handler for logout
466 */
467
468GuacamoleRootUI.buttons.logout.onclick = function() {
469    window.location.href = "logout";
470};
471
472/*
473 * Set handler for login
474 */
475
476GuacamoleRootUI.sections.login_form.onsubmit = function() {
477
478    try {
479
480        // Attempt login
481        GuacamoleRootUI.login(
482            GuacamoleRootUI.fields.username.value,
483            GuacamoleRootUI.fields.password.value
484        );
485
486        // Ensure username/password fields are blurred after login attempt
487        GuacamoleRootUI.fields.username.blur();
488        GuacamoleRootUI.fields.password.blur();
489
490        // Reset UI
491        GuacamoleRootUI.reset();
492
493    }
494    catch (e) {
495
496        // Display error, reset and refocus password field
497        GuacamoleRootUI.messages.login_error.textContent = e.message;
498
499        // Reset and recofus password field
500        GuacamoleRootUI.fields.password.value = "";
501        GuacamoleRootUI.fields.password.focus();
502
503    }
504
505    // Always cancel submit
506    return false;
507
508};
509
510/*
511 * Turn off autocorrect and autocapitalization on usename
512 */
513
514GuacamoleRootUI.fields.username.setAttribute("autocorrect", "off");
515GuacamoleRootUI.fields.username.setAttribute("autocapitalize", "off");
516
517/*
518 * Initialize UI
519 */
520
521GuacamoleRootUI.reset();
522
523/*
524 * Make sure body has an associated touch event handler such that CSS styles
525 * will work in browsers that require this.
526 */
527document.body.ontouchstart = function() {};
Note: See TracBrowser for help on using the repository browser.