@readium/navigator 2.4.0-beta.9 → 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.
Files changed (138) hide show
  1. package/dist/ReadiumCSS-after-B_e3a-PY.js +592 -0
  2. package/dist/ReadiumCSS-after-C-T_0paD.js +530 -0
  3. package/dist/ReadiumCSS-after-lr-n3fz2.js +475 -0
  4. package/dist/ReadiumCSS-after-mXeKKPap.js +490 -0
  5. package/dist/ReadiumCSS-before-Bjd3POej.js +426 -0
  6. package/dist/ReadiumCSS-before-CfXPAGaQ.js +425 -0
  7. package/dist/ReadiumCSS-before-CrNWvuyE.js +425 -0
  8. package/dist/ReadiumCSS-before-KVen5ceo.js +425 -0
  9. package/dist/ReadiumCSS-default-BKAG5pGU.js +162 -0
  10. package/dist/ReadiumCSS-default-C63bYOYF.js +183 -0
  11. package/dist/ReadiumCSS-default-CclvbeNC.js +162 -0
  12. package/dist/ReadiumCSS-default-DnlgDaBu.js +180 -0
  13. package/dist/ReadiumCSS-ebpaj_fonts_patch-Dt2XliTg.js +82 -0
  14. package/dist/index.js +2642 -3430
  15. package/dist/index.umd.cjs +4407 -995
  16. package/package.json +2 -2
  17. package/src/audio/AudioNavigator.ts +155 -42
  18. package/src/audio/AudioPoolManager.ts +27 -14
  19. package/src/audio/engine/AudioEngine.ts +4 -3
  20. package/src/audio/engine/PreservePitchProcessor.js +166 -101
  21. package/src/audio/engine/PreservePitchWorklet.ts +2 -17
  22. package/src/audio/engine/WebAudioEngine.ts +138 -160
  23. package/src/audio/engine/index.ts +2 -2
  24. package/src/audio/index.ts +3 -3
  25. package/src/audio/preferences/AudioDefaults.ts +2 -2
  26. package/src/audio/preferences/AudioPreferences.ts +11 -11
  27. package/src/audio/preferences/AudioPreferencesEditor.ts +13 -13
  28. package/src/audio/preferences/AudioSettings.ts +3 -3
  29. package/src/audio/preferences/index.ts +4 -4
  30. package/src/audio/protection/AudioNavigatorProtector.ts +4 -4
  31. package/src/css/index.ts +1 -1
  32. package/src/epub/EpubNavigator.ts +113 -78
  33. package/src/epub/css/Properties.ts +15 -15
  34. package/src/epub/css/ReadiumCSS.ts +43 -43
  35. package/src/epub/css/index.ts +2 -2
  36. package/src/epub/frame/FrameBlobBuilder.ts +31 -31
  37. package/src/epub/frame/FrameComms.ts +1 -1
  38. package/src/epub/frame/FrameManager.ts +13 -9
  39. package/src/epub/frame/FramePoolManager.ts +13 -13
  40. package/src/epub/frame/index.ts +4 -4
  41. package/src/epub/fxl/FXLCoordinator.ts +3 -3
  42. package/src/epub/fxl/FXLFrameManager.ts +8 -8
  43. package/src/epub/fxl/FXLFramePoolManager.ts +18 -14
  44. package/src/epub/fxl/FXLPeripherals.ts +4 -4
  45. package/src/epub/fxl/index.ts +5 -5
  46. package/src/epub/helpers/scriptMode.ts +45 -0
  47. package/src/epub/index.ts +6 -5
  48. package/src/epub/preferences/EpubDefaults.ts +23 -23
  49. package/src/epub/preferences/EpubPreferences.ts +16 -16
  50. package/src/epub/preferences/EpubPreferencesEditor.ts +53 -53
  51. package/src/epub/preferences/EpubSettings.ts +101 -101
  52. package/src/epub/preferences/index.ts +4 -4
  53. package/src/helpers/index.ts +2 -2
  54. package/src/index.ts +8 -8
  55. package/src/injection/Injector.ts +42 -42
  56. package/src/injection/epubInjectables.ts +86 -17
  57. package/src/injection/index.ts +2 -2
  58. package/src/injection/webpubInjectables.ts +2 -2
  59. package/src/preferences/Configurable.ts +2 -2
  60. package/src/preferences/PreferencesEditor.ts +2 -2
  61. package/src/preferences/guards.ts +2 -2
  62. package/src/preferences/index.ts +5 -5
  63. package/src/protection/CopyProtector.ts +5 -1
  64. package/src/protection/DevToolsDetector.ts +16 -16
  65. package/src/protection/DragAndDropProtector.ts +14 -1
  66. package/src/protection/NavigatorProtector.ts +6 -6
  67. package/src/webpub/WebPubBlobBuilder.ts +1 -1
  68. package/src/webpub/WebPubFrameManager.ts +8 -8
  69. package/src/webpub/WebPubFramePoolManager.ts +7 -7
  70. package/src/webpub/WebPubNavigator.ts +27 -27
  71. package/src/webpub/css/Properties.ts +3 -3
  72. package/src/webpub/css/WebPubCSS.ts +11 -11
  73. package/src/webpub/css/index.ts +2 -2
  74. package/src/webpub/index.ts +6 -6
  75. package/src/webpub/preferences/WebPubDefaults.ts +12 -12
  76. package/src/webpub/preferences/WebPubPreferences.ts +8 -8
  77. package/src/webpub/preferences/WebPubPreferencesEditor.ts +31 -31
  78. package/src/webpub/preferences/WebPubSettings.ts +45 -45
  79. package/src/webpub/preferences/index.ts +4 -4
  80. package/types/src/audio/AudioNavigator.d.ts +34 -5
  81. package/types/src/audio/AudioPoolManager.d.ts +7 -4
  82. package/types/src/audio/engine/AudioEngine.d.ts +4 -3
  83. package/types/src/audio/engine/PreservePitchWorklet.d.ts +1 -4
  84. package/types/src/audio/engine/WebAudioEngine.d.ts +15 -9
  85. package/types/src/audio/engine/index.d.ts +2 -2
  86. package/types/src/audio/index.d.ts +3 -3
  87. package/types/src/audio/preferences/AudioPreferences.d.ts +9 -9
  88. package/types/src/audio/preferences/AudioPreferencesEditor.d.ts +4 -4
  89. package/types/src/audio/preferences/AudioSettings.d.ts +3 -3
  90. package/types/src/audio/preferences/index.d.ts +4 -4
  91. package/types/src/audio/protection/AudioNavigatorProtector.d.ts +2 -2
  92. package/types/src/css/index.d.ts +1 -1
  93. package/types/src/epub/EpubNavigator.d.ts +15 -14
  94. package/types/src/epub/css/Properties.d.ts +2 -2
  95. package/types/src/epub/css/ReadiumCSS.d.ts +3 -3
  96. package/types/src/epub/css/index.d.ts +2 -2
  97. package/types/src/epub/frame/FrameBlobBuilder.d.ts +1 -1
  98. package/types/src/epub/frame/FrameComms.d.ts +1 -1
  99. package/types/src/epub/frame/FrameManager.d.ts +3 -2
  100. package/types/src/epub/frame/FramePoolManager.d.ts +3 -3
  101. package/types/src/epub/frame/index.d.ts +4 -4
  102. package/types/src/epub/fxl/FXLFrameManager.d.ts +3 -3
  103. package/types/src/epub/fxl/FXLFramePoolManager.d.ts +5 -5
  104. package/types/src/epub/fxl/FXLPeripherals.d.ts +2 -2
  105. package/types/src/epub/fxl/index.d.ts +5 -5
  106. package/types/src/epub/helpers/scriptMode.d.ts +16 -0
  107. package/types/src/epub/index.d.ts +6 -5
  108. package/types/src/epub/preferences/EpubDefaults.d.ts +1 -1
  109. package/types/src/epub/preferences/EpubPreferences.d.ts +2 -2
  110. package/types/src/epub/preferences/EpubPreferencesEditor.d.ts +5 -5
  111. package/types/src/epub/preferences/EpubSettings.d.ts +4 -4
  112. package/types/src/epub/preferences/index.d.ts +4 -4
  113. package/types/src/helpers/index.d.ts +2 -2
  114. package/types/src/index.d.ts +8 -8
  115. package/types/src/injection/Injector.d.ts +1 -1
  116. package/types/src/injection/epubInjectables.d.ts +5 -3
  117. package/types/src/injection/index.d.ts +2 -2
  118. package/types/src/injection/webpubInjectables.d.ts +1 -1
  119. package/types/src/preferences/Configurable.d.ts +1 -1
  120. package/types/src/preferences/PreferencesEditor.d.ts +1 -1
  121. package/types/src/preferences/guards.d.ts +1 -1
  122. package/types/src/preferences/index.d.ts +5 -5
  123. package/types/src/protection/CopyProtector.d.ts +1 -0
  124. package/types/src/protection/DragAndDropProtector.d.ts +2 -0
  125. package/types/src/protection/NavigatorProtector.d.ts +1 -1
  126. package/types/src/webpub/WebPubBlobBuilder.d.ts +1 -1
  127. package/types/src/webpub/WebPubFrameManager.d.ts +2 -2
  128. package/types/src/webpub/WebPubFramePoolManager.d.ts +3 -3
  129. package/types/src/webpub/WebPubNavigator.d.ts +10 -10
  130. package/types/src/webpub/css/Properties.d.ts +2 -2
  131. package/types/src/webpub/css/WebPubCSS.d.ts +2 -2
  132. package/types/src/webpub/css/index.d.ts +2 -2
  133. package/types/src/webpub/index.d.ts +6 -6
  134. package/types/src/webpub/preferences/WebPubDefaults.d.ts +1 -1
  135. package/types/src/webpub/preferences/WebPubPreferences.d.ts +2 -2
  136. package/types/src/webpub/preferences/WebPubPreferencesEditor.d.ts +5 -5
  137. package/types/src/webpub/preferences/WebPubSettings.d.ts +4 -4
  138. package/types/src/webpub/preferences/index.d.ts +4 -4
