@readium/navigator-html-injectables 2.3.1-alpha.2 → 2.3.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 (56) hide show
  1. package/dist/index.js +344 -349
  2. package/dist/index.umd.cjs +12 -12
  3. package/package.json +8 -8
  4. package/src/comms/comms.ts +5 -5
  5. package/src/comms/index.ts +3 -3
  6. package/src/helpers/css.ts +2 -4
  7. package/src/helpers/document.ts +9 -9
  8. package/src/helpers/locator.ts +2 -2
  9. package/src/index.ts +4 -4
  10. package/src/modules/Decorator.ts +18 -18
  11. package/src/modules/Module.ts +4 -4
  12. package/src/modules/ModuleLibrary.ts +11 -11
  13. package/src/modules/Peripherals.ts +70 -61
  14. package/src/modules/index.ts +4 -4
  15. package/src/modules/setup/FixedSetup.ts +6 -6
  16. package/src/modules/setup/ReflowableSetup.ts +6 -6
  17. package/src/modules/setup/Setup.ts +5 -5
  18. package/src/modules/setup/WebPubSetup.ts +5 -5
  19. package/src/modules/snapper/ColumnSnapper.ts +20 -39
  20. package/src/modules/snapper/ScrollSnapper.ts +18 -18
  21. package/src/modules/snapper/Snapper.ts +5 -5
  22. package/src/modules/snapper/WebPubSnapper.ts +15 -15
  23. package/src/protection/BulkCopyProtector.ts +15 -15
  24. package/src/protection/KeyCombinationManager.ts +8 -8
  25. package/src/protection/PatternAnalyzer.ts +18 -18
  26. package/src/protection/PrintProtector.ts +12 -12
  27. package/src/protection/SelectionAnalyzer.ts +1 -1
  28. package/src/protection/config.ts +4 -4
  29. package/src/protection/index.ts +6 -6
  30. package/src/vendor/hypothesis/anchoring/html.ts +1 -1
  31. package/src/vendor/hypothesis/anchoring/types.ts +1 -1
  32. package/types/src/comms/comms.d.ts +2 -2
  33. package/types/src/comms/index.d.ts +3 -3
  34. package/types/src/helpers/css.d.ts +1 -2
  35. package/types/src/helpers/document.d.ts +1 -1
  36. package/types/src/index.d.ts +4 -4
  37. package/types/src/modules/Decorator.d.ts +4 -4
  38. package/types/src/modules/Module.d.ts +3 -3
  39. package/types/src/modules/ModuleLibrary.d.ts +1 -1
  40. package/types/src/modules/Peripherals.d.ts +10 -9
  41. package/types/src/modules/index.d.ts +4 -4
  42. package/types/src/modules/setup/FixedSetup.d.ts +4 -4
  43. package/types/src/modules/setup/ReflowableSetup.d.ts +3 -3
  44. package/types/src/modules/setup/Setup.d.ts +4 -4
  45. package/types/src/modules/setup/WebPubSetup.d.ts +3 -3
  46. package/types/src/modules/snapper/ColumnSnapper.d.ts +5 -5
  47. package/types/src/modules/snapper/ScrollSnapper.d.ts +5 -5
  48. package/types/src/modules/snapper/Snapper.d.ts +4 -4
  49. package/types/src/modules/snapper/WebPubSnapper.d.ts +5 -5
  50. package/types/src/protection/BulkCopyProtector.d.ts +1 -1
  51. package/types/src/protection/KeyCombinationManager.d.ts +3 -3
  52. package/types/src/protection/PrintProtector.d.ts +4 -4
  53. package/types/src/protection/config.d.ts +3 -3
  54. package/types/src/protection/index.d.ts +6 -6
  55. package/types/src/vendor/hypothesis/anchoring/html.d.ts +1 -1
  56. package/types/src/vendor/hypothesis/anchoring/types.d.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@readium/navigator-html-injectables",
3
- "version": "2.3.1-alpha.2",
3
+ "version": "2.3.1",
4
4
  "type": "module",
5
5
  "description": "An embeddable solution for connecting frames of HTML publications with a Readium Navigator",
6
6
  "author": "readium",
@@ -26,6 +26,10 @@
26
26
  "reader",
27
27
  "viewer"
28
28
  ],
29
+ "scripts": {
30
+ "clean": "rimraf types dist",
31
+ "build": "pnpm clean && tsc && vite build"
32
+ },
29
33
  "main": "./dist/index.umd.cjs",
30
34
  "module": "./dist/index.js",
31
35
  "types": "./types/src/index.d.ts",
@@ -45,15 +49,11 @@
45
49
  "node": ">=18"
46
50
  },
