diff --git a/.epub/example/OEBPS/scripts/ipub.js b/.epub/example/OEBPS/scripts/ipub.js index 1a9e3e2..f70a681 100644 --- a/.epub/example/OEBPS/scripts/ipub.js +++ b/.epub/example/OEBPS/scripts/ipub.js @@ -28,49 +28,84 @@ class IPUBBackground extends IPUBElement { /** * @private */ - static #observer = (() => { - /** @type {Map} */ - const instancesOnScreen = new Map(); - - document.addEventListener("scroll", () => { - for (const [_, instance] of instancesOnScreen) { - const perc = getPercentageInView( - instance.querySelector("img") || instance, + static #instancesOnScreen = { + /** @type {Map>} */ + map: new Map(), + /** + * @param {IPUBBackground} background + */ + add(background) { + const body = getAncestor(background, IPUBBody.elementName); + if (!body) { + console.error( + `IPUBBackground: ${background.id} does not have a valid ipub-body ancestor`, ); - instance.fade(perc); + return; } - }); - return new IntersectionObserver((entries) => - entries.forEach((e) => { - let instance = e.target.parentElement; + let set = this.map.get(body); + if (!set) { + set = new Set(); + body.addEventListener("scroll", () => { + for (const instance of set.values()) { + const perc = getPercentageInView( + instance.querySelector("img") || instance, + ); + instance.fade(perc); + } + }); + } + set.add(background); + this.map.set(body, set); + }, + /** + * @param {IPUBBackground} background + */ + remove(background) { + const body = getAncestor(background, IPUBBody.elementName); + if (!body) { + console.error( + `IPUBBackground: ${background.id} does not have a valid ipub-body ancestor`, + ); + return; + } - if ( - instance.tagName.toLowerCase() !== - IPUBBackground.elementName.toLowerCase() - ) { - instance = instance.parentElement; - } + const set = this.map.get(body); + if (!set) { + return; + } - if ( - instance.tagName.toLowerCase() !== - IPUBBackground.elementName.toLowerCase() - ) { - console.error( - "IPUBBackground: malformed element", - e.target, - ); - return; - } + set.delete(background); - if (e.intersectionRatio > 0 && instance.id) { - instancesOnScreen.set(instance.id, instance); - } else if (instance.id) { - instancesOnScreen.delete(instance.id); - } - }), - ); - })(); + if (set.size === 0) { + this.map.delete(body); + } + }, + }; + static addToScreen() {} + + /** + * @private + */ + static #observer = new IntersectionObserver((entries) => { + for (const { intersectionRatio, target: image } of entries) { + const instance = getAncestor(image, IPUBBackground.elementName); + + if (!instance) { + console.error( + "IPUBBackground: malformed element", + image, + ); + return; + } + + if (intersectionRatio > 0 && instance.id) { + IPUBBackground.#instancesOnScreen.add(instance); + } else if (instance.id) { + IPUBBackground.#instancesOnScreen.remove(instance); + } + } + }); connectedCallback() { super.connectedCallback(); @@ -126,8 +161,6 @@ class IPUBBackground extends IPUBElement { * @returns {void | Promise} */ fade(perc) { - console.debug(`IPUBBackground: ${this.id} is ${perc} on screen`); - if (!this.style.getPropertyValue("--ipub-fade")) { this.style.setProperty("--ipub-fade", `${perc}%`); return; @@ -264,7 +297,19 @@ class IPUBInteraction extends IPUBElement { } /** + * @param {HTMLElement} el + * @param {string} tagName + * @returns {HTMLElement | undefined} */ +function getAncestor(el, tagName) { + if (!el.parentElement) { + return undefined; + } + if (el.parentElement.tagName.toLowerCase() === tagName.toLowerCase()) { + return el.parentElement; + } + return getAncestor(el.parentElement, tagName); +} /** * @param {Readonly} el @@ -330,3 +375,4 @@ function getPercentageInView(element) { return Math.round((inView / globalThis.innerHeight) * 100); } +