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,75 +1,71 @@
|
|
|
1
1
|
(function ($) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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);
|