From a9c50e0feaae038b0e9c99d28033a2290d354361 Mon Sep 17 00:00:00 2001 From: Mark Boas Date: Thu, 23 Sep 2021 15:15:44 +0200 Subject: [PATCH] added wm ha lite version --- wp-hyperaudio/hyperaudio-admin.php | 18 + wp-hyperaudio/hyperaudio.php | 10 +- wp-hyperaudio/js/hyperaudio-lite.js | 679 +++++++++++++++++----------- 3 files changed, 432 insertions(+), 275 deletions(-) diff --git a/wp-hyperaudio/hyperaudio-admin.php b/wp-hyperaudio/hyperaudio-admin.php index 2c4a535..99128ae 100644 --- a/wp-hyperaudio/hyperaudio-admin.php +++ b/wp-hyperaudio/hyperaudio-admin.php @@ -183,8 +183,26 @@ function hyperaudio_options_page() media-height640pxset the height of the audio or video font-familyArial, Helvetica, sans-serif;set the font family of the transcript idmytranscriptsets the id of the trancript for sharing purposes + webmonetizationtrueenables Web Monetization (false by default)

+

For example:

+

[hyperaudio src="https://example.com/video/video.mp4" width="90%" transcript-height="600px" webmonetization=true]
+ <article>
+ <section>
+ <p>
+ <span data-m="4470" data-d="0" class="speaker">Doc: </span>
+ <span data-m="4470" data-d="270">We </span>
+ <span data-m="4740" data-d="240">have </span>
+ <span data-m="5010" data-d="300">two </span>
+ <span data-m="5310" data-d="600">selves </span>
+ ...
+ </p>
+ </section>
+ </article>
+ [/hyperaudio] +
+

And for those with the caption generating version ...

