mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 21:27:40 +00:00
Merge pull request #159 from glyptodon/session-storage
GUAC-1161: Implement session-local storage.
This commit is contained in:
@@ -30,18 +30,34 @@ angular.module('client').factory('guacClientManager', ['$injector',
|
||||
var ManagedClient = $injector.get('ManagedClient');
|
||||
|
||||
// Required services
|
||||
var $window = $injector.get('$window');
|
||||
var $rootScope = $injector.get('$rootScope');
|
||||
var $window = $injector.get('$window');
|
||||
var sessionStorageFactory = $injector.get('sessionStorageFactory');
|
||||
|
||||
var service = {};
|
||||
|
||||
/**
|
||||
* Map of all active managed clients. Each key is the ID of the connection
|
||||
* used by that client.
|
||||
* Getter/setter which retrieves or sets the map of all active managed
|
||||
* clients. Each key is the ID of the connection used by that client.
|
||||
*
|
||||
* @type Object.<String, ManagedClient>
|
||||
* @type Function
|
||||
*/
|
||||
service.managedClients = {};
|
||||
var storedManagedClients = sessionStorageFactory.create({}, function destroyClientStorage() {
|
||||
|
||||
// Disconnect all clients when storage is destroyed
|
||||
service.clear();
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns a map of all active managed clients. Each key is the ID of the
|
||||
* connection used by that client.
|
||||
*
|
||||
* @returns {Object.<String, ManagedClient>}
|
||||
* A map of all active managed clients.
|
||||
*/
|
||||
service.getManagedClients = function getManagedClients() {
|
||||
return storedManagedClients();
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the existing ManagedClient associated with the connection having
|
||||
@@ -55,13 +71,15 @@ angular.module('client').factory('guacClientManager', ['$injector',
|
||||
* true if an existing client was removed, false otherwise.
|
||||
*/
|
||||
service.removeManagedClient = function replaceManagedClient(id) {
|
||||
|
||||
|
||||
var managedClients = storedManagedClients();
|
||||
|
||||
// Remove client if it exists
|
||||
if (id in service.managedClients) {
|
||||
if (id in managedClients) {
|
||||
|
||||
// Disconnect and remove
|
||||
service.managedClients[id].client.disconnect();
|
||||
delete service.managedClients[id];
|
||||
managedClients[id].client.disconnect();
|
||||
delete managedClients[id];
|
||||
|
||||
// A client was removed
|
||||
return true;
|
||||
@@ -96,7 +114,7 @@ angular.module('client').factory('guacClientManager', ['$injector',
|
||||
service.removeManagedClient(id);
|
||||
|
||||
// Set new client
|
||||
return service.managedClients[id] = ManagedClient.getInstance(id, connectionParameters);
|
||||
return storedManagedClients()[id] = ManagedClient.getInstance(id, connectionParameters);
|
||||
|
||||
};
|
||||
|
||||
@@ -119,12 +137,14 @@ angular.module('client').factory('guacClientManager', ['$injector',
|
||||
*/
|
||||
service.getManagedClient = function getManagedClient(id, connectionParameters) {
|
||||
|
||||
var managedClients = storedManagedClients();
|
||||
|
||||
// Create new managed client if it doesn't already exist
|
||||
if (!(id in service.managedClients))
|
||||
service.managedClients[id] = ManagedClient.getInstance(id, connectionParameters);
|
||||
if (!(id in managedClients))
|
||||
managedClients[id] = ManagedClient.getInstance(id, connectionParameters);
|
||||
|
||||
// Return existing client
|
||||
return service.managedClients[id];
|
||||
return managedClients[id];
|
||||
|
||||
};
|
||||
|
||||
@@ -133,23 +153,20 @@ angular.module('client').factory('guacClientManager', ['$injector',
|
||||
*/
|
||||
service.clear = function clear() {
|
||||
|
||||
var managedClients = storedManagedClients();
|
||||
|
||||
// Disconnect each managed client
|
||||
for (var id in service.managedClients)
|
||||
service.managedClients[id].client.disconnect();
|
||||
for (var id in managedClients)
|
||||
managedClients[id].client.disconnect();
|
||||
|
||||
// Clear managed clients
|
||||
service.managedClients = {};
|
||||
storedManagedClients({});
|
||||
|
||||
};
|
||||
|
||||
// Disconnect all clients when window is unloaded
|
||||
$window.addEventListener('unload', service.clear);
|
||||
|
||||
// Clear clients on logout
|
||||
$rootScope.$on('guacLogout', function handleLogout() {
|
||||
service.clear();
|
||||
});
|
||||
|
||||
return service;
|
||||
|
||||
}]);
|
||||
|
@@ -137,11 +137,13 @@ angular.module('home').directive('guacRecentConnections', [function guacRecentCo
|
||||
if (rootGroup)
|
||||
addVisibleConnectionGroup(rootGroup);
|
||||
|
||||
var managedClients = guacClientManager.getManagedClients();
|
||||
|
||||
// Add all active connections
|
||||
for (var id in guacClientManager.managedClients) {
|
||||
for (var id in managedClients) {
|
||||
|
||||
// Get corresponding managed client
|
||||
var client = guacClientManager.managedClients[id];
|
||||
var client = managedClients[id];
|
||||
|
||||
// Add active connections for clients with associated visible objects
|
||||
if (id in visibleObjects) {
|
||||
@@ -157,7 +159,7 @@ angular.module('home').directive('guacRecentConnections', [function guacRecentCo
|
||||
guacHistory.recentConnections.forEach(function addRecentConnection(historyEntry) {
|
||||
|
||||
// Add recent connections for history entries with associated visible objects
|
||||
if (historyEntry.id in visibleObjects && !(historyEntry.id in guacClientManager.managedClients)) {
|
||||
if (historyEntry.id in visibleObjects && !(historyEntry.id in managedClients)) {
|
||||
|
||||
var object = visibleObjects[historyEntry.id];
|
||||
$scope.recentConnections.push(new RecentConnection(object.name, historyEntry));
|
||||
|
@@ -23,4 +23,6 @@
|
||||
/**
|
||||
* The module for code used to display arbitrary notifications.
|
||||
*/
|
||||
angular.module('notification', []);
|
||||
angular.module('notification', [
|
||||
'storage'
|
||||
]);
|
||||
|
@@ -23,34 +23,33 @@
|
||||
/**
|
||||
* Service for displaying notifications and modal status dialogs.
|
||||
*/
|
||||
angular.module('notification').factory('guacNotification', ['$rootScope',
|
||||
function guacNotification($rootScope) {
|
||||
angular.module('notification').factory('guacNotification', ['$injector',
|
||||
function guacNotification($injector) {
|
||||
|
||||
// Required services
|
||||
var $rootScope = $injector.get('$rootScope');
|
||||
var sessionStorageFactory = $injector.get('sessionStorageFactory');
|
||||
|
||||
var service = {};
|
||||
|
||||
/**
|
||||
* The current status notification, or false if no status is currently
|
||||
* shown.
|
||||
* Getter/setter which retrieves or sets the current status notification,
|
||||
* which may simply be false if no status is currently shown.
|
||||
*
|
||||
* @type Function
|
||||
*/
|
||||
var storedStatus = sessionStorageFactory.create(false);
|
||||
|
||||
/**
|
||||
* Retrieves the current status notification, which may simply be false if
|
||||
* no status is currently shown.
|
||||
*
|
||||
* @type Notification|Boolean
|
||||
*/
|
||||
service.status = false;
|
||||
service.getStatus = function getStatus() {
|
||||
return storedStatus();
|
||||
};
|
||||
|
||||
/**
|
||||
* All currently-visible notifications.
|
||||
*
|
||||
* @type Notification[]
|
||||
*/
|
||||
service.notifications = [];
|
||||
|
||||
/**
|
||||
* The ID of the most recently shown notification, or 0 if no notifications
|
||||
* have yet been shown.
|
||||
*
|
||||
* @type Number
|
||||
*/
|
||||
var notificationUniqueID = 0;
|
||||
|
||||
/**
|
||||
* Shows or hides the given notification as a modal status. If a status
|
||||
* notification is currently shown, no further statuses will be shown
|
||||
@@ -77,59 +76,10 @@ angular.module('notification').factory('guacNotification', ['$rootScope',
|
||||
* guacNotification.showStatus(false);
|
||||
*/
|
||||
service.showStatus = function showStatus(status) {
|
||||
if (!service.status || !status)
|
||||
service.status = status;
|
||||
if (!storedStatus() || !status)
|
||||
storedStatus(status);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a notification to the the list of notifications shown.
|
||||
*
|
||||
* @param {Notification|Object} notification
|
||||
* The notification to add.
|
||||
*
|
||||
* @returns {Number}
|
||||
* A unique ID for the notification that's just been added.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* var id = guacNotification.addNotification({
|
||||
* 'title' : 'Download',
|
||||
* 'text' : 'You have a file ready for download!',
|
||||
* 'actions' : {
|
||||
* 'name' : 'download',
|
||||
* 'callback' : function () {
|
||||
* // download the file and remove the notification here
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*/
|
||||
service.addNotification = function addNotification(notification) {
|
||||
var id = ++notificationUniqueID;
|
||||
|
||||
service.notifications.push({
|
||||
notification : notification,
|
||||
id : id
|
||||
});
|
||||
|
||||
return id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a notification by unique ID.
|
||||
*
|
||||
* @param {Number} id
|
||||
* The unique ID of the notification to remove. This ID is retrieved
|
||||
* from the initial call to addNotification.
|
||||
*/
|
||||
service.removeNotification = function removeNotification(id) {
|
||||
for (var i = 0; i < service.notifications.length; i++) {
|
||||
if (service.notifications[i].id === id) {
|
||||
service.notifications.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Hide status upon navigation
|
||||
$rootScope.$on('$routeChangeSuccess', function() {
|
||||
service.showStatus(false);
|
||||
|
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Factory for session-local storage. Creating session-local storage creates a
|
||||
* getter/setter with semantics tied to the user's session. If a user is logged
|
||||
* in, the storage is consistent. If the user logs out, the storage will not
|
||||
* persist new values, and attempts to retrieve the existing value will result
|
||||
* only in the default value.
|
||||
*/
|
||||
angular.module('storage').factory('sessionStorageFactory', ['$injector', function sessionStorageFactory($injector) {
|
||||
|
||||
// Required services
|
||||
var $rootScope = $injector.get('$rootScope');
|
||||
var authenticationService = $injector.get('authenticationService');
|
||||
|
||||
var service = {};
|
||||
|
||||
/**
|
||||
* Creates session-local storage that uses the provided default value or
|
||||
* getter to obtain new values as necessary. Beware that if the default is
|
||||
* an object, the resulting getter provide deep copies for new values.
|
||||
*
|
||||
* @param {Function|*} [template]
|
||||
* The default value for new users, or a getter which returns a newly-
|
||||
* created default value.
|
||||
*
|
||||
* @param {Function} [destructor]
|
||||
* Function which will be called just before the stored value is
|
||||
* destroyed on logout, if a value is stored.
|
||||
*
|
||||
* @returns {Function}
|
||||
* A getter/setter which returns or sets the current value of the new
|
||||
* session-local storage. Newly-set values will only persist of the
|
||||
* user is actually logged in.
|
||||
*/
|
||||
service.create = function create(template, destructor) {
|
||||
|
||||
/**
|
||||
* Whether new values may be stored and retrieved.
|
||||
*
|
||||
* @type Boolean
|
||||
*/
|
||||
var enabled = !!authenticationService.getCurrentToken();
|
||||
|
||||
/**
|
||||
* Getter which returns the default value for this storage.
|
||||
*
|
||||
* @type Function
|
||||
*/
|
||||
var getter;
|
||||
|
||||
// If getter provided, use that
|
||||
if (typeof template === 'function')
|
||||
getter = template;
|
||||
|
||||
// Otherwise, always create a deep copy
|
||||
else
|
||||
getter = function getCopy() {
|
||||
return angular.copy(template);
|
||||
};
|
||||
|
||||
/**
|
||||
* The current value of this storage, or undefined if not yet set.
|
||||
*/
|
||||
var value = undefined;
|
||||
|
||||
// Reset value and allow storage when the user is logged in
|
||||
$rootScope.$on('guacLogin', function userLoggedIn() {
|
||||
enabled = true;
|
||||
value = undefined;
|
||||
});
|
||||
|
||||
// Reset value and disallow storage when the user is logged out
|
||||
$rootScope.$on('guacLogout', function userLoggedOut() {
|
||||
|
||||
// Call destructor before storage is teared down
|
||||
if (angular.isDefined(value) && destructor)
|
||||
destructor(value);
|
||||
|
||||
// Destroy storage
|
||||
enabled = false;
|
||||
value = undefined;
|
||||
|
||||
});
|
||||
|
||||
// Return getter/setter for value
|
||||
return function sessionLocalGetterSetter(newValue) {
|
||||
|
||||
// Only actually store/retrieve values if enabled
|
||||
if (enabled) {
|
||||
|
||||
// Set value if provided
|
||||
if (angular.isDefined(newValue))
|
||||
value = newValue;
|
||||
|
||||
// Obtain new value if unset
|
||||
if (!angular.isDefined(value))
|
||||
value = getter();
|
||||
|
||||
// Return current value
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
// Otherwise, just pretend to store/retrieve
|
||||
return angular.isDefined(newValue) ? newValue : getter();
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
}]);
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2015 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
|
||||
@@ -20,30 +20,9 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#notificationArea {
|
||||
position: fixed;
|
||||
right: 0.5em;
|
||||
bottom: 0.5em;
|
||||
max-width: 25%;
|
||||
width: 2in;
|
||||
}
|
||||
|
||||
#notificationArea .notification {
|
||||
font-size: 0.7em;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#notificationArea .notification .text {
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#notificationArea .notification.error .text {
|
||||
white-space: normal;
|
||||
text-overflow: clip;
|
||||
text-align: left;
|
||||
}
|
||||
/**
|
||||
* Module which provides generic storage services.
|
||||
*/
|
||||
angular.module('storage', [
|
||||
'auth'
|
||||
]);
|
@@ -38,22 +38,15 @@ THE SOFTWARE.
|
||||
<div ng-if="!expectedCredentials">
|
||||
|
||||
<!-- Global status/error dialog -->
|
||||
<div ng-class="{shown: guacNotification.status}" class="status-outer">
|
||||
<div ng-class="{shown: guacNotification.getStatus()}" class="status-outer">
|
||||
<div class="status-middle">
|
||||
<guac-notification notification="guacNotification.status"></guac-notification>
|
||||
<guac-notification notification="guacNotification.getStatus()"></guac-notification>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content" ng-view>
|
||||
</div>
|
||||
|
||||
<!-- Notification area -->
|
||||
<div id="notificationArea">
|
||||
<div ng-repeat="wrapper in guacNotification.notifications">
|
||||
<guac-notification notification="wrapper.notification"></guac-notification>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Login screen for logged-out users -->
|
||||
|
Reference in New Issue
Block a user