@readium/navigator-html-injectables 2.3.1-alpha.2 → 2.4.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/index.js +852 -701
  2. package/dist/index.umd.cjs +24 -13
  3. package/package.json +8 -8
  4. package/src/Loader.ts +3 -3
  5. package/src/comms/comms.ts +5 -5
  6. package/src/comms/index.ts +3 -3
  7. package/src/helpers/css.ts +2 -4
  8. package/src/helpers/document.ts +13 -10
  9. package/src/helpers/locator.ts +2 -2
  10. package/src/index.ts +4 -4
  11. package/src/modules/Decorator.ts +18 -18
  12. package/src/modules/Module.ts +4 -4
  13. package/src/modules/ModuleLibrary.ts +15 -11
  14. package/src/modules/Peripherals.ts +70 -61
  15. package/src/modules/index.ts +4 -4
  16. package/src/modules/setup/FixedSetup.ts +6 -6
  17. package/src/modules/setup/ReflowableSetup.ts +6 -6
  18. package/src/modules/setup/Setup.ts +5 -5
  19. package/src/modules/setup/WebPubSetup.ts +5 -5
  20. package/src/modules/snapper/CJKVerticalSnapper.ts +322 -0
  21. package/src/modules/snapper/ColumnSnapper.ts +161 -99
  22. package/src/modules/snapper/ScrollSnapper.ts +18 -18
  23. package/src/modules/snapper/Snapper.ts +5 -5
  24. package/src/modules/snapper/WebPubSnapper.ts +15 -15
  25. package/src/protection/BulkCopyProtector.ts +15 -15
  26. package/src/protection/KeyCombinationManager.ts +8 -8
  27. package/src/protection/PatternAnalyzer.ts +18 -18
  28. package/src/protection/PrintProtector.ts +12 -12
  29. package/src/protection/SelectionAnalyzer.ts +1 -1
  30. package/src/protection/config.ts +4 -4
  31. package/src/protection/index.ts +6 -6
  32. package/src/vendor/hypothesis/anchoring/html.ts +1 -1
  33. package/src/vendor/hypothesis/anchoring/types.ts +1 -1
  34. package/types/src/Loader.d.ts +2 -2
  35. package/types/src/comms/comms.d.ts +2 -2
  36. package/types/src/comms/index.d.ts +3 -3
  37. package/types/src/helpers/css.d.ts +1 -2
  38. package/types/src/helpers/document.d.ts +1 -1
  39. package/types/src/index.d.ts +4 -4
  40. package/types/src/modules/Decorator.d.ts +4 -4
  41. package/types/src/modules/Module.d.ts +3 -3
  42. package/types/src/modules/ModuleLibrary.d.ts +2 -2
  43. package/types/src/modules/Peripherals.d.ts +10 -9
  44. package/types/src/modules/index.d.ts +4 -4
  45. package/types/src/modules/setup/FixedSetup.d.ts +4 -4
  46. package/types/src/modules/setup/ReflowableSetup.d.ts +3 -3
  47. package/types/src/modules/setup/Setup.d.ts +4 -4
  48. package/types/src/modules/setup/WebPubSetup.d.ts +3 -3
  49. package/types/src/modules/snapper/CJKVerticalSnapper.d.ts +57 -0
  50. package/types/src/modules/snapper/ColumnSnapper.d.ts +16 -5
  51. package/types/src/modules/snapper/ScrollSnapper.d.ts +5 -5
  52. package/types/src/modules/snapper/Snapper.d.ts +4 -4
  53. package/types/src/modules/snapper/WebPubSnapper.d.ts +5 -5
  54. package/types/src/protection/BulkCopyProtector.d.ts +1 -1
  55. package/types/src/protection/KeyCombinationManager.d.ts +3 -3
  56. package/types/src/protection/PrintProtector.d.ts +4 -4
  57. package/types/src/protection/config.d.ts +3 -3
  58. package/types/src/protection/index.d.ts +6 -6
  59. package/types/src/vendor/hypothesis/anchoring/html.d.ts +1 -1
  60. package/types/src/vendor/hypothesis/anchoring/types.d.ts +1 -1
