diff --git a/__TEST__/hyperaudio-lite.test.js b/__TEST__/hyperaudio-lite.test.js index 5b9ff0d..b6fa1bd 100644 --- a/__TEST__/hyperaudio-lite.test.js +++ b/__TEST__/hyperaudio-lite.test.js @@ -414,6 +414,29 @@ test("setPlayHead updates currentTime and plays if playOnClick is true", () => { expect(ht.myPlayer.play).toHaveBeenCalled(); }); +test("setPlayHead tracks the clicked word when timestamps are duplicated (#269)", () => { + const spans = document.querySelectorAll("span[data-m]"); + const lastWordInFirstParagraph = spans[4]; + const firstWordInSecondParagraph = spans[5]; + const originalTimestamp = lastWordInFirstParagraph.dataset.m; + + lastWordInFirstParagraph.dataset.m = firstWordInSecondParagraph.dataset.m; + ht.wordArr = ht.createWordArray(spans); + ht.myPlayer = { setTime: jest.fn(), play: jest.fn(), paused: true }; + ht.playOnClick = false; + + ht.setPlayHead({ target: firstWordInSecondParagraph }); + + expect(lastWordInFirstParagraph.parentNode.classList.contains("active")).toBe(false); + expect(firstWordInSecondParagraph.parentNode.classList.contains("active")).toBe(true); + expect(ht.activeWordElement).toBe(firstWordInSecondParagraph); + expect(ht.activeParentElement).toBe(firstWordInSecondParagraph.parentNode); + + lastWordInFirstParagraph.dataset.m = originalTimestamp; + ht.wordArr = ht.createWordArray(spans); + ht.clearActiveClasses(); +}); + test("preparePlayHead sets paused to false and calls checkPlayHead", () => { ht.checkPlayHead = jest.fn(); ht.preparePlayHead(); diff --git a/js/hyperaudio-lite.js b/js/hyperaudio-lite.js index c86b2a3..22e4714 100644 --- a/js/hyperaudio-lite.js +++ b/js/hyperaudio-lite.js @@ -732,8 +732,16 @@ class HyperaudioLite { // the playback loop owns the active word; when paused, we explicitly mark // the clicked word so the user sees what they clicked. if (this.myPlayer.paused && target.dataset.m) { + if (this.activeWordElement && this.activeWordElement !== target) { + this.activeWordElement.classList.remove('active'); + } + if (this.activeParentElement && this.activeParentElement !== target.parentNode) { + this.activeParentElement.classList.remove('active'); + } target.classList.add('active'); target.parentNode.classList.add('active'); + this.activeWordElement = target; + this.activeParentElement = target.parentNode; } if (!isNaN(timeSecs)) { diff --git a/js/hyperaudio-lite.mjs b/js/hyperaudio-lite.mjs index 82f9f7c..3e56790 100644 --- a/js/hyperaudio-lite.mjs +++ b/js/hyperaudio-lite.mjs @@ -732,8 +732,16 @@ class HyperaudioLite { // the playback loop owns the active word; when paused, we explicitly mark // the clicked word so the user sees what they clicked. if (this.myPlayer.paused && target.dataset.m) { + if (this.activeWordElement && this.activeWordElement !== target) { + this.activeWordElement.classList.remove('active'); + } + if (this.activeParentElement && this.activeParentElement !== target.parentNode) { + this.activeParentElement.classList.remove('active'); + } target.classList.add('active'); target.parentNode.classList.add('active'); + this.activeWordElement = target; + this.activeParentElement = target.parentNode; } if (!isNaN(timeSecs)) {