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,599 +1,688 @@
1
1
  (function ($) {
2
2
 
3
- AblePlayer.prototype.injectTranscriptArea = function() {
4
-
5
- var thisObj = this;
6
-
7
- this.$transcriptArea = $('<div>', {
8
- 'class': 'able-transcript-area',
9
- 'tabindex': '-1'
10
- });
11
-
12
- this.$transcriptToolbar = $('<div>', {
13
- 'class': 'able-window-toolbar able-' + this.toolbarIconColor + '-controls'
14
- });
15
-
16
- this.$transcriptDiv = $('<div>', {
17
- 'class' : 'able-transcript'
18
- });
19
-
20
- // Transcript toolbar content:
21
- this.$autoScrollTranscriptCheckbox = $('<input id="autoscroll-transcript-checkbox" type="checkbox">');
22
- this.$transcriptToolbar.append($('<label for="autoscroll-transcript-checkbox">' + this.tt.autoScroll + ': </label>'), this.$autoScrollTranscriptCheckbox);
23
-
24
- // Add field for selecting a transcript language
25
- // This will be deleted in initialize.js > recreatePlayer() if there are no languages
26
- this.$transcriptLanguageSelect = $('<select id="transcript-language-select">');
27
- // Add a default "Unknown" option; this will be deleted later if there are any
28
- // elements with a language.
29
- this.$unknownTranscriptOption = $('<option val="unknown">' + this.tt.unknown + '</option>');
30
- this.$transcriptLanguageSelect.append(this.$unknownTranscriptOption);
31
- this.$transcriptLanguageSelect.prop('disabled', true);
32
-
33
- var languageSelectWrapper = $('<div class="transcript-language-select-wrapper">');
34
- this.$transcriptLanguageSelectContainer = languageSelectWrapper;
35
-
36
- languageSelectWrapper.append($('<label for="transcript-language-select">' + this.tt.language + ': </label>'), this.$transcriptLanguageSelect);
37
- this.$transcriptToolbar.append(languageSelectWrapper);
38
- this.$transcriptArea.append(this.$transcriptToolbar, this.$transcriptDiv);
39
-
40
- // If client has provided separate transcript location, put it there.
41
- // Otherwise append it to the body
42
- if (this.transcriptDivLocation) {
43
- $('#' + this.transcriptDivLocation).append(this.$transcriptArea);
44
- }
45
- else {
46
- this.$ableWrapper.append(this.$transcriptArea);
47
- }
48
-
49
- // make it draggable (popup only; NOT external transcript)
50
- if (!this.transcriptDivLocation) {
51
- this.initDragDrop('transcript');
52
- if (this.prefTranscript === 1) {
53
- // transcript is on. Go ahead and position it
54
- this.positionDraggableWindow('transcript',this.getDefaultWidth('transcript'));
55
- }
56
- }
57
-
58
- // If client has provided separate transcript location, override user's preference for hiding transcript
59
- if (!this.prefTranscript && !this.transcriptDivLocation) {
60
- this.$transcriptArea.hide();
61
- }
62
- };
63
-
64
- AblePlayer.prototype.addTranscriptAreaEvents = function() {
65
-
66
- var thisObj = this;
67
-
68
- this.$autoScrollTranscriptCheckbox.click(function () {
69
- thisObj.handleTranscriptLockToggle(thisObj.$autoScrollTranscriptCheckbox.prop('checked'));
70
- });
71
-
72
- this.$transcriptDiv.on('mousewheel DOMMouseScroll click scroll', function (e) {
73
- // Propagation is stopped in transcript click handler, so clicks are on the scrollbar
74
- // or outside of a clickable span.
75
- if (!thisObj.scrollingTranscript) {
76
- thisObj.autoScrollTranscript = false;
77
- thisObj.refreshControls();
78
- }
79
- thisObj.scrollingTranscript = false;
80
- });
81
-
82
- if (typeof this.$transcriptLanguageSelect !== 'undefined') {
83
-
84
- this.$transcriptLanguageSelect.on('click mousedown',function (e) {
85
- // execute default behavior
86
- // prevent propagation of mouse event to toolbar or window
87
- e.stopPropagation();
88
- });
89
-
90
- this.$transcriptLanguageSelect.on('change',function () {
91
-
92
- var language = thisObj.$transcriptLanguageSelect.val();
93
-
94
- thisObj.syncTrackLanguages('transcript',language);
95
- });
96
- }
97
- };
98
-
99
- AblePlayer.prototype.transcriptSrcHasRequiredParts = function() {
100
-
101
- // check the external transcript to be sure it has all required components
102
- // return true or false
103
- // in the process, define all the needed variables and properties
104
-
105
- if ($('#' + this.transcriptSrc).length) {
106
- this.$transcriptArea = $('#' + this.transcriptSrc);
107
- if (this.$transcriptArea.find('.able-window-toolbar').length) {
108
- this.$transcriptToolbar = this.$transcriptArea.find('.able-window-toolbar').eq(0);
109
- if (this.$transcriptArea.find('.able-transcript').length) {
110
- this.$transcriptDiv = this.$transcriptArea.find('.able-transcript').eq(0);
111
- if (this.$transcriptArea.find('.able-transcript-seekpoint').length) {
112
- this.$transcriptSeekpoints = this.$transcriptArea.find('.able-transcript-seekpoint');
113
- return true;
114
- }
115
- }
116
- }
117
- }
118
- return false;
119
- }
120
-
121
- AblePlayer.prototype.setupManualTranscript = function() {
122
-
123
- // Add an auto-scroll checkbox to the toolbar
124
-
125
- this.$autoScrollTranscriptCheckbox = $('<input id="autoscroll-transcript-checkbox" type="checkbox">');
126
- this.$transcriptToolbar.append($('<label for="autoscroll-transcript-checkbox">' + this.tt.autoScroll + ': </label>'), this.$autoScrollTranscriptCheckbox);
127
-
128
- };
129
-
130
- AblePlayer.prototype.updateTranscript = function() {
131
-
132
- if (!this.transcriptType) {
133
- return;
134
- }
135
-
136
- if (this.transcriptType === 'external' || this.transcriptType === 'popup') {
137
-
138
- var chapters, captions, descriptions;
139
-
140
- // Language of transcript might be different than language of captions
141
- // But both are in sync by default
142
- if (this.transcriptLang) {
143
- captions = this.transcriptCaptions.cues;
144
- }
145
- else {
146
- if (this.transcriptCaptions) {
147
- this.transcriptLang = this.transcriptCaptions.language;
148
- captions = this.transcriptCaptions.cues;
149
- }
150
- else if (this.selectedCaptions) {
151
- this.transcriptLang = this.captionLang;
152
- captions = this.selectedCaptions.cues;
153
- }
154
- }
155
-
156
- // setup chapters
157
- if (this.transcriptChapters) {
158
- chapters = this.transcriptChapters.cues;
159
- }
160
- else if (this.chapters.length > 0) {
161
- // Try and match the caption language.
162
- if (this.transcriptLang) {
163
- for (var ii = 0; ii < this.chapters.length; ii++) {
164
- if (this.chapters[ii].language === this.transcriptLang) {
165
- chapters = this.chapters[ii].cues;
166
- }
167
- }
168
- }
169
- if (typeof chapters === 'undefined') {
170
- chapters = this.chapters[0].cues || [];
171
- }
172
- }
173
-
174
- // setup descriptions
175
- if (this.transcriptDescriptions) {
176
- descriptions = this.transcriptDescriptions.cues;
177
- }
178
- else if (this.descriptions.length > 0) {
179
- // Try and match the caption language.
180
- if (this.transcriptLang) {
181
- for (var ii = 0; ii < this.descriptions.length; ii++) {
182
- if (this.descriptions[ii].language === this.transcriptLang) {
183
- descriptions = this.descriptions[ii].cues;
184
- }
185
- }
186
- }
187
- if (!descriptions) {
188
- descriptions = this.descriptions[0].cues || [];
189
- }
190
- }
191
-
192
- var div = this.generateTranscript(chapters || [], captions || [], descriptions || []);
193
-
194
- this.$transcriptDiv.html(div);
195
- // reset transcript selected <option> to this.transcriptLang
196
- if (this.$transcriptLanguageSelect) {
197
- this.$transcriptLanguageSelect.find('option:selected').prop('selected',false);
198
- this.$transcriptLanguageSelect.find('option[lang=' + this.transcriptLang + ']').prop('selected',true);
199
- }
200
- }
201
-
202
- var thisObj = this;
203
-
204
- // Make transcript tabbable if preference is turned on.
205
- if (this.prefTabbable === 1) {
206
- $('.able-transcript span.able-transcript-seekpoint').attr('tabindex','0');
207
- }
208
-
209
- // handle clicks on text within transcript
210
- // Note: This event listeners handles clicks only, not keydown events
211
- // Pressing Enter on an element that is not natively clickable does NOT trigger click()
212
- // Keydown events are handled elsehwere, both globally (ableplayer-base.js) and locally (event.js)
213
- if (this.$transcriptArea.length > 0) {
214
- this.$transcriptArea.find('span.able-transcript-seekpoint').click(function(e) {
215
- thisObj.seekTrigger = 'transcript';
216
- var spanStart = parseFloat($(this).attr('data-start'));
217
- // Add a tiny amount so that we're inside the span.
218
- spanStart += .01;
219
- // Each click within the transcript triggers two click events (not sure why)
220
- // this.seekingFromTranscript is a stopgab to prevent two calls to SeekTo()
221
- if (!thisObj.seekingFromTranscript) {
222
- thisObj.seekingFromTranscript = true;
223
- thisObj.seekTo(spanStart);
224
- }
225
- else {
226
- // don't seek a second time, but do reset var
227
- thisObj.seekingFromTranscript = false;
228
- }
229
- });
230
- }
231
- };
232
-
233
- AblePlayer.prototype.highlightTranscript = function (currentTime) {
234
-
235
- //show highlight in transcript marking current caption
236
-
237
- if (!this.transcriptType) {
238
- return;
239
- }
240
-
241
- var start, end;
242
- var thisObj = this;
243
-
244
- currentTime = parseFloat(currentTime);
245
-
246
- // Highlight the current transcript item.
247
- this.$transcriptArea.find('span.able-transcript-caption').each(function() {
248
- start = parseFloat($(this).attr('data-start'));
249
- end = parseFloat($(this).attr('data-end'));
250
- if (currentTime >= start && currentTime <= end) {
251
- // move all previous highlights before adding one to current span
252
- thisObj.$transcriptArea.find('.able-highlight').removeClass('able-highlight');
253
- $(this).addClass('able-highlight');
254
- return false;
255
- }
256
- });
257
- thisObj.currentHighlight = $('.able-highlight');
258
- if (thisObj.currentHighlight.length === 0) {
259
- // Nothing highlighted.
260
- thisObj.currentHighlight = null;
261
- }
262
- };
263
-
264
- AblePlayer.prototype.generateTranscript = function(chapters, captions, descriptions) {
265
-
266
- var thisObj = this;
267
-
268
- var $main = $('<div class="able-transcript-container"></div>');
269
- var transcriptTitle;
270
-
271
- // set language for transcript container
272
- $main.attr('lang', this.transcriptLang);
273
-
274
- if (typeof this.transcriptTitle !== 'undefined') {
275
- transcriptTitle = this.transcriptTitle;
276
- }
277
- else if (this.lyricsMode) {
278
- transcriptTitle = this.tt.lyricsTitle;
279
- }
280
- else {
281
- transcriptTitle = this.tt.transcriptTitle;
282
- }
283
-
284
- if (typeof this.transcriptDivLocation === 'undefined') {
285
- // only add an HTML heading to internal transcript
286
- // external transcript is expected to have its own heading
287
- var headingNumber = this.playerHeadingLevel;
288
- headingNumber += 1;
289
- var chapterHeadingNumber = headingNumber + 1;
290
-
291
- if (headingNumber <= 6) {
292
- var transcriptHeading = 'h' + headingNumber.toString();
293
- }
294
- else {
295
- var transcriptHeading = 'div';
296
- }
297
- // var transcriptHeadingTag = '<' + transcriptHeading + ' class="able-transcript-heading">';
298
- var $transcriptHeadingTag = $('<' + transcriptHeading + '>');
299
- $transcriptHeadingTag.addClass('able-transcript-heading');
300
- if (headingNumber > 6) {
301
- $transcriptHeadingTag.attr({
302
- 'role': 'heading',
303
- 'aria-level': headingNumber
304
- });
305
- }
306
- $transcriptHeadingTag.text(transcriptTitle);
307
-
308
- // set language of transcript heading to language of player
309
- // this is independent of language of transcript
310
- $transcriptHeadingTag.attr('lang', this.lang);
311
-
312
- $main.append($transcriptHeadingTag);
313
- }
314
-
315
- var nextChapter = 0;
316
- var nextCap = 0;
317
- var nextDesc = 0;
318
-
319
- var addChapter = function(div, chap) {
320
-
321
- if (chapterHeadingNumber <= 6) {
322
- var chapterHeading = 'h' + chapterHeadingNumber.toString();
323
- }
324
- else {
325
- var chapterHeading = 'div';
326
- }
327
-
328
- var $chapterHeadingTag = $('<' + chapterHeading + '>',{
329
- 'class': 'able-transcript-chapter-heading'
330
- });
331
- if (chapterHeadingNumber > 6) {
332
- $chapterHeadingTag.attr({
333
- 'role': 'heading',
334
- 'aria-level': chapterHeadingNumber
335
- });
336
- }
337
-
338
- var flattenComponentForChapter = function(comp) {
339
-
340
- var result = [];
341
- if (comp.type === 'string') {
342
- result.push(comp.value);
343
- }
344
- else {
345
- for (var ii = 0; ii < comp.children.length; ii++) {
346
- result = result.concat(flattenComponentForChapter(comp.children[ii]));
347
- }
348
- }
349
- return result;
350
- }
351
-
352
- var $chapSpan = $('<span>',{
353
- 'class': 'able-transcript-seekpoint'
354
- });
355
- for (var ii = 0; ii < chap.components.children.length; ii++) {
356
- var results = flattenComponentForChapter(chap.components.children[ii]);
357
- for (var jj = 0; jj < results.length; jj++) {
358
- $chapSpan.append(results[jj]);
359
- }
360
- }
361
- $chapSpan.attr('data-start', chap.start.toString());
362
- $chapSpan.attr('data-end', chap.end.toString());
363
- $chapterHeadingTag.append($chapSpan);
364
-
365
- div.append($chapterHeadingTag);
366
- };
367
-
368
- var addDescription = function(div, desc) {
369
- var $descDiv = $('<div>', {
370
- 'class': 'able-transcript-desc'
371
- });
372
- var $descHiddenSpan = $('<span>',{
373
- 'class': 'able-hidden'
374
- });
375
- $descHiddenSpan.attr('lang', thisObj.lang);
376
- $descHiddenSpan.text(thisObj.tt.prefHeadingDescription + ': ');
377
- $descDiv.append($descHiddenSpan);
378
-
379
- var flattenComponentForDescription = function(comp) {
380
-
381
- var result = [];
382
- if (comp.type === 'string') {
383
- result.push(comp.value);
384
- }
385
- else {
386
- for (var ii = 0; ii < comp.children.length; ii++) {
387
- result = result.concat(flattenComponentForDescription(comp.children[ii]));
388
- }
389
- }
390
- return result;
391
- }
392
-
393
- var $descSpan = $('<span>',{
394
- 'class': 'able-transcript-seekpoint'
395
- });
396
- for (var ii = 0; ii < desc.components.children.length; ii++) {
397
- var results = flattenComponentForDescription(desc.components.children[ii]);
398
- for (var jj = 0; jj < results.length; jj++) {
399
- $descSpan.append(results[jj]);
400
- }
401
- }
402
- $descSpan.attr('data-start', desc.start.toString());
403
- $descSpan.attr('data-end', desc.end.toString());
404
- $descDiv.append($descSpan);
405
-
406
- div.append($descDiv);
407
- };
408
-
409
- var addCaption = function(div, cap) {
410
-
411
- var $capSpan = $('<span>',{
412
- 'class': 'able-transcript-seekpoint able-transcript-caption'
413
- });
414
-
415
- var flattenComponentForCaption = function(comp) {
416
-
417
- var result = [];
418
-
419
- var flattenString = function (str) {
420
- var result = [];
421
- if (str === '') {
422
- return result;
423
- }
424
- var openBracket = str.indexOf('[');
425
- var closeBracket = str.indexOf(']');
426
- var openParen = str.indexOf('(');
427
- var closeParen = str.indexOf(')');
428
-
429
- var hasBrackets = openBracket !== -1 && closeBracket !== -1;
430
- var hasParens = openParen !== -1 && closeParen !== -1;
431
-
432
- if ((hasParens && hasBrackets && openBracket < openParen) || hasBrackets) {
433
- result = result.concat(flattenString(str.substring(0, openBracket)));
434
- var $silentSpan = $('<span>',{
435
- 'class': 'able-unspoken'
436
- });
437
- $silentSpan.text(str.substring(openBracket, closeBracket + 1));
438
- result.push($silentSpan);
439
- result = result.concat(flattenString(str.substring(openParen, closeParen + 1)));
440
- }
441
- else if (hasParens) {
442
- result = result.concat(flattenString(str.substring(0, openParen)));
443
- var $silentSpan = $('<span>',{
444
- 'class': 'able-unspoken'
445
- });
446
- $silentSpan.text(str.substring(openBracket, closeBracket + 1));
447
- result.push($silentSpan);
448
- result = result.concat(flattenString(str.substring(closeParen + 1)));
449
- }
450
- else {
451
- result.push(str);
452
- }
453
- return result;
454
- };
455
-
456
- if (comp.type === 'string') {
457
- result = result.concat(flattenString(comp.value));
458
- }
459
- else if (comp.type === 'v') {
460
- var $vSpan = $('<span>',{
461
- 'class': 'able-unspoken'
462
- });
463
- $vSpan.text('(' + comp.value + ')');
464
- result.push($vSpan);
465
- for (var ii = 0; ii < comp.children.length; ii++) {
466
- var subResults = flattenComponentForCaption(comp.children[ii]);
467
- for (var jj = 0; jj < subResults.length; jj++) {
468
- result.push(subResults[jj]);
469
- }
470
- }
471
- }
472
- else if (comp.type === 'b' || comp.type === 'i') {
473
- if (comp.type === 'b') {
474
- var $tag = $('<strong>');
475
- }
476
- else if (comp.type === 'i') {
477
- var $tag = $('<em>');
478
- }
479
- for (var ii = 0; ii < comp.children.length; ii++) {
480
- var subResults = flattenComponentForCaption(comp.children[ii]);
481
- for (var jj = 0; jj < subResults.length; jj++) {
482
- $tag.append(subResults[jj]);
483
- }
484
- }
485
- if (comp.type === 'b' || comp.type == 'i') {
486
- result.push($tag,' ');
487
- }
488
- }
489
- else {
490
- for (var ii = 0; ii < comp.children.length; ii++) {
491
- result = result.concat(flattenComponentForCaption(comp.children[ii]));
492
- }
493
- }
494
- return result;
495
- };
496
-
497
- for (var ii = 0; ii < cap.components.children.length; ii++) {
498
- var results = flattenComponentForCaption(cap.components.children[ii]);
499
- for (var jj = 0; jj < results.length; jj++) {
500
- var result = results[jj];
501
- if (typeof result === 'string') {
502
- if (thisObj.lyricsMode) {
503
- // add <br> BETWEEN each caption and WITHIN each caption (if payload includes "\n")
504
- result = result.replace('\n','<br>') + '<br>';
505
- }
506
- else {
507
- // just add a space between captions
508
- result += ' ';
509
- }
510
- }
511
- $capSpan.append(result);
512
- }
513
- }
514
- $capSpan.attr('data-start', cap.start.toString());
515
- $capSpan.attr('data-end', cap.end.toString());
516
- div.append($capSpan);
517
- div.append(' \n');
518
- };
519
-
520
- // keep looping as long as any one of the three arrays has content
521
- while ((nextChapter < chapters.length) || (nextDesc < descriptions.length) || (nextCap < captions.length)) {
522
-
523
- if ((nextChapter < chapters.length) && (nextDesc < descriptions.length) && (nextCap < captions.length)) {
524
- // they all three have content
525
- var firstStart = Math.min(chapters[nextChapter].start,descriptions[nextDesc].start,captions[nextCap].start);
526
- }
527
- else if ((nextChapter < chapters.length) && (nextDesc < descriptions.length)) {
528
- // chapters & descriptions have content
529
- var firstStart = Math.min(chapters[nextChapter].start,descriptions[nextDesc].start);
530
- }
531
- else if ((nextChapter < chapters.length) && (nextCap < captions.length)) {
532
- // chapters & captions have content
533
- var firstStart = Math.min(chapters[nextChapter].start,captions[nextCap].start);
534
- }
535
- else if ((nextDesc < descriptions.length) && (nextCap < captions.length)) {
536
- // descriptions & captions have content
537
- var firstStart = Math.min(descriptions[nextDesc].start,captions[nextCap].start);
538
- }
539
- else {
540
- var firstStart = null;
541
- }
542
- if (firstStart !== null) {
543
- if (typeof chapters[nextChapter] !== 'undefined' && chapters[nextChapter].start === firstStart) {
544
- addChapter($main, chapters[nextChapter]);
545
- nextChapter += 1;
546
- }
547
- else if (typeof descriptions[nextDesc] !== 'undefined' && descriptions[nextDesc].start === firstStart) {
548
- addDescription($main, descriptions[nextDesc]);
549
- nextDesc += 1;
550
- }
551
- else {
552
- addCaption($main, captions[nextCap]);
553
- nextCap += 1;
554
- }
555
- }
556
- else {
557
- if (nextChapter < chapters.length) {
558
- addChapter($main, chapters[nextChapter]);
559
- nextChapter += 1;
560
- }
561
- else if (nextDesc < descriptions.length) {
562
- addDescription($main, descriptions[nextDesc]);
563
- nextDesc += 1;
564
- }
565
- else if (nextCap < captions.length) {
566
- addCaption($main, captions[nextCap]);
567
- nextCap += 1;
568
- }
569
- }
570
- }
571
- // organize transcript into blocks using [] and () as starting points
572
- var $components = $main.children();
573
- var spanCount = 0;
574
- var openBlock = true;
575
- $components.each(function() {
576
- if ($(this).hasClass('able-transcript-caption')) {
577
- if ($(this).text().indexOf('[') !== -1 || $(this).text().indexOf('(') !== -1) {
578
- // this caption includes a bracket or parenth. Start a new block
579
- // close the previous block first
580
- if (spanCount > 0) {
581
- $main.find('.able-block-temp').removeClass('able-block-temp').wrapAll('<div class="able-transcript-block"></div>');
582
- spanCount = 0;
583
- }
584
- }
585
- $(this).addClass('able-block-temp');
586
- spanCount++;
587
- }
588
- else {
589
- // this is not a caption. Close the caption block
590
- if (spanCount > 0) {
591
- $main.find('.able-block-temp').removeClass('able-block-temp').wrapAll('<div class="able-transcript-block"></div>');
592
- spanCount = 0;
593
- }
594
- }
595
- });
596
- return $main;
597
- };
3
+ AblePlayer.prototype.setupTranscript = function() {
4
+
5
+ var deferred = new $.Deferred();
6
+ var promise = deferred.promise();
7
+
8
+ if (!this.transcriptType) {
9
+ // previously set transcriptType to null since there are no <track> elements
10
+ // check again to see if captions have been collected from other sources (e.g., YouTube)
11
+ if (this.captions.length && (!(this.usingYouTubeCaptions || this.usingVimeoCaptions))) {
12
+ // captions are possible! Use the default type (popup)
13
+ // if other types ('external' and 'manual') were desired, transcriptType would not be null here
14
+ this.transcriptType = 'popup';
15
+ }
16
+ }
17
+
18
+ if (this.transcriptType) {
19
+ if (this.transcriptType === 'popup' || this.transcriptType === 'external') {
20
+ this.injectTranscriptArea();
21
+ deferred.resolve();
22
+ }
23
+ else if (this.transcriptType === 'manual') {
24
+ this.setupManualTranscript();
25
+ deferred.resolve();
26
+ }
27
+ }
28
+ else {
29
+ // there is no transcript
30
+ deferred.resolve();
31
+ }
32
+ return promise;
33
+ };
34
+
35
+ AblePlayer.prototype.injectTranscriptArea = function() {
36
+
37
+ var thisObj, $autoScrollLabel, $languageSelectWrapper, $languageSelectLabel, i, $option;
38
+
39
+ thisObj = this;
40
+ this.$transcriptArea = $('<div>', {
41
+ 'class': 'able-transcript-area',
42
+ 'tabindex': '-1'
43
+ });
44
+
45
+ this.$transcriptToolbar = $('<div>', {
46
+ 'class': 'able-window-toolbar able-' + this.toolbarIconColor + '-controls'
47
+ });
48
+
49
+ this.$transcriptDiv = $('<div>', {
50
+ 'class' : 'able-transcript'
51
+ });
52
+
53
+ // Transcript toolbar content
54
+
55
+ // Add auto Scroll checkbox
56
+ this.$autoScrollTranscriptCheckbox = $('<input>', {
57
+ 'id': 'autoscroll-transcript-checkbox',
58
+ 'type': 'checkbox'
59
+ });
60
+ $autoScrollLabel = $('<label>', {
61
+ 'for': 'autoscroll-transcript-checkbox'
62
+ }).text(this.tt.autoScroll);
63
+ this.$transcriptToolbar.append($autoScrollLabel,this.$autoScrollTranscriptCheckbox);
64
+
65
+ // Add field for selecting a transcript language
66
+ // Only necessary if there is more than one language
67
+ if (this.captions.length > 1) {
68
+ $languageSelectWrapper = $('<div>',{
69
+ 'class': 'transcript-language-select-wrapper'
70
+ });
71
+ $languageSelectLabel = $('<label>',{
72
+ 'for': 'transcript-language-select'
73
+ }).text(this.tt.language);
74
+ this.$transcriptLanguageSelect = $('<select>',{
75
+ 'id': 'transcript-language-select'
76
+ });
77
+ for (i=0; i < this.captions.length; i++) {
78
+ $option = $('<option></option>',{
79
+ value: this.captions[i]['language'],
80
+ lang: this.captions[i]['language']
81
+ }).text(this.captions[i]['label']);
82
+ if (this.captions[i]['def']) {
83
+ $option.prop('selected',true);
84
+ }
85
+ this.$transcriptLanguageSelect.append($option);
86
+ }
87
+ }
88
+ if ($languageSelectWrapper) {
89
+ $languageSelectWrapper.append($languageSelectLabel,this.$transcriptLanguageSelect);
90
+ this.$transcriptToolbar.append($languageSelectWrapper);
91
+ }
92
+ this.$transcriptArea.append(this.$transcriptToolbar, this.$transcriptDiv);
93
+
94
+ // If client has provided separate transcript location, put it there.
95
+ // Otherwise append it to the body
96
+ if (this.transcriptDivLocation) {
97
+ $('#' + this.transcriptDivLocation).append(this.$transcriptArea);
98
+ }
99
+ else {
100
+ this.$ableWrapper.append(this.$transcriptArea);
101
+ }
102
+
103
+ // make it draggable (popup only; NOT external transcript)
104
+ if (!this.transcriptDivLocation) {
105
+ this.initDragDrop('transcript');
106
+ if (this.prefTranscript === 1) {
107
+ // transcript is on. Go ahead and position it
108
+ this.positionDraggableWindow('transcript',this.getDefaultWidth('transcript'));
109
+ }
110
+ }
111
+
112
+ // If client has provided separate transcript location, override user's preference for hiding transcript
113
+ if (!this.prefTranscript && !this.transcriptDivLocation) {
114
+ this.$transcriptArea.hide();
115
+ }
116
+ };
117
+
118
+ AblePlayer.prototype.addTranscriptAreaEvents = function() {
119
+
120
+ var thisObj = this;
121
+
122
+ this.$autoScrollTranscriptCheckbox.click(function () {
123
+ thisObj.handleTranscriptLockToggle(thisObj.$autoScrollTranscriptCheckbox.prop('checked'));
124
+ });
125
+
126
+ this.$transcriptDiv.on('mousewheel DOMMouseScroll click scroll', function (e) {
127
+ // Propagation is stopped in transcript click handler, so clicks are on the scrollbar
128
+ // or outside of a clickable span.
129
+ if (!thisObj.scrollingTranscript) {
130
+ thisObj.autoScrollTranscript = false;
131
+ thisObj.refreshControls('transcript');
132
+ }
133
+ thisObj.scrollingTranscript = false;
134
+ });
135
+
136
+ if (typeof this.$transcriptLanguageSelect !== 'undefined') {
137
+
138
+ this.$transcriptLanguageSelect.on('click mousedown',function (e) {
139
+ // execute default behavior
140
+ // prevent propagation of mouse event to toolbar or window
141
+ e.stopPropagation();
142
+ });
143
+
144
+ this.$transcriptLanguageSelect.on('change',function () {
145
+
146
+ var language = thisObj.$transcriptLanguageSelect.val();
147
+
148
+ thisObj.syncTrackLanguages('transcript',language);
149
+ });
150
+ }
151
+ };
152
+
153
+ AblePlayer.prototype.transcriptSrcHasRequiredParts = function() {
154
+
155
+ // check the external transcript to be sure it has all required components
156
+ // return true or false
157
+ // in the process, define all the needed variables and properties
158
+
159
+ if ($('#' + this.transcriptSrc).length) {
160
+ this.$transcriptArea = $('#' + this.transcriptSrc);
161
+ if (this.$transcriptArea.find('.able-window-toolbar').length) {
162
+ this.$transcriptToolbar = this.$transcriptArea.find('.able-window-toolbar').eq(0);
163
+ if (this.$transcriptArea.find('.able-transcript').length) {
164
+ this.$transcriptDiv = this.$transcriptArea.find('.able-transcript').eq(0);
165
+ if (this.$transcriptArea.find('.able-transcript-seekpoint').length) {
166
+ this.$transcriptSeekpoints = this.$transcriptArea.find('.able-transcript-seekpoint');
167
+ return true;
168
+ }
169
+ }
170
+ }
171
+ }
172
+ return false;
173
+ }
174
+
175
+ AblePlayer.prototype.setupManualTranscript = function() {
176
+
177
+ // Add an auto-scroll checkbox to the toolbar
178
+
179
+ this.$autoScrollTranscriptCheckbox = $('<input id="autoscroll-transcript-checkbox" type="checkbox">');
180
+ this.$transcriptToolbar.append($('<label for="autoscroll-transcript-checkbox">' + this.tt.autoScroll + ': </label>'), this.$autoScrollTranscriptCheckbox);
181
+
182
+ };
183
+
184
+ AblePlayer.prototype.updateTranscript = function() {
185
+
186
+ if (!this.transcriptType) {
187
+ return;
188
+ }
189
+
190
+ if (this.transcriptType === 'external' || this.transcriptType === 'popup') {
191
+
192
+ var chapters, captions, descriptions;
193
+
194
+ // Language of transcript might be different than language of captions
195
+ // But both are in sync by default
196
+ if (this.transcriptLang) {
197
+ captions = this.transcriptCaptions.cues;
198
+ }
199
+ else {
200
+ if (this.transcriptCaptions) {
201
+ this.transcriptLang = this.transcriptCaptions.language;
202
+ captions = this.transcriptCaptions.cues;
203
+ }
204
+ else if (this.selectedCaptions) {
205
+ this.transcriptLang = this.captionLang;
206
+ captions = this.selectedCaptions.cues;
207
+ }
208
+ }
209
+
210
+ // setup chapters
211
+ if (this.transcriptChapters) {
212
+ chapters = this.transcriptChapters.cues;
213
+ }
214
+ else if (this.chapters.length > 0) {
215
+ // Try and match the caption language.
216
+ if (this.transcriptLang) {
217
+ for (var i = 0; i < this.chapters.length; i++) {
218
+ if (this.chapters[i].language === this.transcriptLang) {
219
+ chapters = this.chapters[i].cues;
220
+ }
221
+ }
222
+ }
223
+ if (typeof chapters === 'undefined') {
224
+ chapters = this.chapters[0].cues || [];
225
+ }
226
+ }
227
+
228
+ // setup descriptions
229
+ if (this.transcriptDescriptions) {
230
+ descriptions = this.transcriptDescriptions.cues;
231
+ }
232
+ else if (this.descriptions.length > 0) {
233
+ // Try and match the caption language.
234
+ if (this.transcriptLang) {
235
+ for (var i = 0; i < this.descriptions.length; i++) {
236
+ if (this.descriptions[i].language === this.transcriptLang) {
237
+ descriptions = this.descriptions[i].cues;
238
+ }
239
+ }
240
+ }
241
+ if (!descriptions) {
242
+ descriptions = this.descriptions[0].cues || [];
243
+ }
244
+ }
245
+
246
+ var div = this.generateTranscript(chapters || [], captions || [], descriptions || []);
247
+
248
+ this.$transcriptDiv.html(div);
249
+ // reset transcript selected <option> to this.transcriptLang
250
+ if (this.$transcriptLanguageSelect) {
251
+ this.$transcriptLanguageSelect.find('option:selected').prop('selected',false);
252
+ this.$transcriptLanguageSelect.find('option[lang=' + this.transcriptLang + ']').prop('selected',true);
253
+ }
254
+ }
255
+
256
+ var thisObj = this;
257
+
258
+ // Make transcript tabbable if preference is turned on.
259
+ if (this.prefTabbable === 1) {
260
+ $('.able-transcript span.able-transcript-seekpoint').attr('tabindex','0');
261
+ }
262
+
263
+ // handle clicks on text within transcript
264
+ // Note: This event listeners handles clicks only, not keydown events
265
+ // Pressing Enter on an element that is not natively clickable does NOT trigger click()
266
+ // Keydown events are handled elsehwere, both globally (ableplayer-base.js) and locally (event.js)
267
+ if (this.$transcriptArea.length > 0) {
268
+ this.$transcriptArea.find('span.able-transcript-seekpoint').click(function(e) {
269
+ thisObj.seekTrigger = 'transcript';
270
+ var spanStart = parseFloat($(this).attr('data-start'));
271
+ // Add a tiny amount so that we're inside the span.
272
+ spanStart += .01;
273
+ // Each click within the transcript triggers two click events (not sure why)
274
+ // this.seekingFromTranscript is a stopgab to prevent two calls to SeekTo()
275
+ if (!thisObj.seekingFromTranscript) {
276
+ thisObj.seekingFromTranscript = true;
277
+ thisObj.seekTo(spanStart);
278
+ }
279
+ else {
280
+ // don't seek a second time, but do reset var
281
+ thisObj.seekingFromTranscript = false;
282
+ }
283
+ });
284
+ }
285
+ };
286
+
287
+ AblePlayer.prototype.highlightTranscript = function (currentTime) {
288
+
289
+ //show highlight in transcript marking current caption
290
+
291
+ if (!this.transcriptType) {
292
+ return;
293
+ }
294
+
295
+ var start, end, isChapterHeading;
296
+ var thisObj = this;
297
+
298
+ currentTime = parseFloat(currentTime);
299
+
300
+ // Highlight the current transcript item.
301
+ this.$transcriptArea.find('span.able-transcript-seekpoint').each(function() {
302
+ start = parseFloat($(this).attr('data-start'));
303
+ end = parseFloat($(this).attr('data-end'));
304
+ // be sure this isn't a chapter (don't highlight chapter headings)
305
+ if ($(this).parent().hasClass('able-transcript-chapter-heading')) {
306
+ isChapterHeading = true;
307
+ }
308
+ else {
309
+ isChapterHeading = false;
310
+ }
311
+
312
+ if (currentTime >= start && currentTime <= end && !isChapterHeading) {
313
+ // move all previous highlights before adding one to current span
314
+ thisObj.$transcriptArea.find('.able-highlight').removeClass('able-highlight');
315
+ $(this).addClass('able-highlight');
316
+ return false;
317
+ }
318
+ });
319
+ thisObj.currentHighlight = $('.able-highlight');
320
+ if (thisObj.currentHighlight.length === 0) {
321
+ // Nothing highlighted.
322
+ thisObj.currentHighlight = null;
323
+ }
324
+ };
325
+
326
+ AblePlayer.prototype.generateTranscript = function(chapters, captions, descriptions) {
327
+
328
+ var thisObj = this;
329
+
330
+ var $main = $('<div class="able-transcript-container"></div>');
331
+ var transcriptTitle;
332
+
333
+ // set language for transcript container
334
+ $main.attr('lang', this.transcriptLang);
335
+
336
+ if (typeof this.transcriptTitle !== 'undefined') {
337
+ transcriptTitle = this.transcriptTitle;
338
+ }
339
+ else if (this.lyricsMode) {
340
+ transcriptTitle = this.tt.lyricsTitle;
341
+ }
342
+ else {
343
+ transcriptTitle = this.tt.transcriptTitle;
344
+ }
345
+
346
+ if (typeof this.transcriptDivLocation === 'undefined') {
347
+ // only add an HTML heading to internal transcript
348
+ // external transcript is expected to have its own heading
349
+ var headingNumber = this.playerHeadingLevel;
350
+ headingNumber += 1;
351
+ var chapterHeadingNumber = headingNumber + 1;
352
+
353
+ if (headingNumber <= 6) {
354
+ var transcriptHeading = 'h' + headingNumber.toString();
355
+ }
356
+ else {
357
+ var transcriptHeading = 'div';
358
+ }
359
+ // var transcriptHeadingTag = '<' + transcriptHeading + ' class="able-transcript-heading">';
360
+ var $transcriptHeadingTag = $('<' + transcriptHeading + '>');
361
+ $transcriptHeadingTag.addClass('able-transcript-heading');
362
+ if (headingNumber > 6) {
363
+ $transcriptHeadingTag.attr({
364
+ 'role': 'heading',
365
+ 'aria-level': headingNumber
366
+ });
367
+ }
368
+ $transcriptHeadingTag.text(transcriptTitle);
369
+
370
+ // set language of transcript heading to language of player
371
+ // this is independent of language of transcript
372
+ $transcriptHeadingTag.attr('lang', this.lang);
373
+
374
+ $main.append($transcriptHeadingTag);
375
+ }
376
+
377
+ var nextChapter = 0;
378
+ var nextCap = 0;
379
+ var nextDesc = 0;
380
+
381
+ var addChapter = function(div, chap) {
382
+
383
+ if (chapterHeadingNumber <= 6) {
384
+ var chapterHeading = 'h' + chapterHeadingNumber.toString();
385
+ }
386
+ else {
387
+ var chapterHeading = 'div';
388
+ }
389
+
390
+ var $chapterHeadingTag = $('<' + chapterHeading + '>',{
391
+ 'class': 'able-transcript-chapter-heading'
392
+ });
393
+ if (chapterHeadingNumber > 6) {
394
+ $chapterHeadingTag.attr({
395
+ 'role': 'heading',
396
+ 'aria-level': chapterHeadingNumber
397
+ });
398
+ }
399
+
400
+ var flattenComponentForChapter = function(comp) {
401
+
402
+ var result = [];
403
+ if (comp.type === 'string') {
404
+ result.push(comp.value);
405
+ }
406
+ else {
407
+ for (var i = 0; i < comp.children.length; i++) {
408
+ result = result.concat(flattenComponentForChapter(comp.children[i]));
409
+ }
410
+ }
411
+ return result;
412
+ }
413
+
414
+ var $chapSpan = $('<span>',{
415
+ 'class': 'able-transcript-seekpoint'
416
+ });
417
+ for (var i = 0; i < chap.components.children.length; i++) {
418
+ var results = flattenComponentForChapter(chap.components.children[i]);
419
+ for (var jj = 0; jj < results.length; jj++) {
420
+ $chapSpan.append(results[jj]);
421
+ }
422
+ }
423
+ $chapSpan.attr('data-start', chap.start.toString());
424
+ $chapSpan.attr('data-end', chap.end.toString());
425
+ $chapterHeadingTag.append($chapSpan);
426
+
427
+ div.append($chapterHeadingTag);
428
+ };
429
+
430
+ var addDescription = function(div, desc) {
431
+ var $descDiv = $('<div>', {
432
+ 'class': 'able-transcript-desc'
433
+ });
434
+ var $descHiddenSpan = $('<span>',{
435
+ 'class': 'able-hidden'
436
+ });
437
+ $descHiddenSpan.attr('lang', thisObj.lang);
438
+ $descHiddenSpan.text(thisObj.tt.prefHeadingDescription + ': ');
439
+ $descDiv.append($descHiddenSpan);
440
+
441
+ var flattenComponentForDescription = function(comp) {
442
+
443
+ var result = [];
444
+ if (comp.type === 'string') {
445
+ result.push(comp.value);
446
+ }
447
+ else {
448
+ for (var i = 0; i < comp.children.length; i++) {
449
+ result = result.concat(flattenComponentForDescription(comp.children[i]));
450
+ }
451
+ }
452
+ return result;
453
+ }
454
+
455
+ var $descSpan = $('<span>',{
456
+ 'class': 'able-transcript-seekpoint'
457
+ });
458
+ for (var i = 0; i < desc.components.children.length; i++) {
459
+ var results = flattenComponentForDescription(desc.components.children[i]);
460
+ for (var jj = 0; jj < results.length; jj++) {
461
+ $descSpan.append(results[jj]);
462
+ }
463
+ }
464
+ $descSpan.attr('data-start', desc.start.toString());
465
+ $descSpan.attr('data-end', desc.end.toString());
466
+ $descDiv.append($descSpan);
467
+
468
+ div.append($descDiv);
469
+ };
470
+
471
+ var addCaption = function(div, cap) {
472
+
473
+ var $capSpan = $('<span>',{
474
+ 'class': 'able-transcript-seekpoint able-transcript-caption'
475
+ });
476
+
477
+ var flattenComponentForCaption = function(comp) {
478
+
479
+ var result = [];
480
+
481
+ var parts = 0;
482
+
483
+ var flattenString = function (str) {
484
+
485
+ parts++;
486
+
487
+ var flatStr;
488
+ var result = [];
489
+ if (str === '') {
490
+ return result;
491
+ }
492
+
493
+ var openBracket = str.indexOf('[');
494
+ var closeBracket = str.indexOf(']');
495
+ var openParen = str.indexOf('(');
496
+ var closeParen = str.indexOf(')');
497
+
498
+ var hasBrackets = openBracket !== -1 && closeBracket !== -1;
499
+ var hasParens = openParen !== -1 && closeParen !== -1;
500
+
501
+ if (hasParens || hasBrackets) {
502
+ if (parts > 1) {
503
+ // force a line break between sections that contain parens or brackets
504
+ var silentSpanBreak = '<br/>';
505
+ }
506
+ else {
507
+ var silentSpanBreak = '';
508
+ }
509
+ var silentSpanOpen = silentSpanBreak + '<span class="able-unspoken">';
510
+ var silentSpanClose = '</span>';
511
+ if (hasParens && hasBrackets) {
512
+ // string has both!
513
+ if (openBracket < openParen) {
514
+ // brackets come first. Parse parens separately
515
+ hasParens = false;
516
+ }
517
+ else {
518
+ // parens come first. Parse brackets separately
519
+ hasBrackets = false;
520
+ }
521
+ }
522
+ }
523
+ if (hasParens) {
524
+ flatStr = str.substring(0, openParen);
525
+ flatStr += silentSpanOpen;
526
+ flatStr += str.substring(openParen, closeParen + 1);
527
+ flatStr += silentSpanClose;
528
+ flatStr += flattenString(str.substring(closeParen + 1));
529
+ result.push(flatStr);
530
+ }
531
+ else if (hasBrackets) {
532
+ flatStr = str.substring(0, openBracket);
533
+ flatStr += silentSpanOpen;
534
+ flatStr += str.substring(openBracket, closeBracket + 1);
535
+ flatStr += silentSpanClose;
536
+ flatStr += flattenString(str.substring(closeBracket + 1));
537
+ result.push(flatStr);
538
+ }
539
+ else {
540
+ result.push(str);
541
+ }
542
+ return result;
543
+ };
544
+
545
+ if (comp.type === 'string') {
546
+ result = result.concat(flattenString(comp.value));
547
+ }
548
+ else if (comp.type === 'v') {
549
+ var $vSpan = $('<span>',{
550
+ 'class': 'able-unspoken'
551
+ });
552
+ $vSpan.text('(' + comp.value + ')');
553
+ result.push($vSpan);
554
+ for (var i = 0; i < comp.children.length; i++) {
555
+ var subResults = flattenComponentForCaption(comp.children[i]);
556
+ for (var jj = 0; jj < subResults.length; jj++) {
557
+ result.push(subResults[jj]);
558
+ }
559
+ }
560
+ }
561
+ else if (comp.type === 'b' || comp.type === 'i') {
562
+ if (comp.type === 'b') {
563
+ var $tag = $('<strong>');
564
+ }
565
+ else if (comp.type === 'i') {
566
+ var $tag = $('<em>');
567
+ }
568
+ for (var i = 0; i < comp.children.length; i++) {
569
+ var subResults = flattenComponentForCaption(comp.children[i]);
570
+ for (var jj = 0; jj < subResults.length; jj++) {
571
+ $tag.append(subResults[jj]);
572
+ }
573
+ }
574
+ if (comp.type === 'b' || comp.type == 'i') {
575
+ result.push($tag,' ');
576
+ }
577
+ }
578
+ else {
579
+ for (var i = 0; i < comp.children.length; i++) {
580
+ result = result.concat(flattenComponentForCaption(comp.children[i]));
581
+ }
582
+ }
583
+ return result;
584
+ };
585
+
586
+ for (var i = 0; i < cap.components.children.length; i++) {
587
+ var results = flattenComponentForCaption(cap.components.children[i]);
588
+ for (var jj = 0; jj < results.length; jj++) {
589
+ var result = results[jj];
590
+ if (typeof result === 'string') {
591
+ if (thisObj.lyricsMode) {
592
+ // add <br> BETWEEN each caption and WITHIN each caption (if payload includes "\n")
593
+ result = result.replace('\n','<br>') + '<br>';
594
+ }
595
+ else {
596
+ // just add a space between captions
597
+ result += ' ';
598
+ }
599
+ }
600
+ $capSpan.append(result);
601
+ }
602
+ }
603
+ $capSpan.attr('data-start', cap.start.toString());
604
+ $capSpan.attr('data-end', cap.end.toString());
605
+ div.append($capSpan);
606
+ div.append(' \n');
607
+ };
608
+
609
+ // keep looping as long as any one of the three arrays has content
610
+ while ((nextChapter < chapters.length) || (nextDesc < descriptions.length) || (nextCap < captions.length)) {
611
+
612
+ if ((nextChapter < chapters.length) && (nextDesc < descriptions.length) && (nextCap < captions.length)) {
613
+ // they all three have content
614
+ var firstStart = Math.min(chapters[nextChapter].start,descriptions[nextDesc].start,captions[nextCap].start);
615
+ }
616
+ else if ((nextChapter < chapters.length) && (nextDesc < descriptions.length)) {
617
+ // chapters & descriptions have content
618
+ var firstStart = Math.min(chapters[nextChapter].start,descriptions[nextDesc].start);
619
+ }
620
+ else if ((nextChapter < chapters.length) && (nextCap < captions.length)) {
621
+ // chapters & captions have content
622
+ var firstStart = Math.min(chapters[nextChapter].start,captions[nextCap].start);
623
+ }
624
+ else if ((nextDesc < descriptions.length) && (nextCap < captions.length)) {
625
+ // descriptions & captions have content
626
+ var firstStart = Math.min(descriptions[nextDesc].start,captions[nextCap].start);
627
+ }
628
+ else {
629
+ var firstStart = null;
630
+ }
631
+ if (firstStart !== null) {
632
+ if (typeof chapters[nextChapter] !== 'undefined' && chapters[nextChapter].start === firstStart) {
633
+ addChapter($main, chapters[nextChapter]);
634
+ nextChapter += 1;
635
+ }
636
+ else if (typeof descriptions[nextDesc] !== 'undefined' && descriptions[nextDesc].start === firstStart) {
637
+ addDescription($main, descriptions[nextDesc]);
638
+ nextDesc += 1;
639
+ }
640
+ else {
641
+ addCaption($main, captions[nextCap]);
642
+ nextCap += 1;
643
+ }
644
+ }
645
+ else {
646
+ if (nextChapter < chapters.length) {
647
+ addChapter($main, chapters[nextChapter]);
648
+ nextChapter += 1;
649
+ }
650
+ else if (nextDesc < descriptions.length) {
651
+ addDescription($main, descriptions[nextDesc]);
652
+ nextDesc += 1;
653
+ }
654
+ else if (nextCap < captions.length) {
655
+ addCaption($main, captions[nextCap]);
656
+ nextCap += 1;
657
+ }
658
+ }
659
+ }
660
+ // organize transcript into blocks using [] and () as starting points
661
+ var $components = $main.children();
662
+ var spanCount = 0;
663
+ var openBlock = true;
664
+ $components.each(function() {
665
+ if ($(this).hasClass('able-transcript-caption')) {
666
+ if ($(this).text().indexOf('[') !== -1 || $(this).text().indexOf('(') !== -1) {
667
+ // this caption includes a bracket or parenth. Start a new block
668
+ // close the previous block first
669
+ if (spanCount > 0) {
670
+ $main.find('.able-block-temp').removeClass('able-block-temp').wrapAll('<div class="able-transcript-block"></div>');
671
+ spanCount = 0;
672
+ }
673
+ }
674
+ $(this).addClass('able-block-temp');
675
+ spanCount++;
676
+ }
677
+ else {
678
+ // this is not a caption. Close the caption block
679
+ if (spanCount > 0) {
680
+ $main.find('.able-block-temp').removeClass('able-block-temp').wrapAll('<div class="able-transcript-block"></div>');
681
+ spanCount = 0;
682
+ }
683
+ }
684
+ });
685
+ return $main;
686
+ };
598
687
 
599
688
  })(jQuery);