@@ -1,25 +1,25 @@
1
1
  import { Layout, Link, Locator, Profile, Publication, ReadingProgression } from "@readium/shared";
2
- import { Configurable, ConfigurableSettings, LineLengths, ProgressionRange, VisualNavigator, VisualNavigatorViewport } from "../";
3
- import { FramePoolManager } from "./frame/FramePoolManager";
4
- import { FXLFramePoolManager } from "./fxl/FXLFramePoolManager";
5
- import { CommsEventKey, ContextMenuEvent, FXLModules, KeyboardEventData, ModuleLibrary, ModuleName, ReflowableModules } from "@readium/navigator-html-injectables";
6
- import { BasicTextSelection, FrameClickEvent, SuspiciousActivityEvent } from "@readium/navigator-html-injectables";
2
+ import { Configurable, ConfigurableSettings, LineLengths, ProgressionRange, VisualNavigator, VisualNavigatorViewport } from "../index.ts";
3
+ import { FramePoolManager } from "./frame/FramePoolManager.ts";
4
+ import { FXLFramePoolManager } from "./fxl/FXLFramePoolManager.ts";
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
- import { FXLFrameManager } from "./fxl/FXLFrameManager";
9
- import { FrameManager } from "./frame/FrameManager";
10
- import { IEpubPreferences, EpubPreferences } from "./preferences/EpubPreferences";
11
- import { IEpubDefaults, EpubDefaults } from "./preferences/EpubDefaults";
12
- import { EpubSettings } from "./preferences";
13
- import { EpubPreferencesEditor } from "./preferences/EpubPreferencesEditor";
14
- import { ReadiumCSS } from "./css/ReadiumCSS";
15
- import { RSProperties, UserProperties } from "./css/Properties";
16
- import { getContentWidth } from "../helpers/dimensions";
17
- import { Injector } from "../injection/Injector";
18
- import { createReadiumEpubRules } from "../injection/epubInjectables";
19
- import { IInjectablesConfig } from "../injection/Injectable";
20
- import { IContentProtectionConfig, IKeyboardPeripheralsConfig } from "../Navigator";
21
- import { NavigatorProtector, NAVIGATOR_SUSPICIOUS_ACTIVITY_EVENT } from "../protection/NavigatorProtector";
22
- import { KeyboardPeripherals, NAVIGATOR_KEYBOARD_PERIPHERAL_EVENT } from "../peripherals/KeyboardPeripherals";
7
+ import { FXLFrameManager } from "./fxl/FXLFrameManager.ts";
8
+ import { FrameManager } from "./frame/FrameManager.ts";
9
+ import { IEpubPreferences, EpubPreferences } from "./preferences/EpubPreferences.ts";
10
+ import { IEpubDefaults, EpubDefaults } from "./preferences/EpubDefaults.ts";
11
+ import { EpubSettings } from "./preferences/index.ts";
12
+ import { EpubPreferencesEditor } from "./preferences/EpubPreferencesEditor.ts";
13
+ import { ReadiumCSS } from "./css/ReadiumCSS.ts";
14
+ import { RSProperties, UserProperties } from "./css/Properties.ts";
15
+ import { getContentWidth } from "../helpers/dimensions.ts";
16
+ import { Injector } from "../injection/Injector.ts";
17
+ import { createReadiumEpubRules } from "../injection/epubInjectables.ts";
18
+ import { IInjectableRule, IInjectablesConfig } from "../injection/Injectable.ts";
19
+ import { IContentProtectionConfig, IKeyboardPeripheralsConfig } from "../Navigator.ts";
20
+ import { NavigatorProtector, NAVIGATOR_SUSPICIOUS_ACTIVITY_EVENT } from "../protection/NavigatorProtector.ts";
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 readonly _injector: Injector | null = null;
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,19 +110,26 @@ 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);
111
- this._css = new ReadiumCSS({
112
- rsProperties: new RSProperties({}),
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;
119
+ this._css = new ReadiumCSS({
120
+ rsProperties: new RSProperties({ noVerticalPagination: isCJKVertical || undefined }),
113
121
  userProperties: new UserProperties({}),
114
122
  lineLengths: new LineLengths({
115
123
  optimalChars: this._settings.optimalLineLength,
116
124
  minChars: this._settings.minimalLineLength,
117
125
  maxChars: this._settings.maximalLineLength,
118
- padding: this._settings.scroll
126
+ padding: this._settings.scroll
119
127
  ? (this._settings.scrollPaddingLeft || 0) + (this._settings.scrollPaddingRight || 0)
120
128
  : (this._settings.pageGutter || 0) * 2,
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,
@@ -129,24 +138,23 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
129
138
 
130
139
  this._layout = EpubNavigator.determineLayout(pub, !!this._settings.scroll);
131
140
  this.currentProgression = pub.metadata.effectiveReadingProgression;
132
-
133
- // Combine Readium rules with user-provided injectables
134
- const readiumRules = createReadiumEpubRules(pub.metadata, pub.readingOrder.items);
135
- const userConfig = configuration.injectables || { rules: [], allowedDomains: [] };
136
-
137
- this._injector = new Injector({
138
- rules: [...readiumRules, ...userConfig.rules],
139
- allowedDomains: userConfig.allowedDomains
140
- });
141
+
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
+
144
152
  // Merge keyboard peripherals
145
153
  this._keyboardPeripherals = this.mergeKeyboardPeripherals(
146
154
  this._contentProtection,
147
155
  configuration.keyboardPeripherals || []
148
156
  );
149
-
157
+
150
158
  // Initialize navigator protection if any protection is configured
151
159
  if (this._contentProtection.disableContextMenu ||
152
160
  this._contentProtection.checkAutomation ||
@@ -154,7 +162,7 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
154
162
  this._contentProtection.monitorDevTools ||
155
163
  this._contentProtection.protectPrinting?.disable) {
156
164
  this._navigatorProtector = new NavigatorProtector(this._contentProtection);
157
-
165
+
158
166
  // Listen for custom events from NavigatorProtector
159
167
  this._suspiciousActivityListener = (event: Event) => {
160
168
  const { type, ...activity } = (event as CustomEvent).detail;
@@ -166,13 +174,13 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
166
174
  };
167
175
  window.addEventListener(NAVIGATOR_SUSPICIOUS_ACTIVITY_EVENT, this._suspiciousActivityListener);
168
176
  }
169
-
177
+
170
178
  // Initialize keyboard peripherals separately (works independently of protection)
171
179
  if (this._keyboardPeripherals.length > 0) {
172
180
  this._keyboardPeripheralsManager = new KeyboardPeripherals({
173
181
  keyboardPeripherals: this._keyboardPeripherals
174
182
  });
175
-
183
+
176
184
  // Listen for keyboard peripheral events from main window
177
185
  this._keyboardPeripheralListener = (event: Event) => {
178
186
  const activity = (event as CustomEvent).detail;
@@ -180,8 +188,8 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
180
188
  };
181
189
  window.addEventListener(NAVIGATOR_KEYBOARD_PERIPHERAL_EVENT, this._keyboardPeripheralListener);
182
190
  }
183
-
184
- // We use a resizeObserver cos’ the container parent may not be the width of
191
+
192
+ // We use a resizeObserver cos’ the container parent may not be the width of
185
193
  // the document/window e.g. app using a docking system with left and right panels.
186
194
  // If we observe this.container, that won’t obviously work since we set its width.
187
195
  this.resizeObserver = new ResizeObserver(() => this.ownerWindow.requestAnimationFrame(async () => await this.resizeHandler()));
@@ -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,10 +223,21 @@ 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
- this.container,
216
- this.positions,
239
+ this.container,
240
+ this.positions,
217
241
  this.pub,
218
242
  this._injector,
219
243
  this._contentProtection,
@@ -226,8 +250,8 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
226
250
  await this.updateCSS(false);
227
251
  const cssProperties = this.compileCSSProperties(this._css);
228
252
  this.framePool = new FramePoolManager(
229
- this.container,
230
- this.positions,
253
+ this.container,
254
+ this.positions,
231
255
  cssProperties,
232
256
  this._injector,
233
257
  this._contentProtection,
@@ -247,7 +271,7 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
247
271
  return Object.freeze({ ...this._settings });
248
272
  } else {
249
273
  // Given all the nasty issues moving auto-pagination to EpubSettings creates
250
- // Especially as it’s tied to ReadiumCSS in the first place and could be
274
+ // Especially as it’s tied to ReadiumCSS in the first place and could be
251
275
  // problematic if you intend to use something else,
252
276
  // we return the properties with columnCount overridden
253
277
  const columnCount = this._css.userProperties.colCount || this._css.rsProperties.colCount || this._settings.columnCount;
@@ -271,7 +295,7 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
271
295
  private async applyPreferences() {
272
296
  const oldSettings = this._settings;
273
297
  this._settings = new EpubSettings(this._preferences, this._defaults);
274
-
298
+
275
299
  if (this._preferencesEditor !== null) {
276
300
  // Note: we pass this.settings instead of this._settings to ensure the columnCount is correct
277
301
  this._preferencesEditor = new EpubPreferencesEditor(this._preferences, this.settings, this.pub.metadata);
@@ -312,20 +336,24 @@ 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
- // the existing properties that are not inside this object first,
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
318
346
  const properties = this.compileCSSProperties(css);
319
347
 
320
348
  (this.framePool as FramePoolManager).setCSSProperties(properties);
321
349
 
322
350
  if (
323
- this._css.userProperties.view === "paged" &&
351
+ this._css.userProperties.view === "paged" &&
324
352
  this._layout === Layout.scrolled
325
353
  ) {
326
- await this.setLayout(Layout.reflowable);
354
+ await this.setLayout(Layout.reflowable);
327
355
  } else if (
328
- this._css.userProperties.view === "scroll" &&
356
+ this._css.userProperties.view === "scroll" &&
329
357
  (this._layout === Layout.reflowable)
330
358
  ) {
331
359
  await this.setLayout(Layout.scrolled);
@@ -341,9 +369,10 @@ 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
- // for reflow ReadiumCSS gets the width from columns + line-lengths
375
+ // for reflow ReadiumCSS gets the width from columns + line-lengths
347
376
  // but we need to check whether colCount has changed to commit new CSS
348
377
  const oldColCount = this._css.userProperties.colCount;
349
378
  const oldLineLength = this._css.userProperties.lineLength;
@@ -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.currentFrames;
403
+ return (this.framePool?.currentFrames ?? []).filter(f => !(f instanceof FrameManager && f.isDestroyed));
375
404
  }
376
405
 
377
406
  /**
@@ -525,11 +554,17 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
525
554
  return modules.filter((m) => FXLModules.includes(m));
526
555
  } else modules = modules.filter((m) => ReflowableModules.includes(m));
527
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
+ }
561
+
528
562
  // Horizontal vs. Vertical reading
563
+ const all = modules as ModuleName[];
529
564
  if (this._layout === Layout.scrolled)
530
- modules = modules.filter((m) => m !== "column_snapper");
565
+ modules = all.filter((m) => m !== "column_snapper" && m !== "cjk_vertical_snapper");
531
566
  else
532
- modules = modules.filter((m) => m !== "scroll_snapper");
567
+ modules = all.filter((m) => m !== "scroll_snapper" && m !== "cjk_vertical_snapper");
533
568
 
534
569
  return modules;
535
570
  }
@@ -543,7 +578,7 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
543
578
  this.eventListener(key, value);
544
579
  }
545
580
  })
546
-
581
+
547
582
  }
548
583
 
549
584
  private async apply() {
@@ -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 with a progression that's
659
- // smaller than or equal to the requested progression.
660
- potentialPositions.some((p, idx) => {
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
- if (fromProgression.start <= pr) {
663
- first = p;
697
+ return pr <= fromProgression.start;
698
+ });
664
699
 
665
- // If there’s a match, check the last in view, from the next progression
666
- const nextPositions = potentialPositions.splice(idx + 1, potentialPositions.length);
667
- last = this.findLastPositionInProgressionRange(nextPositions, fromProgression);
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
 
@@ -677,7 +710,7 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
677
710
  this.reflowViewport.readingOrder = [];
678
711
  this.reflowViewport.progressions.clear();
679
712
  this.reflowViewport.positions = null;
680
-
713
+
681
714
  // Use the current position's href
682
715
  if (this.currentLocation) {
683
716
  this.reflowViewport.readingOrder.push(this.currentLocation.href);
@@ -694,13 +727,13 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
694
727
 
695
728
  private async syncLocation(iframeProgress: ProgressionRange) {
696
729
  const progression = iframeProgress;
697
-
730
+
698
731
  const nearestPositions = this.findNearestPositions(progression);
699
-
732
+
700
733
  this.currentLocation = nearestPositions.first.copyWithLocations({
701
734
  progression: progression.start
702
735
  });
703
-
736
+
704
737
  this.lastLocationInView = nearestPositions.last;
705
738
  this.updateViewport(progression);
706
739
  this.listeners.positionChanged(this.currentLocation);
@@ -749,9 +782,11 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
749
782
  }
750
783
 
751
784
  get viewport(): VisualNavigatorViewport {
752
- return this._layout === Layout.fixed
753
- ? (this.framePool as FXLFramePoolManager).viewport
754
- : this.reflowViewport;
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 {
@@ -759,18 +794,18 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
759
794
  const progression = this.viewport.progressions.get(firstHref);
760
795
  return progression?.start === 0;
761
796
  }
762
-
797
+
763
798
  get isScrollEnd(): boolean {
764
799
  const lastHref = this.viewport.readingOrder[this.viewport.readingOrder.length - 1];
765
800
  const progression = this.viewport.progressions.get(lastHref);
766
801
  return progression?.end === 1;
767
802
  }
768
-
803
+
769
804
  get canGoBackward(): boolean {
770
805
  const firstResource = this.pub.readingOrder.items[0]?.href;
771
806
  return !(this.viewport.progressions.has(firstResource) && this.viewport.progressions.get(firstResource)?.start === 0);
772
807
  }
773
-
808
+
774
809
  get canGoForward(): boolean {
775
810
  const lastResource = this.pub.readingOrder.items[this.pub.readingOrder.items.length - 1]?.href;
776
811
  return !(this.viewport.progressions.has(lastResource) && this.viewport.progressions.get(lastResource)?.end === 1);
@@ -866,4 +901,4 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
866
901
  public goLink(link: Link, animated: boolean, cb: (ok: boolean) => void): void {
867
902
  return this.go(link.locator, animated, cb);
868
903
  }
869
- }
904
+ }
@@ -1,14 +1,14 @@
1
- import { ExperimentKey, experiments, TextAlignment } from "../../preferences/Types";
2
- import {
3
- BodyHyphens,
4
- BoxSizing,
5
- FontOpticalSizing,
6
- FontWidth,
7
- Ligatures,
8
- Properties,
9
- TypeScale,
10
- View
11
- } from "../../css/Properties";
1
+ import { ExperimentKey, experiments, TextAlignment } from "../../preferences/Types.ts";
2
+ import {
3
+ BodyHyphens,
4
+ BoxSizing,
5
+ FontOpticalSizing,
6
+ FontWidth,
7
+ Ligatures,
8
+ Properties,
9
+ TypeScale,
10
+ View
11
+ } from "../../css/Properties.ts";
12
12
 
13
13
  export interface IUserProperties {
14
14
  advancedSettings?: boolean | null;
@@ -136,10 +136,10 @@ export class UserProperties extends Properties {
136
136
  if (this.fontSizeNormalize) cssProperties["--USER__fontSizeNormalize"] = this.toFlag("normalize");
137
137
  if (this.fontWeight != null) cssProperties["--USER__fontWeight"] = this.toUnitless(this.fontWeight);
138
138
  if (this.fontWidth != null) {
139
- cssProperties["--USER__fontWidth"] = typeof this.fontWidth === "string"
140
- ? this.fontWidth
139
+ cssProperties["--USER__fontWidth"] = typeof this.fontWidth === "string"
140
+ ? this.fontWidth
141
141
  : this.toUnitless(this.fontWidth);
142
- }
142
+ }
143
143
  if (this.invertFilter === true) {
144
144
  cssProperties["--USER__invertFilter"] = this.toFlag("invert");
145
145
  } else if (typeof this.invertFilter === "number") {
@@ -360,4 +360,4 @@ export class RSProperties extends Properties {
360
360
 
361
361
  return cssProperties;
362
362
  }
363
- }
363
+ }
@@ -1,7 +1,7 @@
1
- import { LineLengths } from "../../helpers";
2
- import { getContentWidth } from "../../helpers/dimensions";
3
- import { EpubSettings } from "../preferences/EpubSettings";
4
- import { IUserProperties, RSProperties, UserProperties } from "./Properties";
1
+ import { LineLengths } from "../../helpers/index.ts";
2
+ import { getContentWidth } from "../../helpers/dimensions.ts";
3
+ import { EpubSettings } from "../preferences/EpubSettings.ts";
4
+ import { IUserProperties, RSProperties, UserProperties } from "./Properties.ts";
5
5
 
6
6
  export interface IReadiumCSS {
7
7
  rsProperties: RSProperties;
@@ -36,7 +36,7 @@ export class ReadiumCSS {
36
36
  // We need to keep the column count reference for resizeHandler
37
37
  this.cachedColCount = settings.columnCount;
38
38
 
39
- if (settings.constraint !== this.constraint)
39
+ if (settings.constraint !== this.constraint)
40
40
  this.constraint = settings.constraint;
41
41
 
42
42
  if (settings.pageGutter !== this.rsProperties.pageGutter)
@@ -62,7 +62,7 @@ export class ReadiumCSS {
62
62
  this.lineLengths.update({
63
63
  fontFace: settings.fontFamily,
64
64
  letterSpacing: settings.letterSpacing,
65
- padding: settings.scroll
65
+ padding: settings.scroll
66
66
  ? (settings.scrollPaddingLeft || 0) + (settings.scrollPaddingRight || 0)
67
67
  : (settings.pageGutter || 0) * 2,
68
68
  wordSpacing: settings.wordSpacing,
@@ -75,24 +75,24 @@ export class ReadiumCSS {
75
75
 
76
76
  if (layout?.effectiveContainerWidth)
77
77
  this.effectiveContainerWidth = layout?.effectiveContainerWidth;
78
-
78
+
79
79
  const updated: IUserProperties = {
80
80
  a11yNormalize: settings.textNormalization,
81
81
  backgroundColor: settings.backgroundColor,
82
82
  blendFilter: settings.blendFilter,
83
- bodyHyphens: typeof settings.hyphens !== "boolean"
84
- ? null
85
- : settings.hyphens
86
- ? "auto"
83
+ bodyHyphens: typeof settings.hyphens !== "boolean"
84
+ ? null
85
+ : settings.hyphens
86
+ ? "auto"
87
87
  : "none",
88
88
  colCount: layout?.colCount,
89
89
  darkenFilter: settings.darkenFilter,
90
90
  deprecatedFontSize: settings.deprecatedFontSize,
91
91
  fontFamily: settings.fontFamily,
92
- fontOpticalSizing: typeof settings.fontOpticalSizing !== "boolean"
93
- ? null
94
- : settings.fontOpticalSizing
95
- ? "auto"
92
+ fontOpticalSizing: typeof settings.fontOpticalSizing !== "boolean"
93
+ ? null
94
+ : settings.fontOpticalSizing
95
+ ? "auto"
96
96
  : "none",
97
97
  fontSize: settings.fontSize,
98
98
  fontSizeNormalize: settings.fontSizeNormalize,
@@ -103,10 +103,10 @@ export class ReadiumCSS {
103
103
  iOSPatch: settings.iOSPatch,
104
104
  iPadOSPatch: settings.iPadOSPatch,
105
105
  letterSpacing: settings.letterSpacing,
106
- ligatures: typeof settings.ligatures !== "boolean"
107
- ? null
108
- : settings.ligatures
109
- ? "common-ligatures"
106
+ ligatures: typeof settings.ligatures !== "boolean"
107
+ ? null
108
+ : settings.ligatures
109
+ ? "common-ligatures"
110
110
  : "none",
111
111
  lineHeight: settings.lineHeight,
112
112
  lineLength: layout?.effectiveLineLength,
@@ -118,10 +118,10 @@ export class ReadiumCSS {
118
118
  selectionTextColor: settings.selectionTextColor,
119
119
  textAlign: settings.textAlign,
120
120
  textColor: settings.textColor,
121
- view: typeof settings.scroll !== "boolean"
122
- ? null
123
- : settings.scroll
124
- ? "scroll"
121
+ view: typeof settings.scroll !== "boolean"
122
+ ? null
123
+ : settings.scroll
124
+ ? "scroll"
125
125
  : "paged",
126
126
  visitedColor: settings.visitedColor,
127
127
  wordSpacing: settings.wordSpacing
@@ -142,21 +142,21 @@ export class ReadiumCSS {
142
142
 
143
143
  private getCompensatedMetrics(scale: number | null, ignoreCompensation: boolean | null) {
144
144
  const zoomFactor = scale || this.userProperties.fontSize || 1;
145
- const zoomCompensation = zoomFactor < 1
145
+ const zoomCompensation = zoomFactor < 1
146
146
  ? 1 / zoomFactor
147
- : ignoreCompensation
148
- ? zoomFactor
147
+ : ignoreCompensation
148
+ ? zoomFactor
149
149
  : 1;
150
150
 
151
151
  return {
152
152
  zoomFactor: zoomFactor,
153
153
  zoomCompensation: zoomCompensation,
154
154
  optimal: Math.round(this.lineLengths.optimalLineLength) * zoomFactor,
155
- minimal: this.lineLengths.minimalLineLength !== null
156
- ? Math.round(this.lineLengths.minimalLineLength * zoomFactor)
155
+ minimal: this.lineLengths.minimalLineLength !== null
156
+ ? Math.round(this.lineLengths.minimalLineLength * zoomFactor)
157
157
  : null,
158
- maximal: this.lineLengths.maximalLineLength !== null
159
- ? Math.round(this.lineLengths.maximalLineLength * zoomFactor)
158
+ maximal: this.lineLengths.maximalLineLength !== null
159
+ ? Math.round(this.lineLengths.maximalLineLength * zoomFactor)
160
160
  : null
161
161
  }
162
162
  }
@@ -181,13 +181,13 @@ export class ReadiumCSS {
181
181
  let effectiveContainerWidth = constrainedWidth;
182
182
 
183
183
  if (colCount === undefined) {
184
- return {
185
- colCount: undefined,
186
- effectiveContainerWidth: effectiveContainerWidth,
187
- effectiveLineLength: Math.round((effectiveContainerWidth / RCSSColCount) * zoomCompensation)
184
+ return {
185
+ colCount: undefined,
186
+ effectiveContainerWidth: effectiveContainerWidth,
187
+ effectiveLineLength: Math.round((effectiveContainerWidth / RCSSColCount) * zoomCompensation)
188
188
  };
189
189
  }
190
-
190
+
191
191
  if (colCount === null) {
192
192
  if (constrainedWidth >= optimal && maximal !== null) {
193
193
  RCSSColCount = Math.floor(constrainedWidth / optimal);
@@ -198,7 +198,7 @@ export class ReadiumCSS {
198
198
  }
199
199
  } else if (colCount > 1) {
200
200
  const minRequiredWidth = Math.round(colCount * (minimal !== null ? minimal : optimal));
201
-
201
+
202
202
  if (constrainedWidth >= minRequiredWidth) {
203
203
  RCSSColCount = colCount;
204
204
  if (maximal === null) {
@@ -228,9 +228,9 @@ export class ReadiumCSS {
228
228
  effectiveContainerWidth = getSingleColWidth();
229
229
  }
230
230
 
231
- return {
232
- colCount: RCSSColCount,
233
- effectiveContainerWidth: effectiveContainerWidth,
231
+ return {
232
+ colCount: RCSSColCount,
233
+ effectiveContainerWidth: effectiveContainerWidth,
234
234
  effectiveLineLength: Math.round(((effectiveContainerWidth / RCSSColCount) / (scale && scale >= 1 ? scale : 1)) * zoomCompensation)
235
235
  };
236
236
  }
@@ -254,9 +254,9 @@ export class ReadiumCSS {
254
254
  effectiveLineLength = ignoreCompensation ? computedWidth : Math.round(computedWidth * zoomCompensation);
255
255
  }
256
256
 
257
- return {
258
- colCount: RCSSColCount,
259
- effectiveContainerWidth: effectiveContainerWidth,
257
+ return {
258
+ colCount: RCSSColCount,
259
+ effectiveContainerWidth: effectiveContainerWidth,
260
260
  effectiveLineLength: effectiveLineLength
261
261
  }
262
262
  }
@@ -272,4 +272,4 @@ export class ReadiumCSS {
272
272
  this.effectiveContainerWidth = pagination.effectiveContainerWidth;
273
273
  this.container.style.width = `${ this.effectiveContainerWidth }px`;
274
274
  }
275
- }
275
+ }
@@ -1,2 +1,2 @@
1
- export * from "./Properties";
2
- export * from "./ReadiumCSS";
1
+ export * from "./Properties.ts";
2
+ export * from "./ReadiumCSS.ts";