New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
馃搱 AmpStoryEventTracker & Integration tests #24548
Changes from all commits
157af55
52a740b
d5097e6
46b8513
a5eae3e
69264bc
a6395dd
979fbbe
cd1801e
e22f15f
6856af7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,7 @@ export const AnalyticsEventType = { | |
INI_LOAD: 'ini-load', | ||
RENDER_START: 'render-start', | ||
SCROLL: 'scroll', | ||
STORY: 'story', | ||
TIMER: 'timer', | ||
VIDEO: 'video', | ||
VISIBLE: 'visible', | ||
|
@@ -109,6 +110,13 @@ const TRACKER_TYPE = Object.freeze({ | |
return new ScrollEventTracker(root); | ||
}, | ||
}, | ||
[AnalyticsEventType.STORY]: { | ||
name: AnalyticsEventType.STORY, | ||
allowedFor: ALLOWED_FOR_ALL_ROOT_TYPES, | ||
klass: function(root) { | ||
return new AmpStoryEventTracker(root); | ||
}, | ||
}, | ||
[AnalyticsEventType.TIMER]: { | ||
name: AnalyticsEventType.TIMER, | ||
allowedFor: ALLOWED_FOR_ALL_ROOT_TYPES, | ||
|
@@ -135,6 +143,14 @@ const TRACKER_TYPE = Object.freeze({ | |
/** @visibleForTesting */ | ||
export const trackerTypeForTesting = TRACKER_TYPE; | ||
|
||
/** | ||
* @param {string} triggerType | ||
* @return {boolean} | ||
*/ | ||
function isAmpStoryTriggerType(triggerType) { | ||
return startsWith(triggerType, 'story'); | ||
} | ||
|
||
/** | ||
* @param {string} triggerType | ||
* @return {boolean} | ||
|
@@ -159,6 +175,9 @@ export function getTrackerKeyName(eventType) { | |
if (isVideoTriggerType(eventType)) { | ||
return AnalyticsEventType.VIDEO; | ||
} | ||
if (isAmpStoryTriggerType(eventType)) { | ||
return AnalyticsEventType.STORY; | ||
} | ||
if (!isReservedTriggerType(eventType)) { | ||
return AnalyticsEventType.CUSTOM; | ||
} | ||
|
@@ -386,6 +405,80 @@ export class CustomEventTracker extends EventTracker { | |
} | ||
} | ||
|
||
// TODO(Enriqe): If needed, add support for sandbox story event. | ||
// (e.g. sandbox-story-xxx). | ||
export class AmpStoryEventTracker extends CustomEventTracker { | ||
/** | ||
* @param {!./analytics-root.AnalyticsRoot} root | ||
*/ | ||
constructor(root) { | ||
super(root); | ||
} | ||
|
||
/** @override */ | ||
add(context, eventType, config, listener) { | ||
// TODO(Enriqe): add support for storySpec. | ||
const rootTarget = this.root.getRootElement(); | ||
|
||
// Fire buffered events if any. | ||
const buffer = this.buffer_ && this.buffer_[eventType]; | ||
if (buffer) { | ||
const bufferLength = buffer.length; | ||
|
||
for (let i = 0; i < bufferLength; i++) { | ||
const event = buffer[i]; | ||
this.fireListener_(event, rootTarget, config, listener); | ||
} | ||
} | ||
|
||
let observables = this.observables_[eventType]; | ||
if (!observables) { | ||
observables = new Observable(); | ||
this.observables_[eventType] = observables; | ||
} | ||
|
||
return this.observables_[eventType].add(event => { | ||
this.fireListener_(event, rootTarget, config, listener); | ||
}); | ||
} | ||
|
||
/** | ||
* Fires listener given the specified configuration. | ||
* @param {!AnalyticsEvent} event | ||
* @param {!Element} rootTarget | ||
* @param {!JsonObject} config | ||
|
||
* @param {function(!AnalyticsEvent)} listener | ||
*/ | ||
fireListener_(event, rootTarget, config, listener) { | ||
const type = event['type']; | ||
const vars = event['vars']; | ||
|
||
listener(new AnalyticsEvent(rootTarget, type, vars)); | ||
} | ||
|
||
/** | ||
* Triggers a custom event for the associated root, or buffers them if the | ||
* observables aren't present yet. | ||
* @param {!AnalyticsEvent} event | ||
*/ | ||
trigger(event) { | ||
const eventType = event['type']; | ||
const observables = this.observables_[eventType]; | ||
|
||
// If listeners already present - trigger right away. | ||
if (observables) { | ||
observables.fire(event); | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sandboxEvent is added if an analytics event is added by an AMP component dynamically, in the format of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To make sure I understand: If that's the case then it should still go to the Let me know if I'm missing something. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's right. All sandbox events will be handled by the |
||
// Create buffer and enqueue event if needed. | ||
if (this.buffer_) { | ||
this.buffer_[eventType] = this.buffer_[eventType] || []; | ||
this.buffer_[eventType].push(event); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Tracks click events. | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make sure I understand: we're adding a "fireListener" method to be able to maybe not fire duplicate events depending on the configuration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that's right. This is going to make it easier for when we introduce the configurable options and control when we fire events or not.