GUAC-919: Copy Angular changes from old GUAC-546 branch.
This commit is contained in:
1 parent
ac2617b92a
commit
5c43ae4ff9
84 files changed
+16551
-7476
No files matched your search
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,25 +0,0 @@
|
||||
Copyright © 2014 [Eli Grey][1].
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
[1]: http://eligrey.com
|
||||
@@ -1,197 +0,0 @@
|
||||
/* Blob.js
|
||||
* A Blob implementation.
|
||||
* 2014-07-24
|
||||
*
|
||||
* By Eli Grey, http://eligrey.com
|
||||
* By Devin Samarin, https://github.com/dsamarin
|
||||
* License: X11/MIT
|
||||
* See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
/*global self, unescape */
|
||||
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
|
||||
plusplus: true */
|
||||
|
||||
/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
|
||||
|
||||
(function (view) {
|
||||
"use strict";
|
||||
|
||||
view.URL = view.URL || view.webkitURL;
|
||||
|
||||
if (view.Blob && view.URL) {
|
||||
try {
|
||||
new Blob;
|
||||
return;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Internally we use a BlobBuilder implementation to base Blob off of
|
||||
// in order to support older browsers that only have BlobBuilder
|
||||
var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
|
||||
var
|
||||
get_class = function(object) {
|
||||
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
|
||||
}
|
||||
, FakeBlobBuilder = function BlobBuilder() {
|
||||
this.data = [];
|
||||
}
|
||||
, FakeBlob = function Blob(data, type, encoding) {
|
||||
this.data = data;
|
||||
this.size = data.length;
|
||||
this.type = type;
|
||||
this.encoding = encoding;
|
||||
}
|
||||
, FBB_proto = FakeBlobBuilder.prototype
|
||||
, FB_proto = FakeBlob.prototype
|
||||
, FileReaderSync = view.FileReaderSync
|
||||
, FileException = function(type) {
|
||||
this.code = this[this.name = type];
|
||||
}
|
||||
, file_ex_codes = (
|
||||
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
|
||||
+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
|
||||
).split(" ")
|
||||
, file_ex_code = file_ex_codes.length
|
||||
, real_URL = view.URL || view.webkitURL || view
|
||||
, real_create_object_URL = real_URL.createObjectURL
|
||||
, real_revoke_object_URL = real_URL.revokeObjectURL
|
||||
, URL = real_URL
|
||||
, btoa = view.btoa
|
||||
, atob = view.atob
|
||||
|
||||
, ArrayBuffer = view.ArrayBuffer
|
||||
, Uint8Array = view.Uint8Array
|
||||
|
||||
, origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/
|
||||
;
|
||||
FakeBlob.fake = FB_proto.fake = true;
|
||||
while (file_ex_code--) {
|
||||
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
|
||||
}
|
||||
// Polyfill URL
|
||||
if (!real_URL.createObjectURL) {
|
||||
URL = view.URL = function(uri) {
|
||||
var
|
||||
uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
|
||||
, uri_origin
|
||||
;
|
||||
uri_info.href = uri;
|
||||
if (!("origin" in uri_info)) {
|
||||
if (uri_info.protocol.toLowerCase() === "data:") {
|
||||
uri_info.origin = null;
|
||||
} else {
|
||||
uri_origin = uri.match(origin);
|
||||
uri_info.origin = uri_origin && uri_origin[1];
|
||||
}
|
||||
}
|
||||
return uri_info;
|
||||
};
|
||||
}
|
||||
URL.createObjectURL = function(blob) {
|
||||
var
|
||||
type = blob.type
|
||||
, data_URI_header
|
||||
;
|
||||
if (type === null) {
|
||||
type = "application/octet-stream";
|
||||
}
|
||||
if (blob instanceof FakeBlob) {
|
||||
data_URI_header = "data:" + type;
|
||||
if (blob.encoding === "base64") {
|
||||
return data_URI_header + ";base64," + blob.data;
|
||||
} else if (blob.encoding === "URI") {
|
||||
return data_URI_header + "," + decodeURIComponent(blob.data);
|
||||
} if (btoa) {
|
||||
return data_URI_header + ";base64," + btoa(blob.data);
|
||||
} else {
|
||||
return data_URI_header + "," + encodeURIComponent(blob.data);
|
||||
}
|
||||
} else if (real_create_object_URL) {
|
||||
return real_create_object_URL.call(real_URL, blob);
|
||||
}
|
||||
};
|
||||
URL.revokeObjectURL = function(object_URL) {
|
||||
if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
|
||||
real_revoke_object_URL.call(real_URL, object_URL);
|
||||
}
|
||||
};
|
||||
FBB_proto.append = function(data/*, endings*/) {
|
||||
var bb = this.data;
|
||||
// decode data to a binary string
|
||||
if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
|
||||
var
|
||||
str = ""
|
||||
, buf = new Uint8Array(data)
|
||||
, i = 0
|
||||
, buf_len = buf.length
|
||||
;
|
||||
for (; i < buf_len; i++) {
|
||||
str += String.fromCharCode(buf[i]);
|
||||
}
|
||||
bb.push(str);
|
||||
} else if (get_class(data) === "Blob" || get_class(data) === "File") {
|
||||
if (FileReaderSync) {
|
||||
var fr = new FileReaderSync;
|
||||
bb.push(fr.readAsBinaryString(data));
|
||||
} else {
|
||||
// async FileReader won't work as BlobBuilder is sync
|
||||
throw new FileException("NOT_READABLE_ERR");
|
||||
}
|
||||
} else if (data instanceof FakeBlob) {
|
||||
if (data.encoding === "base64" && atob) {
|
||||
bb.push(atob(data.data));
|
||||
} else if (data.encoding === "URI") {
|
||||
bb.push(decodeURIComponent(data.data));
|
||||
} else if (data.encoding === "raw") {
|
||||
bb.push(data.data);
|
||||
}
|
||||
} else {
|
||||
if (typeof data !== "string") {
|
||||
data += ""; // convert unsupported types to strings
|
||||
}
|
||||
// decode UTF-16 to binary string
|
||||
bb.push(unescape(encodeURIComponent(data)));
|
||||
}
|
||||
};
|
||||
FBB_proto.getBlob = function(type) {
|
||||
if (!arguments.length) {
|
||||
type = null;
|
||||
}
|
||||
return new FakeBlob(this.data.join(""), type, "raw");
|
||||
};
|
||||
FBB_proto.toString = function() {
|
||||
return "[object BlobBuilder]";
|
||||
};
|
||||
FB_proto.slice = function(start, end, type) {
|
||||
var args = arguments.length;
|
||||
if (args < 3) {
|
||||
type = null;
|
||||
}
|
||||
return new FakeBlob(
|
||||
this.data.slice(start, args > 1 ? end : this.data.length)
|
||||
, type
|
||||
, this.encoding
|
||||
);
|
||||
};
|
||||
FB_proto.toString = function() {
|
||||
return "[object Blob]";
|
||||
};
|
||||
FB_proto.close = function() {
|
||||
this.size = 0;
|
||||
delete this.data;
|
||||
};
|
||||
return FakeBlobBuilder;
|
||||
}(view));
|
||||
|
||||
view.Blob = function(blobParts, options) {
|
||||
var type = options ? (options.type || "") : "";
|
||||
var builder = new BlobBuilder();
|
||||
if (blobParts) {
|
||||
for (var i = 0, len = blobParts.length; i < len; i++) {
|
||||
builder.append(blobParts[i]);
|
||||
}
|
||||
}
|
||||
return builder.getBlob(type);
|
||||
};
|
||||
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));
|
||||
@@ -1,30 +0,0 @@
|
||||
This software is licensed under the MIT/X11 license.
|
||||
|
||||
MIT/X11 license
|
||||
---------------
|
||||
|
||||
Copyright © 2011 [Eli Grey][1].
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
[1]: http://eligrey.com
|
||||
@@ -1,216 +0,0 @@
|
||||
/* FileSaver.js
|
||||
* A saveAs() FileSaver implementation.
|
||||
* 2013-01-23
|
||||
*
|
||||
* By Eli Grey, http://eligrey.com
|
||||
* License: X11/MIT
|
||||
* See LICENSE.md
|
||||
*/
|
||||
|
||||
/*global self */
|
||||
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
|
||||
plusplus: true */
|
||||
|
||||
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
|
||||
|
||||
var saveAs = saveAs
|
||||
|| (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator))
|
||||
|| (function(view) {
|
||||
"use strict";
|
||||
var
|
||||
doc = view.document
|
||||
// only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
|
||||
, get_URL = function() {
|
||||
return view.URL || view.webkitURL || view;
|
||||
}
|
||||
, URL = view.URL || view.webkitURL || view
|
||||
, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
|
||||
, can_use_save_link = "download" in save_link
|
||||
, click = function(node) {
|
||||
var event = doc.createEvent("MouseEvents");
|
||||
event.initMouseEvent(
|
||||
"click", true, false, view, 0, 0, 0, 0, 0
|
||||
, false, false, false, false, 0, null
|
||||
);
|
||||
node.dispatchEvent(event);
|
||||
}
|
||||
, webkit_req_fs = view.webkitRequestFileSystem
|
||||
, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
|
||||
, throw_outside = function (ex) {
|
||||
(view.setImmediate || view.setTimeout)(function() {
|
||||
throw ex;
|
||||
}, 0);
|
||||
}
|
||||
, force_saveable_type = "application/octet-stream"
|
||||
, fs_min_size = 0
|
||||
, deletion_queue = []
|
||||
, process_deletion_queue = function() {
|
||||
var i = deletion_queue.length;
|
||||
while (i--) {
|
||||
var file = deletion_queue[i];
|
||||
if (typeof file === "string") { // file is an object URL
|
||||
URL.revokeObjectURL(file);
|
||||
} else { // file is a File
|
||||
file.remove();
|
||||
}
|
||||
}
|
||||
deletion_queue.length = 0; // clear queue
|
||||
}
|
||||
, dispatch = function(filesaver, event_types, event) {
|
||||
event_types = [].concat(event_types);
|
||||
var i = event_types.length;
|
||||
while (i--) {
|
||||
var listener = filesaver["on" + event_types[i]];
|
||||
if (typeof listener === "function") {
|
||||
try {
|
||||
listener.call(filesaver, event || filesaver);
|
||||
} catch (ex) {
|
||||
throw_outside(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
, FileSaver = function(blob, name) {
|
||||
// First try a.download, then web filesystem, then object URLs
|
||||
var
|
||||
filesaver = this
|
||||
, type = blob.type
|
||||
, blob_changed = false
|
||||
, object_url
|
||||
, target_view
|
||||
, get_object_url = function() {
|
||||
var object_url = get_URL().createObjectURL(blob);
|
||||
deletion_queue.push(object_url);
|
||||
return object_url;
|
||||
}
|
||||
, dispatch_all = function() {
|
||||
dispatch(filesaver, "writestart progress write writeend".split(" "));
|
||||
}
|
||||
// on any filesys errors revert to saving with object URLs
|
||||
, fs_error = function() {
|
||||
// don't create more object URLs than needed
|
||||
if (blob_changed || !object_url) {
|
||||
object_url = get_object_url(blob);
|
||||
}
|
||||
if (target_view) {
|
||||
target_view.location.href = object_url;
|
||||
} else {
|
||||
window.open(object_url, "_blank");
|
||||
}
|
||||
filesaver.readyState = filesaver.DONE;
|
||||
dispatch_all();
|
||||
}
|
||||
, abortable = function(func) {
|
||||
return function() {
|
||||
if (filesaver.readyState !== filesaver.DONE) {
|
||||
return func.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
, create_if_not_found = {create: true, exclusive: false}
|
||||
, slice
|
||||
;
|
||||
filesaver.readyState = filesaver.INIT;
|
||||
if (!name) {
|
||||
name = "download";
|
||||
}
|
||||
if (can_use_save_link) {
|
||||
object_url = get_object_url(blob);
|
||||
save_link.href = object_url;
|
||||
save_link.download = name;
|
||||
click(save_link);
|
||||
filesaver.readyState = filesaver.DONE;
|
||||
dispatch_all();
|
||||
return;
|
||||
}
|
||||
// Object and web filesystem URLs have a problem saving in Google Chrome when
|
||||
// viewed in a tab, so I force save with application/octet-stream
|
||||
// http://code.google.com/p/chromium/issues/detail?id=91158
|
||||
if (view.chrome && type && type !== force_saveable_type) {
|
||||
slice = blob.slice || blob.webkitSlice;
|
||||
blob = slice.call(blob, 0, blob.size, force_saveable_type);
|
||||
blob_changed = true;
|
||||
}
|
||||
// Since I can't be sure that the guessed media type will trigger a download
|
||||
// in WebKit, I append .download to the filename.
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=65440
|
||||
if (webkit_req_fs && name !== "download") {
|
||||
name += ".download";
|
||||
}
|
||||
if (type === force_saveable_type || webkit_req_fs) {
|
||||
target_view = view;
|
||||
}
|
||||
if (!req_fs) {
|
||||
fs_error();
|
||||
return;
|
||||
}
|
||||
fs_min_size += blob.size;
|
||||
req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
|
||||
fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
|
||||
var save = function() {
|
||||
dir.getFile(name, create_if_not_found, abortable(function(file) {
|
||||
file.createWriter(abortable(function(writer) {
|
||||
writer.onwriteend = function(event) {
|
||||
target_view.location.href = file.toURL();
|
||||
deletion_queue.push(file);
|
||||
filesaver.readyState = filesaver.DONE;
|
||||
dispatch(filesaver, "writeend", event);
|
||||
};
|
||||
writer.onerror = function() {
|
||||
var error = writer.error;
|
||||
if (error.code !== error.ABORT_ERR) {
|
||||
fs_error();
|
||||
}
|
||||
};
|
||||
"writestart progress write abort".split(" ").forEach(function(event) {
|
||||
writer["on" + event] = filesaver["on" + event];
|
||||
});
|
||||
writer.write(blob);
|
||||
filesaver.abort = function() {
|
||||
writer.abort();
|
||||
filesaver.readyState = filesaver.DONE;
|
||||
};
|
||||
filesaver.readyState = filesaver.WRITING;
|
||||
}), fs_error);
|
||||
}), fs_error);
|
||||
};
|
||||
dir.getFile(name, {create: false}, abortable(function(file) {
|
||||
// delete file if it already exists
|
||||
file.remove();
|
||||
save();
|
||||
}), abortable(function(ex) {
|
||||
if (ex.code === ex.NOT_FOUND_ERR) {
|
||||
save();
|
||||
} else {
|
||||
fs_error();
|
||||
}
|
||||
}));
|
||||
}), fs_error);
|
||||
}), fs_error);
|
||||
}
|
||||
, FS_proto = FileSaver.prototype
|
||||
, saveAs = function(blob, name) {
|
||||
return new FileSaver(blob, name);
|
||||
}
|
||||
;
|
||||
FS_proto.abort = function() {
|
||||
var filesaver = this;
|
||||
filesaver.readyState = filesaver.DONE;
|
||||
dispatch(filesaver, "abort");
|
||||
};
|
||||
FS_proto.readyState = FS_proto.INIT = 0;
|
||||
FS_proto.WRITING = 1;
|
||||
FS_proto.DONE = 2;
|
||||
|
||||
FS_proto.error =
|
||||
FS_proto.onwritestart =
|
||||
FS_proto.onprogress =
|
||||
FS_proto.onwrite =
|
||||
FS_proto.onabort =
|
||||
FS_proto.onerror =
|
||||
FS_proto.onwriteend =
|
||||
null;
|
||||
|
||||
view.addEventListener("unload", process_deletion_queue, false);
|
||||
return saveAs;
|
||||
}(self));
|
||||
@@ -1,400 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* General set of UI elements and UI-related functions regarding user login and
|
||||
* connection management.
|
||||
*/
|
||||
var GuacamoleRootUI = {
|
||||
|
||||
"sections": {
|
||||
"login_form" : document.getElementById("login-form"),
|
||||
"recent_connections" : document.getElementById("recent-connections"),
|
||||
"all_connections" : document.getElementById("all-connections")
|
||||
},
|
||||
|
||||
"messages": {
|
||||
"login_error" : document.getElementById("login-error"),
|
||||
"no_recent_connections" : document.getElementById("no-recent")
|
||||
},
|
||||
|
||||
"fields": {
|
||||
"username" : document.getElementById("username"),
|
||||
"password" : document.getElementById("password"),
|
||||
},
|
||||
|
||||
"buttons": {
|
||||
"login" : document.getElementById("login"),
|
||||
"logout" : document.getElementById("logout"),
|
||||
"manage" : document.getElementById("manage")
|
||||
},
|
||||
|
||||
"views": {
|
||||
"login" : document.getElementById("login-ui"),
|
||||
"connections" : document.getElementById("connection-list-ui")
|
||||
},
|
||||
|
||||
"parameters" : null
|
||||
|
||||
};
|
||||
|
||||
// Get parameters from query string
|
||||
GuacamoleRootUI.parameters = window.location.search.substring(1) || null;
|
||||
|
||||
/**
|
||||
* A connection UI object which can be easily added to a list of connections
|
||||
* for sake of display.
|
||||
*
|
||||
* @param {String} id The ID of this object, including prefix.
|
||||
* @param {String} name The name that should be displayed.
|
||||
*/
|
||||
GuacamoleRootUI.RecentConnection = function(id, name) {
|
||||
|
||||
/**
|
||||
* The ID of this object, including prefix.
|
||||
* @type String
|
||||
*/
|
||||
this.id = id;
|
||||
|
||||
/**
|
||||
* The displayable name of this object.
|
||||
* @type String
|
||||
*/
|
||||
this.name = name;
|
||||
|
||||
// Create connection display elements
|
||||
var element = GuacUI.createElement("div", "connection");
|
||||
var thumbnail = GuacUI.createChildElement(element, "div", "thumbnail");
|
||||
var caption = GuacUI.createChildElement(element, "div", "caption");
|
||||
var name_element = GuacUI.createChildElement(caption, "span", "name");
|
||||
|
||||
// Connect on click
|
||||
element.addEventListener("click", function(e) {
|
||||
|
||||
// Prevent click from affecting parent
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
// Open connection
|
||||
GuacUI.openObject(id, GuacamoleRootUI.parameters);
|
||||
|
||||
}, false);
|
||||
|
||||
// Set name
|
||||
name_element.textContent = name;
|
||||
|
||||
// Add screenshot if available
|
||||
var thumbnail_url = GuacamoleHistory.get(id).thumbnail;
|
||||
if (thumbnail_url) {
|
||||
|
||||
// Create thumbnail element
|
||||
var thumb_img = GuacUI.createChildElement(thumbnail, "img");
|
||||
thumb_img.src = thumbnail_url;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DOM element representing this connection.
|
||||
*/
|
||||
this.getElement = function() {
|
||||
return element;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the thumbnail URL of this existing connection. Note that this will
|
||||
* only work if the connection already had a thumbnail associated with it.
|
||||
*/
|
||||
this.setThumbnail = function(url) {
|
||||
|
||||
// If no image element, create it
|
||||
if (!thumb_img) {
|
||||
thumb_img = document.createElement("img");
|
||||
thumb_img.src = url;
|
||||
thumbnail.appendChild(thumb_img);
|
||||
}
|
||||
|
||||
// Otherwise, set source of existing
|
||||
else
|
||||
thumb_img.src = url;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Set of all thumbnailed connections, indexed by ID. Here, each connection
|
||||
* is a GuacamoleRootUI.RecentConnection.
|
||||
*/
|
||||
GuacamoleRootUI.recentConnections = {};
|
||||
|
||||
/**
|
||||
* Set of all connections, indexed by ID. Each connection is a
|
||||
* GuacamoleService.Connection.
|
||||
*/
|
||||
GuacamoleRootUI.connections = {};
|
||||
|
||||
/**
|
||||
* Adds the given RecentConnection to the recent connections list.
|
||||
*/
|
||||
GuacamoleRootUI.addRecentConnection = function(id, name) {
|
||||
|
||||
// Create recent connection object
|
||||
var connection = new GuacamoleRootUI.RecentConnection(id, name);
|
||||
|
||||
// Add connection object to list of thumbnailed connections
|
||||
GuacamoleRootUI.recentConnections[connection.id] =
|
||||
connection;
|
||||
|
||||
// Add connection to recent list
|
||||
GuacamoleRootUI.sections.recent_connections.appendChild(
|
||||
connection.getElement());
|
||||
|
||||
// Hide "No recent connections" message
|
||||
GuacamoleRootUI.messages.no_recent_connections.style.display = "none";
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Resets the interface such that the login UI is displayed if
|
||||
* the user is not authenticated (or authentication fails) and
|
||||
* the connection list UI (or the client for the only available
|
||||
* connection, if there is only one) is displayed if the user is
|
||||
* authenticated.
|
||||
*/
|
||||
GuacamoleRootUI.reset = function() {
|
||||
|
||||
function hasEntry(object) {
|
||||
for (var name in object)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read root group
|
||||
var root_group;
|
||||
try {
|
||||
root_group = GuacamoleService.Connections.list(GuacamoleRootUI.parameters);
|
||||
|
||||
// Show admin elements if admin permissions available
|
||||
var permissions = GuacamoleService.Permissions.list(null, GuacamoleRootUI.parameters);
|
||||
if (permissions.administer
|
||||
|| permissions.create_connection
|
||||
|| permissions.create_user
|
||||
|| hasEntry(permissions.update_user)
|
||||
|| hasEntry(permissions.remove_user)
|
||||
|| hasEntry(permissions.administer_user)
|
||||
|| hasEntry(permissions.update_connection)
|
||||
|| hasEntry(permissions.remove_connection)
|
||||
|| hasEntry(permissions.administer_connection))
|
||||
GuacUI.addClass(document.body, "admin");
|
||||
else
|
||||
GuacUI.removeClass(document.body, "admin");
|
||||
|
||||
}
|
||||
catch (e) {
|
||||
|
||||
// Show login UI if unable to get connections
|
||||
GuacamoleRootUI.views.login.style.display = "";
|
||||
GuacamoleRootUI.views.connections.style.display = "none";
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Create group view
|
||||
var group_view = new GuacUI.GroupView(root_group, GuacUI.GroupView.SHOW_CONNECTIONS);
|
||||
GuacamoleRootUI.sections.all_connections.appendChild(group_view.getElement());
|
||||
|
||||
// Add any connections with thumbnails
|
||||
for (var connection_id in group_view.connections) {
|
||||
|
||||
// Get corresponding connection
|
||||
var connection = group_view.connections[connection_id];
|
||||
|
||||
// If thumbnail exists, add to recent connections
|
||||
if (GuacamoleHistory.get("c/" + connection_id).thumbnail)
|
||||
GuacamoleRootUI.addRecentConnection("c/" + connection_id, connection.name);
|
||||
|
||||
}
|
||||
|
||||
// Add any groups with thumbnails
|
||||
for (var group_id in group_view.groups) {
|
||||
|
||||
// Get corresponding group
|
||||
var group = group_view.groups[group_id];
|
||||
|
||||
// If thumbnail exists, add to recent connections
|
||||
if (GuacamoleHistory.get("g/" + group_id).thumbnail)
|
||||
GuacamoleRootUI.addRecentConnection("g/" + group_id, group.name);
|
||||
|
||||
}
|
||||
|
||||
// Open connections when clicked
|
||||
group_view.onconnectionclick = function(connection) {
|
||||
GuacUI.openConnection(connection.id, GuacamoleRootUI.parameters);
|
||||
};
|
||||
|
||||
// Open connection groups when clicked
|
||||
group_view.ongroupclick = function(group) {
|
||||
|
||||
// Connect if balancing
|
||||
if (group.type === GuacamoleService.ConnectionGroup.Type.BALANCING)
|
||||
GuacUI.openConnectionGroup(group.id, GuacamoleRootUI.parameters);
|
||||
|
||||
};
|
||||
|
||||
// Save all connections for later reference
|
||||
GuacamoleRootUI.connections = group_view.connections;
|
||||
|
||||
// If connections could be retrieved, display list
|
||||
GuacamoleRootUI.views.login.style.display = "none";
|
||||
GuacamoleRootUI.views.connections.style.display = "";
|
||||
|
||||
};
|
||||
|
||||
GuacamoleHistory.onchange = function(id, old_entry, new_entry) {
|
||||
|
||||
// Get existing connection, if any
|
||||
var connection = GuacamoleRootUI.recentConnections[id];
|
||||
|
||||
// If we are adding or updating a connection
|
||||
if (new_entry) {
|
||||
|
||||
// Ensure connection is added
|
||||
if (!connection) {
|
||||
|
||||
// If connection not actually defined, storage must be being
|
||||
// modified externally. Stop early.
|
||||
if (!GuacamoleRootUI.connections[id]) return;
|
||||
|
||||
// Create new connection
|
||||
GuacamoleRootUI.addRecentConnection(id, connection.name);
|
||||
|
||||
}
|
||||
|
||||
// Set new thumbnail
|
||||
connection.setThumbnail(new_entry.thumbnail);
|
||||
|
||||
}
|
||||
|
||||
// Otherwise, delete existing connection
|
||||
else {
|
||||
|
||||
GuacamoleRootUI.sections.recent_connections.removeChild(
|
||||
connection.getElement());
|
||||
|
||||
delete GuacamoleRootUI.recentConnections[id];
|
||||
|
||||
// Display "No recent connections" message if none left
|
||||
if (GuacamoleRootUI.recentConnections.length === 0)
|
||||
GuacamoleRootUI.messages.no_recent_connections.style.display = "";
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* This window has no name. We need it to have no name. If someone navigates
|
||||
* to the root UI within the same window as a previous connection, we need to
|
||||
* remove the name from that window such that new attempts to use that previous
|
||||
* connection do not replace the contents of this very window.
|
||||
*/
|
||||
window.name = "";
|
||||
|
||||
/*
|
||||
* Set handler for logout
|
||||
*/
|
||||
|
||||
GuacamoleRootUI.buttons.logout.onclick = function() {
|
||||
window.location.href = "logout";
|
||||
};
|
||||
|
||||
/*
|
||||
* Set handler for admin
|
||||
*/
|
||||
|
||||
GuacamoleRootUI.buttons.manage.onclick = function() {
|
||||
window.location.href = "admin.xhtml";
|
||||
};
|
||||
|
||||
/*
|
||||
* Set handler for login
|
||||
*/
|
||||
|
||||
GuacamoleRootUI.sections.login_form.onsubmit = function() {
|
||||
|
||||
try {
|
||||
|
||||
GuacUI.removeClass(GuacamoleRootUI.views.login, "error");
|
||||
|
||||
// Attempt login
|
||||
GuacamoleService.Auth.login(
|
||||
GuacamoleRootUI.fields.username.value,
|
||||
GuacamoleRootUI.fields.password.value
|
||||
);
|
||||
|
||||
// Ensure username/password fields are blurred after login attempt
|
||||
GuacamoleRootUI.fields.username.blur();
|
||||
GuacamoleRootUI.fields.password.blur();
|
||||
|
||||
// Reset UI
|
||||
GuacamoleRootUI.reset();
|
||||
|
||||
}
|
||||
catch (e) {
|
||||
|
||||
window.setTimeout(function() {
|
||||
|
||||
// Display error
|
||||
GuacUI.addClass(GuacamoleRootUI.views.login, "error");
|
||||
GuacamoleRootUI.messages.login_error.textContent = e.message;
|
||||
|
||||
// Reset and refocus password field
|
||||
GuacamoleRootUI.fields.password.value = "";
|
||||
GuacamoleRootUI.fields.password.focus();
|
||||
|
||||
}, 1);
|
||||
|
||||
}
|
||||
|
||||
// Always cancel submit
|
||||
return false;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Turn off autocorrect and autocapitalization on usename
|
||||
*/
|
||||
|
||||
GuacamoleRootUI.fields.username.setAttribute("autocorrect", "off");
|
||||
GuacamoleRootUI.fields.username.setAttribute("autocapitalize", "off");
|
||||
|
||||
/*
|
||||
* Initialize UI
|
||||
*/
|
||||
|
||||
GuacamoleRootUI.reset();
|
||||
|
||||
/*
|
||||
* Make sure body has an associated touch event handler such that CSS styles
|
||||
* will work in browsers that require this.
|
||||
*/
|
||||
document.body.ontouchstart = function() {};
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user