You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by vn...@apache.org on 2018/08/14 23:37:35 UTC
[03/12] guacamole-client git commit: GUACAMOLE-220: Implement generic
editor directive for manipulating sets of identifiers.
GUACAMOLE-220: Implement generic editor directive for manipulating sets of identifiers.
Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/229b0dee
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/229b0dee
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/229b0dee
Branch: refs/heads/staging/1.0.0
Commit: 229b0dee4882352e7583c4f5872bee92158da712
Parents: 1cf16d1
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Jul 25 02:34:27 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Aug 8 09:00:06 2018 -0700
----------------------------------------------------------------------
.../manage/directives/identifierSetEditor.js | 267 +++++++++++++++++++
.../app/manage/styles/related-objects.css | 82 ++++++
.../manage/templates/identifierSetEditor.html | 46 ++++
.../src/main/webapp/images/arrows/right.png | Bin 0 -> 264 bytes
guacamole/src/main/webapp/images/x-red.png | Bin 0 -> 583 bytes
5 files changed, 395 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/229b0dee/guacamole/src/main/webapp/app/manage/directives/identifierSetEditor.js
----------------------------------------------------------------------
diff --git a/guacamole/src/main/webapp/app/manage/directives/identifierSetEditor.js b/guacamole/src/main/webapp/app/manage/directives/identifierSetEditor.js
new file mode 100644
index 0000000..82f1109
--- /dev/null
+++ b/guacamole/src/main/webapp/app/manage/directives/identifierSetEditor.js
@@ -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;
+
+}]);
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/229b0dee/guacamole/src/main/webapp/app/manage/styles/related-objects.css
----------------------------------------------------------------------
diff --git a/guacamole/src/main/webapp/app/manage/styles/related-objects.css b/guacamole/src/main/webapp/app/manage/styles/related-objects.css
new file mode 100644
index 0000000..ddc85b1
--- /dev/null
+++ b/guacamole/src/main/webapp/app/manage/styles/related-objects.css
@@ -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;
+}
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/229b0dee/guacamole/src/main/webapp/app/manage/templates/identifierSetEditor.html
----------------------------------------------------------------------
diff --git a/guacamole/src/main/webapp/app/manage/templates/identifierSetEditor.html b/guacamole/src/main/webapp/app/manage/templates/identifierSetEditor.html
new file mode 100644
index 0000000..838decf
--- /dev/null
+++ b/guacamole/src/main/webapp/app/manage/templates/identifierSetEditor.html
@@ -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>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/229b0dee/guacamole/src/main/webapp/images/arrows/right.png
----------------------------------------------------------------------
diff --git a/guacamole/src/main/webapp/images/arrows/right.png b/guacamole/src/main/webapp/images/arrows/right.png
new file mode 100644
index 0000000..1b3483e
Binary files /dev/null and b/guacamole/src/main/webapp/images/arrows/right.png differ
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/229b0dee/guacamole/src/main/webapp/images/x-red.png
----------------------------------------------------------------------
diff --git a/guacamole/src/main/webapp/images/x-red.png b/guacamole/src/main/webapp/images/x-red.png
new file mode 100644
index 0000000..e5497f3
Binary files /dev/null and b/guacamole/src/main/webapp/images/x-red.png differ