wai-website-theme 1.6 → 1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/_data/lang.json +1 -0
- data/_data/navigation.yml +85 -0
- data/_data/techniques.yml +1 -0
- data/_data/translations.yml +1 -0
- data/_data/wcag.yml +1 -0
- data/_includes/blockquote.html +6 -0
- data/_includes/box.html +4 -7
- data/_includes/button.html +9 -0
- data/_includes/different.html +2 -2
- data/_includes/footer.html +1 -1
- data/_includes/header.html +5 -5
- data/_includes/image.html +14 -0
- data/_includes/input.html +2 -0
- data/_includes/link.html +1 -1
- data/_includes/menuitem.html +2 -2
- data/_includes/navlist.html +2 -1
- data/_includes/secondarynav.html +6 -6
- data/_includes/showhidebutton.html +1 -0
- data/_includes/toc.html +15 -1
- data/_includes/video-link.html +1 -1
- data/_includes/video-player.html +2 -2
- data/assets/ableplayer/build/ableplayer.dist.js +216 -204
- data/assets/ableplayer/build/ableplayer.js +187 -175
- data/assets/ableplayer/build/ableplayer.min.js +2 -2
- data/assets/css/style.css +1 -1
- data/assets/css/style.css.map +1 -1
- metadata +34 -21
- data/assets/images/video-mask-16-9.svg +0 -1
- data/assets/images/video-mask-4-3.svg +0 -1
- data/assets/images/video-still-accessibility-intro-16-9.jpg +0 -0
@@ -168,6 +168,20 @@
|
|
168
168
|
this.useDescriptionsButton = true;
|
169
169
|
}
|
170
170
|
|
171
|
+
// Silence audio description
|
172
|
+
// set to "false" if the sole purposes of the WebVTT descriptions file
|
173
|
+
// is to display description text visibly and to integrate it into the transcript
|
174
|
+
if ($(media).data('descriptions-audible') !== undefined && $(media).data('descriptions-audible') === false) {
|
175
|
+
this.exposeTextDescriptions = false;
|
176
|
+
}
|
177
|
+
else if ($(media).data('description-audible') !== undefined && $(media).data('description-audible') === false) {
|
178
|
+
// support both singular and plural spelling of attribute
|
179
|
+
this.exposeTextDescriptions = false;
|
180
|
+
}
|
181
|
+
else {
|
182
|
+
this.exposeTextDescriptions = true;
|
183
|
+
}
|
184
|
+
|
171
185
|
// Headings
|
172
186
|
// By default, an off-screen heading is automatically added to the top of the media player
|
173
187
|
// It is intelligently assigned a heading level based on context, via misc.js > getNextHeadingLevel()
|
@@ -189,6 +203,19 @@
|
|
189
203
|
// 3. "popup" - Automatically generated, written to a draggable, resizable popup window that can be toggled on/off with a button
|
190
204
|
// If data-include-transcript="false", there is no "popup" transcript
|
191
205
|
|
206
|
+
if ($(media).data('transcript-div') !== undefined && $(media).data('transcript-div') !== "") {
|
207
|
+
this.transcriptDivLocation = $(media).data('transcript-div');
|
208
|
+
}
|
209
|
+
else {
|
210
|
+
this.transcriptDivLocation = null;
|
211
|
+
}
|
212
|
+
if ($(media).data('include-transcript') !== undefined && $(media).data('include-transcript') === false) {
|
213
|
+
this.hideTranscriptButton = true;
|
214
|
+
}
|
215
|
+
else {
|
216
|
+
this.hideTranscriptButton = null;
|
217
|
+
}
|
218
|
+
|
192
219
|
this.transcriptType = null;
|
193
220
|
if ($(media).data('transcript-src') !== undefined) {
|
194
221
|
this.transcriptSrc = $(media).data('transcript-src');
|
@@ -198,15 +225,9 @@
|
|
198
225
|
}
|
199
226
|
else if ($(media).find('track[kind="captions"], track[kind="subtitles"]').length > 0) {
|
200
227
|
// required tracks are present. COULD automatically generate a transcript
|
201
|
-
|
202
|
-
this.transcriptDivLocation = $(media).data('transcript-div');
|
228
|
+
if (this.transcriptDivLocation) {
|
203
229
|
this.transcriptType = 'external';
|
204
230
|
}
|
205
|
-
else if ($(media).data('include-transcript') !== undefined) {
|
206
|
-
if ($(media).data('include-transcript') !== false) {
|
207
|
-
this.transcriptType = 'popup';
|
208
|
-
}
|
209
|
-
}
|
210
231
|
else {
|
211
232
|
this.transcriptType = 'popup';
|
212
233
|
}
|
@@ -258,18 +279,6 @@
|
|
258
279
|
this.defaultChapter = null;
|
259
280
|
}
|
260
281
|
|
261
|
-
// Previous/Next buttons
|
262
|
-
// valid values of data-prevnext-unit are 'playlist' and 'chapter'; will also accept 'chapters'
|
263
|
-
if ($(media).data('prevnext-unit') === 'chapter' || $(media).data('prevnext-unit') === 'chapters') {
|
264
|
-
this.prevNextUnit = 'chapter';
|
265
|
-
}
|
266
|
-
else if ($(media).data('prevnext-unit') === 'playlist') {
|
267
|
-
this.prevNextUnit = 'playlist';
|
268
|
-
}
|
269
|
-
else {
|
270
|
-
this.prevNextUnit = false;
|
271
|
-
}
|
272
|
-
|
273
282
|
// Slower/Faster buttons
|
274
283
|
// valid values of data-speed-icons are 'animals' (default) and 'arrows'
|
275
284
|
// 'animals' uses turtle and rabbit; 'arrows' uses up/down arrows
|
@@ -757,7 +766,7 @@
|
|
757
766
|
svg[1] = 'M7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714zM18.75 12.093v1.657h-1.657l-2.093-2.093-2.093 2.093h-1.657v-1.657l2.093-2.093-2.093-2.093v-1.657h1.657l2.093 2.093 2.093-2.093h1.657v1.657l-2.093 2.093z';
|
758
767
|
break;
|
759
768
|
|
760
|
-
case 'volume-
|
769
|
+
case 'volume-soft':
|
761
770
|
svg[0] = '0 0 20 20';
|
762
771
|
svg[1] = 'M10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
|
763
772
|
break;
|
@@ -1144,11 +1153,10 @@
|
|
1144
1153
|
thisObj.showSearchResults();
|
1145
1154
|
|
1146
1155
|
// Go ahead and load media, without user requesting it
|
1147
|
-
//
|
1148
|
-
|
1149
|
-
|
1150
|
-
if (thisObj.player === 'html5'
|
1151
|
-
(thisObj.isIOS() || thisObj.startTime > 0 || thisObj.autoplay || thisObj.okToPlay)) {
|
1156
|
+
// Ideally, we would wait until user clicks play, rather than unnecessarily consume their bandwidth
|
1157
|
+
// However, the media needs to load before the 'loadedmetadata' event is fired
|
1158
|
+
// and until that happens we can't get the media's duration
|
1159
|
+
if (thisObj.player === 'html5') {
|
1152
1160
|
thisObj.$media[0].load();
|
1153
1161
|
}
|
1154
1162
|
// refreshControls is called twice building/initializing the player
|
@@ -1571,7 +1579,7 @@
|
|
1571
1579
|
});
|
1572
1580
|
prefs.push({
|
1573
1581
|
'name': 'prefDescFormat', // audio description default state
|
1574
|
-
'label':
|
1582
|
+
'label': null,
|
1575
1583
|
'group': 'descriptions',
|
1576
1584
|
'default': 'video'
|
1577
1585
|
});
|
@@ -1630,7 +1638,7 @@
|
|
1630
1638
|
var available, thisObj, $prefsDiv, formTitle, introText,
|
1631
1639
|
$prefsIntro,$prefsIntroP2,p3Text,$prefsIntroP3,i, j,
|
1632
1640
|
$fieldset, fieldsetClass, fieldsetId,
|
1633
|
-
$
|
1641
|
+
$descFieldset, $descLegend, $legend,
|
1634
1642
|
thisPref, $thisDiv, thisClass, thisId, $thisLabel, $thisField,
|
1635
1643
|
$div1,id1,$radio1,$label1,
|
1636
1644
|
$div2,id2,$radio2,$label2,
|
@@ -1728,35 +1736,17 @@
|
|
1728
1736
|
$prefsDiv.append($prefsIntro);
|
1729
1737
|
}
|
1730
1738
|
|
1731
|
-
|
1732
|
-
|
1733
|
-
|
1734
|
-
|
1735
|
-
|
1736
|
-
|
1737
|
-
|
1738
|
-
$descFieldset1.addClass(fieldsetClass).attr('id',fieldsetId);
|
1739
|
-
$descLegend1 = $('<legend>' + this.tt.prefDescFormat + '</legend>');
|
1740
|
-
$descFieldset1.append($descLegend1);
|
1741
|
-
|
1742
|
-
// Fieldset 2
|
1743
|
-
$descFieldset2 = $('<fieldset>');
|
1744
|
-
fieldsetClass = 'able-prefs-' + form + '2';
|
1745
|
-
fieldsetId = this.mediaId + '-prefs-' + form + '2';
|
1746
|
-
$descFieldset2.addClass(fieldsetClass).attr('id',fieldsetId);
|
1747
|
-
$descLegend2 = $('<legend>' + this.tt.prefHeadingTextDescription + '</legend>');
|
1748
|
-
$descFieldset2.append($descLegend2);
|
1739
|
+
$fieldset = $('<fieldset>');
|
1740
|
+
fieldsetClass = 'able-prefs-' + form;
|
1741
|
+
fieldsetId = this.mediaId + '-prefs-' + form;
|
1742
|
+
$fieldset.addClass(fieldsetClass).attr('id',fieldsetId);
|
1743
|
+
if (form === 'keyboard') {
|
1744
|
+
$legend = $('<legend>' + this.tt.prefHeadingKeyboard1 + '</legend>');
|
1745
|
+
$fieldset.append($legend);
|
1749
1746
|
}
|
1750
|
-
else {
|
1751
|
-
|
1752
|
-
|
1753
|
-
fieldsetClass = 'able-prefs-' + form;
|
1754
|
-
fieldsetId = this.mediaId + '-prefs-' + form;
|
1755
|
-
$fieldset.addClass(fieldsetClass).attr('id',fieldsetId);
|
1756
|
-
if (form === 'keyboard') {
|
1757
|
-
$legend = $('<legend>' + this.tt.prefHeadingKeyboard1 + '</legend>');
|
1758
|
-
$fieldset.append($legend);
|
1759
|
-
}
|
1747
|
+
else if (form === 'descriptions') {
|
1748
|
+
$legend = $('<legend>' + this.tt.prefHeadingTextDescription + '</legend>');
|
1749
|
+
$fieldset.append($legend);
|
1760
1750
|
}
|
1761
1751
|
for (i=0; i<available.length; i++) {
|
1762
1752
|
|
@@ -1766,48 +1756,9 @@
|
|
1766
1756
|
thisPref = available[i]['name'];
|
1767
1757
|
thisClass = 'able-' + thisPref;
|
1768
1758
|
thisId = this.mediaId + '_' + thisPref;
|
1769
|
-
|
1770
|
-
$thisDiv = $('<div>').addClass(thisClass);
|
1771
|
-
}
|
1772
|
-
|
1773
|
-
// Audio Description preferred format radio buttons
|
1774
|
-
if (thisPref == 'prefDescFormat') {
|
1759
|
+
$thisDiv = $('<div>').addClass(thisClass);
|
1775
1760
|
|
1776
|
-
|
1777
|
-
$div1 = $('<div>');
|
1778
|
-
id1 = thisId + '_1';
|
1779
|
-
$label1 = $('<label>')
|
1780
|
-
.attr('for',id1)
|
1781
|
-
.text(this.capitalizeFirstLetter(this.tt.prefDescFormatOption1))
|
1782
|
-
$radio1 = $('<input>',{
|
1783
|
-
type: 'radio',
|
1784
|
-
name: thisPref,
|
1785
|
-
id: id1,
|
1786
|
-
value: 'video'
|
1787
|
-
});
|
1788
|
-
if (this.prefDescFormat === 'video') {
|
1789
|
-
$radio1.prop('checked',true);
|
1790
|
-
};
|
1791
|
-
$div1.append($radio1,$label1);
|
1792
|
-
|
1793
|
-
// option 2 radio button
|
1794
|
-
$div2 = $('<div>');
|
1795
|
-
id2 = thisId + '_2';
|
1796
|
-
$label2 = $('<label>')
|
1797
|
-
.attr('for',id2)
|
1798
|
-
.text(this.capitalizeFirstLetter(this.tt.prefDescFormatOption2));
|
1799
|
-
$radio2 = $('<input>',{
|
1800
|
-
type: 'radio',
|
1801
|
-
name: thisPref,
|
1802
|
-
id: id2,
|
1803
|
-
value: 'text'
|
1804
|
-
});
|
1805
|
-
if (this.prefDescFormat === 'text') {
|
1806
|
-
$radio2.prop('checked',true);
|
1807
|
-
};
|
1808
|
-
$div2.append($radio2,$label2);
|
1809
|
-
}
|
1810
|
-
else if (form === 'captions') {
|
1761
|
+
if (form === 'captions') {
|
1811
1762
|
$thisLabel = $('<label for="' + thisId + '"> ' + available[i]['label'] + '</label>');
|
1812
1763
|
$thisField = $('<select>',{
|
1813
1764
|
name: thisPref,
|
@@ -1899,25 +1850,11 @@
|
|
1899
1850
|
}
|
1900
1851
|
$thisDiv.append($thisField,$thisLabel);
|
1901
1852
|
}
|
1902
|
-
|
1903
|
-
if (thisPref === 'prefDescFormat') {
|
1904
|
-
$descFieldset1.append($div1,$div2);
|
1905
|
-
}
|
1906
|
-
else {
|
1907
|
-
$descFieldset2.append($thisDiv);
|
1908
|
-
}
|
1909
|
-
}
|
1910
|
-
else {
|
1911
|
-
$fieldset.append($thisDiv);
|
1912
|
-
}
|
1853
|
+
$fieldset.append($thisDiv);
|
1913
1854
|
}
|
1914
1855
|
}
|
1915
|
-
|
1916
|
-
|
1917
|
-
}
|
1918
|
-
else {
|
1919
|
-
$prefsDiv.append($fieldset);
|
1920
|
-
}
|
1856
|
+
$prefsDiv.append($fieldset);
|
1857
|
+
|
1921
1858
|
if (form === 'captions') {
|
1922
1859
|
// add a sample closed caption div to prefs dialog
|
1923
1860
|
if (this.mediaType === 'video') {
|
@@ -1946,6 +1883,14 @@
|
|
1946
1883
|
kbLabels.push(this.tt.restart);
|
1947
1884
|
keys.push('s');
|
1948
1885
|
}
|
1886
|
+
else if (this.controls[i] === 'previous') {
|
1887
|
+
kbLabels.push(this.tt.prevTrack);
|
1888
|
+
keys.push('b'); // b = back
|
1889
|
+
}
|
1890
|
+
else if (this.controls[i] === 'next') {
|
1891
|
+
kbLabels.push(this.tt.nextTrack);
|
1892
|
+
keys.push('n');
|
1893
|
+
}
|
1949
1894
|
else if (this.controls[i] === 'rewind') {
|
1950
1895
|
kbLabels.push(this.tt.rewind);
|
1951
1896
|
keys.push('r');
|
@@ -2096,15 +2041,7 @@
|
|
2096
2041
|
available = this.getAvailablePreferences();
|
2097
2042
|
for (i=0; i<available.length; i++) {
|
2098
2043
|
prefName = available[i]['name'];
|
2099
|
-
if (prefName
|
2100
|
-
if (this[prefName] === 'text') {
|
2101
|
-
$('input[value="text"]').prop('checked',true);
|
2102
|
-
}
|
2103
|
-
else {
|
2104
|
-
$('input[value="video"]').prop('checked',true);
|
2105
|
-
}
|
2106
|
-
}
|
2107
|
-
else if ((prefName.indexOf('Captions') !== -1) && (prefName !== 'prefCaptions')) {
|
2044
|
+
if ((prefName.indexOf('Captions') !== -1) && (prefName !== 'prefCaptions')) {
|
2108
2045
|
// this is a caption-related select box
|
2109
2046
|
$('select[name="' + prefName + '"]').val(cookie.preferences[prefName]);
|
2110
2047
|
}
|
@@ -2137,8 +2074,10 @@
|
|
2137
2074
|
if (available[i]['label']) {
|
2138
2075
|
var prefName = available[i]['name'];
|
2139
2076
|
if (prefName == 'prefDescFormat') {
|
2140
|
-
|
2141
|
-
|
2077
|
+
// As of v4.0.10, prefDescFormat is no longer a choice
|
2078
|
+
// this.prefDescFormat = $('input[name="' + prefName + '"]:checked').val();
|
2079
|
+
this.prefDescFormat = 'video';
|
2080
|
+
if (this.prefDescFormat !== cookie.preferences['prefDescFormat']) { // user's preference has changed
|
2142
2081
|
cookie.preferences['prefDescFormat'] = this.prefDescFormat;
|
2143
2082
|
numChanges++;
|
2144
2083
|
}
|
@@ -3187,10 +3126,14 @@
|
|
3187
3126
|
// create a div for exposing description
|
3188
3127
|
// description will be exposed via role="alert" & announced by screen readers
|
3189
3128
|
this.$descDiv = $('<div>',{
|
3190
|
-
'class': 'able-descriptions'
|
3191
|
-
'aria-live': 'assertive',
|
3192
|
-
'aria-atomic': 'true'
|
3129
|
+
'class': 'able-descriptions'
|
3193
3130
|
});
|
3131
|
+
if (this.exposeTextDescriptions) {
|
3132
|
+
this.$descDiv.attr({
|
3133
|
+
'aria-live': 'assertive',
|
3134
|
+
'aria-atomic': 'true'
|
3135
|
+
});
|
3136
|
+
}
|
3194
3137
|
// Start off with description hidden.
|
3195
3138
|
// It will be exposed conditionally within description.js > initDescription()
|
3196
3139
|
this.$descDiv.hide();
|
@@ -3843,6 +3786,11 @@
|
|
3843
3786
|
'br': []
|
3844
3787
|
}
|
3845
3788
|
|
3789
|
+
if (this.hasPlaylist) {
|
3790
|
+
controlLayout['ur'].push('previous');
|
3791
|
+
controlLayout['ur'].push('next');
|
3792
|
+
}
|
3793
|
+
|
3846
3794
|
// test for browser support for volume before displaying volume button
|
3847
3795
|
if (this.browserSupportsVolume()) {
|
3848
3796
|
// volume buttons are: 'mute','volume-soft','volume-medium','volume-loud'
|
@@ -3874,7 +3822,7 @@
|
|
3874
3822
|
bll.push('descriptions'); //audio description
|
3875
3823
|
}
|
3876
3824
|
}
|
3877
|
-
if (this.transcriptType === 'popup') {
|
3825
|
+
if (this.transcriptType === 'popup' && !(this.hideTranscriptButton)) {
|
3878
3826
|
bll.push('transcript');
|
3879
3827
|
}
|
3880
3828
|
|
@@ -3955,7 +3903,7 @@
|
|
3955
3903
|
$controllerSpan.append($sliderDiv);
|
3956
3904
|
if (typeof this.duration === 'undefined' || this.duration === 0) {
|
3957
3905
|
// set arbitrary starting duration, and change it when duration is known
|
3958
|
-
this.duration =
|
3906
|
+
this.duration = 60;
|
3959
3907
|
// also set elapsed to 0
|
3960
3908
|
this.elapsed = 0;
|
3961
3909
|
}
|
@@ -4720,6 +4668,12 @@
|
|
4720
4668
|
else if (control === 'restart') {
|
4721
4669
|
return this.tt.restart;
|
4722
4670
|
}
|
4671
|
+
else if (control === 'previous') {
|
4672
|
+
return this.tt.prevTrack;
|
4673
|
+
}
|
4674
|
+
else if (control === 'next') {
|
4675
|
+
return this.tt.nextTrack;
|
4676
|
+
}
|
4723
4677
|
else if (control === 'rewind') {
|
4724
4678
|
return this.tt.rewind;
|
4725
4679
|
}
|
@@ -6505,7 +6459,7 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
6505
6459
|
|
6506
6460
|
AblePlayer.prototype.refreshVolumeButton = function(volume) {
|
6507
6461
|
|
6508
|
-
var volumeName, volumePct, volumeLabel, volumeIconClass, volumeImg;
|
6462
|
+
var volumeName, volumePct, volumeLabel, volumeIconClass, volumeImg, newSvgData;
|
6509
6463
|
|
6510
6464
|
volumeName = this.getVolumeName(volume);
|
6511
6465
|
volumePct = (volume/10) * 100;
|
@@ -6516,10 +6470,18 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
6516
6470
|
this.$volumeButton.find('span').first().removeClass().addClass(volumeIconClass);
|
6517
6471
|
this.$volumeButton.find('span.able-clipped').text(volumeLabel);
|
6518
6472
|
}
|
6519
|
-
else {
|
6473
|
+
else if (this.iconType === 'image') {
|
6520
6474
|
volumeImg = this.imgPath + 'volume-' + volumeName + '.png';
|
6521
6475
|
this.$volumeButton.find('img').attr('src',volumeImg);
|
6522
6476
|
}
|
6477
|
+
else if (this.iconType === 'svg') {
|
6478
|
+
if (volumeName !== 'mute') {
|
6479
|
+
volumeName = 'volume-' + volumeName;
|
6480
|
+
}
|
6481
|
+
newSvgData = this.getSvgData(volumeName);
|
6482
|
+
this.$volumeButton.find('svg').attr('viewBox',newSvgData[0]);
|
6483
|
+
this.$volumeButton.find('path').attr('d',newSvgData[1]);
|
6484
|
+
}
|
6523
6485
|
};
|
6524
6486
|
|
6525
6487
|
AblePlayer.prototype.moveVolumeHead = function(y) {
|
@@ -6617,6 +6579,7 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
6617
6579
|
};
|
6618
6580
|
|
6619
6581
|
AblePlayer.prototype.handleMute = function() {
|
6582
|
+
|
6620
6583
|
if (this.isMuted()) {
|
6621
6584
|
this.setMute(false);
|
6622
6585
|
}
|
@@ -7095,17 +7058,20 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
7095
7058
|
|
7096
7059
|
// The following variables are applicable to delivery of description:
|
7097
7060
|
// prefDesc == 1 if user wants description (i.e., Description button is on); else 0
|
7098
|
-
// prefDescFormat == either 'video' or 'text'
|
7061
|
+
// prefDescFormat == either 'video' or 'text' (as of v4.0.10, prefDescFormat is always 'video')
|
7099
7062
|
// prefDescPause == 1 to pause video when description starts; else 0
|
7100
7063
|
// prefVisibleDesc == 1 to visibly show text-based description area; else 0
|
7101
7064
|
// hasOpenDesc == true if a described version of video is available via data-desc-src attribute
|
7102
7065
|
// hasClosedDesc == true if a description text track is available
|
7103
7066
|
// this.useDescFormat == either 'video' or 'text'; the format ultimately delivered
|
7104
7067
|
// descOn == true if description of either type is on
|
7068
|
+
// exposeTextDescriptions == true if text description is to be announced audibly; otherwise false
|
7105
7069
|
|
7106
7070
|
var thisObj = this;
|
7107
|
-
|
7108
|
-
|
7071
|
+
if (this.refreshingDesc) {
|
7072
|
+
this.prevDescFormat = this.useDescFormat;
|
7073
|
+
}
|
7074
|
+
else {
|
7109
7075
|
// this is the initial build
|
7110
7076
|
// first, check to see if there's an open-described version of this video
|
7111
7077
|
// checks only the first source since if a described version is provided,
|
@@ -7125,12 +7091,15 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
7125
7091
|
}
|
7126
7092
|
}
|
7127
7093
|
}
|
7094
|
+
|
7128
7095
|
// update this.useDescFormat based on media availability & user preferences
|
7129
7096
|
if (this.prefDesc) {
|
7130
7097
|
if (this.hasOpenDesc && this.hasClosedDesc) {
|
7131
|
-
// both formats are available.
|
7098
|
+
// both formats are available. Always use 'video'
|
7132
7099
|
this.useDescFormat = this.prefDescFormat;
|
7133
7100
|
this.descOn = true;
|
7101
|
+
// Do not pause during descriptions when playing described video
|
7102
|
+
this.prefDescPause = false;
|
7134
7103
|
}
|
7135
7104
|
else if (this.hasOpenDesc) {
|
7136
7105
|
this.useDescFormat = 'video';
|
@@ -7142,14 +7111,8 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
7142
7111
|
}
|
7143
7112
|
}
|
7144
7113
|
else { // description button is off
|
7145
|
-
|
7146
|
-
|
7147
|
-
this.useDescFormat = false;
|
7148
|
-
this.descOn = false;
|
7149
|
-
}
|
7150
|
-
else { // desc has always been off
|
7151
|
-
this.useDescFormat = false;
|
7152
|
-
}
|
7114
|
+
this.useDescFormat = false;
|
7115
|
+
this.descOn = false;
|
7153
7116
|
}
|
7154
7117
|
|
7155
7118
|
if (this.useDescFormat === 'text') {
|
@@ -7181,22 +7144,21 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
7181
7144
|
}
|
7182
7145
|
}
|
7183
7146
|
if (this.descOn) {
|
7184
|
-
|
7185
7147
|
if (this.useDescFormat === 'video') {
|
7186
7148
|
if (!this.usingAudioDescription()) {
|
7187
7149
|
// switched from non-described to described version
|
7188
7150
|
this.swapDescription();
|
7189
7151
|
}
|
7190
|
-
// hide description div
|
7191
|
-
this.$descDiv.hide();
|
7192
|
-
this.$descDiv.removeClass('able-clipped');
|
7193
7152
|
}
|
7194
|
-
|
7195
|
-
this
|
7196
|
-
|
7153
|
+
if (this.hasClosedDesc) {
|
7154
|
+
if (this.prefVisibleDesc) {
|
7155
|
+
// make description text visible
|
7156
|
+
// New in v4.0.10: Do this regardless of useDescFormat
|
7157
|
+
this.$descDiv.show();
|
7197
7158
|
this.$descDiv.removeClass('able-clipped');
|
7198
7159
|
}
|
7199
|
-
else {
|
7160
|
+
else {
|
7161
|
+
// keep it visible to screen readers, but hide it visibly
|
7200
7162
|
this.$descDiv.addClass('able-clipped');
|
7201
7163
|
}
|
7202
7164
|
if (!this.swappingSrc) {
|
@@ -7205,7 +7167,6 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
7205
7167
|
}
|
7206
7168
|
}
|
7207
7169
|
else { // description is off.
|
7208
|
-
|
7209
7170
|
if (this.prevDescFormat === 'video') { // user was previously using description via video
|
7210
7171
|
if (this.usingAudioDescription()) {
|
7211
7172
|
this.swapDescription();
|
@@ -7235,7 +7196,6 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
7235
7196
|
};
|
7236
7197
|
|
7237
7198
|
AblePlayer.prototype.swapDescription = function() {
|
7238
|
-
|
7239
7199
|
// swap described and non-described source media, depending on which is playing
|
7240
7200
|
// this function is only called in two circumstances:
|
7241
7201
|
// 1. Swapping to described version when initializing player (based on user prefs & availability)
|
@@ -7358,7 +7318,7 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
7358
7318
|
// there's a lot of redundancy between this function and showCaptions
|
7359
7319
|
// Trying to combine them ended up in a mess though. Keeping as is for now.
|
7360
7320
|
|
7361
|
-
if (this.swappingSrc) {
|
7321
|
+
if (this.swappingSrc || !this.descOn) {
|
7362
7322
|
return;
|
7363
7323
|
}
|
7364
7324
|
|
@@ -7398,7 +7358,10 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
7398
7358
|
// temporarily remove aria-live from $status in order to prevent description from being interrupted
|
7399
7359
|
this.$status.removeAttr('aria-live');
|
7400
7360
|
descText = flattenComponentForDescription(cues[thisDescription].components);
|
7401
|
-
if (
|
7361
|
+
if (
|
7362
|
+
this.exposeTextDescriptions &&
|
7363
|
+
typeof this.synth !== 'undefined' &&
|
7364
|
+
typeof this.descVoiceIndex !== 'undefined') {
|
7402
7365
|
// browser supports speech synthesis and a voice has been selected in initDescription()
|
7403
7366
|
// use the web speech API
|
7404
7367
|
msg = new SpeechSynthesisUtterance();
|
@@ -7414,7 +7377,7 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
7414
7377
|
if (thisObj.pausedForDescription) {
|
7415
7378
|
thisObj.playMedia();
|
7416
7379
|
}
|
7417
|
-
|
7380
|
+
};
|
7418
7381
|
this.synth.speak(msg);
|
7419
7382
|
if (this.prefVisibleDesc) {
|
7420
7383
|
// write description to the screen for sighted users
|
@@ -7427,7 +7390,7 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
7427
7390
|
// load the new description into the container div for screen readers to read
|
7428
7391
|
this.$descDiv.html(descText);
|
7429
7392
|
}
|
7430
|
-
if (this.prefDescPause) {
|
7393
|
+
if (this.prefDescPause && this.exposeTextDescriptions) {
|
7431
7394
|
this.pauseMedia();
|
7432
7395
|
this.pausedForDescription = true;
|
7433
7396
|
}
|
@@ -8163,30 +8126,27 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
8163
8126
|
if (typeof this.$elapsedTimeContainer !== 'undefined') {
|
8164
8127
|
this.$elapsedTimeContainer.text(this.formatSecondsAsColonTime(displayElapsed));
|
8165
8128
|
}
|
8166
|
-
|
8167
8129
|
// Update seekbar width.
|
8168
8130
|
// To do this, we need to calculate the width of all buttons surrounding it.
|
8169
8131
|
if (this.seekBar) {
|
8170
8132
|
widthUsed = 0;
|
8171
|
-
seekbarSpacer = 40; // adjust for discrepancies in browsers' calculated button widths
|
8172
|
-
|
8173
8133
|
leftControls = this.seekBar.wrapperDiv.parent().prev('div.able-left-controls');
|
8174
8134
|
rightControls = leftControls.next('div.able-right-controls');
|
8175
8135
|
leftControls.children().each(function () {
|
8176
8136
|
if ($(this).prop('tagName')=='BUTTON') {
|
8177
|
-
widthUsed += $(this).
|
8137
|
+
widthUsed += $(this).outerWidth(true); // true = include margin
|
8178
8138
|
}
|
8179
8139
|
});
|
8180
8140
|
rightControls.children().each(function () {
|
8181
8141
|
if ($(this).prop('tagName')=='BUTTON') {
|
8182
|
-
widthUsed += $(this).
|
8142
|
+
widthUsed += $(this).outerWidth(true);
|
8183
8143
|
}
|
8184
8144
|
});
|
8185
8145
|
if (this.fullscreen) {
|
8186
|
-
seekbarWidth = $(window).width() - widthUsed
|
8146
|
+
seekbarWidth = $(window).width() - widthUsed;
|
8187
8147
|
}
|
8188
8148
|
else {
|
8189
|
-
seekbarWidth = this.$ableWrapper.width() - widthUsed
|
8149
|
+
seekbarWidth = this.$ableWrapper.width() - widthUsed;
|
8190
8150
|
}
|
8191
8151
|
// Sometimes some minor fluctuations based on browser weirdness, so set a threshold.
|
8192
8152
|
if (Math.abs(seekbarWidth - this.seekBar.getWidth()) > 5) {
|
@@ -8437,7 +8397,7 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
8437
8397
|
|
8438
8398
|
// Don't change play/pause button display while using the seek bar (or if YouTube stopped)
|
8439
8399
|
if (!thisObj.seekBar.tracking && !thisObj.stoppingYouTube) {
|
8440
|
-
if (currentState === 'paused' || currentState === 'stopped') {
|
8400
|
+
if (currentState === 'paused' || currentState === 'stopped' || currentState === 'ended') {
|
8441
8401
|
thisObj.$playpauseButton.attr('aria-label',thisObj.tt.play);
|
8442
8402
|
|
8443
8403
|
if (thisObj.iconType === 'font') {
|
@@ -8538,6 +8498,34 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
8538
8498
|
this.seekTo(0);
|
8539
8499
|
};
|
8540
8500
|
|
8501
|
+
AblePlayer.prototype.handlePrevTrack = function() {
|
8502
|
+
|
8503
|
+
if (this.playlistIndex === 0) {
|
8504
|
+
// currently on the first track
|
8505
|
+
// wrap to bottom and play the last track
|
8506
|
+
this.playlistIndex = this.$playlist.length - 1;
|
8507
|
+
}
|
8508
|
+
else {
|
8509
|
+
this.playlistIndex--;
|
8510
|
+
}
|
8511
|
+
this.cueingPlaylistItem = true; // stopgap to prevent multiple firings
|
8512
|
+
this.cuePlaylistItem(this.playlistIndex);
|
8513
|
+
};
|
8514
|
+
|
8515
|
+
AblePlayer.prototype.handleNextTrack = function() {
|
8516
|
+
|
8517
|
+
if (this.playlistIndex === this.$playlist.length - 1) {
|
8518
|
+
// currently on the last track
|
8519
|
+
// wrap to top and play the forst track
|
8520
|
+
this.playlistIndex = 0;
|
8521
|
+
}
|
8522
|
+
else {
|
8523
|
+
this.playlistIndex++;
|
8524
|
+
}
|
8525
|
+
this.cueingPlaylistItem = true; // stopgap to prevent multiple firings
|
8526
|
+
this.cuePlaylistItem(this.playlistIndex);
|
8527
|
+
};
|
8528
|
+
|
8541
8529
|
AblePlayer.prototype.handleRewind = function() {
|
8542
8530
|
|
8543
8531
|
var targetTime;
|
@@ -8763,6 +8751,9 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
8763
8751
|
this.descOn = !this.descOn;
|
8764
8752
|
this.prefDesc = + this.descOn; // convert boolean to integer
|
8765
8753
|
this.updateCookie('prefDesc');
|
8754
|
+
if (!this.$descDiv.is(':hidden')) {
|
8755
|
+
this.$descDiv.hide();
|
8756
|
+
}
|
8766
8757
|
this.refreshingDesc = true;
|
8767
8758
|
this.initDescription();
|
8768
8759
|
this.refreshControls('descriptions');
|
@@ -10279,6 +10270,7 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
10279
10270
|
if (!this.transcriptType) {
|
10280
10271
|
// previously set transcriptType to null since there are no <track> elements
|
10281
10272
|
// check again to see if captions have been collected from other sources (e.g., YouTube)
|
10273
|
+
|
10282
10274
|
if (this.captions.length && (!(this.usingYouTubeCaptions || this.usingVimeoCaptions))) {
|
10283
10275
|
// captions are possible! Use the default type (popup)
|
10284
10276
|
// if other types ('external' and 'manual') were desired, transcriptType would not be null here
|
@@ -11136,19 +11128,14 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
11136
11128
|
(function ($) {
|
11137
11129
|
// Media events
|
11138
11130
|
AblePlayer.prototype.onMediaUpdateTime = function (duration, elapsed) {
|
11139
|
-
|
11140
11131
|
// duration and elapsed are passed from callback functions of Vimeo API events
|
11141
11132
|
// duration is expressed as sss.xxx
|
11142
11133
|
// elapsed is expressed as sss.xxx
|
11143
11134
|
var thisObj = this;
|
11144
11135
|
|
11145
11136
|
this.getMediaTimes(duration,elapsed).then(function(mediaTimes) {
|
11146
|
-
|
11147
|
-
|
11148
|
-
}
|
11149
|
-
if (typeof elapsed === 'undefined') {
|
11150
|
-
thisObj.elapsed = mediaTimes['elapsed'];
|
11151
|
-
}
|
11137
|
+
thisObj.duration = mediaTimes['duration'];
|
11138
|
+
thisObj.elapsed = mediaTimes['elapsed'];
|
11152
11139
|
if (thisObj.swappingSrc && (typeof thisObj.swapTime !== 'undefined')) {
|
11153
11140
|
if (thisObj.swapTime === thisObj.elapsed) {
|
11154
11141
|
// described version been swapped and media has scrubbed to time of previous version
|
@@ -11190,7 +11177,6 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
11190
11177
|
};
|
11191
11178
|
|
11192
11179
|
AblePlayer.prototype.onMediaComplete = function () {
|
11193
|
-
|
11194
11180
|
// if there's a playlist, advance to next item and start playing
|
11195
11181
|
if (this.hasPlaylist && !this.cueingPlaylistItem) {
|
11196
11182
|
if (this.playlistIndex === (this.$playlist.length - 1)) {
|
@@ -11200,6 +11186,10 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
11200
11186
|
this.cueingPlaylistItem = true; // stopgap to prevent multiple firings
|
11201
11187
|
this.cuePlaylistItem(0);
|
11202
11188
|
}
|
11189
|
+
else {
|
11190
|
+
this.playing = false;
|
11191
|
+
this.paused = true;
|
11192
|
+
}
|
11203
11193
|
}
|
11204
11194
|
else {
|
11205
11195
|
// this is not the last track. Play the next one.
|
@@ -11231,9 +11221,9 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
11231
11221
|
this.playMedia();
|
11232
11222
|
}
|
11233
11223
|
this.swappingSrc = false; // swapping is finished
|
11234
|
-
this.refreshControls('init');
|
11235
11224
|
}
|
11236
11225
|
}
|
11226
|
+
this.refreshControls('init');
|
11237
11227
|
};
|
11238
11228
|
|
11239
11229
|
// End Media events
|
@@ -11325,12 +11315,21 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
11325
11315
|
// TODO: This is super-fragile since we need to know the length of the class name to split off; update this to other way of dispatching?
|
11326
11316
|
var whichButton = $(el).attr('class').split(' ')[0].substr(20);
|
11327
11317
|
if (whichButton === 'play') {
|
11318
|
+
this.clickedPlay = true;
|
11328
11319
|
this.handlePlay();
|
11329
11320
|
}
|
11330
11321
|
else if (whichButton === 'restart') {
|
11331
11322
|
this.seekTrigger = 'restart';
|
11332
11323
|
this.handleRestart();
|
11333
11324
|
}
|
11325
|
+
else if (whichButton === 'previous') {
|
11326
|
+
this.seekTrigger = 'previous';
|
11327
|
+
this.handlePrevTrack();
|
11328
|
+
}
|
11329
|
+
else if (whichButton === 'next') {
|
11330
|
+
this.seekTrigger = 'next';
|
11331
|
+
this.handleNextTrack();
|
11332
|
+
}
|
11334
11333
|
else if (whichButton === 'rewind') {
|
11335
11334
|
this.seekTrigger = 'rewind';
|
11336
11335
|
this.handleRewind();
|
@@ -11427,6 +11426,7 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
11427
11426
|
e.target.tagName === 'TEXTAREA' ||
|
11428
11427
|
e.target.tagName === 'SELECT'
|
11429
11428
|
)){
|
11429
|
+
|
11430
11430
|
if (which === 27) { // escape
|
11431
11431
|
this.closePopups();
|
11432
11432
|
}
|
@@ -11482,6 +11482,16 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
11482
11482
|
this.handleRewind();
|
11483
11483
|
}
|
11484
11484
|
}
|
11485
|
+
else if (which === 98) { // b = back (previous track)
|
11486
|
+
if (this.usingModifierKeys(e)) {
|
11487
|
+
this.handlePrevTrack();
|
11488
|
+
}
|
11489
|
+
}
|
11490
|
+
else if (which === 110) { // n = next track
|
11491
|
+
if (this.usingModifierKeys(e)) {
|
11492
|
+
this.handleNextTrack();
|
11493
|
+
}
|
11494
|
+
}
|
11485
11495
|
else if (which === 101) { // e = preferences
|
11486
11496
|
if (this.usingModifierKeys(e)) {
|
11487
11497
|
this.handlePrefsClick();
|
@@ -11514,6 +11524,8 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
11514
11524
|
// do something
|
11515
11525
|
})
|
11516
11526
|
.on('loadedmetadata',function() {
|
11527
|
+
// should be able to get duration now
|
11528
|
+
thisObj.duration = thisObj.media.duration;
|
11517
11529
|
thisObj.onMediaNewSourceLoad();
|
11518
11530
|
})
|
11519
11531
|
.on('canplay',function() {
|
@@ -15669,4 +15681,4 @@ if (thisObj.useTtml && (trackSrc.endsWith('.xml') || trackText.startsWith('<?xml
|
|
15669
15681
|
return false;
|
15670
15682
|
};
|
15671
15683
|
|
15672
|
-
})(jQuery);
|
15684
|
+
})(jQuery);
|