@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,4 +1,4 @@
1
- import { ReadiumWindow } from "../helpers/dom";
1
+ import { ReadiumWindow } from "../helpers/dom.ts";
2
2
 
3
3
  interface CopyAttempt {
4
4
  timestamp: number;
@@ -33,7 +33,7 @@ export class BulkCopyProtector {
33
33
  this.copyHistory = this.copyHistory.filter(
34
34
  attempt => now - attempt.timestamp < historyWindow
35
35
  );
36
-
36
+
37
37
  // Trim to max history size
38
38
  if (this.copyHistory.length > this.options.historySize) {
39
39
  this.copyHistory = this.copyHistory.slice(-this.options.historySize);
@@ -42,17 +42,17 @@ export class BulkCopyProtector {
42
42
 
43
43
  private isSuspiciousPattern(now: number): boolean {
44
44
  if (this.copyHistory.length < 3) return false;
45
-
45
+
46
46
  // Check for rapid successive copy attempts
47
47
  const recentAttempts = this.copyHistory.filter(
48
48
  attempt => now - attempt.timestamp < 2000 // Last 2 seconds
49
49
  );
50
-
50
+
51
51
  if (recentAttempts.length >= 3) {
52
52
  // If multiple rapid copy attempts, it's suspicious
53
53
  return true;
54
54
  }
55
-
55
+
56
56
  // Check for increasing selection sizes (bulk copy pattern)
57
57
  const increasingSelections = this.copyHistory
58
58
  .slice()
@@ -61,7 +61,7 @@ export class BulkCopyProtector {
61
61
  if (i === 0) return true;
62
62
  return attempt.length > arr[i - 1].length * 1.5; // Each selection is significantly larger
63
63
  });
64
-
64
+
65
65
  return increasingSelections;
66
66
  }
67
67
 
@@ -70,7 +70,7 @@ export class BulkCopyProtector {
70
70
 
71
71
  const selection = this.window.getSelection();
72
72
  if (!selection) return true;
73
-
73
+
74
74
  const selectedText = selection.toString();
75
75
  const selectedLength = selectedText.length;
76
76
  const docLength = this.window.document.body.innerText.length;
@@ -90,12 +90,12 @@ export class BulkCopyProtector {
90
90
  }
91
91
 
92
92
  const timeSinceLastSelection = now - this.lastSelectionTime;
93
-
93
+
94
94
  // Check for rapid successive selections
95
- const isRapidSelection =
96
- timeSinceLastSelection < 100 &&
95
+ const isRapidSelection =
96
+ timeSinceLastSelection < 100 &&
97
97
  selectedLength > this.lastSelectionLength * 1.5;
98
-
98
+
99
99
  const maxAllowedSelection = Math.min(
100
100
  docLength * this.options.maxSelectionPercent,
101
101
  this.options.absoluteMaxChars
@@ -103,9 +103,9 @@ export class BulkCopyProtector {
103
103
 
104
104
  // Check if this matches a suspicious pattern
105
105
  const isSuspicious = this.isSuspiciousPattern(now);
106
-
107
- const shouldBlock = selectedLength > maxAllowedSelection ||
108
- isRapidSelection ||
106
+
107
+ const shouldBlock = selectedLength > maxAllowedSelection ||
108
+ isRapidSelection ||
109
109
  isSuspicious;
110
110
 
111
111
  // Record this attempt in history
@@ -119,7 +119,7 @@ export class BulkCopyProtector {
119
119
  event?.preventDefault();
120
120
  return false;
121
121
  }
122
-
122
+
123
123
  this.lastSelectionLength = selectedLength;
124
124
  this.lastSelectionTime = now;
125
125
  return true;
@@ -1,6 +1,6 @@
1
- import { KeyCombo, KeyboardPeripheral } from "./KeyboardCombinations";
2
- import { BaseKeyboardPeripheralEvent, KeyboardEventData, BasicTextSelection } from "../modules/Peripherals";
3
- import { ReadiumWindow } from "../helpers/dom";
1
+ import { KeyCombo, KeyboardPeripheral } from "./KeyboardCombinations.ts";
2
+ import { BaseKeyboardPeripheralEvent, KeyboardEventData, BasicTextSelection } from "../modules/Peripherals.ts";
3
+ import { ReadiumWindow } from "../helpers/dom.ts";
4
4
 
5
5
  export type KeyHandler = (event: KeyboardEvent) => void;
6
6
  export type ActivityEventDispatcher = (event: KeyboardPeripheralEvent) => void;
@@ -24,7 +24,7 @@ export class KeyCombinationManager {
24
24
  const shiftMatch = combo.shift === undefined || event.shiftKey === combo.shift;
25
25
  const altMatch = combo.alt === undefined || event.altKey === combo.alt;
26
26
  const metaMatch = combo.meta === undefined || event.metaKey === combo.meta;
27
-
27
+
28
28
  if (keyMatch && ctrlMatch && shiftMatch && altMatch && metaMatch) {
29
29
  return true;
30
30
  }
@@ -49,7 +49,7 @@ export class KeyCombinationManager {
49
49
  * Creates a standardized activity event for keyboard shortcuts
50
50
  */
51
51
  private createActivityEvent(
52
- event: KeyboardEvent,
52
+ event: KeyboardEvent,
53
53
  type: string,
54
54
  targetFrameSrc: string,
55
55
  wnd?: ReadiumWindow,
@@ -61,7 +61,7 @@ export class KeyCombinationManager {
61
61
  const selectedTextStr = selection?.toString() || '';
62
62
  const domRectList = (selectedTextStr && selection?.rangeCount) ? selection.getRangeAt(0)?.getClientRects() : null;
63
63
  const rect = domRectList?.[0];
64
-
64
+
65
65
  if (rect && selectedTextStr) {
66
66
  selectedText = {
67
67
  text: selectedTextStr,
@@ -124,7 +124,7 @@ export class KeyCombinationManager {
124
124
  wnd?: ReadiumWindow,
125
125
  ): (event: KeyboardEvent) => void {
126
126
  const handlers = this.createKeyboardHandlers(targetFrameSrc, shortcuts, dispatcher, wnd);
127
-
127
+
128
128
  return (event: KeyboardEvent) => {
129
129
  for (const handlerConfig of handlers) {
130
130
  if (this.match(event, [handlerConfig])) {
@@ -136,4 +136,4 @@ export class KeyCombinationManager {
136
136
  }
137
137
  };
138
138
  }
139
- }
139
+ }
@@ -1,4 +1,4 @@
1
- import { DEFAULT_PATTERN_ANALYZER_CONFIG } from "./config";
1
+ import { DEFAULT_PATTERN_ANALYZER_CONFIG } from "./config.ts";
2
2
 
3
3
  type Direction = "left" | "right" | "up" | "down";
4
4
 
@@ -10,7 +10,7 @@ export interface PatternAnalyzerOptions {
10
10
  maxConsistentScrolls?: number; // Maximum number of consistent scrolls before flagging
11
11
  }
12
12
 
13
- // TODO: Improve for scroll protection,
13
+ // TODO: Improve for scroll protection,
14
14
  // currently disabled because of false positives
15
15
  export class PatternAnalyzer {
16
16
  private options: PatternAnalyzerOptions;
@@ -20,9 +20,9 @@ export class PatternAnalyzer {
20
20
  velocity: number;
21
21
  distance: number;
22
22
  }> = [];
23
-
23
+
24
24
  private consistentScrollCount = 0;
25
-
25
+
26
26
  constructor(
27
27
  options: Partial<PatternAnalyzerOptions> = {}
28
28
  ) {
@@ -32,18 +32,18 @@ export class PatternAnalyzer {
32
32
 
33
33
  analyze(direction: Direction, distance: number, timeDelta: number): boolean {
34
34
  if (timeDelta <= 0) return false;
35
-
35
+
36
36
  const velocity = Math.abs(distance) / timeDelta;
37
37
  const now = Date.now();
38
-
38
+
39
39
  // Add new event
40
- this.history.push({
41
- timestamp: now,
42
- direction,
40
+ this.history.push({
41
+ timestamp: now,
42
+ direction,
43
43
  velocity,
44
44
  distance: Math.abs(distance)
45
45
  });
46
-
46
+
47
47
  // Clean up old events (keep last 2 seconds of data or historySize, whichever is smaller)
48
48
  this.history = this.history
49
49
  .filter(h => now - h.timestamp < 2000)
@@ -61,19 +61,19 @@ export class PatternAnalyzer {
61
61
  // 2. Check for consistent scrolling patterns
62
62
  const velocities = this.history.map(h => h.velocity);
63
63
  const distances = this.history.map(h => h.distance);
64
-
64
+
65
65
  // Calculate mean and variance of velocities and distances
66
66
  const meanVelocity = velocities.reduce((a, b) => a + b, 0) / velocities.length;
67
67
  const meanDistance = distances.reduce((a, b) => a + b, 0) / distances.length;
68
-
68
+
69
69
  const velocityVariance = velocities.reduce((a, b) => a + Math.pow(b - meanVelocity, 2), 0) / velocities.length;
70
70
  const distanceVariance = distances.reduce((a, b) => a + Math.pow(b - meanDistance, 2), 0) / distances.length;
71
71
 
72
72
  // Check for suspiciously consistent scrolling (low variance in speed and distance)
73
- if (velocityVariance < this.options.minVariance &&
73
+ if (velocityVariance < this.options.minVariance &&
74
74
  distanceVariance < (meanDistance * 0.1)) { // Allow 10% variance in distance
75
75
  this.consistentScrollCount++;
76
-
76
+
77
77
  // Only trigger if we've seen consistent scrolling for a while
78
78
  if (this.consistentScrollCount >= (this.options.maxConsistentScrolls || 10)) {
79
79
  this.resetAfterDetection();
@@ -87,14 +87,14 @@ export class PatternAnalyzer {
87
87
  // 3. Check for rapid direction changes (unnatural back-and-forth scrolling)
88
88
  let directionChanges = 0;
89
89
  let lastDirection = this.history[0].direction;
90
-
90
+
91
91
  for (let i = 1; i < this.history.length; i++) {
92
92
  if (this.history[i].direction !== lastDirection) {
93
93
  directionChanges++;
94
94
  lastDirection = this.history[i].direction;
95
95
  }
96
96
  }
97
-
97
+
98
98
  const directionChangeRatio = directionChanges / this.history.length;
99
99
  if (directionChangeRatio > (this.options.minDirectionChanges || 0.3)) {
100
100
  this.resetAfterDetection();
@@ -109,9 +109,9 @@ export class PatternAnalyzer {
109
109
  this.history = this.history.slice(-3);
110
110
  this.consistentScrollCount = 0;
111
111
  }
112
-
112
+
113
113
  clear(): void {
114
114
  this.history = [];
115
115
  this.consistentScrollCount = 0;
116
116
  }
117
- }
117
+ }
@@ -1,7 +1,7 @@
1
- import { Comms } from "../comms";
2
- import { ReadiumWindow } from "../helpers/dom";
3
- import { Module } from "../modules/Module";
4
- import { ModuleName } from "../modules/ModuleLibrary";
1
+ import { Comms } from "../comms/index.ts";
2
+ import { ReadiumWindow } from "../helpers/dom.ts";
3
+ import { Module } from "../modules/Module.ts";
4
+ import { ModuleName } from "../modules/ModuleLibrary.ts";
5
5
 
6
6
  export interface PrintProtectionConfig {
7
7
  disable?: boolean;
@@ -10,7 +10,7 @@ export interface PrintProtectionConfig {
10
10
 
11
11
  export class PrintProtector extends Module {
12
12
  static readonly moduleName: ModuleName = "print_protection";
13
-
13
+
14
14
  private comms!: Comms;
15
15
  private wnd!: ReadiumWindow;
16
16
  private styleElement: HTMLStyleElement | null = null;
@@ -46,16 +46,16 @@ export class PrintProtector extends Module {
46
46
  wnd.addEventListener("beforeprint", this.beforePrintHandler);
47
47
  }
48
48
 
49
- private registerPrintHandlers() {
49
+ private registerPrintHandlers() {
50
50
  this.comms?.register("print_protection", PrintProtector.moduleName, (data: unknown) => {
51
51
  const config = data as PrintProtectionConfig;
52
-
52
+
53
53
  if (!this.configApplied) {
54
54
  this.configApplied = true;
55
55
  this.setupPrintProtection(this.wnd, config);
56
56
  this.comms?.log("Print protection configuration applied");
57
57
  }
58
-
58
+
59
59
  return true;
60
60
  });
61
61
  }
@@ -72,16 +72,16 @@ export class PrintProtector extends Module {
72
72
  wnd.removeEventListener("beforeprint", this.beforePrintHandler);
73
73
  this.beforePrintHandler = null;
74
74
  }
75
-
75
+
76
76
  if (this.styleElement?.parentNode) {
77
77
  this.styleElement.parentNode.removeChild(this.styleElement);
78
78
  this.styleElement = null;
79
79
  }
80
-
80
+
81
81
  // Unregister all print protection handlers
82
82
  this.comms?.unregisterAll(PrintProtector.moduleName);
83
-
83
+
84
84
  this.configApplied = false;
85
85
  return true;
86
86
  }
87
- }
87
+ }
@@ -10,7 +10,7 @@ export interface SelectionAnalyzerOptions {
10
10
  historySize: number;
11
11
  }
12
12
 
13
- import { SELECTION_ANALYZER_CONFIG } from './config';
13
+ import { SELECTION_ANALYZER_CONFIG } from './config.ts';
14
14
 
15
15
  export class SelectionAnalyzer {
16
16
  private events: SelectionEvent[] = [];
@@ -1,6 +1,6 @@
1
- import { BulkCopyProtectionOptions } from "./BulkCopyProtector";
2
- import { PatternAnalyzerOptions } from "./PatternAnalyzer";
3
- import { SelectionAnalyzerOptions } from "./SelectionAnalyzer";
1
+ import { BulkCopyProtectionOptions } from "./BulkCopyProtector.ts";
2
+ import { PatternAnalyzerOptions } from "./PatternAnalyzer.ts";
3
+ import { SelectionAnalyzerOptions } from "./SelectionAnalyzer.ts";
4
4
 
5
5
  export const DEFAULT_PATTERN_ANALYZER_CONFIG: PatternAnalyzerOptions = {
6
6
  maxVelocity: 200, // Reasonable default for human-like scrolling (pixels/ms)
@@ -30,4 +30,4 @@ export const BULK_COPY_CONFIG: BulkCopyProtectionOptions = {
30
30
  minThreshold: 100,
31
31
  absoluteMaxChars: 5000,
32
32
  historySize: 20
33
- }
33
+ }
@@ -1,6 +1,6 @@
1
- export * from "./BulkCopyProtector";
2
- export * from "./KeyCombinationManager";
3
- export * from "./KeyboardCombinations";
4
- export * from "./PatternAnalyzer";
5
- export * from "./SelectionAnalyzer";
6
- export * from "./PrintProtector";
1
+ export * from "./BulkCopyProtector.ts";
2
+ export * from "./KeyCombinationManager.ts";
3
+ export * from "./KeyboardCombinations.ts";
4
+ export * from "./PatternAnalyzer.ts";
5
+ export * from "./SelectionAnalyzer.ts";
6
+ export * from "./PrintProtector.ts";
@@ -4,7 +4,7 @@ import type {
4
4
  Selector,
5
5
  TextPositionSelector,
6
6
  TextQuoteSelector,
7
- } from './api-types';
7
+ } from './api-types.ts';
8
8
  import {
9
9
  MediaTimeAnchor,
10
10
  RangeAnchor,
@@ -12,7 +12,7 @@ import type {
12
12
  RangeSelector,
13
13
  TextPositionSelector,
14
14
  TextQuoteSelector,
15
- } from './api-types';
15
+ } from './api-types.ts';
16
16
  import { matchQuote } from './match-quote';
17
17
  import { TextRange, TextPosition } from './text-range';
18
18
  import { nodeFromXPath, xpathFromNode } from './xpath';
@@ -1,5 +1,5 @@
1
- import { ReadiumWindow } from "./helpers/dom";
2
- import { ModuleName } from "./modules";
1
+ import { ReadiumWindow } from "./helpers/dom.ts";
2
+ import { ModuleName } from "./modules/index.ts";
3
3
  /**
4
4
  * The Module loader. Handles initialization of the HTML injectables
5
5
  * in the target Window, which could be an IFrame, or the current window).
@@ -1,5 +1,5 @@
1
- import { ReadiumWindow } from "../helpers/dom";
2
- import { CommsEventKey, CommsCommandKey } from "./keys";
1
+ import { ReadiumWindow } from "../helpers/dom.ts";
2
+ import { CommsEventKey, CommsCommandKey } from "./keys.ts";
3
3
  export declare const COMMS_VERSION = 1;
4
4
  export interface CommsMessage {
5
5
  _readium: number;
@@ -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,5 +1,4 @@
1
- import { ReadiumWindow } from "./dom";
2
- export declare const isTypedOMSupported: () => boolean;
1
+ import { ReadiumWindow } from "./dom.ts";
3
2
  export declare function getProperties(wnd: ReadiumWindow): {
4
3
  [key: string]: string;
5
4
  };
@@ -1,4 +1,4 @@
1
- import { ReadiumWindow } from "./dom";
1
+ import { ReadiumWindow } from "./dom.ts";
2
2
  export declare function isRTL(wnd: ReadiumWindow): boolean;
3
3
  export declare function getColumnCountPerScreen(wnd: ReadiumWindow): number;
4
4
  /**
@@ -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,8 +1,8 @@
1
1
  import { Locator } from "@readium/shared";
2
- import { Comms } from "../comms/comms";
3
- import { Module } from "./Module";
4
- import { ModuleName } from "./ModuleLibrary";
5
- import { ReadiumWindow } from "../helpers/dom";
2
+ import { Comms } from "../comms/comms.ts";
3
+ import { Module } from "./Module.ts";
4
+ import { ModuleName } from "./ModuleLibrary.ts";
5
+ import { ReadiumWindow } from "../helpers/dom.ts";
6
6
  export declare enum Width {
7
7
  Wrap = "wrap",// Smallest width fitting the CSS border box.
8
8
  Viewport = "viewport",// Fills the whole viewport.
@@ -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
  export declare abstract class Module {
5
5
  static readonly moduleName: ModuleName;
6
6
  abstract mount(wnd: ReadiumWindow, comms: Comms): boolean;
@@ -1,5 +1,5 @@
1
- import { ModuleDerived } from "./Module";
2
- export type ModuleName = "setup" | "snapper" | "column_snapper" | "scroll_snapper" | "webpub_snapper" | "fixed_setup" | "decorator" | "reflowable_setup" | "peripherals" | "webpub_setup" | "print_protection";
1
+ import { ModuleDerived } from "./Module.ts";
2
+ export type ModuleName = "setup" | "snapper" | "column_snapper" | "scroll_snapper" | "cjk_vertical_snapper" | "webpub_snapper" | "fixed_setup" | "decorator" | "reflowable_setup" | "peripherals" | "webpub_setup" | "print_protection";
3
3
  export declare const FXLModules: ModuleName[];
4
4
  export declare const ReflowableModules: ModuleName[];
5
5
  export declare const WebPubModules: ModuleName[];
@@ -1,12 +1,12 @@
1
- import { Comms } from "../comms/comms";
2
- import { Module } from "./Module";
3
- import { ReadiumWindow } from "../helpers/dom";
4
- import { BulkCopyProtectionOptions } from "../protection/BulkCopyProtector";
5
- import { SelectionAnalyzerOptions } from "../protection/SelectionAnalyzer";
6
- import { SuspiciousActivityType } from "../comms";
7
- import { KeyboardPeripheralEvent } from "../protection/KeyCombinationManager";
8
- import { SuspiciousScrollingEvent } from "./snapper/ScrollSnapper";
9
- import { SuspiciousSnappingEvent } from "./snapper/ColumnSnapper";
1
+ import { Comms } from "../comms/comms.ts";
2
+ import { Module } from "./Module.ts";
3
+ import { ReadiumWindow } from "../helpers/dom.ts";
4
+ import { BulkCopyProtectionOptions } from "../protection/BulkCopyProtector.ts";
5
+ import { SelectionAnalyzerOptions } from "../protection/SelectionAnalyzer.ts";
6
+ import { SuspiciousActivityType } from "../comms/index.ts";
7
+ import { KeyboardPeripheralEvent } from "../protection/KeyCombinationManager.ts";
8
+ import { SuspiciousScrollingEvent } from "./snapper/ScrollSnapper.ts";
9
+ import { SuspiciousSnappingEvent } from "./snapper/ColumnSnapper.ts";
10
10
  export interface FrameClickEvent {
11
11
  defaultPrevented: boolean;
12
12
  doNotDisturb: boolean;
@@ -122,6 +122,7 @@ export declare class Peripherals extends Module {
122
122
  private handleSelection;
123
123
  private addSelectionMonitoring;
124
124
  private removeSelectionMonitoring;
125
+ private onDragOver;
125
126
  private onDragStart;
126
127
  private onDrop;
127
128
  private onContext;
@@ -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,7 +1,7 @@
1
- import { Comms } from "../../comms/comms";
2
- import { Setup } from "./Setup";
3
- import { ModuleName } from "../ModuleLibrary";
4
- import { ReadiumWindow } from "../../helpers/dom";
1
+ import { Comms } from "../../comms/comms.ts";
2
+ import { Setup } from "./Setup.ts";
3
+ import { ModuleName } from "../ModuleLibrary.ts";
4
+ import { ReadiumWindow } from "../../helpers/dom.ts";
5
5
  export declare class FixedSetup extends Setup {
6
6
  static readonly moduleName: ModuleName;
7
7
  mount(wnd: ReadiumWindow, comms: Comms): boolean;
@@ -1,6 +1,6 @@
1
- import { Comms } from "../../comms/comms";
2
- import { Setup } from "./Setup";
3
- import { ReadiumWindow } from "../../helpers/dom";
1
+ import { Comms } from "../../comms/comms.ts";
2
+ import { Setup } from "./Setup.ts";
3
+ import { ReadiumWindow } from "../../helpers/dom.ts";
4
4
  export declare class ReflowableSetup extends Setup {
5
5
  static readonly moduleName = "reflowable_setup";
6
6
  onViewportWidthChanged(event: Event): void;
@@ -1,7 +1,7 @@
1
- import { Comms } from "../../comms/comms";
2
- import { ReadiumWindow } from "../../helpers/dom";
3
- import { Module } from "../Module";
4
- import { ModuleName } from "../ModuleLibrary";
1
+ import { Comms } from "../../comms/comms.ts";
2
+ import { ReadiumWindow } from "../../helpers/dom.ts";
3
+ import { Module } from "../Module.ts";
4
+ import { ModuleName } from "../ModuleLibrary.ts";
5
5
  export declare abstract class Setup extends Module {
6
6
  static readonly moduleName: ModuleName;
7
7
  private comms;
@@ -1,6 +1,6 @@
1
- import { Comms } from "../../comms/comms";
2
- import { ReadiumWindow } from "../../helpers/dom";
3
- import { Module } from "../Module";
1
+ import { Comms } from "../../comms/comms.ts";
2
+ import { ReadiumWindow } from "../../helpers/dom.ts";
3
+ import { Module } from "../Module.ts";
4
4
  export declare class WebPubSetup extends Module {
5
5
  static readonly moduleName = "webpub_setup";
6
6
  private comms;
@@ -0,0 +1,57 @@
1
+ import { Comms } from "../../comms/comms.ts";
2
+ import { ReadiumWindow } from "../../helpers/dom.ts";
3
+ import { ModuleName } from "../ModuleLibrary.ts";
4
+ import { Snapper } from "./Snapper.ts";
5
+ import { BaseSuspiciousActivityEvent } from "../Peripherals.ts";
6
+ export interface SuspiciousCJKScrollingEvent extends BaseSuspiciousActivityEvent {
7
+ type: "suspicious_scrolling";
8
+ scrollDelta: number;
9
+ scrollDirection: "left" | "right";
10
+ targetElement: {
11
+ tagName: string;
12
+ } | null;
13
+ }
14
+ /**
15
+ * Snapper for CJK vertical writing (writing-mode: vertical-rl).
16
+ *
17
+ * In vertical-rl, content overflows on the X axis, flowing from right (start)
18
+ * to left (end). This snapper is the horizontal counterpart of ScrollSnapper:
19
+ * it tracks scrollLeft / scrollWidth / innerWidth and reports progress
20
+ * accordingly.
21
+ *
22
+ * Progress convention:
23
+ * scrollLeft = 0 (right edge, document start) → progress 0
24
+ * scrollLeft = ±(scrollWidth − clientWidth) → progress 1 (document end, left edge)
25
+ *
26
+ * All modern browsers use negative scrollLeft for vertical-rl (range: [−scrollable, 0]).
27
+ * Read it with Math.abs() to get a non-negative offset from document start.
28
+ * Write absolute positions as negative values (go_progression, go_end).
29
+ * Write relative adjustments as viewport-coordinate deltas (go_id, go_text) — this
30
+ * is sign-agnostic and works regardless of browser convention.
31
+ *
32
+ * go_next / go_prev always return false so that the navigator advances to the
33
+ * next or previous spine item — this snapper intentionally provides free
34
+ * horizontal scroll without intra-resource page fragmentation.
35
+ */
36
+ export declare class CJKVerticalSnapper extends Snapper {
37
+ static readonly moduleName: ModuleName;
38
+ private wnd;
39
+ private comms;
40
+ private resizeObserver;
41
+ private patternAnalyzer;
42
+ private lastScrollTime;
43
+ private isScrollProtectionEnabled;
44
+ private initialScrollHandled;
45
+ private isScrolling;
46
+ private lastScrollLeft;
47
+ private isResizing;
48
+ private resizeDebounce;
49
+ private doc;
50
+ /** Total horizontally scrollable distance (magnitude). */
51
+ private scrollable;
52
+ private reportProgress;
53
+ private handleScroll;
54
+ private enableScrollProtection;
55
+ mount(wnd: ReadiumWindow, comms: Comms): boolean;
56
+ unmount(wnd: ReadiumWindow, comms: Comms): boolean;
57
+ }
@@ -1,8 +1,8 @@
1
- import { Comms } from "../../comms";
2
- import { Snapper } from "./Snapper";
3
- import { ModuleName } from "../ModuleLibrary";
4
- import { ReadiumWindow } from "../../helpers/dom";
5
- import { BaseSuspiciousActivityEvent } from "../Peripherals";
1
+ import { Comms } from "../../comms/index.ts";
2
+ import { Snapper } from "./Snapper.ts";
3
+ import { ModuleName } from "../ModuleLibrary.ts";
4
+ import { ReadiumWindow } from "../../helpers/dom.ts";
5
+ import { BaseSuspiciousActivityEvent } from "../Peripherals.ts";
6
6
  export interface SuspiciousSnappingEvent extends BaseSuspiciousActivityEvent {
7
7
  type: "suspicious_snapping";
8
8
  event: null;
@@ -22,6 +22,17 @@ export declare class ColumnSnapper extends Snapper {
22
22
  private doc;
23
23
  private scrollOffset;
24
24
  snapOffset(offset: number): number;
25
+ /**
26
+ * Snap a non-negative normalized offset (distance from document start) to
27
+ * the nearest page boundary. Works identically regardless of reading direction.
28
+ */
29
+ private snapNormOffset;
30
+ /**
31
+ * Normalized scroll position: distance from document start, always in
32
+ * [0, scrollWidth - innerWidth] regardless of reading direction.
33
+ * scrollLeft may be negative depending on the browser — Math.abs() normalizes it.
34
+ */
35
+ private normScroll;
25
36
  reportProgress(): void;
26
37
  private shakeTimeout;
27
38
  shake(): void;
@@ -1,8 +1,8 @@
1
- import { Comms } from "../../comms";
2
- import { ReadiumWindow } from "../../helpers/dom";
3
- import { ModuleName } from "../ModuleLibrary";
4
- import { Snapper } from "./Snapper";
5
- import { BaseSuspiciousActivityEvent } from "../Peripherals";
1
+ import { Comms } from "../../comms/index.ts";
2
+ import { ReadiumWindow } from "../../helpers/dom.ts";
3
+ import { ModuleName } from "../ModuleLibrary.ts";
4
+ import { Snapper } from "./Snapper.ts";
5
+ import { BaseSuspiciousActivityEvent } from "../Peripherals.ts";
6
6
  export interface SuspiciousScrollingEvent extends BaseSuspiciousActivityEvent {
7
7
  type: "suspicious_scrolling";
8
8
  scrollDelta: number;