mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 00:53:21 +00:00 
			
		
		
		
	GUACAMOLE-220: Implement generic editor directive for manipulating sets of identifiers.
This commit is contained in:
		| @@ -0,0 +1,267 @@ | ||||
| /* | ||||
|  * 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. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * A directive for manipulating a set of objects sharing some common relation | ||||
|  * and represented by an array of their identifiers. The specific objects | ||||
|  * added or removed are tracked within a separate pair of arrays of | ||||
|  * identifiers. | ||||
|  */ | ||||
| angular.module('manage').directive('identifierSetEditor', ['$injector', | ||||
|     function identifierSetEditor($injector) { | ||||
|  | ||||
|     var directive = { | ||||
|  | ||||
|         // Element only | ||||
|         restrict: 'E', | ||||
|         replace: true, | ||||
|  | ||||
|         scope: { | ||||
|  | ||||
|             /** | ||||
|              * The translation key of the text which should be displayed within | ||||
|              * the main header of the identifier set editor. | ||||
|              * | ||||
|              * @type String | ||||
|              */ | ||||
|             header : '@', | ||||
|  | ||||
|             /** | ||||
|              * The translation key of the text which should be displayed if no | ||||
|              * identifiers are currently present within the set. | ||||
|              * | ||||
|              * @type String | ||||
|              */ | ||||
|             emptyPlaceholder : '@', | ||||
|  | ||||
|             /** | ||||
|              * The translation key of the text which should be displayed if no | ||||
|              * identifiers are available to be added within the set. | ||||
|              * | ||||
|              * @type String | ||||
|              */ | ||||
|             unavailablePlaceholder : '@', | ||||
|  | ||||
|             /** | ||||
|              * All identifiers which are available to be added to or removed | ||||
|              * from the identifier set being edited. | ||||
|              * | ||||
|              * @type String[] | ||||
|              */ | ||||
|             identifiersAvailable : '=', | ||||
|  | ||||
|             /** | ||||
|              * The current state of the identifier set being manipulated. This | ||||
|              * array will be modified as changes are made through this | ||||
|              * identifier set editor. | ||||
|              * | ||||
|              * @type String[] | ||||
|              */ | ||||
|             identifiers : '=', | ||||
|  | ||||
|             /** | ||||
|              * The set of identifiers that have been added, relative to the | ||||
|              * initial state of the identifier set being manipulated. | ||||
|              * | ||||
|              * @type String[] | ||||
|              */ | ||||
|             identifiersAdded : '=', | ||||
|  | ||||
|             /** | ||||
|              * The set of identifiers that have been removed, relative to the | ||||
|              * initial state of the identifier set being manipulated. | ||||
|              * | ||||
|              * @type String[] | ||||
|              */ | ||||
|             identifiersRemoved : '=' | ||||
|  | ||||
|         }, | ||||
|  | ||||
|         templateUrl: 'app/manage/templates/identifierSetEditor.html' | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     directive.controller = ['$scope', function identifierSetEditorController($scope) { | ||||
|  | ||||
|         /** | ||||
|          * Whether the full list of available identifiers should be displayed. | ||||
|          * Initially, only an abbreviated list of identifiers currently present | ||||
|          * is shown. | ||||
|          * | ||||
|          * @type Boolean | ||||
|          */ | ||||
|         $scope.expanded = false; | ||||
|  | ||||
|         /** | ||||
|          * Map of identifiers to boolean flags indicating whether that | ||||
|          * identifier is currently present (true) or absent (false). If an | ||||
|          * identifier is absent, it may also be absent from this map. | ||||
|          * | ||||
|          * @type Object.<String, Boolean> | ||||
|          */ | ||||
|         $scope.identifierFlags = {}; | ||||
|  | ||||
|         /** | ||||
|          * Adds the given identifier to the given sorted array of identifiers, | ||||
|          * preserving the sorted order of the array. If the identifier is | ||||
|          * already present, no change is made to the array. The given array | ||||
|          * must already be sorted in ascending order. | ||||
|          * | ||||
|          * @param {String[]} arr | ||||
|          *     The sorted array of identifiers to add the given identifier to. | ||||
|          * | ||||
|          * @param {String} identifier | ||||
|          *     The identifier to add to the given array. | ||||
|          */ | ||||
|         var addIdentifier = function addIdentifier(arr, identifier) { | ||||
|  | ||||
|             // Determine location that the identifier should be added to | ||||
|             // maintain sorted order | ||||
|             var index = _.sortedIndex(arr, identifier); | ||||
|  | ||||
|             // Do not add if already present | ||||
|             if (arr[index] === identifier) | ||||
|                 return; | ||||
|  | ||||
|             // Insert identifier at determined location | ||||
|             arr.splice(index, 0, identifier); | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * Removes the given identifier from the given sorted array of | ||||
|          * identifiers, preserving the sorted order of the array. If the | ||||
|          * identifier is already absent, no change is made to the array. The | ||||
|          * given array must already be sorted in ascending order. | ||||
|          * | ||||
|          * @param {String[]} arr | ||||
|          *     The sorted array of identifiers to remove the given identifier | ||||
|          *     from. | ||||
|          * | ||||
|          * @param {String} identifier | ||||
|          *     The identifier to remove from the given array. | ||||
|          * | ||||
|          * @returns {Boolean} | ||||
|          *     true if the identifier was present in the given array and has | ||||
|          *     been removed, false otherwise. | ||||
|          */ | ||||
|         var removeIdentifier = function removeIdentifier(arr, identifier) { | ||||
|  | ||||
|             // Search for identifier in sorted array | ||||
|             var index = _.sortedIndexOf(arr, identifier); | ||||
|  | ||||
|             // Nothing to do if already absent | ||||
|             if (index === -1) | ||||
|                 return false; | ||||
|  | ||||
|             // Remove identifier | ||||
|             arr.splice(index, 1); | ||||
|             return true; | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         // Keep identifierFlags up to date when identifiers array is replaced | ||||
|         // or initially assigned | ||||
|         $scope.$watch('identifiers', function identifiersChanged(identifiers) { | ||||
|  | ||||
|             // Maintain identifiers in sorted order so additions and removals | ||||
|             // can be made more efficiently | ||||
|             if (identifiers) | ||||
|                 identifiers.sort(); | ||||
|  | ||||
|             // Convert array of identifiers into set of boolean | ||||
|             // presence/absence flags | ||||
|             $scope.identifierFlags = {}; | ||||
|             angular.forEach(identifiers, function storeIdentifierFlag(identifier) { | ||||
|                 $scope.identifierFlags[identifier] = true; | ||||
|             }); | ||||
|  | ||||
|         }); | ||||
|  | ||||
|         /** | ||||
|          * Notifies the controller that a change has been made to the flag | ||||
|          * denoting presence/absence of a particular identifier within the | ||||
|          * <code>identifierFlags</code> map. The <code>identifiers</code>, | ||||
|          * <code>identifiersAdded</code>, and <code>identifiersRemoved</code> | ||||
|          * arrays are updated accordingly. | ||||
|          * | ||||
|          * @param {String} identifier | ||||
|          *     The identifier which has been added or removed through modifying | ||||
|          *     its boolean flag within <code>identifierFlags</code>. | ||||
|          */ | ||||
|         $scope.identifierChanged = function identifierChanged(identifier) { | ||||
|  | ||||
|             // Determine status of modified identifier | ||||
|             var present = !!$scope.identifierFlags[identifier]; | ||||
|  | ||||
|             // Add/remove identifier from added/removed sets depending on | ||||
|             // change in flag state | ||||
|             if (present) { | ||||
|  | ||||
|                 addIdentifier($scope.identifiers, identifier); | ||||
|  | ||||
|                 if (!removeIdentifier($scope.identifiersRemoved, identifier)) | ||||
|                     addIdentifier($scope.identifiersAdded, identifier); | ||||
|  | ||||
|             } | ||||
|             else { | ||||
|  | ||||
|                 removeIdentifier($scope.identifiers, identifier); | ||||
|  | ||||
|                 if (!removeIdentifier($scope.identifiersAdded, identifier)) | ||||
|                     addIdentifier($scope.identifiersRemoved, identifier); | ||||
|  | ||||
|             } | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * Removes the given identifier, updating <code>identifierFlags</code>, | ||||
|          * <code>identifiers</code>, <code>identifiersAdded</code>, and | ||||
|          * <code>identifiersRemoved</code> accordingly. | ||||
|          * | ||||
|          * @param {String} identifier | ||||
|          *     The identifier to remove. | ||||
|          */ | ||||
|         $scope.removeIdentifier = function removeIdentifier(identifier) { | ||||
|             $scope.identifierFlags[identifier] = false; | ||||
|             $scope.identifierChanged(identifier); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * Shows the full list of available identifiers. If the full list is | ||||
|          * already shown, this function has no effect. | ||||
|          */ | ||||
|         $scope.expand = function expand() { | ||||
|             $scope.expanded = true; | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * Hides the full list of available identifiers. If the full list is | ||||
|          * already hidden, this function has no effect. | ||||
|          */ | ||||
|         $scope.collapse = function collapse() { | ||||
|             $scope.expanded = false; | ||||
|         }; | ||||
|  | ||||
|     }]; | ||||
|  | ||||
|     return directive; | ||||
|  | ||||
| }]); | ||||
| @@ -0,0 +1,82 @@ | ||||
| /* | ||||
|  * 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. | ||||
|  */ | ||||
|  | ||||
| .related-objects .abbreviated-related-objects { | ||||
|     display: table; | ||||
|     margin: 1em 0; | ||||
| } | ||||
|  | ||||
| .related-objects .abbreviated-related-objects ul { | ||||
|     display: table-cell; | ||||
|     vertical-align: top; | ||||
| } | ||||
|  | ||||
| .related-objects .abbreviated-related-objects ul, | ||||
| .related-objects .all-related-objects ul { | ||||
|     padding: 0; | ||||
|     list-style: none; | ||||
| } | ||||
|  | ||||
| .related-objects .abbreviated-related-objects ul li { | ||||
|  | ||||
|     display: inline-block; | ||||
|     margin: 0.25em; | ||||
|     padding: 0.25em; | ||||
|  | ||||
|     border: 1px solid silver; | ||||
|     background: #F5F5F5; | ||||
|     -moz-border-radius: 0.25em; | ||||
|     -webkit-border-radius: 0.25em; | ||||
|     -khtml-border-radius: 0.25em; | ||||
|     border-radius: 0.25em; | ||||
|  | ||||
| } | ||||
|  | ||||
| .related-objects .abbreviated-related-objects ul li img.remove { | ||||
|     max-height: 0.75em; | ||||
|     max-width: 0.75em; | ||||
|     margin: 0 0.25em; | ||||
| } | ||||
|  | ||||
| .related-objects .abbreviated-related-objects ul li .identifier { | ||||
|     margin: 0 0.25em; | ||||
| } | ||||
|  | ||||
| .related-objects .abbreviated-related-objects img.expand, | ||||
| .related-objects .abbreviated-related-objects img.collapse { | ||||
|     display: table-cell; | ||||
|     max-height: 1.5em; | ||||
|     max-width: 1.5em; | ||||
|     margin: 0.375em 0; | ||||
| } | ||||
|  | ||||
| .related-objects .all-related-objects { | ||||
|     border-top: 1px solid silver; | ||||
| } | ||||
|  | ||||
| .related-objects .abbreviated-related-objects p.no-related-objects, | ||||
| .related-objects .all-related-objects p.no-objects-available { | ||||
|     font-style: italic; | ||||
|     opacity: 0.5; | ||||
| } | ||||
|  | ||||
| .related-objects .abbreviated-related-objects p.no-related-objects { | ||||
|     display: table-cell; | ||||
|     vertical-align: middle; | ||||
| } | ||||
| @@ -0,0 +1,46 @@ | ||||
| <div class="related-objects"> | ||||
|     <div class="header"> | ||||
|         <h2>{{ header | translate }}</h2> | ||||
|         <div class="filter"> | ||||
|             <input class="search-string" type="text" | ||||
|                    placeholder="{{ 'SETTINGS_USERS.FIELD_PLACEHOLDER_FILTER' | translate }}" | ||||
|                    ng-model="filterString"/> | ||||
|         </div> | ||||
|     </div> | ||||
|  | ||||
|     <div class="section"> | ||||
|  | ||||
|         <!-- Abbreviated list of only the currently selected objects --> | ||||
|         <div class="abbreviated-related-objects"> | ||||
|             <img src="images/arrows/right.png" alt="Expand" class="expand" ng-hide="expanded" ng-click="expand()"/> | ||||
|             <img src="images/arrows/down.png" alt="Collapse" class="collapse" ng-show="expanded" ng-click="collapse()"/> | ||||
|             <p ng-hide="identifiers.length" class="no-related-objects">{{ emptyPlaceholder | translate }}</p> | ||||
|             <ul> | ||||
|                 <li ng-repeat="identifier in identifiers | filter: filterString"> | ||||
|                     <label><img src="images/x-red.png" alt="Remove" class="remove" | ||||
|                                 ng-click="removeIdentifier(identifier)"/><span class="identifier">{{ identifier }}</span> | ||||
|                     </label> | ||||
|                 </li> | ||||
|             </ul> | ||||
|         </div> | ||||
|  | ||||
|         <!-- Exhaustive, paginated list of all objects --> | ||||
|         <div class="all-related-objects" ng-show="expanded"> | ||||
|             <p ng-hide="identifiersAvailablePage.length" class="no-objects-available">{{ unavailablePlaceholder | translate }}</p> | ||||
|             <ul> | ||||
|                 <li ng-repeat="identifier in identifiersAvailablePage"> | ||||
|                     <label><input type="checkbox" | ||||
|                            ng-model="identifierFlags[identifier]" | ||||
|                            ng-change="identifierChanged(identifier)"/> | ||||
|                         <span class="identifier">{{ identifier }}</span> | ||||
|                     </label> | ||||
|                 </li> | ||||
|             </ul> | ||||
|  | ||||
|             <!-- Pager controls for user list --> | ||||
|             <guac-pager page="identifiersAvailablePage" page-size="25" | ||||
|                         items="identifiersAvailable | orderBy | filter: filterString"></guac-pager> | ||||
|         </div> | ||||
|  | ||||
|     </div> | ||||
| </div> | ||||
							
								
								
									
										
											BIN
										
									
								
								guacamole/src/main/webapp/images/arrows/right.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								guacamole/src/main/webapp/images/arrows/right.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 264 B | 
							
								
								
									
										
											BIN
										
									
								
								guacamole/src/main/webapp/images/x-red.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								guacamole/src/main/webapp/images/x-red.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 583 B | 
		Reference in New Issue
	
	Block a user