wai-website-theme 1.3.1 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/_includes/different.html +2 -1
  3. data/_includes/external.html +2 -1
  4. data/_includes/header.html +2 -1
  5. data/_includes/menuitem.html +6 -2
  6. data/_includes/peoplelist.html +21 -0
  7. data/_includes/prevnext-navigation.html +56 -0
  8. data/_includes/{prevnext.html → prevnext-order.html} +9 -0
  9. data/_includes/translation-note-msg.html +5 -3
  10. data/_includes/video-player.html +2 -2
  11. data/_layouts/default.html +8 -1
  12. data/_layouts/news.html +7 -1
  13. data/_layouts/policy.html +7 -1
  14. data/_layouts/sidenav.html +8 -1
  15. data/_layouts/sidenavsidebar.html +8 -1
  16. data/assets/ableplayer/Gruntfile.js +2 -1
  17. data/assets/ableplayer/README.md +158 -85
  18. data/assets/ableplayer/build/ableplayer.dist.js +15445 -13823
  19. data/assets/ableplayer/build/ableplayer.js +15445 -13823
  20. data/assets/ableplayer/build/ableplayer.min.css +1 -2
  21. data/assets/ableplayer/build/ableplayer.min.js +3 -10
  22. data/assets/ableplayer/package-lock.json +944 -346
  23. data/assets/ableplayer/package.json +8 -8
  24. data/assets/ableplayer/scripts/ableplayer-base.js +515 -524
  25. data/assets/ableplayer/scripts/browser.js +158 -158
  26. data/assets/ableplayer/scripts/buildplayer.js +1750 -1682
  27. data/assets/ableplayer/scripts/caption.js +424 -401
  28. data/assets/ableplayer/scripts/chapters.js +259 -259
  29. data/assets/ableplayer/scripts/control.js +1831 -1594
  30. data/assets/ableplayer/scripts/description.js +333 -256
  31. data/assets/ableplayer/scripts/dialog.js +145 -145
  32. data/assets/ableplayer/scripts/dragdrop.js +746 -749
  33. data/assets/ableplayer/scripts/event.js +875 -696
  34. data/assets/ableplayer/scripts/initialize.js +819 -912
  35. data/assets/ableplayer/scripts/langs.js +979 -743
  36. data/assets/ableplayer/scripts/metadata.js +124 -124
  37. data/assets/ableplayer/scripts/misc.js +170 -137
  38. data/assets/ableplayer/scripts/preference.js +904 -904
  39. data/assets/ableplayer/scripts/search.js +172 -172
  40. data/assets/ableplayer/scripts/sign.js +82 -78
  41. data/assets/ableplayer/scripts/slider.js +449 -448
  42. data/assets/ableplayer/scripts/track.js +409 -309
  43. data/assets/ableplayer/scripts/transcript.js +684 -595
  44. data/assets/ableplayer/scripts/translation.js +63 -67
  45. data/assets/ableplayer/scripts/ttml2webvtt.js +85 -85
  46. data/assets/ableplayer/scripts/vimeo.js +448 -0
  47. data/assets/ableplayer/scripts/volume.js +395 -380
  48. data/assets/ableplayer/scripts/vts.js +1077 -1077
  49. data/assets/ableplayer/scripts/webvtt.js +766 -763
  50. data/assets/ableplayer/scripts/youtube.js +695 -478
  51. data/assets/ableplayer/styles/ableplayer.css +54 -46
  52. data/assets/ableplayer/translations/nl.js +54 -54
  53. data/assets/ableplayer/translations/pt-br.js +311 -0
  54. data/assets/ableplayer/translations/tr.js +311 -0
  55. data/assets/ableplayer/translations/zh-tw.js +1 -1
  56. data/assets/css/style.css +1 -1
  57. data/assets/css/style.css.map +1 -1
  58. data/assets/images/icons.svg +5 -5
  59. data/assets/scripts/main.js +7 -0
  60. data/assets/search/tipuesearch.js +3 -3
  61. metadata +8 -3
