From f08421d30f502a0214340b1acfb09da849e8560d Mon Sep 17 00:00:00 2001 From: Ashish Puliyel Date: Thu, 28 Jan 2021 10:08:26 +0000 Subject: [PATCH 1/9] initial commit for eventTimer --- src/eventTimer.ts | 87 +++++++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 2 ++ 2 files changed, 89 insertions(+) create mode 100644 src/eventTimer.ts diff --git a/src/eventTimer.ts b/src/eventTimer.ts new file mode 100644 index 000000000..dccbc02c8 --- /dev/null +++ b/src/eventTimer.ts @@ -0,0 +1,87 @@ +class Event { + name: string; + ts: DOMHighResTimeStamp; + + constructor(name: string, mark: PerformanceEntry) { + this.name = name; + this.ts = mark.startTime; + } +} + +interface SlotEventStatus { + prebidStart: boolean; + prebidEnd: boolean; + slotInitalised: boolean; + adOnPage: boolean; +} + +export class EventTimer { + events: Event[]; + startTS: DOMHighResTimeStamp; + triggers: { + first: SlotEventStatus; + topAboveNav: SlotEventStatus; + }; + + constructor() { + this.events = []; + this.startTS = performance.now(); + this.triggers = { + first: { + prebidStart: false, + prebidEnd: false, + slotInitalised: false, + adOnPage: false, + }, + topAboveNav: { + prebidStart: false, + prebidEnd: false, + slotInitalised: false, + adOnPage: false, + }, + }; + } + + mark(name: string): PerformanceEntry { + const longName = `gu.commercial.${name}`; + performance.mark(longName); + + //mark is the item we just created (most recent mark with the name we just set) + const mark = performance + .getEntriesByName(longName, 'mark') + .slice(-1)[0]; + this.events.push(new Event(name, mark)); + return mark; + } + + /** + * Creates a new performance mark + * For slot events also ensures each TYPE of event event is marked only once for 'first' + * (the first time that event is triggered for ANY slot) and once for topAboveNav + * + * @param {string} eventName - The short name applied to the mark + * @param {origin} [origin=page] - Either 'page' (default) or the name of the slot + */ + trigger(eventName: string, origin = 'page'): void { + if (origin === 'page') { + this.mark(eventName); + return; + } + + if (!this.triggers.first[eventName as keyof SlotEventStatus]) { + this.mark(`first-{eventName}`); + this.triggers.first[eventName as keyof SlotEventStatus] = true; + } + + if (origin === 'topAboveNav') { + if ( + !this.triggers.topAboveNav[eventName as keyof SlotEventStatus] + ) { + this.mark(`topAboveNav-{eventName}`); + this.triggers.topAboveNav[ + eventName as keyof SlotEventStatus + ] = true; + } + } + } +} diff --git a/src/index.ts b/src/index.ts index bbabf8e0a..aa3311d90 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,4 +6,6 @@ export { fbPixel } from './third-party-tags/facebook-pixel'; export { twitter } from './third-party-tags/twitter-uwt'; export { inizio } from './third-party-tags/inizio'; export { remarketing } from './third-party-tags/remarketing'; +export { EventTimer } from './EventTimer'; + export type { ThirdPartyTag } from './types'; From d80933ceedee5de80039d76936b41f014cede4a2 Mon Sep 17 00:00:00 2001 From: Ashish Puliyel Date: Mon, 1 Feb 2021 10:45:23 +0000 Subject: [PATCH 2/9] turns out the slot is called 'top-above-nav' --- src/eventTimer.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/eventTimer.ts b/src/eventTimer.ts index dccbc02c8..271270169 100644 --- a/src/eventTimer.ts +++ b/src/eventTimer.ts @@ -20,7 +20,7 @@ export class EventTimer { startTS: DOMHighResTimeStamp; triggers: { first: SlotEventStatus; - topAboveNav: SlotEventStatus; + 'top-above-nav': SlotEventStatus; }; constructor() { @@ -33,7 +33,7 @@ export class EventTimer { slotInitalised: false, adOnPage: false, }, - topAboveNav: { + 'top-above-nav': { prebidStart: false, prebidEnd: false, slotInitalised: false, @@ -46,7 +46,7 @@ export class EventTimer { const longName = `gu.commercial.${name}`; performance.mark(longName); - //mark is the item we just created (most recent mark with the name we just set) + // Most recent mark with this name is the event we just created. const mark = performance .getEntriesByName(longName, 'mark') .slice(-1)[0]; @@ -63,6 +63,7 @@ export class EventTimer { * @param {origin} [origin=page] - Either 'page' (default) or the name of the slot */ trigger(eventName: string, origin = 'page'): void { + const TRACKEDSLOTNAME = 'top-above-nav'; if (origin === 'page') { this.mark(eventName); return; @@ -73,12 +74,14 @@ export class EventTimer { this.triggers.first[eventName as keyof SlotEventStatus] = true; } - if (origin === 'topAboveNav') { + if (origin === TRACKEDSLOTNAME) { if ( - !this.triggers.topAboveNav[eventName as keyof SlotEventStatus] + !this.triggers[TRACKEDSLOTNAME][ + eventName as keyof SlotEventStatus + ] ) { - this.mark(`topAboveNav-{eventName}`); - this.triggers.topAboveNav[ + this.mark(`${TRACKEDSLOTNAME}-{eventName}`); + this.triggers[TRACKEDSLOTNAME][ eventName as keyof SlotEventStatus ] = true; } From b8f15c1919108871ceb59b050862e0fcb178ca3b Mon Sep 17 00:00:00 2001 From: Ashish Puliyel Date: Mon, 1 Feb 2021 12:57:16 +0000 Subject: [PATCH 3/9] added init function --- src/eventTimer.ts | 15 +++++++++++++++ src/types.ts | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/src/eventTimer.ts b/src/eventTimer.ts index 271270169..269435733 100644 --- a/src/eventTimer.ts +++ b/src/eventTimer.ts @@ -23,6 +23,21 @@ export class EventTimer { 'top-above-nav': SlotEventStatus; }; + /** + * Initalise the EventTimer class on page. + * Returns a singleton instance of the EventTimer class and binds + * to window.guardian.commercialTimer. If it's been previously + * initalised and bound it returns the original instance + * + * @returns {EventTimer} Instance of EventTimer + */ + static init(): EventTimer { + if (!window.guardian.commercialTimer) { + window.guardian.commercialTimer = new EventTimer(); + } + return window.guardian.commercialTimer; + } + constructor() { this.events = []; this.startTS = performance.now(); diff --git a/src/types.ts b/src/types.ts index 0cc22bd11..59ecbcf3f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,5 @@ +import type { EventTimer } from './EventTimer'; + export type TagAtrribute = { name: string; value: string; @@ -34,5 +36,8 @@ declare global { val: Record; }>; googletag?: googletag.Googletag; + guardian: { + commercialTimer?: EventTimer; + }; } } From d701f4b407712fe3b6c92dacd2b13583ffc67e6f Mon Sep 17 00:00:00 2001 From: Ashish Puliyel Date: Mon, 1 Feb 2021 17:55:27 +0000 Subject: [PATCH 4/9] rename because osx didn't rename it last time! --- src/{eventTimer.ts => EventTimer.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{eventTimer.ts => EventTimer.ts} (100%) diff --git a/src/eventTimer.ts b/src/EventTimer.ts similarity index 100% rename from src/eventTimer.ts rename to src/EventTimer.ts From cf1328c8d470b8051d5b34ee412bee1b043b0fbe Mon Sep 17 00:00:00 2001 From: Ashish Puliyel Date: Tue, 2 Feb 2021 09:07:19 +0000 Subject: [PATCH 5/9] logical OR is more concise Co-authored-by: Max Duval --- src/EventTimer.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/EventTimer.ts b/src/EventTimer.ts index 269435733..835326d3e 100644 --- a/src/EventTimer.ts +++ b/src/EventTimer.ts @@ -32,10 +32,7 @@ export class EventTimer { * @returns {EventTimer} Instance of EventTimer */ static init(): EventTimer { - if (!window.guardian.commercialTimer) { - window.guardian.commercialTimer = new EventTimer(); - } - return window.guardian.commercialTimer; + return window.guardian.commercialTimer ||= new EventTimer(); } constructor() { From 6cd12e6779b61e14f5418c9d273608c136c6457a Mon Sep 17 00:00:00 2001 From: Ashish Puliyel Date: Tue, 2 Feb 2021 09:21:45 +0000 Subject: [PATCH 6/9] prettier didn't like the last one --- src/EventTimer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EventTimer.ts b/src/EventTimer.ts index 835326d3e..63e08c073 100644 --- a/src/EventTimer.ts +++ b/src/EventTimer.ts @@ -32,7 +32,7 @@ export class EventTimer { * @returns {EventTimer} Instance of EventTimer */ static init(): EventTimer { - return window.guardian.commercialTimer ||= new EventTimer(); + return (window.guardian.commercialTimer ||= new EventTimer()); } constructor() { From 8c9c3d37ea78c7f8b08a70c69063a0fe0816aa5c Mon Sep 17 00:00:00 2001 From: Ashish Puliyel Date: Wed, 3 Feb 2021 13:58:37 +0000 Subject: [PATCH 7/9] better explanation of the singleton. get() helper method --- src/EventTimer.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/EventTimer.ts b/src/EventTimer.ts index 63e08c073..d539f9ea6 100644 --- a/src/EventTimer.ts +++ b/src/EventTimer.ts @@ -14,7 +14,6 @@ interface SlotEventStatus { slotInitalised: boolean; adOnPage: boolean; } - export class EventTimer { events: Event[]; startTS: DOMHighResTimeStamp; @@ -34,6 +33,13 @@ export class EventTimer { static init(): EventTimer { return (window.guardian.commercialTimer ||= new EventTimer()); } + /** + * Just a helper method to access the singleton instance of EventTimer. + * Typical use case is EventTimer.get().trigger + */ + static get(): EventTimer { + return EventTimer.init(); + } constructor() { this.events = []; From 5b53c7868d83577c5d929ec395395d4dd1773df4 Mon Sep 17 00:00:00 2001 From: Ashish Puliyel Date: Wed, 3 Feb 2021 13:59:38 +0000 Subject: [PATCH 8/9] . --- src/EventTimer.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/EventTimer.ts b/src/EventTimer.ts index d539f9ea6..98c668e7d 100644 --- a/src/EventTimer.ts +++ b/src/EventTimer.ts @@ -24,10 +24,12 @@ export class EventTimer { /** * Initalise the EventTimer class on page. - * Returns a singleton instance of the EventTimer class and binds + * Returns the singleton instance of the EventTimer class and binds * to window.guardian.commercialTimer. If it's been previously * initalised and bound it returns the original instance - * + * Note: We save to window.guardian.commercialTimer because + * different bundles (DCR / DCP) can use commercial core, and we want + * all timer events saved to a single instance per-page * @returns {EventTimer} Instance of EventTimer */ static init(): EventTimer { From 382ae91a0cf6212bc6781aafb3ac295a63de299e Mon Sep 17 00:00:00 2001 From: Ashish Puliyel Date: Wed, 3 Feb 2021 14:09:02 +0000 Subject: [PATCH 9/9] linting --- src/EventTimer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EventTimer.ts b/src/EventTimer.ts index 96ce7a098..cf6c937d3 100644 --- a/src/EventTimer.ts +++ b/src/EventTimer.ts @@ -31,13 +31,13 @@ export class EventTimer { * Note: We save to window.guardian.commercialTimer because * different bundles (DCR / DCP) can use commercial core, and we want * all timer events saved to a single instance per-page - * + * * @returns {EventTimer} Instance of EventTimer */ static init(): EventTimer { return (window.guardian.commercialTimer ||= new EventTimer()); } - + /** * Just a helper method to access the singleton instance of EventTimer. * Typical use case is EventTimer.get().trigger