wai-website-theme 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +52 -0
- data/_data/lang.json +730 -0
- data/_data/techniques.yml +180 -0
- data/_data/wcag.yml +125 -0
- data/_includes/.DS_Store +0 -0
- data/_includes/body-class.html +1 -0
- data/_includes/box.html +10 -0
- data/_includes/excol.html +13 -0
- data/_includes/footer.html +40 -0
- data/_includes/head.html +23 -0
- data/_includes/header.html +59 -0
- data/_includes/icon.html +6 -0
- data/_includes/img.html +17 -0
- data/_includes/multilang-list-policy-links.html +29 -0
- data/_includes/multilang-list.html +35 -0
- data/_includes/multilang-policy-title.html +5 -0
- data/_includes/multilang-title-full.html +1 -0
- data/_includes/multilang-title.html +1 -0
- data/_includes/navlist.html +22 -0
- data/_includes/notes.html +2 -0
- data/_includes/prevnext.html +34 -0
- data/_includes/resources.html +19 -0
- data/_includes/sidenav.html +65 -0
- data/_includes/sidenote.html +14 -0
- data/_includes/toc.html +10 -0
- data/_includes/video-player.html +99 -0
- data/_layouts/default.html +26 -0
- data/_layouts/home.html +14 -0
- data/_layouts/news.html +21 -0
- data/_layouts/none.html +1 -0
- data/_layouts/policy.html +72 -0
- data/_layouts/sidenav.html +27 -0
- data/_layouts/sidenavsidebar.html +22 -0
- data/assets/ableplayer/.gitattributes +14 -0
- data/assets/ableplayer/.gitignore +7 -0
- data/assets/ableplayer/Gruntfile.js +105 -0
- data/assets/ableplayer/LICENSE +26 -0
- data/assets/ableplayer/README.md +656 -0
- data/assets/ableplayer/build/ableplayer.dist.js +12157 -0
- data/assets/ableplayer/build/ableplayer.js +12157 -0
- data/assets/ableplayer/build/ableplayer.min.css +2 -0
- data/assets/ableplayer/build/ableplayer.min.js +8 -0
- data/assets/ableplayer/button-icons/able-icons.svg +116 -0
- data/assets/ableplayer/button-icons/black/captions.png +0 -0
- data/assets/ableplayer/button-icons/black/chapters.png +0 -0
- data/assets/ableplayer/button-icons/black/close.png +0 -0
- data/assets/ableplayer/button-icons/black/descriptions.png +0 -0
- data/assets/ableplayer/button-icons/black/ellipsis.png +0 -0
- data/assets/ableplayer/button-icons/black/faster.png +0 -0
- data/assets/ableplayer/button-icons/black/forward.png +0 -0
- data/assets/ableplayer/button-icons/black/fullscreen-collapse.png +0 -0
- data/assets/ableplayer/button-icons/black/fullscreen-expand.png +0 -0
- data/assets/ableplayer/button-icons/black/help.png +0 -0
- data/assets/ableplayer/button-icons/black/next.png +0 -0
- data/assets/ableplayer/button-icons/black/pause.png +0 -0
- data/assets/ableplayer/button-icons/black/pipe.png +0 -0
- data/assets/ableplayer/button-icons/black/play.png +0 -0
- data/assets/ableplayer/button-icons/black/preferences.png +0 -0
- data/assets/ableplayer/button-icons/black/previous.png +0 -0
- data/assets/ableplayer/button-icons/black/rabbit.png +0 -0
- data/assets/ableplayer/button-icons/black/restart.png +0 -0
- data/assets/ableplayer/button-icons/black/rewind.png +0 -0
- data/assets/ableplayer/button-icons/black/sign.png +0 -0
- data/assets/ableplayer/button-icons/black/slower.png +0 -0
- data/assets/ableplayer/button-icons/black/stop.png +0 -0
- data/assets/ableplayer/button-icons/black/transcript.png +0 -0
- data/assets/ableplayer/button-icons/black/turtle.png +0 -0
- data/assets/ableplayer/button-icons/black/volume-loud.png +0 -0
- data/assets/ableplayer/button-icons/black/volume-medium.png +0 -0
- data/assets/ableplayer/button-icons/black/volume-mute.png +0 -0
- data/assets/ableplayer/button-icons/black/volume-soft.png +0 -0
- data/assets/ableplayer/button-icons/fonts/able.eot +0 -0
- data/assets/ableplayer/button-icons/fonts/able.svg +40 -0
- data/assets/ableplayer/button-icons/fonts/able.ttf +0 -0
- data/assets/ableplayer/button-icons/fonts/able.woff +0 -0
- data/assets/ableplayer/button-icons/white/captions.png +0 -0
- data/assets/ableplayer/button-icons/white/chapters.png +0 -0
- data/assets/ableplayer/button-icons/white/close.png +0 -0
- data/assets/ableplayer/button-icons/white/descriptions.png +0 -0
- data/assets/ableplayer/button-icons/white/ellipsis.png +0 -0
- data/assets/ableplayer/button-icons/white/faster.png +0 -0
- data/assets/ableplayer/button-icons/white/forward.png +0 -0
- data/assets/ableplayer/button-icons/white/fullscreen-collapse.png +0 -0
- data/assets/ableplayer/button-icons/white/fullscreen-expand.png +0 -0
- data/assets/ableplayer/button-icons/white/help.png +0 -0
- data/assets/ableplayer/button-icons/white/next.png +0 -0
- data/assets/ableplayer/button-icons/white/pause.png +0 -0
- data/assets/ableplayer/button-icons/white/pipe.png +0 -0
- data/assets/ableplayer/button-icons/white/play.png +0 -0
- data/assets/ableplayer/button-icons/white/preferences.png +0 -0
- data/assets/ableplayer/button-icons/white/previous.png +0 -0
- data/assets/ableplayer/button-icons/white/rabbit.png +0 -0
- data/assets/ableplayer/button-icons/white/restart.png +0 -0
- data/assets/ableplayer/button-icons/white/rewind.png +0 -0
- data/assets/ableplayer/button-icons/white/sign.png +0 -0
- data/assets/ableplayer/button-icons/white/slower.png +0 -0
- data/assets/ableplayer/button-icons/white/stop.png +0 -0
- data/assets/ableplayer/button-icons/white/transcript.png +0 -0
- data/assets/ableplayer/button-icons/white/turtle.png +0 -0
- data/assets/ableplayer/button-icons/white/volume-loud.png +0 -0
- data/assets/ableplayer/button-icons/white/volume-medium.png +0 -0
- data/assets/ableplayer/button-icons/white/volume-mute.png +0 -0
- data/assets/ableplayer/button-icons/white/volume-soft.png +0 -0
- data/assets/ableplayer/images/wingrip.png +0 -0
- data/assets/ableplayer/package.json +22 -0
- data/assets/ableplayer/scripts/JQuery.doWhen.js +113 -0
- data/assets/ableplayer/scripts/ableplayer-base.js +440 -0
- data/assets/ableplayer/scripts/browser.js +162 -0
- data/assets/ableplayer/scripts/buildplayer.js +1609 -0
- data/assets/ableplayer/scripts/caption.js +385 -0
- data/assets/ableplayer/scripts/chapters.js +242 -0
- data/assets/ableplayer/scripts/control.js +1514 -0
- data/assets/ableplayer/scripts/description.js +283 -0
- data/assets/ableplayer/scripts/dialog.js +147 -0
- data/assets/ableplayer/scripts/dragdrop.js +766 -0
- data/assets/ableplayer/scripts/event.js +595 -0
- data/assets/ableplayer/scripts/initialize.js +725 -0
- data/assets/ableplayer/scripts/langs.js +750 -0
- data/assets/ableplayer/scripts/metadata.js +134 -0
- data/assets/ableplayer/scripts/misc.js +72 -0
- data/assets/ableplayer/scripts/preference.js +909 -0
- data/assets/ableplayer/scripts/search.js +171 -0
- data/assets/ableplayer/scripts/sign.js +92 -0
- data/assets/ableplayer/scripts/slider.js +454 -0
- data/assets/ableplayer/scripts/track.js +296 -0
- data/assets/ableplayer/scripts/transcript.js +590 -0
- data/assets/ableplayer/scripts/translation.js +66 -0
- data/assets/ableplayer/scripts/volume.js +383 -0
- data/assets/ableplayer/scripts/webvtt.js +765 -0
- data/assets/ableplayer/scripts/youtube.js +471 -0
- data/assets/ableplayer/styles/ableplayer.css +1241 -0
- data/assets/ableplayer/thirdparty/js.cookie.js +145 -0
- data/assets/ableplayer/thirdparty/modernizr.custom.js +4 -0
- data/assets/ableplayer/translations/ca.js +1 -0
- data/assets/ableplayer/translations/de.js +1 -0
- data/assets/ableplayer/translations/en.js +305 -0
- data/assets/ableplayer/translations/es.js +305 -0
- data/assets/ableplayer/translations/fr.js +305 -0
- data/assets/ableplayer/translations/it.js +303 -0
- data/assets/ableplayer/translations/ja.js +305 -0
- data/assets/ableplayer/translations/nl.js +305 -0
- data/assets/css/style.css +4360 -0
- data/assets/css/style.css.map +1 -0
- data/assets/fonts/anonymouspro-bold.woff +0 -0
- data/assets/fonts/anonymouspro-bold.woff2 +0 -0
- data/assets/fonts/anonymouspro-bolditalic.woff +0 -0
- data/assets/fonts/anonymouspro-bolditalic.woff2 +0 -0
- data/assets/fonts/anonymouspro-italic.woff +0 -0
- data/assets/fonts/anonymouspro-italic.woff2 +0 -0
- data/assets/fonts/anonymouspro-regular.woff +0 -0
- data/assets/fonts/anonymouspro-regular.woff2 +0 -0
- data/assets/fonts/notosans-bold.woff +0 -0
- data/assets/fonts/notosans-bold.woff2 +0 -0
- data/assets/fonts/notosans-bolditalic.woff +0 -0
- data/assets/fonts/notosans-bolditalic.woff2 +0 -0
- data/assets/fonts/notosans-italic.woff +0 -0
- data/assets/fonts/notosans-italic.woff2 +0 -0
- data/assets/fonts/notosans-regular.woff +0 -0
- data/assets/fonts/notosans-regular.woff2 +0 -0
- data/assets/images/.DS_Store +0 -0
- data/assets/images/Shape.svg +10 -0
- data/assets/images/icon-related-content.svg +14 -0
- data/assets/images/icons.svg +126 -0
- data/assets/images/teaser-image@1x.jpg +0 -0
- data/assets/images/teaser-image@2x.jpg +0 -0
- data/assets/images/w3c.sketch +0 -0
- data/assets/images/w3c.svg +10 -0
- data/assets/scripts/jquery.min.js +4 -0
- data/assets/scripts/main.js +208 -0
- data/assets/scripts/svg4everybody.js +1 -0
- metadata +257 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
(function ($) {
|
|
2
|
+
AblePlayer.prototype.initDescription = function() {
|
|
3
|
+
|
|
4
|
+
// set default mode for delivering description (open vs closed)
|
|
5
|
+
// based on availability and user preference
|
|
6
|
+
|
|
7
|
+
// called when player is being built, or when a user
|
|
8
|
+
// toggles the Description button or changes a description-related preference
|
|
9
|
+
// In the latter two scendarios, this.refreshingDesc == true via control.js > handleDescriptionToggle()
|
|
10
|
+
|
|
11
|
+
// The following variables are applicable to delivery of description:
|
|
12
|
+
// prefDesc == 1 if user wants description (i.e., Description button is on); else 0
|
|
13
|
+
// prefDescFormat == either 'video' or 'text'
|
|
14
|
+
// prefDescPause == 1 to pause video when description starts; else 0
|
|
15
|
+
// prefVisibleDesc == 1 to visibly show text-based description area; else 0
|
|
16
|
+
// hasOpenDesc == true if a described version of video is available via data-desc-src attribute
|
|
17
|
+
// hasClosedDesc == true if a description text track is available
|
|
18
|
+
// this.useDescFormat == either 'video' or 'text'; the format ultimately delivered
|
|
19
|
+
// descOn == true if description of either type is on
|
|
20
|
+
if (!this.refreshingDesc) {
|
|
21
|
+
// this is the initial build
|
|
22
|
+
// first, check to see if there's an open-described version of this video
|
|
23
|
+
// checks only the first source since if a described version is provided,
|
|
24
|
+
// it must be provided for all sources
|
|
25
|
+
this.descFile = this.$sources.first().attr('data-desc-src');
|
|
26
|
+
if (typeof this.descFile !== 'undefined') {
|
|
27
|
+
this.hasOpenDesc = true;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// there's no open-described version via data-desc-src, but what about data-youtube-desc-src?
|
|
31
|
+
if (this.youTubeDescId) {
|
|
32
|
+
this.hasOpenDesc = true;
|
|
33
|
+
}
|
|
34
|
+
else { // there are no open-described versions from any source
|
|
35
|
+
this.hasOpenDesc = false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// update this.useDescFormat based on media availability & user preferences
|
|
40
|
+
if (this.prefDesc) {
|
|
41
|
+
if (this.hasOpenDesc && this.hasClosedDesc) {
|
|
42
|
+
// both formats are available. Use whichever one user prefers
|
|
43
|
+
this.useDescFormat = this.prefDescFormat;
|
|
44
|
+
this.descOn = true;
|
|
45
|
+
}
|
|
46
|
+
else if (this.hasOpenDesc) {
|
|
47
|
+
this.useDescFormat = 'video';
|
|
48
|
+
this.descOn = true;
|
|
49
|
+
}
|
|
50
|
+
else if (this.hasClosedDesc) {
|
|
51
|
+
this.useDescFormat = 'text';
|
|
52
|
+
this.descOn = true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else { // description button is off
|
|
56
|
+
if (this.refreshingDesc) { // user just now toggled it off
|
|
57
|
+
this.prevDescFormat = this.useDescFormat;
|
|
58
|
+
this.useDescFormat = false;
|
|
59
|
+
this.descOn = false;
|
|
60
|
+
}
|
|
61
|
+
else { // desc has always been off
|
|
62
|
+
this.useDescFormat = false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (this.descOn) {
|
|
67
|
+
|
|
68
|
+
if (this.useDescFormat === 'video') {
|
|
69
|
+
|
|
70
|
+
if (!this.usingAudioDescription()) {
|
|
71
|
+
// switched from non-described to described version
|
|
72
|
+
this.swapDescription();
|
|
73
|
+
}
|
|
74
|
+
// hide description div
|
|
75
|
+
this.$descDiv.hide();
|
|
76
|
+
this.$descDiv.removeClass('able-clipped');
|
|
77
|
+
}
|
|
78
|
+
else if (this.useDescFormat === 'text') {
|
|
79
|
+
this.$descDiv.show();
|
|
80
|
+
if (this.prefVisibleDesc) { // make it visible to everyone
|
|
81
|
+
this.$descDiv.removeClass('able-clipped');
|
|
82
|
+
}
|
|
83
|
+
else { // keep it visible to screen readers, but hide from everyone else
|
|
84
|
+
this.$descDiv.addClass('able-clipped');
|
|
85
|
+
}
|
|
86
|
+
if (!this.swappingSrc) {
|
|
87
|
+
this.showDescription(this.getElapsed());
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else { // description is off.
|
|
92
|
+
|
|
93
|
+
if (this.prevDescFormat === 'video') { // user was previously using description via video
|
|
94
|
+
if (this.usingAudioDescription()) {
|
|
95
|
+
this.swapDescription();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (this.prevDescFormat === 'text') { // user was previously using text description
|
|
99
|
+
// hide description div from everyone, including screen reader users
|
|
100
|
+
this.$descDiv.hide();
|
|
101
|
+
this.$descDiv.removeClass('able-clipped');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
this.refreshingDesc = false;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Returns true if currently using audio description, false otherwise.
|
|
108
|
+
AblePlayer.prototype.usingAudioDescription = function () {
|
|
109
|
+
|
|
110
|
+
if (this.player === 'youtube') {
|
|
111
|
+
return (this.activeYouTubeId === this.youTubeDescId);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
return (this.$sources.first().attr('data-desc-src') === this.$sources.first().attr('src'));
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
AblePlayer.prototype.swapDescription = function() {
|
|
119
|
+
// swap described and non-described source media, depending on which is playing
|
|
120
|
+
// this function is only called in two circumstances:
|
|
121
|
+
// 1. Swapping to described version when initializing player (based on user prefs & availability)
|
|
122
|
+
// 2. User is toggling description
|
|
123
|
+
var thisObj, i, origSrc, descSrc, srcType, jwSourceIndex, newSource;
|
|
124
|
+
|
|
125
|
+
thisObj = this;
|
|
126
|
+
|
|
127
|
+
// get current time, and start new video at the same time
|
|
128
|
+
// NOTE: There is some risk in resuming playback at the same start time
|
|
129
|
+
// since the described version might include extended audio description (with pauses)
|
|
130
|
+
// and might therefore be longer than the non-described version
|
|
131
|
+
// The benefits though would seem to outweigh this risk
|
|
132
|
+
this.swapTime = this.getElapsed(); // video will scrub to this time after loaded (see event.js)
|
|
133
|
+
|
|
134
|
+
if (this.descOn) {
|
|
135
|
+
// user has requested the described version
|
|
136
|
+
this.showAlert(this.tt.alertDescribedVersion);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// user has requested the non-described version
|
|
140
|
+
this.showAlert(this.tt.alertNonDescribedVersion);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (this.player === 'html5') {
|
|
144
|
+
|
|
145
|
+
if (this.usingAudioDescription()) {
|
|
146
|
+
// the described version is currently playing. Swap to non-described
|
|
147
|
+
for (i=0; i < this.$sources.length; i++) {
|
|
148
|
+
// for all <source> elements, replace src with data-orig-src
|
|
149
|
+
origSrc = this.$sources[i].getAttribute('data-orig-src');
|
|
150
|
+
srcType = this.$sources[i].getAttribute('type');
|
|
151
|
+
if (origSrc) {
|
|
152
|
+
this.$sources[i].setAttribute('src',origSrc);
|
|
153
|
+
}
|
|
154
|
+
if (srcType === 'video/mp4') {
|
|
155
|
+
jwSourceIndex = i;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// No need to check for this.initializing
|
|
159
|
+
// This function is only called during initialization
|
|
160
|
+
// if swapping from non-described to described
|
|
161
|
+
this.swappingSrc = true;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// the non-described version is currently playing. Swap to described.
|
|
165
|
+
for (i=0; i < this.$sources.length; i++) {
|
|
166
|
+
// for all <source> elements, replace src with data-desc-src (if one exists)
|
|
167
|
+
// then store original source in a new data-orig-src attribute
|
|
168
|
+
origSrc = this.$sources[i].getAttribute('src');
|
|
169
|
+
descSrc = this.$sources[i].getAttribute('data-desc-src');
|
|
170
|
+
srcType = this.$sources[i].getAttribute('type');
|
|
171
|
+
if (descSrc) {
|
|
172
|
+
this.$sources[i].setAttribute('src',descSrc);
|
|
173
|
+
this.$sources[i].setAttribute('data-orig-src',origSrc);
|
|
174
|
+
}
|
|
175
|
+
if (srcType === 'video/mp4') {
|
|
176
|
+
jwSourceIndex = i;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
this.swappingSrc = true;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// now reload the source file.
|
|
183
|
+
if (this.player === 'html5') {
|
|
184
|
+
this.media.load();
|
|
185
|
+
}
|
|
186
|
+
else if (this.player === 'youtube') {
|
|
187
|
+
// TODO: Load new youTubeId
|
|
188
|
+
}
|
|
189
|
+
else if (this.player === 'jw' && this.jwPlayer) {
|
|
190
|
+
newSource = this.$sources[jwSourceIndex].getAttribute('src');
|
|
191
|
+
this.jwPlayer.load({file: newSource});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else if (this.player === 'youtube') {
|
|
195
|
+
|
|
196
|
+
if (this.usingAudioDescription()) {
|
|
197
|
+
// the described version is currently playing. Swap to non-described
|
|
198
|
+
this.activeYouTubeId = this.youTubeId;
|
|
199
|
+
this.showAlert(this.tt.alertNonDescribedVersion);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
// the non-described version is currently playing. Swap to described.
|
|
203
|
+
this.activeYouTubeId = this.youTubeDescId;
|
|
204
|
+
this.showAlert(this.tt.alertDescribedVersion);
|
|
205
|
+
}
|
|
206
|
+
if (typeof this.youTubePlayer !== 'undefined') {
|
|
207
|
+
|
|
208
|
+
// retrieve/setup captions for the new video from YouTube
|
|
209
|
+
this.setupAltCaptions().then(function() {
|
|
210
|
+
|
|
211
|
+
if (thisObj.playing) {
|
|
212
|
+
// loadVideoById() loads and immediately plays the new video at swapTime
|
|
213
|
+
thisObj.youTubePlayer.loadVideoById(thisObj.activeYouTubeId,thisObj.swapTime);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
// cueVideoById() loads the new video and seeks to swapTime, but does not play
|
|
217
|
+
thisObj.youTubePlayer.cueVideoById(thisObj.activeYouTubeId,thisObj.swapTime);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
AblePlayer.prototype.showDescription = function(now) {
|
|
225
|
+
|
|
226
|
+
// there's a lot of redundancy between this function and showCaptions
|
|
227
|
+
// Trying to combine them ended up in a mess though. Keeping as is for now.
|
|
228
|
+
|
|
229
|
+
if (this.swappingSrc) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
var d, thisDescription;
|
|
234
|
+
var flattenComponentForDescription = function (component) {
|
|
235
|
+
var result = [];
|
|
236
|
+
if (component.type === 'string') {
|
|
237
|
+
result.push(component.value);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
for (var ii = 0; ii < component.children.length; ii++) {
|
|
241
|
+
result.push(flattenComponentForDescription(component.children[ii]));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return result.join('');
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
var cues;
|
|
248
|
+
if (this.selectedDescriptions) {
|
|
249
|
+
cues = this.selectedDescriptions.cues;
|
|
250
|
+
}
|
|
251
|
+
else if (this.descriptions.length >= 1) {
|
|
252
|
+
cues = this.descriptions[0].cues;
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
cues = [];
|
|
256
|
+
}
|
|
257
|
+
for (d = 0; d < cues.length; d++) {
|
|
258
|
+
if ((cues[d].start <= now) && (cues[d].end > now)) {
|
|
259
|
+
thisDescription = d;
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (typeof thisDescription !== 'undefined') {
|
|
264
|
+
if (this.currentDescription !== thisDescription) {
|
|
265
|
+
// temporarily remove aria-live from $status in order to prevent description from being interrupted
|
|
266
|
+
this.$status.removeAttr('aria-live');
|
|
267
|
+
// load the new description into the container div
|
|
268
|
+
this.$descDiv.html(flattenComponentForDescription(cues[thisDescription].components));
|
|
269
|
+
if (this.prefDescPause) {
|
|
270
|
+
this.pauseMedia();
|
|
271
|
+
}
|
|
272
|
+
this.currentDescription = thisDescription;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
this.$descDiv.html('');
|
|
277
|
+
this.currentDescription = -1;
|
|
278
|
+
// restore aria-live to $status
|
|
279
|
+
this.$status.attr('aria-live','polite');
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
})(jQuery);
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
(function ($) {
|
|
2
|
+
var focusableElementsSelector = "a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]";
|
|
3
|
+
|
|
4
|
+
// Based on the incredible accessible modal dialog.
|
|
5
|
+
window.AccessibleDialog = function(modalDiv, $returnElement, dialogRole, title, $descDiv, closeButtonLabel, width, fullscreen, escapeHook) {
|
|
6
|
+
|
|
7
|
+
this.title = title;
|
|
8
|
+
this.closeButtonLabel = closeButtonLabel;
|
|
9
|
+
this.focusedElementBeforeModal = $returnElement;
|
|
10
|
+
this.escapeHook = escapeHook;
|
|
11
|
+
this.baseId = $(modalDiv).attr('id') || Math.floor(Math.random() * 1000000000).toString();
|
|
12
|
+
var thisObj = this;
|
|
13
|
+
var modal = modalDiv;
|
|
14
|
+
this.modal = modal;
|
|
15
|
+
modal.css({
|
|
16
|
+
'width': width || '50%',
|
|
17
|
+
'top': (fullscreen ? '0' : '5%')
|
|
18
|
+
});
|
|
19
|
+
modal.addClass('able-modal-dialog');
|
|
20
|
+
|
|
21
|
+
if (!fullscreen) {
|
|
22
|
+
var closeButton = $('<button>',{
|
|
23
|
+
'class': 'modalCloseButton',
|
|
24
|
+
'title': thisObj.closeButtonLabel,
|
|
25
|
+
'aria-label': thisObj.closeButtonLabel
|
|
26
|
+
}).text('X');
|
|
27
|
+
closeButton.keydown(function (event) {
|
|
28
|
+
// Space key down
|
|
29
|
+
if (event.which === 32) {
|
|
30
|
+
thisObj.hide();
|
|
31
|
+
}
|
|
32
|
+
}).click(function () {
|
|
33
|
+
thisObj.hide();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
var titleH1 = $('<h1></h1>');
|
|
37
|
+
titleH1.attr('id', 'modalTitle-' + this.baseId);
|
|
38
|
+
titleH1.css('text-align', 'center');
|
|
39
|
+
titleH1.text(title);
|
|
40
|
+
|
|
41
|
+
$descDiv.attr('id', 'modalDesc-' + this.baseId);
|
|
42
|
+
|
|
43
|
+
modal.attr({
|
|
44
|
+
'aria-labelledby': 'modalTitle-' + this.baseId,
|
|
45
|
+
'aria-describedby': 'modalDesc-' + this.baseId
|
|
46
|
+
});
|
|
47
|
+
modal.prepend(titleH1);
|
|
48
|
+
modal.prepend(closeButton);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
modal.attr({
|
|
52
|
+
'aria-hidden': 'true',
|
|
53
|
+
'role': dialogRole
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
modal.keydown(function (event) {
|
|
57
|
+
// Escape
|
|
58
|
+
if (event.which === 27) {
|
|
59
|
+
if (thisObj.escapeHook) {
|
|
60
|
+
thisObj.escapeHook(event, this);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
thisObj.hide();
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Tab
|
|
68
|
+
else if (event.which === 9) {
|
|
69
|
+
// Manually loop tab navigation inside the modal.
|
|
70
|
+
var parts = modal.find('*');
|
|
71
|
+
var focusable = parts.filter(focusableElementsSelector).filter(':visible');
|
|
72
|
+
|
|
73
|
+
if (focusable.length === 0) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
var focused = $(':focus');
|
|
78
|
+
var currentIndex = focusable.index(focused);
|
|
79
|
+
if (event.shiftKey) {
|
|
80
|
+
// If backwards from first element, go to last.
|
|
81
|
+
if (currentIndex === 0) {
|
|
82
|
+
focusable.get(focusable.length - 1).focus();
|
|
83
|
+
event.preventDefault();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
if (currentIndex === focusable.length - 1) {
|
|
88
|
+
focusable.get(0).focus();
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
event.stopPropagation();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
$('body > *').not('.able-modal-overlay').not('.able-modal-dialog').attr('aria-hidden', 'false');
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
AccessibleDialog.prototype.show = function () {
|
|
100
|
+
if (!this.overlay) {
|
|
101
|
+
// Generate overlay.
|
|
102
|
+
var overlay = $('<div></div>').attr({
|
|
103
|
+
'class': 'able-modal-overlay',
|
|
104
|
+
'tabindex': '-1'
|
|
105
|
+
});
|
|
106
|
+
this.overlay = overlay;
|
|
107
|
+
$('body').append(overlay);
|
|
108
|
+
|
|
109
|
+
// Keep from moving focus out of dialog when clicking outside of it.
|
|
110
|
+
overlay.on('mousedown.accessibleModal', function (event) {
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
$('body > *').not('.able-modal-overlay').not('.able-modal-dialog').attr('aria-hidden', 'true');
|
|
116
|
+
|
|
117
|
+
this.overlay.css('display', 'block');
|
|
118
|
+
this.modal.css('display', 'block');
|
|
119
|
+
this.modal.attr({
|
|
120
|
+
'aria-hidden': 'false',
|
|
121
|
+
'tabindex': '-1'
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
var focusable = this.modal.find("*").filter(focusableElementsSelector).filter(':visible');
|
|
125
|
+
if (focusable.length === 0) {
|
|
126
|
+
this.focusedElementBeforeModal.blur();
|
|
127
|
+
}
|
|
128
|
+
var thisObj = this;
|
|
129
|
+
setTimeout(function () {
|
|
130
|
+
// originally set focus on the first focusable element
|
|
131
|
+
// thisObj.modal.find('button.modalCloseButton').first().focus();
|
|
132
|
+
// but setting focus on dialog seems to provide more reliable access to ALL content within
|
|
133
|
+
thisObj.modal.focus();
|
|
134
|
+
}, 300);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
AccessibleDialog.prototype.hide = function () {
|
|
138
|
+
if (this.overlay) {
|
|
139
|
+
this.overlay.css('display', 'none');
|
|
140
|
+
}
|
|
141
|
+
this.modal.css('display', 'none');
|
|
142
|
+
this.modal.attr('aria-hidden', 'true');
|
|
143
|
+
$('body > *').not('.able-modal-overlay').not('.able-modal-dialog').attr('aria-hidden', 'false');
|
|
144
|
+
|
|
145
|
+
this.focusedElementBeforeModal.focus();
|
|
146
|
+
};
|
|
147
|
+
})(jQuery);
|