diff --git a/src/js/video.js b/src/js/video.js index 6a3ee84..07c3dc6 100644 --- a/src/js/video.js +++ b/src/js/video.js @@ -19,7 +19,7 @@ function eventListener(video, ev) { } // Dispatch progress event at around 25%, 50%, 75% and 100% - if (ev.type === 'progress' && !shouldDispatch(video.getProgress())) { + if (ev.type === 'progress' && !shouldDispatch(video)) { return; } @@ -43,8 +43,10 @@ function fireEvent(action, video, extraDetail = {}) { document.body.dispatchEvent(event); } -function shouldDispatch(progress) { - +const dispatchedProgress = {}; +function shouldDispatch(video) { + const progress = video.getProgress(); + const id = video.opts.id; const relevantProgressPoints = [ 8, 9, 10, 11, 12, 23, 24, 25, 26, 27, @@ -53,7 +55,23 @@ function shouldDispatch(progress) { 100 ]; - return relevantProgressPoints.includes(progress); + // Initialise dispatched progress store + if (!dispatchedProgress[id]) { + dispatchedProgress[id] = []; + } + + // Progress is not relevant + if (!relevantProgressPoints.includes(progress)) { + return false; + } + + // Progress has already been dispatched + if (dispatchedProgress[id].includes(progress)) { + return false; + } + + dispatchedProgress[id].push(progress); + return true; } function addEvents(video, events) { diff --git a/test/video.test.js b/test/video.test.js index b972f1a..0aba951 100644 --- a/test/video.test.js +++ b/test/video.test.js @@ -198,6 +198,68 @@ describe('Video', () => { Element.prototype.addEventListener = realAddEventListener; }); + describe('progress eventListener', () => { + let video; + let realVideoEl; + let realDispatchEvent; + let dispatchEventSpy; + + beforeEach(() => { + video = new Video(containerEl); + video.addVideo(); + realVideoEl = video.videoEl; + dispatchEventSpy = sinon.spy(); + realDispatchEvent = document.body.dispatchEvent; + document.body.dispatchEvent = dispatchEventSpy; + }); + + afterEach(() => { + document.body.dispatchEvent = realDispatchEvent; + }); + + it('should dispatch progress events at relevant percentages', () => { + // Duration on the video element is read only so we have to replace + video.videoEl = { + duration: 100, + currentTime: 50 + }; + + // Call dispatch on the original + realVideoEl.dispatchEvent(new ProgressEvent('progress')); + + proclaim.equal(dispatchEventSpy.called, true); + }); + + it('should not dispatch progress events at other percentages', () => { + // Duration on the video element is read only so we have to replace + video.videoEl = { + duration: 100, + currentTime: 80 + }; + + // Call dispatch on the original + realVideoEl.dispatchEvent(new ProgressEvent('progress')); + + proclaim.equal(dispatchEventSpy.called, false); + }); + + it('should dispatch progress events only once per percentage', () => { + // Duration on the video element is read only so we have to replace + video.videoEl = { + duration: 100, + currentTime: 10 + }; + + // Call dispatch multiple times on the original + realVideoEl.dispatchEvent(new ProgressEvent('progress')); + realVideoEl.dispatchEvent(new ProgressEvent('progress')); + realVideoEl.dispatchEvent(new ProgressEvent('progress')); + realVideoEl.dispatchEvent(new ProgressEvent('progress')); + + proclaim.equal(dispatchEventSpy.calledOnce, true); + }); + }); + describe('captions', () => { let fetchStub;