wai-website-theme 1.3.1 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
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);