From 8b193ad89adf7ddba5afbda6f25a5c49149d84cc Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 25 Jul 2016 01:08:16 -0700 Subject: [PATCH 1/6] GUACAMOLE-5: Separate menu semantics from guacUserMenu into own guacMenu directive. --- .../app/navigation/directives/guacMenu.js | 91 ++++++++++ .../app/navigation/directives/guacUserMenu.js | 44 +---- .../webapp/app/navigation/styles/menu.css | 155 ++++++++++++++++++ .../app/navigation/styles/user-menu.css | 145 +--------------- .../app/navigation/templates/guacMenu.html | 7 + .../navigation/templates/guacUserMenu.html | 50 +++--- 6 files changed, 284 insertions(+), 208 deletions(-) create mode 100644 guacamole/src/main/webapp/app/navigation/directives/guacMenu.js create mode 100644 guacamole/src/main/webapp/app/navigation/styles/menu.css create mode 100644 guacamole/src/main/webapp/app/navigation/templates/guacMenu.html diff --git a/guacamole/src/main/webapp/app/navigation/directives/guacMenu.js b/guacamole/src/main/webapp/app/navigation/directives/guacMenu.js new file mode 100644 index 000000000..e00cc1c4f --- /dev/null +++ b/guacamole/src/main/webapp/app/navigation/directives/guacMenu.js @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * A directive which provides an arbitrary menu-style container. The contents + * of the directive are displayed only when the menu is open. + */ +angular.module('navigation').directive('guacMenu', [function guacMenu() { + + return { + restrict: 'E', + transclude: true, + replace: true, + scope: { + + /** + * The string which should be rendered as the menu title. + * + * @type String + */ + menuTitle : '=' + + }, + + templateUrl: 'app/navigation/templates/guacMenu.html', + controller: ['$scope', '$injector', '$element', + function guacMenuController($scope, $injector, $element) { + + // Get required services + var $document = $injector.get('$document'); + + /** + * The outermost element of the guacMenu directive. + * + * @type Element + */ + var element = $element[0]; + + /** + * The main document object. + * + * @type Document + */ + var document = $document[0]; + + /** + * Whether the contents of the menu are currently shown. + * + * @type Boolean + */ + $scope.menuShown = false; + + /** + * Toggles visibility of the menu contents. + */ + $scope.toggleMenu = function toggleMenu() { + $scope.menuShown = !$scope.menuShown; + }; + + // Close menu when use clicks anywhere else + document.body.addEventListener('click', function clickOutsideMenu() { + $scope.$apply(function closeMenu() { + $scope.menuShown = false; + }); + }, false); + + // Prevent click within menu from triggering the outside-menu handler + element.addEventListener('click', function clickInsideMenu(e) { + e.stopPropagation(); + }, false); + + }] // end controller + + }; +}]); diff --git a/guacamole/src/main/webapp/app/navigation/directives/guacUserMenu.js b/guacamole/src/main/webapp/app/navigation/directives/guacUserMenu.js index aed7b7ce2..249f21701 100644 --- a/guacamole/src/main/webapp/app/navigation/directives/guacUserMenu.js +++ b/guacamole/src/main/webapp/app/navigation/directives/guacUserMenu.js @@ -40,36 +40,15 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu() }, templateUrl: 'app/navigation/templates/guacUserMenu.html', - controller: ['$scope', '$injector', '$element', function guacUserMenuController($scope, $injector, $element) { + controller: ['$scope', '$injector', + function guacUserMenuController($scope, $injector) { // Get required services - var $document = $injector.get('$document'); var $location = $injector.get('$location'); var $route = $injector.get('$route'); var authenticationService = $injector.get('authenticationService'); var userPageService = $injector.get('userPageService'); - /** - * The outermost element of the user menu directive. - * - * @type Element - */ - var element = $element[0]; - - /** - * The main document object. - * - * @type Document - */ - var document = $document[0]; - - /** - * Whether the contents of the user menu are currently shown. - * - * @type Boolean - */ - $scope.menuShown = false; - /** * The username of the current user. * @@ -90,13 +69,6 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu() $scope.pages = pages; }); - /** - * Toggles visibility of the user menu. - */ - $scope.toggleMenu = function toggleMenu() { - $scope.menuShown = !$scope.menuShown; - }; - /** * Logs out the current user, redirecting them to back to the root * after logout completes. @@ -125,18 +97,6 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu() */ $scope.actions = [ LOGOUT_ACTION ]; - // Close menu when use clicks anywhere else - document.body.addEventListener('click', function clickOutsideMenu() { - $scope.$apply(function closeMenu() { - $scope.menuShown = false; - }); - }, false); - - // Prevent click within menu from triggering the outside-menu handler - element.addEventListener('click', function clickInsideMenu(e) { - e.stopPropagation(); - }, false); - }] // end controller }; diff --git a/guacamole/src/main/webapp/app/navigation/styles/menu.css b/guacamole/src/main/webapp/app/navigation/styles/menu.css new file mode 100644 index 000000000..c40215871 --- /dev/null +++ b/guacamole/src/main/webapp/app/navigation/styles/menu.css @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +.menu-dropdown { + + /* IE10 */ + display: -ms-flexbox; + -ms-flex-align: center; + -ms-flex-direction: row; + + /* Ancient Mozilla */ + display: -moz-box; + -moz-box-align: center; + -moz-box-orient: horizontal; + + /* Ancient WebKit */ + display: -webkit-box; + -webkit-box-align: center; + -webkit-box-orient: horizontal; + + /* Old WebKit */ + display: -webkit-flex; + -webkit-align-items: center; + -webkit-flex-direction: row; + + /* W3C */ + display: flex; + align-items: center; + flex-direction: row; + +} + +.menu-dropdown { + position: relative; + border-left: 1px solid rgba(0,0,0,0.125); + background: rgba(0,0,0,0.04); +} + +.menu-dropdown:hover { + background: rgba(0,0,0,0.01); +} + +.menu-dropdown.open, +.menu-dropdown.open:hover { + background: rgba(0,0,0,0.3); +} + +.menu-dropdown .menu-title { + + cursor: default; + margin: 0; + min-width: 2in; + padding: 0.5em; + + -ms-flex: 0 0 auto; + -moz-box-flex: 0; + -webkit-box-flex: 0; + -webkit-flex: 0 0 auto; + flex: 0 0 auto; + +} + +.menu-dropdown .menu-indicator { + + position: absolute; + right: 0; + top: 0; + bottom: 0; + + width: 2em; + background-repeat: no-repeat; + background-size: 1em; + background-position: center center; + background-image: url('images/arrows/down.png'); + +} + +.menu-dropdown .options { + + visibility: hidden; + + position: absolute; + top: 100%; + right: 0; + left: -1px; + + background: #EEE; + box-shadow: 0 2px 2px rgba(0, 0, 0, 0.125); + border-left: 1px solid rgba(0,0,0,0.125); + border-bottom: 1px solid rgba(0,0,0,0.125); + + z-index: 5; + +} + +.menu-dropdown .options ul { + margin: 0; + padding: 0; +} + +.menu-dropdown.open .options { + visibility: visible; +} + +.menu-dropdown .options li { + padding: 0; + list-style-type: none; +} + +.menu-dropdown .options li a { + + display: block; + cursor: pointer; + color: black; + text-decoration: none; + padding: 0.75em; + +} + +.menu-dropdown .options li a:hover { + background-color: #CDA; +} + +.menu-dropdown .options li a.current, +.menu-dropdown .options li a.current:hover { + background-color: transparent; + cursor: default; + opacity: 0.25; +} + +.menu-dropdown .options li a.danger { + color: white; + font-weight: bold; + background-color: #A43; +} + +.menu-dropdown .options li a.danger:hover { + background-color: #C54; +} diff --git a/guacamole/src/main/webapp/app/navigation/styles/user-menu.css b/guacamole/src/main/webapp/app/navigation/styles/user-menu.css index 2d8ae5189..7d679edc3 100644 --- a/guacamole/src/main/webapp/app/navigation/styles/user-menu.css +++ b/guacamole/src/main/webapp/app/navigation/styles/user-menu.css @@ -46,55 +46,7 @@ } -.user-menu .user-menu-dropdown { - - /* IE10 */ - display: -ms-flexbox; - -ms-flex-align: center; - -ms-flex-direction: row; - - /* Ancient Mozilla */ - display: -moz-box; - -moz-box-align: center; - -moz-box-orient: horizontal; - - /* Ancient WebKit */ - display: -webkit-box; - -webkit-box-align: center; - -webkit-box-orient: horizontal; - - /* Old WebKit */ - display: -webkit-flex; - -webkit-align-items: center; - -webkit-flex-direction: row; - - /* W3C */ - display: flex; - align-items: center; - flex-direction: row; - -} - -.user-menu .user-menu-dropdown { - position: relative; - border-left: 1px solid rgba(0,0,0,0.125); - background: rgba(0,0,0,0.04); -} - -.user-menu .user-menu-dropdown:hover { - background: rgba(0,0,0,0.01); -} - -.user-menu .user-menu-dropdown.open, -.user-menu .user-menu-dropdown.open:hover { - background: rgba(0,0,0,0.3); -} - -.user-menu .username { - - cursor: default; - margin: 0; - min-width: 2in; +.user-menu .menu-dropdown .menu-title { font-size: 1.25em; font-weight: bold; @@ -105,68 +57,9 @@ background-position: 0.5em center; background-image: url('images/user-icons/guac-user.png'); - -ms-flex: 0 0 auto; - -moz-box-flex: 0; - -webkit-box-flex: 0; - -webkit-flex: 0 0 auto; - flex: 0 0 auto; - } -.user-menu .menu-indicator { - - position: absolute; - right: 0; - top: 0; - bottom: 0; - - width: 2em; - background-repeat: no-repeat; - background-size: 1em; - background-position: center center; - background-image: url('images/arrows/down.png'); - -} - -.user-menu .options { - - visibility: hidden; - - position: absolute; - top: 100%; - right: 0; - left: -1px; - - background: #EEE; - box-shadow: 0 2px 2px rgba(0, 0, 0, 0.125); - border-left: 1px solid rgba(0,0,0,0.125); - border-bottom: 1px solid rgba(0,0,0,0.125); - - z-index: 5; - -} - -.user-menu .options ul { - margin: 0; - padding: 0; -} - -.user-menu .user-menu-dropdown.open .options { - visibility: visible; -} - -.user-menu .options li { - padding: 0; - list-style-type: none; -} - -.user-menu .options li a { - - display: block; - cursor: pointer; - color: black; - text-decoration: none; - padding: 0.75em; +.user-menu .menu-dropdown .options li a { background-repeat: no-repeat; background-size: 1em; @@ -175,39 +68,17 @@ background-image: url('images/protocol-icons/guac-monitor.png'); } - -.user-menu .options li a:hover { - background-color: #CDA; -} - -.user-menu .options li a.current, -.user-menu .options li a.current:hover { - background-color: transparent; - cursor: default; - opacity: 0.25; -} - -.user-menu .options li a[href="#/"] { +.user-menu .menu-dropdown .options li a[href="#/"] { background-image: url('images/action-icons/guac-home-dark.png'); } -.user-menu .options li a[href="#/settings/users"], -.user-menu .options li a[href="#/settings/connections"], -.user-menu .options li a[href="#/settings/sessions"], -.user-menu .options li a[href="#/settings/preferences"] { +.user-menu .menu-dropdown .options li a[href="#/settings/users"], +.user-menu .menu-dropdown .options li a[href="#/settings/connections"], +.user-menu .menu-dropdown .options li a[href="#/settings/sessions"], +.user-menu .menu-dropdown .options li a[href="#/settings/preferences"] { background-image: url('images/action-icons/guac-config-dark.png'); } -.user-menu .options li a.logout { +.user-menu .menu-dropdown .options li a.logout { background-image: url('images/action-icons/guac-logout-dark.png'); } - -.user-menu .options li a.danger { - color: white; - font-weight: bold; - background-color: #A43; -} - -.user-menu .options li a.danger:hover { - background-color: #C54; -} diff --git a/guacamole/src/main/webapp/app/navigation/templates/guacMenu.html b/guacamole/src/main/webapp/app/navigation/templates/guacMenu.html new file mode 100644 index 000000000..f1785cd9f --- /dev/null +++ b/guacamole/src/main/webapp/app/navigation/templates/guacMenu.html @@ -0,0 +1,7 @@ + diff --git a/guacamole/src/main/webapp/app/navigation/templates/guacUserMenu.html b/guacamole/src/main/webapp/app/navigation/templates/guacUserMenu.html index 4acd47442..351da0f2c 100644 --- a/guacamole/src/main/webapp/app/navigation/templates/guacUserMenu.html +++ b/guacamole/src/main/webapp/app/navigation/templates/guacUserMenu.html @@ -1,34 +1,26 @@
+ + + + -
-
{{username}}
- - - - -
+ + +
From 3484d323020ef0b1d3a6f773db3fa345ed5d25f7 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 25 Jul 2016 01:54:04 -0700 Subject: [PATCH 2/6] GUACAMOLE-5: Clean up header and dropdown style. --- guacamole/src/main/webapp/app/client/styles/client.css | 4 ++++ guacamole/src/main/webapp/app/index/styles/headers.css | 4 ++-- guacamole/src/main/webapp/app/manage/styles/attributes.css | 2 +- guacamole/src/main/webapp/app/navigation/styles/menu.css | 5 +++-- .../src/main/webapp/app/navigation/styles/user-menu.css | 3 +-- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/guacamole/src/main/webapp/app/client/styles/client.css b/guacamole/src/main/webapp/app/client/styles/client.css index c110948e8..17c7bf85a 100644 --- a/guacamole/src/main/webapp/app/client/styles/client.css +++ b/guacamole/src/main/webapp/app/client/styles/client.css @@ -116,6 +116,10 @@ body.client { } +.client .menu .header h2 { + text-transform: none; +} + .client .user-menu .options li a.disconnect { background-repeat: no-repeat; background-size: 1em; diff --git a/guacamole/src/main/webapp/app/index/styles/headers.css b/guacamole/src/main/webapp/app/index/styles/headers.css index a99364a60..2e813f42f 100644 --- a/guacamole/src/main/webapp/app/index/styles/headers.css +++ b/guacamole/src/main/webapp/app/index/styles/headers.css @@ -32,7 +32,7 @@ h2 { font-size: 1.25em; font-weight: bold; text-transform: uppercase; - padding: 0.75em 0.5em; + padding: 0.5em; margin: 0; } @@ -90,7 +90,7 @@ h2 { .header .filter { margin: 0; - padding: 0.75em 0.5em; + padding: 0.5em; } .header .filter input { diff --git a/guacamole/src/main/webapp/app/manage/styles/attributes.css b/guacamole/src/main/webapp/app/manage/styles/attributes.css index 70871b03c..136ec5dee 100644 --- a/guacamole/src/main/webapp/app/manage/styles/attributes.css +++ b/guacamole/src/main/webapp/app/manage/styles/attributes.css @@ -49,7 +49,7 @@ font-size: 1.25em; font-weight: bold; text-transform: uppercase; - padding: 0.75em 0.5em; + padding: 0.5em; margin: 1em 0; border-bottom: 1px solid rgba(0, 0, 0, 0.125); diff --git a/guacamole/src/main/webapp/app/navigation/styles/menu.css b/guacamole/src/main/webapp/app/navigation/styles/menu.css index c40215871..4a7c13469 100644 --- a/guacamole/src/main/webapp/app/navigation/styles/menu.css +++ b/guacamole/src/main/webapp/app/navigation/styles/menu.css @@ -65,8 +65,8 @@ cursor: default; margin: 0; - min-width: 2in; padding: 0.5em; + padding-right: 2em; -ms-flex: 0 0 auto; -moz-box-flex: 0; @@ -98,7 +98,8 @@ position: absolute; top: 100%; right: 0; - left: -1px; + min-width: 100%; + white-space: nowrap; background: #EEE; box-shadow: 0 2px 2px rgba(0, 0, 0, 0.125); diff --git a/guacamole/src/main/webapp/app/navigation/styles/user-menu.css b/guacamole/src/main/webapp/app/navigation/styles/user-menu.css index 7d679edc3..9acecc871 100644 --- a/guacamole/src/main/webapp/app/navigation/styles/user-menu.css +++ b/guacamole/src/main/webapp/app/navigation/styles/user-menu.css @@ -48,9 +48,8 @@ .user-menu .menu-dropdown .menu-title { - font-size: 1.25em; font-weight: bold; - padding: 0.5em 2em; + padding-left: 2em; background-repeat: no-repeat; background-size: 1em; From 91254f7f982eed8b322c32b4f675bfbeec134e94 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 25 Jul 2016 02:28:56 -0700 Subject: [PATCH 3/6] GUACAMOLE-5: Add sharing support to the Guacamole client UI. --- .../client/controllers/clientController.js | 72 +++++++++++++++++++ .../webapp/app/client/templates/client.html | 5 ++ .../src/main/webapp/translations/en.json | 2 + 3 files changed, 79 insertions(+) diff --git a/guacamole/src/main/webapp/app/client/controllers/clientController.js b/guacamole/src/main/webapp/app/client/controllers/clientController.js index 74aea6220..d2f9d2623 100644 --- a/guacamole/src/main/webapp/app/client/controllers/clientController.js +++ b/guacamole/src/main/webapp/app/client/controllers/clientController.js @@ -28,6 +28,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams var ManagedClientState = $injector.get('ManagedClientState'); var ManagedFilesystem = $injector.get('ManagedFilesystem'); var ScrollState = $injector.get('ScrollState'); + var UserCredentials = $injector.get('UserCredentials'); // Required services var $location = $injector.get('$location'); @@ -36,6 +37,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams var guacClientManager = $injector.get('guacClientManager'); var guacNotification = $injector.get('guacNotification'); var preferenceService = $injector.get('preferenceService'); + var tunnelService = $injector.get('tunnelService'); var userPageService = $injector.get('userPageService'); /** @@ -235,6 +237,15 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams */ $scope.client = guacClientManager.getManagedClient($routeParams.id, $routeParams.params); + /** + * Map of all available sharing profiles for the current connection by + * their identifiers. If this information is not yet available, or no such + * sharing profiles exist, this will be an empty object. + * + * @type Object. + */ + $scope.sharingProfiles = {}; + /** * Map of all currently pressed keys by keysym. If a particular key is * currently pressed, the value stored under that key's keysym within this @@ -406,6 +417,47 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams }); + // Pull sharing profiles once the tunnel UUID is known + $scope.$watch('client.tunnel.uuid', function retrieveSharingProfiles(uuid) { + + // Only pull sharing profiles if tunnel UUID is actually available + if (!uuid) + return; + + // Pull sharing profiles for the current connection + tunnelService.getSharingProfiles(uuid) + .success(function sharingProfilesRetrieved(sharingProfiles) { + $scope.sharingProfiles = sharingProfiles; + }); + + }); + + /** + * Produces a sharing link for the current connection using the given + * sharing profile. The resulting sharing link, and any required login + * information, will be displayed to the user once the various underlying + * service calls succeed. + * + * @param {SharingProfile} sharingProfile + * The sharing profile to use to generate the sharing link. + */ + $scope.share = function share(sharingProfile) { + + // Retrieve sharing credentials for the sake of generating a share link + tunnelService.getSharingCredentials($scope.client.tunnel.uuid, sharingProfile.identifier) + .success(function sharingCredentialsReceived(sharingCredentials) { + + // TODONT: COMPLETE HACK: Shove the share link into the clipboard + var href = UserCredentials.getLink(sharingCredentials); + $scope.client.clipboardData = { + 'type' : 'text/plain', + 'data' : href + }; + + }); + + }; + // Track pressed keys, opening the Guacamole menu after Ctrl+Alt+Shift $scope.$on('guacKeydown', function keydownListener(event, keysym, keyboard) { @@ -762,6 +814,26 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams }; + /** + * Returns whether the current user can share the current connection with + * other users. A connection can be shared if and only if there is at least + * one associated sharing profile. + * + * @returns {Boolean} + * true if the current user can share the current connection with other + * users, false otherwise. + */ + $scope.canShareConnection = function canShareConnection() { + + // If there is at least one sharing profile, the connection can be shared + for (var dummy in $scope.sharingProfiles) + return true; + + // Otherwise, sharing is not possible + return false; + + }; + // Clean up when view destroyed $scope.$on('$destroy', function clientViewDestroyed() { diff --git a/guacamole/src/main/webapp/app/client/templates/client.html b/guacamole/src/main/webapp/app/client/templates/client.html index 8a4e7fea2..8b5583856 100644 --- a/guacamole/src/main/webapp/app/client/templates/client.html +++ b/guacamole/src/main/webapp/app/client/templates/client.html @@ -43,6 +43,11 @@

{{client.name}}

+ + +
diff --git a/guacamole/src/main/webapp/translations/en.json b/guacamole/src/main/webapp/translations/en.json index 66ad359c6..9e65d20e0 100644 --- a/guacamole/src/main/webapp/translations/en.json +++ b/guacamole/src/main/webapp/translations/en.json @@ -24,6 +24,7 @@ "ACTION_NAVIGATE_HOME" : "Home", "ACTION_SAVE" : "Save", "ACTION_SEARCH" : "Search", + "ACTION_SHARE" : "Share", "ACTION_UPDATE_PASSWORD" : "Update Password", "ACTION_VIEW_HISTORY" : "History", @@ -55,6 +56,7 @@ "ACTION_NAVIGATE_HOME" : "@:APP.ACTION_NAVIGATE_HOME", "ACTION_RECONNECT" : "Reconnect", "ACTION_SAVE_FILE" : "@:APP.ACTION_SAVE", + "ACTION_SHARE" : "@:APP.ACTION_SHARE", "ACTION_UPLOAD_FILES" : "Upload Files", "DIALOG_HEADER_CONNECTING" : "Connecting", From e1cf5821fc526113e13f09ee6dd62a5d179e2553 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 2 Aug 2016 11:50:32 -0700 Subject: [PATCH 4/6] GUACAMOLE-5: Add share icon. --- .../webapp/app/client/styles/share-menu.css | 58 ++++++++++++++++++ .../webapp/app/client/templates/client.html | 12 ++-- guacamole/src/main/webapp/images/share.png | Bin 0 -> 1112 bytes 3 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 guacamole/src/main/webapp/app/client/styles/share-menu.css create mode 100644 guacamole/src/main/webapp/images/share.png diff --git a/guacamole/src/main/webapp/app/client/styles/share-menu.css b/guacamole/src/main/webapp/app/client/styles/share-menu.css new file mode 100644 index 000000000..6d6659b01 --- /dev/null +++ b/guacamole/src/main/webapp/app/client/styles/share-menu.css @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +.share-menu { + + /* IE10 */ + display: -ms-flexbox; + -ms-flex-align: stretch; + -ms-flex-direction: row; + + /* Ancient Mozilla */ + display: -moz-box; + -moz-box-align: stretch; + -moz-box-orient: horizontal; + + /* Ancient WebKit */ + display: -webkit-box; + -webkit-box-align: stretch; + -webkit-box-orient: horizontal; + + /* Old WebKit */ + display: -webkit-flex; + -webkit-align-items: stretch; + -webkit-flex-direction: row; + + /* W3C */ + display: flex; + align-items: stretch; + flex-direction: row; + +} + +.share-menu .menu-dropdown .menu-title { + + padding-left: 2em; + + background-repeat: no-repeat; + background-size: 1em; + background-position: 0.5em center; + background-image: url('images/share.png'); + +} diff --git a/guacamole/src/main/webapp/app/client/templates/client.html b/guacamole/src/main/webapp/app/client/templates/client.html index 8b5583856..2214d5882 100644 --- a/guacamole/src/main/webapp/app/client/templates/client.html +++ b/guacamole/src/main/webapp/app/client/templates/client.html @@ -43,11 +43,13 @@

{{client.name}}

- - - +
diff --git a/guacamole/src/main/webapp/images/share.png b/guacamole/src/main/webapp/images/share.png new file mode 100644 index 0000000000000000000000000000000000000000..75dfde06f4ee35b1b6a4cc1ec02ec5006e1ac3c7 GIT binary patch literal 1112 zcmV-e1gHCnP)uee=Sv|f@-{46rs{cELo7&qb!TCVI{ip z2n!??4T&WSBC)ZpR%$^c2x;OO2@91;NLsW-D?yYlER1IvJE zp1LyBD|69D{9IrSunCxldeYi~>%fbY6dUFWiFf!WswV)L0<;J=%|2qU1X=~(Sh)(! zHPnujiI6C)++(v`uz5N{+!_*l6RGqF|2L|%38H3sY)S;1=SgB#pn43y-;{P>Qc&T! zK^-)_7q0E|{N69v^dyOS8kihF!&2a20DGexMZPQ7fMdW7P5og_yi#CTu#W(TfD^z6 zp}y02%Y0IT8s-M+2K#{7ns_?}`v_1FXR{Fb6)6iM+~g~8GN8|K)LoR2zUr4yAH*14 zz+J(vB!~!82>>_+T<~do9ypVv{-K4NSX{Q80FzxBDm z5y55%m};mUp(p@8At%7k@HZbdij@32fRCEG7L$z#i*9bU2n4xa2t6& zFe5Rs9$+1ltHK#cHUX{$xF(wb*8*IVO@M0wuE{3AV(bYPW2ZG0s0|Cgl`gAo}| zCGd@rCq3^_XL`mI3sAE;zcar!f*pcNdm0Ho{jGPRG!9d1ZAGX<3*PB z_SAQyo}8#59nRQ{yp$b(TxAhznagYE^n|CWZcsXz)r9&W#^?lY33jE1G^B*71W0T4 zGlXm2R{+My3Q#49k9I$>HqK@jiKjn@86#tYJk-GjZxV)42clmKby4843$eDSBX~Dh z<3y Date: Tue, 2 Aug 2016 13:08:04 -0700 Subject: [PATCH 5/6] GUACAMOLE-5: Display share links within Guacamole menu. Persist within ManagedClient. --- .../client/controllers/clientController.js | 41 ++++--- .../webapp/app/client/styles/guac-menu.css | 28 +++++ .../webapp/app/client/templates/client.html | 18 ++- .../webapp/app/client/types/ManagedClient.js | 66 +++++++++++ .../app/client/types/ManagedShareLink.js | 105 ++++++++++++++++++ .../src/main/webapp/translations/en.json | 2 + 6 files changed, 246 insertions(+), 14 deletions(-) create mode 100644 guacamole/src/main/webapp/app/client/types/ManagedShareLink.js diff --git a/guacamole/src/main/webapp/app/client/controllers/clientController.js b/guacamole/src/main/webapp/app/client/controllers/clientController.js index d2f9d2623..b522568b7 100644 --- a/guacamole/src/main/webapp/app/client/controllers/clientController.js +++ b/guacamole/src/main/webapp/app/client/controllers/clientController.js @@ -28,7 +28,6 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams var ManagedClientState = $injector.get('ManagedClientState'); var ManagedFilesystem = $injector.get('ManagedFilesystem'); var ScrollState = $injector.get('ScrollState'); - var UserCredentials = $injector.get('UserCredentials'); // Required services var $location = $injector.get('$location'); @@ -435,26 +434,42 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams /** * Produces a sharing link for the current connection using the given * sharing profile. The resulting sharing link, and any required login - * information, will be displayed to the user once the various underlying - * service calls succeed. + * information, will be displayed to the user within the Guacamole menu. * * @param {SharingProfile} sharingProfile * The sharing profile to use to generate the sharing link. */ $scope.share = function share(sharingProfile) { + ManagedClient.createShareLink($scope.client, sharingProfile); + }; - // Retrieve sharing credentials for the sake of generating a share link - tunnelService.getSharingCredentials($scope.client.tunnel.uuid, sharingProfile.identifier) - .success(function sharingCredentialsReceived(sharingCredentials) { + /** + * Returns whether the current connection has any associated share links. + * + * @returns {Boolean} + * true if the current connection has at least one associated share + * link, false otherwise. + */ + $scope.isShared = function isShared() { + return ManagedClient.isShared($scope.client); + }; - // TODONT: COMPLETE HACK: Shove the share link into the clipboard - var href = UserCredentials.getLink(sharingCredentials); - $scope.client.clipboardData = { - 'type' : 'text/plain', - 'data' : href - }; + /** + * Returns the total number of share links associated with the current + * connection. + * + * @returns {Number} + * The total number of share links associated with the current + * connection. + */ + $scope.getShareLinkCount = function getShareLinkCount() { - }); + // Count total number of links within the ManagedClient's share link map + var linkCount = 0; + for (var dummy in $scope.client.shareLinks) + linkCount++; + + return linkCount; }; diff --git a/guacamole/src/main/webapp/app/client/styles/guac-menu.css b/guacamole/src/main/webapp/app/client/styles/guac-menu.css index bc96eb922..9e0fb7ca7 100644 --- a/guacamole/src/main/webapp/app/client/styles/guac-menu.css +++ b/guacamole/src/main/webapp/app/client/styles/guac-menu.css @@ -171,3 +171,31 @@ #guac-menu #devices .device.filesystem { background-image: url('images/drive.png'); } + +#guac-menu #share-links { + + padding: 1em; + border: 1px solid rgba(0, 0, 0, 0.125); + background: rgba(0, 0, 0, 0.04); + + font-size: 0.8em; + +} + +#guac-menu #share-links h3 { + padding-bottom: 0; +} + +#guac-menu #share-links th { + white-space: nowrap; +} + +#guac-menu #share-links a[href] { + + display: block; + padding: 0 1em; + + font-family: monospace; + font-weight: bold; + +} diff --git a/guacamole/src/main/webapp/app/client/templates/client.html b/guacamole/src/main/webapp/app/client/templates/client.html index 2214d5882..0580c8bbb 100644 --- a/guacamole/src/main/webapp/app/client/templates/client.html +++ b/guacamole/src/main/webapp/app/client/templates/client.html @@ -44,7 +44,7 @@

{{client.name}}