From 58670dc2d2be6f971c37a9969c2f4b2307acab4f Mon Sep 17 00:00:00 2001 From: Oliver Tacke Date: Thu, 4 Jan 2024 12:46:14 +0100 Subject: [PATCH] Clean up IntersectionObserver --- .../components/media-screen/media-screen.js | 28 ++++------------ src/scripts/services/focus-trap.js | 27 +++++---------- src/scripts/services/util.js | 33 +++++++++++++++++++ 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/src/scripts/components/media-screen/media-screen.js b/src/scripts/components/media-screen/media-screen.js index 35a0af2..12f29de 100644 --- a/src/scripts/components/media-screen/media-screen.js +++ b/src/scripts/components/media-screen/media-screen.js @@ -206,27 +206,13 @@ export default class MediaScreen { this.dom.replaceChild(newVisuals, this.visuals); this.visuals = newVisuals; - // iOS is behind ... Again ... - const callback = window.requestIdleCallback ? - window.requestIdleCallback : - window.requestAnimationFrame; - - /* - * Get started once visible and ready. YouTube requires the video to be - * attached to the DOM. - */ - callback(() => { - this.observer = new IntersectionObserver((entries) => { - if (entries[0].isIntersecting) { - this.observer.unobserve(this.dom); - this.initMedia(); - } - }, { - root: document.documentElement, - threshold: 0 - }); - this.observer.observe(this.dom); - }); + Util.callOnceVisible( + this.dom, + () => { + this.initMedia(); + }, + { root: document.documentElement } + ); } else { this.visuals.classList.add('display-none'); diff --git a/src/scripts/services/focus-trap.js b/src/scripts/services/focus-trap.js index 4ba3975..d77230e 100644 --- a/src/scripts/services/focus-trap.js +++ b/src/scripts/services/focus-trap.js @@ -1,3 +1,5 @@ +import Util from '@services/util.js'; + export default class FocusTrap { /** @@ -38,24 +40,13 @@ export default class FocusTrap { this.isActivated = true; - // iOS is behind ... Again ... - const callback = window.requestIdleCallback ? - window.requestIdleCallback : - window.requestAnimationFrame; - - callback(() => { - this.observer = this.observer || new IntersectionObserver((entries) => { - if (entries[0].isIntersecting) { - this.observer.unobserve(this.params.trapElement); - - this.handleVisible(); - } - }, { - root: document.documentElement, - threshold: 0 - }); - this.observer.observe(this.params.trapElement); - }); + Util.callOnceVisible( + this.params.trapElement, + () => { + this.handleVisible(); + }, + { root: document.documentElement } + ); } /** diff --git a/src/scripts/services/util.js b/src/scripts/services/util.js index c05c454..ed7af9c 100644 --- a/src/scripts/services/util.js +++ b/src/scripts/services/util.js @@ -121,4 +121,37 @@ export default class Util { return text; } + + /** + * Call callback function once dom element gets visible in viewport. + * @param {HTMLElement} dom DOM element to wait for. + * @param {function} callback Function to call once DOM element is visible. + * @param {object} [options] IntersectionObserver options. + */ + static callOnceVisible(dom, callback, options = {}) { + if (typeof dom !== 'object' || typeof callback !== 'function') { + return; // Invalid arguments + } + + options.threshold = options.threshold || 0; + + // iOS is behind ... Again ... + const idleCallback = window.requestIdleCallback ? + window.requestIdleCallback : + window.requestAnimationFrame; + + idleCallback(() => { + // Get started once visible and ready + const observer = new IntersectionObserver((entries) => { + if (entries[0].isIntersecting) { + observer.unobserve(dom); + callback(); + } + }, { + ...(options.root && { root: options.root }), + threshold: options.threshold, + }); + observer.observe(dom); + }); + } }