|
11 | 11 | */
|
12 | 12 |
|
13 | 13 | /* eslint-env browser */
|
14 |
| - |
15 |
| -/** |
16 |
| - * log RUM if part of the sample. |
17 |
| - * @param {string} checkpoint identifies the checkpoint in funnel |
18 |
| - * @param {Object} data additional data for RUM sample |
19 |
| - * @param {string} data.source DOM node that is the source of a checkpoint event, |
20 |
| - * identified by #id or .classname |
21 |
| - * @param {string} data.target subject of the checkpoint event, |
22 |
| - * for instance the href of a link, or a search term |
23 |
| - */ |
24 |
| -function sampleRUM(checkpoint, data = {}) { |
| 14 | +function sampleRUM(checkpoint, data) { |
| 15 | + // eslint-disable-next-line max-len |
| 16 | + const timeShift = () => (window.performance ? window.performance.now() : Date.now() - window.hlx.rum.firstReadTime); |
25 | 17 | const SESSION_STORAGE_KEY = 'aem-rum';
|
26 |
| - sampleRUM.baseURL = sampleRUM.baseURL |
27 |
| - || new URL(window.RUM_BASE == null ? 'https://rum.hlx.page' : window.RUM_BASE, window.location); |
28 |
| - sampleRUM.defer = sampleRUM.defer || []; |
29 |
| - const defer = (fnname) => { |
30 |
| - sampleRUM[fnname] = sampleRUM[fnname] || ((...args) => sampleRUM.defer.push({ fnname, args })); |
31 |
| - }; |
32 |
| - sampleRUM.drain = sampleRUM.drain |
33 |
| - || ((dfnname, fn) => { |
34 |
| - sampleRUM[dfnname] = fn; |
35 |
| - sampleRUM.defer |
36 |
| - .filter(({ fnname }) => dfnname === fnname) |
37 |
| - .forEach(({ fnname, args }) => sampleRUM[fnname](...args)); |
38 |
| - }); |
39 |
| - sampleRUM.always = sampleRUM.always || []; |
40 |
| - sampleRUM.always.on = (chkpnt, fn) => { |
41 |
| - sampleRUM.always[chkpnt] = fn; |
42 |
| - }; |
43 |
| - sampleRUM.on = (chkpnt, fn) => { |
44 |
| - sampleRUM.cases[chkpnt] = fn; |
45 |
| - }; |
46 |
| - defer('observe'); |
47 |
| - defer('cwv'); |
48 | 18 | try {
|
49 | 19 | window.hlx = window.hlx || {};
|
50 | 20 | if (!window.hlx.rum) {
|
51 |
| - const usp = new URLSearchParams(window.location.search); |
52 |
| - const weight = usp.get('rum') === 'on' ? 1 : 100; // with parameter, weight is 1. Defaults to 100. |
| 21 | + // eslint-disable-next-line max-len |
| 22 | + const rumStorage = sessionStorage.getItem(SESSION_STORAGE_KEY) |
| 23 | + ? JSON.parse(sessionStorage.getItem(SESSION_STORAGE_KEY)) |
| 24 | + : {}; |
| 25 | + rumStorage.pages = (rumStorage.pages ?? 0) + (Math.floor(Math.random() * 20) - 10) + 1; |
| 26 | + sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(rumStorage)); |
| 27 | + sampleRUM.baseURL = sampleRUM.baseURL |
| 28 | + || new URL( |
| 29 | + window.RUM_BASE == null ? 'https://rum.hlx.page' : window.RUM_BASE, |
| 30 | + window.location, |
| 31 | + ); |
| 32 | + const weight = new URLSearchParams(window.location.search).get('rum') === 'on' ? 1 : 100; |
53 | 33 | const id = Array.from({ length: 75 }, (_, i) => String.fromCharCode(48 + i))
|
54 | 34 | .filter((a) => /\d|[A-Z]/i.test(a))
|
55 | 35 | .filter(() => Math.random() * 75 > 70)
|
56 | 36 | .join('');
|
57 |
| - const random = Math.random(); |
58 |
| - const isSelected = random * weight < 1; |
59 |
| - const firstReadTime = window.performance ? window.performance.timeOrigin : Date.now(); |
60 |
| - const urlSanitizers = { |
61 |
| - full: () => window.location.href, |
62 |
| - origin: () => window.location.origin, |
63 |
| - path: () => window.location.href.replace(/\?.*$/, ''), |
64 |
| - }; |
65 |
| - // eslint-disable-next-line max-len |
66 |
| - const rumSessionStorage = sessionStorage.getItem(SESSION_STORAGE_KEY) |
67 |
| - ? JSON.parse(sessionStorage.getItem(SESSION_STORAGE_KEY)) |
68 |
| - : {}; |
69 |
| - // eslint-disable-next-line max-len |
70 |
| - rumSessionStorage.pages = (rumSessionStorage.pages ? rumSessionStorage.pages : 0) |
71 |
| - + 1 |
72 |
| - /* noise */ + (Math.floor(Math.random() * 20) - 10); |
73 |
| - sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(rumSessionStorage)); |
| 37 | + const isSelected = Math.random() * weight < 1; |
74 | 38 | // eslint-disable-next-line object-curly-newline, max-len
|
75 | 39 | window.hlx.rum = {
|
76 | 40 | weight,
|
77 | 41 | id,
|
78 |
| - random, |
79 | 42 | isSelected,
|
80 |
| - firstReadTime, |
| 43 | + firstReadTime: window.performance ? window.performance.timeOrigin : Date.now(), |
81 | 44 | sampleRUM,
|
82 |
| - sanitizeURL: urlSanitizers[window.hlx.RUM_MASK_URL || 'path'], |
83 |
| - rumSessionStorage, |
| 45 | + queue: [], |
| 46 | + collector: (...args) => window.hlx.rum.queue.push(args), |
84 | 47 | };
|
85 |
| - } |
86 |
| - |
87 |
| - const { weight, id, firstReadTime } = window.hlx.rum; |
88 |
| - if (window.hlx && window.hlx.rum && window.hlx.rum.isSelected) { |
89 |
| - const knownProperties = [ |
90 |
| - 'weight', |
91 |
| - 'id', |
92 |
| - 'referer', |
93 |
| - 'checkpoint', |
94 |
| - 't', |
95 |
| - 'source', |
96 |
| - 'target', |
97 |
| - 'cwv', |
98 |
| - 'CLS', |
99 |
| - 'FID', |
100 |
| - 'LCP', |
101 |
| - 'INP', |
102 |
| - 'TTFB', |
103 |
| - ]; |
104 |
| - const sendPing = (pdata = data) => { |
105 |
| - // eslint-disable-next-line max-len |
106 |
| - const t = Math.round( |
107 |
| - window.performance ? window.performance.now() : Date.now() - firstReadTime, |
108 |
| - ); |
109 |
| - // eslint-disable-next-line object-curly-newline, max-len, no-use-before-define |
110 |
| - const body = JSON.stringify( |
111 |
| - { |
112 |
| - weight, id, referer: window.hlx.rum.sanitizeURL(), checkpoint, t, ...data, |
113 |
| - }, |
114 |
| - knownProperties, |
115 |
| - ); |
| 48 | + if (isSelected) { |
| 49 | + // eslint-disable-next-line object-curly-newline, max-len |
| 50 | + const body = JSON.stringify({ |
| 51 | + weight, |
| 52 | + id, |
| 53 | + referer: window.location.href, |
| 54 | + checkpoint: 'top', |
| 55 | + t: timeShift(), |
| 56 | + target: document.visibilityState, |
| 57 | + }); |
116 | 58 | const url = new URL(`.rum/${weight}`, sampleRUM.baseURL).href;
|
117 | 59 | navigator.sendBeacon(url, body);
|
118 |
| - // eslint-disable-next-line no-console |
119 |
| - console.debug(`ping:${checkpoint}`, pdata); |
120 |
| - }; |
121 |
| - sampleRUM.cases = sampleRUM.cases || { |
122 |
| - load: () => sampleRUM('pagesviewed', { source: window.hlx.rum.rumSessionStorage.pages }) || true, |
123 |
| - cwv: () => sampleRUM.cwv(data) || true, |
124 |
| - lazy: () => { |
125 |
| - // use classic script to avoid CORS issues |
126 |
| - const script = document.createElement('script'); |
127 |
| - script.src = new URL( |
128 |
| - '.rum/@adobe/helix-rum-enhancer@^1/src/index.js', |
129 |
| - sampleRUM.baseURL, |
130 |
| - ).href; |
131 |
| - document.head.appendChild(script); |
132 |
| - return true; |
133 |
| - }, |
134 |
| - }; |
135 |
| - sendPing(data); |
136 |
| - if (sampleRUM.cases[checkpoint]) { |
137 |
| - sampleRUM.cases[checkpoint](); |
| 60 | + // eslint-disable-next-line max-statements-per-line, brace-style |
| 61 | + window.addEventListener('load', () => { |
| 62 | + sampleRUM('load'); |
| 63 | + import(new URL('.rum/@adobe/helix-rum-enhancer@^2/src/index.js', sampleRUM.baseURL)); |
| 64 | + }); |
138 | 65 | }
|
139 | 66 | }
|
140 |
| - if (sampleRUM.always[checkpoint]) { |
141 |
| - sampleRUM.always[checkpoint](data); |
| 67 | + if (window.hlx.rum && window.hlx.rum.isSelected && checkpoint) { |
| 68 | + window.hlx.rum.collector(checkpoint, data, timeShift()); |
142 | 69 | }
|
| 70 | + document.dispatchEvent(new CustomEvent('rum', { detail: { checkpoint, data } })); |
143 | 71 | } catch (error) {
|
144 | 72 | // something went wrong
|
145 | 73 | }
|
@@ -372,6 +300,48 @@ function decorateTemplateAndTheme() {
|
372 | 300 | if (theme) addClasses(document.body, theme);
|
373 | 301 | }
|
374 | 302 |
|
| 303 | +/** |
| 304 | + * Wrap inline text content of block cells within a <p> tag. |
| 305 | + * @param {Element} block the block element |
| 306 | + */ |
| 307 | +function wrapTextNodes(block) { |
| 308 | + const validWrappers = [ |
| 309 | + 'P', |
| 310 | + 'PRE', |
| 311 | + 'UL', |
| 312 | + 'OL', |
| 313 | + 'PICTURE', |
| 314 | + 'TABLE', |
| 315 | + 'H1', |
| 316 | + 'H2', |
| 317 | + 'H3', |
| 318 | + 'H4', |
| 319 | + 'H5', |
| 320 | + 'H6', |
| 321 | + ]; |
| 322 | + |
| 323 | + const wrap = (el) => { |
| 324 | + const wrapper = document.createElement('p'); |
| 325 | + wrapper.append(...el.childNodes); |
| 326 | + el.append(wrapper); |
| 327 | + }; |
| 328 | + |
| 329 | + block.querySelectorAll(':scope > div > div').forEach((blockColumn) => { |
| 330 | + if (blockColumn.hasChildNodes()) { |
| 331 | + const hasWrapper = !!blockColumn.firstElementChild |
| 332 | + && validWrappers.some((tagName) => blockColumn.firstElementChild.tagName === tagName); |
| 333 | + if (!hasWrapper) { |
| 334 | + wrap(blockColumn); |
| 335 | + } else if ( |
| 336 | + blockColumn.firstElementChild.tagName === 'PICTURE' |
| 337 | + && (blockColumn.children.length > 1 || !!blockColumn.textContent.trim()) |
| 338 | + ) { |
| 339 | + wrap(blockColumn); |
| 340 | + } |
| 341 | + } |
| 342 | + }); |
| 343 | +} |
| 344 | + |
375 | 345 | /**
|
376 | 346 | * Decorates paragraphs containing a single link as buttons.
|
377 | 347 | * @param {Element} element container element
|
@@ -635,6 +605,7 @@ function decorateBlock(block) {
|
635 | 605 | block.classList.add('block');
|
636 | 606 | block.dataset.blockName = shortBlockName;
|
637 | 607 | block.dataset.blockStatus = 'initialized';
|
| 608 | + wrapTextNodes(block); |
638 | 609 | const blockWrapper = block.parentElement;
|
639 | 610 | blockWrapper.classList.add(`${shortBlockName}-wrapper`);
|
640 | 611 | const section = block.closest('.section');
|
@@ -723,4 +694,5 @@ export {
|
723 | 694 | toClassName,
|
724 | 695 | updateSectionsStatus,
|
725 | 696 | waitForLCP,
|
| 697 | + wrapTextNodes, |
726 | 698 | };
|
0 commit comments