Skip to content

Commit

Permalink
Open interactive media if chapters OR references are present
Browse files Browse the repository at this point in the history
  • Loading branch information
Splines committed May 22, 2024
1 parent 3d1e319 commit 4ee7034
Show file tree
Hide file tree
Showing 3 changed files with 248 additions and 195 deletions.
115 changes: 65 additions & 50 deletions app/assets/javascripts/thyme/chapter_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,31 @@ class ChapterManager {
this.iaBackButton = iaBackButton;
}

load() {
/**
* Loads chapters from the video element and displays them in the interactive area.
* @param {function} onLoad - Callback function that is called when chapters have been loaded.
* It receives a boolean value that indicates whether chapters are present.
*/
load(onLoad) {
let initialChapters = true;
const videoId = thymeAttributes.video.id;
const chaptersElement = $("#" + videoId + ' track[kind="chapters"]').get(0);
const chapters = this.#getChapters();
const chapterManager = this;

/* after video metadata have been loaded, display chapters in the interactive area
Originally (and more appropriately, according to the standards),
only the 'loadedmetadata' event was used. However, Firefox triggers this event too soon,
i.e. when the readyStates for chapters and elements are 1 (loading) instead of 2 (loaded)
for the events, see https://www.w3schools.com/jsref/event_oncanplay.asp */
video.addEventListener("loadedmetadata", function () {
if (initialChapters && chaptersElement.readyState === 2) {
if (initialChapters && chapters.readyState === 2) {
chapterManager.#displayChapters();
initialChapters = false;
if (onLoad) {
onLoad(chapters.track ? (chapters.track.cues.length > 0) : false);
}
}
});
video.addEventListener("canplay", function () {
if (initialChapters && chaptersElement.readyState === 2) {
if (initialChapters && chapters.readyState === 2) {
chapterManager.#displayChapters();
initialChapters = false;
}
Expand Down Expand Up @@ -66,56 +72,65 @@ class ChapterManager {
}
}

#displayChapters() {
#getChapters() {
const videoId = thymeAttributes.video.id;
return $("#" + videoId + ' track[kind="chapters"]').get(0);
}

#displayChapters() {
const chapterListId = this.chapterListId;
const iaBackButton = this.iaBackButton;
const chapterList = $("#" + chapterListId);
const chaptersElement = $("#" + videoId + ' track[kind="chapters"]').get(0);

let chaptersTrack;
if (chaptersElement.readyState === 2 && (chaptersTrack = chaptersElement.track)) {
chaptersTrack.mode = "hidden";
let times = [];
// read out the chapter track cues and generate html elements for chapters,
// run katex on them
for (let i = 0; i < chaptersTrack.cues.length; i++) {
const cue = chaptersTrack.cues[i];
const chapterName = cue.text;
const start = cue.startTime;
times.push(start);
const $listItem = $("<li/>");
const $link = $("<a/>", {
id: "c-" + start,
text: chapterName,
});
chapterList.append($listItem.append($link));
const chapterElement = $link.get(0);
thymeUtility.renderLatex(chapterElement);
$link.data("text", chapterName);
// if a chapter element is clicked, transport to chapter start time
$link.on("click", function () {
iaBackButton.update();
video.currentTime = this.id.replace("c-", "");
});
}
// store start times as data attribute
chapterList.get(0).dataset.times = JSON.stringify(times);
chapterList.show();
// if the chapters cue changes (i.e. a switch between chapters), highlight
// current chapter elment and scroll it into view, remove highlighting from
// old chapter
$(chaptersTrack).on("cuechange", function () {
$("#" + chapterListId + " li a").removeClass("current");
if (this.activeCues.length > 0) {
const activeStart = this.activeCues[0].startTime;
const chapter = document.getElementById("c-" + activeStart);
if (chapter) {
$(chapter).addClass("current");
chapter.scrollIntoView();
}
}
const chapters = this.#getChapters();
if (chapters.readyState != 2) {
return;
}
const track = chapters.track;
if (!track) {
return;
}

track.mode = "hidden";
let times = [];
// read out the chapter track cues and generate html elements for chapters,
// run katex on them
for (let i = 0; i < track.cues.length; i++) {
const cue = track.cues[i];
const chapterName = cue.text;
const start = cue.startTime;
times.push(start);
const $listItem = $("<li/>");
const $link = $("<a/>", {
id: "c-" + start,
text: chapterName,
});
chapterList.append($listItem.append($link));
const chapterElement = $link.get(0);
thymeUtility.renderLatex(chapterElement);
$link.data("text", chapterName);
// if a chapter element is clicked, transport to chapter start time
$link.on("click", function () {
iaBackButton.update();
video.currentTime = this.id.replace("c-", "");
});
}
// store start times as data attribute
chapterList.get(0).dataset.times = JSON.stringify(times);
chapterList.show();
// if the chapters cue changes (i.e. a switch between chapters), highlight
// current chapter elment and scroll it into view, remove highlighting from
// old chapter
$(track).on("cuechange", function () {
$("#" + chapterListId + " li a").removeClass("current");
if (this.activeCues.length > 0) {
const activeStart = this.activeCues[0].startTime;
const chapter = document.getElementById("c-" + activeStart);
if (chapter) {
$(chapter).addClass("current");
chapter.scrollIntoView();
}
}
});
}
}
Loading

0 comments on commit 4ee7034

Please sign in to comment.