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

Commit 725b19a

Browse files
committed
feat(a11y): improve the accessibility of the projec
1 parent ffff03d commit 725b19a

10 files changed

+132
-24
lines changed

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,19 @@ git diff step-?..step-?
165165
- CSS transition animations.
166166
- CSS keyframe animations.
167167
- JavaScript-based animations.
168+
169+
### step-15 _Accessibility (a11y)_
170+
171+
- Add ngAria module.
172+
- Add labels to the search and order fields.
173+
- Add accessibility plugin for Protractor.
174+
- Add missing alt attributes in the phone detail.
175+
- Add aria live regions to inform the user about results after searching and filtering elements.
176+
- Improve access via keyboard:
177+
- Navigate between the images in a phone detail.
178+
- Add headings elements.
179+
- Add information about checkmarks in the phone detail specs.
180+
168181

169182

170183
## Development with `angular-phonecat`
@@ -267,3 +280,4 @@ For more information on AngularJS, please check out https://angularjs.org/.
267280
[karma]: https://karma-runner.github.io
268281
[node-download]: https://nodejs.org/en/download/
269282
[protractor]: http://www.protractortest.org/
283+
[protractor-accessibility-plugin]: https://github.com/angular/protractor-accessibility-plugin

app/app.css

+29
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ h1 {
77
margin-top: 0;
88
}
99

