From 185ca863fe9a66c952585976a23d549403fea312 Mon Sep 17 00:00:00 2001 From: "Gustavo \"Guz\" L de Mello" Date: Fri, 17 Oct 2025 17:13:57 -0300 Subject: [PATCH] feat(ipub): base elements on IPUBElement This makes the random hex ID logic shared between all elements --- .epub/example/OEBPS/scripts/ipub.js | 95 ++++++++++++++++------------- 1 file changed, 54 insertions(+), 41 deletions(-) diff --git a/.epub/example/OEBPS/scripts/ipub.js b/.epub/example/OEBPS/scripts/ipub.js index 7af3355..884b6aa 100644 --- a/.epub/example/OEBPS/scripts/ipub.js +++ b/.epub/example/OEBPS/scripts/ipub.js @@ -1,19 +1,46 @@ "use strict"; -/** - * @param {string} str - * @returns {string} - */ -function hashString(str) { - return Array.from(str).reduce( - (s, c) => (Math.imul(31, s) + c.charCodeAt(0)) | 0, - 0, - ); +class IPUBElement extends HTMLElement { + static observedAttributes = ["id"]; + + connectedCallback() { + this.ensureID(); + } + + attributeChangedCallback(_name, _oldValue, _newValue) { + this.ensureID(); + } + + ensureID() { + if (this.id) { + return; + } + + // INFO: Hash algorithm by Joe Freeman & Cristian Sanchez at StackOverflow: + // https://stackoverflow.com/a/16348977 + // https://stackoverflow.com/a/3426956 + // + // Licensed under CC BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/) + + let hash = 0; + this.innerHTML.split("").forEach((char) => { + hash = char.charCodeAt(0) + ((hash << 5) - hash); + }); + + let id = ""; + for (let i = 0; i < 3; i++) { + id += ((hash >> (i * 8)) & 0xff).toString(16).padStart(2, "0"); + } + + this.id = id; + } } -class IPUBBackground extends HTMLElement { +class IPUBBackground extends IPUBElement { static elementName = "ipub-background"; - static observedAttributes = ["sticky", "fade", "id"]; + static observedAttributes = ["sticky", "fade"].concat( + super.observedAttributes, + ); /** * @private @@ -63,37 +90,23 @@ class IPUBBackground extends HTMLElement { })(); attributeChangedCallback(name, _oldValue, _newValue) { - console.debug("IPUBBackground: attribute changed", name); - switch (name) { - case "id": { - if (!this.id) { - console.warn( - `IPUBBackground: no ID specified, assigning one based on innerHTML`, - this, - ); - this.id = hashString(this.innerHTML); - } - break; - } - case "fade": { - const image = this.querySelector("img"); - if (image) { - console.debug( - `IPUBBackground: ipub-background#${this.id} to observer`, - ); + super.attributeChangedCallback(); - if (this.hasAttribute("fade")) { - IPUBBackground.#observer.observe(image); - } else { - IPUBBackground.#observer.unobserve(image); - } + if (name === "fade") { + const image = this.querySelector("img"); + if (image) { + console.debug(`IPUBBackground: ipub-background#${this.id} to observer`); - const perc = getPercentageInView(image); - if (perc > 0) { - this.fade(perc); - } + if (this.hasAttribute("fade")) { + IPUBBackground.#observer.observe(image); + } else { + IPUBBackground.#observer.unobserve(image); + } + + const perc = getPercentageInView(image); + if (perc > 0) { + this.fade(perc); } - break; } } } @@ -122,11 +135,11 @@ class IPUBBackground extends HTMLElement { } } -class IPUBContent extends HTMLElement { +class IPUBContent extends IPUBElement { static elementName = "ipub-content"; } -class IPUBImage extends HTMLElement { +class IPUBImage extends IPUBElement { static elementName = "ipub-image"; }