@readium/navigator 1.3.4 → 2.0.0-beta.10
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/index.js +3974 -2928
- package/dist/index.umd.cjs +16 -16
- package/package.json +10 -9
- package/src/Navigator.ts +11 -0
- package/src/epub/EpubNavigator.ts +250 -24
- package/src/epub/css/Properties.ts +396 -0
- package/src/epub/css/ReadiumCSS.ts +339 -0
- package/src/epub/css/index.ts +2 -0
- package/src/epub/frame/FrameBlobBuilder.ts +59 -9
- package/src/epub/frame/FrameManager.ts +23 -1
- package/src/epub/frame/FramePoolManager.ts +62 -4
- package/src/epub/fxl/FXLFramePoolManager.ts +23 -16
- package/src/epub/index.ts +3 -1
- package/src/epub/preferences/EpubDefaults.ts +165 -0
- package/src/epub/preferences/EpubPreferences.ts +192 -0
- package/src/epub/preferences/EpubPreferencesEditor.ts +534 -0
- package/src/epub/preferences/EpubSettings.ts +239 -0
- package/src/epub/preferences/guards.ts +86 -0
- package/src/epub/preferences/index.ts +4 -0
- package/src/helpers/dimensions.ts +13 -0
- package/src/helpers/index.ts +1 -0
- package/src/helpers/lineLength.ts +241 -0
- package/src/helpers/sML.ts +25 -3
- package/src/index.ts +2 -1
- package/src/preferences/Configurable.ts +16 -0
- package/src/preferences/Preference.ts +272 -0
- package/src/preferences/PreferencesEditor.ts +6 -0
- package/src/preferences/Types.ts +38 -0
- package/src/preferences/index.ts +4 -0
- package/types/src/Navigator.d.ts +9 -0
- package/types/src/epub/EpubNavigator.d.ts +34 -4
- package/types/src/epub/css/Properties.d.ts +183 -0
- package/types/src/epub/css/ReadiumCSS.d.ts +31 -0
- package/types/src/epub/css/index.d.ts +2 -0
- package/types/src/epub/frame/FrameBlobBuilder.d.ts +5 -1
- package/types/src/epub/frame/FrameManager.d.ts +4 -0
- package/types/src/epub/frame/FramePoolManager.d.ts +8 -1
- package/types/src/epub/fxl/FXLFramePoolManager.d.ts +4 -4
- package/types/src/epub/index.d.ts +2 -0
- package/types/src/epub/preferences/EpubDefaults.d.ts +86 -0
- package/types/src/epub/preferences/EpubPreferences.d.ts +90 -0
- package/types/src/epub/preferences/EpubPreferencesEditor.d.ts +55 -0
- package/types/src/epub/preferences/EpubSettings.d.ts +89 -0
- package/types/src/epub/preferences/guards.d.ts +9 -0
- package/types/src/epub/preferences/index.d.ts +4 -0
- package/types/src/helpers/dimensions.d.ts +7 -0
- package/types/src/helpers/index.d.ts +1 -0
- package/types/src/helpers/lineLength.d.ts +54 -0
- package/types/src/helpers/sML.d.ts +6 -1
- package/types/src/index.d.ts +1 -0
- package/types/src/preferences/Configurable.d.ts +13 -0
- package/types/src/preferences/Preference.d.ts +117 -0
- package/types/src/preferences/PreferencesEditor.d.ts +5 -0
- package/types/src/preferences/PreferencesSerializer.d.ts +5 -0
- package/types/src/preferences/Types.d.ts +23 -0
- package/types/src/preferences/index.d.ts +4 -0
- package/LICENSE +0 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@readium/navigator",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-beta.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Next generation SDK for publications in Web Apps",
|
|
6
6
|
"author": "readium",
|
|
@@ -44,20 +44,21 @@
|
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=18"
|
|
46
46
|
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc && vite build"
|
|
49
|
+
},
|
|
47
50
|
"devDependencies": {
|
|
48
51
|
"@laynezh/vite-plugin-lib-assets": "^0.5.25",
|
|
52
|
+
"@readium/css": ">=2.0.0-beta.18",
|
|
53
|
+
"@readium/navigator-html-injectables": "workspace:*",
|
|
54
|
+
"@readium/shared": "workspace:*",
|
|
49
55
|
"@types/path-browserify": "^1.0.3",
|
|
50
56
|
"css-selector-generator": "^3.6.9",
|
|
51
57
|
"path-browserify": "^1.0.1",
|
|
52
|
-
"@readium/css": "^1.1.0",
|
|
53
58
|
"tslib": "^2.8.1",
|
|
54
59
|
"typescript": "^5.6.3",
|
|
55
60
|
"typescript-plugin-css-modules": "^5.1.0",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"@readium/shared": "1.2.1"
|
|
59
|
-
},
|
|
60
|
-
"scripts": {
|
|
61
|
-
"build": "tsc && vite build"
|
|
61
|
+
"user-agent-data-types": "^0.4.2",
|
|
62
|
+
"vite": "^4.5.5"
|
|
62
63
|
}
|
|
63
|
-
}
|
|
64
|
+
}
|
package/src/Navigator.ts
CHANGED
|
@@ -2,6 +2,17 @@ import { Link, Locator, Publication, ReadingProgression } from "@readium/shared"
|
|
|
2
2
|
|
|
3
3
|
type cbb = (ok: boolean) => void;
|
|
4
4
|
|
|
5
|
+
export interface ProgressionRange {
|
|
6
|
+
start: number;
|
|
7
|
+
end: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface VisualNavigatorViewport {
|
|
11
|
+
readingOrder: string[]; // Array of href strings for visible resources
|
|
12
|
+
progressions: Map<string, ProgressionRange>; // Map from href to visible scroll progression range
|
|
13
|
+
positions: number[] | null; // Range of visible positions
|
|
14
|
+
}
|
|
15
|
+
|
|
5
16
|
export abstract class Navigator {
|
|
6
17
|
abstract get publication(): Publication; // Publication rendered by this navigator.
|
|
7
18
|
abstract get currentLocator(): Locator; // Current position (detailed) in the publication. Can be used to save a bookmark to the current position.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EPUBLayout, Link, Locator, Publication, ReadingProgression } from "@readium/shared";
|
|
2
|
-
import { VisualNavigator } from "../";
|
|
2
|
+
import { Configurable, ConfigurablePreferences, ConfigurableSettings, LineLengths, VisualNavigator, VisualNavigatorViewport, ProgressionRange } from "../";
|
|
3
3
|
import { FramePoolManager } from "./frame/FramePoolManager";
|
|
4
4
|
import { FXLFramePoolManager } from "./fxl/FXLFramePoolManager";
|
|
5
5
|
import { CommsEventKey, FXLModules, ModuleLibrary, ModuleName, ReflowableModules } from "@readium/navigator-html-injectables";
|
|
@@ -7,9 +7,21 @@ import { BasicTextSelection, FrameClickEvent } from "@readium/navigator-html-inj
|
|
|
7
7
|
import * as path from "path-browserify";
|
|
8
8
|
import { FXLFrameManager } from "./fxl/FXLFrameManager";
|
|
9
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";
|
|
10
17
|
|
|
11
18
|
export type ManagerEventKey = "zoom";
|
|
12
19
|
|
|
20
|
+
export interface EpubNavigatorConfiguration {
|
|
21
|
+
preferences: IEpubPreferences;
|
|
22
|
+
defaults: IEpubDefaults;
|
|
23
|
+
}
|
|
24
|
+
|
|
13
25
|
export interface EpubNavigatorListeners {
|
|
14
26
|
frameLoaded: (wnd: Window) => void;
|
|
15
27
|
positionChanged: (locator: Locator) => void;
|
|
@@ -35,7 +47,7 @@ const defaultListeners = (listeners: EpubNavigatorListeners): EpubNavigatorListe
|
|
|
35
47
|
textSelected: listeners.textSelected || (() => {})
|
|
36
48
|
})
|
|
37
49
|
|
|
38
|
-
export class EpubNavigator extends VisualNavigator {
|
|
50
|
+
export class EpubNavigator extends VisualNavigator implements Configurable<ConfigurableSettings, ConfigurablePreferences> {
|
|
39
51
|
private readonly pub: Publication;
|
|
40
52
|
private readonly container: HTMLElement;
|
|
41
53
|
private readonly listeners: EpubNavigatorListeners;
|
|
@@ -46,16 +58,61 @@ export class EpubNavigator extends VisualNavigator {
|
|
|
46
58
|
private currentProgression: ReadingProgression;
|
|
47
59
|
public readonly layout: EPUBLayout;
|
|
48
60
|
|
|
49
|
-
|
|
61
|
+
private _preferences: EpubPreferences;
|
|
62
|
+
private _defaults: EpubDefaults;
|
|
63
|
+
private _settings: EpubSettings;
|
|
64
|
+
private _css: ReadiumCSS;
|
|
65
|
+
private _preferencesEditor: EpubPreferencesEditor | null = null;
|
|
66
|
+
|
|
67
|
+
private resizeObserver: ResizeObserver;
|
|
68
|
+
|
|
69
|
+
private reflowViewport: VisualNavigatorViewport = {
|
|
70
|
+
readingOrder: [],
|
|
71
|
+
progressions: new Map(),
|
|
72
|
+
positions: null
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
constructor(container: HTMLElement, pub: Publication, listeners: EpubNavigatorListeners, positions: Locator[] = [], initialPosition: Locator | undefined = undefined, configuration: EpubNavigatorConfiguration = { preferences: {}, defaults: {} }) {
|
|
50
76
|
super();
|
|
51
77
|
this.pub = pub;
|
|
52
78
|
this.layout = EpubNavigator.determineLayout(pub);
|
|
53
|
-
this.currentProgression = pub.metadata.effectiveReadingProgression;
|
|
54
79
|
this.container = container;
|
|
55
80
|
this.listeners = defaultListeners(listeners);
|
|
56
81
|
this.currentLocation = initialPosition!;
|
|
57
82
|
if (positions.length)
|
|
58
83
|
this.positions = positions;
|
|
84
|
+
|
|
85
|
+
this._preferences = new EpubPreferences(configuration.preferences);
|
|
86
|
+
this._defaults = new EpubDefaults(configuration.defaults);
|
|
87
|
+
this._settings = new EpubSettings(this._preferences, this._defaults);
|
|
88
|
+
this._css = new ReadiumCSS({
|
|
89
|
+
rsProperties: new RSProperties({}),
|
|
90
|
+
userProperties: new UserProperties({}),
|
|
91
|
+
lineLengths: new LineLengths({
|
|
92
|
+
optimalChars: this._settings.optimalLineLength,
|
|
93
|
+
minChars: this._settings.minimalLineLength,
|
|
94
|
+
maxChars: this._settings.maximalLineLength,
|
|
95
|
+
pageGutter: this._settings.pageGutter,
|
|
96
|
+
fontFace: this._settings.fontFamily,
|
|
97
|
+
letterSpacing: this._settings.letterSpacing,
|
|
98
|
+
wordSpacing: this._settings.wordSpacing,
|
|
99
|
+
// sample: this.pub.metadata.description
|
|
100
|
+
}),
|
|
101
|
+
container: container,
|
|
102
|
+
constraint: this._settings.constraint
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
this.currentProgression = this.layout === EPUBLayout.reflowable
|
|
106
|
+
? (this._settings.scroll
|
|
107
|
+
? ReadingProgression.ttb
|
|
108
|
+
: pub.metadata.effectiveReadingProgression)
|
|
109
|
+
: pub.metadata.effectiveReadingProgression;
|
|
110
|
+
|
|
111
|
+
// We use a resizeObserver cos’ the container parent may not be the width of
|
|
112
|
+
// the document/window e.g. app using a docking system with left and right panels.
|
|
113
|
+
// If we observe this.container, that won’t obviously work since we set its width.
|
|
114
|
+
this.resizeObserver = new ResizeObserver(() => this.ownerWindow.requestAnimationFrame(async () => await this.resizeHandler()));
|
|
115
|
+
this.resizeObserver.observe(this.container.parentElement || document.documentElement);
|
|
59
116
|
}
|
|
60
117
|
|
|
61
118
|
public static determineLayout(pub: Publication): EPUBLayout {
|
|
@@ -79,13 +136,139 @@ export class EpubNavigator extends VisualNavigator {
|
|
|
79
136
|
this.framePool.listener = (key: CommsEventKey | ManagerEventKey, data: unknown) => {
|
|
80
137
|
this.eventListener(key, data);
|
|
81
138
|
}
|
|
82
|
-
} else
|
|
83
|
-
this.
|
|
139
|
+
} else {
|
|
140
|
+
await this.updateCSS(false);
|
|
141
|
+
const cssProperties = this.compileCSSProperties(this._css);
|
|
142
|
+
this.framePool = new FramePoolManager(this.container, this.positions, cssProperties);
|
|
143
|
+
}
|
|
144
|
+
|
|
84
145
|
if(this.currentLocation === undefined)
|
|
85
146
|
this.currentLocation = this.positions[0];
|
|
147
|
+
|
|
148
|
+
await this.resizeHandler();
|
|
86
149
|
await this.apply();
|
|
87
150
|
}
|
|
88
151
|
|
|
152
|
+
public get settings(): Readonly<EpubSettings> {
|
|
153
|
+
if (this.layout === EPUBLayout.fixed) {
|
|
154
|
+
return Object.freeze({ ...this._settings });
|
|
155
|
+
} else {
|
|
156
|
+
// Given all the nasty issues moving auto-pagination to EpubSettings creates
|
|
157
|
+
// Especially as it’s tied to ReadiumCSS in the first place and could be
|
|
158
|
+
// problematic if you intend to use something else,
|
|
159
|
+
// we return the properties with columnCount overridden
|
|
160
|
+
const columnCount = this._css.userProperties.colCount || this._css.rsProperties.colCount || this._settings.columnCount;
|
|
161
|
+
return Object.freeze({ ...this._settings, columnCount: columnCount });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
public get preferencesEditor() {
|
|
166
|
+
if (this._preferencesEditor === null) {
|
|
167
|
+
// Note: we pass this.settings instead of this._settings to ensure the columnCount is correct
|
|
168
|
+
this._preferencesEditor = new EpubPreferencesEditor(this._preferences, this.settings, this.pub.metadata);
|
|
169
|
+
}
|
|
170
|
+
return this._preferencesEditor;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public async submitPreferences(preferences: EpubPreferences) {
|
|
174
|
+
this._preferences = this._preferences.merging(preferences) as EpubPreferences;
|
|
175
|
+
await this.applyPreferences();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private async applyPreferences() {
|
|
179
|
+
const oldSettings = this._settings;
|
|
180
|
+
this._settings = new EpubSettings(this._preferences, this._defaults);
|
|
181
|
+
|
|
182
|
+
if (this._preferencesEditor !== null) {
|
|
183
|
+
// Note: we pass this.settings instead of this._settings to ensure the columnCount is correct
|
|
184
|
+
this._preferencesEditor = new EpubPreferencesEditor(this._preferences, this.settings, this.pub.metadata);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (this.layout === EPUBLayout.fixed) {
|
|
188
|
+
this.handleFXLPrefs(oldSettings, this._settings);
|
|
189
|
+
} else {
|
|
190
|
+
await this.updateCSS(true);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// TODO: fit, etc.
|
|
195
|
+
private handleFXLPrefs(from: EpubSettings, to: EpubSettings) {
|
|
196
|
+
if (from.columnCount !== to.columnCount) {
|
|
197
|
+
(this.framePool as FXLFramePoolManager).setPerPage(to.columnCount);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private async updateCSS(commit: boolean) {
|
|
202
|
+
this._css.update(this._settings);
|
|
203
|
+
|
|
204
|
+
if (commit) await this.commitCSS(this._css);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
private compileCSSProperties(css: ReadiumCSS) {
|
|
208
|
+
const properties: { [key: string]: string } = {};
|
|
209
|
+
|
|
210
|
+
for (const [key, value] of Object.entries(css.rsProperties.toCSSProperties())) {
|
|
211
|
+
properties[key] = value;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
for (const [key, value] of Object.entries(css.userProperties.toCSSProperties())) {
|
|
215
|
+
properties[key] = value;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return properties;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private async commitCSS(css: ReadiumCSS) {
|
|
222
|
+
// Since we’re updating the CSS properties in injectables by removing
|
|
223
|
+
// the existing properties that are not inside this object first,
|
|
224
|
+
// then adding all from it, we don’t compare the previous properties here
|
|
225
|
+
const properties = this.compileCSSProperties(css);
|
|
226
|
+
|
|
227
|
+
(this.framePool as FramePoolManager).setCSSProperties(properties);
|
|
228
|
+
|
|
229
|
+
if (
|
|
230
|
+
this._css.userProperties.view === "paged" &&
|
|
231
|
+
this.readingProgression === ReadingProgression.ttb
|
|
232
|
+
) {
|
|
233
|
+
await this.setReadingProgression(this.pub.metadata.effectiveReadingProgression);
|
|
234
|
+
} else if (
|
|
235
|
+
this._css.userProperties.view === "scroll" &&
|
|
236
|
+
(this.readingProgression === ReadingProgression.ltr || this.readingProgression === ReadingProgression.rtl)
|
|
237
|
+
) {
|
|
238
|
+
await this.setReadingProgression(ReadingProgression.ttb);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
this._css.setContainerWidth();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async resizeHandler() {
|
|
245
|
+
// We check the parentElement cos we want to remove constraint from the container
|
|
246
|
+
// and the container may not be the entire width of the document/window
|
|
247
|
+
const parentEl = this.container.parentElement || document.documentElement;
|
|
248
|
+
|
|
249
|
+
if (this.layout === EPUBLayout.fixed) {
|
|
250
|
+
this.container.style.width = `${ getContentWidth(parentEl) - this._settings.constraint }px`;
|
|
251
|
+
(this.framePool as FXLFramePoolManager).resizeHandler();
|
|
252
|
+
} else {
|
|
253
|
+
// for reflow ReadiumCSS gets the width from columns + line-lengths
|
|
254
|
+
// but we need to check whether colCount has changed to commit new CSS
|
|
255
|
+
const oldColCount = this._css.userProperties.colCount;
|
|
256
|
+
const oldLineLength = this._css.userProperties.lineLength;
|
|
257
|
+
this._css.resizeHandler();
|
|
258
|
+
if (
|
|
259
|
+
this._css.userProperties.view !== "scroll" &&
|
|
260
|
+
oldColCount !== this._css.userProperties.colCount ||
|
|
261
|
+
oldLineLength !== this._css.userProperties.lineLength
|
|
262
|
+
) {
|
|
263
|
+
await this.commitCSS(this._css);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
get ownerWindow() {
|
|
269
|
+
return this.container.ownerDocument.defaultView || window;
|
|
270
|
+
}
|
|
271
|
+
|
|
89
272
|
/**
|
|
90
273
|
* Exposed to the public to compensate for lack of implemented readium conveniences
|
|
91
274
|
* TODO remove when settings management is incorporated
|
|
@@ -217,7 +400,7 @@ export class EpubNavigator extends VisualNavigator {
|
|
|
217
400
|
this.listeners.zoom(data as number);
|
|
218
401
|
break;
|
|
219
402
|
case "progress":
|
|
220
|
-
this.syncLocation(data as
|
|
403
|
+
this.syncLocation(data as ProgressionRange);
|
|
221
404
|
break;
|
|
222
405
|
case "log":
|
|
223
406
|
console.log(this._cframes[0]?.source?.split("/")[3], ...(data as any[]));
|
|
@@ -275,7 +458,7 @@ export class EpubNavigator extends VisualNavigator {
|
|
|
275
458
|
|
|
276
459
|
if(this.layout === EPUBLayout.fixed) {
|
|
277
460
|
const p = this.framePool as FXLFramePoolManager;
|
|
278
|
-
const old = p.
|
|
461
|
+
const old = p.viewport.positions![0];
|
|
279
462
|
if(relative === 1) {
|
|
280
463
|
if(!p.next(p.perPage)) return false;
|
|
281
464
|
} else if(relative === -1) {
|
|
@@ -284,7 +467,7 @@ export class EpubNavigator extends VisualNavigator {
|
|
|
284
467
|
throw Error("Invalid relative value for FXL");
|
|
285
468
|
|
|
286
469
|
// Apply change
|
|
287
|
-
const neW = p.
|
|
470
|
+
const neW = p.viewport.positions![0]
|
|
288
471
|
if(old > neW)
|
|
289
472
|
for (let j = this.positions.length - 1; j >= 0; j--) {
|
|
290
473
|
if(this.positions[j].href === this.pub.readingOrder.items[neW-1].href) {
|
|
@@ -337,10 +520,10 @@ export class EpubNavigator extends VisualNavigator {
|
|
|
337
520
|
return true;
|
|
338
521
|
}
|
|
339
522
|
|
|
340
|
-
private findLastPositionInProgressionRange(positions: Locator[], range:
|
|
523
|
+
private findLastPositionInProgressionRange(positions: Locator[], range: ProgressionRange): Locator | undefined {
|
|
341
524
|
const match = positions.findLastIndex((p) => {
|
|
342
525
|
const pr = p.locations.progression;
|
|
343
|
-
if (pr && pr >
|
|
526
|
+
if (pr && pr > range.start && pr <= range.end) {
|
|
344
527
|
return true;
|
|
345
528
|
} else {
|
|
346
529
|
return false;
|
|
@@ -349,7 +532,7 @@ export class EpubNavigator extends VisualNavigator {
|
|
|
349
532
|
return match !== -1 ? positions[match] : undefined;
|
|
350
533
|
}
|
|
351
534
|
|
|
352
|
-
private findNearestPositions(fromProgression:
|
|
535
|
+
private findNearestPositions(fromProgression: ProgressionRange): { first: Locator, last: Locator | undefined } {
|
|
353
536
|
// TODO replace with locator service
|
|
354
537
|
const potentialPositions = this.positions.filter(
|
|
355
538
|
(p) => p.href === this.currentLocation.href
|
|
@@ -361,13 +544,12 @@ export class EpubNavigator extends VisualNavigator {
|
|
|
361
544
|
// smaller than or equal to the requested progression.
|
|
362
545
|
potentialPositions.some((p, idx) => {
|
|
363
546
|
const pr = p.locations.progression ?? 0;
|
|
364
|
-
if (fromProgression.
|
|
547
|
+
if (fromProgression.start <= pr) {
|
|
365
548
|
first = p;
|
|
366
549
|
|
|
367
550
|
// If there’s a match, check the last in view, from the next progression
|
|
368
551
|
const nextPositions = potentialPositions.splice(idx + 1, potentialPositions.length);
|
|
369
|
-
|
|
370
|
-
last = this.findLastPositionInProgressionRange(nextPositions, range);
|
|
552
|
+
last = this.findLastPositionInProgressionRange(nextPositions, fromProgression);
|
|
371
553
|
|
|
372
554
|
return true;
|
|
373
555
|
}
|
|
@@ -376,12 +558,36 @@ export class EpubNavigator extends VisualNavigator {
|
|
|
376
558
|
return { first: first, last: last }
|
|
377
559
|
}
|
|
378
560
|
|
|
379
|
-
private
|
|
380
|
-
|
|
561
|
+
private updateViewport(progression: ProgressionRange) {
|
|
562
|
+
this.reflowViewport.readingOrder = [];
|
|
563
|
+
this.reflowViewport.progressions.clear();
|
|
564
|
+
this.reflowViewport.positions = null;
|
|
565
|
+
|
|
566
|
+
// Use the current position's href
|
|
567
|
+
if (this.currentLocation) {
|
|
568
|
+
this.reflowViewport.readingOrder.push(this.currentLocation.href);
|
|
569
|
+
this.reflowViewport.progressions.set(this.currentLocation.href, progression);
|
|
570
|
+
|
|
571
|
+
if (this.currentLocation.locations?.position !== undefined) {
|
|
572
|
+
this.reflowViewport.positions = [this.currentLocation.locations.position];
|
|
573
|
+
if (this.lastLocationInView?.locations?.position !== undefined) {
|
|
574
|
+
this.reflowViewport.positions.push(this.lastLocationInView.locations.position);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
private async syncLocation(iframeProgress: ProgressionRange) {
|
|
581
|
+
const progression = iframeProgress;
|
|
582
|
+
|
|
583
|
+
const nearestPositions = this.findNearestPositions(progression);
|
|
584
|
+
|
|
381
585
|
this.currentLocation = nearestPositions.first.copyWithLocations({
|
|
382
|
-
progression:
|
|
586
|
+
progression: progression.start
|
|
383
587
|
});
|
|
588
|
+
|
|
384
589
|
this.lastLocationInView = nearestPositions.last;
|
|
590
|
+
this.updateViewport(progression);
|
|
385
591
|
this.listeners.positionChanged(this.currentLocation);
|
|
386
592
|
await this.framePool.update(this.pub, this.currentLocation, this.determineModules());
|
|
387
593
|
}
|
|
@@ -427,12 +633,32 @@ export class EpubNavigator extends VisualNavigator {
|
|
|
427
633
|
return this.currentLocation;
|
|
428
634
|
}
|
|
429
635
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
636
|
+
get viewport(): VisualNavigatorViewport {
|
|
637
|
+
return this.layout === EPUBLayout.fixed
|
|
638
|
+
? (this.framePool as FXLFramePoolManager).viewport
|
|
639
|
+
: this.reflowViewport;
|
|
640
|
+
}
|
|
434
641
|
|
|
435
|
-
|
|
642
|
+
get isScrollStart(): boolean {
|
|
643
|
+
const firstHref = this.viewport.readingOrder[0];
|
|
644
|
+
const progression = this.viewport.progressions.get(firstHref);
|
|
645
|
+
return progression?.start === 0;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
get isScrollEnd(): boolean {
|
|
649
|
+
const lastHref = this.viewport.readingOrder[this.viewport.readingOrder.length - 1];
|
|
650
|
+
const progression = this.viewport.progressions.get(lastHref);
|
|
651
|
+
return progression?.end === 1;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
get canGoBackward(): boolean {
|
|
655
|
+
const firstResource = this.pub.readingOrder.items[0]?.href;
|
|
656
|
+
return this.viewport.progressions.has(firstResource) && this.viewport.progressions.get(firstResource)?.start === 0;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
get canGoForward(): boolean {
|
|
660
|
+
const lastResource = this.pub.readingOrder.items[this.pub.readingOrder.items.length - 1]?.href;
|
|
661
|
+
return this.viewport.progressions.has(lastResource) && this.viewport.progressions.get(lastResource)?.end === 1;
|
|
436
662
|
}
|
|
437
663
|
|
|
438
664
|
// TODO: This is temporary until user settings are implemented.
|
|
@@ -442,7 +668,7 @@ export class EpubNavigator extends VisualNavigator {
|
|
|
442
668
|
|
|
443
669
|
// TODO: This is temporary until user settings are implemented.
|
|
444
670
|
public async setReadingProgression(newProgression: ReadingProgression) {
|
|
445
|
-
if(this.currentProgression === newProgression) return;
|
|
671
|
+
if(this.currentProgression === newProgression || !this.framePool) return;
|
|
446
672
|
this.currentProgression = newProgression;
|
|
447
673
|
await this.framePool.update(this.pub, this.currentLocator, this.determineModules(), true);
|
|
448
674
|
this.attachListener();
|