GUACAMOLE-422: Merge use consistent mechanism for locale preferences.
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 19f1ead..9fe76a4 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
@@ -92,6 +92,14 @@
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 0000000..a87d772
--- /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 0000000..fdab137
--- /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.<String, String>
+ */
+ $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 7e6ede9..1135118 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 168a1ef..6019e74 100644
--- a/guacamole/src/main/webapp/app/form/services/formService.js
+++ b/guacamole/src/main/webapp/app/form/services/formService.js
@@ -131,6 +131,21 @@
},
/**
+ * 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.
*
* @see {@link Field.Type.TIMEZONE}
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 0000000..404f74e
--- /dev/null
+++ b/guacamole/src/main/webapp/app/form/templates/languageField.html
@@ -0,0 +1 @@
+<select ng-model="model" ng-options="language.key as language.value for language in languages | toArray | orderBy: key"></select>
\ 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 71e7af7..aad0a2e 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 @@
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 @@
* @type Object.<String, Object>
*/
$scope.preferences = preferenceService.preferences;
-
+
/**
- * A map of all available language keys to their human-readable
- * names.
- *
- * @type Object.<String, String>
+ * 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 @@
};
- // 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 9a966b5..dbb2330 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 8c92453..581a66e 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 @@
<!-- Locale settings -->
<div class="settings section locale">
<p>{{'SETTINGS_PREFERENCES.HELP_LOCALE' | translate}}</p>
-
- <!-- Language selection -->
- <div class="form">
- <table class="fields">
- <tr>
- <th>{{'SETTINGS_PREFERENCES.FIELD_HEADER_LANGUAGE' | translate}}</th>
- <td><select ng-model="preferences.language" ng-change="changeLanguage()" ng-options="language.key as language.value for language in languages | orderBy: key"></select></td>
- </tr>
- </table>
- </div>
-
- <!-- Timezone selection -->
- <div class="form">
- <guac-form-field
- field="{ 'type' : 'TIMEZONE', 'name' : 'timezone' }"
- model="preferences.timezone"
- namespace="'SETTINGS_PREFERENCES'">
- </guac-form-field>
- </div>
+ <guac-form content="localeFields" model="preferences" namespace="'SETTINGS_PREFERENCES'"></guac-form>
</div>
<!-- Password update -->