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.
Files changed (173) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +52 -0
  4. data/_data/lang.json +730 -0
  5. data/_data/techniques.yml +180 -0
  6. data/_data/wcag.yml +125 -0
  7. data/_includes/.DS_Store +0 -0
  8. data/_includes/body-class.html +1 -0
  9. data/_includes/box.html +10 -0
  10. data/_includes/excol.html +13 -0
  11. data/_includes/footer.html +40 -0
  12. data/_includes/head.html +23 -0
  13. data/_includes/header.html +59 -0
  14. data/_includes/icon.html +6 -0
  15. data/_includes/img.html +17 -0
  16. data/_includes/multilang-list-policy-links.html +29 -0
  17. data/_includes/multilang-list.html +35 -0
  18. data/_includes/multilang-policy-title.html +5 -0
  19. data/_includes/multilang-title-full.html +1 -0
  20. data/_includes/multilang-title.html +1 -0
  21. data/_includes/navlist.html +22 -0
  22. data/_includes/notes.html +2 -0
  23. data/_includes/prevnext.html +34 -0
  24. data/_includes/resources.html +19 -0
  25. data/_includes/sidenav.html +65 -0
  26. data/_includes/sidenote.html +14 -0
  27. data/_includes/toc.html +10 -0
  28. data/_includes/video-player.html +99 -0
  29. data/_layouts/default.html +26 -0
  30. data/_layouts/home.html +14 -0
  31. data/_layouts/news.html +21 -0
  32. data/_layouts/none.html +1 -0
  33. data/_layouts/policy.html +72 -0
  34. data/_layouts/sidenav.html +27 -0
  35. data/_layouts/sidenavsidebar.html +22 -0
  36. data/assets/ableplayer/.gitattributes +14 -0
  37. data/assets/ableplayer/.gitignore +7 -0
  38. data/assets/ableplayer/Gruntfile.js +105 -0
  39. data/assets/ableplayer/LICENSE +26 -0
  40. data/assets/ableplayer/README.md +656 -0
  41. data/assets/ableplayer/build/ableplayer.dist.js +12157 -0
  42. data/assets/ableplayer/build/ableplayer.js +12157 -0
  43. data/assets/ableplayer/build/ableplayer.min.css +2 -0
  44. data/assets/ableplayer/build/ableplayer.min.js +8 -0
  45. data/assets/ableplayer/button-icons/able-icons.svg +116 -0
  46. data/assets/ableplayer/button-icons/black/captions.png +0 -0
  47. data/assets/ableplayer/button-icons/black/chapters.png +0 -0
  48. data/assets/ableplayer/button-icons/black/close.png +0 -0
  49. data/assets/ableplayer/button-icons/black/descriptions.png +0 -0
  50. data/assets/ableplayer/button-icons/black/ellipsis.png +0 -0
  51. data/assets/ableplayer/button-icons/black/faster.png +0 -0
  52. data/assets/ableplayer/button-icons/black/forward.png +0 -0
  53. data/assets/ableplayer/button-icons/black/fullscreen-collapse.png +0 -0
  54. data/assets/ableplayer/button-icons/black/fullscreen-expand.png +0 -0
  55. data/assets/ableplayer/button-icons/black/help.png +0 -0
  56. data/assets/ableplayer/button-icons/black/next.png +0 -0
  57. data/assets/ableplayer/button-icons/black/pause.png +0 -0
  58. data/assets/ableplayer/button-icons/black/pipe.png +0 -0
  59. data/assets/ableplayer/button-icons/black/play.png +0 -0
  60. data/assets/ableplayer/button-icons/black/preferences.png +0 -0
  61. data/assets/ableplayer/button-icons/black/previous.png +0 -0
  62. data/assets/ableplayer/button-icons/black/rabbit.png +0 -0
  63. data/assets/ableplayer/button-icons/black/restart.png +0 -0
  64. data/assets/ableplayer/button-icons/black/rewind.png +0 -0
  65. data/assets/ableplayer/button-icons/black/sign.png +0 -0
  66. data/assets/ableplayer/button-icons/black/slower.png +0 -0
  67. data/assets/ableplayer/button-icons/black/stop.png +0 -0
  68. data/assets/ableplayer/button-icons/black/transcript.png +0 -0
  69. data/assets/ableplayer/button-icons/black/turtle.png +0 -0
  70. data/assets/ableplayer/button-icons/black/volume-loud.png +0 -0
  71. data/assets/ableplayer/button-icons/black/volume-medium.png +0 -0
  72. data/assets/ableplayer/button-icons/black/volume-mute.png +0 -0
  73. data/assets/ableplayer/button-icons/black/volume-soft.png +0 -0
  74. data/assets/ableplayer/button-icons/fonts/able.eot +0 -0
  75. data/assets/ableplayer/button-icons/fonts/able.svg +40 -0
  76. data/assets/ableplayer/button-icons/fonts/able.ttf +0 -0
  77. data/assets/ableplayer/button-icons/fonts/able.woff +0 -0
  78. data/assets/ableplayer/button-icons/white/captions.png +0 -0
  79. data/assets/ableplayer/button-icons/white/chapters.png +0 -0
  80. data/assets/ableplayer/button-icons/white/close.png +0 -0
  81. data/assets/ableplayer/button-icons/white/descriptions.png +0 -0
  82. data/assets/ableplayer/button-icons/white/ellipsis.png +0 -0
  83. data/assets/ableplayer/button-icons/white/faster.png +0 -0
  84. data/assets/ableplayer/button-icons/white/forward.png +0 -0
  85. data/assets/ableplayer/button-icons/white/fullscreen-collapse.png +0 -0
  86. data/assets/ableplayer/button-icons/white/fullscreen-expand.png +0 -0
  87. data/assets/ableplayer/button-icons/white/help.png +0 -0
  88. data/assets/ableplayer/button-icons/white/next.png +0 -0
  89. data/assets/ableplayer/button-icons/white/pause.png +0 -0
  90. data/assets/ableplayer/button-icons/white/pipe.png +0 -0
  91. data/assets/ableplayer/button-icons/white/play.png +0 -0
  92. data/assets/ableplayer/button-icons/white/preferences.png +0 -0
  93. data/assets/ableplayer/button-icons/white/previous.png +0 -0
  94. data/assets/ableplayer/button-icons/white/rabbit.png +0 -0
  95. data/assets/ableplayer/button-icons/white/restart.png +0 -0
  96. data/assets/ableplayer/button-icons/white/rewind.png +0 -0
  97. data/assets/ableplayer/button-icons/white/sign.png +0 -0
  98. data/assets/ableplayer/button-icons/white/slower.png +0 -0
  99. data/assets/ableplayer/button-icons/white/stop.png +0 -0
  100. data/assets/ableplayer/button-icons/white/transcript.png +0 -0
  101. data/assets/ableplayer/button-icons/white/turtle.png +0 -0
  102. data/assets/ableplayer/button-icons/white/volume-loud.png +0 -0
  103. data/assets/ableplayer/button-icons/white/volume-medium.png +0 -0
  104. data/assets/ableplayer/button-icons/white/volume-mute.png +0 -0
  105. data/assets/ableplayer/button-icons/white/volume-soft.png +0 -0
  106. data/assets/ableplayer/images/wingrip.png +0 -0
  107. data/assets/ableplayer/package.json +22 -0
  108. data/assets/ableplayer/scripts/JQuery.doWhen.js +113 -0
  109. data/assets/ableplayer/scripts/ableplayer-base.js +440 -0
  110. data/assets/ableplayer/scripts/browser.js +162 -0
  111. data/assets/ableplayer/scripts/buildplayer.js +1609 -0
  112. data/assets/ableplayer/scripts/caption.js +385 -0
  113. data/assets/ableplayer/scripts/chapters.js +242 -0
  114. data/assets/ableplayer/scripts/control.js +1514 -0
  115. data/assets/ableplayer/scripts/description.js +283 -0
  116. data/assets/ableplayer/scripts/dialog.js +147 -0
  117. data/assets/ableplayer/scripts/dragdrop.js +766 -0
  118. data/assets/ableplayer/scripts/event.js +595 -0
  119. data/assets/ableplayer/scripts/initialize.js +725 -0
  120. data/assets/ableplayer/scripts/langs.js +750 -0
  121. data/assets/ableplayer/scripts/metadata.js +134 -0
  122. data/assets/ableplayer/scripts/misc.js +72 -0
  123. data/assets/ableplayer/scripts/preference.js +909 -0
  124. data/assets/ableplayer/scripts/search.js +171 -0
  125. data/assets/ableplayer/scripts/sign.js +92 -0
  126. data/assets/ableplayer/scripts/slider.js +454 -0
  127. data/assets/ableplayer/scripts/track.js +296 -0
  128. data/assets/ableplayer/scripts/transcript.js +590 -0
  129. data/assets/ableplayer/scripts/translation.js +66 -0
  130. data/assets/ableplayer/scripts/volume.js +383 -0
  131. data/assets/ableplayer/scripts/webvtt.js +765 -0
  132. data/assets/ableplayer/scripts/youtube.js +471 -0
  133. data/assets/ableplayer/styles/ableplayer.css +1241 -0
  134. data/assets/ableplayer/thirdparty/js.cookie.js +145 -0
  135. data/assets/ableplayer/thirdparty/modernizr.custom.js +4 -0
  136. data/assets/ableplayer/translations/ca.js +1 -0
  137. data/assets/ableplayer/translations/de.js +1 -0
  138. data/assets/ableplayer/translations/en.js +305 -0
  139. data/assets/ableplayer/translations/es.js +305 -0
  140. data/assets/ableplayer/translations/fr.js +305 -0
  141. data/assets/ableplayer/translations/it.js +303 -0
  142. data/assets/ableplayer/translations/ja.js +305 -0
  143. data/assets/ableplayer/translations/nl.js +305 -0
  144. data/assets/css/style.css +4360 -0
  145. data/assets/css/style.css.map +1 -0
  146. data/assets/fonts/anonymouspro-bold.woff +0 -0
  147. data/assets/fonts/anonymouspro-bold.woff2 +0 -0
  148. data/assets/fonts/anonymouspro-bolditalic.woff +0 -0
  149. data/assets/fonts/anonymouspro-bolditalic.woff2 +0 -0
  150. data/assets/fonts/anonymouspro-italic.woff +0 -0
  151. data/assets/fonts/anonymouspro-italic.woff2 +0 -0
  152. data/assets/fonts/anonymouspro-regular.woff +0 -0
  153. data/assets/fonts/anonymouspro-regular.woff2 +0 -0
  154. data/assets/fonts/notosans-bold.woff +0 -0
  155. data/assets/fonts/notosans-bold.woff2 +0 -0
  156. data/assets/fonts/notosans-bolditalic.woff +0 -0
  157. data/assets/fonts/notosans-bolditalic.woff2 +0 -0
  158. data/assets/fonts/notosans-italic.woff +0 -0
  159. data/assets/fonts/notosans-italic.woff2 +0 -0
  160. data/assets/fonts/notosans-regular.woff +0 -0
  161. data/assets/fonts/notosans-regular.woff2 +0 -0
  162. data/assets/images/.DS_Store +0 -0
  163. data/assets/images/Shape.svg +10 -0
  164. data/assets/images/icon-related-content.svg +14 -0
  165. data/assets/images/icons.svg +126 -0
  166. data/assets/images/teaser-image@1x.jpg +0 -0
  167. data/assets/images/teaser-image@2x.jpg +0 -0
  168. data/assets/images/w3c.sketch +0 -0
  169. data/assets/images/w3c.svg +10 -0
  170. data/assets/scripts/jquery.min.js +4 -0
  171. data/assets/scripts/main.js +208 -0
  172. data/assets/scripts/svg4everybody.js +1 -0
  173. 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);