Files
guacamole-client/guacamole/src/main/webapp/app/client/controllers/clientController.js
2014-11-14 21:44:32 -08:00

293 lines
9.5 KiB
JavaScript

/*
* Copyright (C) 2014 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.
*/
/**
* The controller for the page used to connect to a connection or balancing group.
*/
angular.module('home').controller('clientController', ['$scope', '$routeParams', '$injector',
function clientController($scope, $routeParams, $injector) {
/*
* In order to open the guacamole menu, we need to hit ctrl-alt-shift. There are
* several possible keysysms for each key.
*/
var SHIFT_KEYS = {0xFFE1 : true, 0xFFE2: true},
ALT_KEYS = {0xFFE9 : true, 0xFFEA : true, 0xFE03: true},
CTRL_KEYS = {0xFFE3 : true, 0xFFE4: true},
MENU_KEYS = angular.extend({}, SHIFT_KEYS, ALT_KEYS, CTRL_KEYS);
/**
* All client error codes handled and passed off for translation. Any error
* code not present in this list will be represented by the "DEFAULT"
* translation.
*/
var CLIENT_ERRORS = {
0x0201: true,
0x0202: true,
0x0203: true,
0x0205: true,
0x0301: true,
0x0303: true,
0x0308: true,
0x031D: true
};
/**
* All tunnel error codes handled and passed off for translation. Any error
* code not present in this list will be represented by the "DEFAULT"
* translation.
*/
var TUNNEL_ERRORS = {
0x0201: true,
0x0202: true,
0x0203: true,
0x0204: true,
0x0205: true,
0x0301: true,
0x0303: true,
0x0308: true,
0x031D: true
};
// Get DAO for reading connections and groups
var connectionGroupDAO = $injector.get('connectionGroupDAO');
var connectionDAO = $injector.get('connectionDAO');
var ClientProperties = $injector.get('clientProperties');
var statusModal = $injector.get('statusModal');
// Client settings and state
$scope.clientProperties = new ClientProperties();
// Hide menu by default
$scope.menuShown = false;
// Convenience method for closing the menu
$scope.closeMenu = function closeMenu() {
$scope.menuShown = false;
};
// Update the model when clipboard data received from client
$scope.$on('guacClientClipboard', function clipboardDataReceived(clipboardData) {
$scope.guacClipboard = clipboardData;
});
/*
* Parse the type, name, and id out of the url paramteres,
* as well as any extra parameters if set.
*/
var uniqueId = $routeParams.type + '/' + $routeParams.id;
$scope.id = uniqueId;
$scope.connectionParameters = $routeParams.params || '';
// Pull connection name from server
switch ($routeParams.type) {
// Connection
case 'c':
connectionDAO.getConnection($routeParams.id).success(function (connection) {
$scope.connectionName = $scope.page.title = connection.name;
});
break;
// Connection group
case 'g':
connectionGroupDAO.getConnectionGroup($routeParams.id).success(function (group) {
$scope.connectionName = $scope.page.title = group.name;
});
break;
}
var keysCurrentlyPressed = {};
/*
* Check to see if all currently pressed keys are in the set of menu keys.
*/
function checkMenuModeActive() {
for(var keysym in keysCurrentlyPressed) {
if(!MENU_KEYS[keysym]) {
return false;
}
}
return true;
}
$scope.$watch('menuShown', function setKeyboardEnabled(menuShown, menuShownPreviousState) {
// Send clipboard data if menu is hidden
if (!menuShown && menuShownPreviousState) {
$scope.$broadcast('guacClipboard', $scope.clipboardData);
}
// Disable client keyboard if the menu is shown
$scope.clientProperties.keyboardEnabled = !menuShown;
});
$scope.$on('guacKeydown', function keydownListener(event, keysym, keyboard) {
keysCurrentlyPressed[keysym] = true;
/*
* If only menu keys are pressed, and we have one keysym from each group,
* and one of the keys is being released, show the menu.
*/
if(checkMenuModeActive()) {
var currentKeysPressedKeys = Object.keys(keysCurrentlyPressed);
// Check that there is a key pressed for each of the required key classes
if(!_.isEmpty(_.pick(SHIFT_KEYS, currentKeysPressedKeys)) &&
!_.isEmpty(_.pick(ALT_KEYS, currentKeysPressedKeys)) &&
!_.isEmpty(_.pick(CTRL_KEYS, currentKeysPressedKeys))
) {
// Toggle the menu
$scope.safeApply(function() {
$scope.menuShown = !$scope.menuShown;
});
// Reset the keys pressed
keysCurrentlyPressed = {};
}
}
});
// Listen for broadcasted keyup events and fire the appropriate listeners
$scope.$on('guacKeyup', function keyupListener(event, keysym, keyboard) {
delete keysCurrentlyPressed[keysym];
});
// Show status dialog when client status changes
$scope.$on('guacClientStateChange', function clientStateChangeListener(event, client, status) {
// Hide previous status, if any
statusModal.deactivate();
// Show new status if not yet connected
if (status !== "connected") {
statusModal.activate({
title: "client.status.connectingStatusTitle",
text: "client.status.clientStates." + status
});
}
});
// Show status dialog when client errors occur
$scope.$on('guacClientError', function clientErrorListener(event, client, status) {
// Disconnect
$scope.id = null;
// Hide any existing status
statusModal.deactivate();
// Determine translation name of error
var errorName = (status in CLIENT_ERRORS) ? status.toString(16) : "DEFAULT";
// Show error status
statusModal.activate({
className: "error",
title: "client.error.connectionErrorTitle",
text: "client.error.clientErrors." + errorName,
actions: [ "client.action.reconnect" ]
});
});
// Show status dialog when tunnel status changes
$scope.$on('guacTunnelStateChange', function tunnelStateChangeListener(event, tunnel, status) {
// Hide previous status, if any
statusModal.deactivate();
// Show new status only if disconnected
if (status === "closed") {
statusModal.activate({
title: "client.status.closedStatusTitle",
text: "client.status.tunnelStates." + status
});
}
});
// Show status dialog when tunnel errors occur
$scope.$on('guacTunnelError', function tunnelErrorListener(event, tunnel, status) {
// Disconnect
$scope.id = null;
// Hide any existing status
statusModal.deactivate();
// Determine translation name of error
var errorName = (status in TUNNEL_ERRORS) ? status.toString(16) : "DEFAULT";
// Show error status
statusModal.activate({
className: "error",
title: "client.error.connectionErrorTitle",
text: "client.error.tunnelErrors." + errorName,
actions: [ "client.action.reconnect" ]
});
});
// Handle reconnect action
$scope.$on('guacStatusAction', function actionListener(event, action) {
if (action === "client.action.reconnect")
$scope.id = uniqueId;
});
$scope.formattedScale = function formattedScale() {
return Math.round($scope.clientProperties.scale * 100);
};
$scope.zoomIn = function zoomIn() {
$scope.autoFit = false;
$scope.clientProperties.autoFit = false;
$scope.clientProperties.scale += 0.1;
};
$scope.zoomOut = function zoomOut() {
$scope.clientProperties.autoFit = false;
$scope.clientProperties.scale -= 0.1;
};
$scope.autoFit = true;
$scope.changeAutoFit = function changeAutoFit() {
if ($scope.autoFit && $scope.clientProperties.minScale) {
$scope.clientProperties.autoFit = true;
} else {
$scope.clientProperties.autoFit = false;
$scope.clientProperties.scale = 1;
}
};
$scope.autoFitDisabled = function() {
return $scope.clientProperties.minZoom >= 1;
};
}]);