diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/form/Field.java b/guacamole-ext/src/main/java/org/apache/guacamole/form/Field.java index 19f1ead09..9fe76a4b1 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/form/Field.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/form/Field.java @@ -91,6 +91,14 @@ public class Field { */ public static String TIMEZONE = "TIMEZONE"; + /** + * Field type which allows selection of languages. The languages + * displayed are the set of languages supported by the Guacamole web + * application. Legal values are valid language IDs, as dictated by + * the filenames of Guacamole's available translations. + */ + public static String LANGUAGE = "LANGUAGE"; + /** * A date field whose legal values conform to the pattern "YYYY-MM-DD", * zero-padded. diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/form/LanguageField.java b/guacamole-ext/src/main/java/org/apache/guacamole/form/LanguageField.java new file mode 100644 index 000000000..a87d77273 --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/form/LanguageField.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.guacamole.form; + +/** + * Represents a language field. The field may contain only valid language + * identifiers as used by the Guacamole web application for its translations. + * Language identifiers are defined by the filenames of the JSON files + * containing the translation. + */ +public class LanguageField extends Field { + + /** + * Creates a new LanguageField with the given name. + * + * @param name + * The unique name to associate with this field. + */ + public LanguageField(String name) { + super(name, Field.Type.LANGUAGE); + } + + /** + * Parses the given string into a language ID string. As any string may be + * a valid language ID as long as it has a corresponding translation, the + * only transformation currently performed by this function is to ensure + * that a blank language string is parsed into null. + * + * @param language + * The language string to parse, which may be null. + * + * @return + * The ID of the language corresponding to the given string, or null if + * if the given language string was null or blank. + */ + public static String parse(String language) { + + // Return null if no language is provided + if (language == null || language.isEmpty()) + return null; + + // Otherwise, assume language is already a valid language ID + return language; + + } + +} diff --git a/guacamole/src/main/webapp/app/form/controllers/languageFieldController.js b/guacamole/src/main/webapp/app/form/controllers/languageFieldController.js new file mode 100644 index 000000000..fdab13788 --- /dev/null +++ b/guacamole/src/main/webapp/app/form/controllers/languageFieldController.js @@ -0,0 +1,54 @@ +/* + * 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. + */ + + +/** + * Controller for the language field type. The language field type allows the + * user to select a language from the set of languages supported by the + * Guacamole web application. + */ +angular.module('form').controller('languageFieldController', ['$scope', '$injector', + function languageFieldController($scope, $injector) { + + // Required services + var languageService = $injector.get('languageService'); + var requestService = $injector.get('requestService'); + + /** + * A map of all available language keys to their human-readable + * names. + * + * @type Object. + */ + $scope.languages = null; + + // Retrieve defined languages + languageService.getLanguages().then(function languagesRetrieved(languages) { + $scope.$apply(function updateLanguageOptions() { + $scope.languages = languages; + }); + }, requestService.DIE); + + // Interpret undefined/null as empty string + $scope.$watch('model', function setModel(model) { + if (!model && model !== '') + $scope.model = ''; + }); + +}]); diff --git a/guacamole/src/main/webapp/app/form/formModule.js b/guacamole/src/main/webapp/app/form/formModule.js index 7e6ede998..113511842 100644 --- a/guacamole/src/main/webapp/app/form/formModule.js +++ b/guacamole/src/main/webapp/app/form/formModule.js @@ -20,4 +20,7 @@ /** * Module for displaying dynamic forms. */ -angular.module('form', ['locale']); +angular.module('form', [ + 'locale', + 'rest' +]); diff --git a/guacamole/src/main/webapp/app/form/services/formService.js b/guacamole/src/main/webapp/app/form/services/formService.js index 168a1efa7..6019e7445 100644 --- a/guacamole/src/main/webapp/app/form/services/formService.js +++ b/guacamole/src/main/webapp/app/form/services/formService.js @@ -130,6 +130,21 @@ angular.module('form').provider('formService', function formServiceProvider() { templateUrl : 'app/form/templates/textAreaField.html' }, + /** + * Field type which allows selection of languages. The languages + * displayed are the set of languages supported by the Guacamole web + * application. Legal values are valid language IDs, as dictated by + * the filenames of Guacamole's available translations. + * + * @see {@link Field.Type.LANGUAGE} + * @type FieldType + */ + 'LANGUAGE' : { + module : 'form', + controller : 'languageFieldController', + templateUrl : 'app/form/templates/languageField.html' + }, + /** * Field type which allows selection of time zones. * diff --git a/guacamole/src/main/webapp/app/form/templates/languageField.html b/guacamole/src/main/webapp/app/form/templates/languageField.html new file mode 100644 index 000000000..404f74e5e --- /dev/null +++ b/guacamole/src/main/webapp/app/form/templates/languageField.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js b/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js index 71e7af73e..aad0a2e0e 100644 --- a/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js +++ b/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js @@ -39,7 +39,6 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe var $translate = $injector.get('$translate'); var authenticationService = $injector.get('authenticationService'); var guacNotification = $injector.get('guacNotification'); - var languageService = $injector.get('languageService'); var permissionService = $injector.get('permissionService'); var preferenceService = $injector.get('preferenceService'); var requestService = $injector.get('requestService'); @@ -78,21 +77,23 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe * @type Object. */ $scope.preferences = preferenceService.preferences; - + /** - * A map of all available language keys to their human-readable - * names. - * - * @type Object. + * The fields which should be displayed for choosing locale + * preferences. Each field name must be a property on + * $scope.preferences. + * + * @type Field[] */ - $scope.languages = null; - - /** - * Switches the active display langugae to the chosen language. - */ - $scope.changeLanguage = function changeLanguage() { - $translate.use($scope.preferences.language); - }; + $scope.localeFields = [ + { 'type' : 'LANGUAGE', 'name' : 'language' }, + { 'type' : 'TIMEZONE', 'name' : 'timezone' } + ]; + + // Automatically update applied translation when language preference is changed + $scope.$watch('preferences.language', function changeLanguage(language) { + $translate.use(language); + }); /** * The new password for the user. @@ -169,17 +170,6 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe }; - // Retrieve defined languages - languageService.getLanguages() - .then(function languagesRetrieved(languages) { - $scope.languages = Object.keys(languages).map(function(key) { - return { - key: key, - value: languages[key] - }; - }); - }, requestService.DIE); - // Retrieve current permissions permissionService.getEffectivePermissions(dataSource, username) .then(function permissionsRetrieved(permissions) { diff --git a/guacamole/src/main/webapp/app/settings/styles/preferences.css b/guacamole/src/main/webapp/app/settings/styles/preferences.css index 9a966b552..dbb2330a8 100644 --- a/guacamole/src/main/webapp/app/settings/styles/preferences.css +++ b/guacamole/src/main/webapp/app/settings/styles/preferences.css @@ -17,8 +17,23 @@ * under the License. */ -.preferences .update-password .form, -.preferences .locale .form { +.preferences .form .fields { + display: table; padding-left: 0.5em; - border-left: 3px solid rgba(0, 0, 0, 0.125); -} \ No newline at end of file + border-left: 3px solid rgba(0,0,0,0.125); +} + +.preferences .form .fields .labeled-field { + display: table-row; +} + +.preferences .form .fields .field-header, +.preferences .form .fields .form-field { + display: table-cell; + padding: 0.125em; + vertical-align: top; +} + +.preferences .form .fields .field-header { + padding-right: 1em; +} diff --git a/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html b/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html index 8c924539b..581a66e9c 100644 --- a/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html +++ b/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html @@ -3,25 +3,7 @@

{{'SETTINGS_PREFERENCES.HELP_LOCALE' | translate}}

- - -
- - - - - -
{{'SETTINGS_PREFERENCES.FIELD_HEADER_LANGUAGE' | translate}}
-
- - -
- - -
+