diff --git a/Gruntfile.js b/Gruntfile.js index e2a380e4b..3779ed6a1 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -384,6 +384,11 @@ module.exports = function (grunt) { src: ['form/**/*.html'], dest: 'templates/form.js' }, + 'patternfly.bulkselection': { + cwd: 'src/', + src: ['bulkselection/**/*.html'], + dest: 'templates/bulkselection.js' + }, 'patternfly.navigation': { cwd: 'src/', src: ['navigation/**/*.html'], diff --git a/src/bulkselection/bulkselection.component.js b/src/bulkselection/bulkselection.component.js new file mode 100644 index 000000000..7187a9930 --- /dev/null +++ b/src/bulkselection/bulkselection.component.js @@ -0,0 +1,59 @@ +angular.module('patternfly.bulkselection').component('pfBulkSelection', { + + bindings: { + totalRecords: '=', + selectedRecordCount: '=', + updateSelectionFn: '<' + }, + templateUrl: 'bulkselection/bulkselection.html', + controller: function () { + 'use strict'; + + var ctrl = this; + var BULKSELECTION_NONE = 'none'; + var BULKSELECTION_ALL = 'all'; + var BULKSELECTION_PARTIAL = 'partial'; + ctrl.menuIsOpen = false; + + ctrl.$onInit = function () { + ctrl.setBulkSelectionState(BULKSELECTION_NONE); + }; + ctrl.updateBulkSelection = function (bulkSelectAction) { + ctrl.menuIsOpen = false; + ctrl.setBulkSelectionState (bulkSelectAction); + ctrl.updateSelectionFn(ctrl.bulkSelection); + }; + ctrl.toggleBulkSelection = function () { + if (ctrl.selectedRecordCount > 0 || ctrl.bulkSelection === BULKSELECTION_ALL) { + ctrl.updateBulkSelection(BULKSELECTION_NONE); + } else { + ctrl.updateBulkSelection(BULKSELECTION_ALL); + } + }; + ctrl.setBulkSelectionState = function(state) { + ctrl.bulkSelection = state; + switch (state) { + case BULKSELECTION_NONE: + ctrl.menuClass = 'fa-square-o'; + break; + case BULKSELECTION_ALL: + ctrl.menuClass = 'fa-check-square all-selected'; + break; + case BULKSELECTION_PARTIAL: + ctrl.menuClass = 'fa-minus-square-o partially-selected'; + break; + } + }; + ctrl.$doCheck = function () { + var recordsSelectedCount = ctrl.totalRecords - ctrl.selectedRecordCount; + if (ctrl.selectedRecordCount === 0) { + ctrl.setBulkSelectionState(BULKSELECTION_NONE); + } + if (recordsSelectedCount > 0 && ctrl.selectedRecordCount > 0 ) { + ctrl.setBulkSelectionState(BULKSELECTION_PARTIAL); + } else if (recordsSelectedCount === 0) { + ctrl.setBulkSelectionState(BULKSELECTION_ALL); + } + }; + } +}); diff --git a/src/bulkselection/bulkselection.html b/src/bulkselection/bulkselection.html new file mode 100644 index 000000000..0c06d369d --- /dev/null +++ b/src/bulkselection/bulkselection.html @@ -0,0 +1,15 @@ +
+ + +
diff --git a/src/bulkselection/bulkselection.less b/src/bulkselection/bulkselection.less new file mode 100644 index 000000000..a004773fd --- /dev/null +++ b/src/bulkselection/bulkselection.less @@ -0,0 +1,12 @@ +.bulk-selection { + .dropdown-menu { + a{ + &:hover { + cursor: pointer; + } + } + } + .all-selected,.partially-selected { + color: @color-pf-blue-400; + } +} diff --git a/src/bulkselection/bulkselection.module.js b/src/bulkselection/bulkselection.module.js new file mode 100644 index 000000000..1abda243d --- /dev/null +++ b/src/bulkselection/bulkselection.module.js @@ -0,0 +1,8 @@ +/** + * @name patternfly bulk selection + * + * @description + * Allows for handling bulk selection of lists + * + */ +angular.module('patternfly.bulkselection', []); diff --git a/src/patternfly.module.js b/src/patternfly.module.js index ebc20f54a..7d02d3415 100644 --- a/src/patternfly.module.js +++ b/src/patternfly.module.js @@ -6,6 +6,7 @@ */ angular.module('patternfly', [ 'patternfly.autofocus', + 'patternfly.bulkselection', 'patternfly.card', 'patternfly.datepicker', 'patternfly.filters', diff --git a/src/toolbars/examples/toolbar.js b/src/toolbars/examples/toolbar.js index 0260a3dcd..267d58121 100644 --- a/src/toolbars/examples/toolbar.js +++ b/src/toolbars/examples/toolbar.js @@ -13,6 +13,10 @@ * See pfSimpleFilter for filter config options. *
  • .sortConfig - (Object) Optional sort config. If undefined, no sort capabilities are shown. * See pfSort for sort config options. + *
  • .bulkSelectionConfig - (Object) Optional bulk selection config. If undefined, no bulk selection capabilities are shown. + * *
  • .viewsConfig - (Object) Optional configuration settings for view type selection * - @@ -422,11 +422,6 @@ name: 'Action 1', title: 'Do the first thing', actionFn: performAction - }, - { - name: 'Action 2', - title: 'Do something else', - actionFn: performAction } ], moreActions: [ @@ -467,12 +462,30 @@ ], actionsInclude: true }; - + $scope.bulkSelectionChanges = function(action) { + var selectAll = false; + switch(action) { + case 'all': + selectAll = true; + break; + case 'none': + selectAll = false; + break; + } + $scope.items.map((item) => { + item.selected = selectAll; + }); + $scope.updateItemsAvailable(); + } + $scope.selectionConfig = { + bulkSelectionFn: $scope.bulkSelectionChanges + } $scope.toolbarConfig = { viewsConfig: $scope.viewsConfig, filterConfig: $scope.filterConfig, sortConfig: $scope.sortConfig, - actionsConfig: $scope.actionsConfig + actionsConfig: $scope.actionsConfig, + bulkSelectionConfig: $scope.selectionConfig }; $scope.listConfig = { diff --git a/src/toolbars/toolbar.html b/src/toolbars/toolbar.html index e9c5f1f6a..9b2544501 100644 --- a/src/toolbars/toolbar.html +++ b/src/toolbars/toolbar.html @@ -2,6 +2,13 @@
    +
    + +
    diff --git a/src/toolbars/toolbars.module.js b/src/toolbars/toolbars.module.js index 6ee7aeb3d..c2182adc9 100644 --- a/src/toolbars/toolbars.module.js +++ b/src/toolbars/toolbars.module.js @@ -9,4 +9,5 @@ angular.module('patternfly.toolbars', [ 'patternfly.utils', 'patternfly.filters', 'patternfly.sort', + 'patternfly.bulkselection', 'patternfly.views']); diff --git a/styles/angular-patternfly.less b/styles/angular-patternfly.less index 3169d4e9c..701eb6dbf 100644 --- a/styles/angular-patternfly.less +++ b/styles/angular-patternfly.less @@ -1,6 +1,7 @@ @import "../node_modules/patternfly/dist/less/color-variables.less"; @import "../node_modules/bootstrap/less/variables.less"; @import "misc.less"; +@import "../src/bulkselection/bulkselection.less"; @import "../src/card/card.less"; @import "../src/charts/charts.less"; @import "../src/views/views.less"; diff --git a/test/toolbars/toolbar.spec.js b/test/toolbars/toolbar.spec.js index 63da7ec40..38c0f45e5 100644 --- a/test/toolbars/toolbar.spec.js +++ b/test/toolbars/toolbar.spec.js @@ -4,12 +4,13 @@ describe('Directive: pfToolbar', function () { var element; var $pfViewUtils; var performedAction; + var bulkSelectionState; // load the controller's module beforeEach(function () { - module('patternfly.toolbars', 'patternfly.views', 'patternfly.filters', 'toolbars/toolbar.html', + module('patternfly.toolbars', 'patternfly.views', 'patternfly.bulkselection', 'patternfly.filters', 'toolbars/toolbar.html', 'filters/simple-filter/filter.html', 'filters/simple-filter/filter-fields.html', 'filters/simple-filter/filter-results.html', - 'sort/sort.html'); + 'sort/sort.html', 'bulkselection/bulkselection.html'); }); beforeEach(inject(function (_$compile_, _$rootScope_, pfViewUtils) { @@ -31,7 +32,10 @@ describe('Directive: pfToolbar', function () { var performAction = function (action) { performedAction = action; }; - + bulkSelectionState = undefined; + var bulkSelectionCb = function(action) { + bulkSelectionState = action; + }; $scope.config = { viewsConfig: { views: [$pfViewUtils.getDashboardView(), $pfViewUtils.getListView(), $pfViewUtils.getCardView(), $pfViewUtils.getTableView(), $pfViewUtils.getTopologyView()] @@ -129,6 +133,9 @@ describe('Directive: pfToolbar', function () { actionFn: performAction } ] + }, + bulkSelectionConfig:{ + bulkSelectionFn: bulkSelectionCb } }; @@ -300,7 +307,43 @@ describe('Directive: pfToolbar', function () { active = element.find('.active'); expect(active.length).toBe(1); }); + it ('should have bulk selection menu shown', function() { + var bulkSelectionSelector = element.find('.bulk-selection'); + expect(bulkSelectionSelector.length).toBe(1); + }); + it('should allow bulk selection to select all', function() { + var bulkSelectionSelector = element.find('.bulk-selection-menuicon'); + bulkSelectionState = 'none'; + eventFire(bulkSelectionSelector[0], 'click'); + $scope.$apply(); + expect(bulkSelectionState).toBe('all'); + }); + it('should allow bulk selection to be toggled', function() { + var bulkSelectionSelector = element.find('.bulk-selection-menuicon'); + eventFire(bulkSelectionSelector[0], 'click'); + $scope.$apply(); + eventFire(bulkSelectionSelector[0], 'click'); + $scope.$apply(); + expect(bulkSelectionState).toBe('none'); + }); + it ('should not show bulk selection when config is not supplied', function () { + $scope.config = { + }; + + var htmlTmp = ''; + + compileHTML(htmlTmp, $scope); + + bulkSelectionComponent = element.find('.bulk-selection'); + expect(bulkSelectionComponent.length).toBe(0); + }); + it('should allow bulkselection dropdown to unselect all results', function() { + var bulkSelectionButtons = element.find('.bulk-selection .dropdown-menu a'); + eventFire(bulkSelectionButtons[1], 'click'); + $scope.$apply(); + expect(bulkSelectionState).toBe('none'); + }); it ('should call the callback function when a view selector clicked', function () { var listSelector = element.find('.toolbar-pf-view-selector .btn-link'); var functionCalled = false;