@adobe/helix-rum-enhancer
Advanced tools
Comparing version 2.20.0 to 2.21.0
@@ -0,1 +1,16 @@ | ||
# [2.21.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.20.0...v2.21.0) (2024-09-18) | ||
### Bug Fixes | ||
* **dom:** apply change ([67803e6](https://github.com/adobe/helix-rum-enhancer/commit/67803e60f57ef29b9ea1c51eea26d99c778b5f97)) | ||
* **dom:** better handling of empty type form inputs ([d53deb5](https://github.com/adobe/helix-rum-enhancer/commit/d53deb5c6e94ff18df2a01996c39b5cff7636fe4)) | ||
* **dom:** better handling of fake blocks ([66a9049](https://github.com/adobe/helix-rum-enhancer/commit/66a90497a45d754ed0fa4e8f8bc0917be64b3245)) | ||
### Features | ||
* **checkpoints:** add support for the `language` checkpoint ([f99755a](https://github.com/adobe/helix-rum-enhancer/commit/f99755a5cc8eef83b655a6beff5e7e371196c90d)) | ||
* **dom:** more fine-grained sourceselector implementation ([ada279d](https://github.com/adobe/helix-rum-enhancer/commit/ada279d423590fb3feeb304b3a57d6da4ee3c9bf)) | ||
# [2.20.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.19.2...v2.20.0) (2024-08-19) | ||
@@ -2,0 +17,0 @@ |
@@ -33,2 +33,55 @@ /* | ||
function walk(element, checkFn) { | ||
if (!element || element === document.body || element === document.documentElement) { | ||
return undefined; | ||
} | ||
const checkValue = checkFn(element); | ||
return checkValue || walk(element.parentElement, checkFn); | ||
} | ||
function isDialog(element) { | ||
// doing it well | ||
if (element.tagName === 'DIALOG') return true; | ||
// making the best of it | ||
if (element.getAttribute('role') === 'dialog') return true; | ||
if (element.getAttribute('role') === 'alertdialog') return true; | ||
if (element.getAttribute('aria-modal') === 'true') return true; | ||
// doing it wrong | ||
const computedStyle = window.getComputedStyle(element); | ||
return (computedStyle && computedStyle.position === 'fixed' && computedStyle.zIndex > 100); | ||
} | ||
function isButton(element) { | ||
if (element.tagName === 'BUTTON') return true; | ||
if (element.tagName === 'INPUT' && element.getAttribute('type') === 'button') return true; | ||
if (element.tagName === 'A') { | ||
const classes = Array.from(element.classList); | ||
return classes.some((className) => className.match(/button|cta/)); | ||
} | ||
return element.getAttribute('role') === 'button'; | ||
} | ||
function getSourceContext(element) { | ||
if (element.closest('form')) return 'form'; | ||
const block = element.closest('.block[data-block-name]'); | ||
if (block) return `.${block.getAttribute('data-block-name')}`; | ||
if (walk(element, isDialog)) return 'dialog'; | ||
if (element.closest('nav')) return 'nav'; | ||
if (element.closest('header')) return 'header'; | ||
if (element.closest('footer')) return 'footer'; | ||
if (element.closest('aside')) return 'aside'; | ||
return (walk(element, (e) => e.id && `#${e.id}`)); | ||
} | ||
function getSourceElement(element) { | ||
if (element.closest('form') && Array.from(element.closest('form').elements).includes(element)) return element.tagName.toLowerCase() + (element.tagName === 'INPUT' ? `[type='${element.getAttribute('type') || ''}']` : ''); | ||
if (walk(element, isButton)) return 'button'; | ||
return element.tagName.toLowerCase().match(/^(a|img|video)$/) && element.tagName.toLowerCase(); | ||
} | ||
function getSourceIdentifier(element) { | ||
if (element.id) return `#${element.id}`; | ||
if (element.getAttribute('data-block-name')) return `.${element.getAttribute('data-block-name')}`; | ||
return (element.classList.length > 0 && `.${element.classList[0]}`); | ||
} | ||
export const sourceSelector = (element) => { | ||
@@ -42,37 +95,6 @@ try { | ||
} | ||
const form = element.closest('form'); | ||
let formElementSelector = ''; | ||
if (form && Array.from(form.elements).includes(element)) { | ||
formElementSelector = element.tagName === 'INPUT' ? `form input[type='${element.getAttribute('type')}']` : `form ${element.tagName.toLowerCase()}`; | ||
} | ||
const blockName = element.closest('.block') ? element.closest('.block').getAttribute('data-block-name') : ''; | ||
if (element.id || formElementSelector) { | ||
const id = element.id ? `#${element.id}` : ''; | ||
return blockName ? `.${blockName} ${formElementSelector}${id}` : `${formElementSelector}${id}`; | ||
} | ||
if (element.getAttribute('data-block-name')) { | ||
return `.${element.getAttribute('data-block-name')}`; | ||
} | ||
const classes = Array.from(element.classList); | ||
const label = element.tagName.toLowerCase(); | ||
const firstClass = classes.length > 0 ? `.${classes[0]}` : ''; | ||
const labelWithClass = `${element.tagName.toLowerCase()}${firstClass}`; | ||
if (element.tagName.toLowerCase() === 'button' | ||
|| element.type === 'button' | ||
|| classes.some((className) => className.match(/button|cta/))) { | ||
let parent = element.parentElement; | ||
if (!parent) return labelWithClass; | ||
if (parent.id) return `#${parent.id} ${label}`; | ||
while (parent.tagName !== 'BODY' && !parent.id) parent = parent.parentElement; | ||
if (parent.id) return `#${parent.id} ${labelWithClass}`; | ||
return blockName ? `.${blockName} ${labelWithClass}` : labelWithClass; | ||
} | ||
const parent = sourceSelector(element.parentElement); | ||
if (parent) return parent; | ||
return labelWithClass; | ||
const context = getSourceContext(element.parentElement) || ''; | ||
const elementName = getSourceElement(element) || ''; | ||
const identifier = getSourceIdentifier(element) || ''; | ||
return `${context} ${elementName}${identifier}`.trim() || `"${element.textContent.substring(0, 10)}"`; | ||
/* c8 ignore next 3 */ | ||
@@ -79,0 +101,0 @@ } catch (error) { |
@@ -22,2 +22,3 @@ /* | ||
example: [543, 770, 1136], | ||
language: [543, 959, 1139, 620], | ||
}; |
@@ -270,2 +270,7 @@ /* | ||
addEmailParameterTracking(sampleRUM); | ||
fflags.enabled('language', () => { | ||
const target = navigator.language; | ||
const source = document.documentElement.lang; | ||
sampleRUM('language', { source, target }); | ||
}); | ||
} | ||
@@ -272,0 +277,0 @@ |
{ | ||
"name": "@adobe/helix-rum-enhancer", | ||
"version": "2.20.0", | ||
"version": "2.21.0", | ||
"description": "Helix RUM Enhancer", | ||
@@ -36,4 +36,4 @@ "main": "src/index.js", | ||
"devDependencies": { | ||
"@adobe/eslint-config-helix": "2.0.6", | ||
"@adobe/helix-rum-js": "2.2.0", | ||
"@adobe/eslint-config-helix": "2.0.7", | ||
"@adobe/helix-rum-js": "2.4.0", | ||
"@esm-bundle/chai": "4.3.4-fix.0", | ||
@@ -51,11 +51,12 @@ "@semantic-release/changelog": "6.0.3", | ||
"eslint-plugin-header": "3.1.1", | ||
"eslint-plugin-import": "2.29.1", | ||
"husky": "9.1.4", | ||
"jsdoc-to-markdown": "8.0.3", | ||
"eslint-plugin-import": "2.30.0", | ||
"husky": "9.1.5", | ||
"jsdoc-to-markdown": "9.0.0", | ||
"junit-report-builder": "5.0.0", | ||
"lint-staged": "15.2.9", | ||
"lint-staged": "15.2.10", | ||
"mocha": "10.7.3", | ||
"mocha-multi-reporters": "1.5.1", | ||
"rollup": "4.20.0", | ||
"rollup": "4.21.2", | ||
"rollup-plugin-cleanup": "3.2.1", | ||
"rollup-plugin-checksum": "1.0.1", | ||
"rollup-plugin-eslint-bundle": "9.0.0", | ||
@@ -62,0 +63,0 @@ "semantic-release": "24.1.0", |
@@ -26,2 +26,45 @@ # Helix RUM Enhancer | ||
### The `source` parameter and the `sourceSelector` | ||
The `source` parameter is a string that can be used to identify the source of the event. It can be used to identify the source of the event, e.g. a button, a link, a form, etc. | ||
It represents an idealized CSS selector that is both human-readable and specific enough to identify the source of the event in the document, even when not having access to the | ||
orginal document. It is idealized because it pretends the DOM would use modern HTML with concise semantics, even if the actual document uses `class` values for things that would | ||
be better represented by semantic HTML elements. | ||
The `sourceSelector` function is a function that takes a DOM element and returns a descriptive `source` parameter. If the element has a `data-rum-source` attribute, its value is used as the `source` parameter. Otherwise, the function tries to generate a `source` parameter based on the element's tag name, class names, and text content. | ||
The structure of the `source` parameter is as follows: | ||
``` | ||
<context> <element>#<identifier> | ||
``` | ||
All three parts are optional | ||
`context` is | ||
- `form` for form elements | ||
- `dialog` for dialog elements, or parent containers that are fixed positioned and have a positive high z-index | ||
- `.block-name` for Helix blocks | ||
- `header`, `footer`, `nav`, `aside` for main site structure | ||
- `#id` as a fallback, if a container ID is available | ||
`element` is | ||
- `button` for buttons, or links that look like buttons (e.g. with a class `button` or `btn` or `cta`) | ||
- `img` for images | ||
- `video` for videos | ||
- `a` for links that are not buttons | ||
- `input[type="text"]` for input elements (all types are supported) | ||
- `select`, `textarea`, etc. for other form elements | ||
`identifier` is | ||
- the `id` attribute of the element, if provided | ||
- the first `.class` if there are any | ||
- else omitted | ||
Even if an `identifier` is provided, having a `context` and `element` is recommended, as it makes the `source` parameter more readable and easier to understand. | ||
#### Examples | ||
- `` | ||
## Development | ||
@@ -28,0 +71,0 @@ |
@@ -14,4 +14,6 @@ /* | ||
import cleanup from 'rollup-plugin-cleanup'; | ||
import eslint from 'rollup-plugin-eslint-bundle'; | ||
import pkg from 'rollup-plugin-checksum'; | ||
const checksum = pkg.default; | ||
const banner = `/* | ||
@@ -27,7 +29,4 @@ * Copyright 2024 Adobe. All rights reserved. | ||
* governing permissions and limitations under the License. | ||
*/ | ||
*/`; | ||
/* eslint-disable max-classes-per-file, wrap-iife */ | ||
// eslint-disable-next-line func-names`; | ||
const bundles = [ | ||
@@ -60,11 +59,10 @@ { | ||
cleanup({ | ||
comments: ['eslint', 'jsdoc', /^\//, /^\*(?!\sc8\s)(?!\n \* Copyright)/], | ||
maxEmptyLines: -1, | ||
comments: [], | ||
maxEmptyLines: 0, | ||
}), | ||
eslint({ | ||
eslintOptions: { | ||
fix: true, | ||
}, | ||
checksum({ | ||
filename: `${outputFile.split('/').pop()}.md5`, | ||
includeAssets: false, | ||
}), | ||
], | ||
}))]; |
182
src/index.js
@@ -12,5 +12,2 @@ /* | ||
*/ | ||
/* eslint-disable max-classes-per-file, wrap-iife */ | ||
// eslint-disable-next-line func-names | ||
(function () { | ||
@@ -25,6 +22,6 @@ 'use strict'; | ||
enabled: (flag, callback) => fflags.has(flag) && callback(), | ||
disabled: (flag, callback) => !fflags.has(flag) && callback(), | ||
eagercwv: [683], | ||
example: [543, 770, 1136], | ||
language: [543, 959, 1139, 620], | ||
}; | ||
@@ -37,22 +34,4 @@ | ||
const urlSanitizers = { | ||
/** | ||
* Returns the full url. | ||
* If no url is provided, it defaults to window.location.href. | ||
* @param {string} url (default: window.location.href) The url to sanitize | ||
* @returns {string} The sanitized url | ||
*/ | ||
full: (url = window.location.href) => new URL(url).toString(), | ||
/** | ||
* Returns the origin of the provided url. | ||
* If no url is provided, it defaults to window.location.href. | ||
* @param {string} url (default: window.location.href) The url to sanitize | ||
* @returns {string} The sanitized url | ||
*/ | ||
origin: (url = window.location.href) => new URL(url).origin, | ||
/** | ||
* Returns the sanitized url: the origin and the path (no query params or hash) | ||
* If no url is provided, it defaults to window.location.href. | ||
* @param {string} url (default: window.location.href) The url to sanitize | ||
* @returns {string} The sanitized url | ||
*/ | ||
path: (url = window.location.href) => { | ||
@@ -66,3 +45,2 @@ const u = new URL(url); | ||
|| element.currentSrc || element.getAttribute('src') || element.dataset.action || element.action; | ||
const targetSelector = (element) => { | ||
@@ -76,3 +54,2 @@ try { | ||
if (value && !value.startsWith('https://')) { | ||
// resolve relative links | ||
value = new URL(value, window.location).href; | ||
@@ -85,3 +62,47 @@ } | ||
}; | ||
function walk(element, checkFn) { | ||
if (!element || element === document.body || element === document.documentElement) { | ||
return undefined; | ||
} | ||
const checkValue = checkFn(element); | ||
return checkValue || walk(element.parentElement, checkFn); | ||
} | ||
function isDialog(element) { | ||
if (element.tagName === 'DIALOG') return true; | ||
if (element.getAttribute('role') === 'dialog') return true; | ||
if (element.getAttribute('role') === 'alertdialog') return true; | ||
if (element.getAttribute('aria-modal') === 'true') return true; | ||
const computedStyle = window.getComputedStyle(element); | ||
return (computedStyle && computedStyle.position === 'fixed' && computedStyle.zIndex > 100); | ||
} | ||
function isButton(element) { | ||
if (element.tagName === 'BUTTON') return true; | ||
if (element.tagName === 'INPUT' && element.getAttribute('type') === 'button') return true; | ||
if (element.tagName === 'A') { | ||
const classes = Array.from(element.classList); | ||
return classes.some((className) => className.match(/button|cta/)); | ||
} | ||
return element.getAttribute('role') === 'button'; | ||
} | ||
function getSourceContext(element) { | ||
if (element.closest('form')) return 'form'; | ||
const block = element.closest('.block[data-block-name]'); | ||
if (block) return `.${block.getAttribute('data-block-name')}`; | ||
if (walk(element, isDialog)) return 'dialog'; | ||
if (element.closest('nav')) return 'nav'; | ||
if (element.closest('header')) return 'header'; | ||
if (element.closest('footer')) return 'footer'; | ||
if (element.closest('aside')) return 'aside'; | ||
return (walk(element, (e) => e.id && `#${e.id}`)); | ||
} | ||
function getSourceElement(element) { | ||
if (element.closest('form') && Array.from(element.closest('form').elements).includes(element)) return element.tagName.toLowerCase() + (element.tagName === 'INPUT' ? `[type='${element.getAttribute('type') || ''}']` : ''); | ||
if (walk(element, isButton)) return 'button'; | ||
return element.tagName.toLowerCase().match(/^(a|img|video)$/) && element.tagName.toLowerCase(); | ||
} | ||
function getSourceIdentifier(element) { | ||
if (element.id) return `#${element.id}`; | ||
if (element.getAttribute('data-block-name')) return `.${element.getAttribute('data-block-name')}`; | ||
return (element.classList.length > 0 && `.${element.classList[0]}`); | ||
} | ||
const sourceSelector = (element) => { | ||
@@ -95,37 +116,6 @@ try { | ||
} | ||
const form = element.closest('form'); | ||
let formElementSelector = ''; | ||
if (form && Array.from(form.elements).includes(element)) { | ||
formElementSelector = element.tagName === 'INPUT' ? `form input[type='${element.getAttribute('type')}']` : `form ${element.tagName.toLowerCase()}`; | ||
} | ||
const blockName = element.closest('.block') ? element.closest('.block').getAttribute('data-block-name') : ''; | ||
if (element.id || formElementSelector) { | ||
const id = element.id ? `#${element.id}` : ''; | ||
return blockName ? `.${blockName} ${formElementSelector}${id}` : `${formElementSelector}${id}`; | ||
} | ||
if (element.getAttribute('data-block-name')) { | ||
return `.${element.getAttribute('data-block-name')}`; | ||
} | ||
const classes = Array.from(element.classList); | ||
const label = element.tagName.toLowerCase(); | ||
const firstClass = classes.length > 0 ? `.${classes[0]}` : ''; | ||
const labelWithClass = `${element.tagName.toLowerCase()}${firstClass}`; | ||
if (element.tagName.toLowerCase() === 'button' | ||
|| element.type === 'button' | ||
|| classes.some((className) => className.match(/button|cta/))) { | ||
let parent = element.parentElement; | ||
if (!parent) return labelWithClass; | ||
if (parent.id) return `#${parent.id} ${label}`; | ||
while (parent.tagName !== 'BODY' && !parent.id) parent = parent.parentElement; | ||
if (parent.id) return `#${parent.id} ${labelWithClass}`; | ||
return blockName ? `.${blockName} ${labelWithClass}` : labelWithClass; | ||
} | ||
const parent = sourceSelector(element.parentElement); | ||
if (parent) return parent; | ||
return labelWithClass; | ||
const context = getSourceContext(element.parentElement) || ''; | ||
const elementName = getSourceElement(element) || ''; | ||
const identifier = getSourceIdentifier(element) || ''; | ||
return `${context} ${elementName}${identifier}`.trim() || `"${element.textContent.substring(0, 10)}"`; | ||
} catch (error) { | ||
@@ -140,3 +130,2 @@ return null; | ||
.find((cookie) => cookie.startsWith('OptanonAlertBoxClosed=')); | ||
if (cmpCookie) { | ||
@@ -146,3 +135,2 @@ sampleRUM('consent', { source: 'onetrust', target: 'hidden' }); | ||
} | ||
let consentMutationObserver; | ||
@@ -159,12 +147,9 @@ const trackShowConsent = () => { | ||
}; | ||
if (!trackShowConsent()) { | ||
// eslint-disable-next-line max-len | ||
consentMutationObserver = window.MutationObserver | ||
? new MutationObserver(trackShowConsent) | ||
: null; | ||
: null; | ||
if (consentMutationObserver) { | ||
consentMutationObserver.observe( | ||
document.body, | ||
// eslint-disable-next-line object-curly-newline | ||
{ attributes: false, childList: true, subtree: false }, | ||
@@ -175,3 +160,2 @@ ); | ||
} | ||
function addUTMParametersTracking(sampleRUM) { | ||
@@ -181,3 +165,2 @@ const usp = new URLSearchParams(window.location.search); | ||
.filter(([key]) => key.startsWith('utm_')) | ||
// exclude keys that may leak PII | ||
.filter(([key]) => key !== 'utm_id') | ||
@@ -215,14 +198,8 @@ .filter(([key]) => key !== 'utm_term') | ||
const { sampleRUM, queue, isSelected } = (window.hlx && window.hlx.rum) ? window.hlx.rum | ||
: {}; | ||
: {}; | ||
const formSubmitListener = (e) => sampleRUM('formsubmit', { target: targetSelector(e.target), source: sourceSelector(e.target) }); | ||
// eslint-disable-next-line no-use-before-define, max-len | ||
const blocksMutationObserver = window.MutationObserver ? new MutationObserver(blocksMutationsCallback) | ||
: {}; | ||
// eslint-disable-next-line no-use-before-define, max-len | ||
: {}; | ||
const mediaMutationObserver = window.MutationObserver ? new MutationObserver(mediaMutationsCallback) | ||
: {}; | ||
: {}; | ||
function trackCheckpoint(checkpoint, data, t) { | ||
@@ -232,3 +209,2 @@ const { weight, id } = window.hlx.rum; | ||
const sendPing = (pdata = data) => { | ||
// eslint-disable-next-line object-curly-newline, max-len | ||
const body = JSON.stringify({ weight, id, referer: urlSanitizers[window.hlx.RUM_MASK_URL || 'path'](), checkpoint, t, ...data }, KNOWN_PROPERTIES); | ||
@@ -242,3 +218,2 @@ const { href: url, origin } = new URL(`.rum/${weight}`, sampleRUM.collectBaseURL || sampleRUM.baseURL); | ||
} | ||
// eslint-disable-next-line no-console | ||
console.debug(`ping:${checkpoint}`, pdata); | ||
@@ -249,3 +224,2 @@ }; | ||
} | ||
function processQueue() { | ||
@@ -257,3 +231,2 @@ while (queue && queue.length) { | ||
} | ||
function addCWVTracking() { | ||
@@ -264,3 +237,2 @@ setTimeout(() => { | ||
if (document.querySelector(`script[src="${cwvScript}"]`)) { | ||
// web vitals script has been loaded already | ||
return; | ||
@@ -281,7 +253,3 @@ } | ||
}; | ||
const isEager = (metric) => ['CLS', 'LCP'].includes(metric); | ||
// When loading `web-vitals` using a classic script, all the public | ||
// methods can be found on the `webVitals` global namespace. | ||
['FID', 'INP', 'TTFB', 'CLS', 'LCP'].forEach((metric) => { | ||
@@ -300,23 +268,18 @@ const metricFn = window.webVitals[`on${metric}`]; | ||
} catch (error) { | ||
// something went wrong | ||
} | ||
}, 2000); // wait for delayed | ||
}, 2000); | ||
} | ||
function addNavigationTracking() { | ||
// enter checkpoint when referrer is not the current page url | ||
const navigate = (source, type) => { | ||
const payload = { source, target: document.visibilityState }; | ||
// reload: same page, navigate: same origin, enter: everything else | ||
if (type === 'reload' || source === window.location.href) { | ||
sampleRUM('reload', payload); | ||
} else if (type && type !== 'navigate') { | ||
sampleRUM(type, payload); // back, forward, prerender, etc. | ||
sampleRUM(type, payload); | ||
} else if (source && window.location.origin === new URL(source).origin) { | ||
sampleRUM('navigate', payload); // internal navigation | ||
sampleRUM('navigate', payload); | ||
} else { | ||
sampleRUM('enter', payload); // enter site | ||
sampleRUM('enter', payload); | ||
} | ||
}; | ||
new PerformanceObserver((list) => list | ||
@@ -326,3 +289,2 @@ .getEntries().map((entry) => navigate(window.hlx.referrer || document.referrer, entry.type))) | ||
} | ||
function addLoadResourceTracking() { | ||
@@ -344,3 +306,2 @@ const observer = new PerformanceObserver((list) => { | ||
} catch (error) { | ||
// something went wrong | ||
} | ||
@@ -350,3 +311,2 @@ }); | ||
} | ||
function activateBlocksMutationObserver() { | ||
@@ -359,7 +319,5 @@ if (!blocksMutationObserver || blocksMutationObserver.active) { | ||
document.body, | ||
// eslint-disable-next-line object-curly-newline | ||
{ subtree: true, attributes: true, attributeFilter: ['data-block-status'] }, | ||
); | ||
} | ||
function activateMediaMutationObserver() { | ||
@@ -372,7 +330,5 @@ if (!mediaMutationObserver || mediaMutationObserver.active) { | ||
document.body, | ||
// eslint-disable-next-line object-curly-newline | ||
{ subtree: true, attributes: false, childList: true }, | ||
); | ||
} | ||
function getIntersectionObsever(checkpoint) { | ||
@@ -389,3 +345,3 @@ if (!window.IntersectionObserver) { | ||
.forEach((entry) => { | ||
observer.unobserve(entry.target); // observe only once | ||
observer.unobserve(entry.target); | ||
const target = targetSelector(entry.target); | ||
@@ -396,3 +352,2 @@ const source = sourceSelector(entry.target); | ||
} catch (error) { | ||
// something went wrong | ||
} | ||
@@ -409,3 +364,2 @@ }); | ||
} | ||
const observedMedia = new Set(); | ||
@@ -423,3 +377,2 @@ function addViewMediaTracking(parent) { | ||
} | ||
function addFormTracking(parent) { | ||
@@ -429,13 +382,10 @@ activateBlocksMutationObserver(); | ||
parent.querySelectorAll('form').forEach((form) => { | ||
form.removeEventListener('submit', formSubmitListener); // listen only once | ||
form.removeEventListener('submit', formSubmitListener); | ||
form.addEventListener('submit', formSubmitListener); | ||
}); | ||
} | ||
function addObserver(ck, fn, block) { | ||
return DEFAULT_TRACKING_EVENTS.includes(ck) && fn(block); | ||
} | ||
function blocksMutationsCallback(mutations) { | ||
// block specific mutations | ||
mutations | ||
@@ -449,5 +399,3 @@ .filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status') | ||
} | ||
function mediaMutationsCallback(mutations) { | ||
// media mutations | ||
mutations | ||
@@ -458,3 +406,2 @@ .forEach((m) => { | ||
} | ||
function addTrackingFromConfig() { | ||
@@ -474,4 +421,8 @@ document.addEventListener('click', (event) => { | ||
addEmailParameterTracking(sampleRUM); | ||
fflags.enabled('language', () => { | ||
const target = navigator.language; | ||
const source = document.documentElement.lang; | ||
sampleRUM('language', { source, target }); | ||
}); | ||
} | ||
function initEnhancer() { | ||
@@ -485,7 +436,6 @@ try { | ||
} catch (error) { | ||
// something went wrong | ||
} | ||
} | ||
initEnhancer(); | ||
initEnhancer(); | ||
})(); |
@@ -46,3 +46,3 @@ /* | ||
context.body = context.body | ||
.replace(/const weight.*/, 'const weight = 1;') | ||
.replace(/const weight.*/, 'const weight = 1') | ||
.replace(/navigator\.sendBeacon/g, 'fakeSendBeacon') | ||
@@ -49,0 +49,0 @@ .replace('.rum/@adobe/helix-rum-enhancer@^2/src/index.js', 'src/index.map.js'); |
Sorry, the diff of this file is not supported yet
90710
22
1112
88
27