47
51
  "devDependencies": {
52
+ "@readium/shared": "workspace:*",
48
53
  "css-selector-generator": "^3.8.0",
49
54
  "rimraf": "^6.1.2",
50
55
  "tslib": "^2.8.1",
51
56
  "typescript": "^5.9.3",
52
- "vite": "^7.3.1",
53
- "@readium/shared": "2.2.0-alpha.1"
54
- },
55
- "scripts": {
56
- "clean": "rimraf types dist",
57
- "build": "pnpm clean && tsc && vite build"
57
+ "vite": "^7.3.1"
58
58
  }
59
- }
59
+ }
@@ -1,6 +1,6 @@
1
- import { ReadiumWindow } from "../helpers/dom";
2
- import { CommsEventKey, CommsCommandKey } from "./keys";
3
- import { mid } from "./mid";
1
+ import { ReadiumWindow } from "../helpers/dom.ts";
2
+ import { CommsEventKey, CommsCommandKey } from "./keys.ts";
3
+ import { mid } from "./mid.ts";
4
4
 
5
5
  export const COMMS_VERSION = 1;
6
6
 
@@ -21,7 +21,7 @@ export type CommsAck = (ok: boolean) => void;
21
21
  export type CommsCallback = (data: unknown, ack: CommsAck) => void; // TODO: maybe more than void?
22
22
 
23
23
  /**
24
- * Comms is basically a wrapper around window.postMessage that
24
+ * Comms is basically a wrapper around window.postMessage that
25
25
  * adds structure to the messages and lets modules register callbacks.
26
26
  */
27
27
  export class Comms {
@@ -165,4 +165,4 @@ export class Comms {
165
165
  this.destination.postMessage(msg, this.origin, transfer);
166
166
  }
167
167
  }
168
- }
168
+ }
@@ -1,3 +1,3 @@
1
- export * from './comms';
2
- export * from './keys';
3
- export * from './mid';
1
+ export * from './comms.ts';
2
+ export * from './keys.ts';
3
+ export * from './mid.ts';
@@ -1,6 +1,4 @@
1
- import { ReadiumWindow } from "./dom";
2
-
3
- export const isTypedOMSupported = () => typeof window.CSSTransformValue !== 'undefined';
1
+ import { ReadiumWindow } from "./dom.ts";
4
2
 
