@readium/navigator 2.2.0 → 2.2.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/index.js +1886 -1321
- package/dist/index.umd.cjs +218 -17
- package/package.json +1 -1
- package/src/css/Properties.ts +47 -0
- package/src/css/index.ts +1 -0
- package/src/epub/css/Properties.ts +10 -48
- package/src/epub/preferences/EpubDefaults.ts +1 -1
- package/src/epub/preferences/EpubPreferences.ts +1 -1
- package/src/epub/preferences/EpubPreferencesEditor.ts +30 -23
- package/src/index.ts +2 -1
- package/src/preferences/Types.ts +40 -0
- package/src/{epub/preferences → preferences}/guards.ts +5 -6
- package/src/preferences/index.ts +2 -1
- package/src/webpub/WebPubBlobBuilder.ts +26 -4
- package/src/webpub/WebPubFrameManager.ts +16 -0
- package/src/webpub/WebPubFramePoolManager.ts +49 -2
- package/src/webpub/WebPubNavigator.ts +87 -10
- package/src/webpub/css/Properties.ts +71 -0
- package/src/webpub/css/WebPubCSS.ts +42 -0
- package/src/webpub/css/WebPubStylesheet.ts +204 -0
- package/src/webpub/css/index.ts +3 -0
- package/src/webpub/index.ts +3 -1
- package/src/webpub/preferences/WebPubDefaults.ts +61 -0
- package/src/webpub/preferences/WebPubPreferences.ts +88 -0
- package/src/webpub/preferences/WebPubPreferencesEditor.ts +193 -0
- package/src/webpub/preferences/WebPubSettings.ts +88 -0
- package/src/webpub/preferences/index.ts +4 -0
- package/types/src/css/Properties.d.ts +20 -0
- package/types/src/css/index.d.ts +1 -0
- package/types/src/epub/css/Properties.d.ts +1 -21
- package/types/src/index.d.ts +1 -0
- package/types/src/preferences/Types.d.ts +8 -0
- package/types/src/preferences/guards.d.ts +9 -0
- package/types/src/preferences/index.d.ts +1 -0
- package/types/src/webpub/WebPubBlobBuilder.d.ts +5 -1
- package/types/src/webpub/WebPubFrameManager.d.ts +4 -0
- package/types/src/webpub/WebPubFramePoolManager.d.ts +8 -1
- package/types/src/webpub/WebPubNavigator.d.ts +23 -3
- package/types/src/webpub/css/Properties.d.ts +36 -0
- package/types/src/webpub/css/WebPubCSS.d.ts +10 -0
- package/types/src/webpub/css/WebPubStylesheet.d.ts +1 -0
- package/types/src/webpub/css/index.d.ts +3 -0
- package/types/src/webpub/index.d.ts +2 -0
- package/types/src/webpub/preferences/WebPubDefaults.d.ts +32 -0
- package/types/src/webpub/preferences/WebPubPreferences.d.ts +36 -0
- package/types/src/webpub/preferences/WebPubPreferencesEditor.d.ts +27 -0
- package/types/src/webpub/preferences/WebPubSettings.d.ts +35 -0
- package/types/src/webpub/preferences/index.d.ts +4 -0
package/package.json
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type BodyHyphens = "auto" | "none";
|
|
2
|
+
export type BoxSizing = "content-box" | "border-box";
|
|
3
|
+
export type FontOpticalSizing = "auto" | "none";
|
|
4
|
+
export type FontWidth = "ultra-condensed" | "extra-condensed" | "condensed" | "semi-condensed" | "normal" | "semi-expanded" | "expanded" | "extra-expanded" | "ultra-expanded" | number;
|
|
5
|
+
export type Ligatures = "common-ligatures" | "none";
|
|
6
|
+
export type TypeScale = 1 | 1.067 | 1.125 | 1.2 | 1.25 | 1.333 | 1.414 | 1.5 | 1.618;
|
|
7
|
+
export type View = "paged" | "scroll";
|
|
8
|
+
|
|
9
|
+
export abstract class Properties {
|
|
10
|
+
constructor() {}
|
|
11
|
+
|
|
12
|
+
protected toFlag(name: string) {
|
|
13
|
+
return `readium-${ name }-on`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected toUnitless(value: number) {
|
|
17
|
+
return value.toString();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
protected toPercentage(value: number, ratio: boolean = false) {
|
|
21
|
+
if (ratio || value > 0 && value <= 1) {
|
|
22
|
+
return `${ Math.round(value * 100) }%`;
|
|
23
|
+
} else {
|
|
24
|
+
return `${ value }%`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
protected toVw(value: number) {
|
|
29
|
+
const percentage = Math.round(value * 100);
|
|
30
|
+
return `${ Math.min(percentage, 100) }vw`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
protected toVh(value: number) {
|
|
34
|
+
const percentage = Math.round(value * 100);
|
|
35
|
+
return `${ Math.min(percentage, 100) }vh`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
protected toPx(value: number) {
|
|
39
|
+
return `${ value }px`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected toRem(value: number) {
|
|
43
|
+
return `${ value }rem`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
abstract toCSSProperties(): { [key: string]: string };
|
|
47
|
+
}
|
package/src/css/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Properties";
|
|
@@ -1,52 +1,14 @@
|
|
|
1
1
|
import { TextAlignment } from "../../preferences/Types";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
constructor() {}
|
|
13
|
-
|
|
14
|
-
protected toFlag(name: string) {
|
|
15
|
-
return `readium-${ name }-on`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
protected toUnitless(value: number) {
|
|
19
|
-
return value.toString();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
protected toPercentage(value: number, ratio: boolean = false) {
|
|
23
|
-
if (ratio || value > 0 && value <= 1) {
|
|
24
|
-
return `${ Math.round(value * 100) }%`;
|
|
25
|
-
} else {
|
|
26
|
-
return `${ value }%`;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
protected toVw(value: number) {
|
|
31
|
-
const percentage = Math.round(value * 100);
|
|
32
|
-
return `${ Math.min(percentage, 100) }vw`;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
protected toVh(value: number) {
|
|
36
|
-
const percentage = Math.round(value * 100);
|
|
37
|
-
return `${ Math.min(percentage, 100) }vh`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
protected toPx(value: number) {
|
|
41
|
-
return `${ value }px`;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
protected toRem(value: number) {
|
|
45
|
-
return `${ value }rem`;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
abstract toCSSProperties(): { [key: string]: string };
|
|
49
|
-
}
|
|
2
|
+
import {
|
|
3
|
+
BodyHyphens,
|
|
4
|
+
BoxSizing,
|
|
5
|
+
FontOpticalSizing,
|
|
6
|
+
FontWidth,
|
|
7
|
+
Ligatures,
|
|
8
|
+
Properties,
|
|
9
|
+
TypeScale,
|
|
10
|
+
View
|
|
11
|
+
} from "../../css/Properties";
|
|
50
12
|
|
|
51
13
|
export interface IUserProperties {
|
|
52
14
|
advancedSettings?: boolean | null;
|
|
@@ -5,9 +5,16 @@ import { EpubSettings } from "./EpubSettings";
|
|
|
5
5
|
import { BooleanPreference, EnumPreference, Preference, RangePreference } from "../../preferences/Preference";
|
|
6
6
|
import {
|
|
7
7
|
TextAlignment,
|
|
8
|
+
filterRangeConfig,
|
|
8
9
|
fontSizeRangeConfig,
|
|
9
10
|
fontWeightRangeConfig,
|
|
10
|
-
fontWidthRangeConfig
|
|
11
|
+
fontWidthRangeConfig,
|
|
12
|
+
letterSpacingRangeConfig,
|
|
13
|
+
lineHeightRangeConfig,
|
|
14
|
+
lineLengthRangeConfig,
|
|
15
|
+
paragraphIndentRangeConfig,
|
|
16
|
+
paragraphSpacingRangeConfig,
|
|
17
|
+
wordSpacingRangeConfig
|
|
11
18
|
} from "../../preferences/Types";
|
|
12
19
|
|
|
13
20
|
import defaultColors from "@readium/css/css/vars/colors.json";
|
|
@@ -85,8 +92,8 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
|
|
|
85
92
|
onChange: (newValue: number | boolean | null | undefined) => {
|
|
86
93
|
this.updatePreference("darkenFilter", newValue || null);
|
|
87
94
|
},
|
|
88
|
-
supportedRange:
|
|
89
|
-
step:
|
|
95
|
+
supportedRange: filterRangeConfig.range,
|
|
96
|
+
step: filterRangeConfig.step
|
|
90
97
|
});
|
|
91
98
|
}
|
|
92
99
|
|
|
@@ -192,8 +199,8 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
|
|
|
192
199
|
onChange: (newValue: number | boolean | null | undefined) => {
|
|
193
200
|
this.updatePreference("invertFilter", newValue || null);
|
|
194
201
|
},
|
|
195
|
-
supportedRange:
|
|
196
|
-
step:
|
|
202
|
+
supportedRange: filterRangeConfig.range,
|
|
203
|
+
step: filterRangeConfig.step
|
|
197
204
|
});
|
|
198
205
|
}
|
|
199
206
|
|
|
@@ -205,8 +212,8 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
|
|
|
205
212
|
onChange: (newValue: number | boolean | null | undefined) => {
|
|
206
213
|
this.updatePreference("invertGaijiFilter", newValue || null);
|
|
207
214
|
},
|
|
208
|
-
supportedRange:
|
|
209
|
-
step:
|
|
215
|
+
supportedRange: filterRangeConfig.range,
|
|
216
|
+
step: filterRangeConfig.step
|
|
210
217
|
});
|
|
211
218
|
}
|
|
212
219
|
|
|
@@ -240,8 +247,8 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
|
|
|
240
247
|
onChange: (newValue: number | null | undefined) => {
|
|
241
248
|
this.updatePreference("letterSpacing", newValue || null);
|
|
242
249
|
},
|
|
243
|
-
supportedRange:
|
|
244
|
-
step: .
|
|
250
|
+
supportedRange: letterSpacingRangeConfig.range,
|
|
251
|
+
step: letterSpacingRangeConfig.step
|
|
245
252
|
});
|
|
246
253
|
}
|
|
247
254
|
|
|
@@ -266,8 +273,8 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
|
|
|
266
273
|
onChange: (newValue: number | null | undefined) => {
|
|
267
274
|
this.updatePreference("lineHeight", newValue || null);
|
|
268
275
|
},
|
|
269
|
-
supportedRange:
|
|
270
|
-
step: .
|
|
276
|
+
supportedRange: lineHeightRangeConfig.range,
|
|
277
|
+
step: lineHeightRangeConfig.step
|
|
271
278
|
});
|
|
272
279
|
}
|
|
273
280
|
|
|
@@ -290,8 +297,8 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
|
|
|
290
297
|
onChange: (newValue: number | null | undefined) => {
|
|
291
298
|
this.updatePreference("maximalLineLength", newValue);
|
|
292
299
|
},
|
|
293
|
-
supportedRange:
|
|
294
|
-
step:
|
|
300
|
+
supportedRange: lineLengthRangeConfig.range,
|
|
301
|
+
step: lineLengthRangeConfig.step
|
|
295
302
|
});
|
|
296
303
|
}
|
|
297
304
|
|
|
@@ -303,8 +310,8 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
|
|
|
303
310
|
onChange: (newValue: number | null | undefined) => {
|
|
304
311
|
this.updatePreference("minimalLineLength", newValue);
|
|
305
312
|
},
|
|
306
|
-
supportedRange:
|
|
307
|
-
step:
|
|
313
|
+
supportedRange: lineLengthRangeConfig.range,
|
|
314
|
+
step: lineLengthRangeConfig.step
|
|
308
315
|
});
|
|
309
316
|
}
|
|
310
317
|
|
|
@@ -327,8 +334,8 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
|
|
|
327
334
|
onChange: (newValue: number | null | undefined) => {
|
|
328
335
|
this.updatePreference("optimalLineLength", newValue as number);
|
|
329
336
|
},
|
|
330
|
-
supportedRange:
|
|
331
|
-
step:
|
|
337
|
+
supportedRange: lineLengthRangeConfig.range,
|
|
338
|
+
step: lineLengthRangeConfig.step
|
|
332
339
|
});
|
|
333
340
|
}
|
|
334
341
|
|
|
@@ -351,8 +358,8 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
|
|
|
351
358
|
onChange: (newValue: number | null | undefined) => {
|
|
352
359
|
this.updatePreference("paragraphIndent", newValue || null);
|
|
353
360
|
},
|
|
354
|
-
supportedRange:
|
|
355
|
-
step: .
|
|
361
|
+
supportedRange: paragraphIndentRangeConfig.range,
|
|
362
|
+
step: paragraphIndentRangeConfig.step
|
|
356
363
|
});
|
|
357
364
|
}
|
|
358
365
|
|
|
@@ -364,8 +371,8 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
|
|
|
364
371
|
onChange: (newValue: number | null | undefined) => {
|
|
365
372
|
this.updatePreference("paragraphSpacing", newValue || null);
|
|
366
373
|
},
|
|
367
|
-
supportedRange:
|
|
368
|
-
step: .
|
|
374
|
+
supportedRange: paragraphSpacingRangeConfig.range,
|
|
375
|
+
step: paragraphSpacingRangeConfig.step
|
|
369
376
|
});
|
|
370
377
|
}
|
|
371
378
|
|
|
@@ -501,8 +508,8 @@ export class EpubPreferencesEditor implements IPreferencesEditor {
|
|
|
501
508
|
onChange: (newValue: number | null | undefined) => {
|
|
502
509
|
this.updatePreference("wordSpacing", newValue || null);
|
|
503
510
|
},
|
|
504
|
-
supportedRange:
|
|
505
|
-
step:
|
|
511
|
+
supportedRange: wordSpacingRangeConfig.range,
|
|
512
|
+
step: wordSpacingRangeConfig.step
|
|
506
513
|
});
|
|
507
514
|
}
|
|
508
515
|
}
|
package/src/index.ts
CHANGED
package/src/preferences/Types.ts
CHANGED
|
@@ -10,6 +10,11 @@ export type RangeConfig = {
|
|
|
10
10
|
step: number
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
export const filterRangeConfig: RangeConfig = {
|
|
14
|
+
range: [0, 100],
|
|
15
|
+
step: 1
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
export const fontSizeRangeConfig: RangeConfig = {
|
|
14
19
|
range: [0.7, 4],
|
|
15
20
|
step: 0.05
|
|
@@ -23,4 +28,39 @@ export const fontWeightRangeConfig: RangeConfig = {
|
|
|
23
28
|
export const fontWidthRangeConfig: RangeConfig = {
|
|
24
29
|
range: [50, 250],
|
|
25
30
|
step: 10
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const letterSpacingRangeConfig: RangeConfig = {
|
|
34
|
+
range: [0, 1],
|
|
35
|
+
step: .125
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const lineHeightRangeConfig: RangeConfig = {
|
|
39
|
+
range: [1, 2],
|
|
40
|
+
step: .1
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const lineLengthRangeConfig: RangeConfig = {
|
|
44
|
+
range: [20, 100],
|
|
45
|
+
step: 1
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const paragraphIndentRangeConfig: RangeConfig = {
|
|
49
|
+
range: [0, 3],
|
|
50
|
+
step: .25
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const paragraphSpacingRangeConfig: RangeConfig = {
|
|
54
|
+
range: [0, 3],
|
|
55
|
+
step: .25
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const wordSpacingRangeConfig: RangeConfig = {
|
|
59
|
+
range: [0, 2],
|
|
60
|
+
step: .125
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const zoomRangeConfig: RangeConfig = {
|
|
64
|
+
range: [0.7, 4],
|
|
65
|
+
step: 0.05
|
|
26
66
|
}
|
|
@@ -29,14 +29,13 @@ export function ensureString(value: string | null | undefined): string | null |
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export function ensureBoolean(value: boolean | null | undefined): boolean | null | undefined {
|
|
32
|
-
return typeof value === "boolean"
|
|
33
|
-
? value
|
|
34
|
-
: value === undefined || value === null
|
|
35
|
-
? value
|
|
32
|
+
return typeof value === "boolean"
|
|
33
|
+
? value
|
|
34
|
+
: value === undefined || value === null
|
|
35
|
+
? value
|
|
36
36
|
: undefined;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
40
39
|
export function ensureEnumValue<T extends string>(value: T | null | undefined, enumType: Record<T, string>): T | null | undefined {
|
|
41
40
|
if (value === undefined) {
|
|
42
41
|
return undefined;
|
|
@@ -83,4 +82,4 @@ export function ensureValueInRange(value: number | null | undefined, range: [num
|
|
|
83
82
|
|
|
84
83
|
export function withFallback<T>(value: T | null | undefined, defaultValue: T | null): T | null {
|
|
85
84
|
return value === undefined ? defaultValue : value;
|
|
86
|
-
}
|
|
85
|
+
}
|
package/src/preferences/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Link, Publication } from "@readium/shared";
|
|
2
|
+
import { webPubStylesheet } from "./css/WebPubStylesheet";
|
|
2
3
|
|
|
3
4
|
// Utilities (matching FrameBlobBuilder pattern)
|
|
4
5
|
const blobify = (source: string, type: string) => URL.createObjectURL(new Blob([source], { type }));
|
|
@@ -9,6 +10,12 @@ const scriptify = (doc: Document, source: string) => {
|
|
|
9
10
|
s.src = source.startsWith("blob:") ? source : blobify(source, "text/javascript");
|
|
10
11
|
return s;
|
|
11
12
|
}
|
|
13
|
+
const styleify = (doc: Document, source: string) => {
|
|
14
|
+
const s = doc.createElement("style");
|
|
15
|
+
s.dataset.readium = "true";
|
|
16
|
+
s.textContent = source;
|
|
17
|
+
return s;
|
|
18
|
+
}
|
|
12
19
|
|
|
13
20
|
type CacheFunction = () => string;
|
|
14
21
|
const resourceBlobCache = new Map<string, string>();
|
|
@@ -46,11 +53,13 @@ export class WebPubBlobBuilder {
|
|
|
46
53
|
private readonly item: Link;
|
|
47
54
|
private readonly burl: string;
|
|
48
55
|
private readonly pub: Publication;
|
|
56
|
+
private readonly cssProperties?: { [key: string]: string };
|
|
49
57
|
|
|
50
|
-
constructor(pub: Publication, baseURL: string, item: Link) {
|
|
58
|
+
constructor(pub: Publication, baseURL: string, item: Link, cssProperties?: { [key: string]: string }) {
|
|
51
59
|
this.pub = pub;
|
|
52
60
|
this.item = item;
|
|
53
61
|
this.burl = item.toURL(baseURL) || "";
|
|
62
|
+
this.cssProperties = cssProperties;
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
public async build(): Promise<string> {
|
|
@@ -74,7 +83,7 @@ export class WebPubBlobBuilder {
|
|
|
74
83
|
const details = perror.querySelector("div");
|
|
75
84
|
throw new Error(`Failed parsing item ${this.item.href}: ${details?.textContent || perror.textContent}`);
|
|
76
85
|
}
|
|
77
|
-
return this.finalizeDOM(doc, this.burl, this.item.mediaType, txt);
|
|
86
|
+
return this.finalizeDOM(doc, this.burl, this.item.mediaType, txt, this.cssProperties);
|
|
78
87
|
}
|
|
79
88
|
|
|
80
89
|
private hasExecutable(doc: Document): boolean {
|
|
@@ -84,9 +93,23 @@ export class WebPubBlobBuilder {
|
|
|
84
93
|
);
|
|
85
94
|
}
|
|
86
95
|
|
|
87
|
-
private
|
|
96
|
+
private setProperties(cssProperties: { [key: string]: string }, doc: Document) {
|
|
97
|
+
for (const key in cssProperties) {
|
|
98
|
+
const value = cssProperties[key];
|
|
99
|
+
if (value) doc.documentElement.style.setProperty(key, value);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private finalizeDOM(doc: Document, base: string | undefined, mediaType: any, txt?: string, cssProperties?: { [key: string]: string }): string {
|
|
88
104
|
if(!doc) return "";
|
|
89
105
|
|
|
106
|
+
// Add WebPubCSS stylesheet at end of head (like EPUB ReadiumCSS-after)
|
|
107
|
+
const webPubStyle = styleify(doc, webPubStylesheet);
|
|
108
|
+
doc.head.appendChild(webPubStyle);
|
|
109
|
+
if (cssProperties) {
|
|
110
|
+
this.setProperties(cssProperties, doc);
|
|
111
|
+
}
|
|
112
|
+
|
|
90
113
|
doc.body.querySelectorAll("img").forEach((img) => {
|
|
91
114
|
img.setAttribute("fetchpriority", "high");
|
|
92
115
|
});
|
|
@@ -98,7 +121,6 @@ export class WebPubBlobBuilder {
|
|
|
98
121
|
doc.head.firstChild!.before(b);
|
|
99
122
|
}
|
|
100
123
|
|
|
101
|
-
|
|
102
124
|
const hasExecutable = this.hasExecutable(doc);
|
|
103
125
|
if(hasExecutable) doc.head.firstChild!.before(rBefore(doc));
|
|
104
126
|
doc.head.firstChild!.before(cssSelectorGenerator(doc));
|
|
@@ -8,6 +8,7 @@ export class WebPubFrameManager {
|
|
|
8
8
|
private loader: Loader | undefined;
|
|
9
9
|
public readonly source: string;
|
|
10
10
|
private comms: FrameComms | undefined;
|
|
11
|
+
private hidden: boolean = true;
|
|
11
12
|
private destroyed: boolean = false;
|
|
12
13
|
|
|
13
14
|
private currModules: ModuleName[] = [];
|
|
@@ -69,6 +70,7 @@ export class WebPubFrameManager {
|
|
|
69
70
|
this.frame.style.setProperty("aria-hidden", "true");
|
|
70
71
|
this.frame.style.opacity = "0";
|
|
71
72
|
this.frame.style.pointerEvents = "none";
|
|
73
|
+
this.hidden = true;
|
|
72
74
|
|
|
73
75
|
if(this.frame.parentElement) {
|
|
74
76
|
if(this.comms === undefined || !this.comms.ready) return;
|
|
@@ -97,6 +99,7 @@ export class WebPubFrameManager {
|
|
|
97
99
|
this.frame.style.removeProperty("aria-hidden");
|
|
98
100
|
this.frame.style.removeProperty("opacity");
|
|
99
101
|
this.frame.style.removeProperty("pointer-events");
|
|
102
|
+
this.hidden = false;
|
|
100
103
|
|
|
101
104
|
if (sML.UA.WebKit) {
|
|
102
105
|
this.comms?.send("force_webkit_recalc", undefined);
|
|
@@ -115,6 +118,19 @@ export class WebPubFrameManager {
|
|
|
115
118
|
});
|
|
116
119
|
}
|
|
117
120
|
|
|
121
|
+
setCSSProperties(properties: { [key: string]: string }) {
|
|
122
|
+
if(this.destroyed || !this.frame.contentWindow) return;
|
|
123
|
+
|
|
124
|
+
// We need to resume and halt postMessage to update the properties
|
|
125
|
+
// if the frame is hidden since it's been halted in hide()
|
|
126
|
+
if (this.hidden) {
|
|
127
|
+
if (this.comms) this.comms?.resume();
|
|
128
|
+
else this.comms = new FrameComms(this.frame.contentWindow!, this.source);
|
|
129
|
+
}
|
|
130
|
+
this.comms?.send("update_properties", properties);
|
|
131
|
+
if (this.hidden) this.comms?.halt();
|
|
132
|
+
}
|
|
133
|
+
|
|
118
134
|
get iframe() {
|
|
119
135
|
if(this.destroyed) throw Error("Trying to use frame when it doesn't exist");
|
|
120
136
|
return this.frame;
|
|
@@ -6,13 +6,16 @@ import { WebPubFrameManager } from "./WebPubFrameManager";
|
|
|
6
6
|
export class WebPubFramePoolManager {
|
|
7
7
|
private readonly container: HTMLElement;
|
|
8
8
|
private _currentFrame: WebPubFrameManager | undefined;
|
|
9
|
+
private currentCssProperties: { [key: string]: string } | undefined;
|
|
9
10
|
private readonly pool: Map<string, WebPubFrameManager> = new Map();
|
|
10
11
|
private readonly blobs: Map<string, string> = new Map();
|
|
11
12
|
private readonly inprogress: Map<string, Promise<void>> = new Map();
|
|
13
|
+
private pendingUpdates: Map<string, { inPool: boolean }> = new Map();
|
|
12
14
|
private currentBaseURL: string | undefined;
|
|
13
15
|
|
|
14
|
-
constructor(container: HTMLElement) {
|
|
16
|
+
constructor(container: HTMLElement, cssProperties?: { [key: string]: string }) {
|
|
15
17
|
this.container = container;
|
|
18
|
+
this.currentCssProperties = cssProperties;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
async destroy() {
|
|
@@ -90,11 +93,22 @@ export class WebPubFramePoolManager {
|
|
|
90
93
|
this.currentBaseURL = pub.baseURL;
|
|
91
94
|
|
|
92
95
|
const creator = async (href: string) => {
|
|
96
|
+
// Check if blob needs to be recreated due to CSS property changes
|
|
97
|
+
if(this.pendingUpdates.has(href) && this.pendingUpdates.get(href)?.inPool === false) {
|
|
98
|
+
const url = this.blobs.get(href);
|
|
99
|
+
if(url) {
|
|
100
|
+
URL.revokeObjectURL(url);
|
|
101
|
+
this.blobs.delete(href);
|
|
102
|
+
this.pendingUpdates.delete(href);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
93
106
|
if(this.pool.has(href)) {
|
|
94
107
|
const fm = this.pool.get(href)!;
|
|
95
108
|
if(!this.blobs.has(href)) {
|
|
96
109
|
await fm.destroy();
|
|
97
110
|
this.pool.delete(href);
|
|
111
|
+
this.pendingUpdates.delete(href);
|
|
98
112
|
} else {
|
|
99
113
|
await fm.load(modules);
|
|
100
114
|
return;
|
|
@@ -103,7 +117,7 @@ export class WebPubFramePoolManager {
|
|
|
103
117
|
const itm = pub.readingOrder.findWithHref(href);
|
|
104
118
|
if(!itm) return;
|
|
105
119
|
if(!this.blobs.has(href)) {
|
|
106
|
-
const blobBuilder = new WebPubBlobBuilder(pub, this.currentBaseURL || "", itm);
|
|
120
|
+
const blobBuilder = new WebPubBlobBuilder(pub, this.currentBaseURL || "", itm, this.currentCssProperties);
|
|
107
121
|
const blobURL = await blobBuilder.build();
|
|
108
122
|
this.blobs.set(href, blobURL);
|
|
109
123
|
}
|
|
@@ -139,6 +153,39 @@ export class WebPubFramePoolManager {
|
|
|
139
153
|
this.inprogress.delete(newHref);
|
|
140
154
|
}
|
|
141
155
|
|
|
156
|
+
setCSSProperties(properties: { [key: string]: string }) {
|
|
157
|
+
const deepCompare = (obj1: { [key: string]: string }, obj2: { [key: string]: string }) => {
|
|
158
|
+
const keys1 = Object.keys(obj1);
|
|
159
|
+
const keys2 = Object.keys(obj2);
|
|
160
|
+
|
|
161
|
+
if (keys1.length !== keys2.length) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
for (const key of keys1) {
|
|
166
|
+
if (obj1[key] !== obj2[key]) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return true;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// If CSSProperties have changed, we update the currentCssProperties,
|
|
175
|
+
// and set the CSS Properties to all frames already in the pool
|
|
176
|
+
// We also need to invalidate the blobs and recreate them with the new properties.
|
|
177
|
+
// We do that in update, by updating them when needed (they are added into the pool)
|
|
178
|
+
// so that we do not invalidate and recreate blobs over and over again.
|
|
179
|
+
if(!deepCompare(this.currentCssProperties || {}, properties)) {
|
|
180
|
+
this.currentCssProperties = properties;
|
|
181
|
+
this.pool.forEach((frame) => {
|
|
182
|
+
frame.setCSSProperties(properties);
|
|
183
|
+
});
|
|
184
|
+
for (const href of this.blobs.keys()) {
|
|
185
|
+
this.pendingUpdates.set(href, { inPool: this.pool.has(href) });
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
142
189
|
get currentFrames(): (WebPubFrameManager | undefined)[] {
|
|
143
190
|
return [this._currentFrame];
|
|
144
191
|
}
|