From 3bede113936179c7171e4f2823e105edfe690a40 Mon Sep 17 00:00:00 2001 From: "Gustavo \"Guz\" L de Mello" Date: Thu, 23 Oct 2025 14:59:08 -0300 Subject: [PATCH] feat(ipub): ipub-cover, forcing user to interact to enable autoplay --- .epub/example/OEBPS/scripts/ipub.js | 66 +++++++++++++++++++ .../example/OEBPS/sections/section0001.xhtml | 11 ++++ .epub/example/OEBPS/styles/stylesheet.css | 23 +++++++ 3 files changed, 100 insertions(+) diff --git a/.epub/example/OEBPS/scripts/ipub.js b/.epub/example/OEBPS/scripts/ipub.js index 0d1184e..0eb9743 100644 --- a/.epub/example/OEBPS/scripts/ipub.js +++ b/.epub/example/OEBPS/scripts/ipub.js @@ -163,7 +163,15 @@ class IPUBBody extends IPUBElement { this.setAttribute("aria-busy", "true"); + console.log("IPUBBody: defining custom element "); + globalThis.customElements.define(IPUBCover.elementName, IPUBCover); + + /** @type {IPUBCover} */ + const cover = this.querySelector("ipub-cover"); + if (!cover) { IPUBBody.defineContentElements(); + } + cover.onclose = IPUBBody.defineContentElements; this.setAttribute("aria-busy", "false"); } @@ -176,6 +184,64 @@ globalThis.addEventListener("load", () => { globalThis.customElements.define(IPUBBody.elementName, IPUBBody); }); +class IPUBCover extends IPUBElement { + static elementName = "ipub-cover"; + + /** + * @type {() => void} callback + */ + onclose = () => {}; + + connectedCallback() { + super.connectedCallback(); + + console.debug("IPUBCover: Setting up cover"); + this.setAttribute("aria-busy", "true"); + + const dialog = this.querySelector("dialog"); + dialog.show(); + + // HACK: Test if we can autoplay interactions, soundtracks, etc + + /** @type {HTMLMediaElement | null} */ + const media = + this.parentElement.querySelector("audio") ?? + this.parentElement.querySelector("video"); + + if (!media) { + dialog.close(); + return; + } + + const pastVolume = media.volume; + media.volume = 0.1; // don't let the user hear the test audio + + media + .play() + .then(() => { + media.pause(); + media.volume = pastVolume; + media.currentTime = 0; + + console.debug("IPUBCover: Can autoplay interactions, removing cover"); + this.onclose(); + }) + .catch(() => { + console.debug( + "IPUBCover: Cannot autoplay interactions, covering content", + ); + + dialog.parentElement.addEventListener("click", () => { + dialog.close(); + this.onclose(); + }); + + this.setAttribute("aria-busy", "false"); + return; + }); + } +} + class IPUBImage extends IPUBElement { static elementName = "ipub-image"; } diff --git a/.epub/example/OEBPS/sections/section0001.xhtml b/.epub/example/OEBPS/sections/section0001.xhtml index 466e8ed..cfa3d81 100644 --- a/.epub/example/OEBPS/sections/section0001.xhtml +++ b/.epub/example/OEBPS/sections/section0001.xhtml @@ -10,6 +10,17 @@ + + +
+

Test comic

+
+

Click anywhere to +

+
+
+
+
diff --git a/.epub/example/OEBPS/styles/stylesheet.css b/.epub/example/OEBPS/styles/stylesheet.css index be7e339..c3b85a2 100644 --- a/.epub/example/OEBPS/styles/stylesheet.css +++ b/.epub/example/OEBPS/styles/stylesheet.css @@ -12,6 +12,25 @@ overflow: clip; display: flex; + --z-cover: 9; +ipub-cover > dialog[open] { + --ipub-accent-color: #fff; + z-index: var(--z-cover); + background-color: transparent; + border: none; + + display: inline-block; + position: absolute; + backdrop-filter: blur(1rem); + background-image: linear-gradient( + rgba(from var(--ipub-accent-color) r g b / 0) 0%, + rgba(from var(--ipub-accent-color) r g b / 0.5) + calc(100% + calc(var(--ipub-fade, 50%) * -1)) + ); + top: 0; + left: 0; + width: 100%; + height: 100%; } ipub-body { @@ -24,6 +43,10 @@ ipub-body { flex-direction: column; overflow: scroll; + &:has(ipub-cover > dialog[open]) { + overflow: hidden; + } + --ipub-padding: 0%; --ipub-gap: 0%; --ipub-padding-x: var(--ipub-padding, 0%);