- 6 new ReadiumCSS properties wired —
bodyHyphens,paraSpacing,paraIndent,typeScale,backgroundColor,textColorare now fully functional end-to-end (ReadiumCSS.ts, UserProperties.ts, UserSettings.ts) - CitationModule stubs implemented —
contributorsFormatted(editors/translators),eBookVersionFormatted(from Modified date),seriesFormatted(from BelongsTo.Series). Multi-author formatting follows Chicago, MLA 9th, and APA 7th standards - Search progression — navigating to a search result in another chapter now carries correct
totalProgressionandpositioninstead of 0 - Search highlight default colors — all results show yellow, selected result shows orange, no configuration required
- Chapter title on currentLocator —
currentLocator()now populatestitlefromcurrentChapterLink, so consumers get chapter name without TOC lookup
- Upgraded bundled ReadiumCSS from v1.x to v1.1.1 (CJK Latin/Cyrillic script fix)
- Custom patches preserved: image no-stretch and line-height compensation formula
- Added
ReadiumCSS-ebpaj_fonts_patch.css
- Popup.ts XSS — 3 gaps closed:
showPopup,showPopover, andhandleFootnotenow sanitize HTML viasanitize-html - ContentProtectionModule — replaced deprecated
document.execCommand('copy')with async Clipboard API + fallback. Removed IE/Netscape dead code. Eliminated all 5@ts-ignoresuppressions
- index_dita.html — compact modern settings panel: segmented controls, toggle switch, color swatches, value readout sliders, proper reset. Controls for all 6 new CSS properties
- React example — full rewrite: toolbar with page info, sidebar with TOC/settings/bookmarks/search tabs, React 18 createRoot, keyboard navigation, IE11 polyfills removed
- 50 unit tests across 5 files: LocalAnnotator (21), MemoryStore (7), CitationModule (15), ReadiumCSS (3), Locator (4)
- Added vitest config and test tsconfig
- Definitions popup — read
dataset.definitionanddataset.orderfrom parent container element instead of clicked child area div LocalAnnotatorsort comparators —getBookmarks,getAnnotations,getAnnotationsByChapterall returnedundefinedfrom their sort callbacks when entries had no progression value. Sort comparators must return a number;undefinedproduces unstable/undefined sort order. Fixed to return0(equal) instead.hasChildNodescalled as property —getAnnotationPositionandgetAnnotationElementcheckedif (foundElement.hasChildNodes)(always true — it's a function reference) instead ofif (foundElement.hasChildNodes()). Fixed to call the method.- Duplicate
TTSModule2instanceofcheck — the module registration loop inIFrameNavigatorcheckedinstanceof TTSModule2twice in a row. Removed the dead duplicate. for...inon array — the module registration loop usedfor (const index in modules)which is an anti-pattern for arrays (iterates string keys, can pick up prototype properties). Replaced withfor...ofwith an earlycontinueguard for undefined entries.modulesarray typed as non-nullable —IFrameNavigatorConfig.moduleswasReaderModule[]but the array passed fromreader.tscontainedundefinedentries for disabled modules. Corrected type toArray<ReaderModule | undefined>.getTemporarySelectionInfonull-safety — callers passingiframes[0].contentDocument(which isDocument | null) now handled correctly.LocalAnnotatorreturnsnullwhendocis null; all call sites coercenulltoundefinedvia?? undefined.element?.scrollIntoView—AnnotationModule.scrollToHighlightcalled.scrollIntoView()unconditionally on a potentially null element returned bygetAnnotationElement. Added optional chaining.TTSModule2— guardselectionInfobeforeaddRange—selectionInfo.rangewas accessed without a null check after the result ofgetTemporarySelectionInfo. Addedif (selectionInfo?.range)guard.saveTemporarySelectionInfocalled with undefined —TextHighlightercould callsaveTemporarySelectionInfo(selectionInfo)whenselectionInfoisundefined. Added explicit guard.- Viewport meta parsing
@ts-ignore— replaced@ts-ignorein fixed-layout viewport dimension parsing with a proper typedRecord<string, number | string>approach and null-safe destructuring.
- Bumped version to 2.5.0 as the baseline for the v2.5 milestone
- Fixed
package.jsondependency classification:- Moved
@types/sass,@types/pdfjs-dist,sass,@babel/plugin-proposal-private-property-in-objectfromdependencies→devDependencies(build-time only) - Moved
ta-json-xfromdevDependencies→dependencies(used in production code:Publication,Link,JsonUtil)
- Moved
- Updated esbuild browser targets from 2021-era (
chrome89/firefox88/safari14/edge90) to 2025 baseline (chrome109/firefox115/safari16/edge109) - Replaced
arguments[0], arguments[1]anti-pattern inD2Reader.addEventListener()with typed parameters - Removed jQuery type dependency from
IFrameNavigator— replacedJQuery.KeyDownEventwith standard DOMKeyboardEvent - Improved
Navigatorinterface: replaced allanytypes with proper TypeScript types - Improved
NavigatorAPIinterface: all fields now have proper callback signatures;updateSettingsandupdateCurrentLocationcorrectly typed as returningPromise<void> - Improved
ReaderConfiginterface:publication,userSettings,initialAnnotations,lastReadingPositionnow properly typed; newInitialAnnotationsinterface exported - Added
stop(): voidtoReaderModuleinterface — enforced what all 14 modules already implemented UserSettingsConfig.initialUserSettingsmade optional (it was already handled as optional at runtime)LocalStorageStoreConfig.prefixnow acceptsstring | URL(URL is coerced via.toString())Annotatorinterface: allanytypes replaced with properBookmark,Annotation,ISelectionInfo,Window,Documenttypespositions()return type inIFrameNavigatorchanged fromanytoLocator[]- Expanded
index.tspublic API exports: addedBookmark,Annotation,AnnotationMarker,Locations,LocatorText,ReaderConfig,ReaderRights,NavigatorAPI,IFrameAttributes,Injectable,RequestConfig,SampleRead,PublicationServices,InitialAnnotations,InitialUserSettings,LocalStorageStoreConfig
- Removed polyfill.io script from sample viewer (
viewer/index_dita.html) — replaced with direct MathJax 3 CDN inclusion
- Dependency updates via Dependabot (sass, @babel/helpers, image-size, base-x)
currentSettingsis now a property, so you don't call it as a function.- The default export is now a class which you instantiate with
.build, and then call all API methods on the returned instance