@@ -1,75 +1,71 @@
1
1
  (function ($) {
2
- AblePlayer.prototype.getSupportedLangs = function() {
3
- // returns an array of languages for which AblePlayer has translation tables
4
- // Removing 'nl' as of 2.3.54, pending updates
5
- var langs = ['ca','de','en','es','fr','he','it','ja','nb','zh-tw'];
6
- return langs;
7
- };
2
+ AblePlayer.prototype.getSupportedLangs = function() {
3
+ // returns an array of languages for which AblePlayer has translation tables
4
+ var langs = ['ca','de','en','es','fr','he','it','ja','nb','nl','pt-br','tr','zh-tw'];
5
+ return langs;
6
+ };
8
7
 
9
- AblePlayer.prototype.getTranslationText = function() {
10
- // determine language, then get labels and prompts from corresponding translation var
11
- var deferred, thisObj, lang, thisObj, msg, translationFile;
12
- deferred = $.Deferred();
8
+ AblePlayer.prototype.getTranslationText = function() {
9
+ // determine language, then get labels and prompts from corresponding translation var
10
+ var deferred, thisObj, lang, thisObj, msg, translationFile, collapsedLang;
11
+ deferred = $.Deferred();
13
12
 
14
- thisObj = this;
13
+ thisObj = this;
14
+ // get language of the web page, if specified
15
+ if ($('body').attr('lang')) {
16
+ lang = $('body').attr('lang');
17
+ }
18
+ else if ($('html').attr('lang')) {
19
+ lang = $('html').attr('lang');
20
+ }
21
+ else {
22
+ lang = null;
23
+ }
15
24
 
16
- // get language of the web page, if specified
17
- if ($('body').attr('lang')) {
18
- lang = $('body').attr('lang');
19
- }
20
- else if ($('html').attr('lang')) {
21
- lang = $('html').attr('lang');
22
- }
23
- else {
24
- lang = null;
25
- }
25
+ // override this.lang to language of the web page, if known and supported
26
+ // otherwise this.lang will continue using default
27
+ if (!this.forceLang) {
28
+ if (lang) {
29
+ if (lang !== this.lang) {
30
+ if ($.inArray(lang,this.getSupportedLangs()) !== -1) {
31
+ // this is a supported lang
32
+ this.lang = lang;
33
+ }
34
+ else {
35
+ msg = lang + ' is not currently supported. Using default language (' + this.lang + ')';
36
+ if (this.debug) {
37
+ console.log(msg);
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ if (!this.searchLang) {
44
+ this.searchLang = this.lang;
45
+ }
46
+ translationFile = this.rootPath + 'translations/' + this.lang + '.js';
47
+ this.importTranslationFile(translationFile).then(function(result) {
48
+ collapsedLang = thisObj.lang.replace('-','');
49
+ thisObj.tt = eval(collapsedLang);
50
+ deferred.resolve();
51
+ });
52
+ return deferred.promise();
53
+ };
26
54
 
27
- // override this.lang to language of the web page, if known and supported
28
- // otherwise this.lang will continue using default
29
- if (!this.forceLang) {
30
- if (lang) {
31
- if (lang !== this.lang) {
32
- msg = 'Language of web page (' + lang +') ';
33
- if ($.inArray(lang,this.getSupportedLangs()) !== -1) {
34
- // this is a supported lang
35
- msg += ' has a translation table available.';
36
- this.lang = lang;
37
- }
38
- else {
39
- msg += ' is not currently supported. Using default language (' + this.lang + ')';
40
- }
41
- if (this.debug) {
42
- console.log(msg);
43
- }
44
- }
45
- }
46
- }
47
- if (!this.searchLang) {
48
- this.searchLang = this.lang;
49
- }
50
- translationFile = this.rootPath + 'translations/' + this.lang + '.js';
51
- this.importTranslationFile(translationFile).then(function(result) {
52
- thisObj.tt = eval(thisObj.lang);
53
- deferred.resolve();
54
- });
55
- return deferred.promise();
56
- };
55
+ AblePlayer.prototype.importTranslationFile = function(translationFile) {
57
56
 
58
- AblePlayer.prototype.importTranslationFile = function(translationFile) {
59
-
60
- var deferred = $.Deferred();
61
-
62
- $.getScript(translationFile)
63
- .done(function(translationVar,textStatus) {
64
- // translation file successfully retrieved
65
- deferred.resolve(translationVar);
66
- })
67
- .fail(function(jqxhr, settings, exception) {
68
- deferred.fail();
69
- // error retrieving file
70
- // TODO: handle this
71
- });
72
- return deferred.promise();
73
- };
57
+ var deferred = $.Deferred();
58
+ $.getScript(translationFile)
59
+ .done(function(translationVar,textStatus) {
60
+ // translation file successfully retrieved
61
+ deferred.resolve(translationVar);
62
+ })
63
+ .fail(function(jqxhr, settings, exception) {
64
+ deferred.fail();
65
+ // error retrieving file
66
+ // TODO: handle this
67
+ });
68
+ return deferred.promise();
69
+ };
74
70
 
75
71
  })(jQuery);
@@ -1,87 +1,87 @@
1
1
  (function($) {
2
- AblePlayer.prototype.computeEndTime = function(startTime, durationTime) {
3
- var SECONDS = 0;
4
- var MINUTES = 1;
5
- var HOURS = 2;
6
-
7
- var startParts = startTime
8
- .split(':')
9
- .reverse()
10
- .map(function(value) {
11
- return parseFloat(value);
12
- });
13
-
14
- var durationParts = durationTime
15
- .split(':')
16
- .reverse()
17
- .map(function(value) {
18
- return parseFloat(value);
19
- });
20
-
21
- var endTime = startParts
22
- .reduce(function(acc, val, index) {
23
- var sum = val + durationParts[index];
24
-
25
- if (index === SECONDS) {
26
- if (sum > 60) {
27
- durationParts[index + 1] += 1;
28
- sum -= 60;
29
- }
30
-
31
- sum = sum.toFixed(3);
32
- }
33
-
34
- if (index === MINUTES) {
35
- if (sum > 60) {
36
- durationParts[index + 1] += 1;
37
- sum -= 60;
38
- }
39
- }
40
-
41
- if (sum < 10) {
42
- sum = '0' + sum;
43
- }
44
-
45
- acc.push(sum);
46
-
47
- return acc;
48
- }, [])
49
- .reverse()
50
- .join(':');
51
-
52
- return endTime;
53
- };
54
-
55
- AblePlayer.prototype.ttml2webvtt = function(contents) {
56
- var thisObj = this;
57
-
58
- var xml = thisObj.convert.xml2json(contents, {
59
- ignoreComment: true,
60
- alwaysChildren: true,
61
- compact: true,
62
- spaces: 2
63
- });
64
-
65
- var vttHeader = 'WEBVTT\n\n\n';
66
- var captions = JSON.parse(xml).tt.body.div.p;
67
-
68
- var vttCaptions = captions.reduce(function(acc, value, index) {
69
- var text = value._text;
70
- var isArray = Array.isArray(text);
71
- var attributes = value._attributes;
72
- var endTime = thisObj.computeEndTime(attributes.begin, attributes.dur);
73
-
74
- var caption =
75
- thisObj.computeEndTime(attributes.begin, '00:00:0') +
76
- ' --> ' +
77
- thisObj.computeEndTime(attributes.begin, attributes.dur) +
78
- '\n' +
79
- (isArray ? text.join('\n') : text) +
80
- '\n\n';
81
-
82
- return acc + caption;
83
- }, vttHeader);
84
-
85
- return vttCaptions;
86
- };
2
+ AblePlayer.prototype.computeEndTime = function(startTime, durationTime) {
3
+ var SECONDS = 0;
4
+ var MINUTES = 1;
5
+ var HOURS = 2;
6
+
7
+ var startParts = startTime
8
+ .split(':')
9
+ .reverse()
10
+ .map(function(value) {
11
+ return parseFloat(value);
12
+ });
13
+
14
+ var durationParts = durationTime
15
+ .split(':')
16
+ .reverse()
17
+ .map(function(value) {
18
+ return parseFloat(value);
19
+ });
20
+
21
+ var endTime = startParts
22
+ .reduce(function(acc, val, index) {
23
+ var sum = val + durationParts[index];
24
+
25
+ if (index === SECONDS) {
26
+ if (sum > 60) {
27
+ durationParts[index + 1] += 1;
28
+ sum -= 60;
29
+ }
30
+
31
+ sum = sum.toFixed(3);
32
+ }
33
+
34
+ if (index === MINUTES) {
35
+ if (sum > 60) {
36
+ durationParts[index + 1] += 1;
37
+ sum -= 60;
38
+ }
39
+ }
40
+
41
+ if (sum < 10) {
42
+ sum = '0' + sum;
43
+ }
44
+
45
+ acc.push(sum);
46
+
47
+ return acc;
48
+ }, [])
49
+ .reverse()
50
+ .join(':');
51
+
52
+ return endTime;
53
+ };
54
+
55
+ AblePlayer.prototype.ttml2webvtt = function(contents) {
56
+ var thisObj = this;
57
+
58
+ var xml = thisObj.convert.xml2json(contents, {
59
+ ignoreComment: true,
60
+ alwaysChildren: true,
61
+ compact: true,
62
+ spaces: 2
63
+ });
64
+
65
+ var vttHeader = 'WEBVTT\n\n\n';
66
+ var captions = JSON.parse(xml).tt.body.div.p;
67
+
68
+ var vttCaptions = captions.reduce(function(acc, value, index) {
69
+ var text = value._text;
70
+ var isArray = Array.isArray(text);
71
+ var attributes = value._attributes;
72
+ var endTime = thisObj.computeEndTime(attributes.begin, attributes.dur);
73
+
74
+ var caption =
75
+ thisObj.computeEndTime(attributes.begin, '00:00:0') +
76
+ ' --> ' +
77
+ thisObj.computeEndTime(attributes.begin, attributes.dur) +
78
+ '\n' +
79
+ (isArray ? text.join('\n') : text) +
80
+ '\n\n';
81
+
82
+ return acc + caption;
83
+ }, vttHeader);
84
+
85
+ return vttCaptions;
86
+ };
87
87
  })(jQuery);
@@ -0,0 +1,448 @@
1
+
2
+ (function ($) {
3
+ AblePlayer.prototype.initVimeoPlayer = function () {
4
+
5
+ var thisObj, deferred, promise, containerId, vimeoId, autoplay, videoDimensions, options;
6
+ thisObj = this;
7
+
8
+ deferred = new $.Deferred();
9
+ promise = deferred.promise();
10
+
11
+ deferred.resolve();
12
+
13
+ containerId = this.mediaId + '_vimeo';
14
+
15
+ // add container to which Vimeo player iframe will be appended
16
+ this.$mediaContainer.prepend($('<div>').attr('id', containerId));
17
+
18
+ // if a described version is available && user prefers desription
19
+ // init player using the described version
20
+ if (this.vimeoDescId && this.prefDesc) {
21
+ vimeoId = this.vimeoDescId;
22
+ }
23
+ else {
24
+ vimeoId = this.vimeoId;
25
+ }
26
+ this.activeVimeoId = vimeoId;
27
+
28
+ // Notes re. Vimeo Embed Options:
29
+ // If a video is owned by a user with a paid Plus, PRO, or Business account,
30
+ // setting the "background" option to "true" will hide the default controls.
31
+ // It has no effect on videos owned by a free basic account owner (their controls cannot be hidden).
32
+ // Also, setting "background" to "true" has a couple of side effects:
33
+ // In addition to hiding the controls, it also autoplays and loops the video.
34
+ // If the player is initialized with options to set both "autoplay" and "loop" to "false",
35
+ // this does not override the "background" setting.
36
+ // Passing this.autoplay and this.loop anyway, just in case it works someday
37
+ // Meanwhile, workaround is to setup an event listener to immediately pause after video autoplays
38
+
39
+ if (this.autoplay && this.okToPlay) {
40
+ autoplay = 'true';
41
+ }
42
+ else {
43
+ autoplay = 'false';
44
+ }
45
+
46
+ videoDimensions = this.getVimeoDimensions(this.activeVimeoId, containerId);
47
+ if (videoDimensions) {
48
+ this.vimeoWidth = videoDimensions[0];
49
+ this.vimeoHeight = videoDimensions[1];
50
+ this.aspectRatio = thisObj.ytWidth / thisObj.ytHeight;
51
+ }
52
+ else {
53
+ // dimensions are initially unknown
54
+ // sending null values to Vimeo results in a video that uses the default Vimeo dimensions
55
+ // these can then be scraped from the iframe and applied to this.$ableWrapper
56
+ this.vimeoWidth = null;
57
+ this.vimeoHeight = null;
58
+ }
59
+ options = {
60
+ id: vimeoId,
61
+ width: this.vimeoWidth,
62
+ background: true,
63
+ autoplay: this.autoplay,
64
+ loop: this.loop
65
+ };
66
+
67
+ this.vimeoPlayer = new Vimeo.Player(containerId, options);
68
+
69
+ this.vimeoPlayer.ready().then(function() {
70
+
71
+ if (!thisObj.hasPlaylist) {
72
+ // remove the media element, since Vimeo replaces that with its own element in an iframe
73
+ // this is handled differently for playlists. See buildplayer.js > cuePlaylistItem()
74
+ thisObj.$media.remove();
75
+
76
+ // define variables that will impact player setup
77
+
78
+ // vimeoSupportsPlaybackRateChange
79
+ // changing playbackRate is only supported if the video is hosted on a Pro or Business account
80
+ // unfortunately there is no direct way to query for that information.
81
+ // this.vimeoPlayer.getPlaybackRate() returns a value, regardless of account type
82
+ // This is a hack:
83
+ // Attempt to change the playbackRate. If it results in an error, assume changing playbackRate is not supported.
84
+ // Supported playbackRate values are 0.5 to 2.
85
+ thisObj.vimeoPlaybackRate = 1;
86
+ thisObj.vimeoPlayer.setPlaybackRate(thisObj.vimeoPlaybackRate).then(function(playbackRate) {
87
+ // playback rate was set
88
+ thisObj.vimeoSupportsPlaybackRateChange = true;
89
+ }).catch(function(error) {
90
+ thisObj.vimeoSupportsPlaybackRateChange = false;
91
+ });
92
+ deferred.resolve();
93
+ }
94
+ });
95
+ return promise;
96
+ };
97
+
98
+ AblePlayer.prototype.getVimeoPaused = function () {
99
+
100
+ var deferred, promise;
101
+ deferred = new $.Deferred();
102
+ promise = deferred.promise();
103
+
104
+ this.vimeoPlayer.getPaused().then(function (paused) {
105
+ // paused is Boolean
106
+ deferred.resolve(paused);
107
+ });
108
+
109
+ return promise;
110
+ }
111
+
112
+ AblePlayer.prototype.getVimeoEnded = function () {
113
+
114
+ var deferred, promise;
115
+ deferred = new $.Deferred();
116
+ promise = deferred.promise();
117
+
118
+ this.vimeoPlayer.getEnded().then(function (ended) {
119
+ // ended is Boolean
120
+ deferred.resolve(ended);
121
+ });
122
+
123
+ return promise;
124
+ }
125
+
126
+ AblePlayer.prototype.getVimeoState = function () {
127
+
128
+ var thisObj, deferred, promise, promises, gettingPausedPromise, gettingEndedPromise;
129
+
130
+ thisObj = this;
131
+
132
+ deferred = new $.Deferred();
133
+ promise = deferred.promise();
134
+ promises = [];
135
+
136
+ gettingPausedPromise = this.vimeoPlayer.getPaused();
137
+ gettingEndedPromise = this.vimeoPlayer.getEnded();
138
+
139
+ promises.push(gettingPausedPromise);
140
+ promises.push(gettingEndedPromise);
141
+
142
+ gettingPausedPromise.then(function (paused) {
143
+ deferred.resolve(paused);
144
+ });
145
+ gettingEndedPromise.then(function (ended) {
146
+ deferred.resolve(ended);
147
+ });
148
+ $.when.apply($, promises).then(function () {
149
+ deferred.resolve();
150
+ });
151
+ return promise;
152
+ }
153
+
154
+ AblePlayer.prototype.getVimeoDimensions = function (vimeoContainerId) {
155
+
156
+ // get dimensions of YouTube video, return array with width & height
157
+ // Sources, in order of priority:
158
+ // 1. The width and height attributes on <video>
159
+ // 2. YouTube (not yet supported; can't seem to get this data via YouTube Data API without OAuth!)
160
+
161
+ var d, url, $iframe, width, height;
162
+
163
+ d = [];
164
+
165
+ if (typeof this.playerMaxWidth !== 'undefined') {
166
+ d[0] = this.playerMaxWidth;
167
+ // optional: set height as well; not required though since YouTube will adjust height to match width
168
+ if (typeof this.playerMaxHeight !== 'undefined') {
169
+ d[1] = this.playerMaxHeight;
170
+ }
171
+ return d;
172
+ }
173
+ else {
174
+ if (typeof $('#' + vimeoContainerId) !== 'undefined') {
175
+ $iframe = $('#' + vimeoContainerId);
176
+ width = $iframe.width();
177
+ height = $iframe.height();
178
+ if (width > 0 && height > 0) {
179
+ d[0] = width;
180
+ d[1] = height;
181
+ return d;
182
+ }
183
+ }
184
+ }
185
+ return false;
186
+ };
187
+
188
+ AblePlayer.prototype.resizeVimeoPlayer = function(youTubeId, youTubeContainerId) {
189
+
190
+ // called after player is ready, if youTube dimensions were previously unknown
191
+ // Now need to get them from the iframe element that YouTube injected
192
+ // and resize Able Player to match
193
+ var d, width, height;
194
+ if (typeof this.aspectRatio !== 'undefined') {
195
+ // video dimensions have already been collected
196
+ if (this.restoringAfterFullScreen) {
197
+ // restore using saved values
198
+ if (this.youTubePlayer) {
199
+ this.youTubePlayer.setSize(this.ytWidth, this.ytHeight);
200
+ }
201
+ this.restoringAfterFullScreen = false;
202
+ }
203
+ else {
204
+ // recalculate with new wrapper size
205
+ width = this.$ableWrapper.parent().width();
206
+ height = Math.round(width / this.aspectRatio);
207
+ this.$ableWrapper.css({
208
+ 'max-width': width + 'px',
209
+ 'width': ''
210
+ });
211
+ this.youTubePlayer.setSize(width, height);
212
+ if (this.fullscreen) {
213
+ this.youTubePlayer.setSize(width, height);
214
+ }
215
+ else {
216
+ // resizing due to a change in window size, not full screen
217
+ this.youTubePlayer.setSize(this.ytWidth, this.ytHeight);
218
+ }
219
+ }
220
+ }
221
+ else {
222
+ d = this.getYouTubeDimensions(youTubeId, youTubeContainerId);
223
+ if (d) {
224
+ width = d[0];
225
+ height = d[1];
226
+ if (width > 0 && height > 0) {
227
+ this.aspectRatio = width / height;
228
+ this.ytWidth = width;
229
+ this.ytHeight = height;
230
+ if (width !== this.$ableWrapper.width()) {
231
+ // now that we've retrieved YouTube's default width,
232
+ // need to adjust to fit the current player wrapper
233
+ width = this.$ableWrapper.width();
234
+ height = Math.round(width / this.aspectRatio);
235
+ if (this.youTubePlayer) {
236
+ this.youTubePlayer.setSize(width, height);
237
+ }
238
+ }
239
+ }
240
+ }
241
+ }
242
+ };
243
+
244
+ AblePlayer.prototype.setupVimeoCaptions = function () {
245
+
246
+ // called from setupAltCaptions if player is YouTube and there are no <track> captions
247
+
248
+ // use YouTube Data API to get caption data from YouTube
249
+ // function is called only if these conditions are met:
250
+ // 1. this.player === 'youtube'
251
+ // 2. there are no <track> elements with kind="captions"
252
+ // 3. youTubeDataApiKey is defined
253
+
254
+ var deferred = new $.Deferred();
255
+ var promise = deferred.promise();
256
+
257
+ var thisObj, googleApiPromise, youTubeId, i;
258
+
259
+ thisObj = this;
260
+
261
+ // if a described version is available && user prefers desription
262
+ // Use the described version, and get its captions
263
+ if (this.youTubeDescId && this.prefDesc) {
264
+ youTubeId = this.youTubeDescId;
265
+ }
266
+ else {
267
+ youTubeId = this.youTubeId;
268
+ }
269
+ if (typeof youTubeDataAPIKey !== 'undefined') {
270
+ // Wait until Google Client API is loaded
271
+ // When loaded, it sets global var googleApiReady to true
272
+
273
+ // Thanks to Paul Tavares for $.doWhen()
274
+ // https://gist.github.com/purtuga/8257269
275
+ $.doWhen({
276
+ when: function(){
277
+ return googleApiReady;
278
+ },
279
+ interval: 100, // ms
280
+ attempts: 1000
281
+ })
282
+ .done(function(){
283
+ deferred.resolve();
284
+ })
285
+ .fail(function(){
286
+ console.log('Unable to initialize Google API. YouTube captions are currently unavailable.');
287
+ });
288
+ }
289
+ else {
290
+ deferred.resolve();
291
+ }
292
+ return promise;
293
+ };
294
+
295
+ AblePlayer.prototype.getVimeoCaptionTracks = function () {
296
+
297
+ // get data via Vimeo Player API, and push data to this.captions
298
+ // Note: Vimeo doesn't expose the caption cues themselves
299
+ // so this.captions will only include metadata about caption tracks; not cues
300
+ var deferred = new $.Deferred();
301
+ var promise = deferred.promise();
302
+
303
+ var thisObj, i, trackId, isDefaultTrack;
304
+
305
+ thisObj = this;
306
+
307
+ this.vimeoPlayer.getTextTracks().then(function(tracks) {
308
+
309
+ // each Vimeo track includes the following:
310
+ // label (local name of the language)
311
+ // language (2-character code)
312
+ // kind (captions or subtitles, as declared by video owner)
313
+ // mode ('disabled' or 'showing')
314
+
315
+ if (tracks.length) {
316
+
317
+ // create a new button for each caption track
318
+ for (i=0; i<tracks.length; i++) {
319
+
320
+ thisObj.hasCaptions = true;
321
+ thisObj.usingVimeoCaptions = true;
322
+ if (thisObj.prefCaptions === 1) {
323
+ thisObj.captionsOn = true;
324
+ }
325
+ else {
326
+ thisObj.captionsOn = false;
327
+ }
328
+ // assign the default track based on language of the player
329
+ if (tracks[i]['language'] === thisObj.lang) {
330
+ isDefaultTrack = true;
331
+ }
332
+ else {
333
+ isDefaultTrack = false;
334
+ }
335
+ thisObj.tracks.push({
336
+ 'kind': tracks[i]['kind'],
337
+ 'language': tracks[i]['language'],
338
+ 'label': tracks[i]['label'],
339
+ 'def': isDefaultTrack
340
+ });
341
+ }
342
+
343
+ // setupPopups again with new captions array, replacing original
344
+ thisObj.setupPopups('captions');
345
+ deferred.resolve();
346
+ }
347
+ else {
348
+ thisObj.hasCaptions = false;
349
+ thisObj.usingVimeoCaptions = false;
350
+ deferred.resolve();
351
+ }
352
+ });
353
+
354
+ return promise;
355
+ };
356
+
357
+ AblePlayer.prototype.initVimeoCaptionModule = function () {
358
+ // This function is called when YouTube onApiChange event fires
359
+ // to indicate that the player has loaded (or unloaded) a module with exposed API methods
360
+ // it isn't fired until the video starts playing
361
+ // and only fires if captions are available for this video (automated captions don't count)
362
+ // If no captions are available, onApichange event never fires & this function is never called
363
+
364
+ // YouTube iFrame API documentation is incomplete related to captions
365
+ // Found undocumented features on user forums and by playing around
366
+ // Details are here: http://terrillthompson.com/blog/648
367
+ // Summary:
368
+ // User might get either the AS3 (Flash) or HTML5 YouTube player
369
+ // The API uses a different caption module for each player (AS3 = 'cc'; HTML5 = 'captions')
370
+ // There are differences in the data and methods available through these modules
371
+ // This function therefore is used to determine which captions module is being used
372
+ // If it's a known module, this.ytCaptionModule will be used elsewhere to control captions
373
+ var options, fontSize, displaySettings;
374
+
375
+ options = this.youTubePlayer.getOptions();
376
+ if (options.length) {
377
+ for (var i=0; i<options.length; i++) {
378
+ if (options[i] == 'cc') { // this is the AS3 (Flash) player
379
+ this.ytCaptionModule = 'cc';
380
+ if (!this.hasCaptions) {
381
+ // there are captions available via other sources (e.g., <track>)
382
+ // so use these
383
+ this.hasCaptions = true;
384
+ this.usingYouTubeCaptions = true;
385
+ }
386
+ break;
387
+ }
388
+ else if (options[i] == 'captions') { // this is the HTML5 player
389
+ this.ytCaptionModule = 'captions';
390
+ if (!this.hasCaptions) {
391
+ // there are captions available via other sources (e.g., <track>)
392
+ // so use these
393
+ this.hasCaptions = true;
394
+ this.usingYouTubeCaptions = true;
395
+ }
396
+ break;
397
+ }
398
+ }
399
+ if (typeof this.ytCaptionModule !== 'undefined') {
400
+ if (this.usingYouTubeCaptions) {
401
+ // set default languaage
402
+ this.youTubePlayer.setOption(this.ytCaptionModule, 'track', {'languageCode': this.captionLang});
403
+ // set font size using Able Player prefs (values are -1, 0, 1, 2, and 3, where 0 is default)
404
+ this.youTubePlayer.setOption(this.ytCaptionModule,'fontSize',this.translatePrefs('size',this.prefCaptionsSize,'youtube'));
405
+ // ideally could set other display options too, but no others seem to be supported by setOption()
406
+ }
407
+ else {
408
+ // now that we know which cc module was loaded, unload it!
409
+ // we don't want it if we're using local <track> elements for captions
410
+ this.youTubePlayer.unloadModule(this.ytCaptionModule)
411
+ }
412
+ }
413
+ }
414
+ else {
415
+ // no modules were loaded onApiChange
416
+ // unfortunately, gonna have to disable captions if we can't control them
417
+ this.hasCaptions = false;
418
+ this.usingYouTubeCaptions = false;
419
+ }
420
+ this.refreshControls('captions');
421
+ };
422
+
423
+ AblePlayer.prototype.getVimeoPosterUrl = function (youTubeId, width) {
424
+
425
+ // return a URL for retrieving a YouTube poster image
426
+ // supported values of width: 120, 320, 480, 640
427
+
428
+ var url = 'https://img.youtube.com/vi/' + youTubeId;
429
+ if (width == '120') {
430
+ // default (small) thumbnail, 120 x 90
431
+ return url + '/default.jpg';
432
+ }
433
+ else if (width == '320') {
434
+ // medium quality thumbnail, 320 x 180
435
+ return url + '/hqdefault.jpg';
436
+ }
437
+ else if (width == '480') {
438
+ // high quality thumbnail, 480 x 360
439
+ return url + '/hqdefault.jpg';
440
+ }
441
+ else if (width == '640') {
442
+ // standard definition poster image, 640 x 480
443
+ return url + '/sddefault.jpg';
444
+ }
445
+ return false;
446
+ };
447
+
448
+ })(jQuery);