clarity-js 0.6.32 → 0.6.35
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/build/clarity.js +2080 -2100
- package/build/clarity.min.js +1 -1
- package/build/clarity.module.js +2080 -2100
- package/package.json +1 -1
- package/src/core/config.ts +2 -2
- package/src/core/history.ts +27 -27
- package/src/core/version.ts +1 -1
- package/src/data/encode.ts +9 -0
- package/src/data/extract.ts +143 -0
- package/src/data/index.ts +3 -1
- package/src/data/metadata.ts +15 -11
- package/src/data/metric.ts +3 -3
- package/src/diagnostic/encode.ts +9 -0
- package/src/diagnostic/fraud.ts +29 -0
- package/src/diagnostic/index.ts +2 -0
- package/src/diagnostic/script.ts +1 -11
- package/src/interaction/click.ts +2 -1
- package/src/interaction/encode.ts +4 -3
- package/src/interaction/input.ts +1 -8
- package/src/layout/dom.ts +105 -90
- package/src/layout/encode.ts +15 -15
- package/src/layout/index.ts +0 -3
- package/src/layout/mutation.ts +32 -44
- package/src/layout/target.ts +7 -4
- package/src/performance/observer.ts +10 -2
- package/types/core.d.ts +20 -13
- package/types/data.d.ts +27 -7
- package/types/diagnostic.d.ts +6 -0
- package/types/interaction.d.ts +1 -0
- package/types/layout.d.ts +8 -6
- package/types/performance.d.ts +0 -7
- package/src/layout/box.ts +0 -83
- package/src/layout/extract.ts +0 -94
package/package.json
CHANGED
package/src/core/config.ts
CHANGED
package/src/core/history.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { Code, Constant, Setting, Severity } from "@clarity-types/data";
|
|
1
|
+
import { BooleanFlag, Code, Constant, Metric, Setting, Severity } from "@clarity-types/data";
|
|
2
2
|
import * as clarity from "@src/clarity";
|
|
3
|
+
import * as core from "@src/core"
|
|
3
4
|
import { bind } from "@src/core/event";
|
|
4
5
|
import * as internal from "@src/diagnostic/internal";
|
|
6
|
+
import * as metric from "@src/data/metric";
|
|
5
7
|
|
|
6
8
|
let pushState = null;
|
|
7
9
|
let replaceState = null;
|
|
@@ -12,24 +14,29 @@ export function start(): void {
|
|
|
12
14
|
url = getCurrentUrl();
|
|
13
15
|
count = 0;
|
|
14
16
|
bind(window, "popstate", compute);
|
|
15
|
-
|
|
17
|
+
|
|
16
18
|
// Add a proxy to history.pushState function
|
|
17
|
-
if (pushState === null) {
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
if (pushState === null) {
|
|
20
|
+
pushState = history.pushState;
|
|
21
|
+
history.pushState = function(): void {
|
|
20
22
|
pushState.apply(this, arguments);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
if (core.active() && check()) {
|
|
24
|
+
compute();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
24
28
|
|
|
25
29
|
// Add a proxy to history.replaceState function
|
|
26
|
-
if (replaceState === null)
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
if (replaceState === null)
|
|
31
|
+
{
|
|
32
|
+
replaceState = history.replaceState;
|
|
33
|
+
history.replaceState = function(): void {
|
|
29
34
|
replaceState.apply(this, arguments);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
if (core.active() && check()) {
|
|
36
|
+
compute();
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
function check(): boolean {
|
|
@@ -45,27 +52,20 @@ function compute(): void {
|
|
|
45
52
|
if (url !== getCurrentUrl()) {
|
|
46
53
|
// If the url changed, start tracking it as a new page
|
|
47
54
|
clarity.stop();
|
|
48
|
-
window.setTimeout(
|
|
55
|
+
window.setTimeout(restart, Setting.RestartDelay);
|
|
49
56
|
}
|
|
50
57
|
}
|
|
51
58
|
|
|
59
|
+
function restart(): void {
|
|
60
|
+
clarity.start();
|
|
61
|
+
metric.max(Metric.SinglePage, BooleanFlag.True);
|
|
62
|
+
}
|
|
63
|
+
|
|
52
64
|
function getCurrentUrl(): string {
|
|
53
65
|
return location.href ? location.href.replace(location.hash, Constant.Empty) : location.href;
|
|
54
66
|
}
|
|
55
67
|
|
|
56
68
|
export function stop(): void {
|
|
57
|
-
// Restore original function definition of history.pushState
|
|
58
|
-
if (pushState !== null) {
|
|
59
|
-
history.pushState = pushState;
|
|
60
|
-
pushState = null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Restore original function definition of history.replaceState
|
|
64
|
-
if (replaceState !== null) {
|
|
65
|
-
history.replaceState = replaceState;
|
|
66
|
-
replaceState = null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
69
|
url = null;
|
|
70
70
|
count = 0;
|
|
71
71
|
}
|
package/src/core/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let version = "0.6.
|
|
1
|
+
let version = "0.6.35";
|
|
2
2
|
export default version;
|
package/src/data/encode.ts
CHANGED
|
@@ -9,6 +9,7 @@ import * as ping from "@src/data/ping";
|
|
|
9
9
|
import * as summary from "@src/data/summary";
|
|
10
10
|
import * as upgrade from "@src/data/upgrade";
|
|
11
11
|
import * as variable from "@src/data/variable";
|
|
12
|
+
import * as extract from "@src/data/extract";
|
|
12
13
|
import { queue, track } from "./upload";
|
|
13
14
|
|
|
14
15
|
export default function(event: Event): void {
|
|
@@ -105,5 +106,13 @@ export default function(event: Event): void {
|
|
|
105
106
|
queue(tokens, false);
|
|
106
107
|
}
|
|
107
108
|
break;
|
|
109
|
+
case Event.Extract:
|
|
110
|
+
let extractKeys = extract.keys;
|
|
111
|
+
for (let e of extractKeys) {
|
|
112
|
+
tokens.push(e);
|
|
113
|
+
tokens.push(extract.data[e]);
|
|
114
|
+
}
|
|
115
|
+
extract.reset();
|
|
116
|
+
queue(tokens, false);
|
|
108
117
|
}
|
|
109
118
|
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { ExtractSource, Syntax, Type } from "@clarity-types/core";
|
|
2
|
+
import { Event, Setting, ExtractData } from "@clarity-types/data";
|
|
3
|
+
import config from "@src/core/config";
|
|
4
|
+
import encode from "./encode";
|
|
5
|
+
import * as internal from "@src/diagnostic/internal";
|
|
6
|
+
import { Code, Constant, Severity } from "@clarity-types/data";
|
|
7
|
+
|
|
8
|
+
export let data: ExtractData = {};
|
|
9
|
+
export let keys: (number | string)[] = [];
|
|
10
|
+
|
|
11
|
+
let variables : { [key: number]: Syntax[] } = {};
|
|
12
|
+
let selectors : { [key: number]: string } = {};
|
|
13
|
+
export let fragments: string[] = [];
|
|
14
|
+
|
|
15
|
+
export function start(): void {
|
|
16
|
+
try {
|
|
17
|
+
let e = config.extract;
|
|
18
|
+
if (!e) { return; }
|
|
19
|
+
for (let i = 0; i < e.length; i+=3) {
|
|
20
|
+
let source = e[i] as ExtractSource;
|
|
21
|
+
let key = e[i+1] as number;
|
|
22
|
+
switch (source) {
|
|
23
|
+
case ExtractSource.Javascript:
|
|
24
|
+
let variable = e[i+2] as string;
|
|
25
|
+
variables[key] = parse(variable);
|
|
26
|
+
break;
|
|
27
|
+
case ExtractSource.Cookie:
|
|
28
|
+
/*Todo: Add cookie extract logic*/
|
|
29
|
+
break;
|
|
30
|
+
case ExtractSource.Text:
|
|
31
|
+
let match = e[i+2] as string;
|
|
32
|
+
selectors[key] = match;
|
|
33
|
+
break;
|
|
34
|
+
case ExtractSource.Fragment:
|
|
35
|
+
fragments = e[i+2] as string[];
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch(e) {
|
|
41
|
+
internal.log(Code.Config, Severity.Warning, e ? e.name : null);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function clone(v: Syntax[]): Syntax[] {
|
|
46
|
+
return JSON.parse(JSON.stringify(v));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function compute(): void {
|
|
50
|
+
try {
|
|
51
|
+
for (let v in variables) {
|
|
52
|
+
let value = str(evaluate(clone(variables[v])));
|
|
53
|
+
if (value) { update(v, value); }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
for (let s in selectors) {
|
|
57
|
+
let node = document.querySelector(selectors[s] as string) as HTMLElement;
|
|
58
|
+
if (node) { update(s, node.innerText); }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (e) { internal.log(Code.Selector, Severity.Warning, e ? e.name : null); }
|
|
62
|
+
|
|
63
|
+
encode(Event.Extract);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function reset(): void {
|
|
67
|
+
keys = [];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function update(key: string, value: string | number, force: boolean = false): void {
|
|
71
|
+
if (!(key in data) || (key in data && data[key] !== value) || force ) {
|
|
72
|
+
data[key] = value;
|
|
73
|
+
keys.push(key);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function stop(): void {
|
|
78
|
+
data = {};
|
|
79
|
+
keys = [];
|
|
80
|
+
variables = {};
|
|
81
|
+
selectors = {};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function parse(variable: string): Syntax[] {
|
|
85
|
+
let syntax: Syntax[] = [];
|
|
86
|
+
let parts = variable.split(Constant.Dot);
|
|
87
|
+
while (parts.length > 0) {
|
|
88
|
+
let part = parts.shift();
|
|
89
|
+
let arrayStart = part.indexOf(Constant.ArrayStart);
|
|
90
|
+
let conditionStart = part.indexOf(Constant.ConditionStart);
|
|
91
|
+
let conditionEnd = part.indexOf(Constant.ConditionEnd);
|
|
92
|
+
syntax.push({
|
|
93
|
+
name : arrayStart > 0 ? part.substring(0, arrayStart) : (conditionStart > 0 ? part.substring(0, conditionStart) : part),
|
|
94
|
+
type : arrayStart > 0 ? Type.Array : (conditionStart > 0 ? Type.Object : Type.Simple),
|
|
95
|
+
condition : conditionStart > 0 ? part.substring(conditionStart + 1, conditionEnd) : null
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return syntax;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// The function below takes in a variable name in following format: "a.b.c" and safely evaluates its value in javascript context
|
|
103
|
+
// For instance, for a.b.c, it will first check window["a"]. If it exists, it will recursively look at: window["a"]["b"] and finally,
|
|
104
|
+
// return the value for window["a"]["b"]["c"].
|
|
105
|
+
function evaluate(variable: Syntax[], base: Object = window): any {
|
|
106
|
+
if (variable.length == 0) { return base; }
|
|
107
|
+
let part = variable.shift();
|
|
108
|
+
let output;
|
|
109
|
+
if (base && base[part.name]) {
|
|
110
|
+
let obj = base[part.name];
|
|
111
|
+
if (part.type !== Type.Array && match(obj, part.condition)) {
|
|
112
|
+
output = evaluate(variable, obj);
|
|
113
|
+
}
|
|
114
|
+
else if (Array.isArray(obj)) {
|
|
115
|
+
let filtered = [];
|
|
116
|
+
for (var value of obj) {
|
|
117
|
+
if (match(value, part.condition)) {
|
|
118
|
+
let op = evaluate(variable, value)
|
|
119
|
+
if (op) { filtered.push(op); }
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
output = filtered;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return output;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function str(input: string): string {
|
|
132
|
+
// Automatically trim string to max of Setting.ExtractLimit to avoid fetching long strings
|
|
133
|
+
return input ? JSON.stringify(input).substring(0, Setting.ExtractLimit) : input;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function match(base: Object, condition: string): boolean {
|
|
137
|
+
if (condition) {
|
|
138
|
+
let prop = condition.split(":");
|
|
139
|
+
return prop.length > 1 ? base[prop[0]] == prop[1] : base[prop[0]]
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return true;
|
|
143
|
+
}
|
package/src/data/index.ts
CHANGED
|
@@ -11,12 +11,13 @@ import * as summary from "@src/data/summary";
|
|
|
11
11
|
import * as upgrade from "@src/data/upgrade";
|
|
12
12
|
import * as upload from "@src/data/upload";
|
|
13
13
|
import * as variable from "@src/data/variable";
|
|
14
|
+
import * as extract from "@src/data/extract";
|
|
14
15
|
export { event } from "@src/data/custom";
|
|
15
16
|
export { consent, metadata } from "@src/data/metadata";
|
|
16
17
|
export { upgrade } from "@src/data/upgrade";
|
|
17
18
|
export { set, identify } from "@src/data/variable";
|
|
18
19
|
|
|
19
|
-
const modules: Module[] = [baseline, dimension, variable, limit, summary, metadata, envelope, upload, ping, upgrade];
|
|
20
|
+
const modules: Module[] = [baseline, dimension, variable, limit, summary, metadata, envelope, upload, ping, upgrade, extract];
|
|
20
21
|
|
|
21
22
|
export function start(): void {
|
|
22
23
|
// Metric needs to be initialized before we can start measuring. so metric is not wrapped in measure
|
|
@@ -40,4 +41,5 @@ export function compute(): void {
|
|
|
40
41
|
metric.compute();
|
|
41
42
|
summary.compute();
|
|
42
43
|
limit.compute();
|
|
44
|
+
extract.compute();
|
|
43
45
|
}
|
package/src/data/metadata.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Time } from "@clarity-types/core";
|
|
2
|
-
import { BooleanFlag, Constant, Dimension, Metadata, MetadataCallback, Metric, Session, User, Setting } from "@clarity-types/data";
|
|
2
|
+
import { BooleanFlag, Constant, Dimension, Metadata, MetadataCallback, MetadataCallbackOptions, Metric, Session, User, Setting } from "@clarity-types/data";
|
|
3
3
|
import * as core from "@src/core";
|
|
4
4
|
import config from "@src/core/config";
|
|
5
5
|
import hash from "@src/core/hash";
|
|
@@ -8,11 +8,10 @@ import * as metric from "@src/data/metric";
|
|
|
8
8
|
import { set } from "@src/data/variable";
|
|
9
9
|
|
|
10
10
|
export let data: Metadata = null;
|
|
11
|
-
export let
|
|
11
|
+
export let callbacks: MetadataCallbackOptions[] = [];
|
|
12
12
|
let rootDomain = null;
|
|
13
13
|
|
|
14
14
|
export function start(): void {
|
|
15
|
-
callback = null;
|
|
16
15
|
rootDomain = null;
|
|
17
16
|
const ua = navigator && "userAgent" in navigator ? navigator.userAgent : Constant.Empty;
|
|
18
17
|
const title = document && document.title ? document.title : Constant.Empty;
|
|
@@ -40,7 +39,6 @@ export function start(): void {
|
|
|
40
39
|
dimension.log(Dimension.DocumentDirection, document.dir);
|
|
41
40
|
if (navigator) {
|
|
42
41
|
dimension.log(Dimension.Language, (<any>navigator).userLanguage || navigator.language);
|
|
43
|
-
metric.max(Metric.Automation, navigator.webdriver ? BooleanFlag.True : BooleanFlag.False);
|
|
44
42
|
userAgentData();
|
|
45
43
|
}
|
|
46
44
|
|
|
@@ -64,7 +62,7 @@ export function start(): void {
|
|
|
64
62
|
track(u);
|
|
65
63
|
}
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
function userAgentData(): void {
|
|
68
66
|
if (navigator["userAgentData"] && navigator["userAgentData"].getHighEntropyValues) {
|
|
69
67
|
navigator["userAgentData"].getHighEntropyValues(
|
|
70
68
|
["model",
|
|
@@ -84,7 +82,6 @@ export function userAgentData(): void {
|
|
|
84
82
|
}
|
|
85
83
|
|
|
86
84
|
export function stop(): void {
|
|
87
|
-
callback = null;
|
|
88
85
|
rootDomain = null;
|
|
89
86
|
data = null;
|
|
90
87
|
}
|
|
@@ -93,10 +90,9 @@ export function metadata(cb: MetadataCallback, wait: boolean = true): void {
|
|
|
93
90
|
if (data && wait === false) {
|
|
94
91
|
// Immediately invoke the callback if the caller explicitly doesn't want to wait for the upgrade confirmation
|
|
95
92
|
cb(data, !config.lean);
|
|
96
|
-
} else {
|
|
97
|
-
// Save the callback for future reference; so we can inform the caller when page gets upgraded and we have a valid playback flag
|
|
98
|
-
callback = cb;
|
|
99
93
|
}
|
|
94
|
+
|
|
95
|
+
callbacks.push({callback: cb, wait: wait });
|
|
100
96
|
}
|
|
101
97
|
|
|
102
98
|
export function id(): string {
|
|
@@ -127,12 +123,20 @@ function tab(): string {
|
|
|
127
123
|
|
|
128
124
|
export function save(): void {
|
|
129
125
|
let ts = Math.round(Date.now());
|
|
130
|
-
let upgrade = config.lean ? BooleanFlag.False : BooleanFlag.True;
|
|
131
126
|
let upload = config.upload && typeof config.upload === Constant.String ? (config.upload as string).replace(Constant.HTTPS, Constant.Empty) : Constant.Empty;
|
|
132
|
-
|
|
127
|
+
let upgrade = config.lean ? BooleanFlag.False : BooleanFlag.True;
|
|
128
|
+
processCallback(upgrade);
|
|
133
129
|
setCookie(Constant.SessionKey, [data.sessionId, ts, data.pageNum, upgrade, upload].join(Constant.Pipe), Setting.SessionExpire);
|
|
134
130
|
}
|
|
135
131
|
|
|
132
|
+
function processCallback(upgrade: BooleanFlag) {
|
|
133
|
+
if (callbacks.length > 0) {
|
|
134
|
+
callbacks.forEach(x => {
|
|
135
|
+
if (x.callback && (!x.wait || upgrade)) { x.callback(data, !config.lean); }
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
136
140
|
function supported(target: Window | Document, api: string): boolean {
|
|
137
141
|
try { return !!target[api]; } catch { return false; }
|
|
138
142
|
}
|
package/src/data/metric.ts
CHANGED
|
@@ -15,11 +15,11 @@ export function stop(): void {
|
|
|
15
15
|
updates = {};
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export function count(metric: Metric
|
|
18
|
+
export function count(metric: Metric): void {
|
|
19
19
|
if (!(metric in data)) { data[metric] = 0; }
|
|
20
20
|
if (!(metric in updates)) { updates[metric] = 0; }
|
|
21
|
-
data[metric]
|
|
22
|
-
updates[metric]
|
|
21
|
+
data[metric]++;
|
|
22
|
+
updates[metric]++;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export function sum(metric: Metric, value: number): void {
|
package/src/diagnostic/encode.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Event, Token } from "@clarity-types/data";
|
|
2
2
|
import { time } from "@src/core/time";
|
|
3
3
|
import { queue } from "@src/data/upload";
|
|
4
|
+
import * as fraud from "@src/diagnostic/fraud";
|
|
4
5
|
import * as internal from "@src/diagnostic/internal";
|
|
5
6
|
import * as script from "@src/diagnostic/script";
|
|
6
7
|
|
|
@@ -26,5 +27,13 @@ export default async function (type: Event): Promise<void> {
|
|
|
26
27
|
queue(tokens, false);
|
|
27
28
|
}
|
|
28
29
|
break;
|
|
30
|
+
case Event.Fraud:
|
|
31
|
+
if (fraud.data) {
|
|
32
|
+
tokens.push(fraud.data.id);
|
|
33
|
+
tokens.push(fraud.data.target);
|
|
34
|
+
tokens.push(fraud.data.hash);
|
|
35
|
+
queue(tokens, false);
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
29
38
|
}
|
|
30
39
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BooleanFlag, Event, Metric, Setting } from "@clarity-types/data";
|
|
2
|
+
import { FraudData } from "@clarity-types/diagnostic";
|
|
3
|
+
import hash from "@src/core/hash";
|
|
4
|
+
import * as metric from "@src/data/metric";
|
|
5
|
+
import encode from "./encode";
|
|
6
|
+
|
|
7
|
+
let history = [];
|
|
8
|
+
export let data: FraudData;
|
|
9
|
+
|
|
10
|
+
export function start(): void {
|
|
11
|
+
history = [];
|
|
12
|
+
metric.max(Metric.Automation, navigator.webdriver ? BooleanFlag.True : BooleanFlag.False);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function check(id: number, target: number, input: string): void {
|
|
16
|
+
// Compute hash for fraud detection. Hash is computed only if input meets the minimum length criteria
|
|
17
|
+
if (id !== null && input && input.length >= Setting.WordLength) {
|
|
18
|
+
data = { id, target, hash: hash(input) };
|
|
19
|
+
// Only encode this event if we haven't already reported this hash
|
|
20
|
+
if (history.indexOf(data.hash) < 0) {
|
|
21
|
+
history.push(data.hash);
|
|
22
|
+
encode(Event.Fraud);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function stop(): void {
|
|
28
|
+
history = [];
|
|
29
|
+
}
|
package/src/diagnostic/index.ts
CHANGED
package/src/diagnostic/script.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Event, Setting } from "@clarity-types/data";
|
|
2
2
|
import { ScriptErrorData } from "@clarity-types/diagnostic";
|
|
3
3
|
import { bind } from "@src/core/event";
|
|
4
|
-
import * as box from "@src/layout/box";
|
|
5
4
|
import encode from "./encode";
|
|
6
5
|
|
|
7
6
|
let history: { [key: string]: number } = {};
|
|
@@ -29,15 +28,6 @@ function handler(error: ErrorEvent): boolean {
|
|
|
29
28
|
source: error["filename"]
|
|
30
29
|
};
|
|
31
30
|
|
|
32
|
-
// In certain cases, ResizeObserver could lead to flood of benign errors - especially when video element is involved.
|
|
33
|
-
// Reference Chromium issue: https://bugs.chromium.org/p/chromium/issues/detail?id=809574
|
|
34
|
-
// Even though it doesn't impact user experience, or show up in console, it can still flood error reporting through on error
|
|
35
|
-
// To mitigate that, we turn off Clarity's ResizeObserver on getting the first instance of this error
|
|
36
|
-
if (e.message.indexOf(Constant.ResizeObserver) >= 0) {
|
|
37
|
-
box.stop();
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
31
|
encode(Event.ScriptError);
|
|
42
32
|
}
|
|
43
33
|
|
package/src/interaction/click.ts
CHANGED
|
@@ -65,7 +65,8 @@ function handler(event: Event, root: Node, evt: MouseEvent): void {
|
|
|
65
65
|
context: context(a),
|
|
66
66
|
text: text(t),
|
|
67
67
|
link: a ? a.href : null,
|
|
68
|
-
hash: null
|
|
68
|
+
hash: null,
|
|
69
|
+
trust: evt.isTrusted ? BooleanFlag.True : BooleanFlag.False
|
|
69
70
|
}
|
|
70
71
|
});
|
|
71
72
|
schedule(encode.bind(this, event));
|
|
@@ -44,7 +44,7 @@ export default async function (type: Event): Promise<void> {
|
|
|
44
44
|
break;
|
|
45
45
|
case Event.Click:
|
|
46
46
|
for (let entry of click.state) {
|
|
47
|
-
let cTarget = metadata(entry.data.target as Node, entry.event);
|
|
47
|
+
let cTarget = metadata(entry.data.target as Node, entry.event, entry.data.text);
|
|
48
48
|
tokens = [entry.time, entry.event];
|
|
49
49
|
let cHash = cTarget.hash.join(Constant.Dot);
|
|
50
50
|
tokens.push(cTarget.id);
|
|
@@ -58,6 +58,7 @@ export default async function (type: Event): Promise<void> {
|
|
|
58
58
|
tokens.push(scrub(entry.data.text, "click", cTarget.privacy));
|
|
59
59
|
tokens.push(entry.data.link);
|
|
60
60
|
tokens.push(cHash);
|
|
61
|
+
tokens.push(entry.data.trust);
|
|
61
62
|
queue(tokens);
|
|
62
63
|
timeline.track(entry.time, entry.event, cHash, entry.data.x, entry.data.y, entry.data.reaction, entry.data.context);
|
|
63
64
|
}
|
|
@@ -91,10 +92,10 @@ export default async function (type: Event): Promise<void> {
|
|
|
91
92
|
break;
|
|
92
93
|
case Event.Input:
|
|
93
94
|
for (let entry of input.state) {
|
|
94
|
-
let iTarget = metadata(entry.data.target as Node, entry.event);
|
|
95
|
+
let iTarget = metadata(entry.data.target as Node, entry.event, entry.data.value);
|
|
95
96
|
tokens = [entry.time, entry.event];
|
|
96
97
|
tokens.push(iTarget.id);
|
|
97
|
-
tokens.push(entry.data.value);
|
|
98
|
+
tokens.push(scrub(entry.data.value, "input", iTarget.privacy));
|
|
98
99
|
queue(tokens);
|
|
99
100
|
}
|
|
100
101
|
input.reset();
|
package/src/interaction/input.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Event } from "@clarity-types/data";
|
|
2
2
|
import { InputData, InputState, Setting } from "@clarity-types/interaction";
|
|
3
3
|
import { bind } from "@src/core/event";
|
|
4
|
-
import scrub from "@src/core/scrub";
|
|
5
4
|
import { schedule } from "@src/core/task";
|
|
6
5
|
import { time } from "@src/core/time";
|
|
7
6
|
import { clearTimeout, setTimeout } from "@src/core/timeout";
|
|
@@ -24,18 +23,12 @@ function recompute(evt: UIEvent): void {
|
|
|
24
23
|
let input = target(evt) as HTMLInputElement;
|
|
25
24
|
let value = get(input);
|
|
26
25
|
if (input && input.type && value) {
|
|
27
|
-
let v;
|
|
26
|
+
let v = input.value;
|
|
28
27
|
switch (input.type) {
|
|
29
28
|
case "radio":
|
|
30
29
|
case "checkbox":
|
|
31
30
|
v = input.checked ? "true" : "false";
|
|
32
31
|
break;
|
|
33
|
-
case "range":
|
|
34
|
-
v = input.value;
|
|
35
|
-
break;
|
|
36
|
-
default:
|
|
37
|
-
v = scrub(input.value, "input", value.metadata.privacy);
|
|
38
|
-
break;
|
|
39
32
|
}
|
|
40
33
|
|
|
41
34
|
let data: InputData = { target: input, value: v };
|