Add EPUB Reader (Fixed Layout) project#2
Open
Mario55666 wants to merge 24 commits into
Open
Conversation
Vanilla HTML/CSS/JS EPUB reader built on epub.js. Detects EPUB3
fixed-layout ("diseño fijo") books via rendition:layout metadata and
renders them page by page at their intended size (spread: none)
instead of reflowing text, re-dispatching DOMContentLoaded/load on
every page swap so CSS keyframe animations and embedded <script>
content keep working as you navigate. Verified end-to-end in a
headless browser: page-load animations, an actively-updating <canvas>
particle animation, and a click-triggered CSS flip transition driven
by JS all render and respond correctly.
Adds Source-Code/EpubReader/{index.html,style.css,script.js} and a
matching entry in the project list in README.md.
Replace the short drag/drop hint with a titled step-by-step explainer (¿Cómo funciona esta aplicación?) so first-time visitors understand how to open a book, that fixed-layout animated EPUBs are detected automatically, and how to navigate.
Add a link/video modal (#linkModal) and intercept clicks inside the rendered EPUB content in the capture phase: - Absolute (external) <a href="..."> links — the ones epub.js already treats as target="_blank" instead of internal navigation — now open in the modal: direct video files (.mp4/.webm/.ogv/.ogg/.mov) get a <video> player, YouTube/Vimeo links get their embed iframe, and any other external link gets an iframe preview with an "open in new tab" fallback. - Clicking an inline <video> element in the page also opens it larger in the same modal. - Relative links (chapters within the book) are left untouched so normal reading navigation keeps working. - Modal closes on the × button, clicking outside the box, or Escape; closing/opening a new book clears it so nothing keeps playing in the background. Verified with Playwright against a test EPUB covering all 5 cases (external link, YouTube link, direct video file link, inline <video> click, and internal chapter link) — each behaves as intended and no browser popup windows are opened. Also documents the new behavior in the "¿Cómo funciona esta aplicación?" empty-state steps.
Replace the in-page modal overlay with an actual window.open() popup, enlarged and centered on the user's screen, per explicit request: - Direct video files and YouTube/Vimeo links get a self-written HTML page in the popup with a full-size <video>/<iframe> player. - Other external links navigate the popup straight to the href, so the linked site renders with its own layout/scripts intact instead of hitting X-Frame-Options iframe-embedding blocks (a real limitation of the previous modal approach for arbitrary external links). - Clicking an inline <video> in the page also enlarges it the same way. - Internal chapter links are untouched (still normal in-reader nav). - Popups are tracked and closed together when a new book loads. - If the browser's popup blocker stops the window, a small toast explains that instead of silently doing nothing. Fixed a real bug caught in testing: the "noopener" window-feature makes window.open() return null by design, which broke tracking/closing and meant nothing was ever written into the video/embed popups (a blank window would open and just hang). Now using manual `popup.opener = null` for opener isolation on generic links, since only that path needs it — the video/embed popups don't navigate anywhere untrusted. Re-verified with Playwright: external link, YouTube link, direct video file link, inline <video> click, and internal chapter link — all 5 cases behave correctly and no browsing context leaks are opened for external content the reader doesn't control.
… its fonts Screen adapts to the book's format: - fitViewerToBook()/syncViewerSize() size the #viewer box to the exact aspect ratio the EPUB declares (book-level <meta property="rendition: viewport"> if present, else each page's own <meta name="viewport">), like object-fit: contain, instead of stretching fixed-layout pages into a generic rectangle. Reflowable books are unaffected. - Found and fixed a real epub.js quirk while wiring this up: Rendition only re-displays content after a manager resize if `rendition.location` is already set (Rendition#onResized), which isn't true yet on the very first page — resizing at that moment silently cleared the view and never redrew it. Fixed by determining the aspect ratio *before* the initial renderTo() (peekBookAspectRatio() loads the first section's markup ahead of time), with a location-aware deferred-resize guard (pendingSizeSync, flushed from the 'relocated' handler) as a safety net for the rare book whose pages vary in size. Identify, don't distort, typography: - This reader has never injected font CSS into EPUB content (each page renders in its own sandboxed iframe with the book's original stylesheet), so the author's fonts already came through untouched. Made that guarantee visible: syncFontBadge()/detectPageFont() scan the rendered page for @font-face rules (fonts the book embeds itself) and fall back to the computed body font, showing whichever is active in a badge next to the title — proof nothing is being substituted, not a behavior change. Verified with Playwright: viewer aspect ratio matches a 1200x1600 test book exactly (and stays correct across window resizes) with content no longer disappearing, reflowable books keep their normal wide reading pane, and the font badge correctly reports both an embedded @font-face name and a plain CSS font-family fallback.
…declared Fullscreen leaving blank margins: - fullscreenBtn only called requestFullscreen()/exitFullscreen() and never resynced the viewer's size afterward, so it kept whatever pixel size it had in windowed mode inside the now much bigger (or smaller) #stage — added a 'fullscreenchange' listener that calls syncViewerSize() (via rAF) so both the box and epub.js's internal layout catch up. - While verifying that fix, found the real root cause of a subtler version of the same symptom: the `.viewer` CSS had a `transition: width/height` (added earlier purely for polish) that made syncViewerSize()'s getBoundingClientRect() read a mid-animation size one frame after the box started resizing, instead of the final target — epub.js's internal content got resized to that stale, smaller size while the box's own white background kept animating on to the correct larger one, leaving a visible gap of blank background around the actual page content. Resizes must apply instantly for anything that measures the box programmatically, so the transition is removed. Font detection gave false confidence: - The previous badge only checked whether the page's CSS *declared* an @font-face, not whether the browser actually managed to load it — a book can declare a custom font and still silently render with a fallback if the font file 404s or isn't in the EPUB's manifest, and the old badge would call that "Fuente incrustada: X" regardless. Rewrote it on the CSS Font Loading API (document.fonts, the same API epub.js itself uses internally for this purpose) to check each FontFace's real .status: a genuinely loaded custom font still shows green, but one that failed to load now shows an orange "Fuente incrustada no cargó: X" badge plus a console warning explaining the likely cause, instead of a false all-clear. Verified with Playwright: a real embedded TrueType font loads and renders correctly (computed font-family matches, badge green); the same font missing from the manifest is correctly flagged as failed (badge orange, warning logged); fullscreen on both a portrait fixed-layout book and a reflowable book now fills available space with content and background matching exactly, no gap.
Vanilla JS app (JSZip + CodeMirror, no build step) with a DOM explorer, HTML/CSS editors with live preview and autocomplete, inline or bulk text editing, per-chapter undo/redo, and export to a new .epub file.
…l Editor Selecting an object now assigns it a stable, unique id instead of relying on shared classes (common in InDesign-exported EPUBs, where many unrelated objects reuse the same class), so HTML/CSS/animation edits target exactly the selected object. Also fixes a bug where applied CSS (and now animations) never survived export. Adds an "Animación" tab with a catalog of 16 ready-to-use CSS animations (entrances, bounce, pulse, shake, swing, flip, blur, grayscale), inspired by the CSS properties anime.js documents: adjustable duration/delay/easing/ repeat, a live preview on the actual selected object, and a persistent apply step.
… bugs - Fix: previewing an animation on an object that already has an applied CSS/animation rule (persisted with an #id selector) was silently overridden by CSS specificity, making "Reproducir vista previa" appear broken after the first "Aplicar" on that object. - Fix: selecting an object read its computed color/background/transparency through the editor's own selection-highlight overlay, always reporting a contaminated ~12% tint instead of the object's real value. - Fix: layer type detection (image vs vector) read the src/href attribute after asset resolution had already rewritten it to a blob: URL, losing the file extension needed to tell an <img src="x.svg"> from a raster. - Add a "Ninguno" toggle for the color/background pickers, since <input type=color> can't otherwise represent "don't set this". - Add a DOM-tree layer-type badge (image/vector/text/container) and a per-selection transparency readout. - Add a button editor (label + href) for button/anchor/input[button] elements, plus an "insert button" action. - Size the viewer to the EPUB's own declared page format (viewport meta / rendition:viewport) instead of always stretching to fill the pane. - Add a "Probar como lector" popup window rendering the current chapter clean of editor markup, to demonstrate the EPUB as an end reader sees it. - Add a per-tab help panel explaining what each tool does and how it maps to the underlying .xhtml/.epub file. - Add the footer credit.
…ader preview New Source-Code/EpubButtonCatalog: a self-contained XHTML-valid catalog of six buttons pairing Prismic-inspired CSS hover effects (sliding underline, liquid fill, 3D flip, holographic, lift, border draw) with Anime.js click animations (camelCase CSS properties). Includes a 600x800 book container with reflowable content, a button navigation list, welcome/confirmation/ test modal dialogs, an event diagnostic tool, and robust tap handling (click + touchend with preventDefault and a timestamp guard, verified to fire exactly once per tap). Ships as both a single .html and a packaged .epub with Anime.js bundled. Editor fix: resolveAssets ignored script[src], so JavaScript packaged in an EPUB never loaded in the "Probar como lector" popup and interactive books appeared dead there — the root cause of buttons not responding to click or touch. Chapter scripts are now resolved to blob URLs (with js media type) like images and stylesheets, reverted to their original relative paths on export. The editing iframe still blocks script execution by design (sandbox without allow-scripts).
…sertion Single-file variant of the visual EPUB editor whose "Botones" tab holds an 11-button catalog (the original 5 designs plus the 6 Prismic-inspired hover effects from EpubButtonCatalog). Fixes two defects in the consolidated variant: inserting a catalog button never copied its CSS into the chapter (the extraction code was an empty stub reading rules from a just-created blank style element), so buttons arrived unstyled in the exported EPUB; and updateInsertButtonState() was called on every chapter load but never defined, throwing a ReferenceError. The catalog CSS now lives in a single BUTTON_CATALOG_CSS map injected both into the editor page (thumbnail previews) and into the chapter's customCss on insertion, so each button travels complete (class + pseudo-elements + keyframes) inside the exported EPUB. Also ports the script[src] blob resolution and the sandboxed editing iframe from the main editor.
Mesa de trabajo in the viewer statusbar: a Mover toggle that lets any
object be dragged and dropped to a fixed position (absolute coordinates
anchored to a body{position:relative} rule that travels with the export),
move up/down buttons that reorder the selected object among its siblings,
and a delete button (plus the Supr key) — all going through the undo/redo
history. Native HTML5 drags of links/images are suppressed in move mode
so dragging an <a> or <img> doesn't leave the operation hanging, and a
drag is cancelled cleanly if the pointer leaves the page.
Button editing: clicking a catalog style while a button/anchor is
selected now swaps that button's epub-btn-* class (injecting the new
style's CSS) instead of inserting a duplicate; with no button selected
it inserts a new one as before.
…ooter The workspace now stacks vertically (viewer on top, tools below, full width) for portrait screen reading, with the minimum width relaxed from 1366px to 720px. The generic help panel is replaced by per-screen contextual help: each of the 7 tabs has its own text explaining what the tool does and how it affects the EPUB file, shown automatically on the first visit to each screen (step-by-step tutorial) and on demand via the "?" button, updating live when switching tabs. The footer now credits Curso de Infografía 2026 · Docente: Mg Mario Quiroz Martinez.
…th live coordinates When the EPUB declares a page size, the editing viewer now renders the chapter iframe at the document's ORIGINAL pixel dimensions and scales it visually with a CSS transform to fit entirely in the pane: no scrollbars (container clips, inner document overflow hidden via an editor-only rule stripped on export), and all in-document coordinates remain real pixels of the original. The status bar reports the original document dimensions and current scale, live cursor coordinates inside the document, and the selected object's position and size; the layer info panel shows the same position/size for the selection.
The button editor now covers the full interactive workflow: per-button text and background color pickers (written as an #id rule that overrides the catalog class and travels in the export), a hyperlink field for chapter files, anchors or external URLs, and EPUB-context actions — a button can play a chosen animation preset on any object with an id, or toggle another object's visibility. Actions are declared as data-* attributes and executed by a small runtime script embedded in the chapter (ES5, click+touchend with double-fire guard), deliberately written without <, ampersands or comparison operators because XMLSerializer escapes those into entities inside XHTML, which corrupted the first version of the script when exported.
…learer errors Real-world EPUBs URL-encode file names in the OPF/NCX (spaces become %20); zip lookups used the encoded path verbatim, got null, and crashed before the book could render. Paths now fall back to their decoded form for chapters and assets, a chapter without a readable body reports a meaningful error instead of failing later, and the load-failure toast explains what a valid .epub requires.
…clared page Chapters whose content overflows the declared page size (an EPUB declaring 600x800 with a longer chapter) were clipped by the no-scroll fixed-page mode, showing only part of the document. The viewer now measures the real content size after load (and again 400ms later, once async blob images have laid out), uses the larger of declared vs real dimensions for the scaled frame so the whole document is always visible, and reports both sizes in the status bar.
… hidden objects The sandboxed editing viewer never runs the EPUB's action script, so a configured button appeared to do nothing until previewed as a reader. The button editor now has 'Probar accion' (the editor itself replays the configured animation/toggle inside the viewer), 'Ubicar boton' (enables move mode and walks through drag placement), and prominent modal dialogs that confirm each configuration step and explain how the action behaves in a real reader. Objects hidden by the show/hide action render as semi-transparent orange-dashed ghosts in the editor only (rule lives in the internal stylesheet, stripped on export), and the Botones help text now documents the full configuration workflow.
…always-visible button config Probar accion, Ubicar and a new Revisar (reader preview) button now live in the workspace toolbar under the viewer, enabled by selection. The viewer always locks to the EPUB output format with no scrolling anywhere: books without a declared page size get a 600x800 default expanded to the real content, and workspace drags are clamped to the page bounds so no object can land outside the mesa de trabajo. The button configuration panel (text, hyperlink, colors, animation/object-state actions) is now permanently visible in the Botones tab, disabled until a button is selected, instead of hidden - which made users believe the whole configuration system was missing.
InDesign-style animated EPUBs keep every animated object at opacity:0 until the book's own script triggers its entry animation; that script is sandboxed out of the editing viewer, so such books rendered as an empty page with nothing selectable. A workspace toggle (on by default) now forces opacity/visibility and suppresses animations inside the editing viewer only - verified against a real 1920x1080 InDesign EPUB where all 847 objects (68 previously invisible) became selectable, with the exported file free of any editor-only classes.
applyButtonEdit silently returned for anything that was not a button/anchor/input, so selecting an InDesign container and pressing Actualizar Boton did nothing and Probar accion then reported no action configured. The configuration panel now enables for any selected object: colors and animation/visibility actions apply to all elements, the text field disables itself for containers with children (edited via the Texto tab instead), and hyperlinks on non-anchor objects are stored as data-enlace and navigated by the exported runtime on tap. Verified against the real InDesign EPUB: a container was configured with an animate action plus link, tested in-viewer, and exported intact.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Source-Code/EpubReader/: vanilla HTML/CSS/JS EPUB reader built on epub.js — fixed-layout detection, per-page animation/script re-triggering, popup windows for videos/links, format-aware viewer, embedded-font detection.Source-Code/EpubVisualEditor/: vanilla HTML/CSS/JS visual EPUB editor (JSZip + CodeMirror) — DOM explorer with layer-type badges and transparency readout, unique per-object identification (stable ids even when InDesign-style shared classes are reused), HTML/CSS editors with live preview and a common-properties panel (with "Ninguno" color toggles), button editor, 16-preset CSS animation catalog with live preview, inline/bulk text editing, per-chapter undo/redo, per-tab help system, format-aware viewer, "Probar como lector" popup, and clean EPUB re-export.Source-Code/EpubButtonCatalog/: a self-contained interactive button catalog for EPUB3, delivered as a single XHTML-valid HTML file plus a ready-to-read.epubwith Anime.js bundled inside:backgroundColor,borderRadius,letterSpacing,rotateY,translateX,scale).click+touchendlisteners withpreventDefault()and a timestamp guard — automated touch test confirms exactly one dialog open per tap (no double-fire), plustouch-action: manipulationto kill the 300 ms tap delay.resolveAssetsignoredscript[src], so JavaScript packaged inside an EPUB never loaded in the reader-preview popup — interactive books appeared dead there. Chapter scripts are now resolved to blob URLs (withtext/javascriptmedia type) like images/stylesheets, and reverted to their original relative paths on export. The editing iframe still blocks script execution by design (sandbox withoutallow-scripts); the popup is where interactivity runs, matching a real reader.Test plan
::aftertransform, holographic background-position), click animations verified mid-flight (elastic scale,backgroundColorinterpolation), confirmation dialog with exact required text per button, "Probar efecto" dialog with exact required text, diagnostic output (JS active, Anime.js version, listener count), button-list navigation with highlight.has_touch+is_mobile): welcome dialog closed by tap; tapping a catalog button opens the confirmation dialog exactly once (MutationObserver counted 1 open — no double-fire from touchend+click).scriptedmanifest property, Anime.js bundled) and opened through the editor: editing iframe correctly shows the red "JavaScript inactivo" badge (scripts blocked by design), chapter script resolved to a blob URL, and in the "Probar como lector" popup: JS badge active, welcome dialog shown, bundled Anime.js loaded, buttons respond to click with the correct confirmation dialog, diagnostic reports all green.srcreverted from blob URL tojs/anime.min.js, XHTML still well-formed, bundled library intact.catalogo-botones.htmlvalidated as well-formed XML (parseable asapplication/xhtml+xmlby strict EPUB readers): CDATA-wrapped script, self-closed void elements, no raw angle brackets in comments.