diff --git a/guacamole/src/main/frontend/src/app/client/controllers/clientController.js b/guacamole/src/main/frontend/src/app/client/controllers/clientController.js index 2194ce270..d14cda8f6 100644 --- a/guacamole/src/main/frontend/src/app/client/controllers/clientController.js +++ b/guacamole/src/main/frontend/src/app/client/controllers/clientController.js @@ -211,28 +211,43 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams * view. */ updateAttachedClients : function updateAttachedClients(id) { - - // Deconstruct current path into corresponding client IDs - var ids = ManagedClientGroup.getClientIdentifiers($routeParams.id); - - // Add/remove ID as requested - if ($scope.connectionListContext.attachedClients[id]) - ids.push(id); - else - _.pull(ids, id); - - // Reconstruct path, updating attached clients via change in route - $location.path('/client/' + encodeURIComponent(ManagedClientGroup.getIdentifier(ids))); - + $scope.addRemoveClient(id, !$scope.connectionListContext.attachedClients[id]); } }; + /** + * Adds or removes the client with the given ID from the set of clients + * within the current view, updating the current URL accordingly. + * + * @param {string} id + * The ID of the client to add or remove from the current view. + * + * @param {boolean} [remove=false] + * Whether the specified client should be added (false) or removed + * (true). + */ + $scope.addRemoveClient = function addRemoveClient(id, remove) { + + // Deconstruct current path into corresponding client IDs + var ids = ManagedClientGroup.getClientIdentifiers($routeParams.id); + + // Add/remove ID as requested + if (remove) + _.pull(ids, id); + else + ids.push(id); + + // Reconstruct path, updating attached clients via change in route + $location.path('/client/' + encodeURIComponent(ManagedClientGroup.getIdentifier(ids))); + + }; + /** * Reloads the contents of $scope.clientGroup to reflect the client IDs * currently listed in the URL. */ - var updateAttachedClients = function updateAttachedClients() { + var reparseRoute = function reparseRoute() { var previousClients = $scope.clientGroup ? $scope.clientGroup.clients.slice() : []; detachCurrentGroup(); @@ -290,11 +305,11 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams }; // Init sets of clients based on current URL ... - updateAttachedClients(); + reparseRoute(); // ... and re-initialize those sets if the URL has changed without // reloading the route - $scope.$on('$routeUpdate', updateAttachedClients); + $scope.$on('$routeUpdate', reparseRoute); /** * The root connection groups of the connection hierarchy that should be @@ -621,6 +636,18 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams }; + /** + * Disconnects the given ManagedClient, removing it from the current + * view. + * + * @param {ManagedClient} client + * The client to disconnect. + */ + $scope.closeClientTile = function closeClientTile(client) { + $scope.addRemoveClient(client.id, true); + guacClientManager.removeManagedClient(client.id); + }; + /** * Action which immediately disconnects the currently-connected client, if * any. diff --git a/guacamole/src/main/frontend/src/app/client/directives/guacTiledClients.js b/guacamole/src/main/frontend/src/app/client/directives/guacTiledClients.js index efb0d936a..99063769b 100644 --- a/guacamole/src/main/frontend/src/app/client/directives/guacTiledClients.js +++ b/guacamole/src/main/frontend/src/app/client/directives/guacTiledClients.js @@ -31,6 +31,16 @@ angular.module('client').directive('guacTiledClients', [function guacTiledClient directive.scope = { + /** + * The function to invoke when the "close" button in the header of a + * client tile is clicked. The ManagedClient that is closed will be + * made available to the Angular expression defining the callback as + * "$client". + * + * @type function + */ + onClose : '&', + /** * The group of Guacamole clients that should be displayed in an * evenly-tiled grid arrangement. diff --git a/guacamole/src/main/frontend/src/app/client/styles/tiled-client-grid.css b/guacamole/src/main/frontend/src/app/client/styles/tiled-client-grid.css index 11d3a0280..49e0be0f7 100644 --- a/guacamole/src/main/frontend/src/app/client/styles/tiled-client-grid.css +++ b/guacamole/src/main/frontend/src/app/client/styles/tiled-client-grid.css @@ -74,19 +74,47 @@ line-height: 1.5; } -.tiled-client-grid .client-tile .client-tile-name { +.tiled-client-grid .client-tile .client-tile-header { + + display: -webkit-box; + + display: -webkit-flex; + + display: -ms-flexbox; + + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + margin: 0; background: #444; padding: 0 0.25em; font-size: 0.8em; color: white; z-index: 30; + } -.tiled-client-grid .client-tile.focused .client-tile-name { +.tiled-client-grid .client-tile.focused .client-tile-header { background-color: #3161a9; } +.tiled-client-grid .client-tile .client-tile-header > * { + -webkit-box-flex: 0; + -webkit-flex: 0; + -ms-flex: 0; + flex: 0; +} + +.tiled-client-grid .client-tile .client-tile-header .client-tile-name { + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} + .tiled-client-grid .client-tile .main { -webkit-box-flex: 1; -webkit-flex: 1; @@ -94,12 +122,16 @@ flex: 1; } +.tiled-client-grid .client-tile-disconnect, .tiled-client-grid .client-tile-shared-indicator { - display: none; max-height: 1em; height: 100%; } +.tiled-client-grid .client-tile-shared-indicator { + display: none; +} + .tiled-client-grid .shared .client-tile-shared-indicator { display: inline; } diff --git a/guacamole/src/main/frontend/src/app/client/templates/client.html b/guacamole/src/main/frontend/src/app/client/templates/client.html index 5c92f6652..040743953 100644 --- a/guacamole/src/main/frontend/src/app/client/templates/client.html +++ b/guacamole/src/main/frontend/src/app/client/templates/client.html @@ -10,6 +10,7 @@ diff --git a/guacamole/src/main/frontend/src/app/client/templates/guacTiledClients.html b/guacamole/src/main/frontend/src/app/client/templates/guacTiledClients.html index 619fdb062..1a7e72233 100644 --- a/guacamole/src/main/frontend/src/app/client/templates/guacTiledClients.html +++ b/guacamole/src/main/frontend/src/app/client/templates/guacTiledClients.html @@ -8,9 +8,14 @@ 'shared' : isShared(client) }" guac-click="getFocusAssignmentCallback(client)"> -

+

- {{ client.title }} + {{ client.title }} +