@readium/navigator 2.0.0-beta.9 → 2.1.0
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 +1639 -1571
- package/dist/index.umd.cjs +15 -15
- package/package.json +2 -2
- package/src/Navigator.ts +15 -4
- package/src/epub/EpubNavigator.ts +113 -57
- package/src/epub/css/Properties.ts +4 -0
- package/src/epub/css/ReadiumCSS.ts +48 -115
- package/src/epub/frame/FrameManager.ts +7 -1
- package/src/epub/frame/FramePoolManager.ts +1 -2
- package/src/epub/fxl/FXLFramePoolManager.ts +25 -6
- package/src/epub/fxl/FXLSpreader.ts +21 -8
- package/src/epub/preferences/EpubDefaults.ts +5 -4
- package/src/epub/preferences/EpubPreferences.ts +3 -4
- package/src/epub/preferences/EpubPreferencesEditor.ts +48 -50
- package/src/epub/preferences/EpubSettings.ts +10 -4
- package/src/preferences/Types.ts +0 -6
- package/types/src/Navigator.d.ts +9 -0
- package/types/src/epub/EpubNavigator.d.ts +14 -6
- package/types/src/epub/css/Properties.d.ts +2 -0
- package/types/src/epub/css/ReadiumCSS.d.ts +0 -3
- package/types/src/epub/fxl/FXLFramePoolManager.d.ts +3 -1
- package/types/src/epub/fxl/FXLSpreader.d.ts +11 -0
- package/types/src/epub/preferences/EpubDefaults.d.ts +3 -3
- package/types/src/epub/preferences/EpubPreferences.d.ts +3 -3
- package/types/src/epub/preferences/EpubPreferencesEditor.d.ts +2 -2
- package/types/src/epub/preferences/EpubSettings.d.ts +3 -3
- package/types/src/preferences/Types.d.ts +0 -5
- package/types/src/preferences/PreferencesSerializer.d.ts +0 -5
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { LineLengths } from "../../helpers";
|
|
2
2
|
import { getContentWidth } from "../../helpers/dimensions";
|
|
3
|
-
import { LayoutStrategy } from "../../preferences";
|
|
4
3
|
import { EpubSettings } from "../preferences/EpubSettings";
|
|
5
4
|
import { IUserProperties, RSProperties, UserProperties } from "./Properties";
|
|
6
5
|
|
|
@@ -10,7 +9,6 @@ export interface IReadiumCSS {
|
|
|
10
9
|
lineLengths: LineLengths;
|
|
11
10
|
container: HTMLElement;
|
|
12
11
|
constraint: number;
|
|
13
|
-
layoutStrategy?: LayoutStrategy | null;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
export class ReadiumCSS {
|
|
@@ -20,7 +18,6 @@ export class ReadiumCSS {
|
|
|
20
18
|
container: HTMLElement;
|
|
21
19
|
containerParent: HTMLElement;
|
|
22
20
|
constraint: number;
|
|
23
|
-
layoutStrategy: LayoutStrategy;
|
|
24
21
|
private cachedColCount: number | null | undefined;
|
|
25
22
|
private effectiveContainerWidth: number;
|
|
26
23
|
|
|
@@ -31,7 +28,6 @@ export class ReadiumCSS {
|
|
|
31
28
|
this.container = props.container;
|
|
32
29
|
this.containerParent = props.container.parentElement || document.documentElement;
|
|
33
30
|
this.constraint = props.constraint;
|
|
34
|
-
this.layoutStrategy = props.layoutStrategy || LayoutStrategy.lineLength;
|
|
35
31
|
this.cachedColCount = props.userProperties.colCount;
|
|
36
32
|
this.effectiveContainerWidth = getContentWidth(this.containerParent);
|
|
37
33
|
}
|
|
@@ -43,9 +39,6 @@ export class ReadiumCSS {
|
|
|
43
39
|
if (settings.constraint !== this.constraint)
|
|
44
40
|
this.constraint = settings.constraint;
|
|
45
41
|
|
|
46
|
-
if (settings.layoutStrategy && settings.layoutStrategy !== this.layoutStrategy)
|
|
47
|
-
this.layoutStrategy = settings.layoutStrategy;
|
|
48
|
-
|
|
49
42
|
if (settings.pageGutter !== this.rsProperties.pageGutter)
|
|
50
43
|
this.rsProperties.pageGutter = settings.pageGutter;
|
|
51
44
|
|
|
@@ -73,7 +66,7 @@ export class ReadiumCSS {
|
|
|
73
66
|
maxChars: settings.maximalLineLength
|
|
74
67
|
});
|
|
75
68
|
|
|
76
|
-
const layout = this.updateLayout(settings.fontSize, settings.deprecatedFontSize, settings.scroll, settings.columnCount);
|
|
69
|
+
const layout = this.updateLayout(settings.fontSize, settings.deprecatedFontSize || settings.iOSPatch, settings.scroll, settings.columnCount);
|
|
77
70
|
|
|
78
71
|
if (layout?.effectiveContainerWidth)
|
|
79
72
|
this.effectiveContainerWidth = layout?.effectiveContainerWidth;
|
|
@@ -103,6 +96,7 @@ export class ReadiumCSS {
|
|
|
103
96
|
fontWidth: settings.fontWidth,
|
|
104
97
|
invertFilter: settings.invertFilter,
|
|
105
98
|
invertGaijiFilter: settings.invertGaijiFilter,
|
|
99
|
+
iOSPatch: settings.iOSPatch,
|
|
106
100
|
iPadOSPatch: settings.iPadOSPatch,
|
|
107
101
|
letterSpacing: settings.letterSpacing,
|
|
108
102
|
ligatures: typeof settings.ligatures !== "boolean"
|
|
@@ -132,23 +126,21 @@ export class ReadiumCSS {
|
|
|
132
126
|
this.userProperties = new UserProperties(updated);
|
|
133
127
|
}
|
|
134
128
|
|
|
135
|
-
private updateLayout(scale: number | null,
|
|
129
|
+
private updateLayout(scale: number | null, ignoreCompensation: boolean | null, scroll: boolean | null, colCount?: number | null) {
|
|
136
130
|
const isScroll = scroll ?? this.userProperties.view === "scroll";
|
|
137
131
|
|
|
138
132
|
if (isScroll) {
|
|
139
|
-
return this.computeScrollLength(scale,
|
|
133
|
+
return this.computeScrollLength(scale, ignoreCompensation);
|
|
140
134
|
} else {
|
|
141
|
-
return this.paginate(scale,
|
|
135
|
+
return this.paginate(scale, ignoreCompensation, colCount);
|
|
142
136
|
}
|
|
143
137
|
}
|
|
144
138
|
|
|
145
|
-
private getCompensatedMetrics(scale: number | null,
|
|
139
|
+
private getCompensatedMetrics(scale: number | null, ignoreCompensation: boolean | null) {
|
|
146
140
|
const zoomFactor = scale || this.userProperties.fontSize || 1;
|
|
147
141
|
const zoomCompensation = zoomFactor < 1
|
|
148
|
-
?
|
|
149
|
-
|
|
150
|
-
: 1 / zoomFactor
|
|
151
|
-
: deprecatedImplem
|
|
142
|
+
? 1 / zoomFactor
|
|
143
|
+
: ignoreCompensation
|
|
152
144
|
? zoomFactor
|
|
153
145
|
: 1;
|
|
154
146
|
|
|
@@ -168,13 +160,18 @@ export class ReadiumCSS {
|
|
|
168
160
|
// Note: Kept intentionally verbose for debugging
|
|
169
161
|
// TODO: As scroll shows, the effective line-length
|
|
170
162
|
// should be the same as uncompensated when scale >= 1
|
|
171
|
-
private paginate(scale: number | null,
|
|
172
|
-
const constrainedWidth = Math.round(getContentWidth(this.containerParent) -
|
|
173
|
-
const metrics = this.getCompensatedMetrics(scale,
|
|
174
|
-
const zoomCompensation = metrics
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const
|
|
163
|
+
private paginate(scale: number | null, ignoreCompensation: boolean | null, colCount?: number | null) {
|
|
164
|
+
const constrainedWidth = Math.round(getContentWidth(this.containerParent) - this.constraint);
|
|
165
|
+
const metrics = this.getCompensatedMetrics(scale, ignoreCompensation);
|
|
166
|
+
const { zoomCompensation, optimal, minimal, maximal } = metrics;
|
|
167
|
+
|
|
168
|
+
// Helper function for single column width calculation
|
|
169
|
+
const getSingleColWidth = (): number => {
|
|
170
|
+
if (constrainedWidth >= optimal && maximal !== null) {
|
|
171
|
+
return Math.min(Math.round(maximal * zoomCompensation), constrainedWidth);
|
|
172
|
+
}
|
|
173
|
+
return constrainedWidth;
|
|
174
|
+
};
|
|
178
175
|
|
|
179
176
|
let RCSSColCount = 1;
|
|
180
177
|
let effectiveContainerWidth = constrainedWidth;
|
|
@@ -188,96 +185,43 @@ export class ReadiumCSS {
|
|
|
188
185
|
}
|
|
189
186
|
|
|
190
187
|
if (colCount === null) {
|
|
191
|
-
if (
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
RCSSColCount = 1;
|
|
198
|
-
effectiveContainerWidth = constrainedWidth;
|
|
199
|
-
}
|
|
200
|
-
} else if (this.layoutStrategy === LayoutStrategy.lineLength) {
|
|
201
|
-
if (constrainedWidth < optimal || maximal === null) {
|
|
202
|
-
RCSSColCount = 1;
|
|
203
|
-
effectiveContainerWidth = constrainedWidth;
|
|
204
|
-
} else {
|
|
205
|
-
RCSSColCount = Math.floor(constrainedWidth / optimal);
|
|
206
|
-
const requiredWidth = Math.round(RCSSColCount * (maximal * zoomCompensation));
|
|
207
|
-
effectiveContainerWidth = Math.min(requiredWidth, constrainedWidth);
|
|
208
|
-
}
|
|
209
|
-
} else if (this.layoutStrategy === LayoutStrategy.columns) {
|
|
210
|
-
if (constrainedWidth >= optimal) {
|
|
211
|
-
if (maximal === null) {
|
|
212
|
-
RCSSColCount = Math.floor(constrainedWidth / optimal);
|
|
213
|
-
effectiveContainerWidth = constrainedWidth;
|
|
214
|
-
} else {
|
|
215
|
-
RCSSColCount = Math.floor(constrainedWidth / (minimal || optimal));
|
|
216
|
-
const requiredWidth = Math.round((RCSSColCount * (optimal * zoomCompensation)));
|
|
217
|
-
effectiveContainerWidth = Math.min(requiredWidth, constrainedWidth);
|
|
218
|
-
}
|
|
219
|
-
} else {
|
|
220
|
-
RCSSColCount = 1;
|
|
221
|
-
effectiveContainerWidth = constrainedWidth;
|
|
222
|
-
}
|
|
188
|
+
if (constrainedWidth >= optimal && maximal !== null) {
|
|
189
|
+
RCSSColCount = Math.floor(constrainedWidth / optimal);
|
|
190
|
+
const requiredWidth = Math.round(RCSSColCount * (maximal * zoomCompensation));
|
|
191
|
+
effectiveContainerWidth = Math.min(requiredWidth, constrainedWidth);
|
|
192
|
+
} else {
|
|
193
|
+
effectiveContainerWidth = getSingleColWidth();
|
|
223
194
|
}
|
|
224
195
|
} else if (colCount > 1) {
|
|
225
196
|
const minRequiredWidth = Math.round(colCount * (minimal !== null ? minimal : optimal));
|
|
226
197
|
|
|
227
198
|
if (constrainedWidth >= minRequiredWidth) {
|
|
228
199
|
RCSSColCount = colCount;
|
|
229
|
-
if (
|
|
230
|
-
|
|
200
|
+
if (maximal === null) {
|
|
201
|
+
effectiveContainerWidth = constrainedWidth
|
|
202
|
+
} else {
|
|
203
|
+
const requiredWidth = Math.round(RCSSColCount * (maximal * zoomCompensation));
|
|
231
204
|
effectiveContainerWidth = Math.min(requiredWidth, constrainedWidth);
|
|
232
|
-
} else if (
|
|
233
|
-
this.layoutStrategy === LayoutStrategy.lineLength ||
|
|
234
|
-
this.layoutStrategy === LayoutStrategy.columns
|
|
235
|
-
) {
|
|
236
|
-
if (maximal === null) {
|
|
237
|
-
effectiveContainerWidth = constrainedWidth
|
|
238
|
-
} else {
|
|
239
|
-
const requiredWidth = Math.round(RCSSColCount * (maximal * zoomCompensation));
|
|
240
|
-
effectiveContainerWidth = Math.min(requiredWidth, constrainedWidth);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (this.layoutStrategy === LayoutStrategy.columns) {
|
|
244
|
-
console.error("Columns strategy is not compatible with a column count whose value is a number. Falling back to lineLength strategy.");
|
|
245
|
-
}
|
|
246
205
|
}
|
|
247
206
|
} else {
|
|
248
207
|
if (minimal !== null && constrainedWidth < Math.round(colCount * minimal)) {
|
|
249
208
|
RCSSColCount = Math.floor(constrainedWidth / minimal);
|
|
209
|
+
if (RCSSColCount <= 1) {
|
|
210
|
+
RCSSColCount = 1;
|
|
211
|
+
effectiveContainerWidth = getSingleColWidth();
|
|
212
|
+
} else {
|
|
213
|
+
const requiredWidth = Math.round(RCSSColCount * (optimal * zoomCompensation));
|
|
214
|
+
effectiveContainerWidth = Math.min(requiredWidth, constrainedWidth);
|
|
215
|
+
}
|
|
250
216
|
} else {
|
|
251
217
|
RCSSColCount = colCount;
|
|
218
|
+
const requiredWidth = Math.round(RCSSColCount * (optimal * zoomCompensation));
|
|
219
|
+
effectiveContainerWidth = Math.min(requiredWidth, constrainedWidth);
|
|
252
220
|
}
|
|
253
|
-
const requiredWidth = Math.round((RCSSColCount * (optimal * zoomCompensation)));
|
|
254
|
-
effectiveContainerWidth = Math.min(requiredWidth, constrainedWidth);
|
|
255
221
|
}
|
|
256
222
|
} else {
|
|
257
223
|
RCSSColCount = 1;
|
|
258
|
-
|
|
259
|
-
if (constrainedWidth >= optimal) {
|
|
260
|
-
if (this.layoutStrategy === LayoutStrategy.margin) {
|
|
261
|
-
const requiredWidth = Math.round(optimal * zoomCompensation);
|
|
262
|
-
effectiveContainerWidth = Math.min(requiredWidth, constrainedWidth);
|
|
263
|
-
} else if (
|
|
264
|
-
this.layoutStrategy === LayoutStrategy.lineLength ||
|
|
265
|
-
this.layoutStrategy === LayoutStrategy.columns
|
|
266
|
-
) {
|
|
267
|
-
if (maximal === null) {
|
|
268
|
-
effectiveContainerWidth = constrainedWidth
|
|
269
|
-
} else {
|
|
270
|
-
const requiredWidth = Math.round(maximal * zoomCompensation);
|
|
271
|
-
effectiveContainerWidth = Math.min(requiredWidth, constrainedWidth);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
if (this.layoutStrategy === LayoutStrategy.columns) {
|
|
275
|
-
console.error("Columns strategy is not compatible with a column count whose value is a number. Falling back to lineLength strategy.");
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
} else {
|
|
279
|
-
effectiveContainerWidth = constrainedWidth
|
|
280
|
-
}
|
|
224
|
+
effectiveContainerWidth = getSingleColWidth();
|
|
281
225
|
}
|
|
282
226
|
|
|
283
227
|
return {
|
|
@@ -288,9 +232,9 @@ export class ReadiumCSS {
|
|
|
288
232
|
}
|
|
289
233
|
|
|
290
234
|
// This behaves as paginate where colCount = 1
|
|
291
|
-
private computeScrollLength(scale: number | null,
|
|
235
|
+
private computeScrollLength(scale: number | null, ignoreCompensation: boolean | null) {
|
|
292
236
|
const constrainedWidth = Math.round(getContentWidth(this.containerParent) - (this.constraint));
|
|
293
|
-
const metrics = this.getCompensatedMetrics(scale && (scale < 1 ||
|
|
237
|
+
const metrics = this.getCompensatedMetrics(scale && (scale < 1 || ignoreCompensation) ? scale : 1, ignoreCompensation);
|
|
294
238
|
const zoomCompensation = metrics.zoomCompensation;
|
|
295
239
|
const optimal = metrics.optimal;
|
|
296
240
|
const maximal = metrics.maximal;
|
|
@@ -299,22 +243,11 @@ export class ReadiumCSS {
|
|
|
299
243
|
let effectiveContainerWidth = constrainedWidth;
|
|
300
244
|
let effectiveLineLength = Math.round(optimal * zoomCompensation);
|
|
301
245
|
|
|
302
|
-
if (
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
this.layoutStrategy === LayoutStrategy.columns
|
|
308
|
-
) {
|
|
309
|
-
if (this.layoutStrategy === LayoutStrategy.columns) {
|
|
310
|
-
console.error("Columns strategy is not compatible with scroll. Falling back to lineLength strategy.");
|
|
311
|
-
}
|
|
312
|
-
if (maximal === null) {
|
|
313
|
-
effectiveLineLength = constrainedWidth;
|
|
314
|
-
} else {
|
|
315
|
-
const computedWidth = Math.min(Math.round(maximal * zoomCompensation), constrainedWidth);
|
|
316
|
-
effectiveLineLength = deprecatedImplem ? computedWidth : Math.round(computedWidth * zoomCompensation);
|
|
317
|
-
}
|
|
246
|
+
if (maximal === null) {
|
|
247
|
+
effectiveLineLength = constrainedWidth;
|
|
248
|
+
} else {
|
|
249
|
+
const computedWidth = Math.min(Math.round(maximal * zoomCompensation), constrainedWidth);
|
|
250
|
+
effectiveLineLength = ignoreCompensation ? computedWidth : Math.round(computedWidth * zoomCompensation);
|
|
318
251
|
}
|
|
319
252
|
|
|
320
253
|
return {
|
|
@@ -329,7 +262,7 @@ export class ReadiumCSS {
|
|
|
329
262
|
}
|
|
330
263
|
|
|
331
264
|
resizeHandler() {
|
|
332
|
-
const pagination = this.updateLayout(this.userProperties.fontSize, this.userProperties.deprecatedFontSize, this.userProperties.view === "scroll", this.cachedColCount);
|
|
265
|
+
const pagination = this.updateLayout(this.userProperties.fontSize, this.userProperties.deprecatedFontSize || this.userProperties.iOSPatch, this.userProperties.view === "scroll", this.cachedColCount);
|
|
333
266
|
this.userProperties.colCount = pagination.colCount;
|
|
334
267
|
this.userProperties.lineLength = pagination.effectiveLineLength;
|
|
335
268
|
this.effectiveContainerWidth = pagination.effectiveContainerWidth;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Loader, ModuleName } from "@readium/navigator-html-injectables";
|
|
2
2
|
import { FrameComms } from "./FrameComms";
|
|
3
3
|
import { ReadiumWindow } from "../../../../navigator-html-injectables/types/src/helpers/dom";
|
|
4
|
+
import { sML } from "../../helpers";
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
export class FrameManager {
|
|
@@ -95,9 +96,14 @@ export class FrameManager {
|
|
|
95
96
|
this.frame.style.removeProperty("opacity");
|
|
96
97
|
this.frame.style.removeProperty("pointer-events");
|
|
97
98
|
this.hidden = false;
|
|
99
|
+
|
|
100
|
+
if (sML.UA.WebKit) {
|
|
101
|
+
this.comms?.send("force_webkit_recalc", undefined);
|
|
102
|
+
}
|
|
103
|
+
|
|
98
104
|
res();
|
|
99
105
|
}
|
|
100
|
-
if(atProgress
|
|
106
|
+
if(atProgress !== undefined) {
|
|
101
107
|
this.comms?.send("go_progression", atProgress, remove);
|
|
102
108
|
} else {
|
|
103
109
|
remove();
|
|
@@ -155,9 +155,8 @@ export class FramePoolManager {
|
|
|
155
155
|
await newFrame.load(modules); // In order to ensure modules match the latest configuration
|
|
156
156
|
|
|
157
157
|
// Update progression if necessary and show the new frame
|
|
158
|
-
const hasProgression = (locator?.locations?.progression ?? 0) > 0;
|
|
159
158
|
if(newFrame) // If user is speeding through the publication, this can get destroyed
|
|
160
|
-
await newFrame.show(
|
|
159
|
+
await newFrame.show(locator.locations.progression); // Show/activate new frame
|
|
161
160
|
|
|
162
161
|
this._currentFrame = newFrame;
|
|
163
162
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ModuleName } from "@readium/navigator-html-injectables";
|
|
2
|
-
import { Locator, Publication, ReadingProgression,
|
|
2
|
+
import { Locator, Publication, ReadingProgression, Page, Link } from "@readium/shared";
|
|
3
3
|
import { FrameCommsListener } from "../frame";
|
|
4
4
|
import FrameBlobBuider from "../frame/FrameBlobBuilder";
|
|
5
5
|
import { FXLFrameManager } from "./FXLFrameManager";
|
|
6
6
|
import { FXLPeripherals } from "./FXLPeripherals";
|
|
7
|
-
import { FXLSpreader } from "./FXLSpreader";
|
|
7
|
+
import { FXLSpreader, Orientation, Spread } from "./FXLSpreader";
|
|
8
|
+
import { VisualNavigatorViewport } from "../../Navigator";
|
|
8
9
|
|
|
9
10
|
const UPPER_BOUNDARY = 8;
|
|
10
11
|
const LOWER_BOUNDARY = 5;
|
|
@@ -47,7 +48,7 @@ export class FXLFramePoolManager {
|
|
|
47
48
|
this.container = container;
|
|
48
49
|
this.positions = positions;
|
|
49
50
|
this.pub = pub;
|
|
50
|
-
this.spreadPresentation = pub.metadata.
|
|
51
|
+
this.spreadPresentation = pub.metadata.otherMetadata?.spread || Spread.auto;
|
|
51
52
|
|
|
52
53
|
if(this.pub.metadata.effectiveReadingProgression !== ReadingProgression.rtl && this.pub.metadata.effectiveReadingProgression !== ReadingProgression.ltr)
|
|
53
54
|
// TODO support TTB and BTT
|
|
@@ -78,7 +79,7 @@ export class FXLFramePoolManager {
|
|
|
78
79
|
|
|
79
80
|
// this.pages.push(fm);
|
|
80
81
|
this.pool.set(link.href, fm);
|
|
81
|
-
fm.width = 100 / this.length * (link.properties?.
|
|
82
|
+
fm.width = 100 / this.length * (link.properties?.otherProperties["orientation"] === Orientation.landscape || link.properties?.otherProperties["addBlank"] ? this.perPage : 1);
|
|
82
83
|
fm.height = this.height;
|
|
83
84
|
});
|
|
84
85
|
}
|
|
@@ -123,7 +124,7 @@ export class FXLFramePoolManager {
|
|
|
123
124
|
this.pool.forEach((frm, linkHref) => {
|
|
124
125
|
let i = this.pub.readingOrder.items.findIndex(l => l.href === linkHref);
|
|
125
126
|
const link = this.pub.readingOrder.items[i];
|
|
126
|
-
frm.width = 100 / this.length * (link.properties?.
|
|
127
|
+
frm.width = 100 / this.length * (link.properties?.otherProperties["orientation"] === Orientation.landscape || link.properties?.otherProperties["addBlank"] ? this.perPage : 1);
|
|
127
128
|
frm.height = this.height;
|
|
128
129
|
if(!frm.loaded) return;
|
|
129
130
|
const spread = this.spreader.findByLink(link)!;
|
|
@@ -602,7 +603,25 @@ export class FXLFramePoolManager {
|
|
|
602
603
|
return ret as DOMRect;
|
|
603
604
|
}
|
|
604
605
|
|
|
605
|
-
get
|
|
606
|
+
get viewport(): VisualNavigatorViewport {
|
|
607
|
+
const viewport: VisualNavigatorViewport = {
|
|
608
|
+
readingOrder: [],
|
|
609
|
+
progressions: new Map(),
|
|
610
|
+
positions: null
|
|
611
|
+
};
|
|
612
|
+
const currentSpread = this.spreader.currentSpread(this.currentSlide, this.perPage);
|
|
613
|
+
currentSpread.forEach(link => {
|
|
614
|
+
viewport.readingOrder.push(link.href);
|
|
615
|
+
viewport.progressions.set(link.href, { start: 0, end: 1 }); // FXL always uses [0,1] progression
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
// Set positions using currentNumbers
|
|
619
|
+
viewport.positions = this.getCurrentNumbers();
|
|
620
|
+
|
|
621
|
+
return viewport;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private getCurrentNumbers(): number[] {
|
|
606
625
|
if(this.perPage < 2) {
|
|
607
626
|
const link = this.pub.readingOrder.items[this.currentSlide];
|
|
608
627
|
return [link.properties?.otherProperties["number"]];
|
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import { Link, Links,
|
|
1
|
+
import { Link, Links, Page, Publication, ReadingProgression } from "@readium/shared";
|
|
2
|
+
|
|
3
|
+
export enum Orientation {
|
|
4
|
+
auto = "auto",
|
|
5
|
+
landscape = "landscape",
|
|
6
|
+
portrait = "portrait",
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export enum Spread {
|
|
10
|
+
auto = "auto",
|
|
11
|
+
both = "both",
|
|
12
|
+
none = "none",
|
|
13
|
+
landscape = "landscape",
|
|
14
|
+
}
|
|
2
15
|
|
|
3
16
|
export class FXLSpreader {
|
|
4
17
|
shift = true; // TODO getter
|
|
@@ -22,8 +35,8 @@ export class FXLSpreader {
|
|
|
22
35
|
});
|
|
23
36
|
// if(!orientation) item.Properties.Orientation = item.Width > item.Height ? "landscape" : "portrait";
|
|
24
37
|
}
|
|
25
|
-
const isLandscape = item.properties?.
|
|
26
|
-
if((!item.properties?.
|
|
38
|
+
const isLandscape = item.properties?.otherProperties["orientation"] === Orientation.landscape ? true : false;
|
|
39
|
+
if((!item.properties?.page || redo)) item.properties = item.properties?.add({
|
|
27
40
|
"page": isLandscape ? // If a landscape image
|
|
28
41
|
"center" : // Center it
|
|
29
42
|
((((this.shift ? 0 : 1) + index - this.nLandscape) % 2) ?
|
|
@@ -44,21 +57,21 @@ export class FXLSpreader {
|
|
|
44
57
|
if(item.length > 1)
|
|
45
58
|
return; // Only left with single-page "spreads"
|
|
46
59
|
const single = item[0];
|
|
47
|
-
const orientation = single.properties?.
|
|
60
|
+
const orientation = single.properties?.otherProperties["orientation"];
|
|
48
61
|
|
|
49
62
|
// First page is landscape/spread means no shift
|
|
50
|
-
if(index === 0 && (orientation === Orientation.landscape || (orientation !== Orientation.portrait && ((single.width || 0) > (single.height || 0) || single.properties?.
|
|
63
|
+
if(index === 0 && (orientation === Orientation.landscape || (orientation !== Orientation.portrait && ((single.width || 0) > (single.height || 0) || single.properties?.otherProperties["spread"] === Spread.both))))
|
|
51
64
|
this.shift = false;
|
|
52
65
|
|
|
53
66
|
// If last was a true single, and this spread is a center page (that's not special), something's wrong
|
|
54
|
-
if(wasLastSingle && single.properties?.
|
|
67
|
+
if(wasLastSingle && single.properties?.page === Page.center) {
|
|
55
68
|
this.spreads[index - 1][0].addProperties({"addBlank": true});
|
|
56
69
|
/*if(single.findFlag("final"))
|
|
57
70
|
this.nLandscape++;*/
|
|
58
71
|
}
|
|
59
72
|
|
|
60
73
|
// If this single page spread is an orphaned component of a double page spread (and it's not the first page)
|
|
61
|
-
if(orientation === Orientation.portrait && single.properties?.
|
|
74
|
+
if(orientation === Orientation.portrait && single.properties?.page !== "center" && single.properties?.otherProperties["number"] > 1)
|
|
62
75
|
wasLastSingle = true;
|
|
63
76
|
else
|
|
64
77
|
wasLastSingle = false;
|
|
@@ -72,7 +85,7 @@ export class FXLSpreader {
|
|
|
72
85
|
spine.items.forEach((item, index) => {
|
|
73
86
|
if(!index && this.shift) {
|
|
74
87
|
this.spreads.push([item]);
|
|
75
|
-
} else if(item.properties?.
|
|
88
|
+
} else if(item.properties?.page === Page.center) { // If a center (single) page spread, push immediately and reset current set
|
|
76
89
|
if(currentSet.length > 0) this.spreads.push(currentSet);
|
|
77
90
|
this.spreads.push([item]);
|
|
78
91
|
currentSet = [];
|
|
@@ -2,7 +2,6 @@ import {
|
|
|
2
2
|
fontSizeRangeConfig,
|
|
3
3
|
fontWeightRangeConfig,
|
|
4
4
|
fontWidthRangeConfig,
|
|
5
|
-
LayoutStrategy,
|
|
6
5
|
TextAlignment,
|
|
7
6
|
Theme
|
|
8
7
|
} from "../../preferences/Types";
|
|
@@ -37,8 +36,8 @@ export interface IEpubDefaults {
|
|
|
37
36
|
hyphens?: boolean | null,
|
|
38
37
|
invertFilter?: boolean | number | null,
|
|
39
38
|
invertGaijiFilter?: boolean | number | null,
|
|
39
|
+
iOSPatch?: boolean | null,
|
|
40
40
|
iPadOSPatch?: boolean | null,
|
|
41
|
-
layoutStrategy?: LayoutStrategy | null,
|
|
42
41
|
letterSpacing?: number | null,
|
|
43
42
|
ligatures?: boolean | null,
|
|
44
43
|
lineHeight?: number | null,
|
|
@@ -81,8 +80,8 @@ export class EpubDefaults {
|
|
|
81
80
|
hyphens: boolean | null;
|
|
82
81
|
invertFilter: boolean | number | null;
|
|
83
82
|
invertGaijiFilter: boolean | number | null;
|
|
83
|
+
iOSPatch: boolean;
|
|
84
84
|
iPadOSPatch: boolean;
|
|
85
|
-
layoutStrategy: LayoutStrategy | null;
|
|
86
85
|
letterSpacing: number | null;
|
|
87
86
|
ligatures: boolean | null;
|
|
88
87
|
lineHeight: number | null;
|
|
@@ -127,10 +126,12 @@ export class EpubDefaults {
|
|
|
127
126
|
this.hyphens = ensureBoolean(defaults.hyphens) ?? null;
|
|
128
127
|
this.invertFilter = ensureFilter(defaults.invertFilter) ?? false;
|
|
129
128
|
this.invertGaijiFilter = ensureFilter(defaults.invertGaijiFilter) ?? false;
|
|
129
|
+
this.iOSPatch = defaults.iOSPatch === false
|
|
130
|
+
? false
|
|
131
|
+
: ((sMLWithRequest.OS.iOS || sMLWithRequest.OS.iPadOS) && sMLWithRequest.iOSRequest === "mobile");
|
|
130
132
|
this.iPadOSPatch = defaults.iPadOSPatch === false
|
|
131
133
|
? false
|
|
132
134
|
: (sMLWithRequest.OS.iPadOS && sMLWithRequest.iOSRequest === "desktop");
|
|
133
|
-
this.layoutStrategy = ensureEnumValue<LayoutStrategy>(defaults.layoutStrategy, LayoutStrategy) || LayoutStrategy.lineLength;
|
|
134
135
|
this.letterSpacing = ensureNonNegative(defaults.letterSpacing) || null;
|
|
135
136
|
this.ligatures = ensureBoolean(defaults.ligatures) ?? null;
|
|
136
137
|
this.lineHeight = ensureNonNegative(defaults.lineHeight) || null;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ConfigurablePreferences } from "../../preferences/Configurable";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
LayoutStrategy,
|
|
5
4
|
TextAlignment,
|
|
6
5
|
Theme,
|
|
7
6
|
fontSizeRangeConfig,
|
|
@@ -34,8 +33,8 @@ export interface IEpubPreferences {
|
|
|
34
33
|
hyphens?: boolean | null,
|
|
35
34
|
invertFilter?: boolean | number | null,
|
|
36
35
|
invertGaijiFilter?: boolean | number | null,
|
|
36
|
+
iOSPatch?: boolean | null,
|
|
37
37
|
iPadOSPatch?: boolean | null,
|
|
38
|
-
layoutStrategy?: LayoutStrategy | null,
|
|
39
38
|
letterSpacing?: number | null,
|
|
40
39
|
ligatures?: boolean | null,
|
|
41
40
|
lineHeight?: number | null,
|
|
@@ -78,8 +77,8 @@ export class EpubPreferences implements ConfigurablePreferences {
|
|
|
78
77
|
hyphens?: boolean | null;
|
|
79
78
|
invertFilter?: boolean | number | null;
|
|
80
79
|
invertGaijiFilter?: boolean | number | null;
|
|
80
|
+
iOSPatch?: boolean | null;
|
|
81
81
|
iPadOSPatch?: boolean | null;
|
|
82
|
-
layoutStrategy?: LayoutStrategy | null;
|
|
83
82
|
letterSpacing?: number | null;
|
|
84
83
|
ligatures?: boolean | null;
|
|
85
84
|
lineHeight?: number | null;
|
|
@@ -121,8 +120,8 @@ export class EpubPreferences implements ConfigurablePreferences {
|
|
|
121
120
|
this.hyphens = ensureBoolean(preferences.hyphens);
|
|
122
121
|
this.invertFilter = ensureFilter(preferences.invertFilter);
|
|
123
122
|
this.invertGaijiFilter = ensureFilter(preferences.invertGaijiFilter);
|
|
123
|
+
this.iOSPatch = ensureBoolean(preferences.iOSPatch);
|
|
124
124
|
this.iPadOSPatch = ensureBoolean(preferences.iPadOSPatch);
|
|
125
|
-
this.layoutStrategy = ensureEnumValue<LayoutStrategy>(preferences.layoutStrategy, LayoutStrategy);
|
|
126
125
|
this.letterSpacing = ensureNonNegative(preferences.letterSpacing);
|
|
127
126
|
this.ligatures = ensureBoolean(preferences.ligatures);
|
|
128
127
|
this.lineHeight = ensureNonNegative(preferences.lineHeight);
|