

diff --git a/guacamole/src/main/webapp/app/client/controllers/clientController.js b/guacamole/src/main/webapp/app/client/controllers/clientController.js
index 1d386d8dd..328b74e59 100644
--- a/guacamole/src/main/webapp/app/client/controllers/clientController.js
+++ b/guacamole/src/main/webapp/app/client/controllers/clientController.js
@@ -41,11 +41,10 @@ angular.module('home').controller('clientController', ['$scope', '$routeParams',
var connectionDAO = $injector.get('connectionDAO');
// Client settings and state
- $scope.clientParameters = {scale: 1};
+ $scope.clientProperties = {scale: 1};
// Hide menu by default
- $scope.menuShown = false;
- $scope.menuHasBeenShown = false;
+ $scope.menuShown = true;
/*
* Parse the type, name, and id out of the url paramteres,
@@ -113,9 +112,6 @@ angular.module('home').controller('clientController', ['$scope', '$routeParams',
// Toggle the menu
$scope.safeApply(function() {
$scope.menuShown = !$scope.menuShown;
-
- // The menu has been shown at least once before
- $scope.menuHasBeenShown = true;
});
// Reset the keys pressed
@@ -129,4 +125,30 @@ angular.module('home').controller('clientController', ['$scope', '$routeParams',
delete keysCurrentlyPressed[keysym];
});
+ $scope.formattedScale = function formattedScale() {
+ return Math.round($scope.clientProperties.scale * 100);
+ };
+
+ $scope.zoomIn = function zoomIn() {
+ $scope.clientProperties.scale += 0.1;
+ };
+
+ $scope.zoomOut = function zoomOut() {
+ $scope.clientProperties.scale -= 0.1;
+ };
+
+ $scope.autoFit = true;
+
+ $scope.$watch('autoFit', function changeAutoFit(autoFit) {
+ if(autoFit && $scope.clientProperties.minZoom) {
+ $scope.clientProperties.scale = $scope.clientProperties.minZoom;
+ } else {
+ $scope.clientProperties.scale = 1;
+ }
+ });
+
+ $scope.autoFitDisabled = function() {
+ return $scope.clientProperties.minZoom >= 1;
+ };
+
}]);
diff --git a/guacamole/src/main/webapp/app/client/directives/guacClient.js b/guacamole/src/main/webapp/app/client/directives/guacClient.js
index 1aaba56b7..fb8449264 100644
--- a/guacamole/src/main/webapp/app/client/directives/guacClient.js
+++ b/guacamole/src/main/webapp/app/client/directives/guacClient.js
@@ -31,7 +31,7 @@ angular.module('client').directive('guacClient', [function guacClient() {
replace: true,
scope: {
// Parameters for controlling client state
- clientParameters : '=',
+ clientProperties : '=',
// Parameters for initially connecting
id : '=',
@@ -41,6 +41,21 @@ angular.module('client').directive('guacClient', [function guacClient() {
},
templateUrl: 'app/client/templates/guacClient.html',
controller: ['$scope', '$injector', '$element', function guacClientController($scope, $injector, $element) {
+
+ /*
+ * Safe $apply implementation from Alex Vanston:
+ * https://coderwall.com/p/ngisma
+ */
+ $scope.safeApply = function(fn) {
+ var phase = this.$root.$$phase;
+ if(phase === '$apply' || phase === '$digest') {
+ if(fn && (typeof(fn) === 'function')) {
+ fn();
+ }
+ } else {
+ this.$apply(fn);
+ }
+ };
var $window = $injector.get('$window'),
guacAudio = $injector.get('guacAudio'),
@@ -86,10 +101,6 @@ angular.module('client').directive('guacClient', [function guacClient() {
"TEXT_INPUT_PADDING" : 128, /* characters */
"TEXT_INPUT_PADDING_CODEPOINT" : 0x200B,
- /* Settings for zoom */
- "min_zoom" : 1,
- "max_zoom" : 3,
-
/* Current connection parameters */
/* The user defined named for this connection */
@@ -111,6 +122,19 @@ angular.module('client').directive('guacClient', [function guacClient() {
"clipboard_integration_enabled" : undefined
});
+ var CLIENT_PROPERTY_DEFAULTS = {
+ scale: 1
+ };
+
+ for (var propertyName in CLIENT_PROPERTY_DEFAULTS) {
+ if (!(propertyName in $scope.clientProperties))
+ $scope.clientProperties[propertyName] = CLIENT_PROPERTY_DEFAULTS[propertyName];
+ }
+
+ // Maximum and minimum zoom levels
+ $scope.clientProperties.minZoom = 1;
+ $scope.clientProperties.maxZoom = 3;
+
/**
* Updates the scale of the attached Guacamole.Client based on current window
* size and "auto-fit" setting.
@@ -122,23 +146,23 @@ angular.module('client').directive('guacClient', [function guacClient() {
return;
// Determine whether display is currently fit to the screen
- var auto_fit = (guac.getDisplay().getScale() === $scope.min_zoom);
+ var auto_fit = (guac.getDisplay().getScale() === $scope.clientProperties.minZoom);
// Calculate scale to fit screen
- $scope.min_zoom = Math.min(
+ $scope.clientProperties.minZoom = Math.min(
$scope.main.offsetWidth / Math.max(guac.getDisplay().getWidth(), 1),
$scope.main.offsetHeight / Math.max(guac.getDisplay().getHeight(), 1)
);
// Calculate appropriate maximum zoom level
- $scope.max_zoom = Math.max($scope.min_zoom, 3);
+ $scope.clientProperties.maxZoom = Math.max($scope.clientProperties.minZoom, 3);
// Clamp zoom level, maintain auto-fit
- if (guac.getDisplay().getScale() < $scope.min_zoom || auto_fit)
- $scope.setScale($scope.min_zoom);
+ if (guac.getDisplay().getScale() < $scope.clientProperties.minZoom || auto_fit)
+ $scope.clientProperties.scale = $scope.clientProperties.minZoom;
- else if (guac.getDisplay().getScale() > $scope.max_zoom)
- $scope.setScale($scope.max_zoom);
+ else if (guac.getDisplay().getScale() > $scope.clientProperties.maxZoom)
+ $scope.clientProperties.scale = $scope.clientProperties.maxZoom;
};
@@ -166,7 +190,7 @@ angular.module('client').directive('guacClient', [function guacClient() {
*/
guac.getDisplay().onresize = function() {
- $scope.updateDisplayScale();
+ $scope.safeApply($scope.updateDisplayScale);
};
/*
@@ -531,45 +555,30 @@ angular.module('client').directive('guacClient', [function guacClient() {
// Connect
$scope.guac.connect(connectString);
};
+
+ // Adjust scale if modified externally
+ $scope.$watch('clientProperties.scale', function changeScale(scale) {
- /**
- * Sets the current display scale to the given value, where 1 is 100% (1:1
- * pixel ratio). Out-of-range values will be clamped in-range.
- *
- * @param {Number} scale The new scale to apply
- */
- $scope.setScale = function setScale(scale) {
+ // Fix scale within limits
+ scale = Math.max(scale, $scope.clientProperties.minZoom);
+ scale = Math.min(scale, $scope.clientProperties.maxZoom);
- scale = Math.max(scale, $scope.min_zoom);
- scale = Math.min(scale, $scope.max_zoom);
+ // If at minimum zoom level, hide scroll bars
+ if (scale === $scope.clientProperties.minZoom)
+ $scope.main.style.overflow = "hidden";
+ // If not at minimum zoom level, show scroll bars
+ else
+ $scope.main.style.overflow = "auto";
+
+ // Apply scale if client attached
if ($scope.attachedClient)
$scope.attachedClient.getDisplay().scale(scale);
+
+ if (scale !== $scope.clientProperties.scale)
+ $scope.clientProperties.scale = scale;
- return scale;
- };
-
- // Adjust scale if modified externally
- $scope.$watch('clientParameters.scale', function changeScale(scale) {
- $scope.setScale(scale);
- checkScale();
});
-
- // Verify that the scale is within acceptable bounds, and adjust if needed
- function checkScale() {
-
- // If at minimum zoom level, auto fit is ON
- if ($scope.scale === $scope.min_zoom) {
- $scope.main.style.overflow = "hidden";
- $scope.autoFitEnabled = true;
- }
-
- // If at minimum zoom level, auto fit is OFF
- else {
- $scope.main.style.overflow = "auto";
- $scope.autoFitEnabled = false;
- }
- }
var show_keyboard_gesture_possible = true;
diff --git a/guacamole/src/main/webapp/app/client/templates/client.html b/guacamole/src/main/webapp/app/client/templates/client.html
index f6f2256fd..7c2d6da11 100644
--- a/guacamole/src/main/webapp/app/client/templates/client.html
+++ b/guacamole/src/main/webapp/app/client/templates/client.html
@@ -24,7 +24,7 @@