@openreplay/tracker 3.5.12 → 3.5.14
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/cjs/app/guards.d.ts +18 -0
- package/cjs/app/guards.js +24 -0
- package/cjs/app/index.d.ts +5 -1
- package/cjs/app/index.js +55 -32
- package/cjs/app/nodes.d.ts +3 -3
- package/cjs/app/nodes.js +2 -2
- package/cjs/app/observer/observer.d.ts +1 -2
- package/cjs/app/observer/observer.js +73 -60
- package/cjs/app/observer/top_observer.js +3 -3
- package/cjs/app/sanitizer.d.ts +3 -1
- package/cjs/app/sanitizer.js +13 -2
- package/cjs/app/session.d.ts +2 -7
- package/cjs/app/session.js +24 -37
- package/cjs/index.js +2 -2
- package/cjs/modules/console.d.ts +1 -1
- package/cjs/modules/console.js +2 -1
- package/cjs/modules/cssrules.d.ts +1 -1
- package/cjs/modules/cssrules.js +2 -4
- package/cjs/modules/exception.d.ts +1 -1
- package/cjs/modules/img.d.ts +1 -1
- package/cjs/modules/img.js +14 -6
- package/cjs/modules/input.d.ts +2 -1
- package/cjs/modules/input.js +18 -20
- package/cjs/modules/longtasks.d.ts +1 -1
- package/cjs/modules/mouse.d.ts +1 -1
- package/cjs/modules/mouse.js +3 -2
- package/cjs/modules/performance.d.ts +1 -1
- package/cjs/modules/scroll.d.ts +1 -1
- package/cjs/modules/scroll.js +3 -2
- package/cjs/modules/timing.d.ts +1 -1
- package/cjs/modules/timing.js +2 -1
- package/cjs/modules/viewport.d.ts +1 -1
- package/lib/app/guards.d.ts +18 -0
- package/lib/app/guards.js +16 -0
- package/lib/app/index.d.ts +5 -1
- package/lib/app/index.js +56 -33
- package/lib/app/nodes.d.ts +3 -3
- package/lib/app/nodes.js +2 -2
- package/lib/app/observer/observer.d.ts +1 -2
- package/lib/app/observer/observer.js +70 -57
- package/lib/app/observer/top_observer.js +3 -3
- package/lib/app/sanitizer.d.ts +3 -1
- package/lib/app/sanitizer.js +13 -2
- package/lib/app/session.d.ts +2 -7
- package/lib/app/session.js +24 -37
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.js +2 -2
- package/lib/modules/console.d.ts +1 -1
- package/lib/modules/console.js +2 -1
- package/lib/modules/cssrules.d.ts +1 -1
- package/lib/modules/cssrules.js +2 -4
- package/lib/modules/exception.d.ts +1 -1
- package/lib/modules/img.d.ts +1 -1
- package/lib/modules/img.js +14 -6
- package/lib/modules/input.d.ts +2 -1
- package/lib/modules/input.js +18 -20
- package/lib/modules/longtasks.d.ts +1 -1
- package/lib/modules/mouse.d.ts +1 -1
- package/lib/modules/mouse.js +3 -2
- package/lib/modules/performance.d.ts +1 -1
- package/lib/modules/scroll.d.ts +1 -1
- package/lib/modules/scroll.js +3 -2
- package/lib/modules/timing.d.ts +1 -1
- package/lib/modules/timing.js +2 -1
- package/lib/modules/viewport.d.ts +1 -1
- package/package.json +7 -7
- package/cjs/app/context.d.ts +0 -18
- package/cjs/app/context.js +0 -73
- package/lib/app/context.d.ts +0 -18
- package/lib/app/context.js +0 -68
package/lib/modules/cssrules.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CSSInsertRuleURLBased, CSSDeleteRule, TechnicalInfo } from "../common/messages.js";
|
|
2
|
+
import { hasTag } from "../app/guards.js";
|
|
2
3
|
export default function (app) {
|
|
3
4
|
if (app === null) {
|
|
4
5
|
return;
|
|
@@ -30,10 +31,7 @@ export default function (app) {
|
|
|
30
31
|
return deleteRule.call(this, index);
|
|
31
32
|
};
|
|
32
33
|
app.nodes.attachNodeCallback((node) => {
|
|
33
|
-
if (!(node
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
if (!(node.sheet instanceof CSSStyleSheet)) {
|
|
34
|
+
if (!hasTag(node, "STYLE") || !node.sheet) {
|
|
37
35
|
return;
|
|
38
36
|
}
|
|
39
37
|
if (node.textContent !== null && node.textContent.trim().length > 0) {
|
package/lib/modules/img.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import App from "../app/index.js";
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
package/lib/modules/img.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { timestamp, isURL } from "../utils.js";
|
|
2
2
|
import { ResourceTiming, SetNodeAttributeURLBased, SetNodeAttribute } from "../common/messages.js";
|
|
3
|
+
import { hasTag } from "../app/guards.js";
|
|
3
4
|
const PLACEHOLDER_SRC = "https://static.openreplay.com/tracker/placeholder.jpeg";
|
|
4
5
|
export default function (app) {
|
|
5
6
|
function sendPlaceholder(id, node) {
|
|
@@ -17,7 +18,7 @@ export default function (app) {
|
|
|
17
18
|
if (id === undefined) {
|
|
18
19
|
return;
|
|
19
20
|
}
|
|
20
|
-
const { src, complete, naturalWidth, naturalHeight } = this;
|
|
21
|
+
const { src, complete, naturalWidth, naturalHeight, srcset } = this;
|
|
21
22
|
if (!complete) {
|
|
22
23
|
return;
|
|
23
24
|
}
|
|
@@ -31,28 +32,35 @@ export default function (app) {
|
|
|
31
32
|
}
|
|
32
33
|
else {
|
|
33
34
|
app.send(new SetNodeAttributeURLBased(id, 'src', src, app.getBaseHref()));
|
|
35
|
+
srcset && app.send(new SetNodeAttribute(id, 'srcset', srcset));
|
|
34
36
|
}
|
|
35
37
|
});
|
|
36
38
|
const observer = new MutationObserver((mutations) => {
|
|
37
39
|
for (const mutation of mutations) {
|
|
38
|
-
if (mutation.type === "attributes"
|
|
40
|
+
if (mutation.type === "attributes") {
|
|
39
41
|
const target = mutation.target;
|
|
40
42
|
const id = app.nodes.getID(target);
|
|
41
43
|
if (id === undefined) {
|
|
42
44
|
return;
|
|
43
45
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
if (mutation.attributeName === "src") {
|
|
47
|
+
const src = target.src;
|
|
48
|
+
app.send(new SetNodeAttributeURLBased(id, 'src', src, app.getBaseHref()));
|
|
49
|
+
}
|
|
50
|
+
if (mutation.attributeName === "srcset") {
|
|
51
|
+
const srcset = target.srcset;
|
|
52
|
+
app.send(new SetNodeAttribute(id, 'srcset', srcset));
|
|
53
|
+
}
|
|
46
54
|
}
|
|
47
55
|
}
|
|
48
56
|
});
|
|
49
57
|
app.nodes.attachNodeCallback((node) => {
|
|
50
|
-
if (!(node
|
|
58
|
+
if (!hasTag(node, "IMG")) {
|
|
51
59
|
return;
|
|
52
60
|
}
|
|
53
61
|
app.nodes.attachElementListener('error', node, sendImgSrc);
|
|
54
62
|
app.nodes.attachElementListener('load', node, sendImgSrc);
|
|
55
63
|
sendImgSrc.call(node);
|
|
56
|
-
observer.observe(node, { attributes: true });
|
|
64
|
+
observer.observe(node, { attributes: true, attributeFilter: ["src", "srcset"] });
|
|
57
65
|
});
|
|
58
66
|
}
|
package/lib/modules/input.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import App from "../app/index.js";
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
declare type TextEditableElement = HTMLInputElement | HTMLTextAreaElement;
|
|
3
3
|
export declare function getInputLabel(node: TextEditableElement): string;
|
|
4
4
|
export declare const enum InputMode {
|
|
@@ -10,6 +10,7 @@ export interface Options {
|
|
|
10
10
|
obscureInputNumbers: boolean;
|
|
11
11
|
obscureInputEmails: boolean;
|
|
12
12
|
defaultInputMode: InputMode;
|
|
13
|
+
obscureInputDates: boolean;
|
|
13
14
|
}
|
|
14
15
|
export default function (app: App, opts: Partial<Options>): void;
|
|
15
16
|
export {};
|
package/lib/modules/input.js
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import { normSpaces, IN_BROWSER, getLabelAttribute, hasOpenreplayAttribute, } from "../utils.js";
|
|
2
|
+
import { hasTag } from "../app/guards.js";
|
|
2
3
|
import { SetInputTarget, SetInputValue, SetInputChecked } from "../common/messages.js";
|
|
4
|
+
const INPUT_TYPES = ['text', 'password', 'email', 'search', 'number', 'range', 'date'];
|
|
3
5
|
function isTextEditable(node) {
|
|
4
|
-
if (node
|
|
6
|
+
if (hasTag(node, "TEXTAREA")) {
|
|
5
7
|
return true;
|
|
6
8
|
}
|
|
7
|
-
if (!(node
|
|
9
|
+
if (!hasTag(node, "INPUT")) {
|
|
8
10
|
return false;
|
|
9
11
|
}
|
|
10
|
-
|
|
11
|
-
return (type === 'text' ||
|
|
12
|
-
type === 'password' ||
|
|
13
|
-
type === 'email' ||
|
|
14
|
-
type === 'search' ||
|
|
15
|
-
type === 'number' ||
|
|
16
|
-
type === 'range');
|
|
12
|
+
return INPUT_TYPES.includes(node.type);
|
|
17
13
|
}
|
|
18
14
|
function isCheckable(node) {
|
|
19
|
-
if (!(node
|
|
15
|
+
if (!hasTag(node, "INPUT")) {
|
|
20
16
|
return false;
|
|
21
17
|
}
|
|
22
18
|
const type = node.type;
|
|
@@ -26,7 +22,7 @@ const labelElementFor = IN_BROWSER && 'labels' in HTMLInputElement.prototype
|
|
|
26
22
|
? (node) => {
|
|
27
23
|
let p = node;
|
|
28
24
|
while ((p = p.parentNode) !== null) {
|
|
29
|
-
if (p
|
|
25
|
+
if (hasTag(p, "LABEL")) {
|
|
30
26
|
return p;
|
|
31
27
|
}
|
|
32
28
|
}
|
|
@@ -38,7 +34,7 @@ const labelElementFor = IN_BROWSER && 'labels' in HTMLInputElement.prototype
|
|
|
38
34
|
: (node) => {
|
|
39
35
|
let p = node;
|
|
40
36
|
while ((p = p.parentNode) !== null) {
|
|
41
|
-
if (p
|
|
37
|
+
if (hasTag(p, "LABEL")) {
|
|
42
38
|
return p;
|
|
43
39
|
}
|
|
44
40
|
}
|
|
@@ -67,7 +63,8 @@ export default function (app, opts) {
|
|
|
67
63
|
const options = Object.assign({
|
|
68
64
|
obscureInputNumbers: true,
|
|
69
65
|
obscureInputEmails: true,
|
|
70
|
-
defaultInputMode: 0 /* Plain */,
|
|
66
|
+
defaultInputMode: 0 /* InputMode.Plain */,
|
|
67
|
+
obscureInputDates: false,
|
|
71
68
|
}, opts);
|
|
72
69
|
function sendInputTarget(id, node) {
|
|
73
70
|
const label = getInputLabel(node);
|
|
@@ -79,22 +76,23 @@ export default function (app, opts) {
|
|
|
79
76
|
let value = node.value;
|
|
80
77
|
let inputMode = options.defaultInputMode;
|
|
81
78
|
if (node.type === 'password' || hasOpenreplayAttribute(node, 'hidden')) {
|
|
82
|
-
inputMode = 2 /* Hidden */;
|
|
79
|
+
inputMode = 2 /* InputMode.Hidden */;
|
|
83
80
|
}
|
|
84
81
|
else if (hasOpenreplayAttribute(node, 'obscured') ||
|
|
85
|
-
(inputMode === 0 /* Plain */ &&
|
|
86
|
-
((options.obscureInputNumbers && /\d\d\d\d/.test(value)) ||
|
|
82
|
+
(inputMode === 0 /* InputMode.Plain */ &&
|
|
83
|
+
((options.obscureInputNumbers && node.type !== 'date' && /\d\d\d\d/.test(value)) ||
|
|
84
|
+
(options.obscureInputDates && node.type === 'date') ||
|
|
87
85
|
(options.obscureInputEmails &&
|
|
88
86
|
(node.type === 'email' || !!~value.indexOf('@')))))) {
|
|
89
|
-
inputMode = 1 /* Obscured */;
|
|
87
|
+
inputMode = 1 /* InputMode.Obscured */;
|
|
90
88
|
}
|
|
91
89
|
let mask = 0;
|
|
92
90
|
switch (inputMode) {
|
|
93
|
-
case 2 /* Hidden */:
|
|
91
|
+
case 2 /* InputMode.Hidden */:
|
|
94
92
|
mask = -1;
|
|
95
93
|
value = '';
|
|
96
94
|
break;
|
|
97
|
-
case 1 /* Obscured */:
|
|
95
|
+
case 1 /* InputMode.Obscured */:
|
|
98
96
|
mask = value.length;
|
|
99
97
|
value = '';
|
|
100
98
|
break;
|
|
@@ -144,7 +142,7 @@ export default function (app, opts) {
|
|
|
144
142
|
return;
|
|
145
143
|
}
|
|
146
144
|
// TODO: support multiple select (?): use selectedOptions; Need send target?
|
|
147
|
-
if (node
|
|
145
|
+
if (hasTag(node, "SELECT")) {
|
|
148
146
|
sendInputValue(id, node);
|
|
149
147
|
app.attachEventListener(node, "change", () => {
|
|
150
148
|
sendInputValue(id, node);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import App from "../app/index.js";
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
package/lib/modules/mouse.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import App from "../app/index.js";
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
package/lib/modules/mouse.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { hasTag, isSVGElement } from "../app/guards.js";
|
|
1
2
|
import { normSpaces, hasOpenreplayAttribute, getLabelAttribute, } from "../utils.js";
|
|
2
3
|
import { MouseMove, MouseClick } from "../common/messages.js";
|
|
3
4
|
import { getInputLabel } from "./input.js";
|
|
@@ -47,7 +48,7 @@ function _getTarget(target) {
|
|
|
47
48
|
}
|
|
48
49
|
element = element.parentElement;
|
|
49
50
|
}
|
|
50
|
-
if (target
|
|
51
|
+
if (isSVGElement(target)) {
|
|
51
52
|
let owner = target.ownerSVGElement;
|
|
52
53
|
while (owner !== null) {
|
|
53
54
|
target = owner;
|
|
@@ -77,7 +78,7 @@ export default function (app) {
|
|
|
77
78
|
if (dl !== null) {
|
|
78
79
|
return dl;
|
|
79
80
|
}
|
|
80
|
-
if (target
|
|
81
|
+
if (hasTag(target, "INPUT")) {
|
|
81
82
|
return getInputLabel(target);
|
|
82
83
|
}
|
|
83
84
|
if (isClickable(target)) {
|
package/lib/modules/scroll.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import App from "../app/index.js";
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
package/lib/modules/scroll.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SetViewportScroll, SetNodeScroll } from "../common/messages.js";
|
|
2
|
+
import { isElementNode } from "../app/guards.js";
|
|
2
3
|
export default function (app) {
|
|
3
4
|
let documentScroll = false;
|
|
4
5
|
const nodeScroll = new Map();
|
|
@@ -20,8 +21,8 @@ export default function (app) {
|
|
|
20
21
|
documentScroll = false;
|
|
21
22
|
nodeScroll.clear();
|
|
22
23
|
});
|
|
23
|
-
app.nodes.attachNodeCallback(node => {
|
|
24
|
-
if (
|
|
24
|
+
app.nodes.attachNodeCallback((node, isStart) => {
|
|
25
|
+
if (isStart && isElementNode(node) && node.scrollLeft + node.scrollTop > 0) {
|
|
25
26
|
nodeScroll.set(node, [node.scrollLeft, node.scrollTop]);
|
|
26
27
|
}
|
|
27
28
|
});
|
package/lib/modules/timing.d.ts
CHANGED
package/lib/modules/timing.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { hasTag } from "../app/guards.js";
|
|
1
2
|
import { isURL } from "../utils.js";
|
|
2
3
|
import { ResourceTiming, PageLoadTiming, PageRenderTiming } from "../common/messages.js";
|
|
3
4
|
function getPaintBlocks(resources) {
|
|
@@ -7,7 +8,7 @@ function getPaintBlocks(resources) {
|
|
|
7
8
|
for (let i = 0; i < elements.length; i++) {
|
|
8
9
|
const element = elements[i];
|
|
9
10
|
let src = '';
|
|
10
|
-
if (element
|
|
11
|
+
if (hasTag(element, "IMG")) {
|
|
11
12
|
src = element.currentSrc || element.src;
|
|
12
13
|
}
|
|
13
14
|
if (!src) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import App from "../app/index.js";
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openreplay/tracker",
|
|
3
3
|
"description": "The OpenReplay tracker main package",
|
|
4
|
-
"version": "3.5.
|
|
4
|
+
"version": "3.5.14",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"logging",
|
|
7
7
|
"replay"
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@babel/core": "^7.10.2",
|
|
27
27
|
"@rollup/plugin-babel": "^5.0.3",
|
|
28
|
-
"@rollup/plugin-node-resolve": "^
|
|
29
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
30
|
-
"@typescript-eslint/parser": "^
|
|
31
|
-
"eslint": "^
|
|
32
|
-
"eslint-plugin-prettier": "^
|
|
28
|
+
"@rollup/plugin-node-resolve": "^10.0.0",
|
|
29
|
+
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
|
30
|
+
"@typescript-eslint/parser": "^4.33.0",
|
|
31
|
+
"eslint": "^7.8.0",
|
|
32
|
+
"eslint-plugin-prettier": "^4.1.4",
|
|
33
33
|
"prettier": "^2.0.0",
|
|
34
34
|
"replace-in-files": "^2.0.3",
|
|
35
35
|
"rollup": "^2.17.0",
|
|
@@ -41,6 +41,6 @@
|
|
|
41
41
|
"error-stack-parser": "^2.0.6"
|
|
42
42
|
},
|
|
43
43
|
"engines": {
|
|
44
|
-
"node": ">=
|
|
44
|
+
"node": ">=14.15"
|
|
45
45
|
}
|
|
46
46
|
}
|
package/cjs/app/context.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export interface Window extends globalThis.Window {
|
|
2
|
-
HTMLInputElement: typeof HTMLInputElement;
|
|
3
|
-
HTMLLinkElement: typeof HTMLLinkElement;
|
|
4
|
-
HTMLStyleElement: typeof HTMLStyleElement;
|
|
5
|
-
SVGStyleElement: typeof SVGStyleElement;
|
|
6
|
-
HTMLIFrameElement: typeof HTMLIFrameElement;
|
|
7
|
-
Text: typeof Text;
|
|
8
|
-
Element: typeof Element;
|
|
9
|
-
ShadowRoot: typeof ShadowRoot;
|
|
10
|
-
}
|
|
11
|
-
declare type WindowConstructor = Document | Element | Text | ShadowRoot | HTMLInputElement | HTMLLinkElement | HTMLStyleElement | HTMLIFrameElement;
|
|
12
|
-
declare type Constructor<T> = {
|
|
13
|
-
new (...args: any[]): T;
|
|
14
|
-
name: string;
|
|
15
|
-
};
|
|
16
|
-
export declare function isInstance<T extends WindowConstructor>(node: Node, constr: Constructor<T>): node is T;
|
|
17
|
-
export declare function inDocument(node: Node): boolean;
|
|
18
|
-
export {};
|
package/cjs/app/context.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.inDocument = exports.isInstance = void 0;
|
|
4
|
-
// TODO: we need a type expert here so we won't have to ignore the lines
|
|
5
|
-
// TODO: use it everywhere (static function; export from which file? <-- global Window typing required)
|
|
6
|
-
// TODO: most efficient and common way
|
|
7
|
-
// Problem: on YouTube there is context[constr.name] undefined for constr=ShadowDom due to some minimisations
|
|
8
|
-
function isInstance(node, constr) {
|
|
9
|
-
const doc = node.ownerDocument;
|
|
10
|
-
if (!doc) { // null if Document
|
|
11
|
-
return constr.name === 'Document';
|
|
12
|
-
}
|
|
13
|
-
let context =
|
|
14
|
-
// @ts-ignore (for EI, Safary)
|
|
15
|
-
doc.parentWindow ||
|
|
16
|
-
doc.defaultView; // TODO: smart global typing for Window object
|
|
17
|
-
while (context !== window) {
|
|
18
|
-
// @ts-ignore
|
|
19
|
-
if (context[constr.name] && node instanceof context[constr.name]) {
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
// @ts-ignore
|
|
23
|
-
context = context.parent || window;
|
|
24
|
-
}
|
|
25
|
-
// @ts-ignore
|
|
26
|
-
return context[constr.name] ? node instanceof context[constr.name] : node instanceof constr;
|
|
27
|
-
}
|
|
28
|
-
exports.isInstance = isInstance;
|
|
29
|
-
// TODO: ensure 1. it works in every cases (iframes/detached nodes) and 2. the most efficient
|
|
30
|
-
function inDocument(node) {
|
|
31
|
-
const doc = node.ownerDocument;
|
|
32
|
-
if (!doc) {
|
|
33
|
-
return true;
|
|
34
|
-
} // Document
|
|
35
|
-
let current = node;
|
|
36
|
-
while (current) {
|
|
37
|
-
if (current === doc) {
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
else if (isInstance(current, ShadowRoot)) {
|
|
41
|
-
current = current.host;
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
current = current.parentNode;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
exports.inDocument = inDocument;
|
|
50
|
-
// export function inDocument(node: Node): boolean {
|
|
51
|
-
// // @ts-ignore compatability
|
|
52
|
-
// if (node.getRootNode) {
|
|
53
|
-
// let root: Node
|
|
54
|
-
// while ((root = node.getRootNode()) !== node) {
|
|
55
|
-
// ////
|
|
56
|
-
// }
|
|
57
|
-
// }
|
|
58
|
-
// const doc = node.ownerDocument
|
|
59
|
-
// if (!doc) { return false }
|
|
60
|
-
// if (doc.contains(node)) { return true }
|
|
61
|
-
// let context: Window =
|
|
62
|
-
// // @ts-ignore (for EI, Safary)
|
|
63
|
-
// doc.parentWindow ||
|
|
64
|
-
// doc.defaultView;
|
|
65
|
-
// while(context.parent && context.parent !== context) {
|
|
66
|
-
// if (context.document.contains(node)) {
|
|
67
|
-
// return true
|
|
68
|
-
// }
|
|
69
|
-
// // @ts-ignore
|
|
70
|
-
// context = context.parent
|
|
71
|
-
// }
|
|
72
|
-
// return false;
|
|
73
|
-
// }
|
package/lib/app/context.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export interface Window extends globalThis.Window {
|
|
2
|
-
HTMLInputElement: typeof HTMLInputElement;
|
|
3
|
-
HTMLLinkElement: typeof HTMLLinkElement;
|
|
4
|
-
HTMLStyleElement: typeof HTMLStyleElement;
|
|
5
|
-
SVGStyleElement: typeof SVGStyleElement;
|
|
6
|
-
HTMLIFrameElement: typeof HTMLIFrameElement;
|
|
7
|
-
Text: typeof Text;
|
|
8
|
-
Element: typeof Element;
|
|
9
|
-
ShadowRoot: typeof ShadowRoot;
|
|
10
|
-
}
|
|
11
|
-
declare type WindowConstructor = Document | Element | Text | ShadowRoot | HTMLInputElement | HTMLLinkElement | HTMLStyleElement | HTMLIFrameElement;
|
|
12
|
-
declare type Constructor<T> = {
|
|
13
|
-
new (...args: any[]): T;
|
|
14
|
-
name: string;
|
|
15
|
-
};
|
|
16
|
-
export declare function isInstance<T extends WindowConstructor>(node: Node, constr: Constructor<T>): node is T;
|
|
17
|
-
export declare function inDocument(node: Node): boolean;
|
|
18
|
-
export {};
|
package/lib/app/context.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// TODO: we need a type expert here so we won't have to ignore the lines
|
|
2
|
-
// TODO: use it everywhere (static function; export from which file? <-- global Window typing required)
|
|
3
|
-
// TODO: most efficient and common way
|
|
4
|
-
// Problem: on YouTube there is context[constr.name] undefined for constr=ShadowDom due to some minimisations
|
|
5
|
-
export function isInstance(node, constr) {
|
|
6
|
-
const doc = node.ownerDocument;
|
|
7
|
-
if (!doc) { // null if Document
|
|
8
|
-
return constr.name === 'Document';
|
|
9
|
-
}
|
|
10
|
-
let context =
|
|
11
|
-
// @ts-ignore (for EI, Safary)
|
|
12
|
-
doc.parentWindow ||
|
|
13
|
-
doc.defaultView; // TODO: smart global typing for Window object
|
|
14
|
-
while (context !== window) {
|
|
15
|
-
// @ts-ignore
|
|
16
|
-
if (context[constr.name] && node instanceof context[constr.name]) {
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
// @ts-ignore
|
|
20
|
-
context = context.parent || window;
|
|
21
|
-
}
|
|
22
|
-
// @ts-ignore
|
|
23
|
-
return context[constr.name] ? node instanceof context[constr.name] : node instanceof constr;
|
|
24
|
-
}
|
|
25
|
-
// TODO: ensure 1. it works in every cases (iframes/detached nodes) and 2. the most efficient
|
|
26
|
-
export function inDocument(node) {
|
|
27
|
-
const doc = node.ownerDocument;
|
|
28
|
-
if (!doc) {
|
|
29
|
-
return true;
|
|
30
|
-
} // Document
|
|
31
|
-
let current = node;
|
|
32
|
-
while (current) {
|
|
33
|
-
if (current === doc) {
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
else if (isInstance(current, ShadowRoot)) {
|
|
37
|
-
current = current.host;
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
current = current.parentNode;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
// export function inDocument(node: Node): boolean {
|
|
46
|
-
// // @ts-ignore compatability
|
|
47
|
-
// if (node.getRootNode) {
|
|
48
|
-
// let root: Node
|
|
49
|
-
// while ((root = node.getRootNode()) !== node) {
|
|
50
|
-
// ////
|
|
51
|
-
// }
|
|
52
|
-
// }
|
|
53
|
-
// const doc = node.ownerDocument
|
|
54
|
-
// if (!doc) { return false }
|
|
55
|
-
// if (doc.contains(node)) { return true }
|
|
56
|
-
// let context: Window =
|
|
57
|
-
// // @ts-ignore (for EI, Safary)
|
|
58
|
-
// doc.parentWindow ||
|
|
59
|
-
// doc.defaultView;
|
|
60
|
-
// while(context.parent && context.parent !== context) {
|
|
61
|
-
// if (context.document.contains(node)) {
|
|
62
|
-
// return true
|
|
63
|
-
// }
|
|
64
|
-
// // @ts-ignore
|
|
65
|
-
// context = context.parent
|
|
66
|
-
// }
|
|
67
|
-
// return false;
|
|
68
|
-
// }
|