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,698 +1,877 @@
|
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
2
|
+
// Media events
|
|
3
|
+
AblePlayer.prototype.onMediaUpdateTime = function (duration, elapsed) {
|
|
4
|
+
|
|
5
|
+
// duration and elapsed are passed from callback functions of Vimeo API events
|
|
6
|
+
// duration is expressed as sss.xxx
|
|
7
|
+
// elapsed is expressed as sss.xxx
|
|
8
|
+
var thisObj = this;
|
|
9
|
+
|
|
10
|
+
this.getMediaTimes(duration,elapsed).then(function(mediaTimes) {
|
|
11
|
+
if (typeof duration === 'undefined') {
|
|
12
|
+
thisObj.duration = mediaTimes['duration'];
|
|
13
|
+
}
|
|
14
|
+
if (typeof elapsed === 'undefined') {
|
|
15
|
+
thisObj.elapsed = mediaTimes['elapsed'];
|
|
16
|
+
}
|
|
17
|
+
if (thisObj.swappingSrc && (typeof thisObj.swapTime !== 'undefined')) {
|
|
18
|
+
if (thisObj.swapTime === thisObj.elapsed) {
|
|
19
|
+
// described version been swapped and media has scrubbed to time of previous version
|
|
20
|
+
if (thisObj.playing) {
|
|
21
|
+
// resume playback
|
|
22
|
+
thisObj.playMedia();
|
|
23
|
+
// reset vars
|
|
24
|
+
thisObj.swappingSrc = false;
|
|
25
|
+
thisObj.swapTime = null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
else if (thisObj.startedPlaying) {
|
|
30
|
+
// do all the usual time-sync stuff during playback
|
|
31
|
+
if (thisObj.prefHighlight === 1) {
|
|
32
|
+
thisObj.highlightTranscript(thisObj.elapsed);
|
|
33
|
+
}
|
|
34
|
+
thisObj.updateCaption(thisObj.elapsed);
|
|
35
|
+
thisObj.showDescription(thisObj.elapsed);
|
|
36
|
+
thisObj.updateChapter(thisObj.elapsed);
|
|
37
|
+
thisObj.updateMeta(thisObj.elapsed);
|
|
38
|
+
thisObj.refreshControls('timeline', thisObj.duration, thisObj.elapsed);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
AblePlayer.prototype.onMediaPause = function () {
|
|
44
|
+
|
|
45
|
+
if (this.controlsHidden) {
|
|
46
|
+
this.fadeControls('in');
|
|
47
|
+
this.controlsHidden = false;
|
|
48
|
+
}
|
|
49
|
+
if (this.hideControlsTimeoutStatus === 'active') {
|
|
50
|
+
window.clearTimeout(this.hideControlsTimeout);
|
|
51
|
+
this.hideControlsTimeoutStatus = 'clear';
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
this.refreshControls('playpause');
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
AblePlayer.prototype.onMediaComplete = function () {
|
|
58
|
+
|
|
59
|
+
// if there's a playlist, advance to next item and start playing
|
|
60
|
+
if (this.hasPlaylist && !this.cueingPlaylistItem) {
|
|
61
|
+
if (this.playlistIndex === (this.$playlist.length - 1)) {
|
|
62
|
+
// this is the last track in the playlist
|
|
63
|
+
if (this.loop) {
|
|
64
|
+
this.playlistIndex = 0;
|
|
65
|
+
this.cueingPlaylistItem = true; // stopgap to prevent multiple firings
|
|
66
|
+
this.cuePlaylistItem(0);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// this is not the last track. Play the next one.
|
|
71
|
+
this.playlistIndex++;
|
|
72
|
+
this.cueingPlaylistItem = true; // stopgap to prevent multiple firings
|
|
73
|
+
this.cuePlaylistItem(this.playlistIndex)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
this.refreshControls('init');
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
AblePlayer.prototype.onMediaNewSourceLoad = function () {
|
|
80
|
+
|
|
81
|
+
if (this.cueingPlaylistItem) {
|
|
82
|
+
// this variable was set in order to address bugs caused by multiple firings of media 'end' event
|
|
83
|
+
// safe to reset now
|
|
84
|
+
this.cueingPlaylistItem = false;
|
|
85
|
+
}
|
|
86
|
+
if (this.swappingSrc === true) {
|
|
87
|
+
// new source file has just been loaded
|
|
88
|
+
if (this.swapTime > 0) {
|
|
89
|
+
// this.swappingSrc will be set to false after seek is complete
|
|
90
|
+
// see onMediaUpdateTime()
|
|
91
|
+
this.seekTo(this.swapTime);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
if (this.playing) {
|
|
95
|
+
// should be able to resume playback
|
|
96
|
+
this.playMedia();
|
|
97
|
+
}
|
|
98
|
+
this.swappingSrc = false; // swapping is finished
|
|
99
|
+
this.refreshControls('init');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// End Media events
|
|
105
|
+
|
|
106
|
+
AblePlayer.prototype.onWindowResize = function () {
|
|
107
|
+
|
|
108
|
+
if (this.fullscreen) { // replace isFullscreen() with a Boolean. see function for explanation
|
|
109
|
+
|
|
110
|
+
var newWidth, newHeight;
|
|
111
|
+
|
|
112
|
+
newWidth = $(window).width();
|
|
113
|
+
|
|
114
|
+
// haven't isolated why, but some browsers return an innerHeight that's 20px too tall in fullscreen mode
|
|
115
|
+
// Test results:
|
|
116
|
+
// Browsers that require a 20px adjustment: Firefox, IE11 (Trident), Edge
|
|
117
|
+
if (this.isUserAgent('Firefox') || this.isUserAgent('Trident') || this.isUserAgent('Edge')) {
|
|
118
|
+
newHeight = window.innerHeight - this.$playerDiv.outerHeight() - 20;
|
|
119
|
+
}
|
|
120
|
+
else if (window.outerHeight >= window.innerHeight) {
|
|
121
|
+
// Browsers that do NOT require adjustment: Chrome, Safari, Opera, MSIE 10
|
|
122
|
+
newHeight = window.innerHeight - this.$playerDiv.outerHeight();
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// Observed in Safari 9.0.1 on Mac OS X: outerHeight is actually less than innerHeight
|
|
126
|
+
// Maybe a bug, or maybe window.outerHeight is already adjusted for controller height(?)
|
|
127
|
+
// No longer observed in Safari 9.0.2
|
|
128
|
+
newHeight = window.outerHeight;
|
|
129
|
+
}
|
|
130
|
+
if (!this.$descDiv.is(':hidden')) {
|
|
131
|
+
newHeight -= this.$descDiv.height();
|
|
132
|
+
}
|
|
133
|
+
this.positionCaptions('overlay');
|
|
134
|
+
}
|
|
135
|
+
else { // not fullscreen
|
|
136
|
+
if (this.restoringAfterFullScreen) {
|
|
137
|
+
newWidth = this.preFullScreenWidth;
|
|
138
|
+
newHeight = this.preFullScreenHeight;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// not restoring after full screen
|
|
142
|
+
newWidth = this.$ableWrapper.width();
|
|
143
|
+
if (typeof this.aspectRatio !== 'undefined') {
|
|
144
|
+
newHeight = Math.round(newWidth / this.aspectRatio);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// not likely, since this.aspectRatio is defined during intialization
|
|
148
|
+
// however, this is a fallback scenario just in case
|
|
149
|
+
newHeight = this.$ableWrapper.height();
|
|
150
|
+
}
|
|
151
|
+
this.positionCaptions(); // reset with this.prefCaptionsPosition
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
this.resizePlayer(newWidth, newHeight);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
AblePlayer.prototype.addSeekbarListeners = function () {
|
|
158
|
+
|
|
159
|
+
var thisObj = this;
|
|
160
|
+
|
|
161
|
+
// Handle seek bar events.
|
|
162
|
+
this.seekBar.bodyDiv.on('startTracking', function (e) {
|
|
163
|
+
thisObj.pausedBeforeTracking = thisObj.paused;
|
|
164
|
+
thisObj.pauseMedia();
|
|
165
|
+
}).on('tracking', function (e, position) {
|
|
166
|
+
// Scrub transcript, captions, and metadata.
|
|
167
|
+
thisObj.highlightTranscript(position);
|
|
168
|
+
thisObj.updateCaption(position);
|
|
169
|
+
thisObj.showDescription(position);
|
|
170
|
+
thisObj.updateChapter(thisObj.convertChapterTimeToVideoTime(position));
|
|
171
|
+
thisObj.updateMeta(position);
|
|
172
|
+
thisObj.refreshControls('init');
|
|
173
|
+
}).on('stopTracking', function (e, position) {
|
|
174
|
+
if (thisObj.useChapterTimes) {
|
|
175
|
+
thisObj.seekTo(thisObj.convertChapterTimeToVideoTime(position));
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
thisObj.seekTo(position);
|
|
179
|
+
}
|
|
180
|
+
if (!thisObj.pausedBeforeTracking) {
|
|
181
|
+
setTimeout(function () {
|
|
182
|
+
thisObj.playMedia();
|
|
183
|
+
}, 200);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
AblePlayer.prototype.onClickPlayerButton = function (el) {
|
|
189
|
+
|
|
190
|
+
// 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?
|
|
191
|
+
var whichButton = $(el).attr('class').split(' ')[0].substr(20);
|
|
192
|
+
if (whichButton === 'play') {
|
|
193
|
+
this.handlePlay();
|
|
194
|
+
}
|
|
195
|
+
else if (whichButton === 'restart') {
|
|
196
|
+
this.seekTrigger = 'restart';
|
|
197
|
+
this.handleRestart();
|
|
198
|
+
}
|
|
199
|
+
else if (whichButton === 'rewind') {
|
|
200
|
+
this.seekTrigger = 'rewind';
|
|
201
|
+
this.handleRewind();
|
|
202
|
+
}
|
|
203
|
+
else if (whichButton === 'forward') {
|
|
204
|
+
this.seekTrigger = 'forward';
|
|
205
|
+
this.handleFastForward();
|
|
206
|
+
}
|
|
207
|
+
else if (whichButton === 'mute') {
|
|
208
|
+
this.handleMute();
|
|
209
|
+
}
|
|
210
|
+
else if (whichButton === 'volume') {
|
|
211
|
+
this.handleVolume();
|
|
212
|
+
}
|
|
213
|
+
else if (whichButton === 'faster') {
|
|
214
|
+
this.handleRateIncrease();
|
|
215
|
+
}
|
|
216
|
+
else if (whichButton === 'slower') {
|
|
217
|
+
this.handleRateDecrease();
|
|
218
|
+
}
|
|
219
|
+
else if (whichButton === 'captions') {
|
|
220
|
+
this.handleCaptionToggle();
|
|
221
|
+
}
|
|
222
|
+
else if (whichButton === 'chapters') {
|
|
223
|
+
this.handleChapters();
|
|
224
|
+
}
|
|
225
|
+
else if (whichButton === 'descriptions') {
|
|
226
|
+
this.handleDescriptionToggle();
|
|
227
|
+
}
|
|
228
|
+
else if (whichButton === 'sign') {
|
|
229
|
+
this.handleSignToggle();
|
|
230
|
+
}
|
|
231
|
+
else if (whichButton === 'preferences') {
|
|
232
|
+
this.handlePrefsClick();
|
|
233
|
+
}
|
|
234
|
+
else if (whichButton === 'help') {
|
|
235
|
+
this.handleHelpClick();
|
|
236
|
+
}
|
|
237
|
+
else if (whichButton === 'transcript') {
|
|
238
|
+
this.handleTranscriptToggle();
|
|
239
|
+
}
|
|
240
|
+
else if (whichButton === 'fullscreen') {
|
|
241
|
+
this.clickedFullscreenButton = true;
|
|
242
|
+
this.handleFullscreenToggle();
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
AblePlayer.prototype.okToHandleKeyPress = function () {
|
|
247
|
+
|
|
248
|
+
// returns true unless user's focus is on a UI element
|
|
249
|
+
// that is likely to need supported keystrokes, including space
|
|
250
|
+
|
|
251
|
+
var activeElement = AblePlayer.getActiveDOMElement();
|
|
252
|
+
|
|
253
|
+
if ($(activeElement).prop('tagName') === 'INPUT') {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
AblePlayer.prototype.onPlayerKeyPress = function (e) {
|
|
262
|
+
|
|
263
|
+
// handle keystrokes (using DHTML Style Guide recommended key combinations)
|
|
264
|
+
// https://web.archive.org/web/20130127004544/http://dev.aol.com/dhtml_style_guide/#mediaplayer
|
|
265
|
+
// Modifier keys Alt + Ctrl are on by default, but can be changed within Preferences
|
|
266
|
+
// NOTE #1: Style guide only supports Play/Pause, Stop, Mute, Captions, & Volume Up & Down
|
|
267
|
+
// The rest are reasonable best choices
|
|
268
|
+
// NOTE #2: If there are multiple players on a single page, keystroke handlers
|
|
269
|
+
// are only bound to the FIRST player
|
|
270
|
+
// NOTE #3: The DHTML Style Guide is now the W3C WAI-ARIA Authoring Guide and has undergone many revisions
|
|
271
|
+
// including removal of the "media player" design pattern. There's an issue about that:
|
|
272
|
+
// https://github.com/w3c/aria-practices/issues/27
|
|
273
|
+
|
|
274
|
+
if (!this.okToHandleKeyPress()) {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
// Convert to lower case.
|
|
278
|
+
var which = e.which;
|
|
279
|
+
|
|
280
|
+
if (which >= 65 && which <= 90) {
|
|
281
|
+
which += 32;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Only use keypress to control player if focus is NOT on a form field or contenteditable element
|
|
285
|
+
if (!(
|
|
286
|
+
$(':focus').is('[contenteditable]') ||
|
|
287
|
+
$(':focus').is('input') ||
|
|
288
|
+
$(':focus').is('textarea') ||
|
|
289
|
+
$(':focus').is('select') ||
|
|
290
|
+
e.target.hasAttribute('contenteditable') ||
|
|
291
|
+
e.target.tagName === 'INPUT' ||
|
|
292
|
+
e.target.tagName === 'TEXTAREA' ||
|
|
293
|
+
e.target.tagName === 'SELECT'
|
|
294
|
+
)){
|
|
295
|
+
if (which === 27) { // escape
|
|
296
|
+
this.closePopups();
|
|
297
|
+
}
|
|
298
|
+
else if (which === 32) { // spacebar = play/pause
|
|
299
|
+
if (this.$ableWrapper.find('.able-controller button:focus').length === 0) {
|
|
300
|
+
// only toggle play if a button does not have focus
|
|
301
|
+
// if a button has focus, space should activate that button
|
|
302
|
+
this.handlePlay();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
else if (which === 112) { // p = play/pause
|
|
306
|
+
if (this.usingModifierKeys(e)) {
|
|
307
|
+
this.handlePlay();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else if (which === 115) { // s = stop (now restart)
|
|
311
|
+
if (this.usingModifierKeys(e)) {
|
|
312
|
+
this.handleRestart();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
else if (which === 109) { // m = mute
|
|
316
|
+
if (this.usingModifierKeys(e)) {
|
|
317
|
+
this.handleMute();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
else if (which === 118) { // v = volume
|
|
321
|
+
if (this.usingModifierKeys(e)) {
|
|
322
|
+
this.handleVolume();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else if (which >= 49 && which <= 57) { // set volume 1-9
|
|
326
|
+
if (this.usingModifierKeys(e)) {
|
|
327
|
+
this.handleVolume(which);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
else if (which === 99) { // c = caption toggle
|
|
331
|
+
if (this.usingModifierKeys(e)) {
|
|
332
|
+
this.handleCaptionToggle();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
else if (which === 100) { // d = description
|
|
336
|
+
if (this.usingModifierKeys(e)) {
|
|
337
|
+
this.handleDescriptionToggle();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
else if (which === 102) { // f = forward
|
|
341
|
+
if (this.usingModifierKeys(e)) {
|
|
342
|
+
this.handleFastForward();
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
else if (which === 114) { // r = rewind
|
|
346
|
+
if (this.usingModifierKeys(e)) {
|
|
347
|
+
this.handleRewind();
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
else if (which === 101) { // e = preferences
|
|
351
|
+
if (this.usingModifierKeys(e)) {
|
|
352
|
+
this.handlePrefsClick();
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
else if (which === 13) { // Enter
|
|
356
|
+
var thisElement = $(document.activeElement);
|
|
357
|
+
if (thisElement.prop('tagName') === 'SPAN') {
|
|
358
|
+
// register a click on this SPAN
|
|
359
|
+
// if it's a transcript span the transcript span click handler will take over
|
|
360
|
+
thisElement.click();
|
|
361
|
+
}
|
|
362
|
+
else if (thisElement.prop('tagName') === 'LI') {
|
|
363
|
+
thisElement.click();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
AblePlayer.prototype.addHtml5MediaListeners = function () {
|
|
370
|
+
|
|
371
|
+
var thisObj = this;
|
|
372
|
+
|
|
373
|
+
// NOTE: iOS and some browsers do not support autoplay
|
|
374
|
+
// and no events are triggered until media begins to play
|
|
375
|
+
// Able Player gets around this by automatically loading media in some circumstances
|
|
376
|
+
// (see initialize.js > initPlayer() for details)
|
|
377
|
+
this.$media
|
|
378
|
+
.on('emptied',function() {
|
|
379
|
+
// do something
|
|
380
|
+
})
|
|
381
|
+
.on('loadedmetadata',function() {
|
|
382
|
+
thisObj.onMediaNewSourceLoad();
|
|
383
|
+
})
|
|
384
|
+
.on('canplay',function() {
|
|
385
|
+
// previously handled seeking to startTime here
|
|
386
|
+
// but it's probably safer to wait for canplaythrough
|
|
387
|
+
// so we know player can seek ahead to anything
|
|
388
|
+
})
|
|
389
|
+
.on('canplaythrough',function() {
|
|
390
|
+
if (thisObj.userClickedPlaylist) {
|
|
391
|
+
if (!thisObj.startedPlaying) {
|
|
392
|
+
// start playing; no further user action is required
|
|
393
|
+
thisObj.playMedia();
|
|
394
|
+
}
|
|
395
|
+
thisObj.userClickedPlaylist = false; // reset
|
|
396
|
+
}
|
|
397
|
+
if (thisObj.seekTrigger == 'restart' || thisObj.seekTrigger == 'chapter' || thisObj.seekTrigger == 'transcript') {
|
|
398
|
+
// by clicking on any of these elements, user is likely intending to play
|
|
399
|
+
// Not included: elements where user might click multiple times in succession
|
|
400
|
+
// (i.e., 'rewind', 'forward', or seekbar); for these, video remains paused until user initiates play
|
|
401
|
+
thisObj.playMedia();
|
|
402
|
+
}
|
|
403
|
+
else if (!thisObj.startedPlaying) {
|
|
404
|
+
if (thisObj.startTime > 0) {
|
|
405
|
+
if (thisObj.seeking) {
|
|
406
|
+
// a seek has already been initiated
|
|
407
|
+
// since canplaythrough has been triggered, the seek is complete
|
|
408
|
+
thisObj.seeking = false;
|
|
409
|
+
if (thisObj.autoplay || thisObj.okToPlay) {
|
|
410
|
+
thisObj.playMedia();
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
// haven't started seeking yet
|
|
415
|
+
thisObj.seekTo(thisObj.startTime);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
else if (thisObj.defaultChapter && typeof thisObj.selectedChapters !== 'undefined') {
|
|
419
|
+
thisObj.seekToChapter(thisObj.defaultChapter);
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
// there is no startTime, therefore no seeking required
|
|
423
|
+
if (thisObj.autoplay || thisObj.okToPlay) {
|
|
424
|
+
thisObj.playMedia();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
else if (thisObj.hasPlaylist) {
|
|
429
|
+
if ((thisObj.playlistIndex !== thisObj.$playlist.length) || thisObj.loop) {
|
|
430
|
+
// this is not the last track in the playlist (OR playlist is looping so it doesn't matter)
|
|
431
|
+
thisObj.playMedia();
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
// already started playing
|
|
436
|
+
// we're here because a new media source has been loaded and is ready to resume playback
|
|
437
|
+
thisObj.getPlayerState().then(function(currentState) {
|
|
438
|
+
if (thisObj.swappingSrc && currentState === 'stopped') {
|
|
439
|
+
// Safari is the only browser that returns value of 'stopped' (observed in 12.0.1 on MacOS)
|
|
440
|
+
// This prevents 'timeupdate' events from triggering, which prevents the new media src
|
|
441
|
+
// from resuming playback at swapTime
|
|
442
|
+
// This is a hack to jump start Safari
|
|
443
|
+
thisObj.startedPlaying = false;
|
|
444
|
+
if (thisObj.swapTime > 0) {
|
|
445
|
+
thisObj.seekTo(thisObj.swapTime);
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
thisObj.playMedia();
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
})
|
|
454
|
+
.on('play',function() {
|
|
455
|
+
// both 'play' and 'playing' seem to be fired in all browsers (including IE11)
|
|
456
|
+
// therefore, doing nothing here & doing everything when 'playing' is triggered
|
|
457
|
+
thisObj.refreshControls('playpause');
|
|
458
|
+
})
|
|
459
|
+
.on('playing',function() {
|
|
460
|
+
thisObj.playing = true;
|
|
461
|
+
thisObj.paused = false;
|
|
462
|
+
thisObj.refreshControls('playpause');
|
|
463
|
+
})
|
|
464
|
+
.on('ended',function() {
|
|
465
|
+
thisObj.playing = false;
|
|
466
|
+
thisObj.paused = true;
|
|
467
|
+
thisObj.onMediaComplete();
|
|
468
|
+
})
|
|
469
|
+
.on('progress', function() {
|
|
470
|
+
thisObj.refreshControls('timeline');
|
|
471
|
+
})
|
|
472
|
+
.on('waiting',function() {
|
|
473
|
+
// do something
|
|
474
|
+
// previously called refreshControls() here but this event probably doesn't warrant a refresh
|
|
475
|
+
})
|
|
476
|
+
.on('durationchange',function() {
|
|
477
|
+
// Display new duration.
|
|
478
|
+
thisObj.refreshControls('timeline');
|
|
479
|
+
})
|
|
480
|
+
.on('timeupdate',function() {
|
|
481
|
+
thisObj.onMediaUpdateTime(); // includes a call to refreshControls()
|
|
482
|
+
})
|
|
483
|
+
.on('pause',function() {
|
|
484
|
+
if (!thisObj.clickedPlay) {
|
|
485
|
+
// 'pause' was triggered automatically, not initiated by user
|
|
486
|
+
// this happens in some browsers (not Chrome, as of 70.x)
|
|
487
|
+
// when swapping source (e.g., between tracks in a playlist, or swapping description)
|
|
488
|
+
if (thisObj.hasPlaylist || thisObj.swappingSrc) {
|
|
489
|
+
// do NOT set playing to false.
|
|
490
|
+
// doing so prevents continual playback after new track is loaded
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
thisObj.playing = false;
|
|
494
|
+
thisObj.paused = true;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
thisObj.playing = false;
|
|
499
|
+
thisObj.paused = true;
|
|
500
|
+
}
|
|
501
|
+
thisObj.clickedPlay = false; // done with this variable
|
|
502
|
+
thisObj.onMediaPause(); // includes a call to refreshControls()
|
|
503
|
+
})
|
|
504
|
+
.on('ratechange',function() {
|
|
505
|
+
// do something
|
|
506
|
+
})
|
|
507
|
+
.on('volumechange',function() {
|
|
508
|
+
thisObj.volume = thisObj.getVolume();
|
|
509
|
+
if (thisObj.debug) {
|
|
510
|
+
console.log('media volume change to ' + thisObj.volume + ' (' + thisObj.volumeButton + ')');
|
|
511
|
+
}
|
|
512
|
+
})
|
|
513
|
+
.on('error',function() {
|
|
514
|
+
if (thisObj.debug) {
|
|
515
|
+
switch (thisObj.media.error.code) {
|
|
516
|
+
case 1:
|
|
517
|
+
console.log('HTML5 Media Error: MEDIA_ERR_ABORTED');
|
|
518
|
+
break;
|
|
519
|
+
case 2:
|
|
520
|
+
console.log('HTML5 Media Error: MEDIA_ERR_NETWORK ');
|
|
521
|
+
break;
|
|
522
|
+
case 3:
|
|
523
|
+
console.log('HTML5 Media Error: MEDIA_ERR_DECODE ');
|
|
524
|
+
break;
|
|
525
|
+
case 4:
|
|
526
|
+
console.log('HTML5 Media Error: MEDIA_ERR_SRC_NOT_SUPPORTED ');
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
AblePlayer.prototype.addVimeoListeners = function () {
|
|
534
|
+
|
|
535
|
+
// The following content is orphaned. It was in 'canplaythrough' but there's no equivalent event in Vimeo.
|
|
536
|
+
// Maybe it should go under 'loaded' or 'progress' ???
|
|
537
|
+
/*
|
|
538
|
+
if (thisObj.userClickedPlaylist) {
|
|
539
|
+
if (!thisObj.startedPlaying) {
|
|
540
|
+
// start playing; no further user action is required
|
|
541
|
+
thisObj.playMedia();
|
|
542
|
+
}
|
|
543
|
+
thisObj.userClickedPlaylist = false; // reset
|
|
544
|
+
}
|
|
545
|
+
if (thisObj.seekTrigger == 'restart' || thisObj.seekTrigger == 'chapter' || thisObj.seekTrigger == 'transcript') {
|
|
546
|
+
// by clicking on any of these elements, user is likely intending to play
|
|
547
|
+
// Not included: elements where user might click multiple times in succession
|
|
548
|
+
// (i.e., 'rewind', 'forward', or seekbar); for these, video remains paused until user initiates play
|
|
549
|
+
thisObj.playMedia();
|
|
550
|
+
}
|
|
551
|
+
else if (!thisObj.startedPlaying) {
|
|
552
|
+
if (thisObj.startTime > 0) {
|
|
553
|
+
if (thisObj.seeking) {
|
|
554
|
+
// a seek has already been initiated
|
|
555
|
+
// since canplaythrough has been triggered, the seek is complete
|
|
556
|
+
thisObj.seeking = false;
|
|
557
|
+
if (thisObj.autoplay || thisObj.okToPlay) {
|
|
558
|
+
thisObj.playMedia();
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
// haven't started seeking yet
|
|
563
|
+
thisObj.seekTo(thisObj.startTime);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
else if (thisObj.defaultChapter && typeof thisObj.selectedChapters !== 'undefined') {
|
|
567
|
+
thisObj.seekToChapter(thisObj.defaultChapter);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
// there is no startTime, therefore no seeking required
|
|
571
|
+
if (thisObj.autoplay || thisObj.okToPlay) {
|
|
572
|
+
thisObj.playMedia();
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
else if (thisObj.hasPlaylist) {
|
|
577
|
+
if ((thisObj.playlistIndex !== thisObj.$playlist.length) || thisObj.loop) {
|
|
578
|
+
// this is not the last track in the playlist (OR playlist is looping so it doesn't matter)
|
|
579
|
+
thisObj.playMedia();
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
// already started playing
|
|
584
|
+
// we're here because a new media source has been loaded and is ready to resume playback
|
|
585
|
+
thisObj.getPlayerState().then(function(currentState) {
|
|
586
|
+
if (thisObj.swappingSrc && currentState === 'stopped') {
|
|
587
|
+
// Safari is the only browser that returns value of 'stopped' (observed in 12.0.1 on MacOS)
|
|
588
|
+
// This prevents 'timeupdate' events from triggering, which prevents the new media src
|
|
589
|
+
// from resuming playback at swapTime
|
|
590
|
+
// This is a hack to jump start Safari
|
|
591
|
+
thisObj.startedPlaying = false;
|
|
592
|
+
if (thisObj.swapTime > 0) {
|
|
593
|
+
thisObj.seekTo(thisObj.swapTime);
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
thisObj.playMedia();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
*/
|
|
603
|
+
|
|
604
|
+
var thisObj = this;
|
|
605
|
+
|
|
606
|
+
// Vimeo doesn't seem to support chaining of on() functions
|
|
607
|
+
// so each event listener must be attached separately
|
|
608
|
+
this.vimeoPlayer.on('loaded', function(vimeoId) {
|
|
609
|
+
// Triggered when a new video is loaded in the player
|
|
610
|
+
thisObj.onMediaNewSourceLoad();
|
|
611
|
+
});
|
|
612
|
+
this.vimeoPlayer.on('play', function(data) {
|
|
613
|
+
// Triggered when the video plays
|
|
614
|
+
thisObj.playing = true;
|
|
615
|
+
thisObj.startedPlaying = true;
|
|
616
|
+
thisObj.paused = false;
|
|
617
|
+
thisObj.refreshControls('playpause');
|
|
618
|
+
});
|
|
619
|
+
this.vimeoPlayer.on('ended', function(data) {
|
|
620
|
+
// Triggered any time the video playback reaches the end.
|
|
621
|
+
// Note: when loop is turned on, the ended event will not fire.
|
|
622
|
+
thisObj.playing = false;
|
|
623
|
+
thisObj.paused = true;
|
|
624
|
+
thisObj.onMediaComplete();
|
|
625
|
+
});
|
|
626
|
+
this.vimeoPlayer.on('bufferstart', function() {
|
|
627
|
+
// Triggered when buffering starts in the player.
|
|
628
|
+
// This is also triggered during preload and while seeking.
|
|
629
|
+
// There is no associated data with this event.
|
|
630
|
+
});
|
|
631
|
+
this.vimeoPlayer.on('bufferend', function() {
|
|
632
|
+
// Triggered when buffering ends in the player.
|
|
633
|
+
// This is also triggered at the end of preload and seeking.
|
|
634
|
+
// There is no associated data with this event.
|
|
635
|
+
});
|
|
636
|
+
this.vimeoPlayer.on('progress', function(data) {
|
|
637
|
+
// Triggered as the video is loaded.
|
|
638
|
+
// Reports back the amount of the video that has been buffered (NOT the amount played)
|
|
639
|
+
// Data has keys duration, percent, and seconds
|
|
640
|
+
});
|
|
641
|
+
this.vimeoPlayer.on('seeking', function(data) {
|
|
642
|
+
// Triggered when the player starts seeking to a specific time.
|
|
643
|
+
// A timeupdate event will also be fired at the same time.
|
|
644
|
+
});
|
|
645
|
+
this.vimeoPlayer.on('seeked', function(data) {
|
|
646
|
+
// Triggered when the player seeks to a specific time.
|
|
647
|
+
// A timeupdate event will also be fired at the same time.
|
|
648
|
+
});
|
|
649
|
+
this.vimeoPlayer.on('timeupdate',function(data) {
|
|
650
|
+
// Triggered as the currentTime of the video updates.
|
|
651
|
+
// It generally fires every 250ms, but it may vary depending on the browser.
|
|
652
|
+
thisObj.onMediaUpdateTime(data['duration'], data['seconds']);
|
|
653
|
+
});
|
|
654
|
+
this.vimeoPlayer.on('pause',function(data) {
|
|
655
|
+
// Triggered when the video pauses
|
|
656
|
+
if (!thisObj.clickedPlay) {
|
|
657
|
+
// 'pause' was triggered automatically, not initiated by user
|
|
658
|
+
// this happens in some browsers (not Chrome, as of 70.x)
|
|
659
|
+
// when swapping source (e.g., between tracks in a playlist, or swapping description)
|
|
660
|
+
if (thisObj.hasPlaylist || thisObj.swappingSrc) {
|
|
661
|
+
// do NOT set playing to false.
|
|
662
|
+
// doing so prevents continual playback after new track is loaded
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
thisObj.playing = false;
|
|
666
|
+
thisObj.paused = true;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
thisObj.playing = false;
|
|
671
|
+
thisObj.paused = true;
|
|
672
|
+
}
|
|
673
|
+
thisObj.clickedPlay = false; // done with this variable
|
|
674
|
+
thisObj.onMediaPause();
|
|
675
|
+
thisObj.refreshControls('playpause');
|
|
676
|
+
});
|
|
677
|
+
this.vimeoPlayer.on('playbackratechange',function(data) {
|
|
678
|
+
// Triggered when the playback rate of the video in the player changes.
|
|
679
|
+
// The ability to change rate can be disabled by the creator
|
|
680
|
+
// and the event will not fire for those videos.
|
|
681
|
+
// data contains one key: 'playbackRate'
|
|
682
|
+
thisObj.vimeoPlaybackRate = data['playbackRate'];
|
|
683
|
+
});
|
|
684
|
+
this.vimeoPlayer.on('texttrackchange', function(data) {
|
|
685
|
+
// Triggered when the active text track (captions/subtitles) changes.
|
|
686
|
+
// The values will be null if text tracks are turned off.
|
|
687
|
+
// data contains three keys: kind, label, language
|
|
688
|
+
});
|
|
689
|
+
this.vimeoPlayer.on('volumechange',function(data) {
|
|
690
|
+
// Triggered when the volume in the player changes.
|
|
691
|
+
// Some devices do not support setting the volume of the video
|
|
692
|
+
// independently from the system volume,
|
|
693
|
+
// so this event will never fire on those devices.
|
|
694
|
+
thisObj.volume = data['volume'] * 10;
|
|
695
|
+
});
|
|
696
|
+
this.vimeoPlayer.on('error',function(data) {
|
|
697
|
+
// do something with the available data
|
|
698
|
+
// data contains three keys: message, method, name
|
|
699
|
+
// message: A user-friendly error message
|
|
700
|
+
// method: The Vimeo API method call that triggered the error
|
|
701
|
+
// name: Name of the error (not necesssarily user-friendly)
|
|
702
|
+
});
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
AblePlayer.prototype.addEventListeners = function () {
|
|
706
|
+
|
|
707
|
+
var thisObj, whichButton, thisElement;
|
|
708
|
+
|
|
709
|
+
// Save the current object context in thisObj for use with inner functions.
|
|
710
|
+
thisObj = this;
|
|
711
|
+
|
|
712
|
+
// Appropriately resize media player for full screen.
|
|
713
|
+
$(window).resize(function () {
|
|
714
|
+
thisObj.onWindowResize();
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
// Refresh player if it changes from hidden to visible
|
|
718
|
+
// There is no event triggered by a change in visibility
|
|
719
|
+
// but MutationObserver works in most browsers (but NOT in IE 10 or earlier)
|
|
720
|
+
// http://caniuse.com/#feat=mutationobserver
|
|
721
|
+
if (window.MutationObserver) {
|
|
722
|
+
var target = this.$ableDiv[0];
|
|
723
|
+
var observer = new MutationObserver(function(mutations) {
|
|
724
|
+
mutations.forEach(function(mutation) {
|
|
725
|
+
if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
|
|
726
|
+
// the player's style attribute has changed. Check to see if it's visible
|
|
727
|
+
if (thisObj.$ableDiv.is(':visible')) {
|
|
728
|
+
thisObj.refreshControls('init');
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
});
|
|
733
|
+
var config = { attributes: true, childList: true, characterData: true };
|
|
734
|
+
observer.observe(target, config);
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
// browser doesn't support MutationObserver
|
|
738
|
+
// TODO: Figure out an alternative solution for this rare use case in older browsers
|
|
739
|
+
// See example in buildplayer.js > useSvg()
|
|
740
|
+
}
|
|
741
|
+
if (typeof this.seekBar !== 'undefined') {
|
|
742
|
+
this.addSeekbarListeners();
|
|
743
|
+
}
|
|
744
|
+
else {
|
|
745
|
+
// wait a bit and try again
|
|
746
|
+
// TODO: Should set this up to keep trying repeatedly.
|
|
747
|
+
// Seekbar listeners are critical.
|
|
748
|
+
setTimeout(function() {
|
|
749
|
+
if (typeof thisObj.seekBar !== 'undefined') {
|
|
750
|
+
thisObj.addSeekbarListeners();
|
|
751
|
+
}
|
|
752
|
+
},2000);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// handle clicks on player buttons
|
|
756
|
+
this.$controllerDiv.find('button').on('click',function(e){
|
|
757
|
+
e.stopPropagation();
|
|
758
|
+
thisObj.onClickPlayerButton(this);
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
// handle clicks (left only) anywhere on the page. If any popups are open, close them.
|
|
762
|
+
$(document).on('click',function(e) {
|
|
763
|
+
|
|
764
|
+
if (e.button !== 0) { // not a left click
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
if ($('.able-popup:visible').length || $('.able-volume-popup:visible')) {
|
|
768
|
+
// at least one popup is visible
|
|
769
|
+
thisObj.closePopups();
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
// handle mouse movement over player; make controls visible again if hidden
|
|
774
|
+
this.$ableDiv.on('mousemove',function() {
|
|
775
|
+
if (thisObj.controlsHidden) {
|
|
776
|
+
thisObj.fadeControls('in');
|
|
777
|
+
thisObj.controlsHidden = false;
|
|
778
|
+
// if there's already an active timeout, clear it and start timer again
|
|
779
|
+
if (thisObj.hideControlsTimeoutStatus === 'active') {
|
|
780
|
+
window.clearTimeout(thisObj.hideControlsTimeout);
|
|
781
|
+
thisObj.hideControlsTimeoutStatus = 'clear';
|
|
782
|
+
}
|
|
783
|
+
if (thisObj.hideControls) {
|
|
784
|
+
// after showing controls, hide them again after a brief timeout
|
|
785
|
+
thisObj.invokeHideControlsTimeout();
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
// if there's already an active timeout, clear it and start timer again
|
|
790
|
+
if (thisObj.hideControlsTimeoutStatus === 'active') {
|
|
791
|
+
window.clearTimeout(thisObj.hideControlsTimeout);
|
|
792
|
+
thisObj.hideControlsTimeoutStatus = 'clear';
|
|
793
|
+
if (thisObj.hideControls) {
|
|
794
|
+
thisObj.invokeHideControlsTimeout();
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
// if user presses a key from anywhere on the page, show player controls
|
|
801
|
+
$(document).keydown(function() {
|
|
802
|
+
if (thisObj.controlsHidden) {
|
|
803
|
+
thisObj.fadeControls('in');
|
|
804
|
+
thisObj.controlsHidden = false;
|
|
805
|
+
if (thisObj.hideControlsTimeoutStatus === 'active') {
|
|
806
|
+
window.clearTimeout(thisObj.hideControlsTimeout);
|
|
807
|
+
thisObj.hideControlsTimeoutStatus = 'clear';
|
|
808
|
+
}
|
|
809
|
+
if (thisObj.hideControls) {
|
|
810
|
+
// after showing controls, hide them again after a brief timeout
|
|
811
|
+
thisObj.invokeHideControlsTimeout();
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
else {
|
|
815
|
+
// controls are visible
|
|
816
|
+
// if there's already an active timeout, clear it and start timer again
|
|
817
|
+
if (thisObj.hideControlsTimeoutStatus === 'active') {
|
|
818
|
+
window.clearTimeout(thisObj.hideControlsTimeout);
|
|
819
|
+
thisObj.hideControlsTimeoutStatus = 'clear';
|
|
820
|
+
|
|
821
|
+
if (thisObj.hideControls) {
|
|
822
|
+
thisObj.invokeHideControlsTimeout();
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
// handle local keydown events if this isn't the only player on the page;
|
|
829
|
+
// otherwise these are dispatched by global handler (see ableplayer-base,js)
|
|
830
|
+
this.$ableDiv.keydown(function (e) {
|
|
831
|
+
if (AblePlayer.nextIndex > 1) {
|
|
832
|
+
thisObj.onPlayerKeyPress(e);
|
|
833
|
+
}
|
|
834
|
+
});
|
|
835
|
+
|
|
836
|
+
// transcript is not a child of this.$ableDiv
|
|
837
|
+
// therefore, must be added separately
|
|
838
|
+
if (this.$transcriptArea) {
|
|
839
|
+
this.$transcriptArea.keydown(function (e) {
|
|
840
|
+
if (AblePlayer.nextIndex > 1) {
|
|
841
|
+
thisObj.onPlayerKeyPress(e);
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// handle clicks on playlist items
|
|
847
|
+
if (this.$playlist) {
|
|
848
|
+
this.$playlist.click(function(e) {
|
|
849
|
+
if (!thisObj.userClickedPlaylist) {
|
|
850
|
+
// stopgap in case multiple clicks are fired on the same playlist item
|
|
851
|
+
thisObj.userClickedPlaylist = true; // will be set to false after new src is loaded & canplaythrough is triggered
|
|
852
|
+
thisObj.playlistIndex = $(this).index();
|
|
853
|
+
thisObj.cuePlaylistItem(thisObj.playlistIndex);
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// Also play/pause when clicking on the media.
|
|
859
|
+
this.$media.click(function () {
|
|
860
|
+
thisObj.handlePlay();
|
|
861
|
+
});
|
|
862
|
+
|
|
863
|
+
// add listeners for media events
|
|
864
|
+
if (this.player === 'html5') {
|
|
865
|
+
this.addHtml5MediaListeners();
|
|
866
|
+
}
|
|
867
|
+
else if (this.player === 'vimeo') {
|
|
868
|
+
this.addVimeoListeners();
|
|
869
|
+
}
|
|
870
|
+
else if (this.player === 'youtube') {
|
|
871
|
+
// Youtube doesn't give us time update events, so we just periodically generate them ourselves
|
|
872
|
+
setInterval(function () {
|
|
873
|
+
thisObj.onMediaUpdateTime();
|
|
874
|
+
}, 300);
|
|
875
|
+
}
|
|
876
|
+
};
|
|
698
877
|
})(jQuery);
|