@@ -1,20 +1,20 @@
1
- import { Comms } from "../comms/comms";
2
- import { Module } from "./Module";
3
- import { ReadiumWindow, nearestInteractiveElement } from "../helpers/dom";
4
- import { BulkCopyProtector, BulkCopyProtectionOptions } from "../protection/BulkCopyProtector";
5
- import { SelectionAnalyzer, SelectionAnalyzerOptions } from "../protection/SelectionAnalyzer";
6
- import {
7
- KeyboardPeripheral
8
- } from "../protection";
9
- import { SuspiciousActivityType } from "../comms";
10
- import { BULK_COPY_CONFIG, SELECTION_ANALYZER_CONFIG } from "../protection/config";
11
- import {
12
- KeyCombinationManager,
1
+ import { Comms } from "../comms/comms.ts";
2
+ import { Module } from "./Module.ts";
3
+ import { ReadiumWindow, nearestInteractiveElement } from "../helpers/dom.ts";
4
+ import { BulkCopyProtector, BulkCopyProtectionOptions } from "../protection/BulkCopyProtector.ts";
5
+ import { SelectionAnalyzer, SelectionAnalyzerOptions } from "../protection/SelectionAnalyzer.ts";
6
+ import {
7
+ KeyboardPeripheral
8
+ } from "../protection/index.ts";
9
+ import { SuspiciousActivityType } from "../comms/index.ts";
10
+ import { BULK_COPY_CONFIG, SELECTION_ANALYZER_CONFIG } from "../protection/config.ts";
11
+ import {
12
+ KeyCombinationManager,
13
13
  ActivityEventDispatcher,
14
14
  KeyboardPeripheralEvent
15
- } from "../protection/KeyCombinationManager";
16
- import { SuspiciousScrollingEvent } from "./snapper/ScrollSnapper";
17
- import { SuspiciousSnappingEvent } from "./snapper/ColumnSnapper";
15
+ } from "../protection/KeyCombinationManager.ts";
16
+ import { SuspiciousScrollingEvent } from "./snapper/ScrollSnapper.ts";
17
+ import { SuspiciousSnappingEvent } from "./snapper/ColumnSnapper.ts";
18
18
 
19
19
  export interface FrameClickEvent {
20
20
  defaultPrevented: boolean;
@@ -108,7 +108,7 @@ export interface ContextMenuEvent extends Omit<BaseSuspiciousActivityEvent, "typ
108
108
  selectedText?: Omit<BasicTextSelection, "targetFrameSrc">;
109
109
  }
110
110
 
111
- export type SuspiciousActivityEvent =
111
+ export type SuspiciousActivityEvent =
112
112
  | DeveloperToolsEvent
113
113
  | SelectAllEvent
114
114
  | BulkCopyEvent
