wai-website-theme 1.3.1 → 1.4
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 +4 -4
- data/_includes/different.html +2 -1
- data/_includes/external.html +2 -1
- data/_includes/header.html +2 -1
- data/_includes/menuitem.html +6 -2
- data/_includes/peoplelist.html +21 -0
- data/_includes/prevnext-navigation.html +56 -0
- data/_includes/{prevnext.html → prevnext-order.html} +9 -0
- data/_includes/translation-note-msg.html +5 -3
- data/_includes/video-player.html +2 -2
- data/_layouts/default.html +8 -1
- data/_layouts/news.html +7 -1
- data/_layouts/policy.html +7 -1
- data/_layouts/sidenav.html +8 -1
- data/_layouts/sidenavsidebar.html +8 -1
- data/assets/ableplayer/Gruntfile.js +2 -1
- data/assets/ableplayer/README.md +158 -85
- data/assets/ableplayer/build/ableplayer.dist.js +15445 -13823
- data/assets/ableplayer/build/ableplayer.js +15445 -13823
- data/assets/ableplayer/build/ableplayer.min.css +1 -2
- data/assets/ableplayer/build/ableplayer.min.js +3 -10
- data/assets/ableplayer/package-lock.json +944 -346
- data/assets/ableplayer/package.json +8 -8
- data/assets/ableplayer/scripts/ableplayer-base.js +515 -524
- data/assets/ableplayer/scripts/browser.js +158 -158
- data/assets/ableplayer/scripts/buildplayer.js +1750 -1682
- data/assets/ableplayer/scripts/caption.js +424 -401
- data/assets/ableplayer/scripts/chapters.js +259 -259
- data/assets/ableplayer/scripts/control.js +1831 -1594
- data/assets/ableplayer/scripts/description.js +333 -256
- data/assets/ableplayer/scripts/dialog.js +145 -145
- data/assets/ableplayer/scripts/dragdrop.js +746 -749
- data/assets/ableplayer/scripts/event.js +875 -696
- data/assets/ableplayer/scripts/initialize.js +819 -912
- data/assets/ableplayer/scripts/langs.js +979 -743
- data/assets/ableplayer/scripts/metadata.js +124 -124
- data/assets/ableplayer/scripts/misc.js +170 -137
- data/assets/ableplayer/scripts/preference.js +904 -904
- data/assets/ableplayer/scripts/search.js +172 -172
- data/assets/ableplayer/scripts/sign.js +82 -78
- data/assets/ableplayer/scripts/slider.js +449 -448
- data/assets/ableplayer/scripts/track.js +409 -309
- data/assets/ableplayer/scripts/transcript.js +684 -595
- data/assets/ableplayer/scripts/translation.js +63 -67
- data/assets/ableplayer/scripts/ttml2webvtt.js +85 -85
- data/assets/ableplayer/scripts/vimeo.js +448 -0
- data/assets/ableplayer/scripts/volume.js +395 -380
- data/assets/ableplayer/scripts/vts.js +1077 -1077
- data/assets/ableplayer/scripts/webvtt.js +766 -763
- data/assets/ableplayer/scripts/youtube.js +695 -478
- data/assets/ableplayer/styles/ableplayer.css +54 -46
- data/assets/ableplayer/translations/nl.js +54 -54
- data/assets/ableplayer/translations/pt-br.js +311 -0
- data/assets/ableplayer/translations/tr.js +311 -0
- data/assets/ableplayer/translations/zh-tw.js +1 -1
- data/assets/css/style.css +1 -1
- data/assets/css/style.css.map +1 -1
- data/assets/images/icons.svg +5 -5
- data/assets/scripts/main.js +7 -0
- data/assets/search/tipuesearch.js +3 -3
- metadata +8 -3
|
@@ -1,283 +1,360 @@
|
|
|
1
1
|
(function ($) {
|
|
2
|
-
|
|
2
|
+
AblePlayer.prototype.initDescription = function() {
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
// set default mode for delivering description (open vs closed)
|
|
5
|
+
// based on availability and user preference
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
}
|
|
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
|
|
65
20
|
|
|
66
|
-
|
|
21
|
+
var thisObj = this;
|
|
67
22
|
|
|
68
|
-
|
|
23
|
+
if (!this.refreshingDesc) {
|
|
24
|
+
// this is the initial build
|
|
25
|
+
// first, check to see if there's an open-described version of this video
|
|
26
|
+
// checks only the first source since if a described version is provided,
|
|
27
|
+
// it must be provided for all sources
|
|
28
|
+
this.descFile = this.$sources.first().attr('data-desc-src');
|
|
29
|
+
if (typeof this.descFile !== 'undefined') {
|
|
30
|
+
this.hasOpenDesc = true;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// there's no open-described version via data-desc-src,
|
|
34
|
+
// but what about data-youtube-desc-src or data-vimeo-desc-src?
|
|
35
|
+
if (this.youTubeDescId || this.vimeoDescId) {
|
|
36
|
+
this.hasOpenDesc = true;
|
|
37
|
+
}
|
|
38
|
+
else { // there are no open-described versions from any source
|
|
39
|
+
this.hasOpenDesc = false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// update this.useDescFormat based on media availability & user preferences
|
|
44
|
+
if (this.prefDesc) {
|
|
45
|
+
if (this.hasOpenDesc && this.hasClosedDesc) {
|
|
46
|
+
// both formats are available. Use whichever one user prefers
|
|
47
|
+
this.useDescFormat = this.prefDescFormat;
|
|
48
|
+
this.descOn = true;
|
|
49
|
+
}
|
|
50
|
+
else if (this.hasOpenDesc) {
|
|
51
|
+
this.useDescFormat = 'video';
|
|
52
|
+
this.descOn = true;
|
|
53
|
+
}
|
|
54
|
+
else if (this.hasClosedDesc) {
|
|
55
|
+
this.useDescFormat = 'text';
|
|
56
|
+
this.descOn = true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else { // description button is off
|
|
60
|
+
if (this.refreshingDesc) { // user just now toggled it off
|
|
61
|
+
this.prevDescFormat = this.useDescFormat;
|
|
62
|
+
this.useDescFormat = false;
|
|
63
|
+
this.descOn = false;
|
|
64
|
+
}
|
|
65
|
+
else { // desc has always been off
|
|
66
|
+
this.useDescFormat = false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
70
|
+
if (this.useDescFormat === 'text') {
|
|
71
|
+
// check whether browser supports the Web Speech API
|
|
72
|
+
if (window.speechSynthesis) {
|
|
73
|
+
// It does!
|
|
74
|
+
this.synth = window.speechSynthesis;
|
|
75
|
+
this.descVoices = this.synth.getVoices();
|
|
76
|
+
// select the first voice that matches the track language
|
|
77
|
+
// available languages are identified with local suffixes (e.g., en-US)
|
|
78
|
+
// in case no matching voices are found, use the first voice in the voices array
|
|
79
|
+
this.descVoiceIndex = 0;
|
|
80
|
+
for (var i=0; i<this.descVoices.length; i++) {
|
|
81
|
+
if (this.captionLang.length === 2) {
|
|
82
|
+
// match only the first 2 characters of the lang code
|
|
83
|
+
if (this.descVoices[i].lang.substr(0,2).toLowerCase() === this.captionLang.toLowerCase()) {
|
|
84
|
+
this.descVoiceIndex = i;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// match the entire lang code
|
|
90
|
+
if (this.descVoices[i].lang.toLowerCase() === this.captionLang.toLowerCase()) {
|
|
91
|
+
this.descVoiceIndex = i;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (this.descOn) {
|
|
92
99
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
if (this.useDescFormat === 'video') {
|
|
101
|
+
if (!this.usingAudioDescription()) {
|
|
102
|
+
// switched from non-described to described version
|
|
103
|
+
this.swapDescription();
|
|
104
|
+
}
|
|
105
|
+
// hide description div
|
|
106
|
+
this.$descDiv.hide();
|
|
107
|
+
this.$descDiv.removeClass('able-clipped');
|
|
108
|
+
}
|
|
109
|
+
else if (this.useDescFormat === 'text') {
|
|
110
|
+
this.$descDiv.show();
|
|
111
|
+
if (this.prefVisibleDesc) { // make it visible to everyone
|
|
112
|
+
this.$descDiv.removeClass('able-clipped');
|
|
113
|
+
}
|
|
114
|
+
else { // keep it visible to screen readers, but hide from everyone else
|
|
115
|
+
this.$descDiv.addClass('able-clipped');
|
|
116
|
+
}
|
|
117
|
+
if (!this.swappingSrc) {
|
|
118
|
+
this.showDescription(this.elapsed);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else { // description is off.
|
|
106
123
|
|
|
107
|
-
|
|
108
|
-
|
|
124
|
+
if (this.prevDescFormat === 'video') { // user was previously using description via video
|
|
125
|
+
if (this.usingAudioDescription()) {
|
|
126
|
+
this.swapDescription();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else if (this.prevDescFormat === 'text') { // user was previously using text description
|
|
130
|
+
// hide description div from everyone, including screen reader users
|
|
131
|
+
this.$descDiv.hide();
|
|
132
|
+
this.$descDiv.removeClass('able-clipped');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
this.refreshingDesc = false;
|
|
136
|
+
};
|
|
109
137
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
return (this.$sources.first().attr('data-desc-src') === this.$sources.first().attr('src'));
|
|
115
|
-
}
|
|
116
|
-
};
|
|
138
|
+
// Returns true if currently using audio description, false otherwise.
|
|
139
|
+
AblePlayer.prototype.usingAudioDescription = function () {
|
|
117
140
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
141
|
+
if (this.player === 'youtube') {
|
|
142
|
+
return (this.activeYouTubeId === this.youTubeDescId);
|
|
143
|
+
}
|
|
144
|
+
else if (this.player === 'vimeo') {
|
|
145
|
+
return (this.activeVimeoId === this.vimeoDescId);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
return (this.$sources.first().attr('data-desc-src') === this.$sources.first().attr('src'));
|
|
149
|
+
}
|
|
150
|
+
};
|
|
124
151
|
|
|
125
|
-
|
|
152
|
+
AblePlayer.prototype.swapDescription = function() {
|
|
126
153
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
this.swapTime = this.getElapsed(); // video will scrub to this time after loaded (see event.js)
|
|
154
|
+
// swap described and non-described source media, depending on which is playing
|
|
155
|
+
// this function is only called in two circumstances:
|
|
156
|
+
// 1. Swapping to described version when initializing player (based on user prefs & availability)
|
|
157
|
+
// 2. User is toggling description
|
|
158
|
+
var thisObj, i, origSrc, descSrc, srcType, newSource;
|
|
133
159
|
|
|
134
|
-
|
|
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
|
-
}
|
|
160
|
+
thisObj = this;
|
|
142
161
|
|
|
143
|
-
|
|
162
|
+
// get current time, and start new video at the same time
|
|
163
|
+
// NOTE: There is some risk in resuming playback at the same start time
|
|
164
|
+
// since the described version might include extended audio description (with pauses)
|
|
165
|
+
// and might therefore be longer than the non-described version
|
|
166
|
+
// The benefits though would seem to outweigh this risk
|
|
144
167
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
}
|
|
168
|
+
this.swapTime = this.elapsed; // video will scrub to this time after loaded (see event.js)
|
|
169
|
+
if (this.descOn) {
|
|
170
|
+
// user has requested the described version
|
|
171
|
+
this.showAlert(this.tt.alertDescribedVersion);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// user has requested the non-described version
|
|
175
|
+
this.showAlert(this.tt.alertNonDescribedVersion);
|
|
176
|
+
}
|
|
177
|
+
if (this.player === 'html5') {
|
|
181
178
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
179
|
+
if (this.usingAudioDescription()) {
|
|
180
|
+
// the described version is currently playing. Swap to non-described
|
|
181
|
+
for (i=0; i < this.$sources.length; i++) {
|
|
182
|
+
// for all <source> elements, replace src with data-orig-src
|
|
183
|
+
origSrc = this.$sources[i].getAttribute('data-orig-src');
|
|
184
|
+
srcType = this.$sources[i].getAttribute('type');
|
|
185
|
+
if (origSrc) {
|
|
186
|
+
this.$sources[i].setAttribute('src',origSrc);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// No need to check for this.initializing
|
|
190
|
+
// This function is only called during initialization
|
|
191
|
+
// if swapping from non-described to described
|
|
192
|
+
this.swappingSrc = true;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
// the non-described version is currently playing. Swap to described.
|
|
196
|
+
for (i=0; i < this.$sources.length; i++) {
|
|
197
|
+
// for all <source> elements, replace src with data-desc-src (if one exists)
|
|
198
|
+
// then store original source in a new data-orig-src attribute
|
|
199
|
+
origSrc = this.$sources[i].getAttribute('src');
|
|
200
|
+
descSrc = this.$sources[i].getAttribute('data-desc-src');
|
|
201
|
+
srcType = this.$sources[i].getAttribute('type');
|
|
202
|
+
if (descSrc) {
|
|
203
|
+
this.$sources[i].setAttribute('src',descSrc);
|
|
204
|
+
this.$sources[i].setAttribute('data-orig-src',origSrc);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
this.swappingSrc = true;
|
|
208
|
+
}
|
|
195
209
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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') {
|
|
210
|
+
// now reload the source file.
|
|
211
|
+
if (this.player === 'html5') {
|
|
212
|
+
this.media.load();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else if (this.player === 'youtube') {
|
|
207
216
|
|
|
208
|
-
|
|
209
|
-
|
|
217
|
+
if (this.usingAudioDescription()) {
|
|
218
|
+
// the described version is currently playing. Swap to non-described
|
|
219
|
+
this.activeYouTubeId = this.youTubeId;
|
|
220
|
+
this.showAlert(this.tt.alertNonDescribedVersion);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
// the non-described version is currently playing. Swap to described.
|
|
224
|
+
this.activeYouTubeId = this.youTubeDescId;
|
|
225
|
+
this.showAlert(this.tt.alertDescribedVersion);
|
|
226
|
+
}
|
|
227
|
+
if (typeof this.youTubePlayer !== 'undefined') {
|
|
210
228
|
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
};
|
|
229
|
+
// retrieve/setup captions for the new video from YouTube
|
|
230
|
+
this.setupAltCaptions().then(function() {
|
|
223
231
|
|
|
224
|
-
|
|
232
|
+
if (thisObj.playing) {
|
|
233
|
+
// loadVideoById() loads and immediately plays the new video at swapTime
|
|
234
|
+
thisObj.youTubePlayer.loadVideoById(thisObj.activeYouTubeId,thisObj.swapTime);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
// cueVideoById() loads the new video and seeks to swapTime, but does not play
|
|
238
|
+
thisObj.youTubePlayer.cueVideoById(thisObj.activeYouTubeId,thisObj.swapTime);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else if (this.player === 'vimeo') {
|
|
244
|
+
if (this.usingAudioDescription()) {
|
|
245
|
+
// the described version is currently playing. Swap to non-described
|
|
246
|
+
this.activeVimeoId = this.vimeoId;
|
|
247
|
+
this.showAlert(this.tt.alertNonDescribedVersion);
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
// the non-described version is currently playing. Swap to described.
|
|
251
|
+
this.activeVimeoId = this.vimeoDescId;
|
|
252
|
+
this.showAlert(this.tt.alertDescribedVersion);
|
|
253
|
+
}
|
|
254
|
+
// load the new video source
|
|
255
|
+
this.vimeoPlayer.loadVideo(this.activeVimeoId).then(function() {
|
|
225
256
|
|
|
226
|
-
|
|
227
|
-
|
|
257
|
+
if (thisObj.playing) {
|
|
258
|
+
// video was playing when user requested an alternative version
|
|
259
|
+
// seek to swapTime and continue playback (playback happens automatically)
|
|
260
|
+
thisObj.vimeoPlayer.setCurrentTime(thisObj.swapTime);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
// Vimeo autostarts immediately after video loads
|
|
264
|
+
// The "Described" button should not trigger playback, so stop this before the user notices.
|
|
265
|
+
thisObj.vimeoPlayer.pause();
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
};
|
|
228
270
|
|
|
229
|
-
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
271
|
+
AblePlayer.prototype.showDescription = function(now) {
|
|
232
272
|
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
};
|
|
273
|
+
// there's a lot of redundancy between this function and showCaptions
|
|
274
|
+
// Trying to combine them ended up in a mess though. Keeping as is for now.
|
|
246
275
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
276
|
+
if (this.swappingSrc) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
var thisObj, i, cues, d, thisDescription, descText, msg;
|
|
281
|
+
thisObj = this;
|
|
282
|
+
|
|
283
|
+
var flattenComponentForDescription = function (component) {
|
|
284
|
+
var result = [];
|
|
285
|
+
if (component.type === 'string') {
|
|
286
|
+
result.push(component.value);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
for (var i = 0; i < component.children.length; i++) {
|
|
290
|
+
result.push(flattenComponentForDescription(component.children[i]));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return result.join('');
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
if (this.selectedDescriptions) {
|
|
297
|
+
cues = this.selectedDescriptions.cues;
|
|
298
|
+
}
|
|
299
|
+
else if (this.descriptions.length >= 1) {
|
|
300
|
+
cues = this.descriptions[0].cues;
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
cues = [];
|
|
304
|
+
}
|
|
305
|
+
for (d = 0; d < cues.length; d++) {
|
|
306
|
+
if ((cues[d].start <= now) && (cues[d].end > now)) {
|
|
307
|
+
thisDescription = d;
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (typeof thisDescription !== 'undefined') {
|
|
312
|
+
if (this.currentDescription !== thisDescription) {
|
|
313
|
+
// temporarily remove aria-live from $status in order to prevent description from being interrupted
|
|
314
|
+
this.$status.removeAttr('aria-live');
|
|
315
|
+
descText = flattenComponentForDescription(cues[thisDescription].components);
|
|
316
|
+
if (typeof this.synth !== 'undefined' && typeof this.descVoiceIndex !== 'undefined') {
|
|
317
|
+
// browser supports speech synthesis and a voice has been selected in initDescription()
|
|
318
|
+
// use the web speech API
|
|
319
|
+
msg = new SpeechSynthesisUtterance();
|
|
320
|
+
msg.voice = this.descVoices[this.descVoiceIndex]; // Note: some voices don't support altering params
|
|
321
|
+
msg.voiceURI = 'native';
|
|
322
|
+
msg.volume = 1; // 0 to 1
|
|
323
|
+
msg.rate = 1.5; // 0.1 to 10 (1 is normal human speech; 2 is fast but easily decipherable; anything above 2 is blazing fast)
|
|
324
|
+
msg.pitch = 1; //0 to 2
|
|
325
|
+
msg.text = descText;
|
|
326
|
+
msg.lang = this.captionLang;
|
|
327
|
+
msg.onend = function(e) {
|
|
328
|
+
// NOTE: e.elapsedTime might be useful
|
|
329
|
+
if (thisObj.pausedForDescription) {
|
|
330
|
+
thisObj.playMedia();
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
this.synth.speak(msg);
|
|
334
|
+
if (this.prefVisibleDesc) {
|
|
335
|
+
// write description to the screen for sighted users
|
|
336
|
+
// but remove ARIA attributes since it isn't intended to be read by screen readers
|
|
337
|
+
this.$descDiv.html(descText).removeAttr('aria-live aria-atomic');
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
// browser does not support speech synthesis
|
|
342
|
+
// load the new description into the container div for screen readers to read
|
|
343
|
+
this.$descDiv.html(descText);
|
|
344
|
+
}
|
|
345
|
+
if (this.prefDescPause) {
|
|
346
|
+
this.pauseMedia();
|
|
347
|
+
this.pausedForDescription = true;
|
|
348
|
+
}
|
|
349
|
+
this.currentDescription = thisDescription;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
this.$descDiv.html('');
|
|
354
|
+
this.currentDescription = -1;
|
|
355
|
+
// restore aria-live to $status
|
|
356
|
+
this.$status.attr('aria-live','polite');
|
|
357
|
+
}
|
|
358
|
+
};
|
|
282
359
|
|
|
283
360
|
})(jQuery);
|