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,471 @@
|
|
|
1
|
+
(function ($) {
|
|
2
|
+
AblePlayer.prototype.initYouTubePlayer = function () {
|
|
3
|
+
|
|
4
|
+
var thisObj, deferred, promise, youTubeId, googleApiPromise, json;
|
|
5
|
+
thisObj = this;
|
|
6
|
+
|
|
7
|
+
deferred = new $.Deferred();
|
|
8
|
+
promise = deferred.promise();
|
|
9
|
+
|
|
10
|
+
// if a described version is available && user prefers desription
|
|
11
|
+
// init player using the described version
|
|
12
|
+
if (this.youTubeDescId && this.prefDesc) {
|
|
13
|
+
youTubeId = this.youTubeDescId;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
youTubeId = this.youTubeId;
|
|
17
|
+
}
|
|
18
|
+
this.activeYouTubeId = youTubeId;
|
|
19
|
+
if (AblePlayer.youtubeIframeAPIReady) {
|
|
20
|
+
// Script already loaded and ready.
|
|
21
|
+
this.finalizeYoutubeInit().then(function() {
|
|
22
|
+
deferred.resolve();
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
// Has another player already started loading the script? If so, abort...
|
|
27
|
+
if (!AblePlayer.loadingYoutubeIframeAPI) {
|
|
28
|
+
$.getScript('https://www.youtube.com/iframe_api').fail(function () {
|
|
29
|
+
deferred.fail();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Otherwise, keeping waiting for script load event...
|
|
34
|
+
$('body').on('youtubeIframeAPIReady', function () {
|
|
35
|
+
thisObj.finalizeYoutubeInit().then(function() {
|
|
36
|
+
deferred.resolve();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return promise;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
AblePlayer.prototype.finalizeYoutubeInit = function () {
|
|
44
|
+
|
|
45
|
+
// This is called once we're sure the Youtube iFrame API is loaded -- see above
|
|
46
|
+
var deferred, promise, thisObj, containerId, ccLoadPolicy, videoDimensions;
|
|
47
|
+
|
|
48
|
+
deferred = new $.Deferred();
|
|
49
|
+
promise = deferred.promise();
|
|
50
|
+
|
|
51
|
+
thisObj = this;
|
|
52
|
+
|
|
53
|
+
containerId = this.mediaId + '_youtube';
|
|
54
|
+
|
|
55
|
+
this.$mediaContainer.prepend($('<div>').attr('id', containerId));
|
|
56
|
+
// NOTE: Tried the following in place of the above in January 2016
|
|
57
|
+
// because in some cases two videos were being added to the DOM
|
|
58
|
+
// However, once v2.2.23 was fairly stable, unable to reptroduce that problem
|
|
59
|
+
// so maybe it's not an issue. This is preserved here temporarily, just in case it's needed...
|
|
60
|
+
// thisObj.$mediaContainer.html($('<div>').attr('id', containerId));
|
|
61
|
+
|
|
62
|
+
this.youTubeCaptionsReady = false;
|
|
63
|
+
|
|
64
|
+
// if captions are provided locally via <track> elements, use those
|
|
65
|
+
// and unload the captions provided by YouTube
|
|
66
|
+
// Advantages of using <track>:
|
|
67
|
+
// 1. Interactive transcript and searching within video is possible
|
|
68
|
+
// 2. User has greater control over captions' display
|
|
69
|
+
if (thisObj.captions.length) {
|
|
70
|
+
// initialize YouTube player with cc_load_policy = 0
|
|
71
|
+
// this doesn't disable captions;
|
|
72
|
+
// it just doesn't show them automatically (depends on user's preference on YouTube)
|
|
73
|
+
ccLoadPolicy = 0;
|
|
74
|
+
this.usingYouTubeCaptions = false;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// set ccLoadPolicy to 1 only if captions are on;
|
|
78
|
+
// this forces them on, regardless of user's preference on YouTube
|
|
79
|
+
if (this.captionsOn) {
|
|
80
|
+
ccLoadPolicy = 1;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
ccLoadPolicy = 0;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
videoDimensions = this.getYouTubeDimensions(this.activeYouTubeId, containerId);
|
|
87
|
+
if (videoDimensions) {
|
|
88
|
+
this.ytWidth = videoDimensions[0];
|
|
89
|
+
this.ytHeight = videoDimensions[1];
|
|
90
|
+
this.aspectRatio = thisObj.ytWidth / thisObj.ytHeight;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// dimensions are initially unknown
|
|
94
|
+
// sending null values to YouTube results in a video that uses the default YouTube dimensions
|
|
95
|
+
// these can then be scraped from the iframe and applied to this.$ableWrapper
|
|
96
|
+
this.ytWidth = null;
|
|
97
|
+
this.ytHeight = null;
|
|
98
|
+
}
|
|
99
|
+
this.youTubePlayer = new YT.Player(containerId, {
|
|
100
|
+
videoId: this.activeYouTubeId,
|
|
101
|
+
width: this.ytWidth,
|
|
102
|
+
height: this.ytHeight,
|
|
103
|
+
playerVars: {
|
|
104
|
+
enablejsapi: 1,
|
|
105
|
+
start: this.startTime,
|
|
106
|
+
controls: 0, // no controls, using our own
|
|
107
|
+
cc_load_policy: ccLoadPolicy,
|
|
108
|
+
hl: this.lang, // use the default language UI
|
|
109
|
+
modestbranding: 1, // no YouTube logo in controller
|
|
110
|
+
rel: 0, // do not show related videos when video ends
|
|
111
|
+
html5: 1 // force html5 if browser supports it (undocumented parameter; 0 does NOT force Flash)
|
|
112
|
+
},
|
|
113
|
+
events: {
|
|
114
|
+
onReady: function () {
|
|
115
|
+
if (thisObj.swappingSrc) {
|
|
116
|
+
// swap is now complete
|
|
117
|
+
thisObj.swappingSrc = false;
|
|
118
|
+
if (thisObj.playing) {
|
|
119
|
+
// resume playing
|
|
120
|
+
thisObj.playMedia();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (typeof thisObj.aspectRatio === 'undefined') {
|
|
124
|
+
console.log('resizeYouTubePlayer at POS Y1');
|
|
125
|
+
thisObj.resizeYouTubePlayer(thisObj.activeYouTubeId, containerId);
|
|
126
|
+
}
|
|
127
|
+
deferred.resolve();
|
|
128
|
+
},
|
|
129
|
+
onError: function (x) {
|
|
130
|
+
deferred.fail();
|
|
131
|
+
},
|
|
132
|
+
onStateChange: function (x) {
|
|
133
|
+
var playerState = thisObj.getPlayerState(x.data);
|
|
134
|
+
if (playerState === 'playing') {
|
|
135
|
+
thisObj.playing = true;
|
|
136
|
+
thisObj.startedPlaying = true;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
thisObj.playing = false;
|
|
140
|
+
}
|
|
141
|
+
if (thisObj.stoppingYouTube && playerState === 'paused') {
|
|
142
|
+
if (typeof thisObj.$posterImg !== 'undefined') {
|
|
143
|
+
thisObj.$posterImg.show();
|
|
144
|
+
}
|
|
145
|
+
thisObj.stoppingYouTube = false;
|
|
146
|
+
thisObj.seeking = false;
|
|
147
|
+
thisObj.playing = false;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
onPlaybackQualityChange: function () {
|
|
151
|
+
// do something
|
|
152
|
+
},
|
|
153
|
+
onApiChange: function (x) {
|
|
154
|
+
// As of Able Player v2.2.23, we are now getting caption data via the YouTube Data API
|
|
155
|
+
// prior to calling initYouTubePlayer()
|
|
156
|
+
// Previously we got caption data via the YouTube iFrame API, and doing so was an awful mess.
|
|
157
|
+
// onApiChange fires to indicate that the player has loaded (or unloaded) a module with exposed API methods
|
|
158
|
+
// it isn't fired until the video starts playing
|
|
159
|
+
// if captions are available for this video (automated captions don't count)
|
|
160
|
+
// the 'captions' (or 'cc') module is loaded. If no captions are available, this event never fires
|
|
161
|
+
// So, to trigger this event we had to play the video briefly, then pause, then reset.
|
|
162
|
+
// During that brief moment of playback, the onApiChange event was fired and we could setup captions
|
|
163
|
+
// The 'captions' and 'cc' modules are very different, and have different data and methods
|
|
164
|
+
// NOW, in v2.2.23, we still need to initialize the caption modules in order to control captions
|
|
165
|
+
// but we don't have to do that on load in order to get caption data
|
|
166
|
+
// Instead, we can wait until the video starts playing normally, then retrieve the modules
|
|
167
|
+
thisObj.initYouTubeCaptionModule();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
thisObj.injectPoster(thisObj.$mediaContainer, 'youtube');
|
|
172
|
+
thisObj.$media.remove();
|
|
173
|
+
return promise;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
AblePlayer.prototype.getYouTubeDimensions = function (youTubeId, youTubeContainerId) {
|
|
177
|
+
|
|
178
|
+
// get dimensions of YouTube video, return array with width & height
|
|
179
|
+
// Sources, in order of priority:
|
|
180
|
+
// 1. The width and height attributes on <video>
|
|
181
|
+
// 2. YouTube (not yet supported; can't seem to get this data via YouTube Data API without OAuth!)
|
|
182
|
+
|
|
183
|
+
var d, url, $iframe, width, height;
|
|
184
|
+
|
|
185
|
+
d = [];
|
|
186
|
+
|
|
187
|
+
if (typeof this.playerMaxWidth !== 'undefined') {
|
|
188
|
+
d[0] = this.playerMaxWidth;
|
|
189
|
+
// optional: set height as well; not required though since YouTube will adjust height to match width
|
|
190
|
+
if (typeof this.playerMaxHeight !== 'undefined') {
|
|
191
|
+
d[1] = this.playerMaxHeight;
|
|
192
|
+
}
|
|
193
|
+
return d;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
if (typeof $('#' + youTubeContainerId) !== 'undefined') {
|
|
197
|
+
$iframe = $('#' + youTubeContainerId);
|
|
198
|
+
width = $iframe.width();
|
|
199
|
+
height = $iframe.height();
|
|
200
|
+
if (width > 0 && height > 0) {
|
|
201
|
+
d[0] = width;
|
|
202
|
+
d[1] = height;
|
|
203
|
+
return d;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return false;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
AblePlayer.prototype.resizeYouTubePlayer = function(youTubeId, youTubeContainerId) {
|
|
211
|
+
// called after player is ready, if youTube dimensions were previously unknown
|
|
212
|
+
// Now need to get them from the iframe element that YouTube injected
|
|
213
|
+
// and resize Able Player to match
|
|
214
|
+
var d, width, height;
|
|
215
|
+
|
|
216
|
+
if (typeof this.aspectRatio !== 'undefined') {
|
|
217
|
+
// video dimensions have already been collected
|
|
218
|
+
if (this.restoringAfterFullScreen) {
|
|
219
|
+
// restore using saved values
|
|
220
|
+
if (this.youTubePlayer) {
|
|
221
|
+
this.youTubePlayer.setSize(this.ytWidth, this.ytHeight);
|
|
222
|
+
}
|
|
223
|
+
this.restoringAfterFullScreen = false;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
// recalculate with new wrapper size
|
|
227
|
+
width = this.$ableWrapper.parent().width();
|
|
228
|
+
height = Math.round(width / this.aspectRatio);
|
|
229
|
+
this.$ableWrapper.css({
|
|
230
|
+
'max-width': width + 'px',
|
|
231
|
+
'width': ''
|
|
232
|
+
});
|
|
233
|
+
this.youTubePlayer.setSize(width, height);
|
|
234
|
+
if (this.isFullscreen()) {
|
|
235
|
+
this.youTubePlayer.setSize(width, height);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
// resizing due to a change in window size, not full screen
|
|
239
|
+
this.youTubePlayer.setSize(this.ytWidth, this.ytHeight);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
d = this.getYouTubeDimensions(youTubeId, youTubeContainerId);
|
|
245
|
+
if (d) {
|
|
246
|
+
width = d[0];
|
|
247
|
+
height = d[1];
|
|
248
|
+
if (width > 0 && height > 0) {
|
|
249
|
+
this.aspectRatio = width / height;
|
|
250
|
+
this.ytWidth = width;
|
|
251
|
+
this.ytHeight = height;
|
|
252
|
+
if (width !== this.$ableWrapper.width()) {
|
|
253
|
+
// now that we've retrieved YouTube's default width,
|
|
254
|
+
// need to adjust to fit the current player wrapper
|
|
255
|
+
width = this.$ableWrapper.width();
|
|
256
|
+
height = Math.round(width / this.aspectRatio);
|
|
257
|
+
if (this.youTubePlayer) {
|
|
258
|
+
this.youTubePlayer.setSize(width, height);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
AblePlayer.prototype.setupYouTubeCaptions = function () {
|
|
267
|
+
|
|
268
|
+
// called from setupAltCaptions if player is YouTube and there are no <track> captions
|
|
269
|
+
|
|
270
|
+
// use YouTube Data API to get caption data from YouTube
|
|
271
|
+
// function is called only if these conditions are met:
|
|
272
|
+
// 1. this.player === 'youtube'
|
|
273
|
+
// 2. there are no <track> elements with kind="captions"
|
|
274
|
+
// 3. youTubeDataApiKey is defined
|
|
275
|
+
|
|
276
|
+
var deferred = new $.Deferred();
|
|
277
|
+
var promise = deferred.promise();
|
|
278
|
+
|
|
279
|
+
var thisObj, googleApiPromise, youTubeId, i;
|
|
280
|
+
|
|
281
|
+
thisObj = this;
|
|
282
|
+
|
|
283
|
+
// this.ytCaptions has the same structure as this.captions
|
|
284
|
+
// but unfortunately does not contain cues
|
|
285
|
+
// Google *does* offer a captions.download service for downloading captions in WebVTT
|
|
286
|
+
// https://developers.google.com/youtube/v3/docs/captions/download
|
|
287
|
+
// However, this requires OAUTH 2.0 (user must login and give consent)
|
|
288
|
+
// So, for now the best we can do is create an array of available caption/subtitle tracks
|
|
289
|
+
// and provide a button & popup menu to allow users to control them
|
|
290
|
+
this.ytCaptions = [];
|
|
291
|
+
|
|
292
|
+
// if a described version is available && user prefers desription
|
|
293
|
+
// Use the described version, and get its captions
|
|
294
|
+
if (this.youTubeDescId && this.prefDesc) {
|
|
295
|
+
youTubeId = this.youTubeDescId;
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
youTubeId = this.youTubeId;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Wait until Google Client API is loaded
|
|
302
|
+
// When loaded, it sets global var googleApiReady to true
|
|
303
|
+
|
|
304
|
+
// Thanks to Paul Tavares for $.doWhen()
|
|
305
|
+
// https://gist.github.com/purtuga/8257269
|
|
306
|
+
$.doWhen({
|
|
307
|
+
when: function(){
|
|
308
|
+
return googleApiReady;
|
|
309
|
+
},
|
|
310
|
+
interval: 100, // ms
|
|
311
|
+
attempts: 1000
|
|
312
|
+
})
|
|
313
|
+
.done(function(){
|
|
314
|
+
thisObj.getYouTubeCaptionData(youTubeId).done(function() {
|
|
315
|
+
deferred.resolve();
|
|
316
|
+
});
|
|
317
|
+
})
|
|
318
|
+
.fail(function(){
|
|
319
|
+
console.log('Unable to initialize Google API. YouTube captions are currently unavailable.');
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
return promise;
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
AblePlayer.prototype.getYouTubeCaptionData = function (youTubeId) {
|
|
326
|
+
// get data via YouTube Data API, and push data to this.ytCaptions
|
|
327
|
+
var deferred = new $.Deferred();
|
|
328
|
+
var promise = deferred.promise();
|
|
329
|
+
|
|
330
|
+
var thisObj, i, trackId, trackLang, trackLabel, trackKind, isDraft, isDefaultTrack;
|
|
331
|
+
|
|
332
|
+
thisObj = this;
|
|
333
|
+
|
|
334
|
+
gapi.client.setApiKey(youTubeDataAPIKey);
|
|
335
|
+
gapi.client
|
|
336
|
+
.load('youtube', 'v3')
|
|
337
|
+
.then(function() {
|
|
338
|
+
var request = gapi.client.youtube.captions.list({
|
|
339
|
+
'part': 'id, snippet',
|
|
340
|
+
'videoId': youTubeId
|
|
341
|
+
});
|
|
342
|
+
request.then(function(json) {
|
|
343
|
+
if (json.result.items.length) { // video has captions!
|
|
344
|
+
thisObj.hasCaptions = true;
|
|
345
|
+
thisObj.usingYouTubeCaptions = true;
|
|
346
|
+
if (thisObj.prefCaptions === 1) {
|
|
347
|
+
thisObj.captionsOn = true;
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
thisObj.captionsOn = false;
|
|
351
|
+
}
|
|
352
|
+
// Step through results and add them to cues array
|
|
353
|
+
for (i=0; i < json.result.items.length; i++) {
|
|
354
|
+
|
|
355
|
+
trackId = json.result.items[i].id;
|
|
356
|
+
trackLabel = json.result.items[i].snippet.name; // always seems to be empty
|
|
357
|
+
trackLang = json.result.items[i].snippet.language;
|
|
358
|
+
trackKind = json.result.items[i].snippet.trackKind; // ASR, standard, forced
|
|
359
|
+
isDraft = json.result.items[i].snippet.isDraft; // Boolean
|
|
360
|
+
// Other variables that could potentially be collected from snippet:
|
|
361
|
+
// isCC - Boolean, always seems to be false
|
|
362
|
+
// isLarge - Boolean
|
|
363
|
+
// isEasyReader - Boolean
|
|
364
|
+
// isAutoSynced Boolean
|
|
365
|
+
// status - string, always seems to be "serving"
|
|
366
|
+
|
|
367
|
+
if (trackKind !== 'ASR' && !isDraft) {
|
|
368
|
+
|
|
369
|
+
// if track name is empty (it always seems to be), assign a name based on trackLang
|
|
370
|
+
if (trackLabel === '') {
|
|
371
|
+
trackLabel = thisObj.getLanguageName(trackLang);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// assign the default track based on language of the player
|
|
375
|
+
if (trackLang === thisObj.lang) {
|
|
376
|
+
isDefaultTrack = true;
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
isDefaultTrack = false;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
thisObj.ytCaptions.push({
|
|
383
|
+
'language': trackLang,
|
|
384
|
+
'label': trackLabel,
|
|
385
|
+
'def': isDefaultTrack
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// setupPopups again with new ytCaptions array, replacing original
|
|
390
|
+
thisObj.setupPopups('captions');
|
|
391
|
+
deferred.resolve();
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
thisObj.hasCaptions = false;
|
|
395
|
+
thisObj.usingYouTubeCaptions = false;
|
|
396
|
+
deferred.resolve();
|
|
397
|
+
}
|
|
398
|
+
}, function (reason) {
|
|
399
|
+
console.log('Error: ' + reason.result.error.message);
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
return promise;
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
AblePlayer.prototype.initYouTubeCaptionModule = function () {
|
|
406
|
+
// This function is called when YouTube onApiChange event fires
|
|
407
|
+
// to indicate that the player has loaded (or unloaded) a module with exposed API methods
|
|
408
|
+
// it isn't fired until the video starts playing
|
|
409
|
+
// and only fires if captions are available for this video (automated captions don't count)
|
|
410
|
+
// If no captions are available, onApichange event never fires & this function is never called
|
|
411
|
+
|
|
412
|
+
// YouTube iFrame API documentation is incomplete related to captions
|
|
413
|
+
// Found undocumented features on user forums and by playing around
|
|
414
|
+
// Details are here: http://terrillthompson.com/blog/648
|
|
415
|
+
// Summary:
|
|
416
|
+
// User might get either the AS3 (Flash) or HTML5 YouTube player
|
|
417
|
+
// The API uses a different caption module for each player (AS3 = 'cc'; HTML5 = 'captions')
|
|
418
|
+
// There are differences in the data and methods available through these modules
|
|
419
|
+
// This function therefore is used to determine which captions module is being used
|
|
420
|
+
// If it's a known module, this.ytCaptionModule will be used elsewhere to control captions
|
|
421
|
+
var options, fontSize, displaySettings;
|
|
422
|
+
|
|
423
|
+
options = this.youTubePlayer.getOptions();
|
|
424
|
+
if (options.length) {
|
|
425
|
+
for (var i=0; i<options.length; i++) {
|
|
426
|
+
if (options[i] == 'cc') { // this is the AS3 (Flash) player
|
|
427
|
+
this.ytCaptionModule = 'cc';
|
|
428
|
+
if (!this.hasCaptions) {
|
|
429
|
+
// there are captions available via other sources (e.g., <track>)
|
|
430
|
+
// so use these
|
|
431
|
+
this.hasCaptions = true;
|
|
432
|
+
this.usingYouTubeCaptions = true;
|
|
433
|
+
}
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
else if (options[i] == 'captions') { // this is the HTML5 player
|
|
437
|
+
this.ytCaptionModule = 'captions';
|
|
438
|
+
if (!this.hasCaptions) {
|
|
439
|
+
// there are captions available via other sources (e.g., <track>)
|
|
440
|
+
// so use these
|
|
441
|
+
this.hasCaptions = true;
|
|
442
|
+
this.usingYouTubeCaptions = true;
|
|
443
|
+
}
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (typeof this.ytCaptionModule !== 'undefined') {
|
|
448
|
+
if (this.usingYouTubeCaptions) {
|
|
449
|
+
// set default languaage
|
|
450
|
+
this.youTubePlayer.setOption(this.ytCaptionModule, 'track', {'languageCode': this.captionLang});
|
|
451
|
+
// set font size using Able Player prefs (values are -1, 0, 1, 2, and 3, where 0 is default)
|
|
452
|
+
this.youTubePlayer.setOption(this.ytCaptionModule,'fontSize',this.translatePrefs('size',this.prefCaptionsSize,'youtube'));
|
|
453
|
+
// ideally could set other display options too, but no others seem to be supported by setOption()
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
// now that we know which cc module was loaded, unload it!
|
|
457
|
+
// we don't want it if we're using local <track> elements for captions
|
|
458
|
+
this.youTubePlayer.unloadModule(this.ytCaptionModule)
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
// no modules were loaded onApiChange
|
|
464
|
+
// unfortunately, gonna have to disable captions if we can't control them
|
|
465
|
+
this.hasCaptions = false;
|
|
466
|
+
this.usingYouTubeCaptions = false;
|
|
467
|
+
}
|
|
468
|
+
this.refreshControls();
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
})(jQuery);
|