@readium/navigator-html-injectables 2.3.1-alpha.1 → 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.
- package/dist/index.js +344 -349
- package/dist/index.umd.cjs +12 -12
- package/package.json +8 -8
- package/src/comms/comms.ts +5 -5
- package/src/comms/index.ts +3 -3
- package/src/helpers/css.ts +2 -4
- package/src/helpers/document.ts +9 -9
- package/src/helpers/locator.ts +2 -2
- package/src/index.ts +4 -4
- package/src/modules/Decorator.ts +18 -18
- package/src/modules/Module.ts +4 -4
- package/src/modules/ModuleLibrary.ts +11 -11
- package/src/modules/Peripherals.ts +70 -61
- package/src/modules/index.ts +4 -4
- package/src/modules/setup/FixedSetup.ts +6 -6
- package/src/modules/setup/ReflowableSetup.ts +6 -6
- package/src/modules/setup/Setup.ts +5 -5
- package/src/modules/setup/WebPubSetup.ts +5 -5
- package/src/modules/snapper/ColumnSnapper.ts +20 -39
- package/src/modules/snapper/ScrollSnapper.ts +18 -18
- package/src/modules/snapper/Snapper.ts +5 -5
- package/src/modules/snapper/WebPubSnapper.ts +15 -15
- package/src/protection/BulkCopyProtector.ts +15 -15
- package/src/protection/KeyCombinationManager.ts +8 -8
- package/src/protection/PatternAnalyzer.ts +18 -18
- package/src/protection/PrintProtector.ts +12 -12
- package/src/protection/SelectionAnalyzer.ts +1 -1
- package/src/protection/config.ts +4 -4
- package/src/protection/index.ts +6 -6
- package/src/vendor/hypothesis/anchoring/html.ts +1 -1
- package/src/vendor/hypothesis/anchoring/types.ts +1 -1
- package/types/src/comms/comms.d.ts +2 -2
- package/types/src/comms/index.d.ts +3 -3
- package/types/src/helpers/css.d.ts +1 -2
- package/types/src/helpers/document.d.ts +1 -1
- package/types/src/index.d.ts +4 -4
- package/types/src/modules/Decorator.d.ts +4 -4
- package/types/src/modules/Module.d.ts +3 -3
- package/types/src/modules/ModuleLibrary.d.ts +1 -1
- package/types/src/modules/Peripherals.d.ts +10 -9
- package/types/src/modules/index.d.ts +4 -4
- package/types/src/modules/setup/FixedSetup.d.ts +4 -4
- package/types/src/modules/setup/ReflowableSetup.d.ts +3 -3
- package/types/src/modules/setup/Setup.d.ts +4 -4
- package/types/src/modules/setup/WebPubSetup.d.ts +3 -3
- package/types/src/modules/snapper/ColumnSnapper.d.ts +5 -5
- package/types/src/modules/snapper/ScrollSnapper.d.ts +5 -5
- package/types/src/modules/snapper/Snapper.d.ts +4 -4
- package/types/src/modules/snapper/WebPubSnapper.d.ts +5 -5
- package/types/src/protection/BulkCopyProtector.d.ts +1 -1
- package/types/src/protection/KeyCombinationManager.d.ts +3 -3
- package/types/src/protection/PrintProtector.d.ts +4 -4
- package/types/src/protection/config.d.ts +3 -3
- package/types/src/protection/index.d.ts +6 -6
- package/types/src/vendor/hypothesis/anchoring/html.d.ts +1 -1
- 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
|
|
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
|
+
}
|
package/src/comms/comms.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/comms/index.ts
CHANGED
|
@@ -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';
|
package/src/helpers/css.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/helpers/document.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/helpers/locator.ts
CHANGED
|
@@ -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';
|
package/src/modules/Decorator.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/modules/Module.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/modules/index.ts
CHANGED
|
@@ -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';
|