assets/ableplayer/scripts/transcript.js in wai-website-theme-1.3.1 vs assets/ableplayer/scripts/transcript.js in wai-website-theme-1.4
- old
+ new
@@ -1,599 +1,688 @@
(function ($) {
- AblePlayer.prototype.injectTranscriptArea = function() {
+ AblePlayer.prototype.setupTranscript = function() {
- var thisObj = this;
+ var deferred = new $.Deferred();
+ var promise = deferred.promise();
- this.$transcriptArea = $('<div>', {
- 'class': 'able-transcript-area',
- 'tabindex': '-1'
- });
+ if (!this.transcriptType) {
+ // previously set transcriptType to null since there are no <track> elements
+ // check again to see if captions have been collected from other sources (e.g., YouTube)
+ if (this.captions.length && (!(this.usingYouTubeCaptions || this.usingVimeoCaptions))) {
+ // captions are possible! Use the default type (popup)
+ // if other types ('external' and 'manual') were desired, transcriptType would not be null here
+ this.transcriptType = 'popup';
+ }
+ }
- this.$transcriptToolbar = $('<div>', {
- 'class': 'able-window-toolbar able-' + this.toolbarIconColor + '-controls'
- });
+ if (this.transcriptType) {
+ if (this.transcriptType === 'popup' || this.transcriptType === 'external') {
+ this.injectTranscriptArea();
+ deferred.resolve();
+ }
+ else if (this.transcriptType === 'manual') {
+ this.setupManualTranscript();
+ deferred.resolve();
+ }
+ }
+ else {
+ // there is no transcript
+ deferred.resolve();
+ }
+ return promise;
+ };
- this.$transcriptDiv = $('<div>', {
- 'class' : 'able-transcript'
- });
+ AblePlayer.prototype.injectTranscriptArea = function() {
- // Transcript toolbar content:
- this.$autoScrollTranscriptCheckbox = $('<input id="autoscroll-transcript-checkbox" type="checkbox">');
- this.$transcriptToolbar.append($('<label for="autoscroll-transcript-checkbox">' + this.tt.autoScroll + ': </label>'), this.$autoScrollTranscriptCheckbox);
+ var thisObj, $autoScrollLabel, $languageSelectWrapper, $languageSelectLabel, i, $option;
- // Add field for selecting a transcript language
- // This will be deleted in initialize.js > recreatePlayer() if there are no languages
- this.$transcriptLanguageSelect = $('<select id="transcript-language-select">');
- // Add a default "Unknown" option; this will be deleted later if there are any
- // elements with a language.
- this.$unknownTranscriptOption = $('<option val="unknown">' + this.tt.unknown + '</option>');
- this.$transcriptLanguageSelect.append(this.$unknownTranscriptOption);
- this.$transcriptLanguageSelect.prop('disabled', true);
+ thisObj = this;
+ this.$transcriptArea = $('<div>', {
+ 'class': 'able-transcript-area',
+ 'tabindex': '-1'
+ });
- var languageSelectWrapper = $('<div class="transcript-language-select-wrapper">');
- this.$transcriptLanguageSelectContainer = languageSelectWrapper;
+ this.$transcriptToolbar = $('<div>', {
+ 'class': 'able-window-toolbar able-' + this.toolbarIconColor + '-controls'
+ });
- languageSelectWrapper.append($('<label for="transcript-language-select">' + this.tt.language + ': </label>'), this.$transcriptLanguageSelect);
- this.$transcriptToolbar.append(languageSelectWrapper);
- this.$transcriptArea.append(this.$transcriptToolbar, this.$transcriptDiv);
+ this.$transcriptDiv = $('<div>', {
+ 'class' : 'able-transcript'
+ });
- // If client has provided separate transcript location, put it there.
- // Otherwise append it to the body
- if (this.transcriptDivLocation) {
- $('#' + this.transcriptDivLocation).append(this.$transcriptArea);
- }
- else {
- this.$ableWrapper.append(this.$transcriptArea);
- }
+ // Transcript toolbar content
- // make it draggable (popup only; NOT external transcript)
- if (!this.transcriptDivLocation) {
- this.initDragDrop('transcript');
- if (this.prefTranscript === 1) {
- // transcript is on. Go ahead and position it
- this.positionDraggableWindow('transcript',this.getDefaultWidth('transcript'));
- }
- }
+ // Add auto Scroll checkbox
+ this.$autoScrollTranscriptCheckbox = $('<input>', {
+ 'id': 'autoscroll-transcript-checkbox',
+ 'type': 'checkbox'
+ });
+ $autoScrollLabel = $('<label>', {
+ 'for': 'autoscroll-transcript-checkbox'
+ }).text(this.tt.autoScroll);
+ this.$transcriptToolbar.append($autoScrollLabel,this.$autoScrollTranscriptCheckbox);
- // If client has provided separate transcript location, override user's preference for hiding transcript
- if (!this.prefTranscript && !this.transcriptDivLocation) {
- this.$transcriptArea.hide();
- }
- };
+ // Add field for selecting a transcript language
+ // Only necessary if there is more than one language
+ if (this.captions.length > 1) {
+ $languageSelectWrapper = $('<div>',{
+ 'class': 'transcript-language-select-wrapper'
+ });
+ $languageSelectLabel = $('<label>',{
+ 'for': 'transcript-language-select'
+ }).text(this.tt.language);
+ this.$transcriptLanguageSelect = $('<select>',{
+ 'id': 'transcript-language-select'
+ });
+ for (i=0; i < this.captions.length; i++) {
+ $option = $('<option></option>',{
+ value: this.captions[i]['language'],
+ lang: this.captions[i]['language']
+ }).text(this.captions[i]['label']);
+ if (this.captions[i]['def']) {
+ $option.prop('selected',true);
+ }
+ this.$transcriptLanguageSelect.append($option);
+ }
+ }
+ if ($languageSelectWrapper) {
+ $languageSelectWrapper.append($languageSelectLabel,this.$transcriptLanguageSelect);
+ this.$transcriptToolbar.append($languageSelectWrapper);
+ }
+ this.$transcriptArea.append(this.$transcriptToolbar, this.$transcriptDiv);
- AblePlayer.prototype.addTranscriptAreaEvents = function() {
+ // If client has provided separate transcript location, put it there.
+ // Otherwise append it to the body
+ if (this.transcriptDivLocation) {
+ $('#' + this.transcriptDivLocation).append(this.$transcriptArea);
+ }
+ else {
+ this.$ableWrapper.append(this.$transcriptArea);
+ }
- var thisObj = this;
+ // make it draggable (popup only; NOT external transcript)
+ if (!this.transcriptDivLocation) {
+ this.initDragDrop('transcript');
+ if (this.prefTranscript === 1) {
+ // transcript is on. Go ahead and position it
+ this.positionDraggableWindow('transcript',this.getDefaultWidth('transcript'));
+ }
+ }
- this.$autoScrollTranscriptCheckbox.click(function () {
- thisObj.handleTranscriptLockToggle(thisObj.$autoScrollTranscriptCheckbox.prop('checked'));
- });
+ // If client has provided separate transcript location, override user's preference for hiding transcript
+ if (!this.prefTranscript && !this.transcriptDivLocation) {
+ this.$transcriptArea.hide();
+ }
+ };
- this.$transcriptDiv.on('mousewheel DOMMouseScroll click scroll', function (e) {
- // Propagation is stopped in transcript click handler, so clicks are on the scrollbar
- // or outside of a clickable span.
- if (!thisObj.scrollingTranscript) {
- thisObj.autoScrollTranscript = false;
- thisObj.refreshControls();
- }
- thisObj.scrollingTranscript = false;
- });
+ AblePlayer.prototype.addTranscriptAreaEvents = function() {
- if (typeof this.$transcriptLanguageSelect !== 'undefined') {
+ var thisObj = this;
- this.$transcriptLanguageSelect.on('click mousedown',function (e) {
- // execute default behavior
- // prevent propagation of mouse event to toolbar or window
- e.stopPropagation();
- });
+ this.$autoScrollTranscriptCheckbox.click(function () {
+ thisObj.handleTranscriptLockToggle(thisObj.$autoScrollTranscriptCheckbox.prop('checked'));
+ });
- this.$transcriptLanguageSelect.on('change',function () {
+ this.$transcriptDiv.on('mousewheel DOMMouseScroll click scroll', function (e) {
+ // Propagation is stopped in transcript click handler, so clicks are on the scrollbar
+ // or outside of a clickable span.
+ if (!thisObj.scrollingTranscript) {
+ thisObj.autoScrollTranscript = false;
+ thisObj.refreshControls('transcript');
+ }
+ thisObj.scrollingTranscript = false;
+ });
- var language = thisObj.$transcriptLanguageSelect.val();
+ if (typeof this.$transcriptLanguageSelect !== 'undefined') {
- thisObj.syncTrackLanguages('transcript',language);
- });
- }
- };
+ this.$transcriptLanguageSelect.on('click mousedown',function (e) {
+ // execute default behavior
+ // prevent propagation of mouse event to toolbar or window
+ e.stopPropagation();
+ });
- AblePlayer.prototype.transcriptSrcHasRequiredParts = function() {
+ this.$transcriptLanguageSelect.on('change',function () {
- // check the external transcript to be sure it has all required components
- // return true or false
- // in the process, define all the needed variables and properties
+ var language = thisObj.$transcriptLanguageSelect.val();
- if ($('#' + this.transcriptSrc).length) {
- this.$transcriptArea = $('#' + this.transcriptSrc);
- if (this.$transcriptArea.find('.able-window-toolbar').length) {
- this.$transcriptToolbar = this.$transcriptArea.find('.able-window-toolbar').eq(0);
- if (this.$transcriptArea.find('.able-transcript').length) {
- this.$transcriptDiv = this.$transcriptArea.find('.able-transcript').eq(0);
- if (this.$transcriptArea.find('.able-transcript-seekpoint').length) {
- this.$transcriptSeekpoints = this.$transcriptArea.find('.able-transcript-seekpoint');
- return true;
- }
- }
- }
- }
- return false;
- }
+ thisObj.syncTrackLanguages('transcript',language);
+ });
+ }
+ };
- AblePlayer.prototype.setupManualTranscript = function() {
+ AblePlayer.prototype.transcriptSrcHasRequiredParts = function() {
- // Add an auto-scroll checkbox to the toolbar
+ // check the external transcript to be sure it has all required components
+ // return true or false
+ // in the process, define all the needed variables and properties
- this.$autoScrollTranscriptCheckbox = $('<input id="autoscroll-transcript-checkbox" type="checkbox">');
- this.$transcriptToolbar.append($('<label for="autoscroll-transcript-checkbox">' + this.tt.autoScroll + ': </label>'), this.$autoScrollTranscriptCheckbox);
+ if ($('#' + this.transcriptSrc).length) {
+ this.$transcriptArea = $('#' + this.transcriptSrc);
+ if (this.$transcriptArea.find('.able-window-toolbar').length) {
+ this.$transcriptToolbar = this.$transcriptArea.find('.able-window-toolbar').eq(0);
+ if (this.$transcriptArea.find('.able-transcript').length) {
+ this.$transcriptDiv = this.$transcriptArea.find('.able-transcript').eq(0);
+ if (this.$transcriptArea.find('.able-transcript-seekpoint').length) {
+ this.$transcriptSeekpoints = this.$transcriptArea.find('.able-transcript-seekpoint');
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
- };
+ AblePlayer.prototype.setupManualTranscript = function() {
- AblePlayer.prototype.updateTranscript = function() {
+ // Add an auto-scroll checkbox to the toolbar
- if (!this.transcriptType) {
- return;
- }
+ this.$autoScrollTranscriptCheckbox = $('<input id="autoscroll-transcript-checkbox" type="checkbox">');
+ this.$transcriptToolbar.append($('<label for="autoscroll-transcript-checkbox">' + this.tt.autoScroll + ': </label>'), this.$autoScrollTranscriptCheckbox);
- if (this.transcriptType === 'external' || this.transcriptType === 'popup') {
+ };
- var chapters, captions, descriptions;
+ AblePlayer.prototype.updateTranscript = function() {
- // Language of transcript might be different than language of captions
- // But both are in sync by default
- if (this.transcriptLang) {
- captions = this.transcriptCaptions.cues;
- }
- else {
- if (this.transcriptCaptions) {
- this.transcriptLang = this.transcriptCaptions.language;
- captions = this.transcriptCaptions.cues;
- }
- else if (this.selectedCaptions) {
- this.transcriptLang = this.captionLang;
- captions = this.selectedCaptions.cues;
- }
- }
+ if (!this.transcriptType) {
+ return;
+ }
- // setup chapters
- if (this.transcriptChapters) {
- chapters = this.transcriptChapters.cues;
- }
- else if (this.chapters.length > 0) {
- // Try and match the caption language.
- if (this.transcriptLang) {
- for (var ii = 0; ii < this.chapters.length; ii++) {
- if (this.chapters[ii].language === this.transcriptLang) {
- chapters = this.chapters[ii].cues;
- }
- }
- }
- if (typeof chapters === 'undefined') {
- chapters = this.chapters[0].cues || [];
- }
- }
+ if (this.transcriptType === 'external' || this.transcriptType === 'popup') {
- // setup descriptions
- if (this.transcriptDescriptions) {
- descriptions = this.transcriptDescriptions.cues;
- }
- else if (this.descriptions.length > 0) {
- // Try and match the caption language.
- if (this.transcriptLang) {
- for (var ii = 0; ii < this.descriptions.length; ii++) {
- if (this.descriptions[ii].language === this.transcriptLang) {
- descriptions = this.descriptions[ii].cues;
- }
- }
- }
- if (!descriptions) {
- descriptions = this.descriptions[0].cues || [];
- }
- }
+ var chapters, captions, descriptions;
- var div = this.generateTranscript(chapters || [], captions || [], descriptions || []);
+ // Language of transcript might be different than language of captions
+ // But both are in sync by default
+ if (this.transcriptLang) {
+ captions = this.transcriptCaptions.cues;
+ }
+ else {
+ if (this.transcriptCaptions) {
+ this.transcriptLang = this.transcriptCaptions.language;
+ captions = this.transcriptCaptions.cues;
+ }
+ else if (this.selectedCaptions) {
+ this.transcriptLang = this.captionLang;
+ captions = this.selectedCaptions.cues;
+ }
+ }
- this.$transcriptDiv.html(div);
- // reset transcript selected <option> to this.transcriptLang
- if (this.$transcriptLanguageSelect) {
- this.$transcriptLanguageSelect.find('option:selected').prop('selected',false);
- this.$transcriptLanguageSelect.find('option[lang=' + this.transcriptLang + ']').prop('selected',true);
- }
- }
+ // setup chapters
+ if (this.transcriptChapters) {
+ chapters = this.transcriptChapters.cues;
+ }
+ else if (this.chapters.length > 0) {
+ // Try and match the caption language.
+ if (this.transcriptLang) {
+ for (var i = 0; i < this.chapters.length; i++) {
+ if (this.chapters[i].language === this.transcriptLang) {
+ chapters = this.chapters[i].cues;
+ }
+ }
+ }
+ if (typeof chapters === 'undefined') {
+ chapters = this.chapters[0].cues || [];
+ }
+ }
- var thisObj = this;
+ // setup descriptions
+ if (this.transcriptDescriptions) {
+ descriptions = this.transcriptDescriptions.cues;
+ }
+ else if (this.descriptions.length > 0) {
+ // Try and match the caption language.
+ if (this.transcriptLang) {
+ for (var i = 0; i < this.descriptions.length; i++) {
+ if (this.descriptions[i].language === this.transcriptLang) {
+ descriptions = this.descriptions[i].cues;
+ }
+ }
+ }
+ if (!descriptions) {
+ descriptions = this.descriptions[0].cues || [];
+ }
+ }
- // Make transcript tabbable if preference is turned on.
- if (this.prefTabbable === 1) {
- $('.able-transcript span.able-transcript-seekpoint').attr('tabindex','0');
- }
+ var div = this.generateTranscript(chapters || [], captions || [], descriptions || []);
- // handle clicks on text within transcript
- // Note: This event listeners handles clicks only, not keydown events
- // Pressing Enter on an element that is not natively clickable does NOT trigger click()
- // Keydown events are handled elsehwere, both globally (ableplayer-base.js) and locally (event.js)
- if (this.$transcriptArea.length > 0) {
- this.$transcriptArea.find('span.able-transcript-seekpoint').click(function(e) {
- thisObj.seekTrigger = 'transcript';
- var spanStart = parseFloat($(this).attr('data-start'));
- // Add a tiny amount so that we're inside the span.
- spanStart += .01;
- // Each click within the transcript triggers two click events (not sure why)
- // this.seekingFromTranscript is a stopgab to prevent two calls to SeekTo()
- if (!thisObj.seekingFromTranscript) {
- thisObj.seekingFromTranscript = true;
- thisObj.seekTo(spanStart);
- }
- else {
- // don't seek a second time, but do reset var
- thisObj.seekingFromTranscript = false;
- }
- });
- }
- };
+ this.$transcriptDiv.html(div);
+ // reset transcript selected <option> to this.transcriptLang
+ if (this.$transcriptLanguageSelect) {
+ this.$transcriptLanguageSelect.find('option:selected').prop('selected',false);
+ this.$transcriptLanguageSelect.find('option[lang=' + this.transcriptLang + ']').prop('selected',true);
+ }
+ }
- AblePlayer.prototype.highlightTranscript = function (currentTime) {
+ var thisObj = this;
- //show highlight in transcript marking current caption
+ // Make transcript tabbable if preference is turned on.
+ if (this.prefTabbable === 1) {
+ $('.able-transcript span.able-transcript-seekpoint').attr('tabindex','0');
+ }
- if (!this.transcriptType) {
- return;
- }
+ // handle clicks on text within transcript
+ // Note: This event listeners handles clicks only, not keydown events
+ // Pressing Enter on an element that is not natively clickable does NOT trigger click()
+ // Keydown events are handled elsehwere, both globally (ableplayer-base.js) and locally (event.js)
+ if (this.$transcriptArea.length > 0) {
+ this.$transcriptArea.find('span.able-transcript-seekpoint').click(function(e) {
+ thisObj.seekTrigger = 'transcript';
+ var spanStart = parseFloat($(this).attr('data-start'));
+ // Add a tiny amount so that we're inside the span.
+ spanStart += .01;
+ // Each click within the transcript triggers two click events (not sure why)
+ // this.seekingFromTranscript is a stopgab to prevent two calls to SeekTo()
+ if (!thisObj.seekingFromTranscript) {
+ thisObj.seekingFromTranscript = true;
+ thisObj.seekTo(spanStart);
+ }
+ else {
+ // don't seek a second time, but do reset var
+ thisObj.seekingFromTranscript = false;
+ }
+ });
+ }
+ };
- var start, end;
- var thisObj = this;
+ AblePlayer.prototype.highlightTranscript = function (currentTime) {
- currentTime = parseFloat(currentTime);
+ //show highlight in transcript marking current caption
- // Highlight the current transcript item.
- this.$transcriptArea.find('span.able-transcript-caption').each(function() {
- start = parseFloat($(this).attr('data-start'));
- end = parseFloat($(this).attr('data-end'));
- if (currentTime >= start && currentTime <= end) {
- // move all previous highlights before adding one to current span
- thisObj.$transcriptArea.find('.able-highlight').removeClass('able-highlight');
- $(this).addClass('able-highlight');
- return false;
- }
- });
- thisObj.currentHighlight = $('.able-highlight');
- if (thisObj.currentHighlight.length === 0) {
- // Nothing highlighted.
- thisObj.currentHighlight = null;
- }
- };
+ if (!this.transcriptType) {
+ return;
+ }
- AblePlayer.prototype.generateTranscript = function(chapters, captions, descriptions) {
+ var start, end, isChapterHeading;
+ var thisObj = this;
- var thisObj = this;
+ currentTime = parseFloat(currentTime);
- var $main = $('<div class="able-transcript-container"></div>');
- var transcriptTitle;
+ // Highlight the current transcript item.
+ this.$transcriptArea.find('span.able-transcript-seekpoint').each(function() {
+ start = parseFloat($(this).attr('data-start'));
+ end = parseFloat($(this).attr('data-end'));
+ // be sure this isn't a chapter (don't highlight chapter headings)
+ if ($(this).parent().hasClass('able-transcript-chapter-heading')) {
+ isChapterHeading = true;
+ }
+ else {
+ isChapterHeading = false;
+ }
- // set language for transcript container
- $main.attr('lang', this.transcriptLang);
+ if (currentTime >= start && currentTime <= end && !isChapterHeading) {
+ // move all previous highlights before adding one to current span
+ thisObj.$transcriptArea.find('.able-highlight').removeClass('able-highlight');
+ $(this).addClass('able-highlight');
+ return false;
+ }
+ });
+ thisObj.currentHighlight = $('.able-highlight');
+ if (thisObj.currentHighlight.length === 0) {
+ // Nothing highlighted.
+ thisObj.currentHighlight = null;
+ }
+ };
- if (typeof this.transcriptTitle !== 'undefined') {
- transcriptTitle = this.transcriptTitle;
- }
- else if (this.lyricsMode) {
- transcriptTitle = this.tt.lyricsTitle;
- }
- else {
- transcriptTitle = this.tt.transcriptTitle;
- }
+ AblePlayer.prototype.generateTranscript = function(chapters, captions, descriptions) {
- if (typeof this.transcriptDivLocation === 'undefined') {
- // only add an HTML heading to internal transcript
- // external transcript is expected to have its own heading
- var headingNumber = this.playerHeadingLevel;
- headingNumber += 1;
- var chapterHeadingNumber = headingNumber + 1;
+ var thisObj = this;
- if (headingNumber <= 6) {
- var transcriptHeading = 'h' + headingNumber.toString();
- }
- else {
- var transcriptHeading = 'div';
- }
- // var transcriptHeadingTag = '<' + transcriptHeading + ' class="able-transcript-heading">';
- var $transcriptHeadingTag = $('<' + transcriptHeading + '>');
- $transcriptHeadingTag.addClass('able-transcript-heading');
- if (headingNumber > 6) {
- $transcriptHeadingTag.attr({
- 'role': 'heading',
- 'aria-level': headingNumber
- });
- }
- $transcriptHeadingTag.text(transcriptTitle);
+ var $main = $('<div class="able-transcript-container"></div>');
+ var transcriptTitle;
- // set language of transcript heading to language of player
- // this is independent of language of transcript
- $transcriptHeadingTag.attr('lang', this.lang);
+ // set language for transcript container
+ $main.attr('lang', this.transcriptLang);
- $main.append($transcriptHeadingTag);
- }
+ if (typeof this.transcriptTitle !== 'undefined') {
+ transcriptTitle = this.transcriptTitle;
+ }
+ else if (this.lyricsMode) {
+ transcriptTitle = this.tt.lyricsTitle;
+ }
+ else {
+ transcriptTitle = this.tt.transcriptTitle;
+ }
- var nextChapter = 0;
- var nextCap = 0;
- var nextDesc = 0;
+ if (typeof this.transcriptDivLocation === 'undefined') {
+ // only add an HTML heading to internal transcript
+ // external transcript is expected to have its own heading
+ var headingNumber = this.playerHeadingLevel;
+ headingNumber += 1;
+ var chapterHeadingNumber = headingNumber + 1;
- var addChapter = function(div, chap) {
+ if (headingNumber <= 6) {
+ var transcriptHeading = 'h' + headingNumber.toString();
+ }
+ else {
+ var transcriptHeading = 'div';
+ }
+ // var transcriptHeadingTag = '<' + transcriptHeading + ' class="able-transcript-heading">';
+ var $transcriptHeadingTag = $('<' + transcriptHeading + '>');
+ $transcriptHeadingTag.addClass('able-transcript-heading');
+ if (headingNumber > 6) {
+ $transcriptHeadingTag.attr({
+ 'role': 'heading',
+ 'aria-level': headingNumber
+ });
+ }
+ $transcriptHeadingTag.text(transcriptTitle);
- if (chapterHeadingNumber <= 6) {
- var chapterHeading = 'h' + chapterHeadingNumber.toString();
- }
- else {
- var chapterHeading = 'div';
- }
+ // set language of transcript heading to language of player
+ // this is independent of language of transcript
+ $transcriptHeadingTag.attr('lang', this.lang);
- var $chapterHeadingTag = $('<' + chapterHeading + '>',{
- 'class': 'able-transcript-chapter-heading'
- });
- if (chapterHeadingNumber > 6) {
- $chapterHeadingTag.attr({
- 'role': 'heading',
- 'aria-level': chapterHeadingNumber
- });
- }
+ $main.append($transcriptHeadingTag);
+ }
- var flattenComponentForChapter = function(comp) {
+ var nextChapter = 0;
+ var nextCap = 0;
+ var nextDesc = 0;
- var result = [];
- if (comp.type === 'string') {
- result.push(comp.value);
- }
- else {
- for (var ii = 0; ii < comp.children.length; ii++) {
- result = result.concat(flattenComponentForChapter(comp.children[ii]));
- }
- }
- return result;
- }
+ var addChapter = function(div, chap) {
- var $chapSpan = $('<span>',{
- 'class': 'able-transcript-seekpoint'
- });
- for (var ii = 0; ii < chap.components.children.length; ii++) {
- var results = flattenComponentForChapter(chap.components.children[ii]);
- for (var jj = 0; jj < results.length; jj++) {
- $chapSpan.append(results[jj]);
- }
- }
- $chapSpan.attr('data-start', chap.start.toString());
- $chapSpan.attr('data-end', chap.end.toString());
- $chapterHeadingTag.append($chapSpan);
+ if (chapterHeadingNumber <= 6) {
+ var chapterHeading = 'h' + chapterHeadingNumber.toString();
+ }
+ else {
+ var chapterHeading = 'div';
+ }
- div.append($chapterHeadingTag);
- };
+ var $chapterHeadingTag = $('<' + chapterHeading + '>',{
+ 'class': 'able-transcript-chapter-heading'
+ });
+ if (chapterHeadingNumber > 6) {
+ $chapterHeadingTag.attr({
+ 'role': 'heading',
+ 'aria-level': chapterHeadingNumber
+ });
+ }
- var addDescription = function(div, desc) {
- var $descDiv = $('<div>', {
- 'class': 'able-transcript-desc'
- });
- var $descHiddenSpan = $('<span>',{
- 'class': 'able-hidden'
- });
- $descHiddenSpan.attr('lang', thisObj.lang);
- $descHiddenSpan.text(thisObj.tt.prefHeadingDescription + ': ');
- $descDiv.append($descHiddenSpan);
+ var flattenComponentForChapter = function(comp) {
- var flattenComponentForDescription = function(comp) {
+ var result = [];
+ if (comp.type === 'string') {
+ result.push(comp.value);
+ }
+ else {
+ for (var i = 0; i < comp.children.length; i++) {
+ result = result.concat(flattenComponentForChapter(comp.children[i]));
+ }
+ }
+ return result;
+ }
- var result = [];
- if (comp.type === 'string') {
- result.push(comp.value);
- }
- else {
- for (var ii = 0; ii < comp.children.length; ii++) {
- result = result.concat(flattenComponentForDescription(comp.children[ii]));
- }
- }
- return result;
- }
+ var $chapSpan = $('<span>',{
+ 'class': 'able-transcript-seekpoint'
+ });
+ for (var i = 0; i < chap.components.children.length; i++) {
+ var results = flattenComponentForChapter(chap.components.children[i]);
+ for (var jj = 0; jj < results.length; jj++) {
+ $chapSpan.append(results[jj]);
+ }
+ }
+ $chapSpan.attr('data-start', chap.start.toString());
+ $chapSpan.attr('data-end', chap.end.toString());
+ $chapterHeadingTag.append($chapSpan);
- var $descSpan = $('<span>',{
- 'class': 'able-transcript-seekpoint'
- });
- for (var ii = 0; ii < desc.components.children.length; ii++) {
- var results = flattenComponentForDescription(desc.components.children[ii]);
- for (var jj = 0; jj < results.length; jj++) {
- $descSpan.append(results[jj]);
- }
- }
- $descSpan.attr('data-start', desc.start.toString());
- $descSpan.attr('data-end', desc.end.toString());
- $descDiv.append($descSpan);
+ div.append($chapterHeadingTag);
+ };
- div.append($descDiv);
- };
+ var addDescription = function(div, desc) {
+ var $descDiv = $('<div>', {
+ 'class': 'able-transcript-desc'
+ });
+ var $descHiddenSpan = $('<span>',{
+ 'class': 'able-hidden'
+ });
+ $descHiddenSpan.attr('lang', thisObj.lang);
+ $descHiddenSpan.text(thisObj.tt.prefHeadingDescription + ': ');
+ $descDiv.append($descHiddenSpan);
- var addCaption = function(div, cap) {
+ var flattenComponentForDescription = function(comp) {
- var $capSpan = $('<span>',{
- 'class': 'able-transcript-seekpoint able-transcript-caption'
- });
+ var result = [];
+ if (comp.type === 'string') {
+ result.push(comp.value);
+ }
+ else {
+ for (var i = 0; i < comp.children.length; i++) {
+ result = result.concat(flattenComponentForDescription(comp.children[i]));
+ }
+ }
+ return result;
+ }
- var flattenComponentForCaption = function(comp) {
+ var $descSpan = $('<span>',{
+ 'class': 'able-transcript-seekpoint'
+ });
+ for (var i = 0; i < desc.components.children.length; i++) {
+ var results = flattenComponentForDescription(desc.components.children[i]);
+ for (var jj = 0; jj < results.length; jj++) {
+ $descSpan.append(results[jj]);
+ }
+ }
+ $descSpan.attr('data-start', desc.start.toString());
+ $descSpan.attr('data-end', desc.end.toString());
+ $descDiv.append($descSpan);
- var result = [];
+ div.append($descDiv);
+ };
- var flattenString = function (str) {
- var result = [];
- if (str === '') {
- return result;
- }
- var openBracket = str.indexOf('[');
- var closeBracket = str.indexOf(']');
- var openParen = str.indexOf('(');
- var closeParen = str.indexOf(')');
+ var addCaption = function(div, cap) {
- var hasBrackets = openBracket !== -1 && closeBracket !== -1;
- var hasParens = openParen !== -1 && closeParen !== -1;
+ var $capSpan = $('<span>',{
+ 'class': 'able-transcript-seekpoint able-transcript-caption'
+ });
- if ((hasParens && hasBrackets && openBracket < openParen) || hasBrackets) {
- result = result.concat(flattenString(str.substring(0, openBracket)));
- var $silentSpan = $('<span>',{
- 'class': 'able-unspoken'
- });
- $silentSpan.text(str.substring(openBracket, closeBracket + 1));
- result.push($silentSpan);
- result = result.concat(flattenString(str.substring(openParen, closeParen + 1)));
- }
- else if (hasParens) {
- result = result.concat(flattenString(str.substring(0, openParen)));
- var $silentSpan = $('<span>',{
- 'class': 'able-unspoken'
- });
- $silentSpan.text(str.substring(openBracket, closeBracket + 1));
- result.push($silentSpan);
- result = result.concat(flattenString(str.substring(closeParen + 1)));
- }
- else {
- result.push(str);
- }
- return result;
- };
+ var flattenComponentForCaption = function(comp) {
- if (comp.type === 'string') {
- result = result.concat(flattenString(comp.value));
- }
- else if (comp.type === 'v') {
- var $vSpan = $('<span>',{
- 'class': 'able-unspoken'
- });
- $vSpan.text('(' + comp.value + ')');
- result.push($vSpan);
- for (var ii = 0; ii < comp.children.length; ii++) {
- var subResults = flattenComponentForCaption(comp.children[ii]);
- for (var jj = 0; jj < subResults.length; jj++) {
- result.push(subResults[jj]);
- }
- }
- }
- else if (comp.type === 'b' || comp.type === 'i') {
- if (comp.type === 'b') {
- var $tag = $('<strong>');
- }
- else if (comp.type === 'i') {
- var $tag = $('<em>');
- }
- for (var ii = 0; ii < comp.children.length; ii++) {
- var subResults = flattenComponentForCaption(comp.children[ii]);
- for (var jj = 0; jj < subResults.length; jj++) {
- $tag.append(subResults[jj]);
- }
- }
- if (comp.type === 'b' || comp.type == 'i') {
- result.push($tag,' ');
- }
- }
- else {
- for (var ii = 0; ii < comp.children.length; ii++) {
- result = result.concat(flattenComponentForCaption(comp.children[ii]));
- }
- }
- return result;
- };
+ var result = [];
- for (var ii = 0; ii < cap.components.children.length; ii++) {
- var results = flattenComponentForCaption(cap.components.children[ii]);
- for (var jj = 0; jj < results.length; jj++) {
- var result = results[jj];
- if (typeof result === 'string') {
- if (thisObj.lyricsMode) {
- // add <br> BETWEEN each caption and WITHIN each caption (if payload includes "\n")
- result = result.replace('\n','<br>') + '<br>';
- }
- else {
- // just add a space between captions
- result += ' ';
- }
- }
- $capSpan.append(result);
- }
- }
- $capSpan.attr('data-start', cap.start.toString());
- $capSpan.attr('data-end', cap.end.toString());
- div.append($capSpan);
- div.append(' \n');
- };
+ var parts = 0;
- // keep looping as long as any one of the three arrays has content
- while ((nextChapter < chapters.length) || (nextDesc < descriptions.length) || (nextCap < captions.length)) {
+ var flattenString = function (str) {
- if ((nextChapter < chapters.length) && (nextDesc < descriptions.length) && (nextCap < captions.length)) {
- // they all three have content
- var firstStart = Math.min(chapters[nextChapter].start,descriptions[nextDesc].start,captions[nextCap].start);
- }
- else if ((nextChapter < chapters.length) && (nextDesc < descriptions.length)) {
- // chapters & descriptions have content
- var firstStart = Math.min(chapters[nextChapter].start,descriptions[nextDesc].start);
- }
- else if ((nextChapter < chapters.length) && (nextCap < captions.length)) {
- // chapters & captions have content
- var firstStart = Math.min(chapters[nextChapter].start,captions[nextCap].start);
- }
- else if ((nextDesc < descriptions.length) && (nextCap < captions.length)) {
- // descriptions & captions have content
- var firstStart = Math.min(descriptions[nextDesc].start,captions[nextCap].start);
- }
- else {
- var firstStart = null;
- }
- if (firstStart !== null) {
- if (typeof chapters[nextChapter] !== 'undefined' && chapters[nextChapter].start === firstStart) {
- addChapter($main, chapters[nextChapter]);
- nextChapter += 1;
- }
- else if (typeof descriptions[nextDesc] !== 'undefined' && descriptions[nextDesc].start === firstStart) {
- addDescription($main, descriptions[nextDesc]);
- nextDesc += 1;
- }
- else {
- addCaption($main, captions[nextCap]);
- nextCap += 1;
- }
- }
- else {
- if (nextChapter < chapters.length) {
- addChapter($main, chapters[nextChapter]);
- nextChapter += 1;
- }
- else if (nextDesc < descriptions.length) {
- addDescription($main, descriptions[nextDesc]);
- nextDesc += 1;
- }
- else if (nextCap < captions.length) {
- addCaption($main, captions[nextCap]);
- nextCap += 1;
- }
- }
- }
- // organize transcript into blocks using [] and () as starting points
- var $components = $main.children();
- var spanCount = 0;
- var openBlock = true;
- $components.each(function() {
- if ($(this).hasClass('able-transcript-caption')) {
- if ($(this).text().indexOf('[') !== -1 || $(this).text().indexOf('(') !== -1) {
- // this caption includes a bracket or parenth. Start a new block
- // close the previous block first
- if (spanCount > 0) {
- $main.find('.able-block-temp').removeClass('able-block-temp').wrapAll('<div class="able-transcript-block"></div>');
- spanCount = 0;
- }
- }
- $(this).addClass('able-block-temp');
- spanCount++;
- }
- else {
- // this is not a caption. Close the caption block
- if (spanCount > 0) {
- $main.find('.able-block-temp').removeClass('able-block-temp').wrapAll('<div class="able-transcript-block"></div>');
- spanCount = 0;
- }
- }
- });
- return $main;
- };
+ parts++;
+
+ var flatStr;
+ var result = [];
+ if (str === '') {
+ return result;
+ }
+
+ var openBracket = str.indexOf('[');
+ var closeBracket = str.indexOf(']');
+ var openParen = str.indexOf('(');
+ var closeParen = str.indexOf(')');
+
+ var hasBrackets = openBracket !== -1 && closeBracket !== -1;
+ var hasParens = openParen !== -1 && closeParen !== -1;
+
+ if (hasParens || hasBrackets) {
+ if (parts > 1) {
+ // force a line break between sections that contain parens or brackets
+ var silentSpanBreak = '<br/>';
+ }
+ else {
+ var silentSpanBreak = '';
+ }
+ var silentSpanOpen = silentSpanBreak + '<span class="able-unspoken">';
+ var silentSpanClose = '</span>';
+ if (hasParens && hasBrackets) {
+ // string has both!
+ if (openBracket < openParen) {
+ // brackets come first. Parse parens separately
+ hasParens = false;
+ }
+ else {
+ // parens come first. Parse brackets separately
+ hasBrackets = false;
+ }
+ }
+ }
+ if (hasParens) {
+ flatStr = str.substring(0, openParen);
+ flatStr += silentSpanOpen;
+ flatStr += str.substring(openParen, closeParen + 1);
+ flatStr += silentSpanClose;
+ flatStr += flattenString(str.substring(closeParen + 1));
+ result.push(flatStr);
+ }
+ else if (hasBrackets) {
+ flatStr = str.substring(0, openBracket);
+ flatStr += silentSpanOpen;
+ flatStr += str.substring(openBracket, closeBracket + 1);
+ flatStr += silentSpanClose;
+ flatStr += flattenString(str.substring(closeBracket + 1));
+ result.push(flatStr);
+ }
+ else {
+ result.push(str);
+ }
+ return result;
+ };
+
+ if (comp.type === 'string') {
+ result = result.concat(flattenString(comp.value));
+ }
+ else if (comp.type === 'v') {
+ var $vSpan = $('<span>',{
+ 'class': 'able-unspoken'
+ });
+ $vSpan.text('(' + comp.value + ')');
+ result.push($vSpan);
+ for (var i = 0; i < comp.children.length; i++) {
+ var subResults = flattenComponentForCaption(comp.children[i]);
+ for (var jj = 0; jj < subResults.length; jj++) {
+ result.push(subResults[jj]);
+ }
+ }
+ }
+ else if (comp.type === 'b' || comp.type === 'i') {
+ if (comp.type === 'b') {
+ var $tag = $('<strong>');
+ }
+ else if (comp.type === 'i') {
+ var $tag = $('<em>');
+ }
+ for (var i = 0; i < comp.children.length; i++) {
+ var subResults = flattenComponentForCaption(comp.children[i]);
+ for (var jj = 0; jj < subResults.length; jj++) {
+ $tag.append(subResults[jj]);
+ }
+ }
+ if (comp.type === 'b' || comp.type == 'i') {
+ result.push($tag,' ');
+ }
+ }
+ else {
+ for (var i = 0; i < comp.children.length; i++) {
+ result = result.concat(flattenComponentForCaption(comp.children[i]));
+ }
+ }
+ return result;
+ };
+
+ for (var i = 0; i < cap.components.children.length; i++) {
+ var results = flattenComponentForCaption(cap.components.children[i]);
+ for (var jj = 0; jj < results.length; jj++) {
+ var result = results[jj];
+ if (typeof result === 'string') {
+ if (thisObj.lyricsMode) {
+ // add <br> BETWEEN each caption and WITHIN each caption (if payload includes "\n")
+ result = result.replace('\n','<br>') + '<br>';
+ }
+ else {
+ // just add a space between captions
+ result += ' ';
+ }
+ }
+ $capSpan.append(result);
+ }
+ }
+ $capSpan.attr('data-start', cap.start.toString());
+ $capSpan.attr('data-end', cap.end.toString());
+ div.append($capSpan);
+ div.append(' \n');
+ };
+
+ // keep looping as long as any one of the three arrays has content
+ while ((nextChapter < chapters.length) || (nextDesc < descriptions.length) || (nextCap < captions.length)) {
+
+ if ((nextChapter < chapters.length) && (nextDesc < descriptions.length) && (nextCap < captions.length)) {
+ // they all three have content
+ var firstStart = Math.min(chapters[nextChapter].start,descriptions[nextDesc].start,captions[nextCap].start);
+ }
+ else if ((nextChapter < chapters.length) && (nextDesc < descriptions.length)) {
+ // chapters & descriptions have content
+ var firstStart = Math.min(chapters[nextChapter].start,descriptions[nextDesc].start);
+ }
+ else if ((nextChapter < chapters.length) && (nextCap < captions.length)) {
+ // chapters & captions have content
+ var firstStart = Math.min(chapters[nextChapter].start,captions[nextCap].start);
+ }
+ else if ((nextDesc < descriptions.length) && (nextCap < captions.length)) {
+ // descriptions & captions have content
+ var firstStart = Math.min(descriptions[nextDesc].start,captions[nextCap].start);
+ }
+ else {
+ var firstStart = null;
+ }
+ if (firstStart !== null) {
+ if (typeof chapters[nextChapter] !== 'undefined' && chapters[nextChapter].start === firstStart) {
+ addChapter($main, chapters[nextChapter]);
+ nextChapter += 1;
+ }
+ else if (typeof descriptions[nextDesc] !== 'undefined' && descriptions[nextDesc].start === firstStart) {
+ addDescription($main, descriptions[nextDesc]);
+ nextDesc += 1;
+ }
+ else {
+ addCaption($main, captions[nextCap]);
+ nextCap += 1;
+ }
+ }
+ else {
+ if (nextChapter < chapters.length) {
+ addChapter($main, chapters[nextChapter]);
+ nextChapter += 1;
+ }
+ else if (nextDesc < descriptions.length) {
+ addDescription($main, descriptions[nextDesc]);
+ nextDesc += 1;
+ }
+ else if (nextCap < captions.length) {
+ addCaption($main, captions[nextCap]);
+ nextCap += 1;
+ }
+ }
+ }
+ // organize transcript into blocks using [] and () as starting points
+ var $components = $main.children();
+ var spanCount = 0;
+ var openBlock = true;
+ $components.each(function() {
+ if ($(this).hasClass('able-transcript-caption')) {
+ if ($(this).text().indexOf('[') !== -1 || $(this).text().indexOf('(') !== -1) {
+ // this caption includes a bracket or parenth. Start a new block
+ // close the previous block first
+ if (spanCount > 0) {
+ $main.find('.able-block-temp').removeClass('able-block-temp').wrapAll('<div class="able-transcript-block"></div>');
+ spanCount = 0;
+ }
+ }
+ $(this).addClass('able-block-temp');
+ spanCount++;
+ }
+ else {
+ // this is not a caption. Close the caption block
+ if (spanCount > 0) {
+ $main.find('.able-block-temp').removeClass('able-block-temp').wrapAll('<div class="able-transcript-block"></div>');
+ spanCount = 0;
+ }
+ }
+ });
+ return $main;
+ };
})(jQuery);