diff --git a/wp-hyperaudio/hyperaudio.php b/wp-hyperaudio/hyperaudio.php index 87d2f6f..fac47dd 100644 --- a/wp-hyperaudio/hyperaudio.php +++ b/wp-hyperaudio/hyperaudio.php @@ -31,6 +31,7 @@ function hyperaudio_shortcode_handler($atts, $transcript, $tag) $captionsOn = true; $language = "en"; $trackLabel = "English"; + $webmonetization = false; if (isset($atts['src'])) $src = esc_html__($atts['src']); if (isset($atts['width'])) $width = $atts['width']; @@ -46,6 +47,8 @@ function hyperaudio_shortcode_handler($atts, $transcript, $tag) if (isset($atts['language'])) $language = $atts['language']; if (isset($atts['track-label'])) $trackLabel = $atts['track-label']; + if (isset($atts['webmonetization'])) $webmonetization = $atts['webmonetization']; + $transcript = preg_replace( "/\r|\n/", "", $transcript); @@ -174,8 +177,11 @@ function hyperaudio_shortcode_handler($atts, $transcript, $tag) selector: "article" }).init(); - var ht1 = hyperaudiolite(); - ht1.init("'.$transcriptid.'", "hyperplayer'.$id.'", false);'; + var minimizedMode = false; + var autoScroll = true; + var doubleClick = false; + + new HyperaudioLite("'.$transcriptid.'", "hyperplayer'.$id.'", minimizedMode, autoScroll, doubleClick, '.$webmonetization.');'; if ($captionsOn == true) { $o .= 'var cap1 = caption(); diff --git a/wp-hyperaudio/js/hyperaudio-lite.js b/wp-hyperaudio/js/hyperaudio-lite.js index 73c5d1d..fdbd2d4 100644 --- a/wp-hyperaudio/js/hyperaudio-lite.js +++ b/wp-hyperaudio/js/hyperaudio-lite.js @@ -1,196 +1,227 @@ /*! (C) The Hyperaudio Project. MIT @license: en.wikipedia.org/wiki/MIT_License. */ -/*! Version 1.1.0 */ +/*! Version 2.0.4 */ 'use strict'; -var hyperaudiolite = (function () { - - var hal = {}, - transcript, - player, - paraIndex, - wordIndex, - textShot, - paras, - start, - end, - timer, - minimizedMode, - wordArr = [], - playerType, - currentTime, - windowHash, - hashArray, - hashVar; - - - function init(mediaElementId, m) { - - windowHash = window.location.hash; - - hashVar = windowHash.substring(1,windowHash.indexOf("=")); - - - if (hashVar === transcript.id) { - hashArray = windowHash.substr(transcript.id.length+2).split(','); +class HyperaudioLite { + constructor(transcriptId, mediaElementId, minimizedMode, autoscroll, doubleClick, webMonetization) { + this.transcript = document.getElementById(transcriptId); + this.init(mediaElementId, minimizedMode, autoscroll, doubleClick, webMonetization); + } + + init = (mediaElementId, m, a, d, w) => { + const windowHash = window.location.hash; + const hashVar = windowHash.substring(1, windowHash.indexOf('=')); + + if (hashVar === this.transcript.id) { + this.hashArray = windowHash.substr(this.transcript.id.length + 2).split(','); } else { - hashArray = []; + this.hashArray = []; } - transcript.addEventListener('mouseup', function() { + document.addEventListener( + 'selectionchange', + () => { + const mediaFragment = this.getSelectionMediaFragment(); + + if (mediaFragment !== '') { + document.location.hash = mediaFragment; + } + }, + false, + ); - var mediaFragment = getSelectionMediaFragment(); + this.minimizedMode = m; + this.textShot = ''; + this.wordIndex = 0; - if ( mediaFragment !== "") { - document.location.hash = mediaFragment; - } - }, false); + this.autoscroll = a; + this.scrollerContainer = this.transcript; + this.scrollerOffset = 0; + this.scrollerDuration = 800; + this.scrollerDelay = 0; - minimizedMode = m; - textShot = ""; - wordIndex = 0; + this.doubleClick = d; + this.webMonetization = w; //Create the array of timed elements (wordArr) - var words = transcript.querySelectorAll('[data-m]'); + const words = this.transcript.querySelectorAll('[data-m]'); - for (var i = 0; i < words.length; ++i) { - var m = parseInt(words[i].getAttribute('data-m')); - var p = words[i].parentNode; - while (p !== document) { - if (p.tagName.toLowerCase() === 'p' || p.tagName.toLowerCase() === 'figure' || p.tagName.toLowerCase() === 'ul') { - break; - } - p = p.parentNode; - } - wordArr[i] = { 'n': words[i], 'm': m, 'p': p } - } + this.wordArr = this.createWordArray(words); - for (var i = 0; i < wordArr.length; ++i) { - wordArr[i].n.classList.add("unread"); - } - - paras = transcript.getElementsByTagName('p'); + this.paras = this.transcript.getElementsByTagName('p'); - player = document.getElementById(mediaElementId); + this.player = document.getElementById(mediaElementId); - if (player.tagName == "VIDEO" || player.tagName == "AUDIO") { //native HTML media elements - playerType = "native"; - } else { //assume it is a SoundCloud or YouTube iframe - playerType = player.getAttribute("data-player-type"); + if (this.player.tagName == 'VIDEO' || this.player.tagName == 'AUDIO') { + //native HTML media elements + this.playerType = 'native'; + } else { + //assume it is a SoundCloud or YouTube iframe + this.playerType = this.player.getAttribute('data-player-type'); } - if (playerType == "native") { - player.addEventListener('pause', clearTimer, false); - player.addEventListener('play', checkPlayHead, false); - } else if (playerType == "soundcloud"){ // SoundCloud - player = SC.Widget(mediaElementId); - player.bind(SC.Widget.Events.PAUSE, clearTimer); - player.bind(SC.Widget.Events.PLAY, checkPlayHead); - } else { // assume YouTube - var tag = document.createElement('script'); + if (this.playerType === 'native') { + this.player.addEventListener('pause', this.clearTimer, false); + this.player.addEventListener('play', this.checkPlayHead, false); + } else if (this.playerType === 'soundcloud') { + // SoundCloud + this.player = SC.Widget(mediaElementId); + this.player.bind(SC.Widget.Events.PAUSE, this.clearTimer); + this.player.bind(SC.Widget.Events.PLAY, this.checkPlayHead); + } else { + // assume YouTube + const tag = document.createElement('script'); tag.id = 'iframe-demo'; tag.src = 'https://www.youtube.com/iframe_api'; - var firstScriptTag = document.getElementsByTagName('script')[0]; + const firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); - window.onYouTubeIframeAPIReady = function() { - player = new YT.Player(mediaElementId, { + window.onYouTubeIframeAPIReady = function () { + this.player = new YT.Player(mediaElementId, { events: { - 'onStateChange': onPlayerStateChange - } + onStateChange: onPlayerStateChange, + }, }); - } + }; + + onPlayerStateChange = event => { + if (event.data === 1) { + // playing + this.checkPlayHead(); + } else if (event.data === 2) { + // paused + this.clearTimer(); + } + }; + } - function onPlayerStateChange(event) { - if (event.data == 1) { // playing - checkPlayHead(); - } else if (event.data == 2) { // paused - clearTimer(); - } - } + this.paraIndex = 0; + + words[0].classList.add('active'); + this.paras[0].classList.add('active'); + + let playHeadEvent = 'click'; + + if (this.doubleClick === true) { + playHeadEvent = 'dblclick'; } - - paraIndex = 0; - words[0].classList.add("active"); - paras[0].classList.add("active"); - transcript.addEventListener('click', setPlayHead, false); - transcript.addEventListener('click', checkPlayHead, false); - start = hashArray[0]; + this.transcript.addEventListener(playHeadEvent, this.setPlayHead, false); + this.transcript.addEventListener(playHeadEvent, this.checkPlayHead, false); - if (!isNaN(parseFloat(start))) { + const start = this.hashArray[0]; - if (playerType == "native") { - player.currentTime = start; + if (!isNaN(parseFloat(start))) { + if (this.playerType === 'native') { + this.player.currentTime = start; //autoplay - var promise = player.play(); + const promise = this.player.play(); if (promise !== undefined) { - promise.catch(error => { - console.log("Auto-play prevented"); - }).then(() => { + promise + .catch(error => { + console.log('Auto-play prevented'); + }) + .then(() => { // Auto-play started - }); + }); } - } else if (playerType == "soundcloud"){ // SoundCloud - player.seekTo(start * 1000); - } else { // Assume YouTube - window.onYouTubeIframeAPIReady = function() { - player = new YT.Player(mediaElementId, { - playerVars: { 'autoplay': 1 }, + } else if (this.playerType === 'soundcloud') { + // SoundCloud + this.player.seekTo(start * 1000); + } else { + // Assume YouTube + + window.onYouTubeIframeAPIReady = function () { + this.player = new YT.Player(mediaElementId, { + playerVars: { autoplay: 1 }, events: { - 'onReady': function() { - player.seekTo(start, true); - player.playVideo(); - } - } + onReady: function () { + this.player.seekTo(start, true); + this.player.playVideo(); + }, + }, }); - } + }; } } - end = hashArray[1]; + this.end = this.hashArray[1]; //TODO convert to binary search for below for quicker startup - if (start && end) { - for (var i = 1; i < words.length; i++) { - var wordStart = parseInt(words[i].getAttribute("data-m"))/1000; - if ( wordStart > start && end > wordStart ) { - words[i].classList.add("share-match"); + if (start && this.end) { + for (let i = 1; i < words.length; i++) { + const wordStart = parseInt(words[i].getAttribute('data-m')) / 1000; + if (wordStart > start && this.end > wordStart) { + words[i].classList.add('share-match'); } } } - } - function getSelectionMediaFragment() { + if (this.autoscroll === true) { + this.scroller = window.Velocity || window.jQuery.Velocity; + } + }; - var fragment = ""; - var selection = null; + createWordArray = words => { + let wordArr = []; + + words.forEach((word, i) => { + const m = parseInt(word.getAttribute('data-m')); + let p = word.parentNode; + while (p !== document) { + if ( + p.tagName.toLowerCase() === 'p' || + p.tagName.toLowerCase() === 'figure' || + p.tagName.toLowerCase() === 'ul' + ) { + break; + } + p = p.parentNode; + } + wordArr[i] = { n: words[i], m: m, p: p }; + wordArr[i].n.classList.add('unread'); + }); + + return wordArr; + }; + + getSelectionMediaFragment = () => { + let fragment = ''; + let selection = null; if (window.getSelection) { - selection = window.getSelection(); + selection = window.getSelection(); } else if (document.selection) { - selection = document.selection.createRange(); + selection = document.selection.createRange(); } if (selection.toString() !== '') { + let fNode = selection.focusNode.parentNode; + let aNode = selection.anchorNode.parentNode; + + if (aNode.tagName === "P") { + aNode = selection.anchorNode.nextElementSibling; + } - var fNode = selection.focusNode.parentNode; - var aNode = selection.anchorNode.parentNode; + if (fNode.tagName === "P") { + fNode = selection.focusNode.nextElementSibling; + } - if (aNode.getAttribute('data-m') == null || aNode.className == "speaker") { - aNode = aNode.nextElementSibling; + if (aNode.getAttribute('data-m') === null || aNode.className === 'speaker') { + aNode = aNode.nextElementSibling; } - if (fNode.getAttribute('data-m') == null || fNode.className == "speaker") { - fNode = fNode.previousElementSibling; + if (fNode.getAttribute('data-m') === null || fNode.className === 'speaker') { + fNode = fNode.previousElementSibling; } - var aNodeTime = parseInt(aNode.getAttribute('data-m'), 10); - var aNodeDuration = parseInt(aNode.getAttribute('data-d'), 10); - var fNodeTime; - var fNodeDuration; + let aNodeTime = parseInt(aNode.getAttribute('data-m'), 10); + let aNodeDuration = parseInt(aNode.getAttribute('data-d'), 10); + let fNodeTime; + let fNodeDuration; if (fNode != null && fNode.getAttribute('data-m') != null) { fNodeTime = parseInt(fNode.getAttribute('data-m'), 10); @@ -204,200 +235,302 @@ var hyperaudiolite = (function () { fNodeTime = Math.round(fNodeTime / 100) / 10; fNodeDuration = Math.round(fNodeDuration / 100) / 10; - var nodeStart = aNodeTime; - var nodeDuration = Math.round((fNodeTime + fNodeDuration - aNodeTime) * 10) / 10; + let nodeStart = aNodeTime; + let nodeDuration = Math.round((fNodeTime + fNodeDuration - aNodeTime) * 10) / 10; if (aNodeTime >= fNodeTime) { nodeStart = fNodeTime; nodeDuration = Math.round((aNodeTime + aNodeDuration - fNodeTime) * 10) / 10; } - if (nodeDuration == 0 || nodeDuration == null || isNaN(nodeDuration)) { + if (nodeDuration === 0 || nodeDuration === null || isNaN(nodeDuration)) { nodeDuration = 10; // arbitary for now } - fragment = transcript.id+ "=" + nodeStart + "," + (Math.round((nodeStart + nodeDuration) * 10) / 10); + fragment = this.transcript.id + '=' + nodeStart + ',' + Math.round((nodeStart + nodeDuration) * 10) / 10; } - return (fragment); - } + return fragment; + }; - function setPlayHead(e) { - - var target = (e.target) ? e.target : e.srcElement; - target.setAttribute("class", "active"); - var timeSecs = parseInt(target.getAttribute("data-m")) / 1000; - - if(!isNaN(parseFloat(timeSecs))) { - end = null; - if (playerType == "native"){ - player.currentTime = timeSecs; - player.play(); - } else if (playerType == "soundcloud"){ - player.seekTo(timeSecs * 1000); - player.play(); - } else { //assume YouTube - player.seekTo(timeSecs, true); - player.playVideo(); - } - } - } + setPlayHead = e => { + const target = e.target ? e.target : e.srcElement; - function clearTimer() { - if (timer) clearTimeout(timer); - } + // clear elements with class='active' - function checkPlayHead() { + let activeElements = Array.from(this.transcript.getElementsByClassName('active')); - clearTimer(); + activeElements.forEach(e => { + e.classList.remove('active'); + }); - if (playerType == "native"){ - currentTime = player.currentTime; - } else if (playerType == "soundcloud"){ - player.getPosition(function(ms) { - currentTime = ms / 1000; + target.setAttribute('class', 'active'); + + const timeSecs = parseInt(target.getAttribute('data-m')) / 1000; + + if (!isNaN(parseFloat(timeSecs))) { + this.end = null; + + if (this.playerType === 'native') { + this.player.currentTime = timeSecs; + this.player.play(); + } else if (this.playerType === 'soundcloud') { + this.player.seekTo(timeSecs * 1000); + this.player.play(); + } else { + //assume YouTube + + this.player.seekTo(timeSecs, true); + this.player.playVideo(); + } + } + }; + + clearTimer = () => { + if (this.timer) clearTimeout(this.timer); + }; + + checkPlayHead = () => { + this.clearTimer(); + + if (this.playerType === 'native') { + this.currentTime = this.player.currentTime; + this.checkStatus(); + } else if (this.playerType === 'soundcloud') { + this.player.getPosition(ms => { + this.currentTime = ms / 1000; + this.checkStatus(); }); - } else { // assume YouTube - currentTime = player.getCurrentTime(); + } else { + // assume YouTube + this.currentTime = this.player.getCurrentTime(); + this.checkStatus(); } + } + checkStatus = () => { //check for end time of shared piece - if (end && (end < currentTime)) { - player.pause(); - end = null; + if (this.end && this.end < this.currentTime) { + this.player.pause(); + this.end = null; } else { - var newPara = false; - var interval; // used to establish next checkPlayHead - var index = 0; - var words = wordArr.length - 1; - - // Binary search https://en.wikipedia.org/wiki/Binary_search_algorithm - while (index <= words) { - var guessIndex = index + ((words - index) >> 1); // >> 1 has the effect of halving and rounding down - var difference = wordArr[guessIndex].m / 1000 - currentTime; // wordArr[guessIndex].m represents start time of word - - if (difference < 0) { // comes before the element - index = guessIndex + 1; - } - else if (difference > 0) { // comes after the element - words = guessIndex - 1; - } - else { // equals the element - index = guessIndex; - break; - } - } + let newPara = false; + let interval = 0; // used to establish next checkPlayHead - for (var i = 0; i < index; ++i) { - wordArr[i].n.classList.add("read"); - wordArr[i].n.classList.remove("unread"); - } + let indices = this.updateTranscriptVisualState(); - for (var i = index; i < wordArr.length; ++i) { - wordArr[i].n.classList.add("unread"); - wordArr[i].n.classList.remove("read"); - } + let scrollNode = null; - for (var i = 0; i < index; ++i) { - wordArr[i].n.classList.remove("active"); - } + let index = indices.currentWordIndex; + let currentParaIndex = indices.currentParaIndex; - paras = transcript.getElementsByTagName('p'); + if (index > 0) { + scrollNode = this.wordArr[index - 1].n.parentNode; - //remove active class from all paras + if (scrollNode !== null && scrollNode.tagName != 'P') { + // it's not inside a para so just use the element + scrollNode = this.wordArr[index - 1].n; + } - for (var a = 0; a < paras.length; a++) { - if (paras[a].classList.contains("active")) { - paras[a].classList.remove("active"); + if (currentParaIndex != this.paraIndex) { + if (typeof this.scroller !== 'undefined' && this.autoscroll === true) { + if (scrollNode !== null) { + if (typeof this.scrollerContainer !== 'undefined' && this.scrollerContainer !== null) { + this.scroller(scrollNode, 'scroll', { + container: this.scrollerContainer, + duration: this.scrollerDuration, + delay: this.scrollerDelay, + offset: this.scrollerOffset, + }); + } else { + this.scroller(scrollNode, 'scroll', { + duration: this.scrollerDuration, + delay: this.scrollerDelay, + offset: this.scrollerOffset, + }); + } + } else { + // the wordlst needs refreshing + let words = this.transcript.querySelectorAll('[data-m]'); + this.wordArr = this.createWordArray(words); + this.paras = this.transcript.getElementsByTagName('p'); + } + } + + newPara = true; + + this.paraIndex = currentParaIndex; } } - // set current word and para to active + //minimizedMode is still experimental - it changes document.title upon every new word - if (index > 0) { - wordArr[index - 1].n.classList.add("active"); - wordArr[index - 1].n.parentNode.classList.add("active"); - } + if (this.minimizedMode) { + const elements = transcript.querySelectorAll('[data-m]'); + let currentWord = ''; + let lastWordIndex = this.wordIndex; - if (wordArr[index]) { - interval = parseInt(wordArr[index].n.getAttribute('data-m') - currentTime * 1000); - } else { - interval = 0; - } + for (let i = 0; i < elements.length; i++) { + if ((' ' + elements[i].className + ' ').indexOf(' active ') > -1) { + currentWord = elements[i].innerHTML; + this.wordIndex = i; + } + } - // Establish current paragraph index + let textShot = ''; - var currentParaIndex; + if (this.wordIndex != lastWordIndex) { + textShot = textShot + currentWord; + } - for (var a = 0; a < paras.length; a++) { - if (paras[a].classList.contains("active")) { - currentParaIndex = a; - break; + if (textShot.length > 16 || newPara === true) { + document.title = textShot; + textShot = ''; + newPara = false; } } - var scrollNode = null; + if (this.wordArr[index]) { + interval = parseInt(this.wordArr[index].n.getAttribute('data-m') - this.currentTime * 1000); + } - if (index > 0) { - scrollNode = wordArr[index-1].n.parentNode; + this.timer = setTimeout(() => { + this.checkPlayHead(); + }, interval + 1); // +1 to avoid rounding issues (better to be over than under) + } - if (scrollNode.tagName != "P") { // it's not inside a para so just use the element - scrollNode = wordArr[index-1].n; - } + if (this.webMonetization === true) { + //check for payment pointer - if (currentParaIndex != paraIndex) { - Velocity(scrollNode, "scroll", { - container: transcript, - duration: 800, - delay: 0 - }); + let activeElements = this.transcript.getElementsByClassName('active'); - newPara = true; + let paymentPointer = this.checkPaymentPointer(activeElements[activeElements.length - 1]); - paraIndex = currentParaIndex; + if (paymentPointer !== null) { + let metaElements = document.getElementsByTagName('meta'); + let wmMeta = document.querySelector("meta[name='monetization']"); + if (wmMeta === null) { + wmMeta = document.createElement('meta'); + wmMeta.name = 'monetization'; + wmMeta.content = paymentPointer; + document.getElementsByTagName('head')[0].appendChild(wmMeta); + } else { + wmMeta.name = 'monetization'; + wmMeta.content = paymentPointer; } } + } + }; - //minimizedMode is still experimental - it changes document.title upon every new word + checkPaymentPointer = element => { + let paymentPointer = element.getAttribute('data-wm'); - if (minimizedMode) { + if (paymentPointer !== null) { + return paymentPointer; + } else { + let parent = element.parentElement; - var elements = transcript.querySelectorAll('[data-m]'); - var currentWord = ""; - var lastWordIndex = wordIndex; + if (parent === null) { + return null; + } else { + return this.checkPaymentPointer(parent); + } + } + }; + + updateTranscriptVisualState = () => { + let index = 0; + let words = this.wordArr.length - 1; + + // Binary search https://en.wikipedia.org/wiki/Binary_search_algorithm + while (index <= words) { + const guessIndex = index + ((words - index) >> 1); // >> 1 has the effect of halving and rounding down + const difference = this.wordArr[guessIndex].m / 1000 - this.currentTime; // wordArr[guessIndex].m represents start time of word + + if (difference < 0) { + // comes before the element + index = guessIndex + 1; + } else if (difference > 0) { + // comes after the element + words = guessIndex - 1; + } else { + // equals the element + index = guessIndex; + break; + } + } - for (var i = 0; i < elements.length; i++) { - if((' ' + elements[i].className + ' ').indexOf(' active ') > -1) { - currentWord = elements[i].innerHTML; - wordIndex = i; - } - } + this.wordArr.forEach((word, i) => { + let classList = word.n.classList; + if (i < index) { + classList.add('read'); + classList.remove('unread'); + classList.remove('active'); + } else { + classList.add('unread'); + classList.remove('read'); + } + }); - if (wordIndex != lastWordIndex) { - textShot = textShot + currentWord; - } + this.paras = this.transcript.getElementsByTagName('p'); - if (textShot.length > 16 || newPara == true) { - document.title = textShot; - textShot = ""; - newPara = false; - } + //remove active class from all paras + + Array.from(this.paras).forEach(para => { + if (para.classList.contains('active')) { + para.classList.remove('active'); } + }); - timer = setTimeout(function() { - checkPlayHead(); - }, interval+1); // +1 to avoid rounding issues (better to be over than under) - } + // set current word and para to active - } + if (index > 0) { + this.wordArr[index - 1].n.classList.add('active'); + if (this.wordArr[index - 1].n.parentNode !== null) { + this.wordArr[index - 1].n.parentNode.classList.add('active'); + } + } - hal.init = function(transcriptId, mediaElementId, minimizedMode) { - transcript = document.getElementById(transcriptId); - init(mediaElementId, minimizedMode); - //set minimizedMode is an experimental feature - } + // Establish current paragraph index - return hal; + let currentParaIndex; -}); \ No newline at end of file + Array.from(this.paras).every((para, i) => { + if (para.classList.contains('active')) { + currentParaIndex = i; + return false; + } + return true; + }); + + let indices = { + currentWordIndex: index, + currentParaIndex: currentParaIndex, + }; + + return indices; + }; + + setScrollParameters = (duration, delay, offset, container) => { + this.scrollerContainer = container; + this.scrollerDuration = duration; + this.scrollerDelay = delay; + this.scrollerOffset = offset; + }; + + toggleAutoScroll = () => { + this.autoscroll = !this.autoscroll; + }; + + setAutoScroll = state => { + this.autoscroll = state; + }; +} + +// required for testing +if (typeof module !== 'undefined' && module.exports) { + module.exports = { HyperaudioLite }; +} + +//export default HyperaudioLite;