CRITICAL BUG FIX:
The previous pagination system used a linear mapping between word positions
and character positions, which is incorrect for HTML content. This caused
page boundaries to cut through HTML tags, resulting in:
- Missing content (e.g., headings like "Letter 1" skipped entirely)
- Truncated text starting mid-sentence
- Incorrect page breaks that didn't respect HTML structure
Example of the problem:
Plain text: "Letter 1\nTo Mrs. Saville" (25 chars, 5 words)
HTML: "<p>Letter 1</p><p>To Mrs. Saville" (85 chars)
Old calculation: (3 / 5) * 85 = 51 chars (wrong - cuts in middle of tag)
Correct mapping: ~45 chars (respects HTML structure)
SOLUTION:
- Add buildTextNodeMapping() function to traverse HTML DOM
- Track character positions for both HTML source and plain text
- Create mapWordToHtmlChar() to accurately map word positions to HTML positions
- Account for HTML tags, attributes, and element boundaries
TECHNICAL DETAILS:
- Introduce TextNodeInfo interface to track node positions
- Recursively traverse DOM to build accurate character position mapping
- Calculate word positions within each text node separately
- Map word ranges to precise HTML character positions
IMPACT:
✅ Content renders correctly without truncation
✅ Page boundaries respect HTML structure
✅ All text and headings display in correct order
✅ Character positions accurately reflect HTML content
This fix resolves the core issue where pagination was calculated based
on plain text word positions but applied to HTML source, causing
systematic content loss and incorrect page breaks.
Related to: EPUB pagination, content rendering accuracy
Problem:
- Many format modules imported from '../core/reader-context'
- reader-context.ts was a local interface file, not a true context module
- Confusion between canonical reader-shell.ts and local reader-context.ts
- PDF page-cache.ts was 100% dead code (unused, unregistered, no exports)
- Several unused variables and imports across reader modules
Root Cause:
- reader-context.ts created as temporary file during refactoring
- Modules imported from it instead of canonical reader-shell.ts
- page-cache.ts copied from comic version but never integrated
- Incomplete refactoring left behind unused code
Solution:
- Update all imports to use reader-shell (canonical source)
- Remove unused page-cache.ts (dead code)
- Clean up unused variables and imports
- Consolidate type definitions
Changes:
Import Path Updates:
- comic/*: '../core/reader-context' → '../../reader-shell'
- manga/*: '../core/reader-context' → '../../reader-shell'
- pdf/*: '../core/reader-context' → '../../reader-shell'
- reflowable/ebook/*: '../core/reader-context' → '../../reader-shell'
- All now import UniversalReader from single source
Dead Code Removal:
- pdf/page-cache.ts: Deleted entirely
- No init() function exported
- Not registered in reader-shell.ts
- All functions unused (createPDFPageCache, getCachedPage, etc.)
- Only 2 lines of executable code (console.log, DOM cleanup)
- 148 lines of dead code
Clean Up:
- navigator-panel.ts: Remove unused containerRect variable
- api-explorer-docs.ts, api.ts, queue.ts: Fix unused imports
- unlinked_books.ts: Remove unused variables
- panel-dock-system.ts: Remove unused context variables
Impact:
- ✅ All modules use canonical type definitions
- ✅ No more duplicate/conflicting interfaces
- ✅ Dead code removed (148 lines)
- ✅ Cleaner imports, easier maintenance
- ✅ TypeScript compiler warnings resolved
Files changed: 26
Lines changed: +450, -520 (net -70 lines)
BREAKING CHANGE: Unify ebook reader type system to match actual data structures
Problem:
- ReflowableBook type had direct properties (spine, resources, toc, metadata)
- UniversalReader wraps EbookCIF in cif property with runtime state
- Type mismatch caused unsafe 'as any' casts and runtime errors
- Two conflicting UniversalReader definitions existed (reader-shell vs reader-context)
Root Cause:
- Parsers return EbookCIF (nested structure)
- ReflowableBook expected flat structure
- Code mixed both approaches causing confusion
Changes:
Type System Updates:
- Replace all ReflowableBook references with UniversalReader
- Remove duplicate UniversalReader definition in reader-context.ts
- Import UniversalReader from canonical source (reader-shell.ts)
- Update all function signatures across reflowable module
Property Access Patterns:
- book.cif.spine instead of book.spine
- book.cif.resources instead of book.resources
- book.cif.toc instead of book.toc
- book.cif.metadata instead of book.metadata
Fixed Modules:
- reader-shell.ts: UniversalReader object construction
- reader-context.ts: Remove duplicate interface, import from reader-shell
- reader-navigation.ts: Remove unsafe type casts, fix property access
- reader-services.ts: Align with UniversalReader structure
- reflowable/navigation.ts: Update all navigation function signatures
- reflowable/progress-tracker.ts: Update tracker function signatures
- reflowable/parser.ts: Return UniversalReader with proper structure
- reflowable/page-calculator.ts: Update calculation function signatures
- reflowable/ebook/search.ts: Fix property access patterns
- types/reader.d.ts: Remove duplicate type definitions
Impact:
- ✅ Type-safe throughout ebook reader
- ✅ Matches actual data structures from parsers
- ✅ No more unsafe type casts
- ✅ Single source of truth for UniversalReader
- ✅ Aligns with EbookCIF format from API/parsers
Files changed: 10
Lines changed: +320, -180
Update import statements to reflect new module locations:
- panel-editor.ts: fix Alpine and api imports
- copy-handler.ts: fix ReaderContext and toast imports
These corrections address path issues caused by the reader
architecture refactor where modules were moved into
format-specific subdirectories.
Implement complete modularization of reader code by separating format-specific
functionality into dedicated modules. This replaces the monolithic structure
with a clean, maintainable architecture that separates concerns by format type.
## New Architecture
### Format-Specific Modules
- **formats/reflowable/**: EPUB, FB2, TXT, HTML (page-based pagination)
- types.ts: Shared type definitions for reflowable formats
- page-calculator.ts: Word-count based pagination with HTML slicing
- navigation.ts: Page-based navigation logic
- progress-tracker.ts: CFI-based progress tracking
- content-renderer.ts: DOM rendering for page content
- parser.ts: Unified parser interface for all reflowable formats
- ebook/**: Migrated ebook-specific features
- **formats/pdf/**: PDF format support
- Core PDF functionality (navigation, text selection, annotations)
- Advanced features (bookmarks, search, outlines, dual-page)
- Page cache and rendering optimizations
- **formats/comic/**: Comic format support
- Background color, chapter markers, page caching
- Page ordering, gap adjustments
- **formats/manga/**: Manga format support
- RTL navigation, vertical scrolling, reading direction
## Key Improvements
1. **Separation of Concerns**: Each format has its own dedicated module
2. **No Circular Dependencies**: Clean import structure
3. **Type Safety**: Comprehensive TypeScript types throughout
4. **Functional Programming**: Pure functions, no OOP complexity
5. **Scalability**: Easy to add new formats without touching core code
## Migration Path
- Old format-specific code in reader/, ebook/, pdf/, comic/, manga/
- New code in formats/[format]/ structure
- Maintains backward compatibility during transition
- Core reader logic remains format-agnostic
This change enables the implementation of page-based pagination for reflowable
formats while keeping PDF, comic, and manga functionality unchanged.