Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 8539eac

Browse files
crisbetoThomasBurleson
authored andcommitted
fix(progressCircular): add ARIA in indeterminate mode, IE10 visibility, test cleanup
* Adds a polyfill for performance.now. * Doesn't set the aria-valuenow attribute in indeterminate mode. * Fixes the circle being invisible in IE10. * Cleans up the progressCircular testing setup and adds a test for the stroke width. Closes #7420
1 parent 34f2704 commit 8539eac

File tree

2 files changed

+69
-50
lines changed

2 files changed

+69
-50
lines changed

src/components/progressCircular/js/progressCircularDirective.js

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ function MdProgressCircularDirective($$rAF, $window, $mdProgressCircular, $mdUti
9292
};
9393

9494
function MdProgressCircularLink(scope, element) {
95-
var svg = element[0].querySelector('svg');
96-
var path = angular.element(svg.querySelector('path'));
95+
var svg = angular.element(element[0].querySelector('svg'));
96+
var path = angular.element(element[0].querySelector('path'));
9797
var startIndeterminate = $mdProgressCircular.startIndeterminate;
9898
var endIndeterminate = $mdProgressCircular.endIndeterminate;
9999
var rotationIndeterminate = 0;
@@ -112,8 +112,11 @@ function MdProgressCircularDirective($$rAF, $window, $mdProgressCircular, $mdUti
112112
if (mode === MODE_INDETERMINATE) {
113113
startIndeterminateAnimation();
114114
} else {
115+
var newValue = clamp(newValues[0]);
116+
115117
cleanupIndeterminateAnimation();
116-
renderCircle(clamp(oldValues[0]), clamp(newValues[0]));
118+
element.attr('aria-valuenow', newValue);
119+
renderCircle(clamp(oldValues[0]), newValue);
117120
}
118121
}
119122
});
@@ -123,35 +126,38 @@ function MdProgressCircularDirective($$rAF, $window, $mdProgressCircular, $mdUti
123126
scope.$watch('mdDiameter', function(newValue) {
124127
var diameter = getSize(newValue);
125128
var strokeWidth = getStroke(diameter);
129+
var dimensions = {
130+
width: diameter + 'px',
131+
height: diameter + 'px'
132+
};
126133

127134
// The viewBox has to be applied via setAttribute, because it is
128135
// case-sensitive. If jQuery is included in the page, `.attr` lowercases
129136
// all attribute names.
130-
svg.setAttribute('viewBox', '0 0 ' + diameter + ' ' + diameter);
137+
svg[0].setAttribute('viewBox', '0 0 ' + diameter + ' ' + diameter);
138+
139+
// Usually viewBox sets the dimensions for the SVG, however that doesn't
140+
// seem to be the case on IE10.
141+
svg.css(dimensions);
142+
element.css(dimensions);
131143
path.css('stroke-width', strokeWidth + 'px');
132-
element.css({
133-
width: diameter + 'px',
134-
height: diameter + 'px'
135-
});
136144
});
137145

138146
function renderCircle(animateFrom, animateTo, easing, duration, rotation) {
139147
var id = ++lastAnimationId;
140-
var startTime = $window.performance.now();
148+
var startTime = getTimestamp();
141149
var changeInValue = animateTo - animateFrom;
142150
var diameter = getSize(scope.mdDiameter);
143151
var pathDiameter = diameter - getStroke(diameter);
144152
var ease = easing || $mdProgressCircular.easeFn;
145153
var animationDuration = duration || $mdProgressCircular.duration;
146154

147-
element.attr('aria-valuenow', animateTo);
148-
149155
// No need to animate it if the values are the same
150156
if (animateTo === animateFrom) {
151157
path.attr('d', getSvgArc(animateTo, diameter, pathDiameter, rotation));
152158
} else {
153159
$$rAF(function animation(now) {
154-
var currentTime = now - startTime;
160+
var currentTime = (now || getTimestamp()) - startTime;
155161

156162
path.attr('d', getSvgArc(
157163
ease(currentTime, animateFrom, changeInValue, animationDuration),
@@ -187,7 +193,7 @@ function MdProgressCircularDirective($$rAF, $window, $mdProgressCircular, $mdUti
187193

188194
function startIndeterminateAnimation() {
189195
if (!interval) {
190-
var startTime = $window.performance.now();
196+
var startTime = getTimestamp();
191197
var animationDuration = $mdProgressCircular.rotationDurationIndeterminate;
192198
var radius = getSize(scope.mdDiameter) / 2;
193199

@@ -198,7 +204,8 @@ function MdProgressCircularDirective($$rAF, $window, $mdProgressCircular, $mdUti
198204
// with CSS keyframes, however IE11 seems to have problems centering the rotation
199205
// which causes a wobble in the indeterminate animation.
200206
$$rAF(function animation(now) {
201-
var currentTime = now - startTime;
207+
var timestamp = now || getTimestamp();
208+
var currentTime = timestamp - startTime;
202209
var rotation = $mdProgressCircular.easingPresets.linearEase(currentTime, 0, 360, animationDuration);
203210

204211
path.attr('transform', 'rotate(' + rotation + radius + ')');
@@ -211,11 +218,11 @@ function MdProgressCircularDirective($$rAF, $window, $mdProgressCircular, $mdUti
211218

212219
// Reset the animation
213220
if (currentTime >= animationDuration) {
214-
startTime = now;
221+
startTime = timestamp;
215222
}
216223
});
217224

218-
// This shouldn't trigger a digest which is why we don't use $interval.
225+
// Note that this interval isn't supposed to trigger a digest.
219226
interval = $interval(
220227
animateIndeterminate,
221228
$mdProgressCircular.durationIndeterminate + 50,
@@ -224,6 +231,7 @@ function MdProgressCircularDirective($$rAF, $window, $mdProgressCircular, $mdUti
224231
);
225232

226233
animateIndeterminate();
234+
element.removeAttr('aria-valuenow');
227235
}
228236
}
229237

@@ -321,4 +329,12 @@ function MdProgressCircularDirective($$rAF, $window, $mdProgressCircular, $mdUti
321329
function getStroke(diameter) {
322330
return $mdProgressCircular.strokeWidth / 100 * diameter;
323331
}
332+
333+
/**
334+
* Retrieves a timestamp for timing animations.
335+
*/
336+
function getTimestamp() {
337+
var perf = $window.performance;
338+
return perf && perf.now && perf.now() || +new $window.Date();
339+
}
324340
}

src/components/progressCircular/progress-circular.spec.js

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,89 +9,92 @@ describe('mdProgressCircular', function() {
99
}));
1010

1111
afterEach(function() {
12-
element.remove();
12+
if (element) {
13+
element.remove();
14+
}
1315
});
1416

15-
it('should auto-set the md-mode to "indeterminate" if not specified', inject(function($compile, $rootScope, $mdConstant) {
16-
element = $compile('<div>' +
17-
'<md-progress-circular></md-progress-circular>' +
18-
'</div>')($rootScope);
17+
it('should auto-set the md-mode to "indeterminate" if not specified', function() {
18+
var progress = buildIndicator('<md-progress-circular></md-progress-circular>');
1919

2020
$rootScope.$apply(function() {
2121
$rootScope.progress = 50;
2222
$rootScope.mode = "";
2323
});
2424

25-
var progress = element.find('md-progress-circular');
2625
expect(progress.attr('md-mode')).toEqual('indeterminate');
27-
}));
26+
});
2827

29-
it('should trim the md-mode value', inject(function($compile, $rootScope, $mdConstant) {
30-
element = $compile('<div>' +
31-
'<md-progress-circular md-mode=" indeterminate"></md-progress-circular>' +
32-
'</div>')($rootScope);
28+
it('should trim the md-mode value', function() {
29+
var progress = buildIndicator('<md-progress-circular md-mode=" indeterminate"></md-progress-circular>');
3330

3431
$rootScope.$apply(function() {
3532
$rootScope.progress = 50;
3633
});
3734

38-
var progress = element.find('md-progress-circular');
3935
expect(progress.attr('md-mode')).toEqual('indeterminate');
40-
}));
36+
});
4137

42-
it('should auto-set the md-mode to "determinate" if not specified but has value', inject(function($compile, $rootScope, $mdConstant) {
43-
var element = $compile('<div>' +
44-
'<md-progress-circular value="{{progress}}"></md-progress-circular>' +
45-
'</div>')($rootScope);
38+
it('should auto-set the md-mode to "determinate" if not specified but has value', function() {
39+
var progress = buildIndicator('<md-progress-circular value="{{progress}}"></md-progress-circular>');
4640

4741
$rootScope.$apply(function() {
4842
$rootScope.progress = 50;
4943
$rootScope.mode = "";
5044
});
5145

52-
var progress = element.find('md-progress-circular');
5346
expect(progress.attr('md-mode')).toEqual('determinate');
54-
}));
55-
56-
47+
});
5748

58-
it('should update aria-valuenow', inject(function($compile, $rootScope) {
59-
element = $compile('<div>' +
60-
'<md-progress-circular value="{{progress}}">' +
61-
'</md-progress-circular>' +
62-
'</div>')($rootScope);
49+
it('should update aria-valuenow', function() {
50+
var progress = buildIndicator('<md-progress-circular value="{{progress}}"></md-progress-circular>');
6351

6452
$rootScope.$apply(function() {
6553
$rootScope.progress = 50;
6654
});
6755

68-
var progress = element.find('md-progress-circular');
69-
expect(progress.eq(0).attr('aria-valuenow')).toEqual('50');
70-
}));
56+
expect(progress.attr('aria-valuenow')).toEqual('50');
57+
});
58+
59+
it('should\'t set aria-valuenow in indeterminate mode', function() {
60+
var progress = buildIndicator('<md-progress-circular md-mode="indeterminate" value="100"></md-progress-circular>');
61+
62+
expect(progress.attr('aria-valuenow')).toBeUndefined();
63+
});
7164

7265
it('should set the size using percentage values',function() {
7366
var progress = buildIndicator('<md-progress-circular md-diameter="50%"></md-progress-circular>');
74-
var expectedSize = config.progressSize/2 + 'px';
67+
var expectedSize = config.progressSize / 2 + 'px';
7568

7669
expect(progress.css('width')).toBe(expectedSize);
7770
expect(progress.css('height')).toBe(expectedSize);
7871
});
7972

80-
it('should set scaling using pixel values', function() {
73+
it('should set the size using pixel values', function() {
8174
var progress = buildIndicator('<md-progress-circular md-diameter="37px"></md-progress-circular>');
8275

8376
expect(progress.css('width')).toBe('37px');
8477
expect(progress.css('height')).toBe('37px');
8578
});
8679

80+
it('should scale the stroke width as a percentage of the diameter', function() {
81+
var ratio = config.strokeWidth;
82+
var diameter = 25;
83+
var path = buildIndicator(
84+
'<md-progress-circular md-diameter="' + diameter + '"></md-progress-circular>'
85+
).find('path').eq(0);
86+
87+
expect(path.css('stroke-width')).toBe(diameter / ratio + 'px');
88+
});
89+
8790
/**
8891
* Build a progressCircular
8992
*/
9093
function buildIndicator(template) {
91-
element = $compile('<div>' + template + '</div>')($rootScope);
92-
$rootScope.$digest();
94+
element = $compile(template)($rootScope);
95+
$rootScope.$digest();
9396

94-
return element.find('md-progress-circular');
97+
return element;
9598
}
9699

97100
});

0 commit comments

Comments
 (0)