mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 00:53:21 +00:00 
			
		
		
		
	Merge pull request #192 from glyptodon/custom-field-types
GUAC-1176: Implement support for custom field types
This commit is contained in:
		| @@ -0,0 +1,40 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 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. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Controller for checkbox fields. | ||||
|  */ | ||||
| angular.module('form').controller('checkboxFieldController', ['$scope', | ||||
|     function checkboxFieldController($scope) { | ||||
|  | ||||
|     // Update typed value when model is changed | ||||
|     $scope.$watch('model', function modelChanged(model) { | ||||
|         $scope.typedValue = (model === $scope.field.value); | ||||
|     }); | ||||
|  | ||||
|     // Update string value in model when typed value is changed | ||||
|     $scope.$watch('typedValue', function typedValueChanged(typedValue) { | ||||
|         $scope.model = (typedValue ? $scope.field.value : ''); | ||||
|     }); | ||||
|  | ||||
| }]); | ||||
| @@ -0,0 +1,40 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 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. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Controller for number fields. | ||||
|  */ | ||||
| angular.module('form').controller('numberFieldController', ['$scope', | ||||
|     function numberFieldController($scope) { | ||||
|  | ||||
|     // Update typed value when model is changed | ||||
|     $scope.$watch('model', function modelChanged(model) { | ||||
|         $scope.typedValue = (model ? Number(model) : null); | ||||
|     }); | ||||
|  | ||||
|     // Update string value in model when typed value is changed | ||||
|     $scope.$watch('typedValue', function typedValueChanged(typedValue) { | ||||
|         $scope.model = (typedValue ? typedValue.toString() : ''); | ||||
|     }); | ||||
|  | ||||
| }]); | ||||
| @@ -0,0 +1,75 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 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. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Controller for password fields. | ||||
|  */ | ||||
| angular.module('form').controller('passwordFieldController', ['$scope', | ||||
|     function passwordFieldController($scope) { | ||||
|  | ||||
|     /** | ||||
|      * The type to use for the input field. By default, the input field will | ||||
|      * have the type 'password', and thus will be masked. | ||||
|      * | ||||
|      * @type String | ||||
|      * @default 'password' | ||||
|      */ | ||||
|     $scope.passwordInputType = 'password'; | ||||
|  | ||||
|     /** | ||||
|      * Returns a string which describes the action the next call to | ||||
|      * togglePassword() will have. | ||||
|      * | ||||
|      * @return {String} | ||||
|      *     A string which describes the action the next call to | ||||
|      *     togglePassword() will have. | ||||
|      */ | ||||
|     $scope.getTogglePasswordHelpText = function getTogglePasswordHelpText() { | ||||
|  | ||||
|         // If password is hidden, togglePassword() will show the password | ||||
|         if ($scope.passwordInputType === 'password') | ||||
|             return 'FORM.HELP_SHOW_PASSWORD'; | ||||
|  | ||||
|         // If password is shown, togglePassword() will hide the password | ||||
|         return 'FORM.HELP_HIDE_PASSWORD'; | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Toggles visibility of the field contents, if this field is a | ||||
|      * password field. Initially, password contents are masked | ||||
|      * (invisible). | ||||
|      */ | ||||
|     $scope.togglePassword = function togglePassword() { | ||||
|  | ||||
|         // If password is hidden, show the password | ||||
|         if ($scope.passwordInputType === 'password') | ||||
|             $scope.passwordInputType = 'text'; | ||||
|  | ||||
|         // If password is shown, hide the password | ||||
|         else | ||||
|             $scope.passwordInputType = 'password'; | ||||
|  | ||||
|     }; | ||||
|  | ||||
| }]); | ||||
| @@ -0,0 +1,64 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 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. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Controller for select fields. | ||||
|  */ | ||||
| angular.module('form').controller('selectFieldController', ['$scope', '$injector', | ||||
|     function selectFieldController($scope, $injector) { | ||||
|  | ||||
|     // Required services | ||||
|     var translationStringService = $injector.get('translationStringService'); | ||||
|  | ||||
|     /** | ||||
|      * Produces the translation string for the given field option | ||||
|      * value. The translation string will be of the form: | ||||
|      * | ||||
|      * <code>NAMESPACE.FIELD_OPTION_NAME_VALUE<code> | ||||
|      * | ||||
|      * where <code>NAMESPACE</code> is the namespace provided to the | ||||
|      * directive, <code>NAME</code> is the field name transformed | ||||
|      * via translationStringService.canonicalize(), and | ||||
|      * <code>VALUE</code> is the option value transformed via | ||||
|      * translationStringService.canonicalize() | ||||
|      * | ||||
|      * @param {String} value | ||||
|      *     The name of the option value. | ||||
|      * | ||||
|      * @returns {String} | ||||
|      *     The translation string which produces the translated name of the | ||||
|      *     value specified. | ||||
|      */ | ||||
|     $scope.getFieldOption = function getFieldOption(value) { | ||||
|  | ||||
|         // If no field, or no value, then no corresponding translation string | ||||
|         if (!$scope.field || !$scope.field.name || !value) | ||||
|             return ''; | ||||
|  | ||||
|         return translationStringService.canonicalize($scope.namespace || 'MISSING_NAMESPACE') | ||||
|                 + '.FIELD_OPTION_' + translationStringService.canonicalize($scope.field.name) | ||||
|                 + '_'              + translationStringService.canonicalize(value || 'EMPTY'); | ||||
|  | ||||
|     }; | ||||
|  | ||||
| }]); | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Glyptodon LLC | ||||
|  * Copyright (C) 2015 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 | ||||
| @@ -60,55 +60,19 @@ angular.module('form').directive('guacFormField', [function formField() { | ||||
|  | ||||
|         }, | ||||
|         templateUrl: 'app/form/templates/formField.html', | ||||
|         controller: ['$scope', '$injector', function formFieldController($scope, $injector) { | ||||
|         controller: ['$scope', '$injector', '$element', function formFieldController($scope, $injector, $element) { | ||||
|  | ||||
|             // Required services | ||||
|             var formService              = $injector.get('formService'); | ||||
|             var translationStringService = $injector.get('translationStringService'); | ||||
|  | ||||
|             /** | ||||
|              * The type to use for password input fields. By default, password | ||||
|              * input fields have type 'password', and are thus masked. | ||||
|              *  | ||||
|              * @type String | ||||
|              * @default 'password' | ||||
|              */ | ||||
|             $scope.passwordInputType = 'password'; | ||||
|  | ||||
|             /** | ||||
|              * Returns a string which describes the action the next call to | ||||
|              * togglePassword() will have. | ||||
|              * The element which should contain any compiled field content. The | ||||
|              * actual content of a field is dynamically determined by its type. | ||||
|              * | ||||
|              * @return {String} | ||||
|              *     A string which describes the action the next call to | ||||
|              *     togglePassword() will have. | ||||
|              * @type Element[] | ||||
|              */ | ||||
|             $scope.getTogglePasswordHelpText = function getTogglePasswordHelpText() { | ||||
|  | ||||
|                 // If password is hidden, togglePassword() will show the password | ||||
|                 if ($scope.passwordInputType === 'password') | ||||
|                     return 'FORM.HELP_SHOW_PASSWORD'; | ||||
|  | ||||
|                 // If password is shown, togglePassword() will hide the password | ||||
|                 return 'FORM.HELP_HIDE_PASSWORD'; | ||||
|  | ||||
|             }; | ||||
|  | ||||
|             /** | ||||
|              * Toggles visibility of the field contents, if this field is a  | ||||
|              * password field. Initially, password contents are masked | ||||
|              * (invisible). | ||||
|              */ | ||||
|             $scope.togglePassword = function togglePassword() { | ||||
|  | ||||
|                 // If password is hidden, show the password | ||||
|                 if ($scope.passwordInputType === 'password') | ||||
|                     $scope.passwordInputType = 'text'; | ||||
|  | ||||
|                 // If password is shown, hide the password | ||||
|                 else | ||||
|                     $scope.passwordInputType = 'password'; | ||||
|  | ||||
|             }; | ||||
|             var fieldContent = $element.find('.form-field'); | ||||
|  | ||||
|             /** | ||||
|              * Produces the translation string for the header of the current | ||||
| @@ -135,113 +99,20 @@ angular.module('form').directive('guacFormField', [function formField() { | ||||
|  | ||||
|             }; | ||||
|  | ||||
|             /** | ||||
|              * Produces the translation string for the given field option | ||||
|              * value. The translation string will be of the form: | ||||
|              * | ||||
|              * <code>NAMESPACE.FIELD_OPTION_NAME_VALUE<code> | ||||
|              * | ||||
|              * where <code>NAMESPACE</code> is the namespace provided to the | ||||
|              * directive, <code>NAME</code> is the field name transformed | ||||
|              * via translationStringService.canonicalize(), and | ||||
|              * <code>VALUE</code> is the option value transformed via | ||||
|              * translationStringService.canonicalize() | ||||
|              * | ||||
|              * @param {String} value | ||||
|              *     The name of the option value. | ||||
|              * | ||||
|              * @returns {String} | ||||
|              *     The translation string which produces the translated name of the | ||||
|              *     value specified. | ||||
|              */ | ||||
|             $scope.getFieldOption = function getFieldOption(value) { | ||||
|             // Update field contents when field definition is changed | ||||
|             $scope.$watch('field', function setField(field) { | ||||
|  | ||||
|                 // If no field, or no value, then no corresponding translation string | ||||
|                 if (!$scope.field || !$scope.field.name || !value) | ||||
|                     return ''; | ||||
|                 // Reset contents | ||||
|                 fieldContent.innerHTML = ''; | ||||
|  | ||||
|                 return translationStringService.canonicalize($scope.namespace || 'MISSING_NAMESPACE') | ||||
|                         + '.FIELD_OPTION_' + translationStringService.canonicalize($scope.field.name) | ||||
|                         + '_'              + translationStringService.canonicalize(value || 'EMPTY'); | ||||
|  | ||||
|             }; | ||||
|  | ||||
|             /** | ||||
|              * Translates the given string field value into an appropriately- | ||||
|              * typed value as dictated by the attributes of the field, | ||||
|              * exposing that typed value within the scope as | ||||
|              * <code>$scope.typedValue<code>. | ||||
|              * | ||||
|              * @param {String} modelValue | ||||
|              *     The current string value of the field. | ||||
|              */ | ||||
|             var setTypedValue = function setTypedValue(modelValue) { | ||||
|  | ||||
|                 // Don't bother if the model is not yet defined | ||||
|                 if (!$scope.field) | ||||
|                     return; | ||||
|  | ||||
|                 // Coerce numeric strings to numbers | ||||
|                 if ($scope.field.type === 'NUMERIC') | ||||
|                     $scope.typedValue = (modelValue ? Number(modelValue) : null); | ||||
|  | ||||
|                 // Coerce boolean strings to boolean values | ||||
|                 else if ($scope.field.type === 'BOOLEAN') | ||||
|                     $scope.typedValue = (modelValue === $scope.field.value); | ||||
|  | ||||
|                 // All other field types are represented internally as strings | ||||
|                 else | ||||
|                     $scope.typedValue = modelValue || ''; | ||||
|  | ||||
|             }; | ||||
|  | ||||
|             /** | ||||
|              * Translates the given typed field value into a string as dictated | ||||
|              * by the attributes of the field, assigning that string value to | ||||
|              * the model. | ||||
|              * | ||||
|              * @param {String|Number|Boolean} typedValue | ||||
|              *     The current value of the field, as an appropriate JavaScript | ||||
|              *     type. | ||||
|              */ | ||||
|             var setModelValue = function setModelValue(typedValue) { | ||||
|  | ||||
|                 // Don't bother if the model is not yet defined | ||||
|                 if (!$scope.field) | ||||
|                     return; | ||||
|  | ||||
|                 // Convert numeric values back into strings | ||||
|                 if ($scope.field.type === 'NUMERIC') { | ||||
|                     if (!typedValue) | ||||
|                         $scope.model = ''; | ||||
|                     else | ||||
|                         $scope.model = typedValue.toString(); | ||||
|                 // Append field content | ||||
|                 if (field) { | ||||
|                     formService.createFieldElement(field.type, $scope) | ||||
|                     .then(function fieldElementCreated(element) { | ||||
|                         fieldContent.append(element); | ||||
|                     }); | ||||
|                 } | ||||
|  | ||||
|                 // Convert boolean values back into strings based on field description | ||||
|                 else if ($scope.field.type === 'BOOLEAN') | ||||
|                     $scope.model = (typedValue ? $scope.field.value : ''); | ||||
|  | ||||
|                 // All other field types are already strings | ||||
|                 else | ||||
|                     $scope.model = typedValue || ''; | ||||
|  | ||||
|             }; | ||||
|  | ||||
|             // Update string value and re-assign to model when field is changed | ||||
|             $scope.$watch('field', function setField(field) { | ||||
|                 setTypedValue($scope.model); | ||||
|                 setModelValue($scope.typedValue); | ||||
|             }); | ||||
|  | ||||
|             // Update typed value when model is changed | ||||
|             $scope.$watch('model', function setModel(model) { | ||||
|                 setTypedValue(model); | ||||
|             }); | ||||
|  | ||||
|             // Update string value in model when typed value is changed | ||||
|             $scope.$watch('typedValue', function typedValueChanged(typedValue) { | ||||
|                 setModelValue(typedValue); | ||||
|             }); | ||||
|  | ||||
|         }] // end controller | ||||
|   | ||||
							
								
								
									
										275
									
								
								guacamole/src/main/webapp/app/form/services/formService.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								guacamole/src/main/webapp/app/form/services/formService.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,275 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 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. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * A service for maintaining form-related metadata and linking that data to | ||||
|  * corresponding controllers and templates. | ||||
|  */ | ||||
| angular.module('form').provider('formService', function formServiceProvider() { | ||||
|  | ||||
|     /** | ||||
|      * Reference to the provider itself. | ||||
|      * | ||||
|      * @type formServiceProvider | ||||
|      */ | ||||
|     var provider = this; | ||||
|  | ||||
|     /** | ||||
|      * Map of all registered field type definitions by name. | ||||
|      * | ||||
|      * @type Object.<String, FieldType> | ||||
|      */ | ||||
|     this.fieldTypes = { | ||||
|  | ||||
|         /** | ||||
|          * Text field type. | ||||
|          * | ||||
|          * @see {@link Field.Type.TEXT} | ||||
|          * @type FieldType | ||||
|          */ | ||||
|         'TEXT' : { | ||||
|             templateUrl : 'app/form/templates/textField.html' | ||||
|         }, | ||||
|  | ||||
|         /** | ||||
|          * Numeric field type. | ||||
|          * | ||||
|          * @see {@link Field.Type.NUMERIC} | ||||
|          * @type FieldType | ||||
|          */ | ||||
|         'NUMERIC' : { | ||||
|             module      : 'form', | ||||
|             controller  : 'numberFieldController', | ||||
|             templateUrl : 'app/form/templates/numberField.html' | ||||
|         }, | ||||
|  | ||||
|         /** | ||||
|          * Boolean field type. | ||||
|          * | ||||
|          * @see {@link Field.Type.BOOLEAN} | ||||
|          * @type FieldType | ||||
|          */ | ||||
|         'BOOLEAN' : { | ||||
|             module      : 'form', | ||||
|             controller  : 'checkboxFieldController', | ||||
|             templateUrl : 'app/form/templates/checkboxField.html' | ||||
|         }, | ||||
|  | ||||
|         /** | ||||
|          * Username field type. Identical in principle to a text field, but may | ||||
|          * have different semantics. | ||||
|          * | ||||
|          * @see {@link Field.Type.USERNAME} | ||||
|          * @type FieldType | ||||
|          */ | ||||
|         'USERNAME' : { | ||||
|             templateUrl : 'app/form/templates/textField.html' | ||||
|         }, | ||||
|  | ||||
|         /** | ||||
|          * Password field type. Similar to a text field, but the contents of | ||||
|          * the field are masked. | ||||
|          * | ||||
|          * @see {@link Field.Type.PASSWORD} | ||||
|          * @type FieldType | ||||
|          */ | ||||
|         'PASSWORD' : { | ||||
|             module      : 'form', | ||||
|             controller  : 'passwordFieldController', | ||||
|             templateUrl : 'app/form/templates/passwordField.html' | ||||
|         }, | ||||
|  | ||||
|         /** | ||||
|          * Enumerated field type. The user is presented a finite list of values | ||||
|          * to choose from. | ||||
|          * | ||||
|          * @see {@link Field.Type.ENUM} | ||||
|          * @type FieldType | ||||
|          */ | ||||
|         'ENUM' : { | ||||
|             module      : 'form', | ||||
|             controller  : 'selectFieldController', | ||||
|             templateUrl : 'app/form/templates/selectField.html' | ||||
|         }, | ||||
|  | ||||
|         /** | ||||
|          * Multiline field type. The user may enter multiple lines of text. | ||||
|          * | ||||
|          * @see {@link Field.Type.MULTILINE} | ||||
|          * @type FieldType | ||||
|          */ | ||||
|         'MULTILINE' : { | ||||
|             templateUrl : 'app/form/templates/textAreaField.html' | ||||
|         } | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Registers a new field type under the given name. | ||||
|      * | ||||
|      * @param {String} fieldTypeName | ||||
|      *     The name which uniquely identifies the field type being registered. | ||||
|      * | ||||
|      * @param {FieldType} fieldType | ||||
|      *     The field type definition to associate with the given name. | ||||
|      */ | ||||
|     this.registerFieldType = function registerFieldType(fieldTypeName, fieldType) { | ||||
|  | ||||
|         // Store field type | ||||
|         provider.fieldTypes[fieldTypeName] = fieldType; | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     // Factory method required by provider | ||||
|     this.$get = ['$injector', function formServiceFactory($injector) { | ||||
|  | ||||
|         // Required services | ||||
|         var $compile       = $injector.get('$compile'); | ||||
|         var $http          = $injector.get('$http'); | ||||
|         var $q             = $injector.get('$q'); | ||||
|         var $templateCache = $injector.get('$templateCache'); | ||||
|  | ||||
|         var service = {}; | ||||
|  | ||||
|         service.fieldTypes = provider.fieldTypes; | ||||
|  | ||||
|         /** | ||||
|          * Returns a Promise which resolves with the HTML contents of the | ||||
|          * template at the given URL. The template contents will be retrieved from | ||||
|          * the $templateCache if possible. | ||||
|          * | ||||
|          * @param {String} url | ||||
|          *     The URL of the template to retrieve. | ||||
|          * | ||||
|          * @returns {Promise.<String>} | ||||
|          *     A Promise which resolves with the HTML contents of the template at | ||||
|          *     the given URL. | ||||
|          */ | ||||
|         var templateRequest = function templateRequest(url) { | ||||
|  | ||||
|             // Pull template from cache if present | ||||
|             var template = $templateCache.get(url); | ||||
|             if (template) | ||||
|                 return $q.when(template); | ||||
|  | ||||
|             // Defer retrieval of template | ||||
|             var templateContent = $q.defer(); | ||||
|  | ||||
|             // Retrieve template manually | ||||
|             $http({ | ||||
|                 method : 'GET', | ||||
|                 url    : url, | ||||
|                 cache  : true | ||||
|             }) | ||||
|  | ||||
|             // Upon success, resolve promise and update template cache | ||||
|             .success(function templateRetrieved(html) { | ||||
|                 $templateCache.put(url, html); | ||||
|                 templateContent.resolve(html); | ||||
|             }) | ||||
|  | ||||
|             // Fail if template cannot be retrieved | ||||
|             .error(function templateError() { | ||||
|                 templateContent.reject(); | ||||
|             }); | ||||
|  | ||||
|             // Return promise which will resolve with the retrieved template | ||||
|             return templateContent.promise; | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * Compiles and links the field associated with the given name to the given | ||||
|          * scope, producing a distinct and independent DOM Element which functions | ||||
|          * as an instance of that field. The scope object provided must include at | ||||
|          * least the following properties: | ||||
|          * | ||||
|          * namespace: | ||||
|          *     A String which defines the unique namespace associated the | ||||
|          *     translation strings used by the form using a field of this type. | ||||
|          * | ||||
|          * field: | ||||
|          *     The Field object that is being rendered, representing a field of | ||||
|          *     this type. | ||||
|          * | ||||
|          * model: | ||||
|          *     The current String value of the field, if any. | ||||
|          * | ||||
|          * @param {String} fieldTypeName | ||||
|          *     The name of the field type defining the nature of the element to be | ||||
|          *     created. | ||||
|          * | ||||
|          * @param {Object} scope | ||||
|          *     The scope to which the new element will be linked. | ||||
|          * | ||||
|          * @return {Promise.<Element>} | ||||
|          *     A Promise which resolves to the compiled Element. If an error occurs | ||||
|          *     while retrieving the field type, this Promise will be rejected. | ||||
|          */ | ||||
|         service.createFieldElement = function createFieldElement(fieldTypeName, scope) { | ||||
|  | ||||
|             // Ensure field type is defined | ||||
|             var fieldType = provider.fieldTypes[fieldTypeName]; | ||||
|             if (!fieldType) | ||||
|                 return $q.reject(); | ||||
|  | ||||
|             // Populate scope using defined controller | ||||
|             if (fieldType.module && fieldType.controller) { | ||||
|                 var $controller = angular.injector(['ng', fieldType.module]).get('$controller'); | ||||
|                 $controller(fieldType.controller, {'$scope' : scope}); | ||||
|             } | ||||
|  | ||||
|             // Defer compilation of template pending successful retrieval | ||||
|             var compiledTemplate = $q.defer(); | ||||
|  | ||||
|             // Use raw HTML template if provided | ||||
|             if (fieldType.template) | ||||
|                 compiledTemplate.resolve($compile(fieldType.template)(scope)); | ||||
|  | ||||
|             // If no raw HTML template is provided, retrieve template from URL | ||||
|             else { | ||||
|  | ||||
|                 // Attempt to retrieve template HTML | ||||
|                 templateRequest(fieldType.templateUrl) | ||||
|  | ||||
|                 // Resolve with compiled HTML upon success | ||||
|                 .then(function templateRetrieved(html) { | ||||
|                     compiledTemplate.resolve($compile(html)(scope)); | ||||
|                 }) | ||||
|  | ||||
|                 // Reject on failure | ||||
|                 ['catch'](function templateError() { | ||||
|                     compiledTemplate.reject(); | ||||
|                 }); | ||||
|  | ||||
|             } | ||||
|  | ||||
|             // Return promise which resolves to the compiled template | ||||
|             return compiledTemplate.promise; | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         return service; | ||||
|  | ||||
|     }]; | ||||
|  | ||||
| }); | ||||
| @@ -0,0 +1 @@ | ||||
| <input type="checkbox" ng-model="typedValue" autocorrect="off" autocapitalize="off"/> | ||||
| @@ -24,24 +24,8 @@ | ||||
|     <!-- Field header --> | ||||
|     <span class="field-header">{{getFieldHeader() | translate}}</span> | ||||
|  | ||||
|     <!-- Generic input types --> | ||||
|     <!-- Field content --> | ||||
|     <div class="form-field"> | ||||
|         <input ng-show="field.type === 'TEXT'"     type="text"     ng-model="typedValue" autocorrect="off" autocapitalize="off"/> | ||||
|         <input ng-show="field.type === 'NUMERIC'"  type="number"   ng-model="typedValue" autocorrect="off" autocapitalize="off"/> | ||||
|         <input ng-show="field.type === 'USERNAME'" type="text"     ng-model="typedValue" autocorrect="off" autocapitalize="off"/> | ||||
|         <input ng-show="field.type === 'BOOLEAN'"  type="checkbox" ng-model="typedValue" autocorrect="off" autocapitalize="off"/> | ||||
|  | ||||
|         <!-- Password field --> | ||||
|         <div ng-show="field.type === 'PASSWORD'" class="password-field"> | ||||
|             <input type="{{passwordInputType}}" ng-model="typedValue" autocorrect="off" autocapitalize="off"/> | ||||
|             <div class="icon toggle-password" ng-click="togglePassword()" title="{{getTogglePasswordHelpText() | translate}}"></div> | ||||
|         </div> | ||||
|  | ||||
|         <!-- Multiline field --> | ||||
|         <textarea ng-show="field.type === 'MULTILINE'" ng-model="typedValue" autocorrect="off" autocapitalize="off"></textarea> | ||||
|  | ||||
|         <!-- Enumerated field --> | ||||
|         <select ng-show="field.type === 'ENUM'" ng-model="typedValue" ng-options="option.value as getFieldOption(option.value) | translate for option in field.options | orderBy: value"></select> | ||||
|     </div> | ||||
|  | ||||
| </label> | ||||
|   | ||||
| @@ -0,0 +1 @@ | ||||
| <input type="number" ng-model="typedValue" autocorrect="off" autocapitalize="off"/> | ||||
| @@ -0,0 +1,4 @@ | ||||
| <div class="password-field"> | ||||
|     <input type="{{passwordInputType}}" ng-model="model" autocorrect="off" autocapitalize="off"/> | ||||
|     <div class="icon toggle-password" ng-click="togglePassword()" title="{{getTogglePasswordHelpText() | translate}}"></div> | ||||
| </div> | ||||
| @@ -0,0 +1 @@ | ||||
| <select ng-model="model" ng-options="option.value as getFieldOption(option.value) | translate for option in field.options | orderBy: value"></select> | ||||
| @@ -0,0 +1 @@ | ||||
| <textarea ng-model="model" autocorrect="off" autocapitalize="off"></textarea> | ||||
| @@ -0,0 +1 @@ | ||||
| <input type="text" ng-model="model" autocorrect="off" autocapitalize="off"/> | ||||
							
								
								
									
										92
									
								
								guacamole/src/main/webapp/app/form/types/FieldType.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								guacamole/src/main/webapp/app/form/types/FieldType.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 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. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Service which defines the FieldType class. | ||||
|  */ | ||||
| angular.module('form').factory('FieldType', [function defineFieldType() { | ||||
|              | ||||
|     /** | ||||
|      * The object used by the formService for describing field types. | ||||
|      *  | ||||
|      * @constructor | ||||
|      * @param {FieldType|Object} [template={}] | ||||
|      *     The object whose properties should be copied within the new | ||||
|      *     FieldType. | ||||
|      */ | ||||
|     var FieldType = function FieldType(template) { | ||||
|  | ||||
|         // Use empty object by default | ||||
|         template = template || {}; | ||||
|  | ||||
|         /** | ||||
|          * The raw HTML of the template that should be injected into the DOM of | ||||
|          * a form using this field type. If provided, this will be used instead | ||||
|          * of templateUrl. | ||||
|          * | ||||
|          * @type String | ||||
|          */ | ||||
|         this.template = template.template; | ||||
|  | ||||
|         /** | ||||
|          * The URL of the template that should be injected into the DOM of a | ||||
|          * form using this field type. This property will be ignored if a raw | ||||
|          * HTML template is supplied via the template property. | ||||
|          * | ||||
|          * @type String | ||||
|          */ | ||||
|         this.templateUrl = template.templateUrl; | ||||
|  | ||||
|         /** | ||||
|          * The name of the AngularJS module defining the controller for this | ||||
|          * field type. This is optional, as not all field types will need | ||||
|          * controllers. | ||||
|          * | ||||
|          * @type String | ||||
|          */ | ||||
|         this.module = template.module; | ||||
|  | ||||
|         /** | ||||
|          * The name of the controller for this field type. This is optional, as | ||||
|          * not all field types will need controllers. If a controller is | ||||
|          * specified, it will receive the following properties on the scope: | ||||
|          * | ||||
|          * namespace: | ||||
|          *     A String which defines the unique namespace associated the | ||||
|          *     translation strings used by the form using a field of this type. | ||||
|          * | ||||
|          * field: | ||||
|          *     The Field object that is being rendered, representing a field of | ||||
|          *     this type. | ||||
|          * | ||||
|          * model: | ||||
|          *     The current String value of the field, if any. | ||||
|          * | ||||
|          * @type String | ||||
|          */ | ||||
|         this.controller = template.controller; | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     return FieldType; | ||||
|  | ||||
| }]); | ||||
		Reference in New Issue
	
	Block a user