@readium/navigator 2.4.0 → 2.5.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ReadiumCSS-after-B_e3a-PY.js +592 -0
- package/dist/ReadiumCSS-after-C-T_0paD.js +530 -0
- package/dist/ReadiumCSS-after-lr-n3fz2.js +475 -0
- package/dist/ReadiumCSS-after-mXeKKPap.js +490 -0
- package/dist/ReadiumCSS-before-Bjd3POej.js +426 -0
- package/dist/ReadiumCSS-before-CfXPAGaQ.js +425 -0
- package/dist/ReadiumCSS-before-CrNWvuyE.js +425 -0
- package/dist/ReadiumCSS-before-KVen5ceo.js +425 -0
- package/dist/ReadiumCSS-default-BKAG5pGU.js +162 -0
- package/dist/ReadiumCSS-default-C63bYOYF.js +183 -0
- package/dist/ReadiumCSS-default-CclvbeNC.js +162 -0
- package/dist/ReadiumCSS-default-DnlgDaBu.js +180 -0
- package/dist/ReadiumCSS-ebpaj_fonts_patch-Dt2XliTg.js +82 -0
- package/dist/index.js +2267 -3201
- package/dist/index.umd.cjs +4432 -1083
- package/package.json +1 -1
- package/src/audio/index.ts +1 -1
- package/src/epub/EpubNavigator.ts +66 -31
- package/src/epub/frame/FrameBlobBuilder.ts +23 -22
- package/src/epub/frame/FrameManager.ts +4 -0
- package/src/epub/fxl/FXLFramePoolManager.ts +5 -1
- package/src/epub/helpers/scriptMode.ts +45 -0
- package/src/epub/index.ts +1 -0
- package/src/injection/epubInjectables.ts +78 -9
- package/src/injection/webpubInjectables.ts +1 -1
- package/types/src/epub/EpubNavigator.d.ts +4 -3
- package/types/src/epub/frame/FrameManager.d.ts +1 -0
- package/types/src/epub/helpers/scriptMode.d.ts +16 -0
- package/types/src/epub/index.d.ts +1 -0
- package/types/src/injection/epubInjectables.d.ts +4 -2
- package/types/src/injection/webpubInjectables.d.ts +1 -1
package/package.json
CHANGED
package/src/audio/index.ts
CHANGED
|
@@ -2,8 +2,7 @@ import { Layout, Link, Locator, Profile, Publication, ReadingProgression } from
|
|
|
2
2
|
import { Configurable, ConfigurableSettings, LineLengths, ProgressionRange, VisualNavigator, VisualNavigatorViewport } from "../index.ts";
|
|
3
3
|
import { FramePoolManager } from "./frame/FramePoolManager.ts";
|
|
4
4
|
import { FXLFramePoolManager } from "./fxl/FXLFramePoolManager.ts";
|
|
5
|
-
import { CommsEventKey, ContextMenuEvent, FXLModules, KeyboardEventData, ModuleLibrary, ModuleName, ReflowableModules } from "@readium/navigator-html-injectables";
|
|
6
|
-
import { BasicTextSelection, FrameClickEvent, SuspiciousActivityEvent } from "@readium/navigator-html-injectables";
|
|
5
|
+
import { CommsEventKey, ContextMenuEvent, FXLModules, KeyboardEventData, ModuleLibrary, ModuleName, ReflowableModules, BasicTextSelection, FrameClickEvent, SuspiciousActivityEvent } from "@readium/navigator-html-injectables";
|
|
7
6
|
import * as path from "path-browserify";
|
|
8
7
|
import { FXLFrameManager } from "./fxl/FXLFrameManager.ts";
|
|
9
8
|
import { FrameManager } from "./frame/FrameManager.ts";
|
|
@@ -16,10 +15,11 @@ import { RSProperties, UserProperties } from "./css/Properties.ts";
|
|
|
16
15
|
import { getContentWidth } from "../helpers/dimensions.ts";
|
|
17
16
|
import { Injector } from "../injection/Injector.ts";
|
|
18
17
|
import { createReadiumEpubRules } from "../injection/epubInjectables.ts";
|
|
19
|
-
import { IInjectablesConfig } from "../injection/Injectable.ts";
|
|
18
|
+
import { IInjectableRule, IInjectablesConfig } from "../injection/Injectable.ts";
|
|
20
19
|
import { IContentProtectionConfig, IKeyboardPeripheralsConfig } from "../Navigator.ts";
|
|
21
20
|
import { NavigatorProtector, NAVIGATOR_SUSPICIOUS_ACTIVITY_EVENT } from "../protection/NavigatorProtector.ts";
|
|
22
21
|
import { KeyboardPeripherals, NAVIGATOR_KEYBOARD_PERIPHERAL_EVENT } from "../peripherals/KeyboardPeripherals.ts";
|
|
22
|
+
import { getScriptMode } from "./helpers/scriptMode.ts";
|
|
23
23
|
|
|
24
24
|
export type ManagerEventKey = "zoom";
|
|
25
25
|
|
|
@@ -80,7 +80,9 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
80
80
|
private _settings: EpubSettings;
|
|
81
81
|
private _css: ReadiumCSS;
|
|
82
82
|
private _preferencesEditor: EpubPreferencesEditor | null = null;
|
|
83
|
-
private
|
|
83
|
+
private _injector: Injector | null = null;
|
|
84
|
+
private readonly _readiumRulesPromise: Promise<IInjectableRule[]>;
|
|
85
|
+
private readonly _injectablesConfig: IInjectablesConfig;
|
|
84
86
|
private readonly _contentProtection: IContentProtectionConfig;
|
|
85
87
|
private readonly _keyboardPeripherals: IKeyboardPeripheralsConfig;
|
|
86
88
|
private readonly _navigatorProtector: NavigatorProtector | null = null;
|
|
@@ -108,8 +110,14 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
108
110
|
this._preferences = new EpubPreferences(configuration.preferences);
|
|
109
111
|
this._defaults = new EpubDefaults(configuration.defaults);
|
|
110
112
|
this._settings = new EpubSettings(this._preferences, this._defaults);
|
|
113
|
+
// For CJK vertical, force --RS__disablePagination for the entire session.
|
|
114
|
+
// ReadiumCSS.update() never sets noVerticalPagination, so this persists.
|
|
115
|
+
const scriptMode = getScriptMode(pub.metadata);
|
|
116
|
+
const isCJKHorizontal = scriptMode === 'cjk-horizontal';
|
|
117
|
+
const isCJKVertical = scriptMode === 'cjk-vertical';
|
|
118
|
+
const isCJK = isCJKHorizontal || isCJKVertical;
|
|
111
119
|
this._css = new ReadiumCSS({
|
|
112
|
-
rsProperties: new RSProperties({}),
|
|
120
|
+
rsProperties: new RSProperties({ noVerticalPagination: isCJKVertical || undefined }),
|
|
113
121
|
userProperties: new UserProperties({}),
|
|
114
122
|
lineLengths: new LineLengths({
|
|
115
123
|
optimalChars: this._settings.optimalLineLength,
|
|
@@ -121,6 +129,7 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
121
129
|
fontFace: this._settings.fontFamily,
|
|
122
130
|
letterSpacing: this._settings.letterSpacing,
|
|
123
131
|
wordSpacing: this._settings.wordSpacing,
|
|
132
|
+
isCJK: isCJK,
|
|
124
133
|
// sample: this.pub.metadata.description
|
|
125
134
|
}),
|
|
126
135
|
container: container,
|
|
@@ -130,14 +139,13 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
130
139
|
this._layout = EpubNavigator.determineLayout(pub, !!this._settings.scroll);
|
|
131
140
|
this.currentProgression = pub.metadata.effectiveReadingProgression;
|
|
132
141
|
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
});
|
|
142
|
+
// Store user injectables config; Injector is created in load() once
|
|
143
|
+
// the async CSS rules promise has resolved.
|
|
144
|
+
this._injectablesConfig = configuration.injectables || { rules: [], allowedDomains: [] };
|
|
145
|
+
// Start loading Readium CSS rules asynchronously. The promise is
|
|
146
|
+
// awaited in load() before the Injector is created, ensuring the
|
|
147
|
+
// correct script-mode stylesheets are ready before the first frame.
|
|
148
|
+
this._readiumRulesPromise = createReadiumEpubRules(pub.metadata, pub.readingOrder.items);
|
|
141
149
|
|
|
142
150
|
this._contentProtection = configuration.contentProtection || {};
|
|
143
151
|
|
|
@@ -201,6 +209,11 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
201
209
|
if (layout === Layout.scrolled)
|
|
202
210
|
return Layout.scrolled;
|
|
203
211
|
|
|
212
|
+
// CJK vertical writing: force scroll mode so the ScrollSnapper is
|
|
213
|
+
// used and column-based pagination doesn't interfere.
|
|
214
|
+
if (getScriptMode(pub.metadata) === 'cjk-vertical')
|
|
215
|
+
return Layout.scrolled;
|
|
216
|
+
|
|
204
217
|
if (layout === Layout.reflowable && scroll)
|
|
205
218
|
return Layout.scrolled;
|
|
206
219
|
|
|
@@ -210,6 +223,17 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
210
223
|
public async load() {
|
|
211
224
|
if (!this.positions?.length)
|
|
212
225
|
this.positions = await this.pub.positionsFromManifest();
|
|
226
|
+
|
|
227
|
+
// Build Injector now that async CSS loading has had time to resolve.
|
|
228
|
+
// (Started in the constructor, so this typically resolves immediately.)
|
|
229
|
+
if (!this._injector) {
|
|
230
|
+
const readiumRules = await this._readiumRulesPromise;
|
|
231
|
+
this._injector = new Injector({
|
|
232
|
+
rules: [...readiumRules, ...this._injectablesConfig.rules],
|
|
233
|
+
allowedDomains: this._injectablesConfig.allowedDomains
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
213
237
|
if(this._layout === Layout.fixed) {
|
|
214
238
|
this.framePool = new FXLFramePoolManager(
|
|
215
239
|
this.container,
|
|
@@ -312,6 +336,10 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
312
336
|
}
|
|
313
337
|
|
|
314
338
|
private async commitCSS(css: ReadiumCSS) {
|
|
339
|
+
// framePool is only available after load() — guard against early calls
|
|
340
|
+
// from the ResizeObserver which is registered in the constructor.
|
|
341
|
+
if (!this.framePool) return;
|
|
342
|
+
|
|
315
343
|
// Since we’re updating the CSS properties in injectables by removing
|
|
316
344
|
// the existing properties that are not inside this object first,
|
|
317
345
|
// then adding all from it, we don’t compare the previous properties here
|
|
@@ -341,6 +369,7 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
341
369
|
|
|
342
370
|
if (this._layout === Layout.fixed) {
|
|
343
371
|
this.container.style.width = `${ getContentWidth(parentEl) - this._settings.constraint }px`;
|
|
372
|
+
if (!this.framePool) return;
|
|
344
373
|
(this.framePool as FXLFramePoolManager).resizeHandler();
|
|
345
374
|
} else {
|
|
346
375
|
// for reflow ReadiumCSS gets the width from columns + line-lengths
|
|
@@ -371,7 +400,7 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
371
400
|
* TODO remove when settings management is incorporated
|
|
372
401
|
*/
|
|
373
402
|
public get _cframes(): (FXLFrameManager | FrameManager | undefined)[] {
|
|
374
|
-
return this.framePool.
|
|
403
|
+
return (this.framePool?.currentFrames ?? []).filter(f => !(f instanceof FrameManager && f.isDestroyed));
|
|
375
404
|
}
|
|
376
405
|
|
|
377
406
|
/**
|
|
@@ -524,12 +553,18 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
524
553
|
if(this._layout === Layout.fixed) {
|
|
525
554
|
return modules.filter((m) => FXLModules.includes(m));
|
|
526
555
|
} else modules = modules.filter((m) => ReflowableModules.includes(m));
|
|
556
|
+
|
|
557
|
+
// CJK vertical: uses its own X-axis snapper, never column or scroll snappers
|
|
558
|
+
if (getScriptMode(this.pub.metadata) === 'cjk-vertical') {
|
|
559
|
+
return modules.filter((m) => m !== "column_snapper" && m !== "scroll_snapper");
|
|
560
|
+
}
|
|
527
561
|
|
|
528
562
|
// Horizontal vs. Vertical reading
|
|
563
|
+
const all = modules as ModuleName[];
|
|
529
564
|
if (this._layout === Layout.scrolled)
|
|
530
|
-
modules =
|
|
565
|
+
modules = all.filter((m) => m !== "column_snapper" && m !== "cjk_vertical_snapper");
|
|
531
566
|
else
|
|
532
|
-
modules =
|
|
567
|
+
modules = all.filter((m) => m !== "scroll_snapper" && m !== "cjk_vertical_snapper");
|
|
533
568
|
|
|
534
569
|
return modules;
|
|
535
570
|
}
|
|
@@ -655,21 +690,19 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
655
690
|
let first = this.currentLocation;
|
|
656
691
|
let last = undefined;
|
|
657
692
|
|
|
658
|
-
// Find the last locator
|
|
659
|
-
//
|
|
660
|
-
potentialPositions.
|
|
693
|
+
// Find the last locator whose progression is <= fromProgression.start.
|
|
694
|
+
// potentialPositions is ordered by progression ascending (0 → 1).
|
|
695
|
+
const idx = potentialPositions.findLastIndex((p) => {
|
|
661
696
|
const pr = p.locations.progression ?? 0;
|
|
662
|
-
|
|
663
|
-
|
|
697
|
+
return pr <= fromProgression.start;
|
|
698
|
+
});
|
|
664
699
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
700
|
+
if (idx !== -1) {
|
|
701
|
+
first = potentialPositions[idx];
|
|
702
|
+
const nextPositions = potentialPositions.slice(idx + 1);
|
|
703
|
+
last = this.findLastPositionInProgressionRange(nextPositions, fromProgression);
|
|
704
|
+
}
|
|
668
705
|
|
|
669
|
-
return true;
|
|
670
|
-
}
|
|
671
|
-
else return false;
|
|
672
|
-
});
|
|
673
706
|
return { first: first, last: last }
|
|
674
707
|
}
|
|
675
708
|
|
|
@@ -749,9 +782,11 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
749
782
|
}
|
|
750
783
|
|
|
751
784
|
get viewport(): VisualNavigatorViewport {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
785
|
+
if (this._layout === Layout.fixed) {
|
|
786
|
+
if (!this.framePool) return { readingOrder: [], progressions: new Map(), positions: null };
|
|
787
|
+
return (this.framePool as FXLFramePoolManager).viewport;
|
|
788
|
+
}
|
|
789
|
+
return this.reflowViewport;
|
|
755
790
|
}
|
|
756
791
|
|
|
757
792
|
get isScrollStart(): boolean {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Link, MediaType, Publication } from "@readium/shared";
|
|
1
|
+
import { Link, MediaType, Publication, ReadingProgression } from "@readium/shared";
|
|
2
2
|
import { Injector } from "../../injection/Injector.ts";
|
|
3
|
+
import { getScriptMode } from "../helpers/scriptMode.ts";
|
|
3
4
|
|
|
4
5
|
const csp = (domains: string[]) => {
|
|
5
6
|
const d = domains.join(" ");
|
|
@@ -136,37 +137,37 @@ export default class FrameBlobBuider {
|
|
|
136
137
|
if (mediaType === MediaType.XHTML) {
|
|
137
138
|
// InDesign is infamous for setting xml:lang on the body instead of the root element
|
|
138
139
|
// So we have to check whether lang is set on the body and move it to the root element
|
|
139
|
-
const rootLang =
|
|
140
|
-
const bodyLang =
|
|
140
|
+
const rootLang = doc.documentElement.lang || doc.documentElement.getAttribute("xml:lang");
|
|
141
|
+
const bodyLang = doc.body.lang || doc.body.getAttribute("xml:lang");
|
|
141
142
|
if (bodyLang && !rootLang) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
doc.documentElement.lang = bodyLang;
|
|
144
|
+
doc.documentElement.setAttribute("xml:lang", bodyLang);
|
|
145
|
+
doc.body.removeAttribute("xml:lang");
|
|
146
|
+
doc.body.removeAttribute("lang");
|
|
146
147
|
} else if (!rootLang) {
|
|
147
|
-
|
|
148
|
-
|
|
148
|
+
doc.documentElement.lang = primaryLanguage;
|
|
149
|
+
doc.documentElement.setAttribute("xml:lang", primaryLanguage);
|
|
149
150
|
}
|
|
150
151
|
} else if (
|
|
151
152
|
mediaType === MediaType.HTML &&
|
|
152
|
-
!
|
|
153
|
+
!doc.documentElement.lang
|
|
153
154
|
) {
|
|
154
|
-
|
|
155
|
+
doc.documentElement.lang = primaryLanguage;
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
// https://github.com/readium/readium-css/blob/develop/docs/CSS03-injection_and_pagination.md#be-cautious-the-direction-propagates
|
|
161
|
-
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
!
|
|
166
|
-
|
|
159
|
+
// Set dir="rtl" on the root element for RTL publications if the author
|
|
160
|
+
// has not already declared a direction on html or body.
|
|
161
|
+
// See: https://github.com/readium/readium-css/blob/develop/docs/CSS03-injection_and_pagination.md#be-cautious-the-direction-propagates
|
|
162
|
+
// CJK modes must NEVER receive a dir attribute — writing-mode handles
|
|
163
|
+
// directionality visually, and dir="rtl" would break vertical layout.
|
|
164
|
+
const scriptMode = getScriptMode(this.pub.metadata);
|
|
165
|
+
if (scriptMode === "rtl" &&
|
|
166
|
+
!doc.documentElement.dir &&
|
|
167
|
+
!doc.body.dir
|
|
167
168
|
) {
|
|
168
|
-
|
|
169
|
-
}
|
|
169
|
+
doc.documentElement.dir = ReadingProgression.rtl;
|
|
170
|
+
}
|
|
170
171
|
|
|
171
172
|
if (base !== undefined) {
|
|
172
173
|
// Set all URL bases. Very convenient!
|
|
@@ -173,6 +173,10 @@ export class FrameManager {
|
|
|
173
173
|
return this.frame.getBoundingClientRect();
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
get isDestroyed() {
|
|
177
|
+
return this.destroyed;
|
|
178
|
+
}
|
|
179
|
+
|
|
176
180
|
get window() {
|
|
177
181
|
if(this.destroyed || !this.frame.contentWindow) throw Error("Trying to use frame window when it doesn't exist");
|
|
178
182
|
return this.frame.contentWindow;
|
|
@@ -633,7 +633,11 @@ export class FXLFramePoolManager {
|
|
|
633
633
|
progressions: new Map(),
|
|
634
634
|
positions: null
|
|
635
635
|
};
|
|
636
|
-
|
|
636
|
+
// Mirror currentFrames: for single-page mode use currentSlide directly,
|
|
637
|
+
// otherwise use the spreader (which indexes by spread, not by item).
|
|
638
|
+
const currentSpread = this.perPage < 2
|
|
639
|
+
? [this.pub.readingOrder.items[this.currentSlide]]
|
|
640
|
+
: this.spreader.currentSpread(this.currentSlide, this.perPage);
|
|
637
641
|
currentSpread.forEach(link => {
|
|
638
642
|
viewport.readingOrder.push(link.href);
|
|
639
643
|
viewport.progressions.set(link.href, { start: 0, end: 1 }); // FXL always uses [0,1] progression
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Metadata, ReadingProgression } from "@readium/shared";
|
|
2
|
+
|
|
3
|
+
export type ScriptMode = 'ltr' | 'rtl' | 'cjk-horizontal' | 'cjk-vertical';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Derives the script mode from publication metadata.
|
|
7
|
+
*
|
|
8
|
+
* Rules:
|
|
9
|
+
* - Only the first language in the array is used. A Latin book containing
|
|
10
|
+
* some Japanese is still Latin.
|
|
11
|
+
* - For CJK (zh/ja/ko): both language AND explicit reading progression are
|
|
12
|
+
* required. CJK vertical = explicit rtl + CJK language. CJK horizontal =
|
|
13
|
+
* CJK language with ltr or unset progression.
|
|
14
|
+
* - For RTL (ar/fa/he): language wins. If the primary language is a RTL
|
|
15
|
+
* script, RTL mode is applied regardless of the explicit progression
|
|
16
|
+
* direction declared in the OPF.
|
|
17
|
+
*/
|
|
18
|
+
export function getScriptMode(metadata: Metadata): ScriptMode {
|
|
19
|
+
const primaryLang = metadata.languages?.[0]?.toLowerCase();
|
|
20
|
+
// Use explicit readingProgression only — effectiveReadingProgression
|
|
21
|
+
// auto-detects from language, which would create circular logic here.
|
|
22
|
+
const progression = metadata.readingProgression;
|
|
23
|
+
|
|
24
|
+
if (primaryLang) {
|
|
25
|
+
const isCJK = primaryLang.startsWith('zh') ||
|
|
26
|
+
primaryLang.startsWith('ja') ||
|
|
27
|
+
primaryLang.startsWith('ko');
|
|
28
|
+
if (isCJK) {
|
|
29
|
+
// Vertical requires explicit rtl progression. If progression
|
|
30
|
+
// conflicts (e.g. ltr) we fall back to horizontal.
|
|
31
|
+
return progression === ReadingProgression.rtl
|
|
32
|
+
? 'cjk-vertical'
|
|
33
|
+
: 'cjk-horizontal';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// RTL: language is authoritative. ar/fa/he → rtl regardless of
|
|
37
|
+
// what the OPF says about page-progression-direction.
|
|
38
|
+
const isRTLScript = primaryLang.startsWith('ar') ||
|
|
39
|
+
primaryLang.startsWith('fa') ||
|
|
40
|
+
primaryLang.startsWith('he');
|
|
41
|
+
if (isRTLScript) return 'rtl';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return 'ltr';
|
|
45
|
+
}
|
package/src/epub/index.ts
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import { IInjectableRule, IInjectable } from "../injection/Injectable.ts";
|
|
2
2
|
import { stripJS, stripCSS } from "../helpers/minify.ts";
|
|
3
3
|
import { Metadata, Layout, Link } from "@readium/shared";
|
|
4
|
-
|
|
5
|
-
import readiumCSSAfter from "@readium/css/css/dist/ReadiumCSS-after.css?raw";
|
|
6
|
-
import readiumCSSBefore from "@readium/css/css/dist/ReadiumCSS-before.css?raw";
|
|
7
|
-
import readiumCSSDefault from "@readium/css/css/dist/ReadiumCSS-default.css?raw";
|
|
4
|
+
import { getScriptMode } from "../epub/helpers/scriptMode.ts";
|
|
8
5
|
|
|
9
6
|
import cssSelectorGeneratorContent from "../dom/_readium_cssSelectorGenerator.js?raw";
|
|
10
7
|
import executionPreventionContent from "../dom/_readium_executionPrevention.js?raw";
|
|
11
8
|
import onloadProxyContent from "../dom/_readium_executionCleanup.js?raw";
|
|
12
9
|
|
|
13
10
|
/**
|
|
14
|
-
* Creates injectable rules for EPUB content documents
|
|
11
|
+
* Creates injectable rules for EPUB content documents.
|
|
12
|
+
* Async so that script-specific Readium CSS stylesheets can be imported
|
|
13
|
+
* dynamically — only the variant that is actually needed is bundled.
|
|
15
14
|
*/
|
|
16
|
-
export function createReadiumEpubRules(metadata: Metadata, readingOrderItems: Link[]): IInjectableRule[] {
|
|
15
|
+
export async function createReadiumEpubRules(metadata: Metadata, readingOrderItems: Link[]): Promise<IInjectableRule[]> {
|
|
17
16
|
const isFixedLayout = metadata.effectiveLayout === Layout.fixed;
|
|
18
17
|
|
|
19
18
|
const htmlHrefs = readingOrderItems
|
|
@@ -57,12 +56,66 @@ export function createReadiumEpubRules(metadata: Metadata, readingOrderItems: Li
|
|
|
57
56
|
|
|
58
57
|
// Only add Readium CSS for reflowable documents
|
|
59
58
|
if (!isFixedLayout) {
|
|
59
|
+
const scriptMode = getScriptMode(metadata);
|
|
60
|
+
|
|
61
|
+
// Dynamically import only the CSS variant we need
|
|
62
|
+
let cssBeforeRaw: string;
|
|
63
|
+
let cssDefaultRaw: string;
|
|
64
|
+
let cssAfterRaw: string;
|
|
65
|
+
|
|
66
|
+
switch (scriptMode) {
|
|
67
|
+
case 'rtl': {
|
|
68
|
+
const [before, def, after] = await Promise.all([
|
|
69
|
+
import("@readium/css/css/dist/rtl/ReadiumCSS-before.css?raw"),
|
|
70
|
+
import("@readium/css/css/dist/rtl/ReadiumCSS-default.css?raw"),
|
|
71
|
+
import("@readium/css/css/dist/rtl/ReadiumCSS-after.css?raw"),
|
|
72
|
+
]);
|
|
73
|
+
cssBeforeRaw = before.default;
|
|
74
|
+
cssDefaultRaw = def.default;
|
|
75
|
+
cssAfterRaw = after.default;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case 'cjk-horizontal': {
|
|
79
|
+
const [before, def, after] = await Promise.all([
|
|
80
|
+
import("@readium/css/css/dist/cjk-horizontal/ReadiumCSS-before.css?raw"),
|
|
81
|
+
import("@readium/css/css/dist/cjk-horizontal/ReadiumCSS-default.css?raw"),
|
|
82
|
+
import("@readium/css/css/dist/cjk-horizontal/ReadiumCSS-after.css?raw"),
|
|
83
|
+
]);
|
|
84
|
+
cssBeforeRaw = before.default;
|
|
85
|
+
cssDefaultRaw = def.default;
|
|
86
|
+
cssAfterRaw = after.default;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
case 'cjk-vertical': {
|
|
90
|
+
const [before, def, after] = await Promise.all([
|
|
91
|
+
import("@readium/css/css/dist/cjk-vertical/ReadiumCSS-before.css?raw"),
|
|
92
|
+
import("@readium/css/css/dist/cjk-vertical/ReadiumCSS-default.css?raw"),
|
|
93
|
+
import("@readium/css/css/dist/cjk-vertical/ReadiumCSS-after.css?raw"),
|
|
94
|
+
]);
|
|
95
|
+
cssBeforeRaw = before.default;
|
|
96
|
+
cssDefaultRaw = def.default;
|
|
97
|
+
cssAfterRaw = after.default;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
default: {
|
|
101
|
+
const [before, def, after] = await Promise.all([
|
|
102
|
+
import("@readium/css/css/dist/ReadiumCSS-before.css?raw"),
|
|
103
|
+
import("@readium/css/css/dist/ReadiumCSS-default.css?raw"),
|
|
104
|
+
import("@readium/css/css/dist/ReadiumCSS-after.css?raw"),
|
|
105
|
+
]);
|
|
106
|
+
cssBeforeRaw = before.default;
|
|
107
|
+
cssDefaultRaw = def.default;
|
|
108
|
+
cssAfterRaw = after.default;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
60
113
|
// Readium CSS Before - prepended for reflowable
|
|
61
114
|
prependInjectables.unshift({
|
|
62
115
|
id: "readium-css-before",
|
|
63
116
|
as: "link",
|
|
64
117
|
target: "head",
|
|
65
|
-
blob: new Blob([stripCSS(
|
|
118
|
+
blob: new Blob([stripCSS(cssBeforeRaw)], { type: "text/css" }),
|
|
66
119
|
rel: "stylesheet"
|
|
67
120
|
});
|
|
68
121
|
|
|
@@ -73,7 +126,7 @@ export function createReadiumEpubRules(metadata: Metadata, readingOrderItems: Li
|
|
|
73
126
|
id: "readium-css-default",
|
|
74
127
|
as: "link",
|
|
75
128
|
target: "head",
|
|
76
|
-
blob: new Blob([stripCSS(
|
|
129
|
+
blob: new Blob([stripCSS(cssDefaultRaw)], { type: "text/css" }),
|
|
77
130
|
rel: "stylesheet",
|
|
78
131
|
condition: (doc: Document) => !(doc.querySelector("link[rel='stylesheet']") || doc.querySelector("style") || doc.querySelector("[style]:not([style=''])"))
|
|
79
132
|
},
|
|
@@ -82,10 +135,26 @@ export function createReadiumEpubRules(metadata: Metadata, readingOrderItems: Li
|
|
|
82
135
|
id: "readium-css-after",
|
|
83
136
|
as: "link",
|
|
84
137
|
target: "head",
|
|
85
|
-
blob: new Blob([stripCSS(
|
|
138
|
+
blob: new Blob([stripCSS(cssAfterRaw)], { type: "text/css" }),
|
|
86
139
|
rel: "stylesheet"
|
|
87
140
|
}
|
|
88
141
|
);
|
|
142
|
+
|
|
143
|
+
// EBPAJ fonts polyfill — CJK only, when EBPAJ metadata is present
|
|
144
|
+
if (scriptMode === 'cjk-horizontal' || scriptMode === 'cjk-vertical') {
|
|
145
|
+
const isEBPAJ = metadata.description === "ebpaj-guide-1.0" ||
|
|
146
|
+
metadata.otherMetadata?.["ebpaj:guide-version"] !== undefined;
|
|
147
|
+
if (isEBPAJ) {
|
|
148
|
+
const { default: ebpajRaw } = await import("@readium/css/css/dist/ReadiumCSS-ebpaj_fonts_patch.css?raw");
|
|
149
|
+
appendInjectables.push({
|
|
150
|
+
id: "readium-css-ebpaj",
|
|
151
|
+
as: "link",
|
|
152
|
+
target: "head",
|
|
153
|
+
blob: new Blob([stripCSS(ebpajRaw)], { type: "text/css" }),
|
|
154
|
+
rel: "stylesheet"
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
89
158
|
}
|
|
90
159
|
|
|
91
160
|
return [
|
|
@@ -2,8 +2,7 @@ import { Layout, Link, Locator, Publication, ReadingProgression } from "@readium
|
|
|
2
2
|
import { Configurable, ConfigurableSettings, VisualNavigator, VisualNavigatorViewport } from "../index.ts";
|
|
3
3
|
import { FramePoolManager } from "./frame/FramePoolManager.ts";
|
|
4
4
|
import { FXLFramePoolManager } from "./fxl/FXLFramePoolManager.ts";
|
|
5
|
-
import { CommsEventKey, ContextMenuEvent, KeyboardEventData } from "@readium/navigator-html-injectables";
|
|
6
|
-
import { BasicTextSelection, FrameClickEvent, SuspiciousActivityEvent } from "@readium/navigator-html-injectables";
|
|
5
|
+
import { CommsEventKey, ContextMenuEvent, KeyboardEventData, BasicTextSelection, FrameClickEvent, SuspiciousActivityEvent } from "@readium/navigator-html-injectables";
|
|
7
6
|
import { FXLFrameManager } from "./fxl/FXLFrameManager.ts";
|
|
8
7
|
import { FrameManager } from "./frame/FrameManager.ts";
|
|
9
8
|
import { IEpubPreferences, EpubPreferences } from "./preferences/EpubPreferences.ts";
|
|
@@ -50,7 +49,9 @@ export declare class EpubNavigator extends VisualNavigator implements Configurab
|
|
|
50
49
|
private _settings;
|
|
51
50
|
private _css;
|
|
52
51
|
private _preferencesEditor;
|
|
53
|
-
private
|
|
52
|
+
private _injector;
|
|
53
|
+
private readonly _readiumRulesPromise;
|
|
54
|
+
private readonly _injectablesConfig;
|
|
54
55
|
private readonly _contentProtection;
|
|
55
56
|
private readonly _keyboardPeripherals;
|
|
56
57
|
private readonly _navigatorProtector;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Metadata } from "@readium/shared";
|
|
2
|
+
export type ScriptMode = 'ltr' | 'rtl' | 'cjk-horizontal' | 'cjk-vertical';
|
|
3
|
+
/**
|
|
4
|
+
* Derives the script mode from publication metadata.
|
|
5
|
+
*
|
|
6
|
+
* Rules:
|
|
7
|
+
* - Only the first language in the array is used. A Latin book containing
|
|
8
|
+
* some Japanese is still Latin.
|
|
9
|
+
* - For CJK (zh/ja/ko): both language AND explicit reading progression are
|
|
10
|
+
* required. CJK vertical = explicit rtl + CJK language. CJK horizontal =
|
|
11
|
+
* CJK language with ltr or unset progression.
|
|
12
|
+
* - For RTL (ar/fa/he): language wins. If the primary language is a RTL
|
|
13
|
+
* script, RTL mode is applied regardless of the explicit progression
|
|
14
|
+
* direction declared in the OPF.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getScriptMode(metadata: Metadata): ScriptMode;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { IInjectableRule } from "../injection/Injectable.ts";
|
|
2
2
|
import { Metadata, Link } from "@readium/shared";
|
|
3
3
|
/**
|
|
4
|
-
* Creates injectable rules for EPUB content documents
|
|
4
|
+
* Creates injectable rules for EPUB content documents.
|
|
5
|
+
* Async so that script-specific Readium CSS stylesheets can be imported
|
|
6
|
+
* dynamically — only the variant that is actually needed is bundled.
|
|
5
7
|
*/
|
|
6
|
-
export declare function createReadiumEpubRules(metadata: Metadata, readingOrderItems: Link[]): IInjectableRule[]
|
|
8
|
+
export declare function createReadiumEpubRules(metadata: Metadata, readingOrderItems: Link[]): Promise<IInjectableRule[]>;
|