5
3
  export function getProperties(wnd: ReadiumWindow) {
6
4
  const cssProperties: { [key: string]: string } = {};
@@ -52,4 +50,4 @@ export function setProperty(wnd: ReadiumWindow, key: string, value: string) {
52
50
  // Easy way to remove a CSS property
53
51
  export function removeProperty(wnd: ReadiumWindow, key: string) {
54
52
  wnd.document.documentElement.style.removeProperty(key);
55
- }
53
+ }
@@ -1,4 +1,4 @@
1
- import { ReadiumWindow } from "./dom";
1
+ import { ReadiumWindow } from "./dom.ts";
2
2
 
3
3
  export function isRTL(wnd: ReadiumWindow): boolean {
4
4
  return wnd.document.body.dir.toLowerCase() === "rtl";
@@ -12,7 +12,7 @@ export function getColumnCountPerScreen(wnd: ReadiumWindow): number {
12
12
  );
13
13
  }
14
14
 
15
- /**
15
+ /**
16
16
  * Returns the "content height" of an element, which is its clientHeight
17
17
  * minus any vertical padding.
18
18
  *
@@ -26,9 +26,9 @@ export function getContentHeight(el: Element): number {
26
26
  }
27
27
 
28
28
  /**
29
- * We have to make sure that the total number of columns is a multiple
30
- * of the number of columns per screen.
31
- * Otherwise it causes snapping and page turning issues.
29
+ * We have to make sure that the total number of columns is a multiple
30
+ * of the number of columns per screen.
31
+ * Otherwise it causes snapping and page turning issues.
32
32
  * To fix this, we insert and remove blank virtual columns at the end of the resource.
33
33
  */
34
34
  export function appendVirtualColumnIfNeeded(wnd: ReadiumWindow): boolean {
@@ -56,7 +56,7 @@ export function appendVirtualColumnIfNeeded(wnd: ReadiumWindow): boolean {
56
56
  const lonelyColCount = totalColCount % colCountPerScreen;
57
57
 
58
58
  const needed = colCountPerScreen === 1 || lonelyColCount === 0
59
- ? 0
59
+ ? 0
60
60
  : colCountPerScreen - lonelyColCount;
61
61
 
62
62
  if (needed > 0) {
@@ -84,14 +84,14 @@ export function appendVirtualColumnIfNeeded(wnd: ReadiumWindow): boolean {
84
84
  * This forces a recalculation in WebKit browsers.
85
85
  * It is needed in scroll mode to ensure that the content is scrollable.
86
86
  * Webkit seems to find itself in some kind of limbo if we do not do that.
87
- * It has everything correct but the scroll listener is non-functional,
87
+ * It has everything correct but the scroll listener is non-functional,
88
88
  * unless you force a recalc or reflow.
89
89
  * It is not needed in paginated mode.
90
90
  */
91
91
  export function forceWebkitRecalc(wnd: ReadiumWindow) {
92
- // Borrowed from APB themselves…
92
+ // Borrowed from APB themselves…
93
93
  const styleElement = wnd.document.createElement("style");
94
94
  styleElement.appendChild(wnd.document.createTextNode("*{}"));
95
95
  wnd.document.body.appendChild(styleElement);
96
96
  wnd.document.body.removeChild(styleElement);
97
- }
97
+ }
@@ -1,5 +1,5 @@
1
1
  import { Locator } from "@readium/shared";
2
- import { TextQuoteAnchor } from "../vendor/hypothesis/anchoring/types";
2
+ import { TextQuoteAnchor } from "../vendor/hypothesis/anchoring/types.ts";
3
3
 
4
4
  function isReplacedLikeElement(element: Element): boolean {
5
5
  const tagName = element.tagName.toUpperCase();
@@ -66,4 +66,4 @@ export function rangeFromLocator(doc: Document, locator: Locator) {
66
66
  console.error(e);
67
67
  }
68
68
  return null;
69
- }
69
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from './comms';
2
- export * from './modules';
3
- export * from './Loader';
4
- export * from './protection';
1
+ export * from './comms/index.ts';
2
+ export * from './modules/index.ts';
3
+ export * from './Loader.ts';
4
+ export * from './protection/index.ts';
@@ -1,12 +1,12 @@
1
1
  import { Locator } from "@readium/shared";
2
- import { Comms } from "../comms/comms";
3
- import { Module } from "./Module";
4
- import { rangeFromLocator } from "../helpers/locator";
5
- import { ModuleName } from "./ModuleLibrary";
6
- import { Rect, getClientRectsNoOverlap } from "../helpers/rect";
7
- import { getProperty } from "../helpers/css";
8
- import { ReadiumWindow } from "../helpers/dom";
9
- import { isDarkColor, getContrastingTextColor } from "../helpers/color";
2
+ import { Comms } from "../comms/comms.ts";
3
+ import { Module } from "./Module.ts";
4
+ import { rangeFromLocator } from "../helpers/locator.ts";
5
+ import { ModuleName } from "./ModuleLibrary.ts";
6
+ import { Rect, getClientRectsNoOverlap } from "../helpers/rect.ts";
7
+ import { getProperty } from "../helpers/css.ts";
8
+ import { ReadiumWindow } from "../helpers/dom.ts";
9
+ import { isDarkColor, getContrastingTextColor } from "../helpers/color.ts";
10
10
 
11
11
  const DEFAULT_HIGHLIGHT_COLOR = "#FFFF00"; // Yellow in HEX
12
12
 
@@ -184,7 +184,7 @@ class DecorationGroup {
184
184
  const [stylesheet, highlighter]: [HTMLStyleElement, any] = this.requireContainer(true) as [HTMLStyleElement, unknown];
185
185
  highlighter.add(item.range);
186
186
 
187
- const backgroundColor = getProperty(this.wnd, "--USER__backgroundColor") ||
187
+ const backgroundColor = getProperty(this.wnd, "--USER__backgroundColor") ||
188
188
  this.wnd.getComputedStyle(this.wnd.document.documentElement).getPropertyValue("background-color");
189
189
  const tint = item.decoration?.style?.tint ?? DEFAULT_HIGHLIGHT_COLOR;
190
190
 
@@ -198,7 +198,7 @@ class DecorationGroup {
198
198
 
199
199
  /**
200
200
  * Layouts a single DecorationItem.
201
- * @param item
201
+ * @param item
202
202
  */
203
203
  private layout(item: DecorationItem) {
204
204
  if (this.experimentalHighlights && !this.notTextFlag?.has(item.id)) {
@@ -264,7 +264,7 @@ class DecorationGroup {
264
264
 
265
265
  template.innerHTML = `
266
266
  <div
267
- data-readium="true"
267
+ data-readium="true"
268
268
  class="readium-highlight"
269
269
  style="${[
270
270
  `background-color: ${item.decoration?.style?.tint ?? DEFAULT_HIGHLIGHT_COLOR} !important`,
@@ -416,7 +416,7 @@ export class Decorator extends Module {
416
416
 
417
417
  private extractCustomProperty(style: string | null, propertyName: string): string | null {
418
418
  if (!style) return null;
419
-
419
+
420
420
  const match = style.match(new RegExp(`${propertyName}:\\s*([^;]+)`));
421
421
  return match ? match[1].trim() : null;
422
422
  }
@@ -478,24 +478,24 @@ export class Decorator extends Module {
478
478
  const element = mutation.target as Element;
479
479
  const oldStyle = mutation.oldValue;
480
480
  const newStyle = element.getAttribute("style");
481
-
481
+
482
482
  // Check if the relevant CSS custom properties actually changed
483
483
  const oldAppearance = this.extractCustomProperty(oldStyle, "--USER__appearance");
484
484
  const newAppearance = this.extractCustomProperty(newStyle, "--USER__appearance");
485
485
  const oldBgColor = this.extractCustomProperty(oldStyle, "--USER__backgroundColor");
486
486
  const newBgColor = this.extractCustomProperty(newStyle, "--USER__backgroundColor");
487
-
488
- return oldAppearance !== newAppearance ||
487
+
488
+ return oldAppearance !== newAppearance ||
489
489
  oldBgColor !== newBgColor;
490
490
  }
491
491
  return false;
492
492
  });
493
-
493
+
494
494
  if (shouldUpdate) {
495
495
  this.updateHighlightStyles();
496
496
  }
497
497
  });
498
-
498
+
499
499
  this.backgroundObserver.observe(wnd.document.documentElement, {
500
500
  attributes: true,
501
501
  attributeFilter: ["style"],
@@ -519,4 +519,4 @@ export class Decorator extends Module {
519
519
  comms.log("Decorator Unmounted");
520
520
  return true;
521
521
  }
522
- }
522
+ }
@@ -1,6 +1,6 @@
1
- import { Comms } from "../comms";
2
- import { ReadiumWindow } from "../helpers/dom";
3
- import { ModuleName } from "./ModuleLibrary";
1
+ import { Comms } from "../comms/index.ts";
2
+ import { ReadiumWindow } from "../helpers/dom.ts";
3
+ import { ModuleName } from "./ModuleLibrary.ts";
4
4
 
5
5
  export abstract class Module {
6
6
  static readonly moduleName: ModuleName; // snake_case name of the module, must be unique.
@@ -20,4 +20,4 @@ export abstract class Module {
20
20
  abstract unmount(wnd: ReadiumWindow, comms: Comms): boolean;
21
21
  }
22
22
 
23
- export type ModuleDerived = {new (): Module} & typeof Module;
23
+ export type ModuleDerived = {new (): Module} & typeof Module;
@@ -1,13 +1,13 @@
1
- import { ModuleDerived } from "./Module";
2
- import { ColumnSnapper } from "./snapper/ColumnSnapper";
3
- import { ScrollSnapper } from "./snapper/ScrollSnapper";
4
- import { WebPubSnapper } from "./snapper/WebPubSnapper";
5
- import { Peripherals } from "./Peripherals";
6
- import { ReflowableSetup } from "./setup/ReflowableSetup";
7
- import { FixedSetup } from "./setup/FixedSetup";
8
- import { Decorator } from "./Decorator";
9
- import { WebPubSetup } from "./setup/WebPubSetup";
10
- import { PrintProtector } from "../protection/PrintProtector";
1
+ import { ModuleDerived } from "./Module.ts";
2
+ import { ColumnSnapper } from "./snapper/ColumnSnapper.ts";
3
+ import { ScrollSnapper } from "./snapper/ScrollSnapper.ts";
4
+ import { WebPubSnapper } from "./snapper/WebPubSnapper.ts";
5
+ import { Peripherals } from "./Peripherals.ts";
6
+ import { ReflowableSetup } from "./setup/ReflowableSetup.ts";
7
+ import { FixedSetup } from "./setup/FixedSetup.ts";
8
+ import { Decorator } from "./Decorator.ts";
9
+ import { WebPubSetup } from "./setup/WebPubSetup.ts";
10
+ import { PrintProtector } from "../protection/PrintProtector.ts";
11
11
 
12
12
  // All the module names. TODO: Come up with a better way of collecting these in a way TS will recognize
13
13
  export type ModuleName =
@@ -61,4 +61,4 @@ export const ModuleLibrary = new Map<string, ModuleDerived>([
61
61
  ColumnSnapper,
62
62
  ScrollSnapper,
63
63
  PrintProtector
64
- ].map(m => [m.moduleName, m])); // Turn module list into K/V list for quick access by name
64
+ ].map(m => [m.moduleName, m])); // Turn module list into K/V list for quick access by name
@@ -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';