10+
.aria-status { margin-bottom: 10px; }
11+
.aria-status-order{ margin-bottom: 5px; }
12+
1013
/* View: Phone list */
1114
.phones {
1215
list-style: none;
@@ -70,6 +73,19 @@ h1 {
7073
margin: 1em;
7174
}
7275

76+
.phone-thumbs img:focus {
77+
border:2px solid black;
78+
}
79+
80+
.phone-thumbs img:hover {
81+
cursor: pointer;
82+
}
83+
84+
.phone-thumbs button {
85+
background: none;
86+
border: 0;
87+
}
88+
7389
.specs {
7490
clear: both;
7591
list-style: none;
@@ -91,3 +107,16 @@ h1 {
91107
font-size: 1.2em;
92108
font-weight: bold;
93109
}
110+
111+
ul.specs h2 { font-size:1.5em }
112+
113+
.sr-only {
114+
position: absolute;
115+
width: 1px;
116+
height: 1px;
117+
padding: 0;
118+
margin: -1px;
119+
overflow: hidden;
120+
clip: rect(0,0,0,0);
121+
border: 0;
122+
}

app/app.module.js

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
angular.module('phonecatApp', [
55
'ngAnimate',
66
'ngRoute',
7+
'ngAria',
78
'core',
89
'phoneDetail',
910
'phoneList',

app/index.html

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<script src="bower_components/jquery/dist/jquery.js"></script>
1111
<script src="bower_components/angular/angular.js"></script>
1212
<script src="bower_components/angular-animate/angular-animate.js"></script>
13+
<script src="bower_components/angular-aria/angular-aria.js"></script>
1314
<script src="bower_components/angular-resource/angular-resource.js"></script>
1415
<script src="bower_components/angular-route/angular-route.js"></script>
1516
<script src="app.module.js"></script>
@@ -20,6 +21,7 @@
2021
<script src="core/phone/phone.module.js"></script>
2122
<script src="core/phone/phone.service.js"></script>
2223
<script src="phone-list/phone-list.module.js"></script>
24+
<script src="phone-list/phone-list.directive.js"></script>
2325
<script src="phone-list/phone-list.component.js"></script>
2426
<script src="phone-detail/phone-detail.module.js"></script>
2527
<script src="phone-detail/phone-detail.component.js"></script>

app/phone-detail/phone-detail.template.html

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<div class="phone-images">
22
<img ng-src="{{img}}" class="phone"
3+
alt=""
34
ng-class="{selected: img === $ctrl.mainImageUrl}"
45
ng-repeat="img in $ctrl.phone.images" />
56
</div>
@@ -8,22 +9,24 @@ <h1>{{$ctrl.phone.name}}</h1>
89

910
<p>{{$ctrl.phone.description}}</p>
1011

12+
<p class="sr-only">Click on each image to see the enlarge version.</p>
13+
1114
<ul class="phone-thumbs">
1215
<li ng-repeat="img in $ctrl.phone.images">
13-
<img ng-src="{{img}}" ng-click="$ctrl.setImage(img)" />
16+
<button type="button" aria-label="view enlarge version of the image" ng-click="$ctrl.setImage(img)"><img ng-src="{{img}}" alt="" /></button>
1417
</li>
1518
</ul>
1619

1720
<ul class="specs">
1821
<li>
19-
<span>Availability and Networks</span>
22+
<h2>Availability and Networks</h2>
2023
<dl>
2124
<dt>Availability</dt>
2225
<dd ng-repeat="availability in $ctrl.phone.availability">{{availability}}</dd>
2326
</dl>
2427
</li>
2528
<li>
26-
<span>Battery</span>
29+
<h2>Battery</h2>
2730
<dl>
2831
<dt>Type</dt>
2932
<dd>{{$ctrl.phone.battery.type}}</dd>
@@ -34,7 +37,7 @@ <h1>{{$ctrl.phone.name}}</h1>
3437
</dl>
3538
</li>
3639
<li>
37-
<span>Storage and Memory</span>
40+
<h2>Storage and Memory</h2>
3841
<dl>
3942
<dt>RAM</dt>
4043
<dd>{{$ctrl.phone.storage.ram}}</dd>
@@ -43,7 +46,7 @@ <h1>{{$ctrl.phone.name}}</h1>
4346
</dl>
4447
</li>
4548
<li>
46-
<span>Connectivity</span>
49+
<h2>Connectivity</h2>
4750
<dl>
4851
<dt>Network Support</dt>
4952
<dd>{{$ctrl.phone.connectivity.cell}}</dd>
@@ -58,7 +61,7 @@ <h1>{{$ctrl.phone.name}}</h1>
5861
</dl>
5962
</li>
6063
<li>
61-
<span>Android</span>
64+
<h2>Android</h2>
6265
<dl>
6366
<dt>OS Version</dt>
6467
<dd>{{$ctrl.phone.android.os}}</dd>
@@ -67,7 +70,7 @@ <h1>{{$ctrl.phone.name}}</h1>
6770
</dl>
6871
</li>
6972
<li>
70-
<span>Size and Weight</span>
73+
<h2>Size and Weight</h2>
7174
<dl>
7275
<dt>Dimensions</dt>
7376
<dd ng-repeat="dim in $ctrl.phone.sizeAndWeight.dimensions">{{dim}}</dd>
@@ -76,7 +79,7 @@ <h1>{{$ctrl.phone.name}}</h1>
7679
</dl>
7780
</li>
7881
<li>
79-
<span>Display</span>
82+
<h2>Display</h2>
8083
<dl>
8184
<dt>Screen size</dt>
8285
<dd>{{$ctrl.phone.display.screenSize}}</dd>
@@ -87,7 +90,7 @@ <h1>{{$ctrl.phone.name}}</h1>
8790
</dl>
8891
</li>
8992
<li>
90-
<span>Hardware</span>
93+
<h2>Hardware</h2>
9194
<dl>
9295
<dt>CPU</dt>
9396
<dd>{{$ctrl.phone.hardware.cpu}}</dd>
@@ -102,7 +105,7 @@ <h1>{{$ctrl.phone.name}}</h1>
102105
</dl>
103106
</li>
104107
<li>
105-
<span>Camera</span>
108+
<h2>Camera</h2>
106109
<dl>
107110
<dt>Primary</dt>
108111
<dd>{{$ctrl.phone.camera.primary}}</dd>
@@ -111,7 +114,7 @@ <h1>{{$ctrl.phone.name}}</h1>
111114
</dl>
112115
</li>
113116
<li>
114-
<span>Additional Features</span>
117+
<h2>Additional Features</h2>
115118
<dd>{{$ctrl.phone.additionalFeatures}}</dd>
116119
</li>
117120
</ul>
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
'use strict';
3+
4+
/* Directives */
5+
6+
angular.
7+
module('phoneList').
8+
directive('resultList', [function () {
9+
var ariaStatus = document.querySelector('.aria-status');
10+
return {
11+
restrict: 'A',
12+
link: function ($scope) {
13+
$scope.$watch('filtered.length', function (length) {
14+
if(length === 1) {
15+
ariaStatus.innerHTML = length + ' item found';
16+
} else if(length > 1) {
17+
ariaStatus.innerHTML = length + ' items found';
18+
} else {
19+
ariaStatus.innerHTML = 'No items found';
20+
}
21+
});
22+
}
23+
}
24+
}
25+
]).
26+
directive('informOrder', [function () {
27+
var ariaStatusSort = document.querySelector('.aria-status-sort');
28+
return {
29+
restrict: 'A',
30+
link: function ($scope) {
31+
$scope.$watch('$ctrl.orderProp', function (order) {
32+
if(order === 'age') {
33+
ariaStatusSort.innerHTML = 'Items filter by newest'
34+
} else {
35+
ariaStatusSort.innerHTML = 'Items filter by alphabetical order'
36+
}
37+
38+
});
39+
}
40+
}
41+
}
42+
]);

app/phone-list/phone-list.template.html

+15-11
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,29 @@
33
<div class="col-md-2">
44
<!--Sidebar content-->
55

6-
<p>
7-
Search:
8-
<input ng-model="$ctrl.query" />
9-
</p>
10-
11-
<p>
12-
Sort by:
13-
<select ng-model="$ctrl.orderProp">
6+
<div>
7+
<label for="search">Search:</label>
8+
<input id="search" ng-model="$ctrl.query" ng-model-options="{ debounce: 900 }">
9+
</div>
10+
11+
<div class="aria-status" aria-live="assertive" aria-atomic="true"></div>
12+
13+
<div>
14+
<label for="order">Sort by:</label>
15+
<select inform-order id="order" ng-model="$ctrl.orderProp">
1416
<option value="name">Alphabetical</option>
1517
<option value="age">Newest</option>
1618
</select>
17-
</p>
19+
</div>
20+
21+
<div class="aria-status-sort" aria-live="assertive" aria-atomic="true"></div>
1822

1923
</div>
2024
<div class="col-md-10">
2125
<!--Body content-->
2226

23-
<ul class="phones">
24-
<li ng-repeat="phone in $ctrl.phones | filter:$ctrl.query | orderBy:$ctrl.orderProp"
27+
<ul result-list class="phones">
28+
<li ng-repeat="phone in filtered = ($ctrl.phones | filter:$ctrl.query | orderBy:$ctrl.orderProp)"
2529
class="thumbnail phone-list-item">
2630
<a href="#!/phones/{{phone.id}}" class="thumb">
2731
<img ng-src="{{phone.imageUrl}}" alt="{{phone.name}}" />

bower.json

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"dependencies": {
99
"angular": "1.5.x",
1010
"angular-animate": "1.5.x",
11+
"angular-aria": "1.5.x",
1112
"angular-mocks": "1.5.x",
1213
"angular-resource": "1.5.x",
1314
"angular-route": "1.5.x",

e2e-tests/protractor.conf.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ exports.config = {
1717

1818
jasmineNodeOpts: {
1919
defaultTimeoutInterval: 30000
20-
}
20+
},
21+
22+
chromeOnly: true,
23+
directConnect: true,
24+
25+
plugins: [{
26+
chromeA11YDevTools: {
27+
treatWarningsAsFailures: true
28+
},
29+
package: 'protractor-accessibility-plugin'
30+
}]
2131

2232
};

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
"karma-chrome-launcher": "^0.2.3",
1414
"karma-firefox-launcher": "^0.1.7",
1515
"karma-jasmine": "^0.3.8",
16-
"protractor": "^3.2.2"
16+
"protractor": "^3.2.2",
17+
"protractor-accessibility-plugin": "^0.1.1",
18+
"shelljs": "^0.6.0"
1719
},
1820
"scripts": {
1921
"postinstall": "bower install",

0 commit comments

Comments
 (0)