@openreplay/tracker 3.6.1 → 3.6.2
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/LICENSE +1 -1
- package/cjs/app/guards.d.ts +1 -2
- package/cjs/app/guards.js +3 -6
- package/cjs/app/index.d.ts +23 -28
- package/cjs/app/index.js +86 -107
- package/cjs/app/logger.js +3 -6
- package/cjs/app/nodes.d.ts +1 -1
- package/cjs/app/nodes.js +0 -2
- package/cjs/app/observer/iframe_observer.d.ts +1 -1
- package/cjs/app/observer/iframe_observer.js +3 -3
- package/cjs/app/observer/observer.d.ts +3 -2
- package/cjs/app/observer/observer.js +52 -50
- package/cjs/app/observer/shadow_root_observer.d.ts +1 -1
- package/cjs/app/observer/shadow_root_observer.js +3 -3
- package/cjs/app/observer/top_observer.d.ts +2 -13
- package/cjs/app/observer/top_observer.js +23 -58
- package/cjs/app/sanitizer.d.ts +1 -1
- package/cjs/app/sanitizer.js +5 -5
- package/cjs/app/session.d.ts +2 -20
- package/cjs/app/session.js +6 -65
- package/cjs/app/ticker.d.ts +1 -1
- package/cjs/common/messages.d.ts +444 -0
- package/cjs/common/messages.js +794 -0
- package/cjs/common/types.d.ts +9 -0
- package/cjs/common/{interaction.js → types.js} +0 -0
- package/cjs/common/{interaction.d.ts → webworker.d.ts} +5 -5
- package/cjs/common/{messages.gen.js → webworker.js} +0 -1
- package/cjs/index.d.ts +9 -10
- package/cjs/index.js +36 -47
- package/cjs/modules/connection.d.ts +1 -1
- package/cjs/modules/connection.js +2 -2
- package/cjs/modules/console.d.ts +1 -1
- package/cjs/modules/console.js +21 -7
- package/cjs/modules/cssrules.d.ts +1 -1
- package/cjs/modules/cssrules.js +14 -18
- package/cjs/modules/exception.d.ts +3 -3
- package/cjs/modules/exception.js +18 -23
- package/cjs/modules/img.d.ts +1 -1
- package/cjs/modules/img.js +26 -39
- package/cjs/modules/input.d.ts +1 -1
- package/cjs/modules/input.js +21 -21
- package/cjs/modules/longtasks.d.ts +2 -0
- package/cjs/modules/longtasks.js +26 -0
- package/cjs/modules/mouse.d.ts +1 -1
- package/cjs/modules/mouse.js +43 -50
- package/cjs/modules/performance.d.ts +1 -1
- package/cjs/modules/performance.js +2 -2
- package/cjs/modules/scroll.d.ts +1 -1
- package/cjs/modules/scroll.js +7 -16
- package/cjs/modules/timing.d.ts +1 -1
- package/cjs/modules/timing.js +26 -14
- package/cjs/modules/viewport.d.ts +1 -1
- package/cjs/modules/viewport.js +4 -4
- package/cjs/utils.js +7 -7
- package/cjs/vendors/finder/finder.js +48 -53
- package/lib/app/guards.d.ts +1 -2
- package/lib/app/guards.js +2 -4
- package/lib/app/index.d.ts +23 -28
- package/lib/app/index.js +94 -115
- package/lib/app/logger.js +3 -6
- package/lib/app/nodes.d.ts +1 -1
- package/lib/app/nodes.js +0 -2
- package/lib/app/observer/iframe_observer.d.ts +1 -1
- package/lib/app/observer/iframe_observer.js +3 -3
- package/lib/app/observer/observer.d.ts +3 -2
- package/lib/app/observer/observer.js +53 -51
- package/lib/app/observer/shadow_root_observer.d.ts +1 -1
- package/lib/app/observer/shadow_root_observer.js +3 -3
- package/lib/app/observer/top_observer.d.ts +2 -13
- package/lib/app/observer/top_observer.js +27 -62
- package/lib/app/sanitizer.d.ts +1 -1
- package/lib/app/sanitizer.js +7 -7
- package/lib/app/session.d.ts +2 -20
- package/lib/app/session.js +6 -65
- package/lib/app/ticker.d.ts +1 -1
- package/lib/common/messages.d.ts +444 -0
- package/lib/common/messages.js +790 -0
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/common/types.d.ts +9 -0
- package/lib/common/{interaction.js → types.js} +0 -0
- package/lib/common/{interaction.d.ts → webworker.d.ts} +5 -5
- package/lib/common/webworker.js +1 -0
- package/lib/index.d.ts +9 -10
- package/lib/index.js +49 -60
- package/lib/modules/connection.d.ts +1 -1
- package/lib/modules/connection.js +2 -2
- package/lib/modules/console.d.ts +1 -1
- package/lib/modules/console.js +22 -8
- package/lib/modules/cssrules.d.ts +1 -1
- package/lib/modules/cssrules.js +15 -19
- package/lib/modules/exception.d.ts +3 -3
- package/lib/modules/exception.js +18 -23
- package/lib/modules/img.d.ts +1 -1
- package/lib/modules/img.js +28 -41
- package/lib/modules/input.d.ts +1 -1
- package/lib/modules/input.js +23 -23
- package/lib/modules/longtasks.d.ts +2 -0
- package/lib/modules/longtasks.js +23 -0
- package/lib/modules/mouse.d.ts +1 -1
- package/lib/modules/mouse.js +46 -53
- package/lib/modules/performance.d.ts +1 -1
- package/lib/modules/performance.js +3 -3
- package/lib/modules/scroll.d.ts +1 -1
- package/lib/modules/scroll.js +8 -17
- package/lib/modules/timing.d.ts +1 -1
- package/lib/modules/timing.js +28 -16
- package/lib/modules/viewport.d.ts +1 -1
- package/lib/modules/viewport.js +4 -4
- package/lib/utils.js +7 -7
- package/lib/vendors/finder/finder.js +48 -53
- package/package.json +10 -27
- package/.eslintignore +0 -8
- package/.prettierignore +0 -1
- package/cjs/app/messages.d.ts +0 -52
- package/cjs/app/messages.gen.d.ts +0 -57
- package/cjs/app/messages.gen.js +0 -493
- package/cjs/app/messages.js +0 -234
- package/cjs/common/messages.gen.d.ts +0 -382
- package/cjs/modules/adoptedStyleSheets.d.ts +0 -2
- package/cjs/modules/adoptedStyleSheets.js +0 -127
- package/lib/app/messages.d.ts +0 -52
- package/lib/app/messages.gen.d.ts +0 -57
- package/lib/app/messages.gen.js +0 -434
- package/lib/app/messages.js +0 -181
- package/lib/common/messages.gen.d.ts +0 -382
- package/lib/common/messages.gen.js +0 -2
- package/lib/modules/adoptedStyleSheets.d.ts +0 -2
- package/lib/modules/adoptedStyleSheets.js +0 -124
package/lib/modules/exception.js
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
import { JSException } from
|
|
1
|
+
import { JSException } from "../common/messages.js";
|
|
2
2
|
import ErrorStackParser from 'error-stack-parser';
|
|
3
3
|
function getDefaultStack(e) {
|
|
4
|
-
return [
|
|
5
|
-
{
|
|
4
|
+
return [{
|
|
6
5
|
columnNumber: e.colno,
|
|
7
6
|
lineNumber: e.lineno,
|
|
8
7
|
fileName: e.filename,
|
|
9
|
-
functionName:
|
|
10
|
-
source:
|
|
11
|
-
}
|
|
12
|
-
];
|
|
8
|
+
functionName: "",
|
|
9
|
+
source: "",
|
|
10
|
+
}];
|
|
13
11
|
}
|
|
14
12
|
export function getExceptionMessage(error, fallbackStack) {
|
|
15
13
|
let stack = fallbackStack;
|
|
16
14
|
try {
|
|
17
15
|
stack = ErrorStackParser.parse(error);
|
|
18
16
|
}
|
|
19
|
-
catch (e) {
|
|
20
|
-
|
|
17
|
+
catch (e) {
|
|
18
|
+
}
|
|
19
|
+
return new JSException(error.name, error.message, JSON.stringify(stack));
|
|
21
20
|
}
|
|
22
|
-
export function getExceptionMessageFromEvent(e
|
|
21
|
+
export function getExceptionMessageFromEvent(e) {
|
|
23
22
|
if (e instanceof ErrorEvent) {
|
|
24
23
|
if (e.error instanceof Error) {
|
|
25
24
|
return getExceptionMessage(e.error, getDefaultStack(e));
|
|
@@ -30,10 +29,10 @@ export function getExceptionMessageFromEvent(e, context = window) {
|
|
|
30
29
|
name = 'Error';
|
|
31
30
|
message = e.message;
|
|
32
31
|
}
|
|
33
|
-
return JSException(name, message, JSON.stringify(getDefaultStack(e)));
|
|
32
|
+
return new JSException(name, message, JSON.stringify(getDefaultStack(e)));
|
|
34
33
|
}
|
|
35
34
|
}
|
|
36
|
-
else if ('PromiseRejectionEvent' in
|
|
35
|
+
else if ('PromiseRejectionEvent' in window && e instanceof PromiseRejectionEvent) {
|
|
37
36
|
if (e.reason instanceof Error) {
|
|
38
37
|
return getExceptionMessage(e.reason, []);
|
|
39
38
|
}
|
|
@@ -45,7 +44,7 @@ export function getExceptionMessageFromEvent(e, context = window) {
|
|
|
45
44
|
catch (_) {
|
|
46
45
|
message = String(e.reason);
|
|
47
46
|
}
|
|
48
|
-
return JSException('Unhandled Promise Rejection', message, '[]');
|
|
47
|
+
return new JSException('Unhandled Promise Rejection', message, '[]');
|
|
49
48
|
}
|
|
50
49
|
}
|
|
51
50
|
return null;
|
|
@@ -54,18 +53,14 @@ export default function (app, opts) {
|
|
|
54
53
|
const options = Object.assign({
|
|
55
54
|
captureExceptions: true,
|
|
56
55
|
}, opts);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const msg = getExceptionMessageFromEvent(e
|
|
56
|
+
if (options.captureExceptions) {
|
|
57
|
+
const handler = (e) => {
|
|
58
|
+
const msg = getExceptionMessageFromEvent(e);
|
|
60
59
|
if (msg != null) {
|
|
61
60
|
app.send(msg);
|
|
62
61
|
}
|
|
63
|
-
}
|
|
64
|
-
app.attachEventListener(
|
|
65
|
-
app.attachEventListener(
|
|
66
|
-
}
|
|
67
|
-
if (options.captureExceptions) {
|
|
68
|
-
app.observer.attachContextCallback(patchContext);
|
|
69
|
-
patchContext(window);
|
|
62
|
+
};
|
|
63
|
+
app.attachEventListener(window, 'unhandledrejection', (e) => handler(e));
|
|
64
|
+
app.attachEventListener(window, 'error', (e) => handler(e));
|
|
70
65
|
}
|
|
71
66
|
}
|
package/lib/modules/img.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type App from
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
package/lib/modules/img.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { timestamp, isURL } from
|
|
2
|
-
import { ResourceTiming, SetNodeAttributeURLBased, SetNodeAttribute } from
|
|
3
|
-
import { hasTag } from
|
|
1
|
+
import { timestamp, isURL } from "../utils.js";
|
|
2
|
+
import { ResourceTiming, SetNodeAttributeURLBased, SetNodeAttribute } from "../common/messages.js";
|
|
3
|
+
import { hasTag } from "../app/guards.js";
|
|
4
4
|
function resolveURL(url, location = document.location) {
|
|
5
5
|
url = url.trim();
|
|
6
6
|
if (url.startsWith('/')) {
|
|
@@ -16,34 +16,19 @@ function resolveURL(url, location = document.location) {
|
|
|
16
16
|
return location.origin + location.pathname + url;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
const PLACEHOLDER_SRC =
|
|
19
|
+
const PLACEHOLDER_SRC = "https://static.openreplay.com/tracker/placeholder.jpeg";
|
|
20
20
|
export default function (app) {
|
|
21
21
|
function sendPlaceholder(id, node) {
|
|
22
|
-
app.send(SetNodeAttribute(id,
|
|
22
|
+
app.send(new SetNodeAttribute(id, "src", PLACEHOLDER_SRC));
|
|
23
23
|
const { width, height } = node.getBoundingClientRect();
|
|
24
|
-
if (!node.hasAttribute(
|
|
25
|
-
app.send(SetNodeAttribute(id,
|
|
24
|
+
if (!node.hasAttribute("width")) {
|
|
25
|
+
app.send(new SetNodeAttribute(id, "width", String(width)));
|
|
26
26
|
}
|
|
27
|
-
if (!node.hasAttribute(
|
|
28
|
-
app.send(SetNodeAttribute(id,
|
|
27
|
+
if (!node.hasAttribute("height")) {
|
|
28
|
+
app.send(new SetNodeAttribute(id, "height", String(height)));
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
const
|
|
32
|
-
const { srcset } = img;
|
|
33
|
-
if (!srcset) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
const resolvedSrcset = srcset
|
|
37
|
-
.split(',')
|
|
38
|
-
.map((str) => resolveURL(str))
|
|
39
|
-
.join(',');
|
|
40
|
-
app.send(SetNodeAttribute(id, 'srcset', resolvedSrcset));
|
|
41
|
-
};
|
|
42
|
-
const sendSrc = function (id, img) {
|
|
43
|
-
const src = img.src;
|
|
44
|
-
app.send(SetNodeAttributeURLBased(id, 'src', src, app.getBaseHref()));
|
|
45
|
-
};
|
|
46
|
-
const sendImgAttrs = app.safe(function () {
|
|
31
|
+
const sendImgSrc = app.safe(function () {
|
|
47
32
|
const id = app.nodes.getID(this);
|
|
48
33
|
if (id === undefined) {
|
|
49
34
|
return;
|
|
@@ -55,44 +40,46 @@ export default function (app) {
|
|
|
55
40
|
const resolvedSrc = resolveURL(src || ''); // Src type is null sometimes. - is it true?
|
|
56
41
|
if (naturalWidth === 0 && naturalHeight === 0) {
|
|
57
42
|
if (isURL(resolvedSrc)) {
|
|
58
|
-
app.send(ResourceTiming(timestamp(), 0, 0, 0, 0, 0, resolvedSrc, 'img'));
|
|
43
|
+
app.send(new ResourceTiming(timestamp(), 0, 0, 0, 0, 0, resolvedSrc, 'img'));
|
|
59
44
|
}
|
|
60
45
|
}
|
|
61
46
|
else if (resolvedSrc.length >= 1e5 || app.sanitizer.isMasked(id)) {
|
|
62
47
|
sendPlaceholder(id, this);
|
|
63
48
|
}
|
|
64
49
|
else {
|
|
65
|
-
|
|
66
|
-
|
|
50
|
+
app.send(new SetNodeAttribute(id, 'src', resolvedSrc));
|
|
51
|
+
if (srcset) {
|
|
52
|
+
const resolvedSrcset = srcset.split(',').map(str => resolveURL(str)).join(',');
|
|
53
|
+
app.send(new SetNodeAttribute(id, 'srcset', resolvedSrcset));
|
|
54
|
+
}
|
|
67
55
|
}
|
|
68
56
|
});
|
|
69
57
|
const observer = new MutationObserver((mutations) => {
|
|
70
58
|
for (const mutation of mutations) {
|
|
71
|
-
if (mutation.type ===
|
|
59
|
+
if (mutation.type === "attributes") {
|
|
72
60
|
const target = mutation.target;
|
|
73
61
|
const id = app.nodes.getID(target);
|
|
74
62
|
if (id === undefined) {
|
|
75
63
|
return;
|
|
76
64
|
}
|
|
77
|
-
if (mutation.attributeName ===
|
|
78
|
-
|
|
65
|
+
if (mutation.attributeName === "src") {
|
|
66
|
+
const src = target.src;
|
|
67
|
+
app.send(new SetNodeAttributeURLBased(id, 'src', src, app.getBaseHref()));
|
|
79
68
|
}
|
|
80
|
-
if (mutation.attributeName ===
|
|
81
|
-
|
|
69
|
+
if (mutation.attributeName === "srcset") {
|
|
70
|
+
const srcset = target.srcset;
|
|
71
|
+
app.send(new SetNodeAttribute(id, 'srcset', srcset));
|
|
82
72
|
}
|
|
83
73
|
}
|
|
84
74
|
}
|
|
85
75
|
});
|
|
86
|
-
app.attachStopCallback(() => {
|
|
87
|
-
observer.disconnect();
|
|
88
|
-
});
|
|
89
76
|
app.nodes.attachNodeCallback((node) => {
|
|
90
|
-
if (!hasTag(node,
|
|
77
|
+
if (!hasTag(node, "IMG")) {
|
|
91
78
|
return;
|
|
92
79
|
}
|
|
93
|
-
app.nodes.attachElementListener('error', node,
|
|
94
|
-
app.nodes.attachElementListener('load', node,
|
|
95
|
-
|
|
96
|
-
observer.observe(node, { attributes: true, attributeFilter: [
|
|
80
|
+
app.nodes.attachElementListener('error', node, sendImgSrc);
|
|
81
|
+
app.nodes.attachElementListener('load', node, sendImgSrc);
|
|
82
|
+
sendImgSrc.call(node);
|
|
83
|
+
observer.observe(node, { attributes: true, attributeFilter: ["src", "srcset"] });
|
|
97
84
|
});
|
|
98
85
|
}
|
package/lib/modules/input.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type App from
|
|
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 {
|
package/lib/modules/input.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { normSpaces, IN_BROWSER, getLabelAttribute, hasOpenreplayAttribute } from
|
|
2
|
-
import { hasTag } from
|
|
3
|
-
import { SetInputTarget, SetInputValue, SetInputChecked } from
|
|
1
|
+
import { normSpaces, IN_BROWSER, getLabelAttribute, hasOpenreplayAttribute, } from "../utils.js";
|
|
2
|
+
import { hasTag } from "../app/guards.js";
|
|
3
|
+
import { SetInputTarget, SetInputValue, SetInputChecked } from "../common/messages.js";
|
|
4
4
|
const INPUT_TYPES = ['text', 'password', 'email', 'search', 'number', 'range', 'date'];
|
|
5
5
|
function isTextEditable(node) {
|
|
6
|
-
if (hasTag(node,
|
|
6
|
+
if (hasTag(node, "TEXTAREA")) {
|
|
7
7
|
return true;
|
|
8
8
|
}
|
|
9
|
-
if (!hasTag(node,
|
|
9
|
+
if (!hasTag(node, "INPUT")) {
|
|
10
10
|
return false;
|
|
11
11
|
}
|
|
12
12
|
return INPUT_TYPES.includes(node.type);
|
|
13
13
|
}
|
|
14
14
|
function isCheckable(node) {
|
|
15
|
-
if (!hasTag(node,
|
|
15
|
+
if (!hasTag(node, "INPUT")) {
|
|
16
16
|
return false;
|
|
17
17
|
}
|
|
18
18
|
const type = node.type;
|
|
@@ -22,7 +22,7 @@ const labelElementFor = IN_BROWSER && 'labels' in HTMLInputElement.prototype
|
|
|
22
22
|
? (node) => {
|
|
23
23
|
let p = node;
|
|
24
24
|
while ((p = p.parentNode) !== null) {
|
|
25
|
-
if (hasTag(p,
|
|
25
|
+
if (hasTag(p, "LABEL")) {
|
|
26
26
|
return p;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -34,13 +34,13 @@ const labelElementFor = IN_BROWSER && 'labels' in HTMLInputElement.prototype
|
|
|
34
34
|
: (node) => {
|
|
35
35
|
let p = node;
|
|
36
36
|
while ((p = p.parentNode) !== null) {
|
|
37
|
-
if (hasTag(p,
|
|
37
|
+
if (hasTag(p, "LABEL")) {
|
|
38
38
|
return p;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
const id = node.id;
|
|
42
42
|
if (id) {
|
|
43
|
-
const labels =
|
|
43
|
+
const labels = document.querySelectorAll('label[for="' + id + '"]');
|
|
44
44
|
if (labels !== null && labels.length === 1) {
|
|
45
45
|
return labels[0];
|
|
46
46
|
}
|
|
@@ -50,13 +50,12 @@ export function getInputLabel(node) {
|
|
|
50
50
|
let label = getLabelAttribute(node);
|
|
51
51
|
if (label === null) {
|
|
52
52
|
const labelElement = labelElementFor(node);
|
|
53
|
-
label =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
node.type;
|
|
53
|
+
label = (labelElement && labelElement.innerText)
|
|
54
|
+
|| node.placeholder
|
|
55
|
+
|| node.name
|
|
56
|
+
|| node.id
|
|
57
|
+
|| node.className
|
|
58
|
+
|| node.type;
|
|
60
59
|
}
|
|
61
60
|
return normSpaces(label).slice(0, 100);
|
|
62
61
|
}
|
|
@@ -70,7 +69,7 @@ export default function (app, opts) {
|
|
|
70
69
|
function sendInputTarget(id, node) {
|
|
71
70
|
const label = getInputLabel(node);
|
|
72
71
|
if (label !== '') {
|
|
73
|
-
app.send(SetInputTarget(id, label));
|
|
72
|
+
app.send(new SetInputTarget(id, label));
|
|
74
73
|
}
|
|
75
74
|
}
|
|
76
75
|
function sendInputValue(id, node) {
|
|
@@ -83,7 +82,8 @@ export default function (app, opts) {
|
|
|
83
82
|
(inputMode === 0 /* Plain */ &&
|
|
84
83
|
((options.obscureInputNumbers && node.type !== 'date' && /\d\d\d\d/.test(value)) ||
|
|
85
84
|
(options.obscureInputDates && node.type === 'date') ||
|
|
86
|
-
(options.obscureInputEmails &&
|
|
85
|
+
(options.obscureInputEmails &&
|
|
86
|
+
(node.type === 'email' || !!~value.indexOf('@')))))) {
|
|
87
87
|
inputMode = 1 /* Obscured */;
|
|
88
88
|
}
|
|
89
89
|
let mask = 0;
|
|
@@ -97,7 +97,7 @@ export default function (app, opts) {
|
|
|
97
97
|
value = '';
|
|
98
98
|
break;
|
|
99
99
|
}
|
|
100
|
-
app.send(SetInputValue(id, value, mask));
|
|
100
|
+
app.send(new SetInputValue(id, value, mask));
|
|
101
101
|
}
|
|
102
102
|
const inputValues = new Map();
|
|
103
103
|
const checkableValues = new Map();
|
|
@@ -135,7 +135,7 @@ export default function (app, opts) {
|
|
|
135
135
|
}
|
|
136
136
|
if (checked !== node.checked) {
|
|
137
137
|
checkableValues.set(id, node.checked);
|
|
138
|
-
app.send(SetInputChecked(id, node.checked));
|
|
138
|
+
app.send(new SetInputChecked(id, node.checked));
|
|
139
139
|
}
|
|
140
140
|
});
|
|
141
141
|
});
|
|
@@ -146,9 +146,9 @@ export default function (app, opts) {
|
|
|
146
146
|
return;
|
|
147
147
|
}
|
|
148
148
|
// TODO: support multiple select (?): use selectedOptions; Need send target?
|
|
149
|
-
if (hasTag(node,
|
|
149
|
+
if (hasTag(node, "SELECT")) {
|
|
150
150
|
sendInputValue(id, node);
|
|
151
|
-
app.attachEventListener(node,
|
|
151
|
+
app.attachEventListener(node, "change", () => {
|
|
152
152
|
sendInputValue(id, node);
|
|
153
153
|
});
|
|
154
154
|
}
|
|
@@ -159,7 +159,7 @@ export default function (app, opts) {
|
|
|
159
159
|
}
|
|
160
160
|
if (isCheckable(node)) {
|
|
161
161
|
checkableValues.set(id, node.checked);
|
|
162
|
-
app.send(SetInputChecked(id, node.checked));
|
|
162
|
+
app.send(new SetInputChecked(id, node.checked));
|
|
163
163
|
return;
|
|
164
164
|
}
|
|
165
165
|
}));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { LongTask } from "../common/messages.js";
|
|
2
|
+
;
|
|
3
|
+
;
|
|
4
|
+
export default function (app) {
|
|
5
|
+
if (!('PerformanceObserver' in window) || !('PerformanceLongTaskTiming' in window)) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const contexts = ["unknown", "self", "same-origin-ancestor", "same-origin-descendant", "same-origin", "cross-origin-ancestor", "cross-origin-descendant", "cross-origin-unreachable", "multiple-contexts"];
|
|
9
|
+
const containerTypes = ["window", "iframe", "embed", "object"];
|
|
10
|
+
function longTask(entry) {
|
|
11
|
+
let type = "", src = "", id = "", name = "";
|
|
12
|
+
const container = entry.attribution[0];
|
|
13
|
+
if (container != null) {
|
|
14
|
+
type = container.containerType;
|
|
15
|
+
name = container.containerName;
|
|
16
|
+
id = container.containerId;
|
|
17
|
+
src = container.containerSrc;
|
|
18
|
+
}
|
|
19
|
+
app.send(new LongTask(entry.startTime + performance.timing.navigationStart, entry.duration, Math.max(contexts.indexOf(entry.name), 0), Math.max(containerTypes.indexOf(type), 0), name, id, src));
|
|
20
|
+
}
|
|
21
|
+
const observer = new PerformanceObserver((list) => list.getEntries().forEach(longTask));
|
|
22
|
+
observer.observe({ entryTypes: ['longtask'] });
|
|
23
|
+
}
|
package/lib/modules/mouse.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type App from
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
package/lib/modules/mouse.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { hasTag, isSVGElement
|
|
2
|
-
import { normSpaces, hasOpenreplayAttribute, getLabelAttribute } from
|
|
3
|
-
import { MouseMove, MouseClick } from
|
|
4
|
-
import { getInputLabel } from
|
|
5
|
-
function _getSelector(target
|
|
1
|
+
import { hasTag, isSVGElement } from "../app/guards.js";
|
|
2
|
+
import { normSpaces, hasOpenreplayAttribute, getLabelAttribute, } from "../utils.js";
|
|
3
|
+
import { MouseMove, MouseClick } from "../common/messages.js";
|
|
4
|
+
import { getInputLabel } from "./input.js";
|
|
5
|
+
function _getSelector(target) {
|
|
6
6
|
let el = target;
|
|
7
7
|
let selector = null;
|
|
8
8
|
do {
|
|
@@ -10,10 +10,9 @@ function _getSelector(target, document) {
|
|
|
10
10
|
return `#${el.id}` + (selector ? ` > ${selector}` : '');
|
|
11
11
|
}
|
|
12
12
|
selector =
|
|
13
|
-
el.className
|
|
14
|
-
.
|
|
15
|
-
.
|
|
16
|
-
.filter((cn) => cn !== '')
|
|
13
|
+
el.className.split(' ')
|
|
14
|
+
.map(cn => cn.trim())
|
|
15
|
+
.filter(cn => cn !== '')
|
|
17
16
|
.reduce((sel, cn) => `${sel}.${cn}`, el.tagName.toLowerCase()) +
|
|
18
17
|
(selector ? ` > ${selector}` : '');
|
|
19
18
|
if (el === document.body) {
|
|
@@ -25,23 +24,23 @@ function _getSelector(target, document) {
|
|
|
25
24
|
}
|
|
26
25
|
function isClickable(element) {
|
|
27
26
|
const tag = element.tagName.toUpperCase();
|
|
28
|
-
return
|
|
27
|
+
return tag === 'BUTTON' ||
|
|
29
28
|
tag === 'A' ||
|
|
30
29
|
tag === 'LI' ||
|
|
31
30
|
tag === 'SELECT' ||
|
|
32
31
|
element.onclick != null ||
|
|
33
|
-
element.getAttribute('role') === 'button'
|
|
32
|
+
element.getAttribute('role') === 'button';
|
|
34
33
|
//|| element.className.includes("btn")
|
|
35
|
-
// MBTODO:
|
|
34
|
+
// MBTODO: intersect addEventListener
|
|
36
35
|
}
|
|
37
|
-
//TODO: fix (typescript
|
|
38
|
-
function getTarget(target
|
|
36
|
+
//TODO: fix (typescript doesn't allow work when the guard is inside the function)
|
|
37
|
+
function getTarget(target) {
|
|
39
38
|
if (target instanceof Element) {
|
|
40
|
-
return _getTarget(target
|
|
39
|
+
return _getTarget(target);
|
|
41
40
|
}
|
|
42
41
|
return null;
|
|
43
42
|
}
|
|
44
|
-
function _getTarget(target
|
|
43
|
+
function _getTarget(target) {
|
|
45
44
|
let element = target;
|
|
46
45
|
while (element !== null && element !== document.documentElement) {
|
|
47
46
|
if (hasOpenreplayAttribute(element, 'masked')) {
|
|
@@ -65,7 +64,8 @@ function _getTarget(target, document) {
|
|
|
65
64
|
if (tag === 'INPUT') {
|
|
66
65
|
return element;
|
|
67
66
|
}
|
|
68
|
-
if (isClickable(element) ||
|
|
67
|
+
if (isClickable(element) ||
|
|
68
|
+
getLabelAttribute(element) !== null) {
|
|
69
69
|
return element;
|
|
70
70
|
}
|
|
71
71
|
element = element.parentElement;
|
|
@@ -78,7 +78,7 @@ export default function (app) {
|
|
|
78
78
|
if (dl !== null) {
|
|
79
79
|
return dl;
|
|
80
80
|
}
|
|
81
|
-
if (hasTag(target,
|
|
81
|
+
if (hasTag(target, "INPUT")) {
|
|
82
82
|
return getInputLabel(target);
|
|
83
83
|
}
|
|
84
84
|
if (isClickable(target)) {
|
|
@@ -104,46 +104,39 @@ export default function (app) {
|
|
|
104
104
|
});
|
|
105
105
|
const sendMouseMove = () => {
|
|
106
106
|
if (mousePositionChanged) {
|
|
107
|
-
app.send(MouseMove(mousePositionX, mousePositionY));
|
|
107
|
+
app.send(new MouseMove(mousePositionX, mousePositionY));
|
|
108
108
|
mousePositionChanged = false;
|
|
109
109
|
}
|
|
110
110
|
};
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
const selectorMap = {};
|
|
112
|
+
function getSelector(id, target) {
|
|
113
|
+
return selectorMap[id] = selectorMap[id] || _getSelector(target);
|
|
114
|
+
}
|
|
115
|
+
app.attachEventListener(document.documentElement, 'mouseover', (e) => {
|
|
116
|
+
const target = getTarget(e.target);
|
|
117
|
+
if (target !== mouseTarget) {
|
|
118
|
+
mouseTarget = target;
|
|
119
|
+
mouseTargetTime = performance.now();
|
|
115
120
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
mousePositionY = e.clientY + top;
|
|
127
|
-
mousePositionChanged = true;
|
|
128
|
-
}, false);
|
|
129
|
-
app.attachEventListener(document, 'click', (e) => {
|
|
130
|
-
const target = getTarget(e.target, document);
|
|
131
|
-
if ((!e.clientX && !e.clientY) || target === null) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
const id = app.nodes.getID(target);
|
|
135
|
-
if (id !== undefined) {
|
|
136
|
-
sendMouseMove();
|
|
137
|
-
app.send(MouseClick(id, mouseTarget === target ? Math.round(performance.now() - mouseTargetTime) : 0, getTargetLabel(target), getSelector(id, target)), true);
|
|
138
|
-
}
|
|
139
|
-
mouseTarget = null;
|
|
140
|
-
});
|
|
141
|
-
};
|
|
142
|
-
app.nodes.attachNodeCallback((node) => {
|
|
143
|
-
if (isDocument(node)) {
|
|
144
|
-
patchDocument(node);
|
|
121
|
+
});
|
|
122
|
+
app.attachEventListener(document, 'mousemove', (e) => {
|
|
123
|
+
mousePositionX = e.clientX;
|
|
124
|
+
mousePositionY = e.clientY;
|
|
125
|
+
mousePositionChanged = true;
|
|
126
|
+
}, false);
|
|
127
|
+
app.attachEventListener(document, 'click', (e) => {
|
|
128
|
+
const target = getTarget(e.target);
|
|
129
|
+
if ((!e.clientX && !e.clientY) || target === null) {
|
|
130
|
+
return;
|
|
145
131
|
}
|
|
132
|
+
const id = app.nodes.getID(target);
|
|
133
|
+
if (id !== undefined) {
|
|
134
|
+
sendMouseMove();
|
|
135
|
+
app.send(new MouseClick(id, mouseTarget === target
|
|
136
|
+
? Math.round(performance.now() - mouseTargetTime)
|
|
137
|
+
: 0, getTargetLabel(target), getSelector(id, target)), true);
|
|
138
|
+
}
|
|
139
|
+
mouseTarget = null;
|
|
146
140
|
});
|
|
147
|
-
patchDocument(document);
|
|
148
141
|
app.ticker.attach(sendMouseMove, 10);
|
|
149
142
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IN_BROWSER } from
|
|
2
|
-
import { PerformanceTrack } from
|
|
1
|
+
import { IN_BROWSER } from "../utils.js";
|
|
2
|
+
import { PerformanceTrack } from "../common/messages.js";
|
|
3
3
|
const perf = IN_BROWSER && 'performance' in window && 'memory' in performance // works in Chrome only
|
|
4
4
|
? performance
|
|
5
5
|
: { memory: {} };
|
|
@@ -31,7 +31,7 @@ export default function (app, opts) {
|
|
|
31
31
|
if (frames === undefined || ticks === undefined) {
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
-
app.send(PerformanceTrack(frames, ticks, perf.memory.totalJSHeapSize || 0, perf.memory.usedJSHeapSize || 0));
|
|
34
|
+
app.send(new PerformanceTrack(frames, ticks, perf.memory.totalJSHeapSize || 0, perf.memory.usedJSHeapSize || 0));
|
|
35
35
|
ticks = frames = document.hidden ? -1 : 0;
|
|
36
36
|
};
|
|
37
37
|
app.attachStartCallback(() => {
|
package/lib/modules/scroll.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type App from
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
package/lib/modules/scroll.js
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import { SetViewportScroll, SetNodeScroll } from
|
|
2
|
-
import { isElementNode
|
|
1
|
+
import { SetViewportScroll, SetNodeScroll } from "../common/messages.js";
|
|
2
|
+
import { isElementNode } from "../app/guards.js";
|
|
3
3
|
export default function (app) {
|
|
4
4
|
let documentScroll = false;
|
|
5
5
|
const nodeScroll = new Map();
|
|
6
|
-
|
|
7
|
-
if (target instanceof Element) {
|
|
8
|
-
nodeScroll.set(target, [target.scrollLeft, target.scrollTop]);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
const sendSetViewportScroll = app.safe(() => app.send(SetViewportScroll(window.pageXOffset ||
|
|
6
|
+
const sendSetViewportScroll = app.safe(() => app.send(new SetViewportScroll(window.pageXOffset ||
|
|
12
7
|
(document.documentElement && document.documentElement.scrollLeft) ||
|
|
13
8
|
(document.body && document.body.scrollLeft) ||
|
|
14
9
|
0, window.pageYOffset ||
|
|
@@ -18,7 +13,7 @@ export default function (app) {
|
|
|
18
13
|
const sendSetNodeScroll = app.safe((s, node) => {
|
|
19
14
|
const id = app.nodes.getID(node);
|
|
20
15
|
if (id !== undefined) {
|
|
21
|
-
app.send(SetNodeScroll(id, s[0], s[1]));
|
|
16
|
+
app.send(new SetNodeScroll(id, s[0], s[1]));
|
|
22
17
|
}
|
|
23
18
|
});
|
|
24
19
|
app.attachStartCallback(sendSetViewportScroll);
|
|
@@ -30,20 +25,16 @@ export default function (app) {
|
|
|
30
25
|
if (isStart && isElementNode(node) && node.scrollLeft + node.scrollTop > 0) {
|
|
31
26
|
nodeScroll.set(node, [node.scrollLeft, node.scrollTop]);
|
|
32
27
|
}
|
|
33
|
-
else if (isRootNode(node)) {
|
|
34
|
-
// scroll is not-composed event (https://javascript.info/shadow-dom-events)
|
|
35
|
-
app.attachEventListener(node, 'scroll', (e) => {
|
|
36
|
-
setNodeScroll(e.target);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
28
|
});
|
|
40
|
-
app.attachEventListener(
|
|
29
|
+
app.attachEventListener(window, 'scroll', (e) => {
|
|
41
30
|
const target = e.target;
|
|
42
31
|
if (target === document) {
|
|
43
32
|
documentScroll = true;
|
|
44
33
|
return;
|
|
45
34
|
}
|
|
46
|
-
|
|
35
|
+
if (target instanceof Element) {
|
|
36
|
+
nodeScroll.set(target, [target.scrollLeft, target.scrollTop]);
|
|
37
|
+
}
|
|
47
38
|
});
|
|
48
39
|
app.ticker.attach(() => {
|
|
49
40
|
if (documentScroll) {
|
package/lib/modules/timing.d.ts
CHANGED