diff --git a/guacamole/src/main/frontend/src/app/index/controllers/indexController.js b/guacamole/src/main/frontend/src/app/index/controllers/indexController.js index 9b9078235..532f0db65 100644 --- a/guacamole/src/main/frontend/src/app/index/controllers/indexController.js +++ b/guacamole/src/main/frontend/src/app/index/controllers/indexController.js @@ -69,6 +69,46 @@ angular.module('index').controller('indexController', ['$scope', '$injector', */ $scope.expectedCredentials = null; + /** + * Possible overall states of the client side of the web application. + * + * @enum {string} + */ + var ApplicationState = { + + /** + * The application has fully loaded but is awaiting credentials from + * the user before proceeding. + */ + AWAITING_CREDENTIALS : 'awaitingCredentials', + + /** + * A fatal error has occurred that will prevent the client side of the + * application from functioning properly. + */ + FATAL_ERROR : 'fatalError', + + /** + * The application has just started within the user's browser and has + * not yet settled into any specific state. + */ + LOADING : 'loading', + + /** + * The application has fully loaded and the user has logged in + */ + READY : 'ready' + + }; + + /** + * The current overall state of the client side of the application. + * Possible values are defined by {@link ApplicationState}. + * + * @type string + */ + $scope.applicationState = ApplicationState.LOADING; + /** * Basic page-level information. */ @@ -103,7 +143,7 @@ angular.module('index').controller('indexController', ['$scope', '$injector', // Do not handle key events if not logged in or if a notification is // shown - if ($scope.expectedCredentials || guacNotification.getStatus()) + if ($scope.applicationState !== ApplicationState.READY || guacNotification.getStatus()) return true; // Warn of pending keydown @@ -122,7 +162,7 @@ angular.module('index').controller('indexController', ['$scope', '$injector', // Do not handle key events if not logged in or if a notification is // shown - if ($scope.expectedCredentials || guacNotification.getStatus()) + if ($scope.applicationState !== ApplicationState.READY || guacNotification.getStatus()) return; // Warn of pending keyup @@ -168,32 +208,52 @@ angular.module('index').controller('indexController', ['$scope', '$injector', }, true); + /** + * Reloads the current route and controller, effectively forcing + * reauthentication. If the user is not logged in, this will result in + * the login screen appearing. + */ + $scope.reAuthenticate = function reAuthenticate() { + $scope.reAuthenticating = true; + $route.reload(); + }; + // Display login screen if a whole new set of credentials is needed $scope.$on('guacInvalidCredentials', function loginInvalid(event, parameters, error) { + + $scope.applicationState = ApplicationState.AWAITING_CREDENTIALS; $scope.page.title = 'APP.NAME'; $scope.page.bodyClassName = ''; + $scope.loginHelpText = null; $scope.acceptedCredentials = {}; $scope.expectedCredentials = error.expected; - $scope.fatalError = null; + }); // Prompt for remaining credentials if provided credentials were not enough $scope.$on('guacInsufficientCredentials', function loginInsufficient(event, parameters, error) { + + $scope.applicationState = ApplicationState.AWAITING_CREDENTIALS; $scope.page.title = 'APP.NAME'; $scope.page.bodyClassName = ''; + $scope.loginHelpText = error.translatableMessage; $scope.acceptedCredentials = parameters; $scope.expectedCredentials = error.expected; - $scope.fatalError = null; + }); // Replace absolutely all content with an error message if the page itself // cannot be displayed due to an error $scope.$on('guacFatalPageError', function fatalPageError(error) { + + $scope.applicationState = ApplicationState.FATAL_ERROR; $scope.page.title = 'APP.NAME'; $scope.page.bodyClassName = ''; + $scope.fatalError = error; + }); // Ensure new pages always start with clear keyboard state @@ -209,10 +269,7 @@ angular.module('index').controller('indexController', ['$scope', '$injector', // Clear login screen if route change was successful (and thus // login was either successful or not required) - $scope.loginHelpText = null; - $scope.acceptedCredentials = null; - $scope.expectedCredentials = null; - $scope.fatalError = null; + $scope.applicationState = ApplicationState.READY; // Set title var title = current.$$route.title; diff --git a/guacamole/src/main/frontend/src/app/index/styles/cloak.css b/guacamole/src/main/frontend/src/app/index/styles/cloak.css new file mode 100644 index 000000000..701107bdf --- /dev/null +++ b/guacamole/src/main/frontend/src/app/index/styles/cloak.css @@ -0,0 +1,27 @@ +/* + * 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. + */ + +/* + * Hide portions of DOM by default until Angular has finished loading, + * compiling, etc. + */ + +*[ng-cloak], .translate-cloak { + display: none !important; +} diff --git a/guacamole/src/main/frontend/src/app/index/styles/fatal-page-error.css b/guacamole/src/main/frontend/src/app/index/styles/fatal-page-error.css index 9a50e9c9b..bbfe40615 100644 --- a/guacamole/src/main/frontend/src/app/index/styles/fatal-page-error.css +++ b/guacamole/src/main/frontend/src/app/index/styles/fatal-page-error.css @@ -17,23 +17,10 @@ * under the License. */ -.fatal-page-error-outer { - display: table; - height: 100%; - width: 100%; - position: fixed; - left: 0; - top: 0; +.fatal-page-error-modal guac-modal { z-index: 30; } -.fatal-page-error-middle { - width: 100%; - text-align: center; - display: table-cell; - vertical-align: middle; -} - .fatal-page-error { display: inline-block; width: 100%; diff --git a/guacamole/src/main/frontend/src/app/index/styles/status.css b/guacamole/src/main/frontend/src/app/index/styles/status.css index a24c71a56..7fd63672d 100644 --- a/guacamole/src/main/frontend/src/app/index/styles/status.css +++ b/guacamole/src/main/frontend/src/app/index/styles/status.css @@ -17,25 +17,11 @@ * under the License. */ -.status-outer { - display: table; - height: 100%; - width: 100%; - position: fixed; - left: 0; - top: 0; +.global-status-modal guac-modal { background: rgba(0, 0, 0, 0.5); - z-index: 10; } -.status-middle { - width: 100%; - text-align: center; - display: table-cell; - vertical-align: middle; -} - -.status-middle .notification { +.global-status-modal .notification { width: 75%; max-width: 5in; @@ -47,34 +33,10 @@ } -.status-middle .notification .body { +.global-status-modal .notification .body { margin: 1.25em; } -.status-middle .notification .buttons { +.global-status-modal .notification .buttons { margin: 1em; } - -/* Fade entire status area in/out based on shown status */ - -.status-outer { - visibility: hidden; - opacity: 0; - transition: opacity, visibility; - transition-duration: 0.25s; -} - -.shown.status-outer { - visibility: visible; - opacity: 1; -} - -/* Hide dialog immediately based on status */ - -.status-middle .notification { - visibility: hidden; -} - -.shown .status-middle .notification { - visibility: visible; -} diff --git a/guacamole/src/main/frontend/src/app/notification/directives/guacModal.js b/guacamole/src/main/frontend/src/app/notification/directives/guacModal.js new file mode 100644 index 000000000..8cc6392cb --- /dev/null +++ b/guacamole/src/main/frontend/src/app/notification/directives/guacModal.js @@ -0,0 +1,29 @@ +/* + * 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 for displaying arbitrary modal content. + */ +angular.module('notification').directive('guacModal', [function guacModal() { + return { + restrict: 'E', + templateUrl: 'app/notification/templates/guacModal.html', + transclude: true + }; +}]); diff --git a/guacamole/src/main/frontend/src/app/notification/styles/modal.css b/guacamole/src/main/frontend/src/app/notification/styles/modal.css new file mode 100644 index 000000000..ad35bb472 --- /dev/null +++ b/guacamole/src/main/frontend/src/app/notification/styles/modal.css @@ -0,0 +1,41 @@ +/* + * 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. + */ + +guac-modal { + display: table; + height: 100%; + width: 100%; + position: fixed; + left: 0; + top: 0; + z-index: 10; +} + +guac-modal .modal-contents { + width: 100%; + text-align: center; + display: table-cell; + vertical-align: middle; +} + +guac-modal { + animation: fadein 0.125s linear; + -moz-animation: fadein 0.125s linear; + -webkit-animation: fadein 0.125s linear; +} diff --git a/guacamole/src/main/frontend/src/app/notification/templates/guacModal.html b/guacamole/src/main/frontend/src/app/notification/templates/guacModal.html new file mode 100644 index 000000000..57a1b5a46 --- /dev/null +++ b/guacamole/src/main/frontend/src/app/notification/templates/guacModal.html @@ -0,0 +1,3 @@ +
diff --git a/guacamole/src/main/frontend/src/index.html b/guacamole/src/main/frontend/src/index.html index 2f0f39cfe..e8dbdb82a 100644 --- a/guacamole/src/main/frontend/src/index.html +++ b/guacamole/src/main/frontend/src/index.html @@ -38,41 +38,35 @@