@readium/navigator-html-injectables 2.4.1 → 2.4.2-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.
- package/dist/index.js +401 -386
- package/dist/index.umd.cjs +11 -11
- package/package.json +1 -1
- package/src/helpers/dom.ts +30 -9
- package/src/index.ts +1 -0
- package/src/{protection → keyboard}/KeyCombinationManager.ts +17 -3
- package/src/{protection → keyboard}/KeyboardCombinations.ts +1 -0
- package/src/keyboard/index.ts +2 -0
- package/src/modules/Peripherals.ts +3 -8
- package/src/protection/index.ts +1 -3
- package/types/src/helpers/dom.d.ts +2 -0
- package/types/src/index.d.ts +1 -0
- package/types/src/{protection → keyboard}/KeyboardCombinations.d.ts +1 -0
- package/types/src/keyboard/index.d.ts +2 -0
- package/types/src/modules/Peripherals.d.ts +2 -1
- package/types/src/protection/index.d.ts +0 -2
- /package/types/src/{protection → keyboard}/KeyCombinationManager.d.ts +0 -0
package/package.json
CHANGED
package/src/helpers/dom.ts
CHANGED
|
@@ -30,6 +30,7 @@ export function deselect(wnd: ReadiumWindow) {
|
|
|
30
30
|
|
|
31
31
|
const interactiveTags = [
|
|
32
32
|
"a",
|
|
33
|
+
"area",
|
|
33
34
|
"audio",
|
|
34
35
|
"button",
|
|
35
36
|
"canvas",
|
|
@@ -43,17 +44,14 @@ const interactiveTags = [
|
|
|
43
44
|
"video",
|
|
44
45
|
];
|
|
45
46
|
|
|
47
|
+
const interactiveRoles = ["dialog", "radiogroup", "radio", "menu", "menuitem"];
|
|
48
|
+
|
|
46
49
|
// See https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling
|
|
47
50
|
export function nearestInteractiveElement(element: Element): Element | null {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
// Checks whether the element is editable by the user.
|
|
53
|
-
if (
|
|
54
|
-
element.hasAttribute("contenteditable") &&
|
|
55
|
-
element.getAttribute("contenteditable")?.toLowerCase() !== "false"
|
|
56
|
-
) {
|
|
51
|
+
// If the element or any ancestor is blocked, return null immediately
|
|
52
|
+
if (isElementBlocked(element)) return null;
|
|
53
|
+
|
|
54
|
+
if (isInteractiveElement(element)) {
|
|
57
55
|
return element;
|
|
58
56
|
}
|
|
59
57
|
|
|
@@ -65,6 +63,29 @@ export function nearestInteractiveElement(element: Element): Element | null {
|
|
|
65
63
|
return null;
|
|
66
64
|
}
|
|
67
65
|
|
|
66
|
+
export function isElementBlocked(element: Element | null): boolean {
|
|
67
|
+
if (!element) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return element.closest("[inert]") !== null || element.hasAttribute("disabled");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function isInteractiveElement(element: Element | null): boolean {
|
|
75
|
+
if (!element) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check for interactive roles
|
|
80
|
+
if (element.role && interactiveRoles.includes(element.role)) return true;
|
|
81
|
+
|
|
82
|
+
if ((element as HTMLElement).tabIndex >= 0) return true;
|
|
83
|
+
|
|
84
|
+
// Use existing interactive tags logic
|
|
85
|
+
return interactiveTags.includes(element.nodeName.toLowerCase()) ||
|
|
86
|
+
element.hasAttribute("contenteditable") && element.getAttribute("contenteditable")?.toLowerCase() !== "false";
|
|
87
|
+
}
|
|
88
|
+
|
|
68
89
|
/// Returns the `Locator` object to the first block element that is visible on
|
|
69
90
|
/// the screen.
|
|
70
91
|
export function findFirstVisibleLocator(wnd: ReadiumWindow, scrolling: boolean) {
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { KeyCombo, KeyboardPeripheral } from "./KeyboardCombinations.ts";
|
|
2
2
|
import { BaseKeyboardPeripheralEvent, KeyboardEventData, BasicTextSelection } from "../modules/Peripherals.ts";
|
|
3
|
-
import { ReadiumWindow } from "../helpers/dom.ts";
|
|
3
|
+
import { isInteractiveElement, nearestInteractiveElement, ReadiumWindow } from "../helpers/dom.ts";
|
|
4
4
|
|
|
5
5
|
export type KeyHandler = (event: KeyboardEvent) => void;
|
|
6
6
|
export type ActivityEventDispatcher = (event: KeyboardPeripheralEvent) => void;
|
|
@@ -56,6 +56,8 @@ export class KeyCombinationManager {
|
|
|
56
56
|
): KeyboardPeripheralEvent {
|
|
57
57
|
// Capture selected text if window is available
|
|
58
58
|
let selectedText: Omit<BasicTextSelection, "targetFrameSrc"> | undefined;
|
|
59
|
+
let interactiveElement: string | undefined;
|
|
60
|
+
|
|
59
61
|
if (wnd) {
|
|
60
62
|
const selection = wnd.getSelection();
|
|
61
63
|
const selectedTextStr = selection?.toString() || '';
|
|
@@ -71,6 +73,12 @@ export class KeyCombinationManager {
|
|
|
71
73
|
height: rect.height
|
|
72
74
|
};
|
|
73
75
|
}
|
|
76
|
+
|
|
77
|
+
// Capture interactive element information following the same pattern as onPointUp
|
|
78
|
+
const activeElement = wnd.document.activeElement;
|
|
79
|
+
if (activeElement && activeElement !== wnd.document.body) {
|
|
80
|
+
interactiveElement = nearestInteractiveElement(activeElement)?.outerHTML;
|
|
81
|
+
}
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
return {
|
|
@@ -84,7 +92,8 @@ export class KeyCombinationManager {
|
|
|
84
92
|
shiftKey: event.shiftKey,
|
|
85
93
|
metaKey: event.metaKey,
|
|
86
94
|
targetFrameSrc: targetFrameSrc,
|
|
87
|
-
selectedText
|
|
95
|
+
selectedText,
|
|
96
|
+
interactiveElement
|
|
88
97
|
};
|
|
89
98
|
}
|
|
90
99
|
|
|
@@ -128,10 +137,15 @@ export class KeyCombinationManager {
|
|
|
128
137
|
return (event: KeyboardEvent) => {
|
|
129
138
|
for (const handlerConfig of handlers) {
|
|
130
139
|
if (this.match(event, [handlerConfig])) {
|
|
140
|
+
const suppress = handlerConfig.suppressOnInteractiveElement;
|
|
141
|
+
if (suppress) {
|
|
142
|
+
const active = document.activeElement;
|
|
143
|
+
if (Array.isArray(suppress) ? suppress.some(sel => active?.matches(sel)) : isInteractiveElement(active)) return;
|
|
144
|
+
}
|
|
131
145
|
event.preventDefault();
|
|
132
146
|
event.stopPropagation();
|
|
133
147
|
handlerConfig.handler!(event);
|
|
134
|
-
return;
|
|
148
|
+
return;
|
|
135
149
|
}
|
|
136
150
|
}
|
|
137
151
|
};
|
|
@@ -3,18 +3,12 @@ import { Module } from "./Module.ts";
|
|
|
3
3
|
import { ReadiumWindow, nearestInteractiveElement } from "../helpers/dom.ts";
|
|
4
4
|
import { BulkCopyProtector, BulkCopyProtectionOptions } from "../protection/BulkCopyProtector.ts";
|
|
5
5
|
import { SelectionAnalyzer, SelectionAnalyzerOptions } from "../protection/SelectionAnalyzer.ts";
|
|
6
|
-
import {
|
|
7
|
-
KeyboardPeripheral
|
|
8
|
-
} from "../protection/index.ts";
|
|
9
6
|
import { SuspiciousActivityType } from "../comms/index.ts";
|
|
10
7
|
import { BULK_COPY_CONFIG, SELECTION_ANALYZER_CONFIG } from "../protection/config.ts";
|
|
11
|
-
import {
|
|
12
|
-
KeyCombinationManager,
|
|
13
|
-
ActivityEventDispatcher,
|
|
14
|
-
KeyboardPeripheralEvent
|
|
15
|
-
} from "../protection/KeyCombinationManager.ts";
|
|
16
8
|
import { SuspiciousScrollingEvent } from "./snapper/ScrollSnapper.ts";
|
|
17
9
|
import { SuspiciousSnappingEvent } from "./snapper/ColumnSnapper.ts";
|
|
10
|
+
import { ActivityEventDispatcher, KeyboardPeripheralEvent, KeyCombinationManager } from "../keyboard/KeyCombinationManager.ts";
|
|
11
|
+
import { KeyboardPeripheral } from "../keyboard/KeyboardCombinations.ts";
|
|
18
12
|
|
|
19
13
|
export interface FrameClickEvent {
|
|
20
14
|
defaultPrevented: boolean;
|
|
@@ -59,6 +53,7 @@ export interface BaseKeyboardPeripheralEvent {
|
|
|
59
53
|
timestamp: number;
|
|
60
54
|
targetFrameSrc: string;
|
|
61
55
|
selectedText?: Omit<BasicTextSelection, "targetFrameSrc">;
|
|
56
|
+
interactiveElement?: string;
|
|
62
57
|
}
|
|
63
58
|
|
|
64
59
|
export interface DeveloperToolsEvent extends BaseSuspiciousActivityEvent, KeyboardEventData {
|
package/src/protection/index.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export * from "./BulkCopyProtector.ts";
|
|
2
|
-
export * from "./KeyCombinationManager.ts";
|
|
3
|
-
export * from "./KeyboardCombinations.ts";
|
|
4
2
|
export * from "./PatternAnalyzer.ts";
|
|
5
3
|
export * from "./SelectionAnalyzer.ts";
|
|
6
|
-
export * from "./PrintProtector.ts";
|
|
4
|
+
export * from "./PrintProtector.ts";
|
|
@@ -20,5 +20,7 @@ export interface ReadiumWindow extends Window {
|
|
|
20
20
|
}
|
|
21
21
|
export declare function deselect(wnd: ReadiumWindow): void;
|
|
22
22
|
export declare function nearestInteractiveElement(element: Element): Element | null;
|
|
23
|
+
export declare function isElementBlocked(element: Element | null): boolean;
|
|
24
|
+
export declare function isInteractiveElement(element: Element | null): boolean;
|
|
23
25
|
export declare function findFirstVisibleLocator(wnd: ReadiumWindow, scrolling: boolean): Locator;
|
|
24
26
|
export {};
|
package/types/src/index.d.ts
CHANGED
|
@@ -4,9 +4,9 @@ import { ReadiumWindow } from "../helpers/dom.ts";
|
|
|
4
4
|
import { BulkCopyProtectionOptions } from "../protection/BulkCopyProtector.ts";
|
|
5
5
|
import { SelectionAnalyzerOptions } from "../protection/SelectionAnalyzer.ts";
|
|
6
6
|
import { SuspiciousActivityType } from "../comms/index.ts";
|
|
7
|
-
import { KeyboardPeripheralEvent } from "../protection/KeyCombinationManager.ts";
|
|
8
7
|
import { SuspiciousScrollingEvent } from "./snapper/ScrollSnapper.ts";
|
|
9
8
|
import { SuspiciousSnappingEvent } from "./snapper/ColumnSnapper.ts";
|
|
9
|
+
import { KeyboardPeripheralEvent } from "../keyboard/KeyCombinationManager.ts";
|
|
10
10
|
export interface FrameClickEvent {
|
|
11
11
|
defaultPrevented: boolean;
|
|
12
12
|
doNotDisturb: boolean;
|
|
@@ -44,6 +44,7 @@ export interface BaseKeyboardPeripheralEvent {
|
|
|
44
44
|
timestamp: number;
|
|
45
45
|
targetFrameSrc: string;
|
|
46
46
|
selectedText?: Omit<BasicTextSelection, "targetFrameSrc">;
|
|
47
|
+
interactiveElement?: string;
|
|
47
48
|
}
|
|
48
49
|
export interface DeveloperToolsEvent extends BaseSuspiciousActivityEvent, KeyboardEventData {
|
|
49
50
|
type: "developer_tools";
|
|
File without changes
|