From af2fc2a0f9672f5735a92c7cb7021cf999024bb6 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 4 Mar 2019 08:18:14 -0600 Subject: [PATCH 1/8] intermediate tracking progress --- src/lib/vast_elements/tracking_events.js | 29 ++++++++++++- test/fixtures/vast-progress.xml | 49 ++++++++++++++++++++++ test/vast_elements/tracking_events.spec.js | 17 ++++++++ 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/vast-progress.xml diff --git a/src/lib/vast_elements/tracking_events.js b/src/lib/vast_elements/tracking_events.js index f920ed6..81ca81e 100644 --- a/src/lib/vast_elements/tracking_events.js +++ b/src/lib/vast_elements/tracking_events.js @@ -1,5 +1,26 @@ import VastElementBase from './vast_element_base'; +class TrackingEvent { + constructor({ event, offset, url } = { offset: null }) { + this.event = event; + this.offset = offset; + this.url = url; + console.log('creating new tracking event', this.event()); + } + + event() { + return this.event; + } + + offset() { + return this.offset; + } + + url() { + return this.url; + } +} + export default class TrackingEvents extends VastElementBase { setup() { this.trackingUrls = []; @@ -11,12 +32,16 @@ export default class TrackingEvents extends VastElementBase { onVastReady() { this.trackingUrls = this.elements.map(el => { - return [el.getAttribute('event'), el.childNodes[0].nodeValue]; + return new TrackingEvent({ + event: el.getAttribute('event'), + offset: el.getAttribute('offset'), + url: el.childNodes[0].nodeValue, + }); }); } trackingUrlsFor(eventName) { - return this.trackingUrls.filter(t => t[0] == eventName).map(t => t[1]); + return this.trackingUrls.filter(t => t.event() == eventName).map(t => t.url()); } addImpressionTrackingImagesFor(eventName, doc = document) { diff --git a/test/fixtures/vast-progress.xml b/test/fixtures/vast-progress.xml new file mode 100644 index 0000000..4304303 --- /dev/null +++ b/test/fixtures/vast-progress.xml @@ -0,0 +1,49 @@ + + + + iabtechlab + iabtechlab video ad + + + + http://example.com/error + http://example.com/track/impression + + + + 00:00:16 + + http://example.com/tracking/start + http://example.com/tracking/firstQuartile + http://example.com/tracking/midpoint + http://example.com/tracking/thirdQuartile + http://example.com/tracking/complete + http://example.com/tracking/progress-10 + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/vast_elements/tracking_events.spec.js b/test/vast_elements/tracking_events.spec.js index 12aada8..a6c8f1e 100644 --- a/test/vast_elements/tracking_events.spec.js +++ b/test/vast_elements/tracking_events.spec.js @@ -47,3 +47,20 @@ describe('Media Files extension', () => { }); }); }); + +describe('Progess with time codes', () => { + let xml; + let vast; + + beforeAll(async () => { + xml = fs.readFileSync('./test/fixtures/vast-progress.xml'); + vast = new Vast(); + await vast.useXmlString(xml); + }); + + it('should return nothing when adding images to the doc', () => { + expect(vast.addImpressionTrackingImagesFor('start')).toBe(undefined); + }); + + // creativeView +}); From 1d430e8d18495b6efe055a607c3e336c739a17e2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 10 Mar 2019 16:54:57 -0500 Subject: [PATCH 2/8] forgot this in the merge --- test/fixtures/vast-progress.xml | 49 --------------------------------- 1 file changed, 49 deletions(-) diff --git a/test/fixtures/vast-progress.xml b/test/fixtures/vast-progress.xml index f87548f..4304303 100644 --- a/test/fixtures/vast-progress.xml +++ b/test/fixtures/vast-progress.xml @@ -1,4 +1,3 @@ -<<<<<<< HEAD @@ -47,52 +46,4 @@ -======= - - - - iabtechlab - iabtechlab video ad - - - - http://example.com/error - http://example.com/track/impression - - - - 00:00:16 - - http://example.com/tracking/start - http://example.com/tracking/firstQuartile - http://example.com/tracking/midpoint - http://example.com/tracking/thirdQuartile - http://example.com/tracking/complete - http://example.com/tracking/progress-10 - - - - - - - - - - - - - - - - - - - - - - - - - ->>>>>>> master From 5f85988aaaf8d21813a65dcbc1d0f97a347607e7 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 11 Mar 2019 06:51:38 -0500 Subject: [PATCH 3/8] timecode support --- jest.config.js | 2 + src/lib/timecodes.js | 30 +++++++++++++ src/lib/vast_elements/tracking_events.js | 51 ++++++++++++++++------ test/fixtures/vast-progress.xml | 2 + test/timecodes.spec.js | 18 ++++++++ test/vast_elements/tracking_events.spec.js | 15 +++++-- 6 files changed, 102 insertions(+), 16 deletions(-) create mode 100644 src/lib/timecodes.js create mode 100644 test/timecodes.spec.js diff --git a/jest.config.js b/jest.config.js index 810103f..2d10a9b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,4 +2,6 @@ module.exports = { reporters: ['default', 'jest-junit'], testEnvironment: 'jsdom', testPathIgnorePatterns: ['/build/', '/node_modules/', '/test/cypress/'], + coveragePathIgnorePatterns: ['/node_modules/', '/test/cypress/', '/src/lib/applications/'], + coverageReporters: ['text-summary', 'lcov'], }; diff --git a/src/lib/timecodes.js b/src/lib/timecodes.js new file mode 100644 index 0000000..d2816a4 --- /dev/null +++ b/src/lib/timecodes.js @@ -0,0 +1,30 @@ +export default class Timecode { + static secondsToTimecode(maybeSeconds) { + const seconds = Number(maybeSeconds); + + if (isNaN(seconds) || maybeSeconds.toString().indexOf('%') != -1) { + return null; + } + + const date = new Date(null); + date.setSeconds(seconds); + return date.toISOString().substr(11, 8); + } + + static timecodeToSeconds(timecode) { + let parts = timecode.split(':'); + let seconds = 0; + let multiplier = 1; + + while (parts.length > 0) { + seconds += multiplier * parseInt(parts.pop(), 10); + multiplier *= 60; + } + return seconds; + } + + static timecodeToTimecode(code) { + const result = this.secondsToTimecode(this.timecodeToSeconds(code)); + return result; + } +} diff --git a/src/lib/vast_elements/tracking_events.js b/src/lib/vast_elements/tracking_events.js index 8b25577..3565b75 100644 --- a/src/lib/vast_elements/tracking_events.js +++ b/src/lib/vast_elements/tracking_events.js @@ -1,24 +1,46 @@ import VastElementBase from './vast_element_base'; +import Timecodes from '../timecodes'; import NodeValue from '../node_value'; class TrackingEvent { - constructor({ event, offset, url } = { offset: null }) { - this.event = event; - this.offset = offset; - this.url = url; - console.log('creating new tracking event', this.event()); + constructor({ eventName, url }) { + this._eventName = eventName; + this._url = url; } - event() { - return this.event; + eventName() { + return this._eventName; + } + + matches(string) { + return this.eventName() == string; + } + + url() { + return this._url; + } +} + +class ProgressTrackingEvent { + constructor({ offset, url }) { + this._offset = offset; + this._url = url; + } + + matches(secondsOrTimeCodeOrPercent) { + return ( + this.offset() == secondsOrTimeCodeOrPercent || + this.offset() == Timecodes.secondsToTimecode(secondsOrTimeCodeOrPercent) || + this.offset() == Timecodes.timecodeToTimecode(secondsOrTimeCodeOrPercent) + ); } offset() { - return this.offset; + return this._offset; } url() { - return this.url; + return this._url; } } @@ -33,16 +55,19 @@ export default class TrackingEvents extends VastElementBase { onVastReady() { this.trackingUrls = this.elements.map(el => { - return new TrackingEvent({ - event: el.getAttribute('event'), + const trackingEvent = el.hasAttribute('offset') ? ProgressTrackingEvent : TrackingEvent; + + return new trackingEvent({ + eventName: el.getAttribute('event'), offset: el.getAttribute('offset'), - url: el.childNodes[0].nodeValue, + url: NodeValue.fromElement(el), }); }); } trackingUrlsFor(eventName) { - return this.trackingUrls.filter(t => t.event() == eventName).map(t => t.url()); + // const timeCodeEventName = this.toTimeCode(eventName) + return this.trackingUrls.filter(t => t.matches(eventName)).map(t => t.url()); } addImpressionTrackingImagesFor(eventName, doc = document) { diff --git a/test/fixtures/vast-progress.xml b/test/fixtures/vast-progress.xml index 4304303..ae30809 100644 --- a/test/fixtures/vast-progress.xml +++ b/test/fixtures/vast-progress.xml @@ -20,6 +20,8 @@ http://example.com/tracking/thirdQuartile http://example.com/tracking/complete http://example.com/tracking/progress-10 + http://example.com/tracking/progress-140 + http://example.com/tracking/progress-15-percent diff --git a/test/timecodes.spec.js b/test/timecodes.spec.js new file mode 100644 index 0000000..247e98e --- /dev/null +++ b/test/timecodes.spec.js @@ -0,0 +1,18 @@ +import Timecodes from '../src/lib/timecodes'; + +describe('Timecode utility', () => { + it('should convert seconds to timecode', () => { + expect(Timecodes.secondsToTimecode(30)).toBe('00:00:30'); + expect(Timecodes.secondsToTimecode(90)).toBe('00:01:30'); + expect(Timecodes.secondsToTimecode('30')).toBe('00:00:30'); + }); + + it('should convert timecode to seconds', () => { + expect(Timecodes.timecodeToSeconds('00:00:30')).toBe(30); + expect(Timecodes.timecodeToSeconds('00:01:30')).toBe(90); + }); + + it('should convert partial timecode to full timecode', () => { + expect(Timecodes.timecodeToTimecode('00:30')).toBe('00:00:30'); + }); +}); diff --git a/test/vast_elements/tracking_events.spec.js b/test/vast_elements/tracking_events.spec.js index a6c8f1e..5c69d3e 100644 --- a/test/vast_elements/tracking_events.spec.js +++ b/test/vast_elements/tracking_events.spec.js @@ -58,9 +58,18 @@ describe('Progess with time codes', () => { await vast.useXmlString(xml); }); - it('should return nothing when adding images to the doc', () => { - expect(vast.addImpressionTrackingImagesFor('start')).toBe(undefined); + it('should return progress percent urls', () => { + expect(vast.trackingUrlsFor('15%')).toContain('http://example.com/tracking/progress-15-percent'); }); - // creativeView + it('should return progress timecode urls', () => { + expect(vast.trackingUrlsFor('00:00:10')).toContain('http://example.com/tracking/progress-10'); + expect(vast.trackingUrlsFor('00:01:40')).toContain('http://example.com/tracking/progress-140'); + }); + + it('should return progress timecode urls no matter how they are formatted', () => { + expect(vast.trackingUrlsFor('10')).toContain('http://example.com/tracking/progress-10'); + expect(vast.trackingUrlsFor('00:10')).toContain('http://example.com/tracking/progress-10'); + expect(vast.trackingUrlsFor('100')).toContain('http://example.com/tracking/progress-140'); + }); }); From 872443a4e96e09a80c45ab97be87bff8d34436d4 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 12 Mar 2019 06:13:03 -0500 Subject: [PATCH 4/8] simplified tracking classes --- src/lib/vast_elements/tracking_events.js | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/lib/vast_elements/tracking_events.js b/src/lib/vast_elements/tracking_events.js index 3565b75..f4bd895 100644 --- a/src/lib/vast_elements/tracking_events.js +++ b/src/lib/vast_elements/tracking_events.js @@ -4,16 +4,12 @@ import NodeValue from '../node_value'; class TrackingEvent { constructor({ eventName, url }) { - this._eventName = eventName; + this.eventName = eventName; this._url = url; } - eventName() { - return this._eventName; - } - matches(string) { - return this.eventName() == string; + return this.eventName == string; } url() { @@ -23,22 +19,18 @@ class TrackingEvent { class ProgressTrackingEvent { constructor({ offset, url }) { - this._offset = offset; + this.offset = offset; this._url = url; } matches(secondsOrTimeCodeOrPercent) { return ( - this.offset() == secondsOrTimeCodeOrPercent || - this.offset() == Timecodes.secondsToTimecode(secondsOrTimeCodeOrPercent) || - this.offset() == Timecodes.timecodeToTimecode(secondsOrTimeCodeOrPercent) + this.offset == secondsOrTimeCodeOrPercent || + this.offset == Timecodes.secondsToTimecode(secondsOrTimeCodeOrPercent) || + this.offset == Timecodes.timecodeToTimecode(secondsOrTimeCodeOrPercent) ); } - offset() { - return this._offset; - } - url() { return this._url; } @@ -66,7 +58,6 @@ export default class TrackingEvents extends VastElementBase { } trackingUrlsFor(eventName) { - // const timeCodeEventName = this.toTimeCode(eventName) return this.trackingUrls.filter(t => t.matches(eventName)).map(t => t.url()); } From 10a0902d4274c76f4bf000ac9480889e3f65d911 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 12 Mar 2019 09:25:34 -0500 Subject: [PATCH 5/8] support for tracking names and offsets --- src/lib/quartile_support.js | 8 ++++ src/lib/timecodes.js | 23 +++++++++ src/lib/vast.js | 4 ++ src/lib/vast_elements/tracking_events.js | 56 ++++++++++++++++++---- test/fixtures/vast-progress.xml | 1 + test/vast_elements/tracking_events.spec.js | 19 ++++++++ 6 files changed, 101 insertions(+), 10 deletions(-) diff --git a/src/lib/quartile_support.js b/src/lib/quartile_support.js index 401d1e7..dd9a346 100644 --- a/src/lib/quartile_support.js +++ b/src/lib/quartile_support.js @@ -7,6 +7,14 @@ const QUARTILES = [ ]; export default class QuartileSupport { + static quartiles() { + let quartiles = {}; + QUARTILES.forEach(quart => { + quartiles[quart[1]] = quart[0]; + }); + return quartiles; + } + constructor() { this.seenQuartiles = []; this.callbacks = []; diff --git a/src/lib/timecodes.js b/src/lib/timecodes.js index d2816a4..376d6f4 100644 --- a/src/lib/timecodes.js +++ b/src/lib/timecodes.js @@ -1,4 +1,12 @@ export default class Timecode { + /** + * Converts seconds to a three segment timecode hh:mm:ss + * Examples: 30 => "00:00:30" + * 90 => "00:01:30" + * + * @param {String|Number} maybeSeconds + * @returns {String} "hh:mm:ss" timecode + */ static secondsToTimecode(maybeSeconds) { const seconds = Number(maybeSeconds); @@ -11,6 +19,14 @@ export default class Timecode { return date.toISOString().substr(11, 8); } + /** + * Converts timecode hh:mm:ss to total seconds + * Examples: "00:00:30" => 30 + * "00:10:10" => 610 + * + * @param {String} timecode Timecode input + * @returns {Number} the number of seconds represented in the timecode + */ static timecodeToSeconds(timecode) { let parts = timecode.split(':'); let seconds = 0; @@ -23,6 +39,13 @@ export default class Timecode { return seconds; } + /** + * Will properly format the timecode into three segment parts + * Example: "01:10" => "00:01:10" + * + * @param {String} code input timecode + * @returns {String} three segment timecode hh:mm:ss + */ static timecodeToTimecode(code) { const result = this.secondsToTimecode(this.timecodeToSeconds(code)); return result; diff --git a/src/lib/vast.js b/src/lib/vast.js index 3fa84d1..24e2baa 100644 --- a/src/lib/vast.js +++ b/src/lib/vast.js @@ -89,6 +89,10 @@ export default class Vast { return this.loadedElements['TrackingEvents'].trackingUrlsFor(eventName); } + trackingEventNamesWithOffsets() { + return this.loadedElements['TrackingEvents'].trackingEventNamesWithOffsets(); + } + addImpressionTrackingImagesFor(eventName, doc = document) { return this.loadedElements['TrackingEvents'].addImpressionTrackingImagesFor(eventName, doc); } diff --git a/src/lib/vast_elements/tracking_events.js b/src/lib/vast_elements/tracking_events.js index f4bd895..57567ab 100644 --- a/src/lib/vast_elements/tracking_events.js +++ b/src/lib/vast_elements/tracking_events.js @@ -1,6 +1,7 @@ import VastElementBase from './vast_element_base'; import Timecodes from '../timecodes'; import NodeValue from '../node_value'; +import QuartileSupport from '../quartile_support'; class TrackingEvent { constructor({ eventName, url }) { @@ -12,6 +13,15 @@ class TrackingEvent { return this.eventName == string; } + name() { + return this.eventName; + } + + offsetInSeconds(duration) { + const quarts = QuartileSupport.quartiles(); + return quarts[this.eventName] * duration; + } + url() { return this._url; } @@ -31,6 +41,18 @@ class ProgressTrackingEvent { ); } + name() { + return this.offset; + } + + offsetInSeconds(duration) { + if (this.offset.indexOf('%') != -1) { + return duration * (Number(this.offset.replace('%', '')) / 100.0); + } else { + return Timecodes.timecodeToSeconds(this.offset); + } + } + url() { return this._url; } @@ -38,27 +60,34 @@ class ProgressTrackingEvent { export default class TrackingEvents extends VastElementBase { setup() { - this.trackingUrls = []; + this.trackingEvents = []; + this.duration = undefined; } static selector() { - return 'Ad TrackingEvents Tracking'; + return 'Ad TrackingEvents Tracking, Ad Inline Creative Duration'; } onVastReady() { - this.trackingUrls = this.elements.map(el => { - const trackingEvent = el.hasAttribute('offset') ? ProgressTrackingEvent : TrackingEvent; + this.duration = Timecodes.timecodeToSeconds( + NodeValue.fromElement(this.elements.find(el => el.nodeName == 'Duration')) + ); + + this.trackingEvents = this.elements + .filter(el => el.nodeName != 'Duration') + .map(el => { + const trackingEvent = el.hasAttribute('offset') ? ProgressTrackingEvent : TrackingEvent; - return new trackingEvent({ - eventName: el.getAttribute('event'), - offset: el.getAttribute('offset'), - url: NodeValue.fromElement(el), + return new trackingEvent({ + eventName: el.getAttribute('event'), + offset: el.getAttribute('offset'), + url: NodeValue.fromElement(el), + }); }); - }); } trackingUrlsFor(eventName) { - return this.trackingUrls.filter(t => t.matches(eventName)).map(t => t.url()); + return this.trackingEvents.filter(t => t.matches(eventName)).map(t => t.url()); } addImpressionTrackingImagesFor(eventName, doc = document) { @@ -66,4 +95,11 @@ export default class TrackingEvents extends VastElementBase { this.addImpressionUrl(url, { doc: doc, name: eventName }); }); } + + trackingEventNamesWithOffsets() { + return this.trackingEvents.reduce((all, event) => { + all[event.name()] = event.offsetInSeconds(this.duration); + return all; + }, {}); + } } diff --git a/test/fixtures/vast-progress.xml b/test/fixtures/vast-progress.xml index ae30809..365dcd3 100644 --- a/test/fixtures/vast-progress.xml +++ b/test/fixtures/vast-progress.xml @@ -22,6 +22,7 @@ http://example.com/tracking/progress-10 http://example.com/tracking/progress-140 http://example.com/tracking/progress-15-percent + http://example.com/tracking/progress-50-percent diff --git a/test/vast_elements/tracking_events.spec.js b/test/vast_elements/tracking_events.spec.js index 5c69d3e..402a06e 100644 --- a/test/vast_elements/tracking_events.spec.js +++ b/test/vast_elements/tracking_events.spec.js @@ -73,3 +73,22 @@ describe('Progess with time codes', () => { expect(vast.trackingUrlsFor('100')).toContain('http://example.com/tracking/progress-140'); }); }); + +describe('Return Tracking event names', () => { + let xml; + let vast; + + beforeAll(async () => { + xml = fs.readFileSync('./test/fixtures/vast-progress.xml'); + vast = new Vast(); + await vast.useXmlString(xml); + }); + + it('should return tracking urls with names', () => { + const eventNamesOffsets = vast.trackingEventNamesWithOffsets(); + + expect(eventNamesOffsets['15%']).toBe(2.4); + expect(eventNamesOffsets['00:01:40']).toBe(100); + expect(eventNamesOffsets['thirdQuartile']).toBe(12); + }); +}); From 1c3dae72ca57ff1e58d21b28da5791dbad5883e2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 12 Mar 2019 11:41:57 -0500 Subject: [PATCH 6/8] safer handling of partial feeds --- src/lib/node_value.js | 1 + src/lib/vast_elements/tracking_events.js | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/node_value.js b/src/lib/node_value.js index 0e83e40..206c8fd 100644 --- a/src/lib/node_value.js +++ b/src/lib/node_value.js @@ -5,6 +5,7 @@ export default class NodeValue { * @param {DOM Element} el An elemenet with a single CDATA or TEXT entity */ static fromElement(el) { + if (!el) return null; const matchedItem = Array.from(el.childNodes).find(n => { return (n.nodeType == Node.TEXT_NODE || n.nodeType == Node.CDATA_SECTION_NODE) && !!n.nodeValue.trim(); }); diff --git a/src/lib/vast_elements/tracking_events.js b/src/lib/vast_elements/tracking_events.js index 57567ab..2b92be1 100644 --- a/src/lib/vast_elements/tracking_events.js +++ b/src/lib/vast_elements/tracking_events.js @@ -69,9 +69,8 @@ export default class TrackingEvents extends VastElementBase { } onVastReady() { - this.duration = Timecodes.timecodeToSeconds( - NodeValue.fromElement(this.elements.find(el => el.nodeName == 'Duration')) - ); + const durationValue = NodeValue.fromElement(this.elements.find(el => el.nodeName == 'Duration')); + this.duration = Timecodes.timecodeToSeconds(durationValue || '0'); this.trackingEvents = this.elements .filter(el => el.nodeName != 'Duration') From 683cc7575e373a739052f23dd081feb6655cf82e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 16 Mar 2019 23:15:08 -0500 Subject: [PATCH 7/8] offset support is complete --- src/lib/applications/video_js.js | 7 ++++++ src/lib/quartile_support.js | 7 +++++- src/lib/vast.js | 4 ++++ src/lib/vast_elements/tracking_events.js | 24 +++++++++++++++++++- test/quartile_support.spec.js | 26 +++++++++++++++++++++- test/vast_elements/tracking_events.spec.js | 8 +++++++ 6 files changed, 73 insertions(+), 3 deletions(-) diff --git a/src/lib/applications/video_js.js b/src/lib/applications/video_js.js index 1cc6821..bfa3056 100644 --- a/src/lib/applications/video_js.js +++ b/src/lib/applications/video_js.js @@ -155,6 +155,13 @@ export default class VideoJs { } setupQuartileSupport() { + const events = this.vast.trackingEventNamesWithOffsetPercent(); + for (const name in events) { + this.quartileSupport.addEvent({ + name: name, + offset: events[name], + }); + } this.quartileSupport.onQuartileChange(quartile => { if (!this.vastPresented()) return; this.vast.addImpressionTrackingImagesFor(quartile); diff --git a/src/lib/quartile_support.js b/src/lib/quartile_support.js index dd9a346..95e86b3 100644 --- a/src/lib/quartile_support.js +++ b/src/lib/quartile_support.js @@ -16,12 +16,17 @@ export default class QuartileSupport { } constructor() { + this.quartiles = QUARTILES.slice(0); this.seenQuartiles = []; this.callbacks = []; this.currentTime = 0; this.duration = Infinity; } + addEvent({ name, offset }) { + this.quartiles.push([offset, name]); + } + setDuration(time) { if (time != 0) { this.duration = time; @@ -42,7 +47,7 @@ export default class QuartileSupport { checkForQuartileEvent() { const percentComplete = this.currentTime / this.duration; - const matchingQuartiles = QUARTILES.filter(quartile => { + const matchingQuartiles = this.quartiles.filter(quartile => { return quartile[0] < percentComplete; }); diff --git a/src/lib/vast.js b/src/lib/vast.js index 24e2baa..e7afb46 100644 --- a/src/lib/vast.js +++ b/src/lib/vast.js @@ -93,6 +93,10 @@ export default class Vast { return this.loadedElements['TrackingEvents'].trackingEventNamesWithOffsets(); } + trackingEventNamesWithOffsetPercent() { + return this.loadedElements['TrackingEvents'].trackingEventNamesWithOffsetPercent(); + } + addImpressionTrackingImagesFor(eventName, doc = document) { return this.loadedElements['TrackingEvents'].addImpressionTrackingImagesFor(eventName, doc); } diff --git a/src/lib/vast_elements/tracking_events.js b/src/lib/vast_elements/tracking_events.js index 2b92be1..a4df21e 100644 --- a/src/lib/vast_elements/tracking_events.js +++ b/src/lib/vast_elements/tracking_events.js @@ -22,6 +22,11 @@ class TrackingEvent { return quarts[this.eventName] * duration; } + offsetInPercent(duration) { + const quarts = QuartileSupport.quartiles(); + return quarts[this.eventName]; + } + url() { return this._url; } @@ -53,6 +58,10 @@ class ProgressTrackingEvent { } } + offsetInPercent(duration) { + return Math.min(1.0, this.offsetInSeconds(duration) / duration); + } + url() { return this._url; } @@ -97,7 +106,20 @@ export default class TrackingEvents extends VastElementBase { trackingEventNamesWithOffsets() { return this.trackingEvents.reduce((all, event) => { - all[event.name()] = event.offsetInSeconds(this.duration); + const offsetSeconds = event.offsetInSeconds(this.duration); + if (offsetSeconds) { + all[event.name()] = offsetSeconds; + } + return all; + }, {}); + } + + trackingEventNamesWithOffsetPercent() { + return this.trackingEvents.reduce((all, event) => { + const offsetPercent = event.offsetInPercent(this.duration); + if (offsetPercent) { + all[event.name()] = offsetPercent; + } return all; }, {}); } diff --git a/test/quartile_support.spec.js b/test/quartile_support.spec.js index 4ee1240..7450ff9 100644 --- a/test/quartile_support.spec.js +++ b/test/quartile_support.spec.js @@ -18,13 +18,37 @@ describe('Basic Quartile Functionality', () => { }); }); +describe('Quartile Support for other non-quartile events', () => { + let qs; + beforeEach(() => { + qs = new QuartileSupport(); + qs.setDuration(10); + }); + + it('should allow additional events to be registered at offsets', () => { + expect(typeof qs.addEvent).toBe('function'); + }); + + it('should accept a name and an offset in seconds', () => { + qs.addEvent({ name: 'progress-10', offset: 0.1 }); + + let lastQName; + qs.onQuartileChange(quartileName => { + lastQName = quartileName; + }); + + qs.setCurrentTime(1.5); + expect(lastQName).toBe('progress-10'); + }); +}); + describe('Callbacks for changes', () => { let qs; beforeEach(() => { qs = new QuartileSupport(); }); - it('should not set start on 0s', () => { + it('should not set start on 0s', () => { let lastQName = null; qs.onQuartileChange(quartileName => { lastQName = quartileName; diff --git a/test/vast_elements/tracking_events.spec.js b/test/vast_elements/tracking_events.spec.js index 402a06e..6121a0c 100644 --- a/test/vast_elements/tracking_events.spec.js +++ b/test/vast_elements/tracking_events.spec.js @@ -91,4 +91,12 @@ describe('Return Tracking event names', () => { expect(eventNamesOffsets['00:01:40']).toBe(100); expect(eventNamesOffsets['thirdQuartile']).toBe(12); }); + + it('should return tracking urls with names', () => { + const eventNamesOffsets = vast.trackingEventNamesWithOffsetPercent(); + + expect(eventNamesOffsets['15%']).toBe(0.15); + expect(eventNamesOffsets['00:01:40']).toBe(1.0); + expect(eventNamesOffsets['thirdQuartile']).toBe(0.75); + }); }); From d0ccaf21f87dbd353b9236e57f1448993fb94010 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 16 Mar 2019 23:21:15 -0500 Subject: [PATCH 8/8] updates version and change log --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4af89c0..01abbbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v1.2 (March 16, 2019) + +- Support for all Tracking directives of the form: `Tracking event="progress"` + ## v1.1 (March 3, 2019) - Preparing for open sourcing, adding documentation diff --git a/package.json b/package.json index 7ee232c..c513351 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "concert-vast", - "version": "1.1.0", + "version": "1.2.0", "description": "Simple Vast Parsing for Concert Video Ads", "main": "src/index.js", "author": "Vox Media",