diff --git a/src/progressbar/docs/readme.md b/src/progressbar/docs/readme.md index 46071279bd..31a420fea1 100644 --- a/src/progressbar/docs/readme.md +++ b/src/progressbar/docs/readme.md @@ -22,8 +22,11 @@ It supports multiple (stacked) bars into the same `` element or a _(Default: true)_ : Whether bars use transitions to achieve the width change. + * `title` + _(Default: progressbar)_ : + Title to use as label (for accessibility) ### Stacked ### Place multiple ``s into the same `` element to stack them. -`` supports `max` and `animate` & `` supports `value` and `type` attributes. +`` supports `max`, `animate`, and `title` & `` supports `value`, `title`, and `type` attributes. diff --git a/src/progressbar/progressbar.js b/src/progressbar/progressbar.js index 435c72ccaa..6affa08fca 100644 --- a/src/progressbar/progressbar.js +++ b/src/progressbar/progressbar.js @@ -14,7 +14,7 @@ angular.module('ui.bootstrap.progressbar', []) this.bars = []; $scope.max = angular.isDefined($scope.max) ? $scope.max : progressConfig.max; - this.addBar = function(bar, element) { + this.addBar = function(bar, element, attrs) { if (!animate) { element.css({'transition': 'none'}); } @@ -22,6 +22,7 @@ angular.module('ui.bootstrap.progressbar', []) this.bars.push(bar); bar.max = $scope.max; + bar.title = attrs && angular.isDefined(attrs.title) ? attrs.title : 'progressbar'; bar.$watch('value', function(value) { bar.recalculatePercentage(); @@ -79,7 +80,8 @@ angular.module('ui.bootstrap.progressbar', []) controller: 'ProgressController', require: 'progress', scope: { - max: '=?' + max: '=?', + title: '@?' }, templateUrl: 'template/progressbar/progress.html', link: function() { @@ -102,7 +104,7 @@ angular.module('ui.bootstrap.progressbar', []) }, templateUrl: 'template/progressbar/bar.html', link: function(scope, element, attrs, progressCtrl) { - progressCtrl.addBar(scope, element); + progressCtrl.addBar(scope, element, attrs); } }; }) @@ -140,7 +142,7 @@ angular.module('ui.bootstrap.progressbar', []) }, templateUrl: 'template/progressbar/progressbar.html', link: function(scope, element, attrs, progressCtrl) { - progressCtrl.addBar(scope, angular.element(element.children()[0])); + progressCtrl.addBar(scope, angular.element(element.children()[0]), {title: attrs.title}); } }; }); diff --git a/src/progressbar/test/progressbar.spec.js b/src/progressbar/test/progressbar.spec.js index eabf57b5cf..7ea59ac8b0 100644 --- a/src/progressbar/test/progressbar.spec.js +++ b/src/progressbar/test/progressbar.spec.js @@ -51,7 +51,7 @@ describe('progressbar directive', function() { $compile = _$compile_; $rootScope = _$rootScope_; $rootScope.value = 22; - element = $compile('{{value}} %')($rootScope); + element = $compile('{{value}} %')($rootScope); $rootScope.$digest(); })); @@ -81,6 +81,14 @@ describe('progressbar directive', function() { expect(bar.attr('aria-valuemax')).toBe('100'); expect(bar.attr('aria-valuenow')).toBe('22'); expect(bar.attr('aria-valuetext')).toBe('22%'); + expect(bar.attr('aria-labelledby')).toBe('foo'); + }); + + it('has the default aria-labelledby value of `progressbar`', function() { + element = $compile('{{value}} %')($rootScope); + $rootScope.$digest(); + var bar = getBar(0); + expect(bar.attr('aria-labelledby')).toBe('progressbar'); }); it('transcludes "bar" text', function() { @@ -197,11 +205,11 @@ describe('progressbar directive', function() { describe('stacked', function() { beforeEach(inject(function() { $rootScope.objects = [ - { value: 10, type: 'success' }, - { value: 50, type: 'warning' }, - { value: 20 } + { value: 10, title: 'foo', type: 'success' }, + { value: 50, title: 'bar', type: 'warning' }, + { value: 20, title: 'baz' } ]; - element = $compile('{{o.value}}')($rootScope); + element = $compile('{{o.value}}')($rootScope); $rootScope.$digest(); })); @@ -261,6 +269,40 @@ describe('progressbar directive', function() { expect(getBar(0)).not.toHaveClass(BAR_CLASS + '-warning'); }); + it('should have the correct aria markup', function() { + expect(getBar(0).attr('aria-valuenow')).toBe('10'); + expect(getBar(0).attr('aria-valuemin')).toBe('0'); + expect(getBar(0).attr('aria-valuemax')).toBe('100'); + expect(getBar(0).attr('aria-valuetext')).toBe('10%'); + expect(getBar(0).attr('aria-labelledby')).toBe('foo'); + + expect(getBar(1).attr('aria-valuenow')).toBe('50'); + expect(getBar(1).attr('aria-valuemin')).toBe('0'); + expect(getBar(1).attr('aria-valuemax')).toBe('100'); + expect(getBar(1).attr('aria-valuetext')).toBe('50%'); + expect(getBar(1).attr('aria-labelledby')).toBe('bar'); + + expect(getBar(2).attr('aria-valuenow')).toBe('20'); + expect(getBar(2).attr('aria-valuemin')).toBe('0'); + expect(getBar(2).attr('aria-valuemax')).toBe('100'); + expect(getBar(2).attr('aria-valuetext')).toBe('20%'); + expect(getBar(2).attr('aria-labelledby')).toBe('baz'); + }); + + it('should default to `progressbar`', function() { + $rootScope.objects = [ + { value: 10, title: 'foo', type: 'success' }, + { value: 50, title: 'bar', type: 'warning' }, + { value: 20, title: 'baz' } + ]; + element = $compile('{{o.value}}')($rootScope); + $rootScope.$digest(); + + expect(getBar(0).attr('aria-labelledby')).toBe('progressbar'); + expect(getBar(1).attr('aria-labelledby')).toBe('progressbar'); + expect(getBar(2).attr('aria-labelledby')).toBe('progressbar'); + }); + describe('"max" attribute', function() { beforeEach(inject(function() { $rootScope.max = 200; diff --git a/template/progressbar/bar.html b/template/progressbar/bar.html index a507f8e240..b5b61e03a4 100644 --- a/template/progressbar/bar.html +++ b/template/progressbar/bar.html @@ -1 +1 @@ -
+
diff --git a/template/progressbar/progress.html b/template/progressbar/progress.html index 1968537006..38ee9f79aa 100644 --- a/template/progressbar/progress.html +++ b/template/progressbar/progress.html @@ -1 +1 @@ -
\ No newline at end of file +
\ No newline at end of file diff --git a/template/progressbar/progressbar.html b/template/progressbar/progressbar.html index 18abd71fba..dbfa5aaf13 100644 --- a/template/progressbar/progressbar.html +++ b/template/progressbar/progressbar.html @@ -1,3 +1,3 @@
-
+