@financial-times/cp-content-pipeline-ui 7.1.1 → 7.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/lib/components/CustomCodeComponent/client/index.d.ts +3 -1
- package/lib/components/CustomCodeComponent/client/index.js +7 -70
- package/lib/components/CustomCodeComponent/client/index.js.map +1 -1
- package/lib/components/CustomCodeComponent/client/tracking.d.ts +32 -0
- package/lib/components/CustomCodeComponent/client/tracking.js +85 -0
- package/lib/components/CustomCodeComponent/client/tracking.js.map +1 -0
- package/package.json +1 -1
- package/src/components/CustomCodeComponent/client/index.ts +9 -90
- package/src/components/CustomCodeComponent/client/tracking.ts +117 -0
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -574,6 +574,13 @@
|
|
|
574
574
|
* @financial-times/cp-content-pipeline-client bumped from ^3.7.2 to ^3.7.3
|
|
575
575
|
* @financial-times/cp-content-pipeline-schema bumped from ^2.10.1 to ^2.10.2
|
|
576
576
|
|
|
577
|
+
## [7.1.2](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-ui-v7.1.1...cp-content-pipeline-ui-v7.1.2) (2024-09-24)
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
### Bug Fixes
|
|
581
|
+
|
|
582
|
+
* tracking for ccc ([d21e731](https://github.com/Financial-Times/cp-content-pipeline/commit/d21e7310ca88cd8b9e21af2439c39ae4243eec0f))
|
|
583
|
+
|
|
577
584
|
## [7.1.1](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-ui-v7.1.0...cp-content-pipeline-ui-v7.1.1) (2024-09-17)
|
|
578
585
|
|
|
579
586
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CustomCodeComponentTracker } from './tracking';
|
|
1
2
|
/**
|
|
2
3
|
* CustomCodeComponentClient
|
|
3
4
|
* @description Track the view of a rendered custom code component
|
|
@@ -8,8 +9,9 @@ declare class CustomCodeComponentClient {
|
|
|
8
9
|
/**
|
|
9
10
|
* Track the mount of a custom code component
|
|
10
11
|
*/
|
|
11
|
-
|
|
12
|
+
tracking: CustomCodeComponentTracker;
|
|
12
13
|
constructor(el: Element);
|
|
13
14
|
static init(rootEl?: Element): (CustomCodeComponentClient | undefined)[];
|
|
15
|
+
static destroy(components: CustomCodeComponentClient[]): void;
|
|
14
16
|
}
|
|
15
17
|
export default CustomCodeComponentClient;
|
|
@@ -1,74 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
* TrackMount
|
|
5
|
-
* @description Track initial render of a custom code component
|
|
6
|
-
* @param {HTMLElement} mountElement - The custom code component
|
|
7
|
-
* @param {TrackingData} trackingData - The specific component data
|
|
8
|
-
*/
|
|
9
|
-
class TrackMount {
|
|
10
|
-
constructor(mountElement, trackingData) {
|
|
11
|
-
this.mountElement = mountElement;
|
|
12
|
-
this.trackingData = trackingData;
|
|
13
|
-
this.handleMount = () => {
|
|
14
|
-
const event = new CustomEvent('oTracking.event', {
|
|
15
|
-
detail: {
|
|
16
|
-
category: 'component',
|
|
17
|
-
action: 'mount',
|
|
18
|
-
...this.trackingData,
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
document.body.dispatchEvent(event);
|
|
22
|
-
};
|
|
23
|
-
this.init();
|
|
24
|
-
}
|
|
25
|
-
init() {
|
|
26
|
-
this.mountElement.addEventListener('ccc-connected', () => {
|
|
27
|
-
new TrackView(this.mountElement, this.trackingData);
|
|
28
|
-
this.handleMount();
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* TrackView
|
|
34
|
-
* @description Track the view of a rendered custom code component
|
|
35
|
-
* @param {HTMLElement} mountElement - The custom code component
|
|
36
|
-
* @param {TrackingData} trackingData - The specific component data
|
|
37
|
-
*/
|
|
38
|
-
class TrackView {
|
|
39
|
-
constructor(viewElement, trackingData) {
|
|
40
|
-
this.viewElement = viewElement;
|
|
41
|
-
this.trackingData = trackingData;
|
|
42
|
-
this.handleView = () => {
|
|
43
|
-
const event = new CustomEvent('oTracking.event', {
|
|
44
|
-
detail: {
|
|
45
|
-
category: 'component',
|
|
46
|
-
action: 'view',
|
|
47
|
-
...this.trackingData,
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
document.body.dispatchEvent(event);
|
|
51
|
-
};
|
|
52
|
-
this.viewElement = viewElement;
|
|
53
|
-
this.trackingData = trackingData;
|
|
54
|
-
this.init();
|
|
55
|
-
}
|
|
56
|
-
init() {
|
|
57
|
-
//Intersection observer that observes when viewElement is in view
|
|
58
|
-
this.observer = new IntersectionObserver((entries) => {
|
|
59
|
-
entries.forEach((entry) => {
|
|
60
|
-
if (entry.isIntersecting) {
|
|
61
|
-
this.handleView();
|
|
62
|
-
this.observer?.disconnect();
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
this.observer.observe(this.viewElement);
|
|
67
|
-
}
|
|
68
|
-
destroy() {
|
|
69
|
-
this.observer?.disconnect();
|
|
70
|
-
}
|
|
71
|
-
}
|
|
3
|
+
const tracking_1 = require("./tracking");
|
|
72
4
|
/**
|
|
73
5
|
* CustomCodeComponentClient
|
|
74
6
|
* @description Track the view of a rendered custom code component
|
|
@@ -84,12 +16,17 @@ class CustomCodeComponentClient {
|
|
|
84
16
|
type: 'custom-code-component',
|
|
85
17
|
},
|
|
86
18
|
};
|
|
87
|
-
this.
|
|
19
|
+
this.tracking = new tracking_1.CustomCodeComponentTracker(el, trackingData);
|
|
88
20
|
}
|
|
89
21
|
static init(rootEl) {
|
|
90
22
|
const root = rootEl instanceof Element ? rootEl : document;
|
|
91
23
|
return Array.from(root.querySelectorAll('custom-code-component')).map((el) => new CustomCodeComponentClient(el));
|
|
92
24
|
}
|
|
25
|
+
static destroy(components) {
|
|
26
|
+
components.forEach((component) => {
|
|
27
|
+
component.tracking.destroy();
|
|
28
|
+
});
|
|
29
|
+
}
|
|
93
30
|
}
|
|
94
31
|
exports.default = CustomCodeComponentClient;
|
|
95
32
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/CustomCodeComponent/client/index.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/CustomCodeComponent/client/index.ts"],"names":[],"mappings":";;AAAA,yCAAuD;AAEvD;;;;;GAKG;AACH,MAAM,yBAAyB;IAM7B,YAAY,EAAW;QACrB,MAAM,YAAY,GAAG;YACnB,SAAS,EAAE;gBACT,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE;gBAC/B,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE;gBACnC,IAAI,EAAE,uBAAuB;aAC9B;SACF,CAAA;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,qCAA0B,CAAC,EAAa,EAAE,YAAY,CAAC,CAAA;IAC7E,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,MAAgB;QAC1B,MAAM,IAAI,GAAG,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAA;QAC1D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,uBAAuB,CAAC,CAAC,CAAC,GAAG,CACnE,CAAC,EAAW,EAAE,EAAE,CAAC,IAAI,yBAAyB,CAAC,EAAE,CAAC,CACnD,CAAA;IACH,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,UAAuC;QACpD,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;YAC/B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;QAC9B,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AAED,kBAAe,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
type Component = {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
type: string;
|
|
5
|
+
timeElapsedSeconds?: number;
|
|
6
|
+
};
|
|
7
|
+
type TrackingData = {
|
|
8
|
+
component: Component;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* CustomCodeComponentTracker
|
|
12
|
+
* @description Track initial render of a custom code component
|
|
13
|
+
* @param {HTMLElement} mountElement - The custom code component
|
|
14
|
+
* @param {TrackingData} trackingData - The specific component data
|
|
15
|
+
*/
|
|
16
|
+
declare class CustomCodeComponentTracker {
|
|
17
|
+
private component;
|
|
18
|
+
private trackingData;
|
|
19
|
+
private startTime;
|
|
20
|
+
private totalVisibleTime;
|
|
21
|
+
private timeElapsedSeconds;
|
|
22
|
+
private observer;
|
|
23
|
+
private viewing;
|
|
24
|
+
constructor(component: Element, trackingData: TrackingData);
|
|
25
|
+
private init;
|
|
26
|
+
private onCccConnected;
|
|
27
|
+
private onCccError;
|
|
28
|
+
private dispatchEvent;
|
|
29
|
+
private onChange;
|
|
30
|
+
destroy(): void;
|
|
31
|
+
}
|
|
32
|
+
export { CustomCodeComponentTracker };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CustomCodeComponentTracker = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* CustomCodeComponentTracker
|
|
6
|
+
* @description Track initial render of a custom code component
|
|
7
|
+
* @param {HTMLElement} mountElement - The custom code component
|
|
8
|
+
* @param {TrackingData} trackingData - The specific component data
|
|
9
|
+
*/
|
|
10
|
+
class CustomCodeComponentTracker {
|
|
11
|
+
constructor(component, trackingData) {
|
|
12
|
+
this.component = component;
|
|
13
|
+
this.trackingData = trackingData;
|
|
14
|
+
this.startTime = 0;
|
|
15
|
+
this.totalVisibleTime = 0;
|
|
16
|
+
this.timeElapsedSeconds = null;
|
|
17
|
+
this.component = component;
|
|
18
|
+
this.trackingData = trackingData;
|
|
19
|
+
this.observer = null;
|
|
20
|
+
this.viewing = false;
|
|
21
|
+
this.init();
|
|
22
|
+
}
|
|
23
|
+
init() {
|
|
24
|
+
this.dispatchEvent('mount');
|
|
25
|
+
this.component.addEventListener('error', this.onCccError.bind(this));
|
|
26
|
+
this.component.addEventListener('ccc-connected', this.onCccConnected.bind(this));
|
|
27
|
+
}
|
|
28
|
+
onCccConnected() {
|
|
29
|
+
this.dispatchEvent('success');
|
|
30
|
+
this.observer = new IntersectionObserver(this.onChange.bind(this), {
|
|
31
|
+
rootMargin: `0px 0px -300px 0px`,
|
|
32
|
+
threshold: 0,
|
|
33
|
+
});
|
|
34
|
+
this.observer.observe(this.component);
|
|
35
|
+
}
|
|
36
|
+
onCccError() {
|
|
37
|
+
this.dispatchEvent('error');
|
|
38
|
+
}
|
|
39
|
+
dispatchEvent(action) {
|
|
40
|
+
const component = this.trackingData.component;
|
|
41
|
+
if (this.timeElapsedSeconds) {
|
|
42
|
+
component.timeElapsedSeconds = this.timeElapsedSeconds;
|
|
43
|
+
}
|
|
44
|
+
const event = new CustomEvent('oTracking.event', {
|
|
45
|
+
detail: {
|
|
46
|
+
category: 'component',
|
|
47
|
+
action,
|
|
48
|
+
...component,
|
|
49
|
+
},
|
|
50
|
+
bubbles: true,
|
|
51
|
+
});
|
|
52
|
+
document.body.dispatchEvent(event);
|
|
53
|
+
}
|
|
54
|
+
onChange(changes) {
|
|
55
|
+
changes.forEach((change) => {
|
|
56
|
+
if (change.target !== this.component) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (change.boundingClientRect.height > 0 &&
|
|
60
|
+
(change.isIntersecting || change.intersectionRatio >= 1)) {
|
|
61
|
+
this.dispatchEvent('view');
|
|
62
|
+
this.startTime = performance.now();
|
|
63
|
+
this.viewing = true;
|
|
64
|
+
}
|
|
65
|
+
if (this.viewing &&
|
|
66
|
+
(!change.isIntersecting || change.intersectionRatio === 0)) {
|
|
67
|
+
this.totalVisibleTime = performance.now() - this.startTime;
|
|
68
|
+
this.timeElapsedSeconds = parseFloat((this.totalVisibleTime / 1000).toFixed(2));
|
|
69
|
+
this.dispatchEvent('stop-view');
|
|
70
|
+
this.totalVisibleTime = 0;
|
|
71
|
+
this.timeElapsedSeconds = null;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
destroy() {
|
|
76
|
+
if (this.observer && this.component) {
|
|
77
|
+
this.observer.unobserve(this.component);
|
|
78
|
+
this.observer.disconnect();
|
|
79
|
+
this.component.removeEventListener('ccc-connected', this.onCccConnected.bind(this));
|
|
80
|
+
this.component.removeEventListener('error', this.onCccError.bind(this));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.CustomCodeComponentTracker = CustomCodeComponentTracker;
|
|
85
|
+
//# sourceMappingURL=tracking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracking.js","sourceRoot":"","sources":["../../../../src/components/CustomCodeComponent/client/tracking.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,91 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
id: string
|
|
3
|
-
name: string
|
|
4
|
-
type: string
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
type TrackingData = {
|
|
8
|
-
component: Component
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* TrackMount
|
|
13
|
-
* @description Track initial render of a custom code component
|
|
14
|
-
* @param {HTMLElement} mountElement - The custom code component
|
|
15
|
-
* @param {TrackingData} trackingData - The specific component data
|
|
16
|
-
*/
|
|
17
|
-
class TrackMount {
|
|
18
|
-
constructor(
|
|
19
|
-
private mountElement: Element,
|
|
20
|
-
private trackingData: TrackingData
|
|
21
|
-
) {
|
|
22
|
-
this.init()
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
private init() {
|
|
26
|
-
this.mountElement.addEventListener('ccc-connected', () => {
|
|
27
|
-
new TrackView(this.mountElement as Element, this.trackingData)
|
|
28
|
-
this.handleMount()
|
|
29
|
-
})
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
private handleMount = () => {
|
|
33
|
-
const event = new CustomEvent('oTracking.event', {
|
|
34
|
-
detail: {
|
|
35
|
-
category: 'component',
|
|
36
|
-
action: 'mount',
|
|
37
|
-
...this.trackingData,
|
|
38
|
-
},
|
|
39
|
-
})
|
|
40
|
-
document.body.dispatchEvent(event)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* TrackView
|
|
46
|
-
* @description Track the view of a rendered custom code component
|
|
47
|
-
* @param {HTMLElement} mountElement - The custom code component
|
|
48
|
-
* @param {TrackingData} trackingData - The specific component data
|
|
49
|
-
*/
|
|
50
|
-
class TrackView {
|
|
51
|
-
private observer: IntersectionObserver | undefined
|
|
52
|
-
constructor(
|
|
53
|
-
private viewElement: Element,
|
|
54
|
-
private trackingData: TrackingData
|
|
55
|
-
) {
|
|
56
|
-
this.viewElement = viewElement as Element
|
|
57
|
-
this.trackingData = trackingData
|
|
58
|
-
this.init()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private init() {
|
|
62
|
-
//Intersection observer that observes when viewElement is in view
|
|
63
|
-
this.observer = new IntersectionObserver((entries) => {
|
|
64
|
-
entries.forEach((entry) => {
|
|
65
|
-
if (entry.isIntersecting) {
|
|
66
|
-
this.handleView()
|
|
67
|
-
this.observer?.disconnect()
|
|
68
|
-
}
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
this.observer.observe(this.viewElement as Element)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
private handleView = () => {
|
|
75
|
-
const event = new CustomEvent('oTracking.event', {
|
|
76
|
-
detail: {
|
|
77
|
-
category: 'component',
|
|
78
|
-
action: 'view',
|
|
79
|
-
...this.trackingData,
|
|
80
|
-
},
|
|
81
|
-
})
|
|
82
|
-
document.body.dispatchEvent(event)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
destroy(): void {
|
|
86
|
-
this.observer?.disconnect()
|
|
87
|
-
}
|
|
88
|
-
}
|
|
1
|
+
import { CustomCodeComponentTracker } from './tracking'
|
|
89
2
|
|
|
90
3
|
/**
|
|
91
4
|
* CustomCodeComponentClient
|
|
@@ -97,7 +10,7 @@ class CustomCodeComponentClient {
|
|
|
97
10
|
/**
|
|
98
11
|
* Track the mount of a custom code component
|
|
99
12
|
*/
|
|
100
|
-
|
|
13
|
+
tracking: CustomCodeComponentTracker
|
|
101
14
|
|
|
102
15
|
constructor(el: Element) {
|
|
103
16
|
const trackingData = {
|
|
@@ -107,7 +20,7 @@ class CustomCodeComponentClient {
|
|
|
107
20
|
type: 'custom-code-component',
|
|
108
21
|
},
|
|
109
22
|
}
|
|
110
|
-
this.
|
|
23
|
+
this.tracking = new CustomCodeComponentTracker(el as Element, trackingData)
|
|
111
24
|
}
|
|
112
25
|
|
|
113
26
|
static init(rootEl?: Element): (CustomCodeComponentClient | undefined)[] {
|
|
@@ -116,6 +29,12 @@ class CustomCodeComponentClient {
|
|
|
116
29
|
(el: Element) => new CustomCodeComponentClient(el)
|
|
117
30
|
)
|
|
118
31
|
}
|
|
32
|
+
|
|
33
|
+
static destroy(components: CustomCodeComponentClient[]): void {
|
|
34
|
+
components.forEach((component) => {
|
|
35
|
+
component.tracking.destroy()
|
|
36
|
+
})
|
|
37
|
+
}
|
|
119
38
|
}
|
|
120
39
|
|
|
121
40
|
export default CustomCodeComponentClient
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
type Component = {
|
|
2
|
+
id: string
|
|
3
|
+
name: string
|
|
4
|
+
type: string
|
|
5
|
+
timeElapsedSeconds?: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type TrackingData = {
|
|
9
|
+
component: Component
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* CustomCodeComponentTracker
|
|
14
|
+
* @description Track initial render of a custom code component
|
|
15
|
+
* @param {HTMLElement} mountElement - The custom code component
|
|
16
|
+
* @param {TrackingData} trackingData - The specific component data
|
|
17
|
+
*/
|
|
18
|
+
class CustomCodeComponentTracker {
|
|
19
|
+
private startTime: number
|
|
20
|
+
private totalVisibleTime: number
|
|
21
|
+
private timeElapsedSeconds: number | null
|
|
22
|
+
private observer: IntersectionObserver | null
|
|
23
|
+
private viewing: boolean
|
|
24
|
+
|
|
25
|
+
constructor(private component: Element, private trackingData: TrackingData) {
|
|
26
|
+
this.startTime = 0
|
|
27
|
+
this.totalVisibleTime = 0
|
|
28
|
+
this.timeElapsedSeconds = null
|
|
29
|
+
this.component = component
|
|
30
|
+
this.trackingData = trackingData
|
|
31
|
+
this.observer = null
|
|
32
|
+
this.viewing = false
|
|
33
|
+
this.init()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private init() {
|
|
37
|
+
this.dispatchEvent('mount')
|
|
38
|
+
this.component.addEventListener('error', this.onCccError.bind(this))
|
|
39
|
+
this.component.addEventListener(
|
|
40
|
+
'ccc-connected',
|
|
41
|
+
this.onCccConnected.bind(this)
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private onCccConnected(): void {
|
|
46
|
+
this.dispatchEvent('success')
|
|
47
|
+
this.observer = new IntersectionObserver(this.onChange.bind(this), {
|
|
48
|
+
rootMargin: `0px 0px -300px 0px`,
|
|
49
|
+
threshold: 0,
|
|
50
|
+
})
|
|
51
|
+
this.observer.observe(this.component)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private onCccError(): void {
|
|
55
|
+
this.dispatchEvent('error')
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private dispatchEvent(action: string): void {
|
|
59
|
+
const component = this.trackingData.component
|
|
60
|
+
|
|
61
|
+
if (this.timeElapsedSeconds) {
|
|
62
|
+
component.timeElapsedSeconds = this.timeElapsedSeconds
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const event = new CustomEvent('oTracking.event', {
|
|
66
|
+
detail: {
|
|
67
|
+
category: 'component',
|
|
68
|
+
action,
|
|
69
|
+
...component,
|
|
70
|
+
},
|
|
71
|
+
bubbles: true,
|
|
72
|
+
})
|
|
73
|
+
document.body.dispatchEvent(event)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private onChange(changes: IntersectionObserverEntry[]): void {
|
|
77
|
+
changes.forEach((change) => {
|
|
78
|
+
if (change.target !== this.component) {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
if (
|
|
82
|
+
change.boundingClientRect.height > 0 &&
|
|
83
|
+
(change.isIntersecting || change.intersectionRatio >= 1)
|
|
84
|
+
) {
|
|
85
|
+
this.dispatchEvent('view')
|
|
86
|
+
this.startTime = performance.now()
|
|
87
|
+
this.viewing = true
|
|
88
|
+
}
|
|
89
|
+
if (
|
|
90
|
+
this.viewing &&
|
|
91
|
+
(!change.isIntersecting || change.intersectionRatio === 0)
|
|
92
|
+
) {
|
|
93
|
+
this.totalVisibleTime = performance.now() - this.startTime
|
|
94
|
+
this.timeElapsedSeconds = parseFloat(
|
|
95
|
+
(this.totalVisibleTime / 1000).toFixed(2)
|
|
96
|
+
)
|
|
97
|
+
this.dispatchEvent('stop-view')
|
|
98
|
+
this.totalVisibleTime = 0
|
|
99
|
+
this.timeElapsedSeconds = null
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
destroy(): void {
|
|
105
|
+
if (this.observer && this.component) {
|
|
106
|
+
this.observer.unobserve(this.component)
|
|
107
|
+
this.observer.disconnect()
|
|
108
|
+
this.component.removeEventListener(
|
|
109
|
+
'ccc-connected',
|
|
110
|
+
this.onCccConnected.bind(this)
|
|
111
|
+
)
|
|
112
|
+
this.component.removeEventListener('error', this.onCccError.bind(this))
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export { CustomCodeComponentTracker }
|