Github user mike-jumper commented on a diff in the pull request:
https://github.com/apache/guacamole-client/pull/309#discussion_r208805738
--- Diff:
guacamole/src/main/webapp/app/manage/directives/identifierSetEditor.js ---
@@ -0,0 +1,299 @@
+/*
+ * 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 = {};
+
+ /**
+ * Map of identifiers to boolean flags indicating whether that
+ * identifier is editable. If an identifier is not editable, it
will be
+ * absent from this map.
+ *
+ * @type Object.<String, Boolean>
+ */
+ $scope.isEditable = {};
+
+ /**
+ * 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;
+ });
+
+ });
+
+ // Keep identifierFlags up to date when identifiers array is
replaced
--- End diff --
OK, I've rebased away the pasta.
---