@adobe/helix-rum-enhancer 1.11.0 → 2.1.0
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 +16 -4
- package/README.md +5 -3
- package/package.json +3 -2
- package/src/index.js +218 -121
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
# [1.
|
|
1
|
+
# [2.1.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.0.0...v2.1.0) (2024-01-22)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **loadresource:** enable loadresource checkpoint for all origins ([0be8de7](https://github.com/adobe/helix-rum-enhancer/commit/0be8de7ee3e57afdd60a2b9af743bedd061e907d))
|
|
2
7
|
|
|
3
8
|
|
|
4
9
|
### Features
|
|
5
10
|
|
|
6
|
-
* **observer:** enable tracking of JSON loading for all browsers that have a PerformanceObserver implementation ([
|
|
11
|
+
* **observer:** enable tracking of JSON loading for all browsers that have a PerformanceObserver implementation ([45b5e64](https://github.com/adobe/helix-rum-enhancer/commit/45b5e6428fb9c51e8fc4d477c574d44a361b3ec2))
|
|
7
12
|
|
|
8
|
-
# [
|
|
13
|
+
# [2.0.0](https://github.com/adobe/helix-rum-enhancer/compare/v1.9.1...v2.0.0) (2024-01-16)
|
|
9
14
|
|
|
10
15
|
|
|
11
16
|
### Features
|
|
12
17
|
|
|
13
|
-
*
|
|
18
|
+
* prepare compatibility with @adobe/helix-rum-js@2 ([b1cef07](https://github.com/adobe/helix-rum-enhancer/commit/b1cef07ec59c8134056a9aaf25a331016aeffe39))
|
|
19
|
+
* prepare compatibility with @adobe/helix-rum-js@2 ([702a873](https://github.com/adobe/helix-rum-enhancer/commit/702a8731d783850d26b2daae3a839e7ee4192e47))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### BREAKING CHANGES
|
|
23
|
+
|
|
24
|
+
* this version can only be used from helix-rum-js@v2 and up
|
|
25
|
+
* this version can only be used from helix-rum-js@v2 and up
|
|
14
26
|
|
|
15
27
|
## [1.9.1](https://github.com/adobe/helix-rum-enhancer/compare/v1.9.0...v1.9.1) (2024-01-11)
|
|
16
28
|
|
package/README.md
CHANGED
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
## Status
|
|
6
6
|
[](https://codecov.io/gh/adobe/helix-rum-enhancer)
|
|
7
|
-
[](https://github.com/adobe/helix-rum-enhancer/actions/workflows/main.yaml)
|
|
8
8
|
[](https://github.com/adobe/helix-rum-enhancer/blob/master/LICENSE.txt)
|
|
9
9
|
[](https://github.com/adobe/helix-rum-enhancer/issues)
|
|
10
|
-
[](https://lgtm.com/projects/g/adobe/helix-rum-enhancer)
|
|
11
10
|
[](https://github.com/semantic-release/semantic-release)
|
|
12
11
|
|
|
13
12
|
## Usage
|
|
@@ -17,10 +16,13 @@ This library is meant to be used in conjunction with and loaded by the `sampleRU
|
|
|
17
16
|
It will add following new checkpoints:
|
|
18
17
|
|
|
19
18
|
- `cwv`: Core Web Vitals Collection
|
|
19
|
+
- `pagesviewed`: number that helps to estimate how many pages are seen in average by a user.
|
|
20
20
|
- `click`: A click anywhere in the document
|
|
21
21
|
- `viewblock`: A Helix block has been scrolled into the viewport
|
|
22
22
|
- `viewmedia`: An image or video hosted by Helix Media Bus has been scrolled into the viewport
|
|
23
|
-
- `enter`:
|
|
23
|
+
- `reload`, `navigate`, `enter`: depending on how the current page was accessed
|
|
24
|
+
- `formsubmit`: when a form is submitted
|
|
25
|
+
- `leave`: when the user leaves the page
|
|
24
26
|
|
|
25
27
|
## Development
|
|
26
28
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-rum-enhancer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Helix RUM Enhancer",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"lint": "eslint .",
|
|
10
10
|
"docs": "npx jsdoc2md -c .jsdoc.json --files 'src/*.js' > docs/API.md",
|
|
11
11
|
"semantic-release": "semantic-release",
|
|
12
|
+
"semantic-release-dry": "semantic-release --dry-run --branches $CI_BRANCH",
|
|
12
13
|
"prepare": "husky install"
|
|
13
14
|
},
|
|
14
15
|
"repository": {
|
|
@@ -32,7 +33,7 @@
|
|
|
32
33
|
"@semantic-release/changelog": "6.0.3",
|
|
33
34
|
"@semantic-release/git": "10.0.1",
|
|
34
35
|
"@semantic-release/npm": "11.0.2",
|
|
35
|
-
"c8": "9.
|
|
36
|
+
"c8": "9.1.0",
|
|
36
37
|
"codecov": "3.8.3",
|
|
37
38
|
"eslint": "8.56.0",
|
|
38
39
|
"eslint-plugin-header": "3.1.1",
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2023 Adobe. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -9,66 +9,21 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
entries
|
|
18
|
-
.filter((entry) => entry.isIntersecting)
|
|
19
|
-
.forEach((entry) => {
|
|
20
|
-
sampleRUM.blockobserver.unobserve(entry.target); // observe only once
|
|
21
|
-
const target = sampleRUM.targetselector(entry.target);
|
|
22
|
-
const source = sampleRUM.sourceselector(entry.target);
|
|
23
|
-
sampleRUM('viewblock', { target, source });
|
|
24
|
-
});
|
|
25
|
-
}, { threshold: 0.25 }) : { observe: () => { } };
|
|
26
|
-
|
|
27
|
-
sampleRUM.mediaobserver = (window.IntersectionObserver) ? new IntersectionObserver((entries) => {
|
|
28
|
-
entries
|
|
29
|
-
.filter((entry) => entry.isIntersecting)
|
|
30
|
-
.forEach((entry) => {
|
|
31
|
-
sampleRUM.mediaobserver.unobserve(entry.target); // observe only once
|
|
32
|
-
const target = sampleRUM.targetselector(entry.target);
|
|
33
|
-
const source = sampleRUM.sourceselector(entry.target);
|
|
34
|
-
sampleRUM('viewmedia', { target, source });
|
|
35
|
-
});
|
|
36
|
-
}, { threshold: 0.25 }) : { observe: () => { } };
|
|
37
|
-
|
|
38
|
-
sampleRUM.drain('observe', ((elements) => {
|
|
39
|
-
elements.forEach((element) => {
|
|
40
|
-
if (element.tagName.toLowerCase() === 'img'
|
|
41
|
-
|| element.tagName.toLowerCase() === 'video'
|
|
42
|
-
|| element.tagName.toLowerCase() === 'audio'
|
|
43
|
-
|| element.tagName.toLowerCase() === 'iframe') {
|
|
44
|
-
sampleRUM.mediaobserver.observe(element);
|
|
45
|
-
} else {
|
|
46
|
-
sampleRUM.blockobserver.observe(element);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
}));
|
|
50
|
-
|
|
51
|
-
const navigate = (source, type) => {
|
|
52
|
-
const payload = { source, target: document.visibilityState };
|
|
53
|
-
// reload: same page, navigate: same origin, enter: everything else
|
|
54
|
-
if (type === 'reload' || source === window.location.href) {
|
|
55
|
-
sampleRUM('reload', payload);
|
|
56
|
-
} else if (type !== 'navigate') {
|
|
57
|
-
sampleRUM(type, payload); // back, forward, prerender, etc.
|
|
58
|
-
} else if (source && window.location.origin === new URL(source).origin) {
|
|
59
|
-
sampleRUM('navigate', payload); // internal navigation
|
|
60
|
-
} else {
|
|
61
|
-
sampleRUM('enter', payload); // enter site
|
|
62
|
-
}
|
|
63
|
-
};
|
|
12
|
+
/* eslint-env browser */
|
|
13
|
+
const KNOWN_PROPERTIES = ['weight', 'id', 'referer', 'checkpoint', 't', 'source', 'target', 'cwv', 'CLS', 'FID', 'LCP', 'INP', 'TTFB'];
|
|
14
|
+
const DEFAULT_TRACKING_EVENTS = ['click', 'cwv', 'form', 'enterleave', 'viewblock', 'viewmedia', 'loadresource'];
|
|
15
|
+
const SESSION_STORAGE_KEY = 'aem-rum';
|
|
16
|
+
const { sampleRUM, queue, isSelected } = window.hlx.rum;
|
|
64
17
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
18
|
+
const urlSanitizers = {
|
|
19
|
+
full: () => window.location.href,
|
|
20
|
+
origin: () => window.location.origin,
|
|
21
|
+
path: () => window.location.href.replace(/\?.*$/, ''),
|
|
22
|
+
};
|
|
68
23
|
|
|
69
|
-
|
|
70
|
-
let value = element.getAttribute('data-rum-target') || element.getAttribute('href')
|
|
71
|
-
|
|
24
|
+
const targetselector = (element) => {
|
|
25
|
+
let value = element.getAttribute('data-rum-target') || element.getAttribute('href')
|
|
26
|
+
|| element.currentSrc || element.getAttribute('src') || element.dataset.action || element.action;
|
|
72
27
|
if (value && !value.startsWith('https://')) {
|
|
73
28
|
// resolve relative links
|
|
74
29
|
value = new URL(value, window.location).href;
|
|
@@ -76,42 +31,7 @@ sampleRUM.targetselector = (element) => {
|
|
|
76
31
|
return value;
|
|
77
32
|
};
|
|
78
33
|
|
|
79
|
-
|
|
80
|
-
const cwvScript = new URL('.rum/web-vitals/dist/web-vitals.iife.js', sampleRUM.baseURL).href;
|
|
81
|
-
if (document.querySelector(`script[src="${cwvScript}"]`)) {
|
|
82
|
-
// web vitals script has been loaded already
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
// use classic script to avoid CORS issues
|
|
86
|
-
const script = document.createElement('script');
|
|
87
|
-
script.src = cwvScript;
|
|
88
|
-
script.onload = () => {
|
|
89
|
-
const storeCWV = (measurement) => {
|
|
90
|
-
const data = { cwv: {} };
|
|
91
|
-
data.cwv[measurement.name] = measurement.value;
|
|
92
|
-
sampleRUM('cwv', data);
|
|
93
|
-
};
|
|
94
|
-
// When loading `web-vitals` using a classic script, all the public
|
|
95
|
-
// methods can be found on the `webVitals` global namespace.
|
|
96
|
-
['CLS', 'FID', 'LCP', 'INP', 'TTFB']
|
|
97
|
-
.map((metric) => window.webVitals[`get${metric}`])
|
|
98
|
-
.filter((metric) => typeof metric === 'function')
|
|
99
|
-
.forEach((invokeMetric) => {
|
|
100
|
-
invokeMetric(storeCWV);
|
|
101
|
-
});
|
|
102
|
-
};
|
|
103
|
-
document.head.appendChild(script);
|
|
104
|
-
}));
|
|
105
|
-
|
|
106
|
-
sampleRUM.drain('leave', ((event = {}) => {
|
|
107
|
-
if (sampleRUM.left || (event.type === 'visibilitychange' && document.visibilityState !== 'hidden')) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
sampleRUM.left = true;
|
|
111
|
-
sampleRUM('leave');
|
|
112
|
-
}));
|
|
113
|
-
|
|
114
|
-
sampleRUM.sourceselector = (element) => {
|
|
34
|
+
const sourceselector = (element) => {
|
|
115
35
|
if (element === document.body || element === document.documentElement || !element) {
|
|
116
36
|
return undefined;
|
|
117
37
|
}
|
|
@@ -124,8 +44,8 @@ sampleRUM.sourceselector = (element) => {
|
|
|
124
44
|
formElementSelector = element.tagName === 'INPUT' ? `form input[type='${element.getAttribute('type')}']` : `form ${element.tagName.toLowerCase()}`;
|
|
125
45
|
}
|
|
126
46
|
|
|
127
|
-
const blockName = element.closest('.block') ? element.closest('.block').getAttribute('data-block-name') : '';
|
|
128
47
|
if (element.id || formElementSelector) {
|
|
48
|
+
const blockName = element.closest('.block') ? element.closest('.block').getAttribute('data-block-name') : '';
|
|
129
49
|
const id = element.id ? `#${element.id}` : '';
|
|
130
50
|
return blockName ? `.${blockName} ${formElementSelector}${id}` : `${formElementSelector}${id}`;
|
|
131
51
|
}
|
|
@@ -133,34 +53,211 @@ sampleRUM.sourceselector = (element) => {
|
|
|
133
53
|
if (element.getAttribute('data-block-name')) {
|
|
134
54
|
return `.${element.getAttribute('data-block-name')}`;
|
|
135
55
|
}
|
|
56
|
+
return sourceselector(element.parentElement);
|
|
57
|
+
};
|
|
136
58
|
|
|
137
|
-
|
|
138
|
-
|
|
59
|
+
const formSubmitListener = (e) => sampleRUM('formsubmit', { target: targetselector(e.target), source: sourceselector(e.target) });
|
|
60
|
+
// eslint-disable-next-line no-use-before-define
|
|
61
|
+
const mutationObserver = window.MutationObserver ? new MutationObserver(mutationsCallback) : null;
|
|
62
|
+
|
|
63
|
+
// eslint-disable-next-line no-unused-vars
|
|
64
|
+
function optedIn(checkpoint, data) {
|
|
65
|
+
// TODO: check config service to know if
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
// Gets configured collection from the config service for the current domain
|
|
69
|
+
function getCollectionConfig() {
|
|
70
|
+
return DEFAULT_TRACKING_EVENTS;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function trackCheckpoint(checkpoint, data, t) {
|
|
74
|
+
const { weight, id } = window.hlx.rum;
|
|
75
|
+
if (optedIn(checkpoint, data) && isSelected) {
|
|
76
|
+
const sendPing = (pdata = data) => {
|
|
77
|
+
// eslint-disable-next-line object-curly-newline, max-len
|
|
78
|
+
const body = JSON.stringify({ weight, id, sanitizeURL: urlSanitizers[window.hlx.RUM_MASK_URL || 'path'], checkpoint, t, ...data }, KNOWN_PROPERTIES);
|
|
79
|
+
const url = new URL(`.rum/${weight}`, sampleRUM.baseURL).href;
|
|
80
|
+
navigator.sendBeacon(url, body);
|
|
81
|
+
// eslint-disable-next-line no-console
|
|
82
|
+
console.debug(`ping:${checkpoint}`, pdata);
|
|
83
|
+
};
|
|
84
|
+
sendPing(data);
|
|
139
85
|
}
|
|
140
|
-
|
|
141
|
-
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function processQueue() {
|
|
89
|
+
while (queue.length) {
|
|
90
|
+
const ck = queue.shift();
|
|
91
|
+
trackCheckpoint(...ck);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function addCWVTracking() {
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
const cwvScript = new URL('.rum/web-vitals/dist/web-vitals.iife.js', sampleRUM.baseURL).href;
|
|
98
|
+
if (document.querySelector(`script[src="${cwvScript}"]`)) {
|
|
99
|
+
// web vitals script has been loaded already
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const script = document.createElement('script');
|
|
103
|
+
script.src = cwvScript;
|
|
104
|
+
script.onload = () => {
|
|
105
|
+
const storeCWV = (measurement) => {
|
|
106
|
+
const data = { cwv: {} };
|
|
107
|
+
data.cwv[measurement.name] = measurement.value;
|
|
108
|
+
sampleRUM('cwv', data);
|
|
109
|
+
};
|
|
110
|
+
// When loading `web-vitals` using a classic script, all the public
|
|
111
|
+
// methods can be found on the `webVitals` global namespace.
|
|
112
|
+
['CLS', 'FID', 'LCP', 'INP', 'TTFB']
|
|
113
|
+
.map((metric) => window.webVitals[`get${metric}`])
|
|
114
|
+
.filter((metric) => typeof metric === 'function')
|
|
115
|
+
.forEach((invokeMetric) => {
|
|
116
|
+
invokeMetric(storeCWV);
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
document.head.appendChild(script);
|
|
120
|
+
}, 2000); // wait for delayed
|
|
121
|
+
}
|
|
142
122
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
123
|
+
function addEnterLeaveTracking() {
|
|
124
|
+
// enter checkpoint when referrer is not the current page url
|
|
125
|
+
const navigate = (source, type) => {
|
|
126
|
+
const payload = { source, target: document.visibilityState };
|
|
127
|
+
// reload: same page, navigate: same origin, enter: everything else
|
|
128
|
+
if (type === 'reload' || source === window.location.href) {
|
|
129
|
+
sampleRUM('reload', payload);
|
|
130
|
+
} else if (type !== 'navigate') {
|
|
131
|
+
sampleRUM(type, payload); // back, forward, prerender, etc.
|
|
132
|
+
} else if (source && window.location.origin === new URL(source).origin) {
|
|
133
|
+
sampleRUM('navigate', payload); // internal navigation
|
|
134
|
+
} else {
|
|
135
|
+
sampleRUM('enter', payload); // enter site
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
navigate(document.referrer);
|
|
139
|
+
|
|
140
|
+
new PerformanceObserver((list) => list
|
|
141
|
+
.getEntries().map((entry) => navigate(document.referrer, entry.type)))
|
|
142
|
+
.observe({ type: 'navigation', buffered: true });
|
|
143
|
+
|
|
144
|
+
const leave = ((event) => {
|
|
145
|
+
if (leave.left || (event.type === 'visibilitychange' && document.visibilityState !== 'hidden')) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
leave.left = true;
|
|
149
|
+
sampleRUM('leave');
|
|
150
|
+
});
|
|
151
|
+
window.addEventListener('visibilitychange', ((event) => leave(event)));
|
|
152
|
+
window.addEventListener('pagehide', ((event) => leave(event)));
|
|
153
|
+
}
|
|
146
154
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
155
|
+
function addLoadResourceTracking() {
|
|
156
|
+
const observer = new PerformanceObserver((list) => {
|
|
157
|
+
list.getEntries()
|
|
158
|
+
.filter((entry) => !entry.responseStatus || entry.responseStatus < 400)
|
|
159
|
+
.filter((entry) => window.location.hostname === new URL(entry.name).hostname)
|
|
160
|
+
.filter((entry) => new URL(entry.name).pathname.match('.*(\\.plain\\.html|\\.json)$'))
|
|
161
|
+
.forEach((entry) => {
|
|
162
|
+
sampleRUM('loadresource', { source: entry.name, target: Math.round(entry.duration) });
|
|
163
|
+
});
|
|
151
164
|
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
.
|
|
162
|
-
|
|
163
|
-
|
|
165
|
+
observer.observe({ type: 'resource', buffered: true });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function activateBlocksMutationObserver() {
|
|
169
|
+
if (!mutationObserver || mutationObserver.active) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
mutationObserver.active = true;
|
|
173
|
+
mutationObserver.observe(
|
|
174
|
+
document.body,
|
|
175
|
+
// eslint-disable-next-line object-curly-newline
|
|
176
|
+
{ subtree: true, attributes: true, attributeFilter: ['data-block-status'] },
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function getIntersectionObsever(checkpoint) {
|
|
181
|
+
if (!window.IntersectionObserver) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
activateBlocksMutationObserver();
|
|
185
|
+
const observer = new IntersectionObserver((entries) => {
|
|
186
|
+
entries
|
|
187
|
+
.filter((entry) => entry.isIntersecting)
|
|
188
|
+
.forEach((entry) => {
|
|
189
|
+
observer.unobserve(entry.target); // observe only once
|
|
190
|
+
const target = targetselector(entry.target);
|
|
191
|
+
const source = sourceselector(entry.target);
|
|
192
|
+
sampleRUM(checkpoint, { target, source });
|
|
193
|
+
});
|
|
194
|
+
}, { threshold: 0.25 });
|
|
195
|
+
return observer;
|
|
196
|
+
}
|
|
197
|
+
function addViewBlockTracking(element) {
|
|
198
|
+
const blockobserver = getIntersectionObsever('viewblock');
|
|
199
|
+
if (blockobserver) {
|
|
200
|
+
const blocks = element.getAttribute('data-block-status') ? [element] : element.querySelectorAll('div[data-block-status="loaded"]');
|
|
201
|
+
blocks.forEach((b) => blockobserver.observe(b));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function addViewMediaTracking(parent) {
|
|
206
|
+
const mediaobserver = getIntersectionObsever('viewmedia');
|
|
207
|
+
if (mediaobserver) {
|
|
208
|
+
parent.querySelectorAll('picture > img, video, audio, iframe').forEach((m) => {
|
|
209
|
+
if (!m.closest('div .block') || m.closest('div[data-block-status="loaded"]')) {
|
|
210
|
+
mediaobserver.observe(m);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function addFormTracking(parent) {
|
|
217
|
+
activateBlocksMutationObserver();
|
|
218
|
+
parent.querySelectorAll('form').forEach((form) => {
|
|
219
|
+
form.removeEventListener('submit', formSubmitListener); // listen only once
|
|
220
|
+
form.addEventListener('submit', formSubmitListener);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const addObserver = (ck, fn, block) => getCollectionConfig().includes(ck) && fn(block);
|
|
225
|
+
function mutationsCallback(mutations) {
|
|
226
|
+
mutations.filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status')
|
|
227
|
+
.filter((m) => m.target.dataset.blockStatus === 'loaded')
|
|
228
|
+
.forEach((m) => {
|
|
229
|
+
addObserver('form', addFormTracking, m.target);
|
|
230
|
+
addObserver('viewblock', addViewBlockTracking, m.target);
|
|
231
|
+
addObserver('viewmedia', addViewMediaTracking, m.target);
|
|
164
232
|
});
|
|
165
|
-
}
|
|
166
|
-
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function addTrackingFromConfig() {
|
|
236
|
+
const trackingFunctions = {
|
|
237
|
+
click: () => {
|
|
238
|
+
document.addEventListener('click', (event) => {
|
|
239
|
+
sampleRUM('click', { target: targetselector(event.target), source: sourceselector(event.target) });
|
|
240
|
+
});
|
|
241
|
+
},
|
|
242
|
+
cwv: () => addCWVTracking(),
|
|
243
|
+
form: () => addFormTracking(window.document.body),
|
|
244
|
+
enterleave: () => addEnterLeaveTracking(),
|
|
245
|
+
loadresource: () => addLoadResourceTracking(),
|
|
246
|
+
viewblock: () => addViewBlockTracking(window.document.body),
|
|
247
|
+
viewmedia: () => addViewMediaTracking(window.document.body),
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
getCollectionConfig().filter((ck) => trackingFunctions[ck])
|
|
251
|
+
.forEach((ck) => trackingFunctions[ck]());
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function initEnhancer() {
|
|
255
|
+
// eslint-disable-next-line max-len
|
|
256
|
+
const rumStorage = sessionStorage.getItem(SESSION_STORAGE_KEY) ? JSON.parse(sessionStorage.getItem(SESSION_STORAGE_KEY)) : {};
|
|
257
|
+
sampleRUM('pagesviewed', { source: rumStorage.pages });
|
|
258
|
+
addTrackingFromConfig();
|
|
259
|
+
window.hlx.rum.collector = trackCheckpoint;
|
|
260
|
+
processQueue();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
initEnhancer();
|