@@ -141,20 +141,20 @@ export class Peripherals extends Module {
141
141
  // State management
142
142
  private cleanupCallbacks: (() => void)[] = [];
143
143
  private pointerMoved = false;
144
-
144
+
145
145
  // Feature flags
146
146
  private isContextMenuEnabled = false;
147
147
  private isDragAndDropEnabled = false;
148
148
  private isSelectionMonitoringEnabled = false;
149
149
  private isBulkCopyProtectionEnabled = false;
150
-
150
+
151
151
  // Selection analysis
152
152
  private selectionAnalyzer: SelectionAnalyzer | null = null;
153
153
  private currentSelection: string | null = null;
154
-
154
+
155
155
  // Bulk copy protection
156
156
  private bulkCopyProtector: BulkCopyProtector | null = null;
157
-
157
+
158
158
  // Key combination manager
159
159
  private keyManager = new KeyCombinationManager();
160
160
 
@@ -173,6 +173,7 @@ export class Peripherals extends Module {
173
173
  private addDragAndDropPrevention(): void {
174
174
  if (this.isDragAndDropEnabled || !this.wnd) return;
175
175
  this.wnd.document.addEventListener("dragstart", this.onDragStart);
176
+ this.wnd.document.addEventListener("dragover", this.onDragOver);
176
177
  this.wnd.document.addEventListener("drop", this.onDrop);
177
178
  this.isDragAndDropEnabled = true;
178
179
  }
@@ -180,6 +181,7 @@ export class Peripherals extends Module {
180
181
  private removeDragAndDropPrevention(): void {
181
182
  if (!this.isDragAndDropEnabled || !this.wnd) return;
182
183
  this.wnd.document.removeEventListener("dragstart", this.onDragStart);
184
+ this.wnd.document.removeEventListener("dragover", this.onDragOver);
183
185
  this.wnd.document.removeEventListener("drop", this.onDrop);
184
186
  this.isDragAndDropEnabled = false;
185
187
  }
@@ -189,15 +191,15 @@ export class Peripherals extends Module {
189
191
  private enableKeyboardPeripherals(shortcuts: KeyboardPeripheral[] = []): void {
190
192
  // Clear any existing state
191
193
  this.disableKeyboardPeripherals();
192
-
194
+
193
195
  // Create activity event dispatcher
194
196
  const dispatcher: ActivityEventDispatcher = (activityEvent) => {
195
197
  this.comms?.send("keyboard_peripherals", activityEvent);
196
198
  };
197
-
199
+
198
200
  // Create unified handler using centralized KeyCombinationManager
199
201
  this.keyDownHandler = this.keyManager.createUnifiedHandler(this.wnd.location.href, shortcuts, dispatcher, this.wnd);
200
-
202
+
201
203
  // Add the event listener
202
204
  if (this.wnd) {
203
205
  this.wnd.document.addEventListener("keydown", this.keyDownHandler, {
@@ -205,7 +207,7 @@ export class Peripherals extends Module {
205
207
  });
206
208
  }
207
209
  }
208
-
210
+
209
211
  private disableKeyboardPeripherals(): void {
210
212
  if (this.wnd && this.keyDownHandler) {
211
213
  this.wnd.document.removeEventListener("keydown", this.keyDownHandler, {
@@ -217,11 +219,11 @@ export class Peripherals extends Module {
217
219
 
218
220
  private addBulkCopyProtection(options: Partial<BulkCopyProtectionOptions> = {}): void {
219
221
  if (this.isBulkCopyProtectionEnabled || !this.wnd) return;
220
-
222
+
221
223
  const defaultOptions = BULK_COPY_CONFIG;
222
-
224
+
223
225
  const finalOptions = options ? { ...defaultOptions, ...options } : defaultOptions;
224
-
226
+
225
227
  this.bulkCopyProtector = new BulkCopyProtector(this.wnd, finalOptions);
226
228
  this.wnd.document.addEventListener("copy", this.preventBulkCopy, true);
227
229
  this.wnd.document.addEventListener("cut", this.preventBulkCopy, true);
@@ -230,7 +232,7 @@ export class Peripherals extends Module {
230
232
 
231
233
  private removeBulkCopyProtection(): void {
232
234
  if (!this.isBulkCopyProtectionEnabled || !this.wnd) return;
233
-
235
+
234
236
  this.wnd.document.removeEventListener("copy", this.preventBulkCopy, true);
235
237
  this.wnd.document.removeEventListener("cut", this.preventBulkCopy, true);
236
238
  this.bulkCopyProtector?.destroy();
@@ -242,15 +244,15 @@ export class Peripherals extends Module {
242
244
  if (!this.isBulkCopyProtectionEnabled || !this.bulkCopyProtector) {
243
245
  return true;
244
246
  }
245
-
247
+
246
248
  if (!this.bulkCopyProtector.shouldAllowCopy(event)) {
247
249
  event.preventDefault();
248
-
250
+
249
251
  const selection = this.wnd.getSelection();
250
252
  const selectedText = selection?.toString() || '';
251
253
  const domRectList = selectedText ? selection?.getRangeAt(0)?.getClientRects() : null;
252
254
  const rect = domRectList?.[0];
253
-
255
+
254
256
  const activityEvent: BulkCopyEvent = {
255
257
  type: "bulk_copy",
256
258
  timestamp: Date.now(),
@@ -276,18 +278,18 @@ export class Peripherals extends Module {
276
278
  if (!this.isSelectionMonitoringEnabled || !this.wnd || !this.selectionAnalyzer) {
277
279
  return;
278
280
  }
279
-
281
+
280
282
  const selection = this.wnd.getSelection();
281
283
  if (selection) {
282
284
  this.currentSelection = selection.toString();
283
285
  const isSuspicious = this.selectionAnalyzer.analyze(selection);
284
-
286
+
285
287
  if (isSuspicious && this.currentSelection) {
286
288
  const selection = this.wnd.getSelection();
287
289
  const selectedText = selection?.toString() || '';
288
290
  const domRectList = (selectedText && selection?.rangeCount) ? selection.getRangeAt(0)?.getClientRects() : null;
289
291
  const rect = domRectList?.[0];
290
-
292
+
291
293
  const activityEvent: SuspiciousSelectionEvent = {
292
294
  type: "suspicious_selection",
293
295
  timestamp: Date.now(),
@@ -311,25 +313,32 @@ export class Peripherals extends Module {
311
313
 
312
314
  private addSelectionMonitoring(options?: SelectionAnalyzerOptions): void {
313
315
  if (this.isSelectionMonitoringEnabled || !this.wnd) return;
314
-
316
+
315
317
  // Use provided options or fall back to default config
316
318
  const analyzerOptions = options || SELECTION_ANALYZER_CONFIG;
317
319
  this.selectionAnalyzer = new SelectionAnalyzer(analyzerOptions);
318
320
  this.wnd.document.addEventListener("selectionchange", this.handleSelection);
319
321
  this.isSelectionMonitoringEnabled = true;
320
322
  }
321
-
323
+
322
324
  private removeSelectionMonitoring(): void {
323
325
  if (!this.isSelectionMonitoringEnabled || !this.wnd) {
324
326
  return;
325
327
  }
326
-
328
+
327
329
  this.wnd.document.removeEventListener("selectionchange", this.handleSelection);
328
330
  this.selectionAnalyzer?.clear();
329
331
  this.selectionAnalyzer = null;
330
332
  this.isSelectionMonitoringEnabled = false;
331
333
  }
332
334
 
335
+ private onDragOver = (event: DragEvent) => {
336
+ if (this.isDragAndDropEnabled) {
337
+ event.preventDefault();
338
+ event.stopPropagation();
339
+ }
340
+ };
341
+
333
342
  private onDragStart = (event: DragEvent) => {
334
343
  if (this.isDragAndDropEnabled) {
335
344
  // Drag and drop protection is enabled - prevent it
@@ -374,7 +383,7 @@ export class Peripherals extends Module {
374
383
  const selectedText = selection?.toString() || '';
375
384
  const domRectList = (selectedText && selection?.rangeCount) ? selection.getRangeAt(0)?.getClientRects() : null;
376
385
  const rect = domRectList?.[0];
377
-
386
+
378
387
  const activityEvent: ContextMenuEvent = {
379
388
  timestamp: Date.now(),
380
389
  clientX: event.clientX,
@@ -484,20 +493,20 @@ export class Peripherals extends Module {
484
493
  // Single handler for all content protection features
485
494
  this.comms?.register("peripherals_protection", Peripherals.moduleName, (data: unknown, ack) => {
486
495
  const config = data as ContentProtectionConfig;
487
-
496
+
488
497
  // Apply config only on first call, then ignore subsequent calls (immutable)
489
498
  if (!this.configApplied) {
490
499
  this.configApplied = true;
491
-
500
+
492
501
  // Selection monitoring with optional configuration
493
502
  if (config.monitorSelection) {
494
- const options = typeof config.monitorSelection === "boolean"
495
- ? undefined
503
+ const options = typeof config.monitorSelection === "boolean"
504
+ ? undefined
496
505
  : config.monitorSelection;
497
506
  this.addSelectionMonitoring(options);
498
507
  this.comms?.log("Selection monitoring enabled");
499
508
  }
500
-
509
+
501
510
  // Copy
502
511
  if (typeof config.protectCopy === "object") {
503
512
  // Limited copying with custom thresholds
@@ -508,40 +517,40 @@ export class Peripherals extends Module {
508
517
  this.comms?.log("Copy protection enabled (limited)");
509
518
  } else if (config.protectCopy === true) {
510
519
  // Block all copying
511
- this.addBulkCopyProtection({
512
- enabled: true,
513
- maxSelectionPercent: 0,
514
- minThreshold: 0,
515
- absoluteMaxChars: 0
520
+ this.addBulkCopyProtection({
521
+ enabled: true,
522
+ maxSelectionPercent: 0,
523
+ minThreshold: 0,
524
+ absoluteMaxChars: 0
516
525
  });
517
526
  this.comms?.log("Copy protection enabled");
518
527
  }
519
-
528
+
520
529
  // Context menu
521
530
  if (config.disableContextMenu) {
522
531
  this.addContextMenuPrevention();
523
532
  this.comms?.log("Context menu protection enabled");
524
533
  }
525
-
534
+
526
535
  // Drag and drop
527
536
  if (config.disableDragAndDrop) {
528
537
  this.addDragAndDropPrevention();
529
538
  this.comms?.log("Drag and drop protection enabled");
530
539
  }
531
540
  }
532
-
541
+
533
542
  ack(true);
534
543
  });
535
544
 
536
545
  // Separate handler for keyboard peripherals
537
546
  this.comms?.register("keyboard_peripherals", Peripherals.moduleName, (data: unknown, ack) => {
538
547
  const keyboardPeripherals = data as KeyboardPeripheral[];
539
-
548
+
540
549
  if (keyboardPeripherals && keyboardPeripherals.length > 0) {
541
550
  this.enableKeyboardPeripherals(keyboardPeripherals);
542
551
  this.comms?.log(`Keyboard peripherals enabled: ${keyboardPeripherals.map(p => p.type).join(", ")}`);
543
552
  }
544
-
553
+
545
554
  ack(true);
546
555
  });
547
556
  }
@@ -549,10 +558,10 @@ export class Peripherals extends Module {
549
558
  mount(wnd: ReadiumWindow, comms: Comms): boolean {
550
559
  this.wnd = wnd;
551
560
  this.comms = comms;
552
-
561
+
553
562
  // Register protection handlers
554
563
  this.registerProtectionHandlers();
555
-
564
+
556
565
  // Core event listeners (always active)
557
566
  wnd.document.addEventListener("pointerdown", this.onPointerDown);
558
567
  wnd.document.addEventListener("pointerup", this.onPointerUp);
@@ -570,24 +579,24 @@ export class Peripherals extends Module {
570
579
  this.removeContextMenuPrevention();
571
580
  this.removeDragAndDropPrevention();
572
581
  this.disableKeyboardPeripherals();
573
-
582
+
574
583
  // Clean up event listeners
575
584
  this.cleanupCallbacks.forEach(cleanup => cleanup());
576
585
  this.cleanupCallbacks = [];
577
-
586
+
578
587
  // Remove core event listeners
579
588
  wnd.document.removeEventListener("pointerdown", this.onPointerDown);
580
589
  wnd.document.removeEventListener("pointerup", this.onPointerUp);
581
590
  wnd.document.removeEventListener("pointermove", this.onPointerMove);
582
591
  wnd.document.removeEventListener("click", this.onClicker);
583
-
592
+
584
593
  // Unregister all handlers
585
594
  comms.unregisterAll(Peripherals.moduleName);
586
-
595
+
587
596
  // Reset config applied flag for fresh instances
588
597
  this.configApplied = false;
589
-
598
+
590
599
  comms.log("Peripherals Unmounted");
591
600
  return true;
592
601
  }
593
- }
602
+ }
@@ -1,4 +1,4 @@
1
- export * from './Decorator';
2
- export * from './Module';
3
- export * from './ModuleLibrary';
4
- export * from './Peripherals';
1
+ export * from './Decorator.ts';
2
+ export * from './Module.ts';
3
+ export * from './ModuleLibrary.ts';
4
+ export * from './Peripherals.ts';
@@ -1,8 +1,8 @@
1
- import { Comms } from "../../comms/comms";
2
- import { Setup } from "./Setup";
3
- import { removeProperty, setProperty } from "../../helpers/css";
4
- import { ModuleName } from "../ModuleLibrary";
5
- import { ReadiumWindow, deselect } from "../../helpers/dom";
1
+ import { Comms } from "../../comms/comms.ts";
2
+ import { Setup } from "./Setup.ts";
3
+ import { removeProperty, setProperty } from "../../helpers/css.ts";
4
+ import { ModuleName } from "../ModuleLibrary.ts";
5
+ import { ReadiumWindow, deselect } from "../../helpers/dom.ts";
6
6
 
7
7
  const FIXED_STYLE_ID = "readium-fixed-style";
8
8
 
@@ -72,4 +72,4 @@ export class FixedSetup extends Setup {
72
72
  comms.log("FixedSetup Unmounted");
73
73
  return super.unmount(wnd, comms);
74
74
  }
75
- }
75
+ }
@@ -1,7 +1,7 @@
1
- import { Comms } from "../../comms/comms";
2
- import { Setup } from "./Setup";
3
- import { getProperties, removeProperty, setProperty, updateProperties } from "../../helpers/css";
4
- import { ReadiumWindow } from "../../helpers/dom";
1
+ import { Comms } from "../../comms/comms.ts";
2
+ import { Setup } from "./Setup.ts";
3
+ import { getProperties, removeProperty, setProperty, updateProperties } from "../../helpers/css.ts";
4
+ import { ReadiumWindow } from "../../helpers/dom.ts";
5
5
 
6
6
  const VIEWPORT_META_TAG_ID = "readium-viewport";
7
7
 
@@ -40,7 +40,7 @@ export class ReflowableSetup extends Setup {
40
40
  ack(true);
41
41
  });
42
42
  comms.register("update_properties", ReflowableSetup.moduleName, (data, ack) => {
43
- // In order to keep the viewport width that is added in the setup itself,
43
+ // In order to keep the viewport width that is added in the setup itself,
44
44
  // and don’t have EpubNavigator concerned with this, we need to add it there
45
45
  (data as { [key: string]: string })["--RS__viewportWidth"] = `${ wnd.innerWidth }px`;
46
46
  updateProperties(wnd, data as { [key: string]: string });
@@ -73,4 +73,4 @@ export class ReflowableSetup extends Setup {
73
73
  comms.log("ReflowableSetup Unmounted");
74
74
  return super.unmount(wnd, comms);
75
75
  }
76
- }
76
+ }
@@ -1,7 +1,7 @@
1
- import { Comms } from "../../comms/comms";
2
- import { ReadiumWindow, EPUBReadingSystem } from "../../helpers/dom";
3
- import { Module } from "../Module";
4
- import { ModuleName } from "../ModuleLibrary";
1
+ import { Comms } from "../../comms/comms.ts";
2
+ import { ReadiumWindow, EPUBReadingSystem } from "../../helpers/dom.ts";
3
+ import { Module } from "../Module.ts";
4
+ import { ModuleName } from "../ModuleLibrary.ts";
5
5
 
6
6
  export abstract class Setup extends Module {
7
7
  static readonly moduleName: ModuleName = "setup";
@@ -157,4 +157,4 @@ export abstract class Setup extends Module {
157
157
  comms.log("Setup Unmounted");
158
158
  return true;
159
159
  }
160
- }
160
+ }
@@ -1,7 +1,7 @@
1
- import { Comms } from "../../comms/comms";
2
- import { ReadiumWindow } from "../../helpers/dom";
3
- import { Module } from "../Module";
4
- import { getProperties, removeProperty, setProperty, updateProperties } from "../../helpers/css";
1
+ import { Comms } from "../../comms/comms.ts";
2
+ import { ReadiumWindow } from "../../helpers/dom.ts";
3
+ import { Module } from "../Module.ts";
4
+ import { getProperties, removeProperty, setProperty, updateProperties } from "../../helpers/css.ts";
5
5
 
6
6
  export class WebPubSetup extends Module {
7
7
  static readonly moduleName = "webpub_setup";
@@ -61,4 +61,4 @@ export class WebPubSetup extends Module {
61
61
  comms.log("WebPubSetup Unmounted");
62
62
  return true;
63
63
  }
64
- }
64
+ }