diff --git a/awx/ui/static/js/docs.js b/awx/ui/static/js/docs.js
index 9398fde08c..8f51c66bf2 100644
--- a/awx/ui/static/js/docs.js
+++ b/awx/ui/static/js/docs.js
@@ -1 +1 @@
-import 'tower/debug';
+import 'tower/shared/multi-select-list/main.js';
diff --git a/awx/ui/static/js/forms/CustomInventory.js b/awx/ui/static/js/forms/CustomInventory.js
index 45f2279781..df9aaf9f23 100644
--- a/awx/ui/static/js/forms/CustomInventory.js
+++ b/awx/ui/static/js/forms/CustomInventory.js
@@ -8,7 +8,7 @@
*/
/**
* @ngdoc function
- * @name forms.function:Organizations
+ * @name forms.function:CustomInventory
* @description This form is for adding/editing an organization
*/
diff --git a/awx/ui/static/js/helpers/ConfigureTower.js b/awx/ui/static/js/helpers/ConfigureTower.js
index 3bda266ca9..15142da257 100644
--- a/awx/ui/static/js/helpers/ConfigureTower.js
+++ b/awx/ui/static/js/helpers/ConfigureTower.js
@@ -3,7 +3,7 @@
*/
/**
* @ngdoc function
- * @name helpers.function:Schedules
+ * @name helpers.function:ConfigureTower
* @description
* Schedules Helper
*
diff --git a/awx/ui/static/js/helpers/CustomInventory.js b/awx/ui/static/js/helpers/CustomInventory.js
index 6ca3ba4834..b5a7167efb 100644
--- a/awx/ui/static/js/helpers/CustomInventory.js
+++ b/awx/ui/static/js/helpers/CustomInventory.js
@@ -3,7 +3,7 @@
*/
/**
* @ngdoc function
- * @name helpers.function:Schedules
+ * @name helpers.function:CustomInventory
* @description
* Schedules Helper
*
diff --git a/awx/ui/static/js/helpers/Survey.js b/awx/ui/static/js/helpers/Survey.js
index 06984e0402..b41b345eba 100644
--- a/awx/ui/static/js/helpers/Survey.js
+++ b/awx/ui/static/js/helpers/Survey.js
@@ -3,7 +3,7 @@
*/
/**
* @ngdoc function
- * @name helpers.function:Schedules
+ * @name helpers.function:Survey
* @description
* Schedules Helper
*
diff --git a/awx/ui/static/js/shared/multi-select-list/multi-select-list.controller.js b/awx/ui/static/js/shared/multi-select-list/multi-select-list.controller.js
index f7a8c52849..d55bd2e2e9 100644
--- a/awx/ui/static/js/shared/multi-select-list/multi-select-list.controller.js
+++ b/awx/ui/static/js/shared/multi-select-list/multi-select-list.controller.js
@@ -1,3 +1,12 @@
+/**
+ * @ngdoc object
+ * @name multiSelectList.controller:multiSelectList
+ *
+ * @description
+ *
+ * `multiSelectList` controller provides the API for the {@link multiSelectList.directive:multiSelectList `multiSelectList`} directive. The controller contains methods for selecting/deselecting items, controlling the extended selection, registering items to be selectable and emitting an event on the directive's `$scope`.
+ *
+ */
export default ['$scope',
function ($scope) {
$scope.items = [];
@@ -7,10 +16,11 @@ export default ['$scope',
deselectedItems: []
};
+ // Makes $scope.selection.length an alias for $scope.selectedItems.length
Object.defineProperty($scope.selection,
'length',
{ get: function() {
- return this.items.length;
+ return this.selectedItems.length;
}
});
@@ -26,15 +36,41 @@ export default ['$scope',
_items.pluck('value').difference($scope.selection.selectedItems)
.value();
+ /**
+ *
+ * @ngdoc event
+ * @name multiSelectList.selectionChanged
+ * @eventOf multiSelectList.directive:multiSelectList
+ *
+ */
$scope.$emit('multiSelectList.selectionChanged', $scope.selection);
}
+ /**
+ * @ngdoc
+ * @name multiSelectList.controller:multiSelectList#registerItem
+ * @methodOf multiSelectList.controller:multiSelectList
+ *
+ * @description
+ * Prepares an object to be tracked in the select list. Returns the
+ * decorated item created by
+ * {@link multiSelectList.controller:multiSelectList#decorateItem `decorateItem`}
+ */
this.registerItem = function(item) {
var decoratedItem = this.decorateItem(item);
$scope.items = $scope.items.concat(decoratedItem);
return decoratedItem;
};
+ /**
+ * @ngdoc
+ * @name multiSelectList.controller:multiSelectList#deregisterItem
+ * @methodOf multiSelectList.controller:multiSelectList
+ *
+ * @description
+ * Removes an item from the list; called if the item is removed from the display
+ * so that it is no longer tracked as a selectable item.
+ */
this.deregisterItem = function(leavingItem) {
$scope.items = $scope.items.filter(function(item) {
return leavingItem !== item;
@@ -42,6 +78,18 @@ export default ['$scope',
rebuildSelections();
};
+ /**
+ * @ngdoc
+ * @name multiSelectList.controller:multiSelectList#decorateItem
+ * @methodOf multiSelectList.controller:multiSelectList
+ *
+ * @description
+ *
+ * This decorates an item with an object that has an `isSelected` property.
+ * This value is used to determine the lists of selected and non-selected
+ * items to emit with the `multiSelectList.selectionChanged`
+ * event.
+ */
this.decorateItem = function(item) {
return {
isSelected: false,
@@ -49,12 +97,31 @@ export default ['$scope',
};
};
+ /**
+ * @ngdoc
+ * @name multiSelectList.controller:multiSelectList#selectAll
+ * @methodOf multiSelectList.controller:multiSelectList
+ *
+ * @description
+ * Marks all items in the list as selected.
+ * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
+ */
this.selectAll = function() {
$scope.items.forEach(function(item) {
item.isSelected = true;
});
+ rebuildSelections();
};
+ /**
+ * @ngdoc
+ * @name multiSelectList.controller:multiSelectList#deselectAll
+ * @methodOf multiSelectList.controller:multiSelectList
+ *
+ * @description
+ * Marks all items in the list as not selected.
+ * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
+ */
this.deselectAll = function() {
$scope.items.forEach(function(item) {
item.isSelected = false;
@@ -64,19 +131,59 @@ export default ['$scope',
};
+ /**
+ * @ngdoc
+ * @name multiSelectList.controller:multiSelectList#deselectAllExtended
+ * @methodOf multiSelectList.controller:multiSelectList
+ *
+ * @description
+ * Disables extended selection.
+ * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
+ */
this.deselectAllExtended = function(extendedLength) {
$scope.selection.isExtended = false;
+ rebuildSelections();
};
+ /**
+ * @ngdoc
+ * @name multiSelectList.controller:multiSelectList#selectAllExtended
+ * @methodOf multiSelectList.controller:multiSelectList
+ *
+ * @description
+ * Enables extended selection.
+ * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
+ */
this.selectAllExtended = function(extendedLength) {
$scope.selection.isExtended = true;
+ rebuildSelections();
};
+ /**
+ * @ngdoc
+ * @name multiSelectList.controller:multiSelectList#selectItem
+ * @methodOf multiSelectList.controller:multiSelectList
+ *
+ * @description
+ * Marks an item as selected.
+ * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
+ *
+ */
this.selectItem = function(item) {
item.isSelected = true;
rebuildSelections();
};
+ /**
+ * @ngdoc
+ * @name multiSelectList.controller:multiSelectList#deregisterItem
+ * @methodOf multiSelectList.controller:multiSelectList
+ *
+ * @description
+ * Marks an item as not selected.
+ * Triggers {@link multiSelectList.selectionChanged `multiSelectList.selectionChanged`}
+ *
+ */
this.deselectItem = function(item) {
item.isSelected = false;
rebuildSelections();
diff --git a/awx/ui/static/js/shared/multi-select-list/multi-select-list.directive.js b/awx/ui/static/js/shared/multi-select-list/multi-select-list.directive.js
index 0f80b99433..f65d8a2f4d 100644
--- a/awx/ui/static/js/shared/multi-select-list/multi-select-list.directive.js
+++ b/awx/ui/static/js/shared/multi-select-list/multi-select-list.directive.js
@@ -1,8 +1,75 @@
+/**
+ * @ngdoc overview
+ * @name multiSelectList
+ * @scope
+ * @description Does some stuff
+ *
+ * @ngdoc directive
+ * @name multiSelectList.directive:multiSelectList
+ * @description
+ * The `multiSelectList` directive works in conjunction with the
+ * `selectListItem` and (optionally) the `selectAll` directives to
+ * render checkboxes with list items and tracking the selected state
+ * of each item. The `selectListItem` directive renders a checkbox,
+ * and the `multiSelectList` directive tracks the selected state
+ * of list items. The `selectAll` directive renders a checkbox that
+ * will select/deselect all items in the list.
+ *
+ *
+ * This directive exposes a special object on its local scope called
+ * `selection` that is used to access the current selection state.
+ * The following properties on `selection` are available:
+ *
+ * | Property | Type | Details |
+ * |-------------------|-----------------|-------------------------------------------------------------|
+ * | `selectedItems` | {@type array} | The items that are currently selected |
+ * | `deselectedItem` | {@type array} | The items that are currently _not_ selected |
+ * | `isExtended` | {@type boolean} | Indicates that the user has requested an extended selection |
+ * | `length` | {@type number} | The length of the selected items array |
+ *
+ * Use the `multi-select-list` directive to indicate that you want
+ * to allow users to select items in a list. To display a checkbox
+ * next to each item, use the {@link multiSelectList.directive:selectListItem `select-list-item`} directive.
+ *
+ * # Rendering a basic multi-select list
+ *
+ * @example
+ *
+ * This example creates a list of names and then
+ * uses `multiSelectList` to make the names
+ * selectable:
+ *
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+ *
+*/
import controller from './multi-select-list.controller';
export default
- [ function() {
- return {
+[ function() {
+ return {
restrict: 'A',
scope: {
},
diff --git a/awx/ui/static/js/shared/multi-select-list/select-all.directive.js b/awx/ui/static/js/shared/multi-select-list/select-all.directive.js
index 2c7fa8fc1b..bbeee0e5bd 100644
--- a/awx/ui/static/js/shared/multi-select-list/select-all.directive.js
+++ b/awx/ui/static/js/shared/multi-select-list/select-all.directive.js
@@ -1,3 +1,122 @@
+/**
+ * @ngdoc directive
+ * @name multiSelectList.directive:selectAll
+ * @scope
+ * @restrict E
+ *
+ * @param {string} label The text that will appear next to the checkbox
+ * @param {number} itemsLength The number of displayed items in the list
+ * @param {number} extendedItemsLength The total number of items in the list used for extended mode (see below)
+ * @param {string_expression} extendedLabel A custom label to display when prompting the user to extend the selection; this is an expression so strings must be in single quotes ('), but you can use scope varibles here to display the count of items with the `extendedItemsLength` property
+ * @param {boolean_expression} selectionsEmpty An expression that evaluates to a truthy value used to disable
+ * the select all checkbox when the displayed list is empty
+ *
+ * @description
+ *
+ * Use the `select-all` directive as a child of a `multi-select-list`
+ * to present the user with a checkbox that, when checked, checks all
+ * `select-list-item` children, and when unchecked it unchecks them.
+ *
+ *
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+ *
+ *
+ * ## Extended Selections
+ *
+ * In some cases the list items you are displaying are only a subset of
+ * a larger list (eg. using pagination or infinite scroll to seperate
+ * items). In these cases, when a user checks "select all", it may be
+ * useful to give them the option to also select all the remaining
+ * items in the list.
+ *
+ * This behavior is controlled by the `extendedItemsLength` property
+ * of this directive. Set it to the total length of items in the list.
+ * For example, if you have a list of 100 items, displayed 10 per page,
+ * then `itemsLength` would be 10 and `extendedItemsLength` would be 100.
+ * When the user checks "select all" in the above example, it will show
+ * a button prompting them to "Select all 100 items". When the user selects
+ * this option, the `select-all` directive tells the `multiSelectList`
+ * controller that the selection is "extended" to all the items in the list.
+ * Listeners to the `multiSelectList.selectionChanged` event can then use this
+ * flag to respond differently when all items are selected.
+ *
+ *
+ *
+
+ angular.module('extendedSelectionExample', ['multiSelectList'])
+ .controller('namesController', ['$scope', function($scope) {
+
+ var cleanup = $scope.$on('multiSelectList.selectionChanged', function(e, selection) {
+ $scope.isSelectionExtended = selection.isExtended;
+ });
+
+ $scope.$on('$destroy', cleanup);
+
+ $scope.allNames =
+ [ { name: 'John'
+ },
+ { name: 'Jared'
+ },
+ { name: 'Joe'
+ },
+ { name: 'James'
+ },
+ { name: 'Matt'
+ },
+ { name: 'Luke'
+ },
+ { name: 'Chris'
+ }
+ ];
+
+ $scope.firstPageOfNames =
+ $scope.allNames.slice(0,3);
+ }]);
+
+
+
+
Extended Selection
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+ *
+ */
// TODO: Extract to its own helper
// Example:
// template('shared/multi-select-list/select-all')
@@ -17,14 +136,14 @@ export default
label: '@',
itemsLength: '=',
extendedItemsLength: '=',
- isSelectionExtended: '=',
+ extendedLabel: '&',
isSelectionEmpty: '=selectionsEmpty'
},
templateUrl: template('shared/multi-select-list/select-all'),
link: function(scope, element, attrs, controller) {
scope.label = scope.label || 'All';
- scope.selectExtendedLabel = scope.extendedLabel || 'Select all ' + scope.extendedItemsLength + ' items';
+ scope.selectExtendedLabel = scope.extendedLabel() || 'Select all ' + scope.extendedItemsLength + ' items';
scope.deselectExtendedLabel = scope.deselectExtendedLabel || 'Deselect extra items';
scope.doSelectAll = function(e) {
@@ -36,6 +155,12 @@ export default
}
} else {
controller.deselectAll();
+
+ if (scope.isSelectionExtended) {
+ scope.deselectAllExtended();
+ }
+
+ scope.showExtendedMessage = false;
}
};
@@ -51,10 +176,12 @@ export default
scope.selectAllExtended = function() {
controller.selectAllExtended(scope.extendedItemsLength);
+ scope.isSelectionExtended = true;
};
scope.deselectAllExtended = function() {
controller.deselectAllExtended(scope.extendedItemsLength);
+ scope.isSelectionExtended = false;
};
}
diff --git a/awx/ui/static/js/shared/multi-select-list/select-all.partial.html b/awx/ui/static/js/shared/multi-select-list/select-all.partial.html
index 9b5e62a3f9..8cf597c10c 100644
--- a/awx/ui/static/js/shared/multi-select-list/select-all.partial.html
+++ b/awx/ui/static/js/shared/multi-select-list/select-all.partial.html
@@ -13,6 +13,6 @@
diff --git a/awx/ui/static/js/shared/multi-select-list/select-list-item.directive.js b/awx/ui/static/js/shared/multi-select-list/select-list-item.directive.js
index ecba972cc9..726fb044a0 100644
--- a/awx/ui/static/js/shared/multi-select-list/select-list-item.directive.js
+++ b/awx/ui/static/js/shared/multi-select-list/select-list-item.directive.js
@@ -1,3 +1,21 @@
+/**
+ * @ngdoc directive
+ * @name multiSelectList.directive:selectListItem
+ * @restrict E
+ * @scope
+ * @description
+ *
+ The `select-list-item` directive renders a checkbox for tracking
+ the state of a given item in a list. When the user checks the
+ checkbox it tells the `multi-select-list` controller to select
+ the item; when the user unchecks the checkbox it tells the controller
+ to deselect the item.
+
+ @example
+
+ For examples of using this directive, see {@link multiSelectList.directive:multiSelectList multiSelectList}.
+
+ */
export default
[ function() {
return {
diff --git a/awx/ui/static/js/widgets/PortalJobs.js b/awx/ui/static/js/widgets/PortalJobs.js
index ffd8005aba..b51a388a7d 100644
--- a/awx/ui/static/js/widgets/PortalJobs.js
+++ b/awx/ui/static/js/widgets/PortalJobs.js
@@ -3,7 +3,7 @@
*/
/**
* @ngdoc function
- * @name widgets.function:DashboardJobs
+ * @name widgets.function:PortalJobs
* @description
*
*/