From 5c7e030d466e98f1f617ccedb315e0402c4dedb1 Mon Sep 17 00:00:00 2001 From: Justin Edelson Date: Fri, 5 Jan 2024 12:37:01 -0500 Subject: [PATCH 1/2] feat: add viewmedia RUM events for background images --- scripts/rum-enhancements.js | 40 +++++++++++++++++++++++++++++++++++++ scripts/scripts.js | 7 +++++++ 2 files changed, 47 insertions(+) create mode 100644 scripts/rum-enhancements.js diff --git a/scripts/rum-enhancements.js b/scripts/rum-enhancements.js new file mode 100644 index 0000000..ba19af1 --- /dev/null +++ b/scripts/rum-enhancements.js @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +const { sampleRUM, isSelected } = window.hlx.rum; + +function extractBackgroundImage(element) { + const matches = /^url\("?(.+)"?\)/.exec(element.style.backgroundImage); + return matches ? matches[1] : undefined; +} + +const backgroundImageObserver = (window.IntersectionObserver) + ? new IntersectionObserver((entries, observer) => { + entries + .filter((entry) => entry.isIntersecting) + .forEach((entry) => { + observer.unobserve(entry.target); // observe only once + const target = extractBackgroundImage(entry.target); + const source = sampleRUM.sourceselector(entry.target); + if (target) { + sampleRUM('viewmedia', { target, source }); + } + }); + }, { threshold: 0.25 }) : { observe: () => { } }; + +// eslint-disable-next-line import/prefer-default-export +export function observeBackgroundImages(elements) { + if (isSelected) { + elements.forEach((element) => { + backgroundImageObserver.observe(element); + }); + } +} diff --git a/scripts/scripts.js b/scripts/scripts.js index cc9111f..d16a994 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -207,6 +207,12 @@ function initSidekick() { } } +async function customizeRUM() { + const { observeBackgroundImages } = await import('./rum-enhancements.js'); + + observeBackgroundImages(document.querySelectorAll('[style*="background-image"]')); +} + const { loadArea, setConfig } = await import(`${miloLibs}/utils/utils.js`); (async function loadPage() { @@ -220,5 +226,6 @@ const { loadArea, setConfig } = await import(`${miloLibs}/utils/utils.js`); await buildAutoBlocks(); overrideMiloBlocks(); await loadArea(); + await customizeRUM(); initSidekick(); }()); From cd0f2255d03c4141dc94a8c788d31600db2693e4 Mon Sep 17 00:00:00 2001 From: Justin Edelson Date: Fri, 5 Jan 2024 12:37:57 -0500 Subject: [PATCH 2/2] feat: add RUM viewmedia/viewblock events for dynamically loaded article cards --- scripts/rum-enhancements.js | 54 +++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/scripts/rum-enhancements.js b/scripts/rum-enhancements.js index ba19af1..4a07b24 100644 --- a/scripts/rum-enhancements.js +++ b/scripts/rum-enhancements.js @@ -38,3 +38,57 @@ export function observeBackgroundImages(elements) { }); } } + +class ArticleFeedObserver { + #feed; + + #observedElements = []; + + constructor(feed) { + this.#feed = feed; + } + + start() { + if (this.#feed.classList.contains('appear')) { + // the observer was started after the feed appeared, so observe the blocks and media now. + this.#triggerRUMObserve(); + this.#startChildMutationObserver(); + } else { + // otherwise, wait until the feed appears. + new MutationObserver((mutations, observer) => { + mutations.forEach((mutation) => { + if (mutation.type === 'attributes' && mutation.attributeName === 'class' && mutation.target.classList.contains('appear')) { + observer.disconnect(); + this.#triggerRUMObserve(); + this.#startChildMutationObserver(); + } + }); + }).observe(this.#feed, { attributes: true }); + } + } + + #triggerRUMObserve() { + const elementsToObserve = Array.from(this.#feed.querySelectorAll('.article-card, picture > img')) + .filter((element) => !this.#observedElements.includes(element)); + this.#observedElements.push(...elementsToObserve); + sampleRUM.observe(elementsToObserve); + } + + // handle dynamically added article cards by re-triggering RUM observation + // don't need to be super precise here, since we are tracking which elements + // have already been observed in #observe() + #startChildMutationObserver() { + const articleCards = this.#feed.querySelector('.article-cards'); + if (articleCards) { + new MutationObserver(() => { + this.#triggerRUMObserve(); + }).observe(articleCards, { childList: true }); + } + } +} + +if (isSelected) { + document.querySelectorAll('.article-feed').forEach((articleFeed) => { + new ArticleFeedObserver(articleFeed).start(); + }); +}