@readium/navigator 2.4.0-beta.9 → 2.4.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 +597 -451
- package/dist/index.umd.cjs +190 -127
- package/package.json +2 -2
- package/src/audio/AudioNavigator.ts +155 -42
- package/src/audio/AudioPoolManager.ts +27 -14
- package/src/audio/engine/AudioEngine.ts +4 -3
- package/src/audio/engine/PreservePitchProcessor.js +166 -101
- package/src/audio/engine/PreservePitchWorklet.ts +2 -17
- package/src/audio/engine/WebAudioEngine.ts +138 -160
- package/src/audio/engine/index.ts +2 -2
- package/src/audio/index.ts +3 -3
- package/src/audio/preferences/AudioDefaults.ts +2 -2
- package/src/audio/preferences/AudioPreferences.ts +11 -11
- package/src/audio/preferences/AudioPreferencesEditor.ts +13 -13
- package/src/audio/preferences/AudioSettings.ts +3 -3
- package/src/audio/preferences/index.ts +4 -4
- package/src/audio/protection/AudioNavigatorProtector.ts +4 -4
- package/src/css/index.ts +1 -1
- package/src/epub/EpubNavigator.ts +52 -52
- package/src/epub/css/Properties.ts +15 -15
- package/src/epub/css/ReadiumCSS.ts +43 -43
- package/src/epub/css/index.ts +2 -2
- package/src/epub/frame/FrameBlobBuilder.ts +10 -11
- package/src/epub/frame/FrameComms.ts +1 -1
- package/src/epub/frame/FrameManager.ts +9 -9
- package/src/epub/frame/FramePoolManager.ts +13 -13
- package/src/epub/frame/index.ts +4 -4
- package/src/epub/fxl/FXLCoordinator.ts +3 -3
- package/src/epub/fxl/FXLFrameManager.ts +8 -8
- package/src/epub/fxl/FXLFramePoolManager.ts +13 -13
- package/src/epub/fxl/FXLPeripherals.ts +4 -4
- package/src/epub/fxl/index.ts +5 -5
- package/src/epub/index.ts +5 -5
- package/src/epub/preferences/EpubDefaults.ts +23 -23
- package/src/epub/preferences/EpubPreferences.ts +16 -16
- package/src/epub/preferences/EpubPreferencesEditor.ts +53 -53
- package/src/epub/preferences/EpubSettings.ts +101 -101
- package/src/epub/preferences/index.ts +4 -4
- package/src/helpers/index.ts +2 -2
- package/src/index.ts +8 -8
- package/src/injection/Injector.ts +42 -42
- package/src/injection/epubInjectables.ts +8 -8
- package/src/injection/index.ts +2 -2
- package/src/injection/webpubInjectables.ts +1 -1
- package/src/preferences/Configurable.ts +2 -2
- package/src/preferences/PreferencesEditor.ts +2 -2
- package/src/preferences/guards.ts +2 -2
- package/src/preferences/index.ts +5 -5
- package/src/protection/CopyProtector.ts +5 -1
- package/src/protection/DevToolsDetector.ts +16 -16
- package/src/protection/DragAndDropProtector.ts +14 -1
- package/src/protection/NavigatorProtector.ts +6 -6
- package/src/webpub/WebPubBlobBuilder.ts +1 -1
- package/src/webpub/WebPubFrameManager.ts +8 -8
- package/src/webpub/WebPubFramePoolManager.ts +7 -7
- package/src/webpub/WebPubNavigator.ts +27 -27
- package/src/webpub/css/Properties.ts +3 -3
- package/src/webpub/css/WebPubCSS.ts +11 -11
- package/src/webpub/css/index.ts +2 -2
- package/src/webpub/index.ts +6 -6
- package/src/webpub/preferences/WebPubDefaults.ts +12 -12
- package/src/webpub/preferences/WebPubPreferences.ts +8 -8
- package/src/webpub/preferences/WebPubPreferencesEditor.ts +31 -31
- package/src/webpub/preferences/WebPubSettings.ts +45 -45
- package/src/webpub/preferences/index.ts +4 -4
- package/types/src/audio/AudioNavigator.d.ts +34 -5
- package/types/src/audio/AudioPoolManager.d.ts +7 -4
- package/types/src/audio/engine/AudioEngine.d.ts +4 -3
- package/types/src/audio/engine/PreservePitchWorklet.d.ts +1 -4
- package/types/src/audio/engine/WebAudioEngine.d.ts +15 -9
- package/types/src/audio/engine/index.d.ts +2 -2
- package/types/src/audio/index.d.ts +3 -3
- package/types/src/audio/preferences/AudioPreferences.d.ts +9 -9
- package/types/src/audio/preferences/AudioPreferencesEditor.d.ts +4 -4
- package/types/src/audio/preferences/AudioSettings.d.ts +3 -3
- package/types/src/audio/preferences/index.d.ts +4 -4
- package/types/src/audio/protection/AudioNavigatorProtector.d.ts +2 -2
- package/types/src/css/index.d.ts +1 -1
- package/types/src/epub/EpubNavigator.d.ts +11 -11
- package/types/src/epub/css/Properties.d.ts +2 -2
- package/types/src/epub/css/ReadiumCSS.d.ts +3 -3
- package/types/src/epub/css/index.d.ts +2 -2
- package/types/src/epub/frame/FrameBlobBuilder.d.ts +1 -1
- package/types/src/epub/frame/FrameComms.d.ts +1 -1
- package/types/src/epub/frame/FrameManager.d.ts +2 -2
- package/types/src/epub/frame/FramePoolManager.d.ts +3 -3
- package/types/src/epub/frame/index.d.ts +4 -4
- package/types/src/epub/fxl/FXLFrameManager.d.ts +3 -3
- package/types/src/epub/fxl/FXLFramePoolManager.d.ts +5 -5
- package/types/src/epub/fxl/FXLPeripherals.d.ts +2 -2
- package/types/src/epub/fxl/index.d.ts +5 -5
- package/types/src/epub/index.d.ts +5 -5
- package/types/src/epub/preferences/EpubDefaults.d.ts +1 -1
- package/types/src/epub/preferences/EpubPreferences.d.ts +2 -2
- package/types/src/epub/preferences/EpubPreferencesEditor.d.ts +5 -5
- package/types/src/epub/preferences/EpubSettings.d.ts +4 -4
- package/types/src/epub/preferences/index.d.ts +4 -4
- package/types/src/helpers/index.d.ts +2 -2
- package/types/src/index.d.ts +8 -8
- package/types/src/injection/Injector.d.ts +1 -1
- package/types/src/injection/epubInjectables.d.ts +1 -1
- package/types/src/injection/index.d.ts +2 -2
- package/types/src/preferences/Configurable.d.ts +1 -1
- package/types/src/preferences/PreferencesEditor.d.ts +1 -1
- package/types/src/preferences/guards.d.ts +1 -1
- package/types/src/preferences/index.d.ts +5 -5
- package/types/src/protection/CopyProtector.d.ts +1 -0
- package/types/src/protection/DragAndDropProtector.d.ts +2 -0
- package/types/src/protection/NavigatorProtector.d.ts +1 -1
- package/types/src/webpub/WebPubBlobBuilder.d.ts +1 -1
- package/types/src/webpub/WebPubFrameManager.d.ts +2 -2
- package/types/src/webpub/WebPubFramePoolManager.d.ts +3 -3
- package/types/src/webpub/WebPubNavigator.d.ts +10 -10
- package/types/src/webpub/css/Properties.d.ts +2 -2
- package/types/src/webpub/css/WebPubCSS.d.ts +2 -2
- package/types/src/webpub/css/index.d.ts +2 -2
- package/types/src/webpub/index.d.ts +6 -6
- package/types/src/webpub/preferences/WebPubDefaults.d.ts +1 -1
- package/types/src/webpub/preferences/WebPubPreferences.d.ts +2 -2
- package/types/src/webpub/preferences/WebPubPreferencesEditor.d.ts +5 -5
- package/types/src/webpub/preferences/WebPubSettings.d.ts +4 -4
- package/types/src/webpub/preferences/index.d.ts +4 -4
package/src/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export * from './Navigator';
|
|
2
|
-
export * from './webpub';
|
|
3
|
-
export * from './epub';
|
|
4
|
-
export * from './audio';
|
|
5
|
-
export * from './helpers';
|
|
6
|
-
export * from './preferences';
|
|
7
|
-
export * from './css';
|
|
8
|
-
export * from './injection';
|
|
1
|
+
export * from './Navigator.ts';
|
|
2
|
+
export * from './webpub/index.ts';
|
|
3
|
+
export * from './epub/index.ts';
|
|
4
|
+
export * from './audio/index.ts';
|
|
5
|
+
export * from './helpers/index.ts';
|
|
6
|
+
export * from './preferences/index.ts';
|
|
7
|
+
export * from './css/index.ts';
|
|
8
|
+
export * from './injection/index.ts';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IInjectableRule, IInjectable, IInjector, IInjectablesConfig } from "./Injectable";
|
|
1
|
+
import { IInjectableRule, IInjectable, IInjector, IInjectablesConfig } from "./Injectable.ts";
|
|
2
2
|
import { Link } from "@readium/shared";
|
|
3
3
|
|
|
4
4
|
const inferTypeFromResource = (resource: IInjectable): string | undefined => {
|
|
@@ -6,19 +6,19 @@ const inferTypeFromResource = (resource: IInjectable): string | undefined => {
|
|
|
6
6
|
if ("blob" in resource && resource.blob.type) {
|
|
7
7
|
return resource.blob.type;
|
|
8
8
|
}
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
// For scripts, default to text/javascript
|
|
11
11
|
if (resource.as === "script") {
|
|
12
12
|
return "text/javascript";
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
// For links, try to infer from URL extension
|
|
16
16
|
if (resource.as === "link" && "url" in resource) {
|
|
17
17
|
const url = resource.url.toLowerCase();
|
|
18
18
|
if (url.endsWith(".css")) return "text/css";
|
|
19
19
|
if ([".js", ".mjs", ".cjs"].some(ext => url.endsWith(ext))) return "text/javascript";
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
return undefined;
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -30,7 +30,7 @@ const applyAttributes = (element: HTMLElement, resource: IInjectable): void => {
|
|
|
30
30
|
if (key === "type" || key === "rel" || key === "href" || key === "src") {
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
if (value !== undefined && value !== null) {
|
|
35
35
|
// Convert boolean attributes to proper HTML format
|
|
36
36
|
if (typeof value === "boolean") {
|
|
@@ -48,52 +48,52 @@ const applyAttributes = (element: HTMLElement, resource: IInjectable): void => {
|
|
|
48
48
|
const scriptify = (doc: Document, resource: IInjectable, source: string): HTMLScriptElement => {
|
|
49
49
|
const s = doc.createElement("script");
|
|
50
50
|
s.dataset.readium = "true";
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
// Set the injectable ID if provided
|
|
53
53
|
if (resource.id) {
|
|
54
54
|
s.id = resource.id;
|
|
55
55
|
}
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
// Apply root-level type if provided
|
|
58
58
|
const finalType = resource.type || inferTypeFromResource(resource);
|
|
59
59
|
if (finalType) {
|
|
60
60
|
s.type = finalType;
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
// Apply extra attributes
|
|
64
64
|
applyAttributes(s, resource);
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
// Always set src from the processed URL
|
|
67
67
|
s.src = source;
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
return s;
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
const linkify = (doc: Document, resource: IInjectable, source: string): HTMLLinkElement => {
|
|
73
73
|
const s = doc.createElement("link");
|
|
74
74
|
s.dataset.readium = "true";
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
// Set the injectable ID if provided
|
|
77
77
|
if (resource.id) {
|
|
78
78
|
s.id = resource.id;
|
|
79
79
|
}
|
|
80
|
-
|
|
80
|
+
|
|
81
81
|
// Apply root-level rel if provided
|
|
82
82
|
if (resource.rel) {
|
|
83
83
|
s.rel = resource.rel;
|
|
84
84
|
}
|
|
85
|
-
|
|
85
|
+
|
|
86
86
|
const finalType = resource.type || inferTypeFromResource(resource);
|
|
87
87
|
if (finalType) {
|
|
88
88
|
s.type = finalType;
|
|
89
89
|
}
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
// Apply extra attributes
|
|
92
92
|
applyAttributes(s, resource);
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
// Always set href from the processed URL
|
|
95
95
|
s.href = source;
|
|
96
|
-
|
|
96
|
+
|
|
97
97
|
return s;
|
|
98
98
|
};
|
|
99
99
|
|
|
@@ -103,7 +103,7 @@ export class Injector implements IInjector {
|
|
|
103
103
|
private readonly rules: IInjectableRule[];
|
|
104
104
|
private readonly allowedDomains: string[] = [];
|
|
105
105
|
private injectableIdCounter = 0;
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
constructor(config: IInjectablesConfig) {
|
|
108
108
|
// Validate allowed domains - they should be proper URLs for external resources
|
|
109
109
|
this.allowedDomains = (config.allowedDomains || []).map(domain => {
|
|
@@ -114,11 +114,11 @@ export class Injector implements IInjector {
|
|
|
114
114
|
throw new Error(`Invalid allowed domain: "${domain}". Must be a valid URL (e.g., "https://fonts.googleapis.com").`);
|
|
115
115
|
}
|
|
116
116
|
});
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
// Assign IDs to injectables that don't have them
|
|
119
119
|
this.rules = config.rules.map(rule => {
|
|
120
120
|
const processedRule: IInjectableRule = { ...rule };
|
|
121
|
-
|
|
121
|
+
|
|
122
122
|
// Process prepend injectables (reverse to preserve order when prepending)
|
|
123
123
|
if (rule.prepend) {
|
|
124
124
|
processedRule.prepend = rule.prepend.map(injectable => ({
|
|
@@ -126,7 +126,7 @@ export class Injector implements IInjector {
|
|
|
126
126
|
id: injectable.id || `injectable-${this.injectableIdCounter++}`
|
|
127
127
|
})).reverse(); // Reverse here so we can process normally later
|
|
128
128
|
}
|
|
129
|
-
|
|
129
|
+
|
|
130
130
|
// Process append injectables (keep original order)
|
|
131
131
|
if (rule.append) {
|
|
132
132
|
processedRule.append = rule.append.map(injectable => ({
|
|
@@ -134,11 +134,11 @@ export class Injector implements IInjector {
|
|
|
134
134
|
id: injectable.id || `injectable-${this.injectableIdCounter++}`
|
|
135
135
|
}));
|
|
136
136
|
}
|
|
137
|
-
|
|
137
|
+
|
|
138
138
|
return processedRule;
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
public dispose(): void {
|
|
143
143
|
// Cleanup any created blob URLs
|
|
144
144
|
for (const url of this.createdBlobUrls) {
|
|
@@ -155,7 +155,7 @@ export class Injector implements IInjector {
|
|
|
155
155
|
return [...this.allowedDomains]; // Return a copy to prevent external modification
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
public async injectForDocument(doc: Document, link: Link): Promise<void> {
|
|
158
|
+
public async injectForDocument(doc: Document, link: Link): Promise<void> {
|
|
159
159
|
for (const rule of this.rules) {
|
|
160
160
|
if (this.matchesRule(rule, link)) {
|
|
161
161
|
await this.applyRule(doc, rule);
|
|
@@ -166,7 +166,7 @@ export class Injector implements IInjector {
|
|
|
166
166
|
private matchesRule(rule: IInjectableRule, link: Link): boolean {
|
|
167
167
|
// Use the original href from the publication, not the resolved blob URL
|
|
168
168
|
const originalHref = link.href;
|
|
169
|
-
|
|
169
|
+
|
|
170
170
|
return rule.resources.some(pattern => {
|
|
171
171
|
if (pattern instanceof RegExp) {
|
|
172
172
|
return pattern.test(originalHref);
|
|
@@ -178,7 +178,7 @@ export class Injector implements IInjector {
|
|
|
178
178
|
private async getOrCreateBlobUrl(resource: IInjectable): Promise<string> {
|
|
179
179
|
// Use the injectable ID as the cache key
|
|
180
180
|
const cacheKey = resource.id!; // ID is guaranteed to exist after constructor
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
if (this.blobStore.has(cacheKey)) {
|
|
183
183
|
const entry = this.blobStore.get(cacheKey)!;
|
|
184
184
|
entry.refCount++;
|
|
@@ -191,7 +191,7 @@ export class Injector implements IInjector {
|
|
|
191
191
|
this.createdBlobUrls.add(url);
|
|
192
192
|
return url;
|
|
193
193
|
}
|
|
194
|
-
|
|
194
|
+
|
|
195
195
|
throw new Error("Resource must have a blob property");
|
|
196
196
|
}
|
|
197
197
|
|
|
@@ -231,7 +231,7 @@ export class Injector implements IInjector {
|
|
|
231
231
|
|
|
232
232
|
private createPreloadLink(doc: Document, resource: IInjectable, url: string): void {
|
|
233
233
|
if (resource.as !== "link" || resource.rel !== "preload") return;
|
|
234
|
-
|
|
234
|
+
|
|
235
235
|
// Create a new resource object with preload attributes
|
|
236
236
|
const preloadResource: IInjectable = {
|
|
237
237
|
...resource,
|
|
@@ -241,7 +241,7 @@ export class Injector implements IInjector {
|
|
|
241
241
|
as: resource.as
|
|
242
242
|
}
|
|
243
243
|
};
|
|
244
|
-
|
|
244
|
+
|
|
245
245
|
const preloadLink = linkify(doc, preloadResource, url);
|
|
246
246
|
doc.head.appendChild(preloadLink);
|
|
247
247
|
}
|
|
@@ -258,22 +258,22 @@ export class Injector implements IInjector {
|
|
|
258
258
|
|
|
259
259
|
private async applyRule(doc: Document, rule: IInjectableRule): Promise<void> {
|
|
260
260
|
const createdElements: { element: HTMLElement; url: string }[] = [];
|
|
261
|
-
|
|
261
|
+
|
|
262
262
|
// Collect all injectables that pass their conditions before modifying the document
|
|
263
|
-
const prependInjectables = rule.prepend ? rule.prepend.filter(resource =>
|
|
263
|
+
const prependInjectables = rule.prepend ? rule.prepend.filter(resource =>
|
|
264
264
|
!resource.condition || resource.condition(doc)
|
|
265
265
|
) : [];
|
|
266
|
-
|
|
267
|
-
const appendInjectables = rule.append ? rule.append.filter(resource =>
|
|
266
|
+
|
|
267
|
+
const appendInjectables = rule.append ? rule.append.filter(resource =>
|
|
268
268
|
!resource.condition || resource.condition(doc)
|
|
269
269
|
) : [];
|
|
270
|
-
|
|
270
|
+
|
|
271
271
|
try {
|
|
272
272
|
// Process prepend injectables first (already reversed in constructor)
|
|
273
273
|
for (const resource of prependInjectables) {
|
|
274
274
|
await this.processInjectable(resource, doc, createdElements, "prepend");
|
|
275
275
|
}
|
|
276
|
-
|
|
276
|
+
|
|
277
277
|
// Process append injectables next (in order)
|
|
278
278
|
for (const resource of appendInjectables) {
|
|
279
279
|
await this.processInjectable(resource, doc, createdElements, "append");
|
|
@@ -291,11 +291,11 @@ export class Injector implements IInjector {
|
|
|
291
291
|
throw error;
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
|
-
|
|
294
|
+
|
|
295
295
|
private async processInjectable(
|
|
296
|
-
resource: IInjectable,
|
|
297
|
-
doc: Document,
|
|
298
|
-
createdElements: { element: HTMLElement; url: string }[],
|
|
296
|
+
resource: IInjectable,
|
|
297
|
+
doc: Document,
|
|
298
|
+
createdElements: { element: HTMLElement; url: string }[],
|
|
299
299
|
position: "prepend" | "append"
|
|
300
300
|
): Promise<void> {
|
|
301
301
|
const target = resource.target === "body" ? doc.body : doc.head;
|
|
@@ -304,13 +304,13 @@ export class Injector implements IInjector {
|
|
|
304
304
|
let url: string | null = null;
|
|
305
305
|
try {
|
|
306
306
|
url = await this.getResourceUrl(resource, doc);
|
|
307
|
-
|
|
307
|
+
|
|
308
308
|
if (resource.rel === "preload" && "url" in resource) {
|
|
309
309
|
this.createPreloadLink(doc, resource, url);
|
|
310
310
|
} else {
|
|
311
311
|
const element = this.createElement(doc, resource, url);
|
|
312
312
|
createdElements.push({ element, url });
|
|
313
|
-
|
|
313
|
+
|
|
314
314
|
if (position === "prepend") {
|
|
315
315
|
target.prepend(element);
|
|
316
316
|
} else {
|
|
@@ -329,10 +329,10 @@ export class Injector implements IInjector {
|
|
|
329
329
|
private isValidUrl(url: string, doc: Document): boolean {
|
|
330
330
|
try {
|
|
331
331
|
const parsed = new URL(url, doc.baseURI);
|
|
332
|
-
|
|
332
|
+
|
|
333
333
|
// Allow data URLs
|
|
334
334
|
if (parsed.protocol === "data:") return true;
|
|
335
|
-
|
|
335
|
+
|
|
336
336
|
// Allow blob URLs that we created
|
|
337
337
|
if (parsed.protocol === "blob:" && this.createdBlobUrls.has(url)) {
|
|
338
338
|
return true;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IInjectableRule, IInjectable } from "../injection/Injectable";
|
|
2
|
-
import { stripJS, stripCSS } from "../helpers/minify";
|
|
1
|
+
import { IInjectableRule, IInjectable } from "../injection/Injectable.ts";
|
|
2
|
+
import { stripJS, stripCSS } from "../helpers/minify.ts";
|
|
3
3
|
import { Metadata, Layout, Link } from "@readium/shared";
|
|
4
4
|
|
|
5
5
|
import readiumCSSAfter from "@readium/css/css/dist/ReadiumCSS-after.css?raw";
|
|
@@ -15,15 +15,15 @@ import onloadProxyContent from "../dom/_readium_executionCleanup.js?raw";
|
|
|
15
15
|
*/
|
|
16
16
|
export function createReadiumEpubRules(metadata: Metadata, readingOrderItems: Link[]): IInjectableRule[] {
|
|
17
17
|
const isFixedLayout = metadata.effectiveLayout === Layout.fixed;
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
const htmlHrefs = readingOrderItems
|
|
20
20
|
.filter(item => item.mediaType.isHTML)
|
|
21
21
|
.map(item => item.href);
|
|
22
|
-
|
|
23
|
-
const resources = htmlHrefs.length > 0
|
|
24
|
-
? htmlHrefs
|
|
22
|
+
|
|
23
|
+
const resources = htmlHrefs.length > 0
|
|
24
|
+
? htmlHrefs
|
|
25
25
|
: [/\.xhtml$/, /\.html$/]; // fallback patterns
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
// Core injectables that should be prepended
|
|
28
28
|
const prependInjectables: IInjectable[] = [
|
|
29
29
|
// CSS Selector Generator - always injected
|
|
@@ -65,7 +65,7 @@ export function createReadiumEpubRules(metadata: Metadata, readingOrderItems: Li
|
|
|
65
65
|
blob: new Blob([stripCSS(readiumCSSBefore)], { type: "text/css" }),
|
|
66
66
|
rel: "stylesheet"
|
|
67
67
|
});
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
// Readium CSS Default and After - appended for reflowable
|
|
70
70
|
appendInjectables.unshift(
|
|
71
71
|
// Readium CSS Default - only for reflowable AND no existing styles
|
package/src/injection/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from "./Injectable";
|
|
2
|
-
export * from "./Injector";
|
|
1
|
+
export * from "./Injectable.ts";
|
|
2
|
+
export * from "./Injector.ts";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IInjectableRule, IInjectable } from "../injection/Injectable";
|
|
2
|
-
import { stripJS, stripCSS } from "../helpers/minify";
|
|
2
|
+
import { stripJS, stripCSS } from "../helpers/minify.ts";
|
|
3
3
|
import { Link } from "@readium/shared";
|
|
4
4
|
|
|
5
5
|
import readiumCSSWebPub from "@readium/css/css/dist/webPub/ReadiumCSS-webPub.css?raw";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IPreferencesEditor } from "./PreferencesEditor";
|
|
1
|
+
import { IPreferencesEditor } from "./PreferencesEditor.ts";
|
|
2
2
|
|
|
3
3
|
export interface ConfigurableSettings {
|
|
4
4
|
[key: string]: any;
|
|
@@ -12,4 +12,4 @@ export interface Configurable<ConfigurableSettings, ConfigurablePreferences> {
|
|
|
12
12
|
settings: ConfigurableSettings;
|
|
13
13
|
submitPreferences(preferences: ConfigurablePreferences): void;
|
|
14
14
|
preferencesEditor: IPreferencesEditor;
|
|
15
|
-
}
|
|
15
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExperimentKey, experiments } from './Types';
|
|
1
|
+
import { ExperimentKey, experiments } from './Types.ts';
|
|
2
2
|
|
|
3
3
|
export function ensureLessThanOrEqual<T extends number | null | undefined>(value: T, compareTo: T): T | undefined {
|
|
4
4
|
if (value === undefined || value === null) {
|
|
@@ -94,4 +94,4 @@ export function ensureExperiment(experimentsInput: ExperimentKey[] | null | unde
|
|
|
94
94
|
return null;
|
|
95
95
|
}
|
|
96
96
|
return experimentsInput.filter(exp => exp in experiments);
|
|
97
|
-
}
|
|
97
|
+
}
|
package/src/preferences/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from "./Configurable";
|
|
2
|
-
export * from "./Preference";
|
|
3
|
-
export * from "./PreferencesEditor";
|
|
4
|
-
export * from "./Types";
|
|
5
|
-
export * from "./guards";
|
|
1
|
+
export * from "./Configurable.ts";
|
|
2
|
+
export * from "./Preference.ts";
|
|
3
|
+
export * from "./PreferencesEditor.ts";
|
|
4
|
+
export * from "./Types.ts";
|
|
5
|
+
export * from "./guards.ts";
|
|
@@ -4,6 +4,7 @@ export interface CopyProtectionOptions {
|
|
|
4
4
|
|
|
5
5
|
export class CopyProtector {
|
|
6
6
|
private copyHandler: (event: ClipboardEvent) => void;
|
|
7
|
+
private unloadHandler: () => void;
|
|
7
8
|
|
|
8
9
|
constructor(options: CopyProtectionOptions = {}) {
|
|
9
10
|
this.copyHandler = (event: ClipboardEvent) => {
|
|
@@ -12,11 +13,14 @@ export class CopyProtector {
|
|
|
12
13
|
options.onCopyBlocked?.();
|
|
13
14
|
};
|
|
14
15
|
|
|
16
|
+
this.unloadHandler = () => this.destroy();
|
|
17
|
+
|
|
15
18
|
document.addEventListener("copy", this.copyHandler, true);
|
|
16
|
-
window.addEventListener("unload",
|
|
19
|
+
window.addEventListener("unload", this.unloadHandler);
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
public destroy() {
|
|
20
23
|
document.removeEventListener("copy", this.copyHandler, true);
|
|
24
|
+
window.removeEventListener("unload", this.unloadHandler);
|
|
21
25
|
}
|
|
22
26
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { sML } from "../helpers/sML";
|
|
2
|
-
import { WorkerConsole } from "./utils/WorkerConsole";
|
|
3
|
-
import { log, table, clear } from "./utils/console";
|
|
4
|
-
import { isBrave } from "./utils/platform";
|
|
5
|
-
import { match } from "./utils/match";
|
|
1
|
+
import { sML } from "../helpers/sML.ts";
|
|
2
|
+
import { WorkerConsole } from "./utils/WorkerConsole.ts";
|
|
3
|
+
import { log, table, clear } from "./utils/console.ts";
|
|
4
|
+
import { isBrave } from "./utils/platform.ts";
|
|
5
|
+
import { match } from "./utils/match.ts";
|
|
6
6
|
|
|
7
7
|
export interface DevToolsDetectorOptions {
|
|
8
8
|
/** Callback when Developer Tools are detected as open */
|
|
@@ -57,12 +57,12 @@ export class DevToolsDetector {
|
|
|
57
57
|
for (let i = 0; i < 500; i++) {
|
|
58
58
|
largeObject[`${i}`] = `${i}`;
|
|
59
59
|
}
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
const largeObjectArray: Record<string, string>[] = [];
|
|
62
62
|
for (let i = 0; i < 50; i++) {
|
|
63
63
|
largeObjectArray.push(largeObject);
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
return largeObjectArray;
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -81,7 +81,7 @@ export class DevToolsDetector {
|
|
|
81
81
|
*/
|
|
82
82
|
private async calcTablePrintTime(): Promise<number> {
|
|
83
83
|
const largeObjectArray = this.getLargeObjectArray();
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
if (this.workerConsole) {
|
|
86
86
|
try {
|
|
87
87
|
const result = await this.workerConsole.table(largeObjectArray);
|
|
@@ -105,7 +105,7 @@ export class DevToolsDetector {
|
|
|
105
105
|
*/
|
|
106
106
|
private async calcLogPrintTime(): Promise<number> {
|
|
107
107
|
const largeObjectArray = this.getLargeObjectArray();
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
if (this.workerConsole) {
|
|
110
110
|
const result = await this.workerConsole.log(largeObjectArray);
|
|
111
111
|
return result.time;
|
|
@@ -124,7 +124,7 @@ export class DevToolsDetector {
|
|
|
124
124
|
return match({
|
|
125
125
|
includes: [
|
|
126
126
|
() => !!sML.UA.Chrome,
|
|
127
|
-
() => !!sML.UA.Chromium,
|
|
127
|
+
() => !!sML.UA.Chromium,
|
|
128
128
|
() => !!sML.UA.Safari,
|
|
129
129
|
() => !!sML.UA.Firefox
|
|
130
130
|
],
|
|
@@ -203,7 +203,7 @@ export class DevToolsDetector {
|
|
|
203
203
|
private async detectDevTools(): Promise<boolean> {
|
|
204
204
|
// Primary method: Performance-based detection (from original library)
|
|
205
205
|
const performanceResult = await this.checkPerformanceBased();
|
|
206
|
-
|
|
206
|
+
|
|
207
207
|
if (performanceResult) {
|
|
208
208
|
return true;
|
|
209
209
|
}
|
|
@@ -227,7 +227,7 @@ export class DevToolsDetector {
|
|
|
227
227
|
|
|
228
228
|
if (currentlyOpen !== this.isOpen) {
|
|
229
229
|
this.isOpen = currentlyOpen;
|
|
230
|
-
|
|
230
|
+
|
|
231
231
|
if (currentlyOpen) {
|
|
232
232
|
this.options.onDetected();
|
|
233
233
|
} else {
|
|
@@ -258,7 +258,7 @@ export class DevToolsDetector {
|
|
|
258
258
|
public async checkNow(): Promise<boolean> {
|
|
259
259
|
const wasOpen = this.isOpen;
|
|
260
260
|
this.isOpen = await this.detectDevTools();
|
|
261
|
-
|
|
261
|
+
|
|
262
262
|
if (this.isOpen !== wasOpen) {
|
|
263
263
|
if (this.isOpen) {
|
|
264
264
|
this.options.onDetected();
|
|
@@ -266,7 +266,7 @@ export class DevToolsDetector {
|
|
|
266
266
|
this.options.onClosed();
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
|
-
|
|
269
|
+
|
|
270
270
|
return this.isOpen;
|
|
271
271
|
}
|
|
272
272
|
|
|
@@ -278,13 +278,13 @@ export class DevToolsDetector {
|
|
|
278
278
|
clearInterval(this.intervalId);
|
|
279
279
|
this.intervalId = undefined;
|
|
280
280
|
}
|
|
281
|
-
|
|
281
|
+
|
|
282
282
|
// Cleanup Web Worker
|
|
283
283
|
if (this.workerConsole) {
|
|
284
284
|
this.workerConsole.destroy();
|
|
285
285
|
this.workerConsole = undefined;
|
|
286
286
|
}
|
|
287
|
-
|
|
287
|
+
|
|
288
288
|
this.isOpen = false;
|
|
289
289
|
this.checkCount = 0;
|
|
290
290
|
}
|
|
@@ -5,7 +5,9 @@ export interface DragAndDropProtectionOptions {
|
|
|
5
5
|
|
|
6
6
|
export class DragAndDropProtector {
|
|
7
7
|
private dragstartHandler: (event: DragEvent) => void;
|
|
8
|
+
private dragoverHandler: (event: DragEvent) => void;
|
|
8
9
|
private dropHandler: (event: DragEvent) => void;
|
|
10
|
+
private unloadHandler: () => void;
|
|
9
11
|
|
|
10
12
|
constructor(options: DragAndDropProtectionOptions = {}) {
|
|
11
13
|
this.dragstartHandler = (event: DragEvent) => {
|
|
@@ -14,6 +16,12 @@ export class DragAndDropProtector {
|
|
|
14
16
|
options.onDragDetected?.(Array.from(event.dataTransfer?.types ?? []));
|
|
15
17
|
};
|
|
16
18
|
|
|
19
|
+
// dragover must be prevented to allow drop to fire in some browsers.
|
|
20
|
+
this.dragoverHandler = (event: DragEvent) => {
|
|
21
|
+
event.preventDefault();
|
|
22
|
+
event.stopPropagation();
|
|
23
|
+
};
|
|
24
|
+
|
|
17
25
|
this.dropHandler = (event: DragEvent) => {
|
|
18
26
|
event.preventDefault();
|
|
19
27
|
event.stopPropagation();
|
|
@@ -22,13 +30,18 @@ export class DragAndDropProtector {
|
|
|
22
30
|
options.onDropDetected?.(types, fileCount);
|
|
23
31
|
};
|
|
24
32
|
|
|
33
|
+
this.unloadHandler = () => this.destroy();
|
|
34
|
+
|
|
25
35
|
document.addEventListener("dragstart", this.dragstartHandler, true);
|
|
36
|
+
document.addEventListener("dragover", this.dragoverHandler, true);
|
|
26
37
|
document.addEventListener("drop", this.dropHandler, true);
|
|
27
|
-
window.addEventListener("unload",
|
|
38
|
+
window.addEventListener("unload", this.unloadHandler);
|
|
28
39
|
}
|
|
29
40
|
|
|
30
41
|
public destroy() {
|
|
31
42
|
document.removeEventListener("dragstart", this.dragstartHandler, true);
|
|
43
|
+
document.removeEventListener("dragover", this.dragoverHandler, true);
|
|
32
44
|
document.removeEventListener("drop", this.dropHandler, true);
|
|
45
|
+
window.removeEventListener("unload", this.unloadHandler);
|
|
33
46
|
}
|
|
34
47
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { AutomationDetector } from "./AutomationDetector";
|
|
2
|
-
import { DevToolsDetector } from "./DevToolsDetector";
|
|
3
|
-
import { IframeEmbeddingDetector } from "./IframeEmbeddingDetector";
|
|
4
|
-
import { PrintProtector } from "./PrintProtector";
|
|
5
|
-
import { ContextMenuProtector } from "./ContextMenuProtector";
|
|
1
|
+
import { AutomationDetector } from "./AutomationDetector.ts";
|
|
2
|
+
import { DevToolsDetector } from "./DevToolsDetector.ts";
|
|
3
|
+
import { IframeEmbeddingDetector } from "./IframeEmbeddingDetector.ts";
|
|
4
|
+
import { PrintProtector } from "./PrintProtector.ts";
|
|
5
|
+
import { ContextMenuProtector } from "./ContextMenuProtector.ts";
|
|
6
6
|
import { ContextMenuEvent } from "@readium/navigator-html-injectables";
|
|
7
|
-
import { IContentProtectionConfig } from "../Navigator";
|
|
7
|
+
import { IContentProtectionConfig } from "../Navigator.ts";
|
|
8
8
|
|
|
9
9
|
export const NAVIGATOR_SUSPICIOUS_ACTIVITY_EVENT = "readium:navigator:suspiciousActivity";
|
|
10
10
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Loader, ModuleName } from "@readium/navigator-html-injectables";
|
|
2
|
-
import { FrameComms } from "../epub/frame/FrameComms";
|
|
3
|
-
import { ReadiumWindow } from "../../../navigator-html-injectables/types/src/helpers/dom";
|
|
4
|
-
import { sML } from "../helpers";
|
|
5
|
-
import { IContentProtectionConfig, IKeyboardPeripheralsConfig } from "../Navigator";
|
|
2
|
+
import { FrameComms } from "../epub/frame/FrameComms.ts";
|
|
3
|
+
import type { ReadiumWindow } from "../../../navigator-html-injectables/types/src/helpers/dom";
|
|
4
|
+
import { sML } from "../helpers/index.ts";
|
|
5
|
+
import { IContentProtectionConfig, IKeyboardPeripheralsConfig } from "../Navigator.ts";
|
|
6
6
|
|
|
7
7
|
export class WebPubFrameManager {
|
|
8
8
|
private frame: HTMLIFrameElement;
|
|
@@ -31,7 +31,7 @@ export class WebPubFrameManager {
|
|
|
31
31
|
// Protect against background color bleeding
|
|
32
32
|
this.frame.style.backgroundColor = "#FFFFFF";
|
|
33
33
|
this.source = source;
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
// Use the provided content protection config directly without overriding defaults
|
|
36
36
|
this.contentProtectionConfig = { ...contentProtectionConfig };
|
|
37
37
|
this.keyboardPeripheralsConfig = [...keyboardPeripheralsConfig];
|
|
@@ -68,10 +68,10 @@ export class WebPubFrameManager {
|
|
|
68
68
|
|
|
69
69
|
private applyContentProtection() {
|
|
70
70
|
if (!this.comms) this.comms!.resume();
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
// Send content protection config
|
|
73
73
|
this.comms!.send("peripherals_protection", this.contentProtectionConfig);
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
// Send keyboard peripherals separately
|
|
76
76
|
if (this.keyboardPeripheralsConfig && this.keyboardPeripheralsConfig.length > 0) {
|
|
77
77
|
this.comms!.send("keyboard_peripherals", this.keyboardPeripheralsConfig);
|
|
@@ -186,4 +186,4 @@ export class WebPubFrameManager {
|
|
|
186
186
|
get ldr() {
|
|
187
187
|
return this.loader;
|
|
188
188
|
}
|
|
189
|
-
}
|
|
189
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ModuleName } from "@readium/navigator-html-injectables";
|
|
2
2
|
import { Locator, Publication } from "@readium/shared";
|
|
3
|
-
import { WebPubBlobBuilder } from "./WebPubBlobBuilder";
|
|
4
|
-
import { WebPubFrameManager } from "./WebPubFrameManager";
|
|
5
|
-
import { Injector } from "../injection/Injector";
|
|
6
|
-
import { IContentProtectionConfig, IKeyboardPeripheralsConfig } from "../Navigator";
|
|
3
|
+
import { WebPubBlobBuilder } from "./WebPubBlobBuilder.ts";
|
|
4
|
+
import { WebPubFrameManager } from "./WebPubFrameManager.ts";
|
|
5
|
+
import { Injector } from "../injection/Injector.ts";
|
|
6
|
+
import { IContentProtectionConfig, IKeyboardPeripheralsConfig } from "../Navigator.ts";
|
|
7
7
|
|
|
8
8
|
export class WebPubFramePoolManager {
|
|
9
9
|
private readonly container: HTMLElement;
|
|
@@ -19,7 +19,7 @@ export class WebPubFramePoolManager {
|
|
|
19
19
|
private readonly keyboardPeripheralsConfig: IKeyboardPeripheralsConfig;
|
|
20
20
|
|
|
21
21
|
constructor(
|
|
22
|
-
container: HTMLElement,
|
|
22
|
+
container: HTMLElement,
|
|
23
23
|
cssProperties?: { [key: string]: string },
|
|
24
24
|
injector?: Injector | null,
|
|
25
25
|
contentProtectionConfig: IContentProtectionConfig = {},
|
|
@@ -142,7 +142,7 @@ export class WebPubFramePoolManager {
|
|
|
142
142
|
if(!itm) return;
|
|
143
143
|
if(!this.blobs.has(href)) {
|
|
144
144
|
const blobBuilder = new WebPubBlobBuilder(
|
|
145
|
-
pub,
|
|
145
|
+
pub,
|
|
146
146
|
this.currentBaseURL || "",
|
|
147
147
|
itm,
|
|
148
148
|
{
|
|
@@ -250,4 +250,4 @@ export class WebPubFramePoolManager {
|
|
|
250
250
|
});
|
|
251
251
|
return ret as DOMRect;
|
|
252
252
|
}
|
|
253
|
-
}
|
|
253
|
+
}
|