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.
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,6 +1,6 @@
1
1
  {
2
2
  "name": "ableplayer",
3
- "version": "3.2.0",
3
+ "version": "4.0.00",
4
4
  "description": "fully accessible HTML5 media player",
5
5
  "homepage": "http://ableplayer.github.io/ableplayer",
6
6
  "bugs": "https://github.com/ableplayer/ableplayer/issues",
@@ -19,13 +19,13 @@
19
19
  "xml-js": "1.6.2"
20
20
  },
21
21
  "devDependencies": {
22
- "grunt": ">=0.4.1",
23
- "grunt-contrib-clean": ">=0.6.0",
24
- "grunt-contrib-concat": ">=0.3.0",
25
- "grunt-contrib-copy": ">=0.4.1",
26
- "grunt-contrib-cssmin": ">=0.6.1",
27
- "grunt-contrib-jshint": "^0.10.0",
28
- "grunt-contrib-uglify": ">=0.2.2",
22
+ "grunt": "^1.0.4",
23
+ "grunt-contrib-clean": "^2.0.0",
24
+ "grunt-contrib-concat": "^1.0.1",
25
+ "grunt-contrib-copy": "^1.0.0",
26
+ "grunt-contrib-cssmin": "^3.0.0",
27
+ "grunt-contrib-jshint": "^2.1.0",
28
+ "grunt-contrib-uglify": "^4.0.1",
29
29
  "grunt-remove-logging": ">=0.2.0"
30
30
  }
31
31
  }
@@ -1,33 +1,33 @@
1
1
  /*
2
- // JavaScript for Able Player
2
+ // JavaScript for Able Player
3
3
 
4
- // HTML5 Media API:
5
- // http://www.w3.org/TR/html5/embedded-content-0.html#htmlmediaelement
6
- // http://dev.w3.org/html5/spec-author-view/video.html
4
+ // HTML5 Media API:
5
+ // http://www.w3.org/TR/html5/embedded-content-0.html#htmlmediaelement
6
+ // http://dev.w3.org/html5/spec-author-view/video.html
7
7
 
8
- // W3C API Test Page:
9
- // http://www.w3.org/2010/05/video/mediaevents.html
8
+ // W3C API Test Page:
9
+ // http://www.w3.org/2010/05/video/mediaevents.html
10
10
 
11
- // Uses JW Player as fallback
12
- // JW Player configuration options:
13
- // http://support.jwplayer.com/customer/portal/articles/1413113-configuration-options-reference
14
- // (NOTE: some options are not documented, e.g., volume)
15
- // JW Player 6 API reference:
16
- // http://support.jwplayer.com/customer/portal/articles/1413089-javascript-api-reference
11
+ // YouTube Player API for iframe Embeds
12
+ https://developers.google.com/youtube/iframe_api_reference
13
+ // YouTube Player Parameters
14
+ https://developers.google.com/youtube/player_parameters?playerVersion=HTML5
17
15
 
18
- // YouTube Player API for iframe Embeds
19
- https://developers.google.com/youtube/iframe_api_reference
20
- // YouTube Player Parameters
21
- https://developers.google.com/youtube/player_parameters?playerVersion=HTML5
16
+ // YouTube Data API
17
+ https://developers.google.com/youtube/v3
22
18
 
23
- // YouTube Data API
24
- https://developers.google.com/youtube/v3
19
+ // Vimeo Player API
20
+ https://github.com/vimeo/player.js
25
21
 
26
- // Google API Client Library for JavaScript
27
- https://developers.google.com/api-client-library/javascript/dev/dev_jscript
22
+ // Google API Client Library for JavaScript
23
+ https://developers.google.com/api-client-library/javascript/dev/dev_jscript
28
24
 
29
- // Google API Explorer: YouTube services and methods
30
- https://developers.google.com/apis-explorer/#s/youtube/v3/
25
+ // Google API Explorer: YouTube services and methods
26
+ https://developers.google.com/apis-explorer/#s/youtube/v3/
27
+
28
+ // Web Speech API (Speech Synthesis)
29
+ // https://w3c.github.io/speech-api/#tts-section
30
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/speechSynthesis
31
31
  */
32
32
 
33
33
  /*jslint node: true, browser: true, white: true, indent: 2, unparam: true, plusplus: true */
@@ -35,506 +35,497 @@
35
35
  "use strict";
36
36
 
