From 3c4bd0482899fb346d976d5c59e894e92214978f Mon Sep 17 00:00:00 2001
From: Enrique Marroquin <5449100+Enriqe@users.noreply.github.com>
Date: Mon, 18 Nov 2019 13:30:14 -0500
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=F0=9F=93=88=20=20Add=20analytics=20tr?=
=?UTF-8?q?igger=20for=20elements=20that=20show=20a=20tooltip=20(#25547)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* support for focused and click thru states
* support affiliate links
* types
* stop propagation on click events within affiliate links and embedded components
* add stop propagation in tooltip click
* renaming
---
examples/amp-story/analytics.html | 44 +++++++++++++++++--
extensions/amp-analytics/0.1/events.js | 13 +++++-
.../amp-analytics/0.1/test/test-events.js | 6 +--
.../amp-story/1.0/amp-story-affiliate-link.js | 26 +++++++++--
.../1.0/amp-story-embedded-component.js | 25 ++++++++++-
extensions/amp-story/1.0/page-advancement.js | 1 +
extensions/amp-story/1.0/story-analytics.js | 16 +++++--
.../amp-story/1.0/test/test-analytics.js | 4 +-
8 files changed, 116 insertions(+), 19 deletions(-)
diff --git a/examples/amp-story/analytics.html b/examples/amp-story/analytics.html
index 0df23aad10cb..1e1d1396a2e0 100644
--- a/examples/amp-story/analytics.html
+++ b/examples/amp-story/analytics.html
@@ -43,7 +43,7 @@
"endpoint": "https://raw.githubusercontent.com/ampproject/amphtml/master/examples/img/ampicon.png",
"base": "${endpoint}?${type|default:foo}&path=${canonicalPath}",
"pageView": "${base}?&index=${storyPageIndex}&count=${storyPageCount}&id=${storyPageId}&muted=${storyIsMuted}&progress=${storyProgress}",
- "click": "${base}?index=${storyPageIndex}&id=${storyPageId}&bookendTargetHref=${storyBookendTargetHref}&bookendCardType=${storyBookendComponentType}&bookendCardPosition=${storyBookendComponentPosition}"
+ "click": "${base}?&index=${storyPageIndex}&id=${storyPageId}&bookendTargetHref=${storyBookendTargetHref}&bookendCardType=${storyBookendComponentType}&bookendCardPosition=${storyBookendComponentPosition}"
},
"triggers": {
"trackAnchorClicks": {
@@ -61,6 +61,16 @@
"eventId": "clickOnBookend"
}
},
+ "trackFocusedState": {
+ "on": "story-focus",
+ "tagName": "a",
+ "request": "click"
+ },
+ "trackClickThru": {
+ "on": "story-click-through",
+ "tagName": "a",
+ "request": "click"
+ },
"trackPageview": {
"on": "story-page-visible",
"request": "pageView",
@@ -104,15 +114,43 @@
Page Two
Page Three
+ click me
click me
-
+
+
+ Page Four
+
+ amp.devamp.devamp.devamp.devamp.devamp.dev
+
+
+ amp.devamp.devamp.devamp.devamp.devamp.dev
+
+
+ amp.devamp.devamp.devamp.devamp.devamp.dev
+
+
+ amp.devamp.devamp.devamp.devamp.devamp.dev
+
+
+ amp.devamp.devamp.devamp.devamp.devamp.dev
+
+
+ amp.devamp.devamp.devamp.devamp.devamp.dev
+
+
+ amp.devamp.devamp.devamp.devamp.devamp.dev
+
+
+
+
+
- Page Four
+ Page Five
{
'storyPageIndex': '0',
'storyPageId': 'p4',
'storyPageCount': '4',
- 'pageDetails': {'repeated': false},
+ 'eventDetails': {'repeated': false},
};
tracker.add(
@@ -842,7 +842,7 @@ describes.realWin('Events', {amp: 1}, env => {
'storyPageIndex': '0',
'storyPageId': 'p4',
'storyPageCount': '4',
- 'pageDetails': {'repeated': true},
+ 'eventDetails': {'repeated': true},
};
tracker.add(target, 'story-page-visible', storyAnalyticsConfig, handler);
@@ -859,7 +859,7 @@ describes.realWin('Events', {amp: 1}, env => {
'storyPageIndex': '0',
'storyPageId': 'p4',
'storyPageCount': '4',
- 'pageDetails': {'repeated': true},
+ 'eventDetails': {'repeated': true},
};
tracker.add(target, 'story-page-visible', storyAnalyticsConfig, handler);
diff --git a/extensions/amp-story/1.0/amp-story-affiliate-link.js b/extensions/amp-story/1.0/amp-story-affiliate-link.js
index e0a1155bb9fe..1da389f89dc8 100644
--- a/extensions/amp-story/1.0/amp-story-affiliate-link.js
+++ b/extensions/amp-story/1.0/amp-story-affiliate-link.js
@@ -20,6 +20,7 @@
import {Services} from '../../../src/services';
import {StateProperty, getStoreService} from './amp-story-store-service';
+import {StoryAnalyticsEvent, getAnalyticsService} from './story-analytics';
import {getAmpdoc} from '../../../src/service';
import {htmlFor} from '../../../src/static-template';
@@ -61,6 +62,9 @@ export class AmpStoryAffiliateLink {
/** @private @const {!../../../src/service/resources-interface.ResourcesInterface} */
this.resources_ = Services.resourcesForDoc(getAmpdoc(this.win_.document));
+
+ /** @private @const {!./story-analytics.StoryAnalyticsService} */
+ this.analyticsService_ = getAnalyticsService(this.win_, element);
}
/**
@@ -80,15 +84,15 @@ export class AmpStoryAffiliateLink {
this.addLaunchElement_();
});
- this.initializeListener_();
+ this.initializeListeners_();
this.element_[AFFILIATE_LINK_BUILT] = true;
}
/**
- * Initialize listener to toggle expanded state.
+ * Initializes listeners.
* @private
*/
- initializeListener_() {
+ initializeListeners_() {
this.storeService_.subscribe(
StateProperty.AFFILIATE_LINK_STATE,
elementToToggleExpand => {
@@ -98,9 +102,23 @@ export class AmpStoryAffiliateLink {
this.launchEl_.toggleAttribute('hidden', !expand);
if (expand) {
this.element_.toggleAttribute('pristine', false);
+ this.analyticsService_.triggerEvent(
+ StoryAnalyticsEvent.FOCUS,
+ this.element_
+ );
}
}
);
+
+ this.element_.addEventListener('click', event => {
+ if (this.element_.hasAttribute('expanded')) {
+ event.stopPropagation();
+ this.analyticsService_.triggerEvent(
+ StoryAnalyticsEvent.CLICK_THROUGH,
+ this.element_
+ );
+ }
+ });
}
/**
@@ -114,7 +132,7 @@ export class AmpStoryAffiliateLink {
-
+
`;
this.element_.appendChild(iconEl);
}
diff --git a/extensions/amp-story/1.0/amp-story-embedded-component.js b/extensions/amp-story/1.0/amp-story-embedded-component.js
index eccb62a6c8b4..b5cfb2239386 100644
--- a/extensions/amp-story/1.0/amp-story-embedded-component.js
+++ b/extensions/amp-story/1.0/amp-story-embedded-component.js
@@ -22,7 +22,11 @@ import {
UIType,
getStoreService,
} from './amp-story-store-service';
-import {AdvancementMode} from './story-analytics';
+import {
+ AdvancementMode,
+ StoryAnalyticsEvent,
+ getAnalyticsService,
+} from './story-analytics';
import {CSS} from '../../../build/amp-story-tooltip-1.0.css';
import {EventType, dispatch} from './events';
import {LocalizedStringId} from '../../../src/localized-strings';
@@ -286,6 +290,9 @@ export class AmpStoryEmbeddedComponent {
/** @private @const {!../../../src/service/resources-interface.ResourcesInterface} */
this.resources_ = Services.resourcesForDoc(getAmpdoc(this.win_.document));
+ /** @private @const {!./story-analytics.StoryAnalyticsService} */
+ this.analyticsService_ = getAnalyticsService(this.win_, storyEl);
+
/** @private @const {!../../../src/service/owners-interface.OwnersInterface} */
this.owners_ = Services.ownersForDoc(getAmpdoc(this.win_.document));
@@ -384,6 +391,10 @@ export class AmpStoryEmbeddedComponent {
case EmbeddedComponentState.FOCUSED:
this.state_ = state;
this.onFocusedStateUpdate_(component);
+ this.analyticsService_.triggerEvent(
+ StoryAnalyticsEvent.FOCUS,
+ this.triggeringTarget_
+ );
break;
case EmbeddedComponentState.HIDDEN:
this.state_ = state;
@@ -503,6 +514,18 @@ export class AmpStoryEmbeddedComponent {
this.onOutsideTooltipClick_(event)
);
+ this.tooltip_.addEventListener(
+ 'click',
+ event => {
+ event.stopPropagation();
+ this.analyticsService_.triggerEvent(
+ StoryAnalyticsEvent.CLICK_THROUGH,
+ this.triggeringTarget_
+ );
+ },
+ true /** capture */
+ );
+
return this.shadowRoot_;
}
diff --git a/extensions/amp-story/1.0/page-advancement.js b/extensions/amp-story/1.0/page-advancement.js
index f547971f7d12..2c05f0d1356d 100644
--- a/extensions/amp-story/1.0/page-advancement.js
+++ b/extensions/amp-story/1.0/page-advancement.js
@@ -552,6 +552,7 @@ class ManualAdvancement extends AdvancementConfig {
const pageRect = this.element_.getLayoutBox();
if (this.isHandledByEmbeddedComponent_(event, pageRect)) {
+ event.stopPropagation();
event.preventDefault();
const embedComponent = /** @type {InteractiveComponentDef} */ (this.storeService_.get(
StateProperty.INTERACTIVE_COMPONENT_STATE
diff --git a/extensions/amp-story/1.0/story-analytics.js b/extensions/amp-story/1.0/story-analytics.js
index 9e0486391995..59c78dfba082 100644
--- a/extensions/amp-story/1.0/story-analytics.js
+++ b/extensions/amp-story/1.0/story-analytics.js
@@ -25,6 +25,8 @@ export const StoryAnalyticsEvent = {
BOOKEND_CLICK: 'story-bookend-click',
BOOKEND_ENTER: 'story-bookend-enter',
BOOKEND_EXIT: 'story-bookend-exit',
+ CLICK_THROUGH: 'story-click-through',
+ FOCUS: 'story-focus',
LAST_PAGE_VISIBLE: 'story-last-page-visible',
PAGE_ATTACHMENT_ENTER: 'story-page-attachment-enter',
PAGE_ATTACHMENT_EXIT: 'story-page-attachment-exit',
@@ -127,23 +129,25 @@ export class StoryAnalyticsService {
/**
* @param {!StoryAnalyticsEvent} eventType
+ * @param {Element=} element
*/
- triggerEvent(eventType) {
+ triggerEvent(eventType, element = null) {
this.incrementPageEventCount_(eventType);
triggerAnalyticsEvent(
this.element_,
eventType,
- this.updateDetails(eventType)
+ this.updateDetails(eventType, element)
);
}
/**
* Updates event details.
* @param {!StoryAnalyticsEvent} eventType
+ * @param {Element=} element
* @visibleForTesting
* @return {!JsonObject}}
*/
- updateDetails(eventType) {
+ updateDetails(eventType, element = null) {
const details = {};
const vars = this.variableService_.get();
const pageId = vars['storyPageId'];
@@ -152,8 +156,12 @@ export class StoryAnalyticsService {
details.repeated = true;
}
+ if (element) {
+ details.tagName = element.tagName.toLowerCase();
+ }
+
return /** @type {!JsonObject} */ (Object.assign(
- {pageDetails: details},
+ {eventDetails: details},
vars
));
}
diff --git a/extensions/amp-story/1.0/test/test-analytics.js b/extensions/amp-story/1.0/test/test-analytics.js
index cca1a471863a..1d16861d8ad4 100644
--- a/extensions/amp-story/1.0/test/test-analytics.js
+++ b/extensions/amp-story/1.0/test/test-analytics.js
@@ -70,7 +70,7 @@ describes.fakeWin('amp-story analytics', {}, env => {
expect(trigger).to.have.been.calledOnceWith('story-page-visible');
const details = analytics.updateDetails('story-page-visible');
- expect(details.pageDetails).to.deep.equal({});
+ expect(details.eventDetails).to.deep.equal({});
});
it('should mark event as repeated when fired more than once', () => {
@@ -94,7 +94,7 @@ describes.fakeWin('amp-story analytics', {}, env => {
expect(trigger).to.have.been.calledWith('story-page-visible');
expect(trigger).to.have.been.calledThrice;
expect(
- analytics.updateDetails('story-page-visible').pageDetails
+ analytics.updateDetails('story-page-visible').eventDetails
).to.deep.include({
'repeated': true,
});