37
37
  (function ($) {
38
- $(document).ready(function () {
39
- $('video, audio').each(function (index, element) {
40
- if ($(element).data('able-player') !== undefined) {
41
- new AblePlayer($(this),$(element));
42
- }
43
- });
44
- });
45
-
46
- // YouTube player support; pass ready event to jQuery so we can catch in player.
47
- window.onYouTubeIframeAPIReady = function() {
48
- AblePlayer.youtubeIframeAPIReady = true;
49
- $('body').trigger('youtubeIframeAPIReady', []);
50
- };
51
-
52
- // If there is only one player on the page, dispatch global keydown events to it
53
- // Otherwise, keydowwn events are handled locally (see event.js > handleEventListeners())
54
- $(window).keydown(function(e) {
55
- if (AblePlayer.nextIndex === 1) {
56
- AblePlayer.lastCreated.onPlayerKeyPress(e);
57
- }
58
- });
59
-
60
- // Construct an AblePlayer object
61
- // Parameters are:
62
- // media - jQuery selector or element identifying the media.
63
- window.AblePlayer = function(media) {
64
-
65
- // Keep track of the last player created for use with global events.
66
- AblePlayer.lastCreated = this;
67
-
68
- this.media = media;
69
- if ($(media).length === 0) {
70
- this.provideFallback();
71
- return;
72
- }
73
-
74
- ///////////////////////////////
75
- //
76
- // Default variables assignment
77
- //
78
- ///////////////////////////////
79
-
80
- // The following variables CAN be overridden with HTML attributes
81
-
82
- // autoplay (Boolean; if present always resolves to true, regardless of value)
83
- if ($(media).attr('autoplay') !== undefined) {
84
- this.autoplay = true;
85
- }
86
- else {
87
- this.autoplay = false;
88
- }
89
-
90
- // loop (Boolean; if present always resolves to true, regardless of value)
91
- if ($(media).attr('loop') !== undefined) {
92
- this.loop = true;
93
- }
94
- else {
95
- this.loop = false;
96
- }
97
-
98
- // playsinline (Boolean; if present always resolves to true, regardless of value)
99
- if ($(media).attr('playsinline') !== undefined) {
100
- this.playsInline = '1'; // this value gets passed to YT.Player contructor in youtube.js
101
- }
102
- else {
103
- this.playsInline = '0';
104
- }
105
-
106
- // start-time
107
- if ($(media).data('start-time') !== undefined && $.isNumeric($(media).data('start-time'))) {
108
- this.startTime = $(media).data('start-time');
109
- }
110
- else {
111
- this.startTime = 0;
112
- }
113
-
114
- // debug
115
- if ($(media).data('debug') !== undefined && $(media).data('debug') !== false) {
116
- this.debug = true;
117
- }
118
- else {
119
- this.debug = false;
120
- }
121
-
122
- // Path to root directory of Able Player code
123
- if ($(media).data('root-path') !== undefined) {
124
- // add a trailing slash if there is none
125
- this.rootPath = $(media).data('root-path').replace(/\/?$/, '/');
126
- }
127
- else {
128
- this.rootPath = this.getRootPath();
129
- }
130
-
131
- // Volume
132
- // Range is 0 to 10. Best not to crank it to avoid overpowering screen readers
133
- this.defaultVolume = 7;
134
- if ($(media).data('volume') !== undefined && $(media).data('volume') !== "") {
135
- var volume = $(media).data('volume');
136
- if (volume >= 0 && volume <= 10) {
137
- this.defaultVolume = volume;
138
- }
139
- }
140
- this.volume = this.defaultVolume;
141
-
142
- // Optional Buttons
143
- // Buttons are added to the player controller if relevant media is present
144
- // However, in some applications it might be undesirable to show buttons
145
- // (e.g., if chapters or transcripts are provided in an external container)
146
-
147
- if ($(media).data('use-chapters-button') !== undefined && $(media).data('use-chapters-button') === false) {
148
- this.useChaptersButton = false;
149
- }
150
- else {
151
- this.useChaptersButton = true;
152
- }
153
-
154
- if ($(media).data('use-descriptions-button') !== undefined && $(media).data('use-descriptions-button') === false) {
155
- this.useDescriptionsButton = false;
156
- }
157
- else {
158
- this.useDescriptionsButton = true;
159
- }
160
-
161
- // Headings
162
- // By default, an off-screen heading is automatically added to the top of the media player
163
- // It is intelligently assigned a heading level based on context, via misc.js > getNextHeadingLevel()
164
- // Authors can override this behavior by manually assigning a heading level using data-heading-level
165
- // Accepted values are 1-6, or 0 which indicates "no heading"
166
- // (i.e., author has already hard-coded a heading before the media player; Able Player doesn't need to do this)
167
- if ($(media).data('heading-level') !== undefined && $(media).data('heading-level') !== "") {
168
- var headingLevel = $(media).data('heading-level');
169
- if (/^[0-6]*$/.test(headingLevel)) { // must be a valid HTML heading level 1-6; or 0
170
- this.playerHeadingLevel = headingLevel;
171
- }
172
- }
173
-
174
- // Transcripts
175
- // There are three types of interactive transcripts.
176
- // In descending of order of precedence (in case there are conflicting tags), they are:
177
- // 1. "manual" - A manually coded external transcript (requires data-transcript-src)
178
- // 2. "external" - Automatically generated, written to an external div (requires data-transcript-div)
179
- // 3. "popup" - Automatically generated, written to a draggable, resizable popup window that can be toggled on/off with a button
180
- // If data-include-transcript="false", there is no "popup" transcript
181
-
182
- this.transcriptType = null;
183
- if ($(media).data('transcript-src') !== undefined) {
184
- this.transcriptSrc = $(media).data('transcript-src');
185
- if (this.transcriptSrcHasRequiredParts()) {
186
- this.transcriptType = 'manual';
187
- }
188
- else {
189
- this.transcriptType = null;
190
- }
191
- }
192
- else if ($(media).find('track[kind="captions"], track[kind="subtitles"]').length > 0) {
193
- // required tracks are present. COULD automatically generate a transcript
194
- if ($(media).data('transcript-div') !== undefined && $(media).data('transcript-div') !== "") {
195
- this.transcriptDivLocation = $(media).data('transcript-div');
196
- this.transcriptType = 'external';
197
- }
198
- else if ($(media).data('include-transcript') !== undefined) {
199
- if ($(media).data('include-transcript') !== false) {
200
- this.transcriptType = 'popup';
201
- }
202
- }
203
- else {
204
- this.transcriptType = 'popup';
205
- }
206
- }
207
-
208
- // In "Lyrics Mode", line breaks in WebVTT caption files are supported in the transcript
209
- // If false (default), line breaks are are removed from transcripts in order to provide a more seamless reading experience
210
- // If true, line breaks are preserved, so content can be presented karaoke-style, or as lines in a poem
211
- if ($(media).data('lyrics-mode') !== undefined && $(media).data('lyrics-mode') !== false) {
212
- this.lyricsMode = true;
213
- }
214
- else {
215
- this.lyricsMode = false;
216
- }
217
-
218
- // Transcript Title
219
- if ($(media).data('transcript-title') !== undefined && $(media).data('transcript-title') !== "") {
220
- this.transcriptTitle = $(media).data('transcript-title');
221
- }
222
- else {
223
- // do nothing. The default title will be defined later (see transcript.js)
224
- }
225
-
226
- // Captions
227
- // data-captions-position can be used to set the default captions position
228
- // this is only the default, and can be overridden by user preferences
229
- // valid values of data-captions-position are 'below' and 'overlay'
230
- if ($(media).data('captions-position') === 'overlay') {
231
- this.defaultCaptionsPosition = 'overlay';
232
- }
233
- else { // the default, even if not specified
234
- this.defaultCaptionsPosition = 'below';
235
- }
236
-
237
- // Chapters
238
- if ($(media).data('chapters-div') !== undefined && $(media).data('chapters-div') !== "") {
239
- this.chaptersDivLocation = $(media).data('chapters-div');
240
- }
241
-
242
- if ($(media).data('chapters-title') !== undefined) {
243
- // NOTE: empty string is valid; results in no title being displayed
244
- this.chaptersTitle = $(media).data('chapters-title');
245
- }
246
-
247
- if ($(media).data('chapters-default') !== undefined && $(media).data('chapters-default') !== "") {
248
- this.defaultChapter = $(media).data('chapters-default');
249
- }
250
- else {
251
- this.defaultChapter = null;
252
- }
253
-
254
- // Previous/Next buttons
255
- // valid values of data-prevnext-unit are 'playlist' and 'chapter'; will also accept 'chapters'
256
- if ($(media).data('prevnext-unit') === 'chapter' || $(media).data('prevnext-unit') === 'chapters') {
257
- this.prevNextUnit = 'chapter';
258
- }
259
- else if ($(media).data('prevnext-unit') === 'playlist') {
260
- this.prevNextUnit = 'playlist';
261
- }
262
- else {
263
- this.prevNextUnit = false;
264
- }
265
-
266
- // Slower/Faster buttons
267
- // valid values of data-speed-icons are 'animals' (default) and 'arrows'
268
- // 'animals' uses turtle and rabbit; 'arrows' uses up/down arrows
269
- if ($(media).data('speed-icons') === 'arrows') {
270
- this.speedIcons = 'arrows';
271
- }
272
- else {
273
- this.speedIcons = 'animals';
274
- }
275
-
276
- // Seekbar
277
- // valid values of data-seekbar-scope are 'chapter' and 'video'; will also accept 'chapters'
278
- if ($(media).data('seekbar-scope') === 'chapter' || $(media).data('seekbar-scope') === 'chapters') {
279
- this.seekbarScope = 'chapter';
280
- }
281
- else {
282
- this.seekbarScope = 'video';
283
- }
284
-
285
- // YouTube
286
- if ($(media).data('youtube-id') !== undefined && $(media).data('youtube-id') !== "") {
287
- this.youTubeId = $(media).data('youtube-id');
288
- }
289
-
290
- if ($(media).data('youtube-desc-id') !== undefined && $(media).data('youtube-desc-id') !== "") {
291
- this.youTubeDescId = $(media).data('youtube-desc-id');
292
- }
293
-
294
- if ($(media).data('youtube-nocookie') !== undefined && $(media).data('youtube-nocookie')) {
295
- this.youTubeNoCookie = true;
296
- }
297
- else {
298
- this.youTubeNoCookie = false;
299
- }
300
-
301
- // Icon type
302
- // By default, AblePlayer 3.0.33 and higher uses SVG icons for the player controls
303
- // Fallback for browsers that don't support SVG is scalable icomoon fonts
304
- // Ultimate fallback is images, if the user has a custom style sheet that overrides font-family
305
- // Use data-icon-type to force controls to use either 'svg', 'font', or 'images'
306
- this.iconType = 'font';
307
- this.forceIconType = false;
308
- if ($(media).data('icon-type') !== undefined && $(media).data('icon-type') !== "") {
309
- var iconType = $(media).data('icon-type');
310
- if (iconType === 'font' || iconType == 'image' || iconType == 'svg') {
311
- this.iconType = iconType;
312
- this.forceIconType = true;
313
- }
314
- }
315
-
316
- if ($(media).data('allow-fullscreen') !== undefined && $(media).data('allow-fullscreen') === false) {
317
- this.allowFullScreen = false;
318
- }
319
- else {
320
- this.allowFullScreen = true;
321
- }
322
-
323
- // Seek interval
324
- // Number of seconds to seek forward or back with Rewind & Forward buttons
325
- // Unless specified with data-seek-interval, the default value is re-calculated in initialize.js > setSeekInterval();
326
- // Calculation attempts to intelligently assign a reasonable interval based on media length
327
- this.defaultSeekInterval = 10;
328
- this.useFixedSeekInterval = false;
329
- if ($(media).data('seek-interval') !== undefined && $(media).data('seek-interval') !== "") {
330
- var seekInterval = $(media).data('seek-interval');
331
- if (/^[1-9][0-9]*$/.test(seekInterval)) { // must be a whole number greater than 0
332
- this.seekInterval = seekInterval;
333
- this.useFixedSeekInterval = true; // do not override with calculuation
334
- }
335
- }
336
-
337
- // Now Playing
338
- // Shows "Now Playing:" plus the title of the current track above player
339
- // Only used if there is a playlist
340
- if ($(media).data('show-now-playing') !== undefined && $(media).data('show-now-playing') === false) {
341
- this.showNowPlaying = false;
342
- }
343
- else {
344
- this.showNowPlaying = true;
345
- }
346
-
347
- // TTML support (experimental); enabled for testing with data-use-ttml (Boolean)
348
- if ($(media).data('use-ttml') !== undefined) {
349
- this.useTtml = true;
350
- // The following may result in a console error.
351
- this.convert = require('xml-js');
352
- }
353
- else {
354
- this.useTtml = false;
355
- }
356
-
357
- // Fallback Player
358
- // The only supported fallback is JW Player, licensed separately
359
- // JW Player files must be included in folder specified in this.fallbackPath
360
- // JW Player will be loaded as needed in browsers that don't support HTML5 media
361
- // NOTE: As of 2.3.44, NO FALLBACK is used unless data-fallback='jw'
362
-
363
- this.fallback = null;
364
- this.fallbackPath = null;
365
- this.fallbackJwKey = null;
366
- this.testFallback = false;
367
-
368
- if ($(media).data('fallback') !== undefined && $(media).data('fallback') !== "") {
369
- var fallback = $(media).data('fallback');
370
- if (fallback === 'jw') {
371
- this.fallback = fallback;
372
- }
373
- }
374
-
375
- if (this.fallback === 'jw') {
376
-
377
- if ($(media).data('fallback-path') !== undefined && $(media).data('fallback-path') !== false) {
378
- this.fallbackPath = $(media).data('fallback-path');
379
-
380
- var path = $(media).data('fallback-path');
381
-
382
- // remove js file is specified.
383
- var playerJs = 'jwplayer.js';
384
- if (path.endsWith(playerJs)) {
385
- path = path.slice(0, path.length - playerJs.length);
386
- }
387
- this.fallbackPath = path;
388
- } else {
389
- this.fallbackPath = this.rootPath + 'thirdparty/';
390
- }
391
-
392
- if ($(media).data('fallback-jwkey') !== undefined) {
393
- this.fallbackJwKey = $(media).data('fallback-jwkey');
394
- }
395
-
396
- if ($(media).data('test-fallback') !== undefined && $(media).data('test-fallback') !== false) {
397
- this.testFallback = true;
398
- }
399
- }
400
-
401
- // Language
402
- this.lang = 'en';
403
- if ($(media).data('lang') !== undefined && $(media).data('lang') !== "") {
404
- var lang = $(media).data('lang');
405
- if (lang.length == 2) {
406
- this.lang = lang;
407
- }
408
- }
409
- // Player language is determined as follows (in translation.js > getTranslationText() ):
410
- // 1. Lang attributes on <html> or <body>, if a matching translation file is available
411
- // 2. The value of this.lang, if a matching translation file is available
412
- // 3. English
413
- // To override this formula and force #2 to take precedence over #1, set data-force-lang="true"
414
- if ($(media).data('force-lang') !== undefined && $(media).data('force-lang') !== false) {
415
- this.forceLang = true;
416
- }
417
- else {
418
- this.forceLang = false;
419
- }
420
-
421
- // Metadata Tracks
422
- if ($(media).data('meta-type') !== undefined && $(media).data('meta-type') !== "") {
423
- this.metaType = $(media).data('meta-type');
424
- }
425
-
426
- if ($(media).data('meta-div') !== undefined && $(media).data('meta-div') !== "") {
427
- this.metaDiv = $(media).data('meta-div');
428
- }
429
-
430
- // Search
431
- if ($(media).data('search') !== undefined && $(media).data('search') !== "") {
432
- // conducting a search currently requires an external div in which to write the results
433
- if ($(media).data('search-div') !== undefined && $(media).data('search-div') !== "") {
434
- this.searchString = $(media).data('search');
435
- this.searchDiv = $(media).data('search-div');
436
- }
437
-
438
- // Search Language
439
- if ($(media).data('search-lang') !== undefined && $(media).data('search-lang') !== "") {
440
- this.searchLang = $(media).data('search-lang');
441
- }
442
- else {
443
- this.searchLang = null; // will change to final value of this.lang in translation.js > getTranslationText()
444
- }
445
-
446
- // conducting a search currently requires an external div in which to write the results
447
- if ($(media).data('search-div') !== undefined && $(media).data('search-div') !== "") {
448
- this.searchString = $(media).data('search');
449
- this.searchDiv = $(media).data('search-div');
450
- }
451
- }
452
-
453
- // Hide controls when video starts playing
454
- // They will reappear again when user presses a key or moves the mouse
455
- if ($(media).data('hide-controls') !== undefined && $(media).data('hide-controls') !== false) {
456
- this.hideControls = true;
457
- }
458
- else {
459
- this.hideControls = false;
460
- }
461
-
462
- // Define built-in variables that CANNOT be overridden with HTML attributes
463
- this.setDefaults();
464
-
465
- ////////////////////////////////////////
466
- //
467
- // End assignment of default variables
468
- //
469
- ////////////////////////////////////////
470
-
471
- this.ableIndex = AblePlayer.nextIndex;
472
- AblePlayer.nextIndex += 1;
473
-
474
- this.title = $(media).attr('title');
475
-
476
- // populate translation object with localized versions of all labels and prompts
477
- // use defer method to defer additional processing until text is retrieved
478
- this.tt = {};
479
- var thisObj = this;
480
- $.when(this.getTranslationText()).then(
481
- function () {
482
- if (thisObj.countProperties(thisObj.tt) > 50) {
483
- // close enough to ensure that most text variables are populated
484
- thisObj.setup();
485
- }
486
- else {
487
- // can't continue loading player with no text
488
- thisObj.provideFallback();
489
- }
490
- }
491
- );
492
- };
493
-
494
- // Index to increment every time new player is created.
495
- AblePlayer.nextIndex = 0;
496
-
497
- AblePlayer.prototype.setup = function() {
498
- var thisObj = this;
499
- this.reinitialize().then(function () {
500
- if (!thisObj.player) {
501
- // No player for this media, show last-line fallback.
502
- thisObj.provideFallback();
503
- }
504
- else {
505
- thisObj.setupInstance().then(function () {
506
- thisObj.recreatePlayer();
507
- });
508
- }
509
- });
510
- };
511
-
512
- AblePlayer.getActiveDOMElement = function () {
513
- var activeElement = document.activeElement;
514
-
515
- // For shadow DOMs we need to keep digging down through the DOMs
516
- while (activeElement.shadowRoot && activeElement.shadowRoot.activeElement) {
517
- activeElement = activeElement.shadowRoot.activeElement;
518
- }
519
-
520
- return activeElement;
521
- };
522
-
523
- AblePlayer.localGetElementById = function(element, id) {
524
- if (element.getRootNode)
525
- {
526
- // Use getRootNode() and querySelector() where supported (for shadow DOM support)
527
- return $(element.getRootNode().querySelector('#' + id));
528
- }
529
- else
530
- {
531
- // If getRootNode is not supported it should be safe to use document.getElementById (since there is no shadow DOM support)
532
- return $(document.getElementById(id));
533
- }
534
- };
535
-
536
-
537
-
538
- AblePlayer.youtubeIframeAPIReady = false;
539
- AblePlayer.loadingYoutubeIframeAPI = false;
38
+ $(document).ready(function () {
39
+ $('video, audio').each(function (index, element) {
40
+ if ($(element).data('able-player') !== undefined) {
41
+ new AblePlayer($(this),$(element));
42
+ }
43
+ });
44
+ });
45
+
46
+ // YouTube player support; pass ready event to jQuery so we can catch in player.
47
+ window.onYouTubeIframeAPIReady = function() {
48
+ AblePlayer.youtubeIframeAPIReady = true;
49
+ $('body').trigger('youtubeIframeAPIReady', []);
50
+ };
51
+
52
+ // If there is only one player on the page, dispatch global keydown events to it
53
+ // Otherwise, keydowwn events are handled locally (see event.js > handleEventListeners())
54
+ $(window).keydown(function(e) {
55
+ if (AblePlayer.nextIndex === 1) {
56
+ AblePlayer.lastCreated.onPlayerKeyPress(e);
57
+ }
58
+ });
59
+
60
+ // Construct an AblePlayer object
61
+ // Parameters are:
62
+ // media - jQuery selector or element identifying the media.
63
+ window.AblePlayer = function(media) {
64
+
65
+ // Keep track of the last player created for use with global events.
66
+ AblePlayer.lastCreated = this;
67
+
68
+ this.media = media;
69
+ if ($(media).length === 0) {
70
+ this.provideFallback();
71
+ return;
72
+ }
73
+
74
+ ///////////////////////////////
75
+ //
76
+ // Default variables assignment
77
+ //
78
+ ///////////////////////////////
79
+
80
+ // The following variables CAN be overridden with HTML attributes
81
+
82
+ // autoplay (Boolean; if present always resolves to true, regardless of value)
83
+ if ($(media).attr('autoplay') !== undefined) {
84
+ this.autoplay = true; // this value remains constant
85
+ this.okToPlay = true; // this value can change dynamically
86
+ }
87
+ else {
88
+ this.autoplay = false;
89
+ this.okToPlay = false;
90
+ }
91
+
92
+ // loop (Boolean; if present always resolves to true, regardless of value)
93
+ if ($(media).attr('loop') !== undefined) {
94
+ this.loop = true;
95
+ }
96
+ else {
97
+ this.loop = false;
98
+ }
99
+
100
+ // playsinline (Boolean; if present always resolves to true, regardless of value)
101
+ if ($(media).attr('playsinline') !== undefined) {
102
+ this.playsInline = '1'; // this value gets passed to YT.Player contructor in youtube.js
103
+ }
104
+ else {
105
+ this.playsInline = '0';
106
+ }
107
+
108
+ // poster (Boolean, indicating whether media element has a poster attribute)
109
+ if ($(media).attr('poster')) {
110
+ this.hasPoster = true;
111
+ }
112
+ else {
113
+ this.hasPoster = false;
114
+ }
115
+
116
+ // start-time
117
+ if ($(media).data('start-time') !== undefined && $.isNumeric($(media).data('start-time'))) {
118
+ this.startTime = $(media).data('start-time');
119
+ }
120
+ else {
121
+ this.startTime = 0;
122
+ }
123
+
124
+ // debug
125
+ if ($(media).data('debug') !== undefined && $(media).data('debug') !== false) {
126
+ this.debug = true;
127
+ }
128
+ else {
129
+ this.debug = false;
130
+ }
131
+
132
+ // Path to root directory of Able Player code
133
+ if ($(media).data('root-path') !== undefined) {
134
+ // add a trailing slash if there is none
135
+ this.rootPath = $(media).data('root-path').replace(/\/?$/, '/');
136
+ }
137
+ else {
138
+ this.rootPath = this.getRootPath();
139
+ }
140
+
141
+ // Volume
142
+ // Range is 0 to 10. Best not to crank it to avoid overpowering screen readers
143
+ this.defaultVolume = 7;
144
+ if ($(media).data('volume') !== undefined && $(media).data('volume') !== "") {
145
+ var volume = $(media).data('volume');
146
+ if (volume >= 0 && volume <= 10) {
147
+ this.defaultVolume = volume;
148
+ }
149
+ }
150
+ this.volume = this.defaultVolume;
151
+
152
+ // Optional Buttons
153
+ // Buttons are added to the player controller if relevant media is present
154
+ // However, in some applications it might be undesirable to show buttons
155
+ // (e.g., if chapters or transcripts are provided in an external container)
156
+
157
+ if ($(media).data('use-chapters-button') !== undefined && $(media).data('use-chapters-button') === false) {
158
+ this.useChaptersButton = false;
159
+ }
160
+ else {
161
+ this.useChaptersButton = true;
162
+ }
163
+
164
+ if ($(media).data('use-descriptions-button') !== undefined && $(media).data('use-descriptions-button') === false) {
165
+ this.useDescriptionsButton = false;
166
+ }
167
+ else {
168
+ this.useDescriptionsButton = true;
169
+ }
170
+
171
+ // Headings
172
+ // By default, an off-screen heading is automatically added to the top of the media player
173
+ // It is intelligently assigned a heading level based on context, via misc.js > getNextHeadingLevel()
174
+ // Authors can override this behavior by manually assigning a heading level using data-heading-level
175
+ // Accepted values are 1-6, or 0 which indicates "no heading"
176
+ // (i.e., author has already hard-coded a heading before the media player; Able Player doesn't need to do this)
177
+ if ($(media).data('heading-level') !== undefined && $(media).data('heading-level') !== "") {
178
+ var headingLevel = $(media).data('heading-level');
179
+ if (/^[0-6]*$/.test(headingLevel)) { // must be a valid HTML heading level 1-6; or 0
180
+ this.playerHeadingLevel = headingLevel;
181
+ }
182
+ }
183
+
184
+ // Transcripts
185
+ // There are three types of interactive transcripts.
186
+ // In descending of order of precedence (in case there are conflicting tags), they are:
187
+ // 1. "manual" - A manually coded external transcript (requires data-transcript-src)
188
+ // 2. "external" - Automatically generated, written to an external div (requires data-transcript-div)
189
+ // 3. "popup" - Automatically generated, written to a draggable, resizable popup window that can be toggled on/off with a button
190
+ // If data-include-transcript="false", there is no "popup" transcript
191
+
192
+ this.transcriptType = null;
193
+ if ($(media).data('transcript-src') !== undefined) {
194
+ this.transcriptSrc = $(media).data('transcript-src');
195
+ if (this.transcriptSrcHasRequiredParts()) {
196
+ this.transcriptType = 'manual';
197
+ }
198
+ }
199
+ else if ($(media).find('track[kind="captions"], track[kind="subtitles"]').length > 0) {
200
+ // required tracks are present. COULD automatically generate a transcript
201
+ if ($(media).data('transcript-div') !== undefined && $(media).data('transcript-div') !== "") {
202
+ this.transcriptDivLocation = $(media).data('transcript-div');
203
+ this.transcriptType = 'external';
204
+ }
205
+ else if ($(media).data('include-transcript') !== undefined) {
206
+ if ($(media).data('include-transcript') !== false) {
207
+ this.transcriptType = 'popup';
208
+ }
209
+ }
210
+ else {
211
+ this.transcriptType = 'popup';
212
+ }
213
+ }
214
+
215
+ // In "Lyrics Mode", line breaks in WebVTT caption files are supported in the transcript
216
+ // If false (default), line breaks are are removed from transcripts in order to provide a more seamless reading experience
217
+ // If true, line breaks are preserved, so content can be presented karaoke-style, or as lines in a poem
218
+ if ($(media).data('lyrics-mode') !== undefined && $(media).data('lyrics-mode') !== false) {
219
+ this.lyricsMode = true;
220
+ }
221
+ else {
222
+ this.lyricsMode = false;
223
+ }
224
+
225
+ // Transcript Title
226
+ if ($(media).data('transcript-title') !== undefined && $(media).data('transcript-title') !== "") {
227
+ this.transcriptTitle = $(media).data('transcript-title');
228
+ }
229
+ else {
230
+ // do nothing. The default title will be defined later (see transcript.js)
231
+ }
232
+
233
+ // Captions
234
+ // data-captions-position can be used to set the default captions position
235
+ // this is only the default, and can be overridden by user preferences
236
+ // valid values of data-captions-position are 'below' and 'overlay'
237
+ if ($(media).data('captions-position') === 'overlay') {
238
+ this.defaultCaptionsPosition = 'overlay';
239
+ }
240
+ else { // the default, even if not specified
241
+ this.defaultCaptionsPosition = 'below';
242
+ }
243
+
244
+ // Chapters
245
+ if ($(media).data('chapters-div') !== undefined && $(media).data('chapters-div') !== "") {
246
+ this.chaptersDivLocation = $(media).data('chapters-div');
247
+ }
248
+
249
+ if ($(media).data('chapters-title') !== undefined) {
250
+ // NOTE: empty string is valid; results in no title being displayed
251
+ this.chaptersTitle = $(media).data('chapters-title');
252
+ }
253
+
254
+ if ($(media).data('chapters-default') !== undefined && $(media).data('chapters-default') !== "") {
255
+ this.defaultChapter = $(media).data('chapters-default');
256
+ }
257
+ else {
258
+ this.defaultChapter = null;
259
+ }
260
+
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
+ // Slower/Faster buttons
274
+ // valid values of data-speed-icons are 'animals' (default) and 'arrows'
275
+ // 'animals' uses turtle and rabbit; 'arrows' uses up/down arrows
276
+ if ($(media).data('speed-icons') === 'arrows') {
277
+ this.speedIcons = 'arrows';
278
+ }
279
+ else {
280
+ this.speedIcons = 'animals';
281
+ }
282
+
283
+ // Seekbar
284
+ // valid values of data-seekbar-scope are 'chapter' and 'video'; will also accept 'chapters'
285
+ if ($(media).data('seekbar-scope') === 'chapter' || $(media).data('seekbar-scope') === 'chapters') {
286
+ this.seekbarScope = 'chapter';
287
+ }
288
+ else {
289
+ this.seekbarScope = 'video';
290
+ }
291
+
292
+ // YouTube
293
+ if ($(media).data('youtube-id') !== undefined && $(media).data('youtube-id') !== "") {
294
+ this.youTubeId = $(media).data('youtube-id');
295
+ }
296
+
297
+ if ($(media).data('youtube-desc-id') !== undefined && $(media).data('youtube-desc-id') !== "") {
298
+ this.youTubeDescId = $(media).data('youtube-desc-id');
299
+ }
300
+
301
+ if ($(media).data('youtube-nocookie') !== undefined && $(media).data('youtube-nocookie')) {
302
+ this.youTubeNoCookie = true;
303
+ }
304
+ else {
305
+ this.youTubeNoCookie = false;
306
+ }
307
+
308
+ // Vimeo
309
+ if ($(media).data('vimeo-id') !== undefined && $(media).data('vimeo-id') !== "") {
310
+ this.vimeoId = $(media).data('vimeo-id');
311
+ }
312
+ if ($(media).data('vimeo-desc-id') !== undefined && $(media).data('vimeo-desc-id') !== "") {
313
+ this.vimeoDescId = $(media).data('vimeo-desc-id');
314
+ }
315
+
316
+ // Icon type
317
+ // By default, AblePlayer 3.0.33 and higher uses SVG icons for the player controls
318
+ // Fallback for browsers that don't support SVG is scalable icomoon fonts
319
+ // Ultimate fallback is images, if the user has a custom style sheet that overrides font-family
320
+ // Use data-icon-type to force controls to use either 'svg', 'font', or 'images'
321
+ this.iconType = 'font';
322
+ this.forceIconType = false;
323
+ if ($(media).data('icon-type') !== undefined && $(media).data('icon-type') !== "") {
324
+ var iconType = $(media).data('icon-type');
325
+ if (iconType === 'font' || iconType == 'image' || iconType == 'svg') {
326
+ this.iconType = iconType;
327
+ this.forceIconType = true;
328
+ }
329
+ }
330
+
331
+ if ($(media).data('allow-fullscreen') !== undefined && $(media).data('allow-fullscreen') === false) {
332
+ this.allowFullScreen = false;
333
+ }
334
+ else {
335
+ this.allowFullScreen = true;
336
+ }
337
+
338
+ // Seek interval
339
+ // Number of seconds to seek forward or back with Rewind & Forward buttons
340
+ // Unless specified with data-seek-interval, the default value is re-calculated in initialize.js > setSeekInterval();
341
+ // Calculation attempts to intelligently assign a reasonable interval based on media length
342
+ this.defaultSeekInterval = 10;
343
+ this.useFixedSeekInterval = false;
344
+ if ($(media).data('seek-interval') !== undefined && $(media).data('seek-interval') !== "") {
345
+ var seekInterval = $(media).data('seek-interval');
346
+ if (/^[1-9][0-9]*$/.test(seekInterval)) { // must be a whole number greater than 0
347
+ this.seekInterval = seekInterval;
348
+ this.useFixedSeekInterval = true; // do not override with calculuation
349
+ }
350
+ }
351
+
352
+ // Now Playing
353
+ // Shows "Now Playing:" plus the title of the current track above player
354
+ // Only used if there is a playlist
355
+ if ($(media).data('show-now-playing') !== undefined && $(media).data('show-now-playing') === false) {
356
+ this.showNowPlaying = false;
357
+ }
358
+ else {
359
+ this.showNowPlaying = true;
360
+ }
361
+
362
+ // TTML support (experimental); enabled for testing with data-use-ttml (Boolean)
363
+ if ($(media).data('use-ttml') !== undefined) {
364
+ this.useTtml = true;
365
+ // The following may result in a console error.
366
+ this.convert = require('xml-js');
367
+ }
368
+ else {
369
+ this.useTtml = false;
370
+ }
371
+
372
+ // Fallback
373
+ // The only supported fallback content as of version 4.0 is:
374
+ // 1. Content nested within the <audio> or <video> element.
375
+ // 2. A standard localized message (see buildplayer.js > provideFallback()
376
+ // The data-test-fallback attribute can be used to test the fallback solution in any browser
377
+ if ($(media).data('test-fallback') !== undefined && $(media).data('test-fallback') !== false) {
378
+ this.testFallback = true;
379
+ }
380
+
381
+ // Language
382
+ this.lang = 'en';
383
+ if ($(media).data('lang') !== undefined && $(media).data('lang') !== "") {
384
+ var lang = $(media).data('lang');
385
+ if (lang.length == 2) {
386
+ this.lang = lang;
387
+ }
388
+ }
389
+ // Player language is determined as follows (in translation.js > getTranslationText() ):
390
+ // 1. Lang attributes on <html> or <body>, if a matching translation file is available
391
+ // 2. The value of this.lang, if a matching translation file is available
392
+ // 3. English
393
+ // To override this formula and force #2 to take precedence over #1, set data-force-lang="true"
394
+ if ($(media).data('force-lang') !== undefined && $(media).data('force-lang') !== false) {
395
+ this.forceLang = true;
396
+ }
397
+ else {
398
+ this.forceLang = false;
399
+ }
400
+
401
+ // Metadata Tracks
402
+ if ($(media).data('meta-type') !== undefined && $(media).data('meta-type') !== "") {
403
+ this.metaType = $(media).data('meta-type');
404
+ }
405
+
406
+ if ($(media).data('meta-div') !== undefined && $(media).data('meta-div') !== "") {
407
+ this.metaDiv = $(media).data('meta-div');
408
+ }
409
+
410
+ // Search
411
+ if ($(media).data('search') !== undefined && $(media).data('search') !== "") {
412
+ // conducting a search currently requires an external div in which to write the results
413
+ if ($(media).data('search-div') !== undefined && $(media).data('search-div') !== "") {
414
+ this.searchString = $(media).data('search');
415
+ this.searchDiv = $(media).data('search-div');
416
+ }
417
+
418
+ // Search Language
419
+ if ($(media).data('search-lang') !== undefined && $(media).data('search-lang') !== "") {
420
+ this.searchLang = $(media).data('search-lang');
421
+ }
422
+ else {
423
+ this.searchLang = null; // will change to final value of this.lang in translation.js > getTranslationText()
424
+ }
425
+
426
+ // conducting a search currently requires an external div in which to write the results
427
+ if ($(media).data('search-div') !== undefined && $(media).data('search-div') !== "") {
428
+ this.searchString = $(media).data('search');
429
+ this.searchDiv = $(media).data('search-div');
430
+ }
431
+ }
432
+
433
+ // Hide controls when video starts playing
434
+ // They will reappear again when user presses a key or moves the mouse
435
+ // As of v4.0, controls are hidden automatically on playback in fullscreen mode
436
+ if ($(media).data('hide-controls') !== undefined && $(media).data('hide-controls') !== false) {
437
+ this.hideControls = true;
438
+ this.hideControlsOriginal = true; // a copy of hideControls, since the former may change if user enters full screen mode
439
+ }
440
+ else {
441
+ this.hideControls = false;
442
+ this.hideControlsOriginal = false;
443
+ }
444
+
445
+ // Define built-in variables that CANNOT be overridden with HTML attributes
446
+ this.setDefaults();
447
+
448
+ ////////////////////////////////////////
449
+ //
450
+ // End assignment of default variables
451
+ //
452
+ ////////////////////////////////////////
453
+
454
+ this.ableIndex = AblePlayer.nextIndex;
455
+ AblePlayer.nextIndex += 1;
456
+
457
+ this.title = $(media).attr('title');
458
+
459
+ // populate translation object with localized versions of all labels and prompts
460
+ // use defer method to defer additional processing until text is retrieved
461
+ this.tt = {};
462
+ var thisObj = this;
463
+ $.when(this.getTranslationText()).then(
464
+ function () {
465
+ if (thisObj.countProperties(thisObj.tt) > 50) {
466
+ // close enough to ensure that most text variables are populated
467
+ thisObj.setup();
468
+ }
469
+ else {
470
+ // can't continue loading player with no text
471
+ thisObj.provideFallback();
472
+ }
473
+ }
474
+ );
475
+ };
476
+
477
+ // Index to increment every time new player is created.
478
+ AblePlayer.nextIndex = 0;
479
+
480
+ AblePlayer.prototype.setup = function() {
481
+
482
+ var thisObj = this;
483
+ this.initializing = true; // will remain true until entire sequence of function calls is complete
484
+ this.reinitialize().then(function () {
485
+ if (!thisObj.player) {
486
+ // No player for this media, show last-line fallback.
487
+ thisObj.provideFallback();
488
+ }
489
+ else {
490
+ thisObj.setupInstance().then(function () {
491
+ thisObj.setupInstancePlaylist();
492
+ if (!thisObj.hasPlaylist) {
493
+ // for playlists, recreatePlayer() is called from within cuePlaylistItem()
494
+ thisObj.recreatePlayer();
495
+ }
496
+ thisObj.initializing = false;
497
+ thisObj.playerCreated = true; // remains true until browser is refreshed
498
+ });
499
+ }
500
+ });
501
+ };
502
+
503
+ AblePlayer.getActiveDOMElement = function () {
504
+ var activeElement = document.activeElement;
505
+
506
+ // For shadow DOMs we need to keep digging down through the DOMs
507
+ while (activeElement.shadowRoot && activeElement.shadowRoot.activeElement) {
508
+ activeElement = activeElement.shadowRoot.activeElement;
509
+ }
510
+
511
+ return activeElement;
512
+ };
513
+
514
+ AblePlayer.localGetElementById = function(element, id) {
515
+ if (element.getRootNode)
516
+ {
517
+ // Use getRootNode() and querySelector() where supported (for shadow DOM support)
518
+ return $(element.getRootNode().querySelector('#' + id));
519
+ }
520
+ else
521
+ {
522
+ // If getRootNode is not supported it should be safe to use document.getElementById (since there is no shadow DOM support)
523
+ return $(document.getElementById(id));
524
+ }
525
+ };
526
+
527
+
528
+
529
+ AblePlayer.youtubeIframeAPIReady = false;
530
+ AblePlayer.loadingYoutubeIframeAPI = false;
540
531
  })(jQuery);