clarity-js 0.6.23
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/README.md +26 -0
- package/build/clarity.js +4479 -0
- package/build/clarity.min.js +1 -0
- package/build/clarity.module.js +4473 -0
- package/package.json +66 -0
- package/rollup.config.ts +38 -0
- package/src/clarity.ts +54 -0
- package/src/core/config.ts +21 -0
- package/src/core/copy.ts +3 -0
- package/src/core/event.ts +25 -0
- package/src/core/hash.ts +19 -0
- package/src/core/history.ts +69 -0
- package/src/core/index.ts +79 -0
- package/src/core/measure.ts +17 -0
- package/src/core/report.ts +27 -0
- package/src/core/scrub.ts +102 -0
- package/src/core/task.ts +180 -0
- package/src/core/time.ts +14 -0
- package/src/core/timeout.ts +10 -0
- package/src/core/version.ts +2 -0
- package/src/data/baseline.ts +89 -0
- package/src/data/compress.ts +31 -0
- package/src/data/custom.ts +18 -0
- package/src/data/dimension.ts +42 -0
- package/src/data/encode.ts +109 -0
- package/src/data/envelope.ts +46 -0
- package/src/data/index.ts +43 -0
- package/src/data/limit.ts +42 -0
- package/src/data/metadata.ts +232 -0
- package/src/data/metric.ts +51 -0
- package/src/data/ping.ts +36 -0
- package/src/data/summary.ts +34 -0
- package/src/data/token.ts +39 -0
- package/src/data/upgrade.ts +36 -0
- package/src/data/upload.ts +250 -0
- package/src/data/variable.ts +46 -0
- package/src/diagnostic/encode.ts +40 -0
- package/src/diagnostic/image.ts +23 -0
- package/src/diagnostic/index.ts +14 -0
- package/src/diagnostic/internal.ts +41 -0
- package/src/diagnostic/script.ts +45 -0
- package/src/global.ts +22 -0
- package/src/index.ts +8 -0
- package/src/interaction/click.ts +140 -0
- package/src/interaction/encode.ts +140 -0
- package/src/interaction/index.ts +45 -0
- package/src/interaction/input.ts +64 -0
- package/src/interaction/pointer.ts +108 -0
- package/src/interaction/resize.ts +30 -0
- package/src/interaction/scroll.ts +73 -0
- package/src/interaction/selection.ts +66 -0
- package/src/interaction/timeline.ts +65 -0
- package/src/interaction/unload.ts +25 -0
- package/src/interaction/visibility.ts +24 -0
- package/src/layout/box.ts +83 -0
- package/src/layout/discover.ts +27 -0
- package/src/layout/document.ts +46 -0
- package/src/layout/dom.ts +442 -0
- package/src/layout/encode.ts +111 -0
- package/src/layout/extract.ts +75 -0
- package/src/layout/index.ts +25 -0
- package/src/layout/mutation.ts +232 -0
- package/src/layout/node.ts +211 -0
- package/src/layout/offset.ts +19 -0
- package/src/layout/region.ts +143 -0
- package/src/layout/schema.ts +66 -0
- package/src/layout/selector.ts +24 -0
- package/src/layout/target.ts +44 -0
- package/src/layout/traverse.ts +28 -0
- package/src/performance/connection.ts +37 -0
- package/src/performance/encode.ts +40 -0
- package/src/performance/index.ts +15 -0
- package/src/performance/navigation.ts +31 -0
- package/src/performance/observer.ts +87 -0
- package/test/core.test.ts +82 -0
- package/test/helper.ts +104 -0
- package/test/html/core.html +17 -0
- package/test/tsconfig.test.json +6 -0
- package/tsconfig.json +21 -0
- package/tslint.json +33 -0
- package/types/core.d.ts +127 -0
- package/types/data.d.ts +344 -0
- package/types/diagnostic.d.ts +24 -0
- package/types/index.d.ts +30 -0
- package/types/interaction.d.ts +110 -0
- package/types/layout.d.ts +200 -0
- package/types/performance.d.ts +40 -0
package/build/clarity.js
ADDED
|
@@ -0,0 +1,4479 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var upload$1 = /*#__PURE__*/Object.freeze({
|
|
6
|
+
__proto__: null,
|
|
7
|
+
get track () { return track; },
|
|
8
|
+
get start () { return start$a; },
|
|
9
|
+
get queue () { return queue; },
|
|
10
|
+
get stop () { return stop$9; }
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
var config$1 = {
|
|
14
|
+
projectId: null,
|
|
15
|
+
delay: 1 * 1000 /* Second */,
|
|
16
|
+
cssRules: false,
|
|
17
|
+
lean: false,
|
|
18
|
+
track: true,
|
|
19
|
+
content: true,
|
|
20
|
+
mask: [],
|
|
21
|
+
unmask: [],
|
|
22
|
+
regions: [],
|
|
23
|
+
metrics: [],
|
|
24
|
+
cookies: [],
|
|
25
|
+
report: null,
|
|
26
|
+
upload: null,
|
|
27
|
+
fallback: null,
|
|
28
|
+
upgrade: null
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
var startTime = 0;
|
|
32
|
+
function start$E() {
|
|
33
|
+
startTime = performance.now();
|
|
34
|
+
}
|
|
35
|
+
function time(ts) {
|
|
36
|
+
if (ts === void 0) { ts = null; }
|
|
37
|
+
ts = ts ? ts : performance.now();
|
|
38
|
+
return Math.max(Math.round(ts - startTime), 0);
|
|
39
|
+
}
|
|
40
|
+
function stop$B() {
|
|
41
|
+
startTime = 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var state$7 = null;
|
|
45
|
+
var buffer = null;
|
|
46
|
+
var update$1 = false;
|
|
47
|
+
function start$D() {
|
|
48
|
+
update$1 = false;
|
|
49
|
+
reset$n();
|
|
50
|
+
}
|
|
51
|
+
function reset$n() {
|
|
52
|
+
// Baseline state holds the previous values - if it is updated in the current payload,
|
|
53
|
+
// reset the state to current value after sending the previous state
|
|
54
|
+
if (update$1) {
|
|
55
|
+
state$7 = { time: time(), event: 4 /* Baseline */, data: {
|
|
56
|
+
visible: buffer.visible,
|
|
57
|
+
docWidth: buffer.docWidth,
|
|
58
|
+
docHeight: buffer.docHeight,
|
|
59
|
+
screenWidth: buffer.screenWidth,
|
|
60
|
+
screenHeight: buffer.screenHeight,
|
|
61
|
+
scrollX: buffer.scrollX,
|
|
62
|
+
scrollY: buffer.scrollY,
|
|
63
|
+
pointerX: buffer.pointerX,
|
|
64
|
+
pointerY: buffer.pointerY,
|
|
65
|
+
activityTime: buffer.activityTime
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
buffer = buffer ? buffer : {
|
|
70
|
+
visible: 1 /* True */,
|
|
71
|
+
docWidth: 0,
|
|
72
|
+
docHeight: 0,
|
|
73
|
+
screenWidth: 0,
|
|
74
|
+
screenHeight: 0,
|
|
75
|
+
scrollX: 0,
|
|
76
|
+
scrollY: 0,
|
|
77
|
+
pointerX: 0,
|
|
78
|
+
pointerY: 0,
|
|
79
|
+
activityTime: 0
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function track$7(event, x, y) {
|
|
83
|
+
switch (event) {
|
|
84
|
+
case 8 /* Document */:
|
|
85
|
+
buffer.docWidth = x;
|
|
86
|
+
buffer.docHeight = y;
|
|
87
|
+
break;
|
|
88
|
+
case 11 /* Resize */:
|
|
89
|
+
buffer.screenWidth = x;
|
|
90
|
+
buffer.screenHeight = y;
|
|
91
|
+
break;
|
|
92
|
+
case 10 /* Scroll */:
|
|
93
|
+
buffer.scrollX = x;
|
|
94
|
+
buffer.scrollY = y;
|
|
95
|
+
break;
|
|
96
|
+
default:
|
|
97
|
+
buffer.pointerX = x;
|
|
98
|
+
buffer.pointerY = y;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
update$1 = true;
|
|
102
|
+
}
|
|
103
|
+
function activity(t) {
|
|
104
|
+
buffer.activityTime = t;
|
|
105
|
+
}
|
|
106
|
+
function visibility(t, visible) {
|
|
107
|
+
buffer.visible = visible === "visible" ? 1 /* True */ : 0 /* False */;
|
|
108
|
+
if (!buffer.visible) {
|
|
109
|
+
activity(t);
|
|
110
|
+
}
|
|
111
|
+
update$1 = true;
|
|
112
|
+
}
|
|
113
|
+
function compute$c() {
|
|
114
|
+
if (update$1) {
|
|
115
|
+
encode$1(4 /* Baseline */);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function stop$A() {
|
|
119
|
+
reset$n();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
var baseline = /*#__PURE__*/Object.freeze({
|
|
123
|
+
__proto__: null,
|
|
124
|
+
get state () { return state$7; },
|
|
125
|
+
start: start$D,
|
|
126
|
+
reset: reset$n,
|
|
127
|
+
track: track$7,
|
|
128
|
+
activity: activity,
|
|
129
|
+
visibility: visibility,
|
|
130
|
+
compute: compute$c,
|
|
131
|
+
stop: stop$A
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
var data$k = null;
|
|
135
|
+
function event(key, value) {
|
|
136
|
+
if (active() &&
|
|
137
|
+
key &&
|
|
138
|
+
value &&
|
|
139
|
+
typeof key === "string" /* String */ &&
|
|
140
|
+
typeof value === "string" /* String */ &&
|
|
141
|
+
key.length < 255 &&
|
|
142
|
+
value.length < 255) {
|
|
143
|
+
data$k = { key: key, value: value };
|
|
144
|
+
encode$1(24 /* Custom */);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// tslint:disable: no-bitwise
|
|
149
|
+
function hash (input) {
|
|
150
|
+
// Code inspired from C# GetHashCode: https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/string.cs
|
|
151
|
+
var hash = 0;
|
|
152
|
+
var hashOne = 5381;
|
|
153
|
+
var hashTwo = hashOne;
|
|
154
|
+
for (var i = 0; i < input.length; i += 2) {
|
|
155
|
+
var charOne = input.charCodeAt(i);
|
|
156
|
+
hashOne = ((hashOne << 5) + hashOne) ^ charOne;
|
|
157
|
+
if (i + 1 < input.length) {
|
|
158
|
+
var charTwo = input.charCodeAt(i + 1);
|
|
159
|
+
hashTwo = ((hashTwo << 5) + hashTwo) ^ charTwo;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Replace the magic number from C# implementation (1566083941) with a smaller prime number (11579)
|
|
163
|
+
// This ensures we don't hit integer overflow and prevent collisions
|
|
164
|
+
hash = Math.abs(hashOne + (hashTwo * 11579));
|
|
165
|
+
return hash.toString(36);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
var data$j = null;
|
|
169
|
+
function start$C() {
|
|
170
|
+
reset$m();
|
|
171
|
+
}
|
|
172
|
+
function set(variable, value) {
|
|
173
|
+
var values = typeof value === "string" /* String */ ? [value] : value;
|
|
174
|
+
log$2(variable, values);
|
|
175
|
+
}
|
|
176
|
+
function identify(userId, sessionId, pageId) {
|
|
177
|
+
if (sessionId === void 0) { sessionId = null; }
|
|
178
|
+
if (pageId === void 0) { pageId = null; }
|
|
179
|
+
log$2("userId" /* UserId */, [userId]);
|
|
180
|
+
log$2("sessionId" /* SessionId */, [sessionId]);
|
|
181
|
+
log$2("pageId" /* PageId */, [pageId]);
|
|
182
|
+
}
|
|
183
|
+
function log$2(variable, value) {
|
|
184
|
+
if (active() &&
|
|
185
|
+
variable &&
|
|
186
|
+
value &&
|
|
187
|
+
typeof variable === "string" /* String */ &&
|
|
188
|
+
variable.length < 255) {
|
|
189
|
+
var validValues = variable in data$j ? data$j[variable] : [];
|
|
190
|
+
for (var i = 0; i < value.length; i++) {
|
|
191
|
+
if (typeof value[i] === "string" /* String */ && value[i].length < 255) {
|
|
192
|
+
validValues.push(value[i]);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
data$j[variable] = validValues;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function compute$b() {
|
|
199
|
+
encode$1(34 /* Variable */);
|
|
200
|
+
}
|
|
201
|
+
function reset$m() {
|
|
202
|
+
data$j = {};
|
|
203
|
+
}
|
|
204
|
+
function stop$z() {
|
|
205
|
+
reset$m();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
var variable = /*#__PURE__*/Object.freeze({
|
|
209
|
+
__proto__: null,
|
|
210
|
+
get data () { return data$j; },
|
|
211
|
+
start: start$C,
|
|
212
|
+
set: set,
|
|
213
|
+
identify: identify,
|
|
214
|
+
compute: compute$b,
|
|
215
|
+
reset: reset$m,
|
|
216
|
+
stop: stop$z
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
var data$i = null;
|
|
220
|
+
var callback = null;
|
|
221
|
+
var rootDomain = null;
|
|
222
|
+
function start$B() {
|
|
223
|
+
callback = null;
|
|
224
|
+
rootDomain = null;
|
|
225
|
+
var ua = navigator && "userAgent" in navigator ? navigator.userAgent : "" /* Empty */;
|
|
226
|
+
var title = document && document.title ? document.title : "" /* Empty */;
|
|
227
|
+
// Populate ids for this page
|
|
228
|
+
var s = session();
|
|
229
|
+
var u = user();
|
|
230
|
+
data$i = {
|
|
231
|
+
projectId: config$1.projectId || hash(location.host),
|
|
232
|
+
userId: u.id,
|
|
233
|
+
sessionId: s.session,
|
|
234
|
+
pageNum: s.count
|
|
235
|
+
};
|
|
236
|
+
// Override configuration based on what's in the session storage
|
|
237
|
+
config$1.lean = config$1.track && s.upgrade !== null ? s.upgrade === 0 /* False */ : config$1.lean;
|
|
238
|
+
config$1.upload = config$1.track && typeof config$1.upload === "string" /* String */ && s.upload ? s.upload : config$1.upload;
|
|
239
|
+
// Log dimensions
|
|
240
|
+
log$1(0 /* UserAgent */, ua);
|
|
241
|
+
log$1(3 /* PageTitle */, title);
|
|
242
|
+
log$1(1 /* Url */, location.href);
|
|
243
|
+
log$1(2 /* Referrer */, document.referrer);
|
|
244
|
+
log$1(15 /* TabId */, tab());
|
|
245
|
+
log$1(16 /* PageLanguage */, document.documentElement.lang);
|
|
246
|
+
log$1(17 /* DocumentDirection */, document.dir);
|
|
247
|
+
if (navigator) {
|
|
248
|
+
log$1(9 /* Language */, navigator.userLanguage || navigator.language);
|
|
249
|
+
}
|
|
250
|
+
// Metrics
|
|
251
|
+
max(0 /* ClientTimestamp */, s.ts);
|
|
252
|
+
max(1 /* Playback */, 0 /* False */);
|
|
253
|
+
if (screen) {
|
|
254
|
+
max(14 /* ScreenWidth */, Math.round(screen.width));
|
|
255
|
+
max(15 /* ScreenHeight */, Math.round(screen.height));
|
|
256
|
+
max(16 /* ColorDepth */, Math.round(screen.colorDepth));
|
|
257
|
+
}
|
|
258
|
+
// Read cookies specified in configuration
|
|
259
|
+
for (var _i = 0, _a = config$1.cookies; _i < _a.length; _i++) {
|
|
260
|
+
var key = _a[_i];
|
|
261
|
+
var value = getCookie(key);
|
|
262
|
+
if (value) {
|
|
263
|
+
set(key, value);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Track ids using a cookie if configuration allows it
|
|
267
|
+
track$6(u);
|
|
268
|
+
}
|
|
269
|
+
function stop$y() {
|
|
270
|
+
callback = null;
|
|
271
|
+
rootDomain = null;
|
|
272
|
+
}
|
|
273
|
+
function metadata$2(cb) {
|
|
274
|
+
callback = cb;
|
|
275
|
+
}
|
|
276
|
+
function id() {
|
|
277
|
+
return data$i ? [data$i.userId, data$i.sessionId, data$i.pageNum].join("." /* Dot */) : "" /* Empty */;
|
|
278
|
+
}
|
|
279
|
+
function consent() {
|
|
280
|
+
if (active()) {
|
|
281
|
+
config$1.track = true;
|
|
282
|
+
track$6(user(), 1 /* True */);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function clear() {
|
|
286
|
+
// Clear any stored information in the cookie that tracks session information so we can restart fresh the next time
|
|
287
|
+
setCookie("_clsk" /* SessionKey */, "" /* Empty */, 0);
|
|
288
|
+
}
|
|
289
|
+
function tab() {
|
|
290
|
+
var id = shortid();
|
|
291
|
+
if (config$1.track && supported$1(window, "sessionStorage" /* SessionStorage */)) {
|
|
292
|
+
var value = sessionStorage.getItem("_cltk" /* TabKey */);
|
|
293
|
+
id = value ? value : id;
|
|
294
|
+
sessionStorage.setItem("_cltk" /* TabKey */, id);
|
|
295
|
+
}
|
|
296
|
+
return id;
|
|
297
|
+
}
|
|
298
|
+
function save() {
|
|
299
|
+
var ts = Math.round(Date.now());
|
|
300
|
+
var upgrade = config$1.lean ? 0 /* False */ : 1 /* True */;
|
|
301
|
+
var upload = config$1.upload && typeof config$1.upload === "string" /* String */ ? config$1.upload.replace("https://" /* HTTPS */, "" /* Empty */) : "" /* Empty */;
|
|
302
|
+
if (upgrade && callback) {
|
|
303
|
+
callback(data$i, !config$1.lean);
|
|
304
|
+
}
|
|
305
|
+
setCookie("_clsk" /* SessionKey */, [data$i.sessionId, ts, data$i.pageNum, upgrade, upload].join("|" /* Pipe */), 1 /* SessionExpire */);
|
|
306
|
+
}
|
|
307
|
+
function supported$1(target, api) {
|
|
308
|
+
try {
|
|
309
|
+
return !!target[api];
|
|
310
|
+
}
|
|
311
|
+
catch (_a) {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function track$6(u, consent) {
|
|
316
|
+
if (consent === void 0) { consent = null; }
|
|
317
|
+
// If consent is not explicitly specified, infer it from the user object
|
|
318
|
+
consent = consent === null ? u.consent : consent;
|
|
319
|
+
// Convert time precision into days to reduce number of bytes we have to write in a cookie
|
|
320
|
+
// E.g. Math.ceil(1628735962643 / (24*60*60*1000)) => 18852 (days) => ejo in base36 (13 bytes => 3 bytes)
|
|
321
|
+
var end = Math.ceil((Date.now() + (365 /* Expire */ * 86400000 /* Day */)) / 86400000 /* Day */);
|
|
322
|
+
// To avoid cookie churn, write user id cookie only once every day
|
|
323
|
+
if (u.expiry === null || Math.abs(end - u.expiry) >= 1 /* CookieInterval */ || u.consent !== consent) {
|
|
324
|
+
setCookie("_clck" /* CookieKey */, [data$i.userId, 1 /* CookieVersion */, end.toString(36), consent].join("|" /* Pipe */), 365 /* Expire */);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function shortid() {
|
|
328
|
+
var id = Math.floor(Math.random() * Math.pow(2, 32));
|
|
329
|
+
if (window && window.crypto && window.crypto.getRandomValues && Uint32Array) {
|
|
330
|
+
id = window.crypto.getRandomValues(new Uint32Array(1))[0];
|
|
331
|
+
}
|
|
332
|
+
return id.toString(36);
|
|
333
|
+
}
|
|
334
|
+
function session() {
|
|
335
|
+
var output = { session: shortid(), ts: Math.round(Date.now()), count: 1, upgrade: null, upload: "" /* Empty */ };
|
|
336
|
+
var value = getCookie("_clsk" /* SessionKey */);
|
|
337
|
+
if (value) {
|
|
338
|
+
var parts = value.split("|" /* Pipe */);
|
|
339
|
+
// Making it backward & forward compatible by using greater than comparison (v0.6.21)
|
|
340
|
+
// In future version, we can reduce the parts length to be 5 where the last part contains the full upload URL
|
|
341
|
+
if (parts.length >= 5 && output.ts - num$2(parts[1]) < 1800000 /* SessionTimeout */) {
|
|
342
|
+
output.session = parts[0];
|
|
343
|
+
output.count = num$2(parts[2]) + 1;
|
|
344
|
+
output.upgrade = num$2(parts[3]);
|
|
345
|
+
output.upload = parts.length >= 6 ? "" + "https://" /* HTTPS */ + parts[5] + "/" + parts[4] : "" + "https://" /* HTTPS */ + parts[4];
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return output;
|
|
349
|
+
}
|
|
350
|
+
function num$2(string, base) {
|
|
351
|
+
if (base === void 0) { base = 10; }
|
|
352
|
+
return parseInt(string, base);
|
|
353
|
+
}
|
|
354
|
+
function user() {
|
|
355
|
+
var output = { id: shortid(), expiry: null, consent: 0 /* False */ };
|
|
356
|
+
var cookie = getCookie("_clck" /* CookieKey */);
|
|
357
|
+
if (cookie && cookie.length > 0) {
|
|
358
|
+
// Splitting and looking up first part for forward compatibility, in case we wish to store additional information in a cookie
|
|
359
|
+
var parts = cookie.split("|" /* Pipe */);
|
|
360
|
+
// For backward compatibility introduced in v0.6.18; following code can be removed with future iterations
|
|
361
|
+
// Count number of times Clarity's user cookie crumb appears in document.cookie (could be on different sub-domains e.g. www.domain.com and .domain.com)
|
|
362
|
+
var count = 0;
|
|
363
|
+
for (var _i = 0, _a = document.cookie.split(";" /* Semicolon */); _i < _a.length; _i++) {
|
|
364
|
+
var c = _a[_i];
|
|
365
|
+
count += c.split("=" /* Equals */)[0].trim() === "_clck" /* CookieKey */ ? 1 : 0;
|
|
366
|
+
}
|
|
367
|
+
// Check if we either got version-less cookie value or saw multiple copies of the user cookie crumbs
|
|
368
|
+
// In both these cases, we go ahead and delete the existing cookie set on current domain
|
|
369
|
+
if (parts.length === 1 || count > 1) {
|
|
370
|
+
var deleted = "" + ";" /* Semicolon */ + "expires=" /* Expires */ + (new Date(0)).toUTCString() + ";path=/" /* Path */;
|
|
371
|
+
// First, delete current user cookie which might be set on current sub-domain vs. root domain
|
|
372
|
+
document.cookie = "_clck" /* CookieKey */ + "=" + deleted;
|
|
373
|
+
// Second, same thing for current session cookie so it can be re-written later with the root domain
|
|
374
|
+
document.cookie = "_clsk" /* SessionKey */ + "=" + deleted;
|
|
375
|
+
}
|
|
376
|
+
// End code for backward compatibility
|
|
377
|
+
// Read version information and timestamp from cookie, if available
|
|
378
|
+
if (parts.length > 2) {
|
|
379
|
+
output.expiry = num$2(parts[2], 36);
|
|
380
|
+
}
|
|
381
|
+
// Check if we have explicit consent to track this user
|
|
382
|
+
if (parts.length > 3 && num$2(parts[3]) === 1) {
|
|
383
|
+
output.consent = 1 /* True */;
|
|
384
|
+
}
|
|
385
|
+
// Set track configuration to true for this user if we have explicit consent, regardless of project setting
|
|
386
|
+
config$1.track = config$1.track || output.consent === 1 /* True */;
|
|
387
|
+
// Get user id from cookie only if we tracking is enabled, otherwise fallback to a random id
|
|
388
|
+
output.id = config$1.track ? parts[0] : output.id;
|
|
389
|
+
}
|
|
390
|
+
return output;
|
|
391
|
+
}
|
|
392
|
+
function getCookie(key) {
|
|
393
|
+
if (supported$1(document, "cookie" /* Cookie */)) {
|
|
394
|
+
var cookies = document.cookie.split(";" /* Semicolon */);
|
|
395
|
+
if (cookies) {
|
|
396
|
+
for (var i = 0; i < cookies.length; i++) {
|
|
397
|
+
var pair = cookies[i].split("=" /* Equals */);
|
|
398
|
+
if (pair.length > 1 && pair[0] && pair[0].trim() === key) {
|
|
399
|
+
return pair[1];
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
function setCookie(key, value, time) {
|
|
407
|
+
if (config$1.track && ((navigator && navigator.cookieEnabled) || supported$1(document, "cookie" /* Cookie */))) {
|
|
408
|
+
var expiry = new Date();
|
|
409
|
+
expiry.setDate(expiry.getDate() + time);
|
|
410
|
+
var expires = expiry ? "expires=" /* Expires */ + expiry.toUTCString() : "" /* Empty */;
|
|
411
|
+
var cookie = key + "=" + value + ";" /* Semicolon */ + expires + ";path=/" /* Path */;
|
|
412
|
+
try {
|
|
413
|
+
// Attempt to get the root domain only once and fall back to writing cookie on the current domain.
|
|
414
|
+
if (rootDomain === null) {
|
|
415
|
+
var hostname = location.hostname ? location.hostname.split("." /* Dot */) : [];
|
|
416
|
+
// Walk backwards on a domain and attempt to set a cookie, until successful
|
|
417
|
+
for (var i = hostname.length - 1; i >= 0; i--) {
|
|
418
|
+
rootDomain = "." + hostname[i] + (rootDomain ? rootDomain : "" /* Empty */);
|
|
419
|
+
// We do not wish to attempt writing a cookie on the absolute last part of the domain, e.g. .com or .net.
|
|
420
|
+
// So we start attempting after second-last part, e.g. .domain.com (PASS) or .co.uk (FAIL)
|
|
421
|
+
if (i < hostname.length - 1) {
|
|
422
|
+
// Write the cookie on the current computed top level domain
|
|
423
|
+
document.cookie = "" + cookie + ";" /* Semicolon */ + "domain=" /* Domain */ + rootDomain;
|
|
424
|
+
// Once written, check if the cookie exists and its value matches exactly with what we intended to set
|
|
425
|
+
// Checking for exact value match helps us eliminate a corner case where the cookie may already be present with a different value
|
|
426
|
+
// If the check is successful, no more action is required and we can return from the function since rootDomain cookie is already set
|
|
427
|
+
// If the check fails, continue with the for loop until we can successfully set and verify the cookie
|
|
428
|
+
if (getCookie(key) === value) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
// Finally, if we were not successful and gone through all the options, play it safe and reset rootDomain to be empty
|
|
434
|
+
// This forces our code to fall back to always writing cookie to the current domain
|
|
435
|
+
rootDomain = "" /* Empty */;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
catch (_a) {
|
|
439
|
+
rootDomain = "" /* Empty */;
|
|
440
|
+
}
|
|
441
|
+
document.cookie = rootDomain ? "" + cookie + ";" /* Semicolon */ + "domain=" /* Domain */ + rootDomain : cookie;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
var metadata$3 = /*#__PURE__*/Object.freeze({
|
|
446
|
+
__proto__: null,
|
|
447
|
+
get data () { return data$i; },
|
|
448
|
+
get callback () { return callback; },
|
|
449
|
+
start: start$B,
|
|
450
|
+
stop: stop$y,
|
|
451
|
+
metadata: metadata$2,
|
|
452
|
+
id: id,
|
|
453
|
+
consent: consent,
|
|
454
|
+
clear: clear,
|
|
455
|
+
save: save
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
var history$5;
|
|
459
|
+
function reset$l() {
|
|
460
|
+
history$5 = [];
|
|
461
|
+
}
|
|
462
|
+
function report(check, message) {
|
|
463
|
+
if (message === void 0) { message = null; }
|
|
464
|
+
// Do not report the same message twice for the same page
|
|
465
|
+
if (history$5 && history$5.indexOf(message) === -1) {
|
|
466
|
+
var url = config$1.report;
|
|
467
|
+
if (url && url.length > 0) {
|
|
468
|
+
var payload = { c: check, p: data$i.projectId, u: data$i.userId, s: data$i.sessionId, n: data$i.pageNum };
|
|
469
|
+
if (message)
|
|
470
|
+
payload.m = message;
|
|
471
|
+
// Using POST request instead of a GET request (img-src) to not violate existing CSP rules
|
|
472
|
+
// Since, Clarity already uses XHR to upload data, we stick with similar POST mechanism for reporting too
|
|
473
|
+
var xhr = new XMLHttpRequest();
|
|
474
|
+
xhr.open("POST", url);
|
|
475
|
+
xhr.send(JSON.stringify(payload));
|
|
476
|
+
history$5.push(message);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
var version$1 = "0.6.23";
|
|
482
|
+
|
|
483
|
+
var data$h = null;
|
|
484
|
+
function start$A() {
|
|
485
|
+
var m = data$i;
|
|
486
|
+
data$h = {
|
|
487
|
+
version: version$1,
|
|
488
|
+
sequence: 0,
|
|
489
|
+
start: 0,
|
|
490
|
+
duration: 0,
|
|
491
|
+
projectId: m.projectId,
|
|
492
|
+
userId: m.userId,
|
|
493
|
+
sessionId: m.sessionId,
|
|
494
|
+
pageNum: m.pageNum,
|
|
495
|
+
upload: 0 /* Async */,
|
|
496
|
+
end: 0 /* False */
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
function stop$x() {
|
|
500
|
+
data$h = null;
|
|
501
|
+
}
|
|
502
|
+
function envelope(last) {
|
|
503
|
+
data$h.start = data$h.start + data$h.duration;
|
|
504
|
+
data$h.duration = time() - data$h.start;
|
|
505
|
+
data$h.sequence++;
|
|
506
|
+
data$h.upload = last && "sendBeacon" in navigator ? 1 /* Beacon */ : 0 /* Async */;
|
|
507
|
+
data$h.end = last ? 1 /* True */ : 0 /* False */;
|
|
508
|
+
return [
|
|
509
|
+
data$h.version,
|
|
510
|
+
data$h.sequence,
|
|
511
|
+
data$h.start,
|
|
512
|
+
data$h.duration,
|
|
513
|
+
data$h.projectId,
|
|
514
|
+
data$h.userId,
|
|
515
|
+
data$h.sessionId,
|
|
516
|
+
data$h.pageNum,
|
|
517
|
+
data$h.upload,
|
|
518
|
+
data$h.end
|
|
519
|
+
];
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
var envelope$1 = /*#__PURE__*/Object.freeze({
|
|
523
|
+
__proto__: null,
|
|
524
|
+
get data () { return data$h; },
|
|
525
|
+
start: start$A,
|
|
526
|
+
stop: stop$x,
|
|
527
|
+
envelope: envelope
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
var data$g;
|
|
531
|
+
function start$z() {
|
|
532
|
+
data$g = { check: 0 /* None */ };
|
|
533
|
+
}
|
|
534
|
+
function check$3(bytes) {
|
|
535
|
+
if (data$g.check === 0 /* None */) {
|
|
536
|
+
var reason = data$g.check;
|
|
537
|
+
reason = data$h.sequence >= 128 /* PayloadLimit */ ? 1 /* Payload */ : reason;
|
|
538
|
+
reason = time() > 7200000 /* ShutdownLimit */ ? 2 /* Shutdown */ : reason;
|
|
539
|
+
reason = bytes > 10485760 /* PlaybackBytesLimit */ ? 2 /* Shutdown */ : reason;
|
|
540
|
+
if (reason !== data$g.check) {
|
|
541
|
+
trigger$1(reason);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
function trigger$1(reason) {
|
|
546
|
+
report(reason);
|
|
547
|
+
data$g.check = reason;
|
|
548
|
+
clear();
|
|
549
|
+
stop();
|
|
550
|
+
}
|
|
551
|
+
function compute$a() {
|
|
552
|
+
if (data$g.check !== 0 /* None */) {
|
|
553
|
+
encode$1(35 /* Limit */);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
function stop$w() {
|
|
557
|
+
data$g = null;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
var limit = /*#__PURE__*/Object.freeze({
|
|
561
|
+
__proto__: null,
|
|
562
|
+
get data () { return data$g; },
|
|
563
|
+
start: start$z,
|
|
564
|
+
check: check$3,
|
|
565
|
+
trigger: trigger$1,
|
|
566
|
+
compute: compute$a,
|
|
567
|
+
stop: stop$w
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
var data$f = null;
|
|
571
|
+
var updates$3 = null;
|
|
572
|
+
function start$y() {
|
|
573
|
+
data$f = {};
|
|
574
|
+
updates$3 = {};
|
|
575
|
+
}
|
|
576
|
+
function stop$v() {
|
|
577
|
+
data$f = {};
|
|
578
|
+
updates$3 = {};
|
|
579
|
+
}
|
|
580
|
+
function log$1(dimension, value) {
|
|
581
|
+
// Check valid value before moving ahead
|
|
582
|
+
if (value) {
|
|
583
|
+
// Ensure received value is casted into a string if it wasn't a string to begin with
|
|
584
|
+
value = "" + value;
|
|
585
|
+
if (!(dimension in data$f)) {
|
|
586
|
+
data$f[dimension] = [];
|
|
587
|
+
}
|
|
588
|
+
if (data$f[dimension].indexOf(value) < 0) {
|
|
589
|
+
data$f[dimension].push(value);
|
|
590
|
+
// If this is a new value, track it as part of updates object
|
|
591
|
+
// This allows us to only send back new values in subsequent payloads
|
|
592
|
+
if (!(dimension in updates$3)) {
|
|
593
|
+
updates$3[dimension] = [];
|
|
594
|
+
}
|
|
595
|
+
updates$3[dimension].push(value);
|
|
596
|
+
// Limit check to ensure we have a cap on number of dimensions we can collect
|
|
597
|
+
if (data$f[dimension].length > 128 /* CollectionLimit */) {
|
|
598
|
+
trigger$1(5 /* Collection */);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function compute$9() {
|
|
604
|
+
encode$1(1 /* Dimension */);
|
|
605
|
+
}
|
|
606
|
+
function reset$k() {
|
|
607
|
+
updates$3 = {};
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
var dimension = /*#__PURE__*/Object.freeze({
|
|
611
|
+
__proto__: null,
|
|
612
|
+
get data () { return data$f; },
|
|
613
|
+
get updates () { return updates$3; },
|
|
614
|
+
start: start$y,
|
|
615
|
+
stop: stop$v,
|
|
616
|
+
log: log$1,
|
|
617
|
+
compute: compute$9,
|
|
618
|
+
reset: reset$k
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
function setTimeout(handler, timeout, event) {
|
|
622
|
+
return window.setTimeout(measure(handler), timeout, event);
|
|
623
|
+
}
|
|
624
|
+
function clearTimeout(handle) {
|
|
625
|
+
return window.clearTimeout(handle);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
var data$e;
|
|
629
|
+
var last = 0;
|
|
630
|
+
var interval = 0;
|
|
631
|
+
var timeout$6 = null;
|
|
632
|
+
function start$x() {
|
|
633
|
+
interval = 60000 /* PingInterval */;
|
|
634
|
+
last = 0;
|
|
635
|
+
}
|
|
636
|
+
function reset$j() {
|
|
637
|
+
if (timeout$6) {
|
|
638
|
+
clearTimeout(timeout$6);
|
|
639
|
+
}
|
|
640
|
+
timeout$6 = setTimeout(ping, interval);
|
|
641
|
+
last = time();
|
|
642
|
+
}
|
|
643
|
+
function ping() {
|
|
644
|
+
var now = time();
|
|
645
|
+
data$e = { gap: now - last };
|
|
646
|
+
encode$1(25 /* Ping */);
|
|
647
|
+
if (data$e.gap < 300000 /* PingTimeout */) {
|
|
648
|
+
timeout$6 = setTimeout(ping, interval);
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
suspend();
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
function stop$u() {
|
|
655
|
+
clearTimeout(timeout$6);
|
|
656
|
+
last = 0;
|
|
657
|
+
interval = 0;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
var ping$1 = /*#__PURE__*/Object.freeze({
|
|
661
|
+
__proto__: null,
|
|
662
|
+
get data () { return data$e; },
|
|
663
|
+
start: start$x,
|
|
664
|
+
reset: reset$j,
|
|
665
|
+
stop: stop$u
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
var data$d = null;
|
|
669
|
+
function start$w() {
|
|
670
|
+
data$d = {};
|
|
671
|
+
}
|
|
672
|
+
function stop$t() {
|
|
673
|
+
data$d = {};
|
|
674
|
+
}
|
|
675
|
+
function track$5(event, time) {
|
|
676
|
+
if (!(event in data$d)) {
|
|
677
|
+
data$d[event] = [[time, 0]];
|
|
678
|
+
}
|
|
679
|
+
else {
|
|
680
|
+
var e = data$d[event];
|
|
681
|
+
var last = e[e.length - 1];
|
|
682
|
+
// Add a new entry only if the new event occurs after configured interval
|
|
683
|
+
// Otherwise, extend the duration of the previous entry
|
|
684
|
+
if (time - last[0] > 100 /* SummaryInterval */) {
|
|
685
|
+
data$d[event].push([time, 0]);
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
last[1] = time - last[0];
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
function compute$8() {
|
|
693
|
+
encode$1(36 /* Summary */);
|
|
694
|
+
}
|
|
695
|
+
function reset$i() {
|
|
696
|
+
data$d = {};
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
var summary = /*#__PURE__*/Object.freeze({
|
|
700
|
+
__proto__: null,
|
|
701
|
+
get data () { return data$d; },
|
|
702
|
+
start: start$w,
|
|
703
|
+
stop: stop$t,
|
|
704
|
+
track: track$5,
|
|
705
|
+
compute: compute$8,
|
|
706
|
+
reset: reset$i
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
var data$c = null;
|
|
710
|
+
function start$v() {
|
|
711
|
+
if (!config$1.lean && config$1.upgrade) {
|
|
712
|
+
config$1.upgrade("Config" /* Config */);
|
|
713
|
+
}
|
|
714
|
+
data$c = null;
|
|
715
|
+
}
|
|
716
|
+
// Following call will upgrade the session from lean mode into the full mode retroactively from the start of the page.
|
|
717
|
+
// As part of the lean mode, we do not send back any layout information - including discovery of DOM and mutations.
|
|
718
|
+
// However, if there's a need for full fidelity playback, calling this function will disable lean mode
|
|
719
|
+
// and send all backed up layout events to the server.
|
|
720
|
+
function upgrade(key) {
|
|
721
|
+
// Upgrade only if Clarity was successfully activated on the page
|
|
722
|
+
if (active() && config$1.lean) {
|
|
723
|
+
config$1.lean = false;
|
|
724
|
+
data$c = { key: key };
|
|
725
|
+
// Update metadata to track we have upgraded this session
|
|
726
|
+
save();
|
|
727
|
+
// Callback upgrade handler, if configured
|
|
728
|
+
if (config$1.upgrade) {
|
|
729
|
+
config$1.upgrade(key);
|
|
730
|
+
}
|
|
731
|
+
encode$1(3 /* Upgrade */);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
function stop$s() {
|
|
735
|
+
data$c = null;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
var upgrade$1 = /*#__PURE__*/Object.freeze({
|
|
739
|
+
__proto__: null,
|
|
740
|
+
get data () { return data$c; },
|
|
741
|
+
start: start$v,
|
|
742
|
+
upgrade: upgrade,
|
|
743
|
+
stop: stop$s
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
/*! *****************************************************************************
|
|
747
|
+
Copyright (c) Microsoft Corporation.
|
|
748
|
+
|
|
749
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
750
|
+
purpose with or without fee is hereby granted.
|
|
751
|
+
|
|
752
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
753
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
754
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
755
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
756
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
757
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
758
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
759
|
+
***************************************************************************** */
|
|
760
|
+
|
|
761
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
762
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
763
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
764
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
765
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
766
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
767
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
function __generator(thisArg, body) {
|
|
772
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
773
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
774
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
775
|
+
function step(op) {
|
|
776
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
777
|
+
while (_) try {
|
|
778
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
779
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
780
|
+
switch (op[0]) {
|
|
781
|
+
case 0: case 1: t = op; break;
|
|
782
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
783
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
784
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
785
|
+
default:
|
|
786
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
787
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
788
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
789
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
790
|
+
if (t[2]) _.ops.pop();
|
|
791
|
+
_.trys.pop(); continue;
|
|
792
|
+
}
|
|
793
|
+
op = body.call(thisArg, _);
|
|
794
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
795
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
var supported = "CompressionStream" /* CompressionStream */ in window;
|
|
800
|
+
function compress (input) {
|
|
801
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
802
|
+
var stream, _a;
|
|
803
|
+
return __generator(this, function (_c) {
|
|
804
|
+
switch (_c.label) {
|
|
805
|
+
case 0:
|
|
806
|
+
_c.trys.push([0, 3, , 4]);
|
|
807
|
+
if (!supported) return [3 /*break*/, 2];
|
|
808
|
+
stream = new ReadableStream({ start: function (controller) {
|
|
809
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
810
|
+
return __generator(this, function (_a) {
|
|
811
|
+
controller.enqueue(input);
|
|
812
|
+
controller.close();
|
|
813
|
+
return [2 /*return*/];
|
|
814
|
+
});
|
|
815
|
+
});
|
|
816
|
+
} }).pipeThrough(new TextEncoderStream()).pipeThrough(new window["CompressionStream" /* CompressionStream */]("gzip"));
|
|
817
|
+
_a = Uint8Array.bind;
|
|
818
|
+
return [4 /*yield*/, read(stream)];
|
|
819
|
+
case 1: return [2 /*return*/, new (_a.apply(Uint8Array, [void 0, _c.sent()]))()];
|
|
820
|
+
case 2: return [3 /*break*/, 4];
|
|
821
|
+
case 3:
|
|
822
|
+
_c.sent();
|
|
823
|
+
return [3 /*break*/, 4];
|
|
824
|
+
case 4: return [2 /*return*/, null];
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
function read(stream) {
|
|
830
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
831
|
+
var reader, chunks, done, value;
|
|
832
|
+
var _a;
|
|
833
|
+
return __generator(this, function (_b) {
|
|
834
|
+
switch (_b.label) {
|
|
835
|
+
case 0:
|
|
836
|
+
reader = stream.getReader();
|
|
837
|
+
chunks = [];
|
|
838
|
+
done = false;
|
|
839
|
+
value = [];
|
|
840
|
+
_b.label = 1;
|
|
841
|
+
case 1:
|
|
842
|
+
if (!!done) return [3 /*break*/, 3];
|
|
843
|
+
return [4 /*yield*/, reader.read()];
|
|
844
|
+
case 2:
|
|
845
|
+
(_a = _b.sent(), done = _a.done, value = _a.value);
|
|
846
|
+
if (done) {
|
|
847
|
+
return [2 /*return*/, chunks];
|
|
848
|
+
}
|
|
849
|
+
chunks.push.apply(chunks, value);
|
|
850
|
+
return [3 /*break*/, 1];
|
|
851
|
+
case 3: return [2 /*return*/, chunks];
|
|
852
|
+
}
|
|
853
|
+
});
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
var modules$1 = [baseline, dimension, variable, limit, summary, metadata$3, envelope$1, upload$1, ping$1, upgrade$1];
|
|
858
|
+
function start$u() {
|
|
859
|
+
// Metric needs to be initialized before we can start measuring. so metric is not wrapped in measure
|
|
860
|
+
start$9();
|
|
861
|
+
modules$1.forEach(function (x) { return measure(x.start)(); });
|
|
862
|
+
}
|
|
863
|
+
function stop$r() {
|
|
864
|
+
// Stop modules in the reverse order of their initialization
|
|
865
|
+
// The ordering below should respect inter-module dependency.
|
|
866
|
+
// E.g. if upgrade depends on upload, then upgrade needs to end before upload.
|
|
867
|
+
// Similarly, if upload depends on metadata, upload needs to end before metadata.
|
|
868
|
+
modules$1.slice().reverse().forEach(function (x) { return measure(x.stop)(); });
|
|
869
|
+
stop$8();
|
|
870
|
+
}
|
|
871
|
+
function compute$7() {
|
|
872
|
+
compute$b();
|
|
873
|
+
compute$c();
|
|
874
|
+
compute$9();
|
|
875
|
+
compute$2();
|
|
876
|
+
compute$8();
|
|
877
|
+
compute$a();
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
function scrub (value, hint, privacy, mangle) {
|
|
881
|
+
if (mangle === void 0) { mangle = false; }
|
|
882
|
+
if (value) {
|
|
883
|
+
switch (privacy) {
|
|
884
|
+
case 0 /* None */:
|
|
885
|
+
return value;
|
|
886
|
+
case 1 /* Sensitive */:
|
|
887
|
+
switch (hint) {
|
|
888
|
+
case "*T" /* TextTag */:
|
|
889
|
+
case "value":
|
|
890
|
+
case "placeholder":
|
|
891
|
+
return redact(value);
|
|
892
|
+
case "input":
|
|
893
|
+
return mangleToken(value);
|
|
894
|
+
}
|
|
895
|
+
return value;
|
|
896
|
+
case 2 /* Text */:
|
|
897
|
+
case 3 /* TextImage */:
|
|
898
|
+
switch (hint) {
|
|
899
|
+
case "*T" /* TextTag */:
|
|
900
|
+
return mangle ? mangleText(value) : mask(value);
|
|
901
|
+
case "src":
|
|
902
|
+
case "srcset":
|
|
903
|
+
case "title":
|
|
904
|
+
case "alt":
|
|
905
|
+
return privacy === 3 /* TextImage */ ? "" /* Empty */ : value;
|
|
906
|
+
case "value":
|
|
907
|
+
case "click":
|
|
908
|
+
case "input":
|
|
909
|
+
return mangleToken(value);
|
|
910
|
+
case "placeholder":
|
|
911
|
+
return mask(value);
|
|
912
|
+
}
|
|
913
|
+
break;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
return value;
|
|
917
|
+
}
|
|
918
|
+
function mangleText(value) {
|
|
919
|
+
var trimmed = value.trim();
|
|
920
|
+
if (trimmed.length > 0) {
|
|
921
|
+
var first = trimmed[0];
|
|
922
|
+
var index = value.indexOf(first);
|
|
923
|
+
var prefix = value.substr(0, index);
|
|
924
|
+
var suffix = value.substr(index + trimmed.length);
|
|
925
|
+
return "" + prefix + trimmed.length.toString(36) + suffix;
|
|
926
|
+
}
|
|
927
|
+
return value;
|
|
928
|
+
}
|
|
929
|
+
function mask(value) {
|
|
930
|
+
return value.replace(/\S/gi, "\u2022" /* Mask */);
|
|
931
|
+
}
|
|
932
|
+
function mangleToken(value) {
|
|
933
|
+
var length = ((Math.floor(value.length / 5 /* WordLength */) + 1) * 5 /* WordLength */);
|
|
934
|
+
var output = "" /* Empty */;
|
|
935
|
+
for (var i = 0; i < length; i++) {
|
|
936
|
+
output += i > 0 && i % 5 /* WordLength */ === 0 ? " " /* Space */ : "\u2022" /* Mask */;
|
|
937
|
+
}
|
|
938
|
+
return output;
|
|
939
|
+
}
|
|
940
|
+
function redact(value) {
|
|
941
|
+
var spaceIndex = -1;
|
|
942
|
+
var hasDigit = false;
|
|
943
|
+
var hasEmail = false;
|
|
944
|
+
var hasWhitespace = false;
|
|
945
|
+
var array = null;
|
|
946
|
+
for (var i = 0; i < value.length; i++) {
|
|
947
|
+
var c = value.charCodeAt(i);
|
|
948
|
+
hasDigit = hasDigit || (c >= 48 && c <= 57); // Check for digits in the current word
|
|
949
|
+
hasEmail = hasEmail || c === 64; // Check for @ sign anywhere within the current word
|
|
950
|
+
hasWhitespace = c === 9 || c === 10 || c === 13 || c === 32; // Whitespace character (32: blank space | 9: \t | 10: \n | 13: \r)
|
|
951
|
+
// Process each word as an individual token to redact any sensitive information
|
|
952
|
+
if (i === 0 || i === value.length - 1 || hasWhitespace) {
|
|
953
|
+
// Performance optimization: Lazy load string -> array conversion only when required
|
|
954
|
+
if (hasDigit || hasEmail) {
|
|
955
|
+
if (array === null) {
|
|
956
|
+
array = value.split("" /* Empty */);
|
|
957
|
+
}
|
|
958
|
+
mutate(array, spaceIndex, hasWhitespace ? i : i + 1);
|
|
959
|
+
}
|
|
960
|
+
// Reset digit and email flags after every word boundary, except the beginning of string
|
|
961
|
+
if (hasWhitespace) {
|
|
962
|
+
hasDigit = false;
|
|
963
|
+
hasEmail = false;
|
|
964
|
+
spaceIndex = i;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
return array ? array.join("" /* Empty */) : value;
|
|
969
|
+
}
|
|
970
|
+
function mutate(array, start, end) {
|
|
971
|
+
for (var i = start + 1; i < end; i++) {
|
|
972
|
+
array[i] = "\u2022" /* Mask */;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// Track the start time to be able to compute duration at the end of the task
|
|
977
|
+
var idleTimeout = 5000;
|
|
978
|
+
var tracker = {};
|
|
979
|
+
var queuedTasks = [];
|
|
980
|
+
var activeTask = null;
|
|
981
|
+
var pauseTask = null;
|
|
982
|
+
var resumeResolve = null;
|
|
983
|
+
function pause$1() {
|
|
984
|
+
if (pauseTask === null) {
|
|
985
|
+
pauseTask = new Promise(function (resolve) {
|
|
986
|
+
resumeResolve = resolve;
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
function resume$1() {
|
|
991
|
+
if (pauseTask) {
|
|
992
|
+
resumeResolve();
|
|
993
|
+
pauseTask = null;
|
|
994
|
+
if (activeTask === null) {
|
|
995
|
+
run();
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
function reset$h() {
|
|
1000
|
+
tracker = {};
|
|
1001
|
+
queuedTasks = [];
|
|
1002
|
+
activeTask = null;
|
|
1003
|
+
pauseTask = null;
|
|
1004
|
+
}
|
|
1005
|
+
function schedule$1(task, priority) {
|
|
1006
|
+
if (priority === void 0) { priority = 0 /* Normal */; }
|
|
1007
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1008
|
+
var _i, queuedTasks_1, q, promise;
|
|
1009
|
+
return __generator(this, function (_a) {
|
|
1010
|
+
// If this task is already scheduled, skip it
|
|
1011
|
+
for (_i = 0, queuedTasks_1 = queuedTasks; _i < queuedTasks_1.length; _i++) {
|
|
1012
|
+
q = queuedTasks_1[_i];
|
|
1013
|
+
if (q.task === task) {
|
|
1014
|
+
return [2 /*return*/];
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
promise = new Promise(function (resolve) {
|
|
1018
|
+
var insert = priority === 1 /* High */ ? "unshift" : "push";
|
|
1019
|
+
// Queue this task for asynchronous execution later
|
|
1020
|
+
// We also store a unique page identifier (id) along with the task to ensure
|
|
1021
|
+
// ensure that we do not accidentally execute this task in context of a different page
|
|
1022
|
+
queuedTasks[insert]({ task: task, resolve: resolve, id: id() });
|
|
1023
|
+
});
|
|
1024
|
+
// If there is no active task running, and Clarity is not in pause state,
|
|
1025
|
+
// invoke the first task in the queue synchronously. This ensures that we don't yield the thread during unload event
|
|
1026
|
+
if (activeTask === null && pauseTask === null) {
|
|
1027
|
+
run();
|
|
1028
|
+
}
|
|
1029
|
+
return [2 /*return*/, promise];
|
|
1030
|
+
});
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
function run() {
|
|
1034
|
+
var entry = queuedTasks.shift();
|
|
1035
|
+
if (entry) {
|
|
1036
|
+
activeTask = entry;
|
|
1037
|
+
entry.task().then(function () {
|
|
1038
|
+
// Bail out if the context in which this task was operating is different from the current page
|
|
1039
|
+
// An example scenario where task could span across pages is Single Page Applications (SPA)
|
|
1040
|
+
// A task that started on page #1, but completes on page #2
|
|
1041
|
+
if (entry.id !== id()) {
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
entry.resolve();
|
|
1045
|
+
activeTask = null; // Reset active task back to null now that the promise is resolved
|
|
1046
|
+
run();
|
|
1047
|
+
}).catch(function (error) {
|
|
1048
|
+
// If one of the scheduled tasks failed, log, recover and continue processing rest of the tasks
|
|
1049
|
+
if (entry.id !== id()) {
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
if (error) {
|
|
1053
|
+
log(0 /* RunTask */, 1 /* Warning */, error.name, error.message, error.stack);
|
|
1054
|
+
}
|
|
1055
|
+
activeTask = null;
|
|
1056
|
+
run();
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
function state$6(timer) {
|
|
1061
|
+
var id = key(timer);
|
|
1062
|
+
if (id in tracker) {
|
|
1063
|
+
var elapsed = performance.now() - tracker[id].start;
|
|
1064
|
+
return (elapsed > tracker[id].yield) ? 0 /* Wait */ : 1 /* Run */;
|
|
1065
|
+
}
|
|
1066
|
+
// If this task is no longer being tracked, send stop message to the caller
|
|
1067
|
+
return 2 /* Stop */;
|
|
1068
|
+
}
|
|
1069
|
+
function start$t(timer) {
|
|
1070
|
+
tracker[key(timer)] = { start: performance.now(), calls: 0, yield: 30 /* LongTask */ };
|
|
1071
|
+
}
|
|
1072
|
+
function restart$1(timer) {
|
|
1073
|
+
var id = key(timer);
|
|
1074
|
+
if (tracker && tracker[id]) {
|
|
1075
|
+
var c = tracker[id].calls;
|
|
1076
|
+
var y = tracker[id].yield;
|
|
1077
|
+
start$t(timer);
|
|
1078
|
+
tracker[id].calls = c + 1;
|
|
1079
|
+
tracker[id].yield = y;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
function stop$q(timer) {
|
|
1083
|
+
var end = performance.now();
|
|
1084
|
+
var id = key(timer);
|
|
1085
|
+
var duration = end - tracker[id].start;
|
|
1086
|
+
sum(timer.cost, duration);
|
|
1087
|
+
count$1(5 /* InvokeCount */);
|
|
1088
|
+
// For the first execution, which is synchronous, time is automatically counted towards TotalDuration.
|
|
1089
|
+
// However, for subsequent asynchronous runs, we need to manually update TotalDuration metric.
|
|
1090
|
+
if (tracker[id].calls > 0) {
|
|
1091
|
+
sum(4 /* TotalCost */, duration);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
function suspend$1(timer) {
|
|
1095
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1096
|
+
var id, _a;
|
|
1097
|
+
return __generator(this, function (_b) {
|
|
1098
|
+
switch (_b.label) {
|
|
1099
|
+
case 0:
|
|
1100
|
+
id = key(timer);
|
|
1101
|
+
if (!(id in tracker)) return [3 /*break*/, 2];
|
|
1102
|
+
stop$q(timer);
|
|
1103
|
+
_a = tracker[id];
|
|
1104
|
+
return [4 /*yield*/, wait()];
|
|
1105
|
+
case 1:
|
|
1106
|
+
_a.yield = (_b.sent()).timeRemaining();
|
|
1107
|
+
restart$1(timer);
|
|
1108
|
+
_b.label = 2;
|
|
1109
|
+
case 2:
|
|
1110
|
+
// After we are done with suspending task, ensure that we are still operating in the right context
|
|
1111
|
+
// If the task is still being tracked, continue running the task, otherwise ask caller to stop execution
|
|
1112
|
+
return [2 /*return*/, id in tracker ? 1 /* Run */ : 2 /* Stop */];
|
|
1113
|
+
}
|
|
1114
|
+
});
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
function key(timer) {
|
|
1118
|
+
return timer.id + "." + timer.cost;
|
|
1119
|
+
}
|
|
1120
|
+
function wait() {
|
|
1121
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1122
|
+
return __generator(this, function (_a) {
|
|
1123
|
+
switch (_a.label) {
|
|
1124
|
+
case 0:
|
|
1125
|
+
if (!pauseTask) return [3 /*break*/, 2];
|
|
1126
|
+
return [4 /*yield*/, pauseTask];
|
|
1127
|
+
case 1:
|
|
1128
|
+
_a.sent();
|
|
1129
|
+
_a.label = 2;
|
|
1130
|
+
case 2: return [2 /*return*/, new Promise(function (resolve) {
|
|
1131
|
+
requestIdleCallback(resolve, { timeout: idleTimeout });
|
|
1132
|
+
})];
|
|
1133
|
+
}
|
|
1134
|
+
});
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
// Use native implementation of requestIdleCallback if it exists.
|
|
1138
|
+
// Otherwise, fall back to a custom implementation using requestAnimationFrame & MessageChannel.
|
|
1139
|
+
// While it's not possible to build a perfect polyfill given the nature of this API, the following code attempts to get close.
|
|
1140
|
+
// Background context: requestAnimationFrame invokes the js code right before: style, layout and paint computation within the frame.
|
|
1141
|
+
// This means, that any code that runs as part of requestAnimationFrame will by default be blocking in nature. Not what we want.
|
|
1142
|
+
// For non-blocking behavior, We need to know when browser has finished painiting. This can be accomplished in two different ways (hacks):
|
|
1143
|
+
// (1) Use MessageChannel to pass the message, and browser will receive the message right after pain event has occured.
|
|
1144
|
+
// (2) Use setTimeout call within requestAnimationFrame. This also works, but there's a risk that browser may throttle setTimeout calls.
|
|
1145
|
+
// Given this information, we are currently using (1) from above. More information on (2) as well as some additional context is below:
|
|
1146
|
+
// https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Performance_best_practices_for_Firefox_fe_engineers
|
|
1147
|
+
function requestIdleCallbackPolyfill(callback, options) {
|
|
1148
|
+
var startTime = performance.now();
|
|
1149
|
+
var channel = new MessageChannel();
|
|
1150
|
+
var incoming = channel.port1;
|
|
1151
|
+
var outgoing = channel.port2;
|
|
1152
|
+
incoming.onmessage = function (event) {
|
|
1153
|
+
var currentTime = performance.now();
|
|
1154
|
+
var elapsed = currentTime - startTime;
|
|
1155
|
+
var duration = currentTime - event.data;
|
|
1156
|
+
if (duration > 30 /* LongTask */ && elapsed < options.timeout) {
|
|
1157
|
+
requestAnimationFrame(function () { outgoing.postMessage(currentTime); });
|
|
1158
|
+
}
|
|
1159
|
+
else {
|
|
1160
|
+
var didTimeout_1 = elapsed > options.timeout;
|
|
1161
|
+
callback({
|
|
1162
|
+
didTimeout: didTimeout_1,
|
|
1163
|
+
timeRemaining: function () { return didTimeout_1 ? 30 /* LongTask */ : Math.max(0, 30 /* LongTask */ - duration); }
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
};
|
|
1167
|
+
requestAnimationFrame(function () { outgoing.postMessage(performance.now()); });
|
|
1168
|
+
}
|
|
1169
|
+
var requestIdleCallback = window["requestIdleCallback"] || requestIdleCallbackPolyfill;
|
|
1170
|
+
|
|
1171
|
+
var data$b;
|
|
1172
|
+
function start$s() {
|
|
1173
|
+
bind(document, "error", handler$5, true);
|
|
1174
|
+
}
|
|
1175
|
+
function handler$5(error) {
|
|
1176
|
+
var element = error.target;
|
|
1177
|
+
if (element && element.tagName === "IMG") {
|
|
1178
|
+
data$b = { source: element.src, target: element };
|
|
1179
|
+
schedule$1(encode$3.bind(this, 32 /* ImageError */));
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
function stop$p() {
|
|
1183
|
+
data$b = null;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// Following code takes an array of tokens and transforms it to optimize for repeating tokens and make it efficient to send over the wire
|
|
1187
|
+
// The way it works is that it iterate over all tokens and checks if the current token was already seen in the tokens array so far
|
|
1188
|
+
// If so, it replaces the token with its reference (index). This helps us save bytes by not repeating the same value twice.
|
|
1189
|
+
// E.g. If tokens array is: ["hello", "world", "coding", "language", "world", "language", "example"]
|
|
1190
|
+
// Then the resulting tokens array after following code execution would be: ["hello", "world", "coding", "language", [1, 3], "example"]
|
|
1191
|
+
// Where [1,3] points to tokens[1] => "world" and tokens[3] => "language"
|
|
1192
|
+
function tokenize (tokens) {
|
|
1193
|
+
var output = [];
|
|
1194
|
+
var lookup = {};
|
|
1195
|
+
var pointer = 0;
|
|
1196
|
+
var reference = null;
|
|
1197
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
1198
|
+
// Only optimize for string values
|
|
1199
|
+
if (typeof tokens[i] === "string" /* String */) {
|
|
1200
|
+
var token = tokens[i];
|
|
1201
|
+
var index = lookup[token] || -1;
|
|
1202
|
+
if (index >= 0) {
|
|
1203
|
+
if (reference) {
|
|
1204
|
+
reference.push(index);
|
|
1205
|
+
}
|
|
1206
|
+
else {
|
|
1207
|
+
reference = [index];
|
|
1208
|
+
output.push(reference);
|
|
1209
|
+
pointer++;
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
else {
|
|
1213
|
+
reference = null;
|
|
1214
|
+
output.push(token);
|
|
1215
|
+
lookup[token] = pointer++;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
else {
|
|
1219
|
+
// If the value is anything other than string, append it as it is to the output array
|
|
1220
|
+
// And, also increment the pointer to stay in sync with output array
|
|
1221
|
+
reference = null;
|
|
1222
|
+
output.push(tokens[i]);
|
|
1223
|
+
pointer++;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
return output;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
var data$a;
|
|
1230
|
+
function reset$g() {
|
|
1231
|
+
data$a = null;
|
|
1232
|
+
}
|
|
1233
|
+
function start$r() {
|
|
1234
|
+
reset$g();
|
|
1235
|
+
compute$6();
|
|
1236
|
+
}
|
|
1237
|
+
function compute$6() {
|
|
1238
|
+
var body = document.body;
|
|
1239
|
+
var d = document.documentElement;
|
|
1240
|
+
var bodyClientWidth = body ? body.clientWidth : null;
|
|
1241
|
+
var bodyScrollWidth = body ? body.scrollWidth : null;
|
|
1242
|
+
var bodyOffsetWidth = body ? body.offsetWidth : null;
|
|
1243
|
+
var documentClientWidth = d ? d.clientWidth : null;
|
|
1244
|
+
var documentScrollWidth = d ? d.scrollWidth : null;
|
|
1245
|
+
var documentOffsetWidth = d ? d.offsetWidth : null;
|
|
1246
|
+
var width = Math.max(bodyClientWidth, bodyScrollWidth, bodyOffsetWidth, documentClientWidth, documentScrollWidth, documentOffsetWidth);
|
|
1247
|
+
var bodyClientHeight = body ? body.clientHeight : null;
|
|
1248
|
+
var bodyScrollHeight = body ? body.scrollHeight : null;
|
|
1249
|
+
var bodyOffsetHeight = body ? body.offsetHeight : null;
|
|
1250
|
+
var documentClientHeight = d ? d.clientHeight : null;
|
|
1251
|
+
var documentScrollHeight = d ? d.scrollHeight : null;
|
|
1252
|
+
var documentOffsetHeight = d ? d.offsetHeight : null;
|
|
1253
|
+
var height = Math.max(bodyClientHeight, bodyScrollHeight, bodyOffsetHeight, documentClientHeight, documentScrollHeight, documentOffsetHeight);
|
|
1254
|
+
// Check that width or height has changed from before, and also that width & height are not null values
|
|
1255
|
+
if ((data$a === null || width !== data$a.width || height !== data$a.height) && width !== null && height !== null) {
|
|
1256
|
+
data$a = { width: width, height: height };
|
|
1257
|
+
encode$4(8 /* Document */);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
function end() {
|
|
1261
|
+
reset$g();
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
function encode$4 (type, timer, ts) {
|
|
1265
|
+
if (timer === void 0) { timer = null; }
|
|
1266
|
+
if (ts === void 0) { ts = null; }
|
|
1267
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1268
|
+
var eventTime, tokens, _a, d, _i, _b, r, b, _c, b_1, entry, values, _d, values_1, value, state, data, active, privacy, mangle, keys, _e, keys_1, key, size, factor, attr;
|
|
1269
|
+
return __generator(this, function (_f) {
|
|
1270
|
+
switch (_f.label) {
|
|
1271
|
+
case 0:
|
|
1272
|
+
eventTime = ts || time();
|
|
1273
|
+
tokens = [eventTime, type];
|
|
1274
|
+
_a = type;
|
|
1275
|
+
switch (_a) {
|
|
1276
|
+
case 8 /* Document */: return [3 /*break*/, 1];
|
|
1277
|
+
case 7 /* Region */: return [3 /*break*/, 2];
|
|
1278
|
+
case 37 /* Box */: return [3 /*break*/, 3];
|
|
1279
|
+
case 5 /* Discover */: return [3 /*break*/, 4];
|
|
1280
|
+
case 6 /* Mutation */: return [3 /*break*/, 4];
|
|
1281
|
+
}
|
|
1282
|
+
return [3 /*break*/, 11];
|
|
1283
|
+
case 1:
|
|
1284
|
+
d = data$a;
|
|
1285
|
+
tokens.push(d.width);
|
|
1286
|
+
tokens.push(d.height);
|
|
1287
|
+
track$7(type, d.width, d.height);
|
|
1288
|
+
queue(tokens);
|
|
1289
|
+
return [3 /*break*/, 11];
|
|
1290
|
+
case 2:
|
|
1291
|
+
for (_i = 0, _b = state$5; _i < _b.length; _i++) {
|
|
1292
|
+
r = _b[_i];
|
|
1293
|
+
tokens = [r.time, 7 /* Region */];
|
|
1294
|
+
tokens.push(r.data.id);
|
|
1295
|
+
tokens.push(r.data.state);
|
|
1296
|
+
tokens.push(r.data.name);
|
|
1297
|
+
queue(tokens);
|
|
1298
|
+
}
|
|
1299
|
+
reset$d();
|
|
1300
|
+
return [3 /*break*/, 11];
|
|
1301
|
+
case 3:
|
|
1302
|
+
b = data$9;
|
|
1303
|
+
for (_c = 0, b_1 = b; _c < b_1.length; _c++) {
|
|
1304
|
+
entry = b_1[_c];
|
|
1305
|
+
tokens.push(entry.id);
|
|
1306
|
+
tokens.push(entry.width);
|
|
1307
|
+
tokens.push(entry.height);
|
|
1308
|
+
}
|
|
1309
|
+
reset$f();
|
|
1310
|
+
queue(tokens);
|
|
1311
|
+
return [3 /*break*/, 11];
|
|
1312
|
+
case 4:
|
|
1313
|
+
// Check if we are operating within the context of the current page
|
|
1314
|
+
if (state$6(timer) === 2 /* Stop */) {
|
|
1315
|
+
return [3 /*break*/, 11];
|
|
1316
|
+
}
|
|
1317
|
+
values = updates$2();
|
|
1318
|
+
if (!(values.length > 0)) return [3 /*break*/, 10];
|
|
1319
|
+
_d = 0, values_1 = values;
|
|
1320
|
+
_f.label = 5;
|
|
1321
|
+
case 5:
|
|
1322
|
+
if (!(_d < values_1.length)) return [3 /*break*/, 9];
|
|
1323
|
+
value = values_1[_d];
|
|
1324
|
+
state = state$6(timer);
|
|
1325
|
+
if (!(state === 0 /* Wait */)) return [3 /*break*/, 7];
|
|
1326
|
+
return [4 /*yield*/, suspend$1(timer)];
|
|
1327
|
+
case 6:
|
|
1328
|
+
state = _f.sent();
|
|
1329
|
+
_f.label = 7;
|
|
1330
|
+
case 7:
|
|
1331
|
+
if (state === 2 /* Stop */) {
|
|
1332
|
+
return [3 /*break*/, 9];
|
|
1333
|
+
}
|
|
1334
|
+
data = value.data;
|
|
1335
|
+
active = value.metadata.active;
|
|
1336
|
+
privacy = value.metadata.privacy;
|
|
1337
|
+
mangle = shouldMangle(value);
|
|
1338
|
+
keys = active ? ["tag", "path", "attributes", "value"] : ["tag"];
|
|
1339
|
+
compute$5(value.id);
|
|
1340
|
+
for (_e = 0, keys_1 = keys; _e < keys_1.length; _e++) {
|
|
1341
|
+
key = keys_1[_e];
|
|
1342
|
+
if (data[key]) {
|
|
1343
|
+
switch (key) {
|
|
1344
|
+
case "tag":
|
|
1345
|
+
size = value.metadata.size;
|
|
1346
|
+
factor = mangle ? -1 : 1;
|
|
1347
|
+
tokens.push(value.id * factor);
|
|
1348
|
+
if (value.parent && active) {
|
|
1349
|
+
tokens.push(value.parent);
|
|
1350
|
+
}
|
|
1351
|
+
if (value.previous && active) {
|
|
1352
|
+
tokens.push(value.previous);
|
|
1353
|
+
}
|
|
1354
|
+
tokens.push(value.position ? data[key] + "~" + value.position : data[key]);
|
|
1355
|
+
if (size && size.length === 2) {
|
|
1356
|
+
tokens.push("" + "#" /* Box */ + str(size[0]) + "." + str(size[1]));
|
|
1357
|
+
}
|
|
1358
|
+
break;
|
|
1359
|
+
case "path":
|
|
1360
|
+
tokens.push(value.data.path + ">");
|
|
1361
|
+
break;
|
|
1362
|
+
case "attributes":
|
|
1363
|
+
for (attr in data[key]) {
|
|
1364
|
+
if (data[key][attr] !== undefined) {
|
|
1365
|
+
tokens.push(attribute(attr, data[key][attr], privacy));
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
break;
|
|
1369
|
+
case "value":
|
|
1370
|
+
tokens.push(scrub(data[key], data.tag, privacy, mangle));
|
|
1371
|
+
break;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
_f.label = 8;
|
|
1376
|
+
case 8:
|
|
1377
|
+
_d++;
|
|
1378
|
+
return [3 /*break*/, 5];
|
|
1379
|
+
case 9:
|
|
1380
|
+
if (type === 6 /* Mutation */) {
|
|
1381
|
+
activity(eventTime);
|
|
1382
|
+
}
|
|
1383
|
+
queue(tokenize(tokens), !config$1.lean);
|
|
1384
|
+
_f.label = 10;
|
|
1385
|
+
case 10: return [3 /*break*/, 11];
|
|
1386
|
+
case 11: return [2 /*return*/];
|
|
1387
|
+
}
|
|
1388
|
+
});
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
function shouldMangle(value) {
|
|
1392
|
+
var privacy = value.metadata.privacy;
|
|
1393
|
+
return value.data.tag === "*T" /* TextTag */ && !(privacy === 0 /* None */ || privacy === 1 /* Sensitive */);
|
|
1394
|
+
}
|
|
1395
|
+
function str(input) {
|
|
1396
|
+
return input.toString(36);
|
|
1397
|
+
}
|
|
1398
|
+
function attribute(key, value, privacy) {
|
|
1399
|
+
return key + "=" + scrub(value, key, privacy);
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
var data$9 = [];
|
|
1403
|
+
var enabled = false;
|
|
1404
|
+
var observer$2 = null;
|
|
1405
|
+
function start$q() {
|
|
1406
|
+
reset$f();
|
|
1407
|
+
observer$2 = null;
|
|
1408
|
+
enabled = window["ResizeObserver"] ? true : false;
|
|
1409
|
+
}
|
|
1410
|
+
function compute$5(id) {
|
|
1411
|
+
if (enabled === false) {
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
observer$2 = observer$2 === null ? new ResizeObserver(handler$4) : observer$2;
|
|
1415
|
+
if (observer$2) {
|
|
1416
|
+
var value = getValue(id);
|
|
1417
|
+
// If this is the first time computing size for this node, go ahead and wire up ResizeObserver
|
|
1418
|
+
// In all other cases, value.metadata.size will be null or an array with two elements [width, height]
|
|
1419
|
+
// And, in those cases, we will skip through the following section and not attach the observer
|
|
1420
|
+
if (value && value.metadata.size !== null && value.metadata.size.length === 0) {
|
|
1421
|
+
var node = getNode(id);
|
|
1422
|
+
if (node && node.nodeType === Node.ELEMENT_NODE) {
|
|
1423
|
+
var e = node;
|
|
1424
|
+
var r = e.getBoundingClientRect();
|
|
1425
|
+
value.metadata.size = [Math.floor(r.width * 100 /* BoxPrecision */), Math.floor(r.height * 100 /* BoxPrecision */)];
|
|
1426
|
+
observer$2.observe(e);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
function handler$4(entries) {
|
|
1432
|
+
window.requestAnimationFrame(function () {
|
|
1433
|
+
for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
|
|
1434
|
+
var entry = entries_1[_i];
|
|
1435
|
+
var target = entry.target;
|
|
1436
|
+
var id = target ? getId(target) : null;
|
|
1437
|
+
if (id) {
|
|
1438
|
+
var v = getValue(id);
|
|
1439
|
+
var s = v.metadata.size;
|
|
1440
|
+
var b = entry.borderBoxSize;
|
|
1441
|
+
var w = null;
|
|
1442
|
+
var h = null;
|
|
1443
|
+
// Check if browser supports borderBoxSize property on ResizeObserverEntry object
|
|
1444
|
+
// Otherwise, fall back to using getBoundingClientRect() to be cross browser compatible
|
|
1445
|
+
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/borderBoxSize
|
|
1446
|
+
if (b && b.length > 0) {
|
|
1447
|
+
w = Math.floor(b[0].inlineSize * 100 /* BoxPrecision */);
|
|
1448
|
+
h = Math.floor(b[0].blockSize * 100 /* BoxPrecision */);
|
|
1449
|
+
}
|
|
1450
|
+
else {
|
|
1451
|
+
var r = target.getBoundingClientRect();
|
|
1452
|
+
w = Math.floor(r.width * 100 /* BoxPrecision */);
|
|
1453
|
+
h = Math.floor(r.height * 100 /* BoxPrecision */);
|
|
1454
|
+
}
|
|
1455
|
+
// Capture new width & height only if they are different from what we have in in-memory cache
|
|
1456
|
+
if (w !== s[0] && h !== s[1]) {
|
|
1457
|
+
s = [w, h];
|
|
1458
|
+
data$9.push({ id: id, width: w, height: h });
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
// Schedule encode only when we have at least one valid data entry
|
|
1463
|
+
if (data$9.length > 0) {
|
|
1464
|
+
encode$4(37 /* Box */);
|
|
1465
|
+
}
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
function reset$f() {
|
|
1469
|
+
data$9 = [];
|
|
1470
|
+
}
|
|
1471
|
+
function stop$o() {
|
|
1472
|
+
reset$f();
|
|
1473
|
+
if (observer$2) {
|
|
1474
|
+
observer$2.disconnect();
|
|
1475
|
+
observer$2 = null;
|
|
1476
|
+
}
|
|
1477
|
+
enabled = false;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
var history$4 = {};
|
|
1481
|
+
var data$8;
|
|
1482
|
+
function start$p() {
|
|
1483
|
+
bind(window, "error", handler$3);
|
|
1484
|
+
history$4 = {};
|
|
1485
|
+
}
|
|
1486
|
+
function handler$3(error) {
|
|
1487
|
+
var e = error["error"] || error;
|
|
1488
|
+
// While rare, it's possible for code to fail repeatedly during the lifetime of the same page
|
|
1489
|
+
// In those cases, we only want to log the failure first few times and not spam logs with redundant information.
|
|
1490
|
+
if (!(e.message in history$4)) {
|
|
1491
|
+
history$4[e.message] = 0;
|
|
1492
|
+
}
|
|
1493
|
+
if (history$4[e.message]++ >= 5 /* ScriptErrorLimit */) {
|
|
1494
|
+
return true;
|
|
1495
|
+
}
|
|
1496
|
+
// Send back information only if the handled error has valid information
|
|
1497
|
+
if (e && e.message) {
|
|
1498
|
+
data$8 = {
|
|
1499
|
+
message: e.message,
|
|
1500
|
+
line: error["lineno"],
|
|
1501
|
+
column: error["colno"],
|
|
1502
|
+
stack: e.stack,
|
|
1503
|
+
source: error["filename"]
|
|
1504
|
+
};
|
|
1505
|
+
// In certain cases, ResizeObserver could lead to flood of benign errors - especially when video element is involved.
|
|
1506
|
+
// Reference Chromium issue: https://bugs.chromium.org/p/chromium/issues/detail?id=809574
|
|
1507
|
+
// Even though it doesn't impact user experience, or show up in console, it can still flood error reporting through on error
|
|
1508
|
+
// To mitigate that, we turn off Clarity's ResizeObserver on getting the first instance of this error
|
|
1509
|
+
if (e.message.indexOf("ResizeObserver" /* ResizeObserver */) >= 0) {
|
|
1510
|
+
stop$o();
|
|
1511
|
+
return false;
|
|
1512
|
+
}
|
|
1513
|
+
encode$3(31 /* ScriptError */);
|
|
1514
|
+
}
|
|
1515
|
+
return true;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
function encode$3 (type) {
|
|
1519
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1520
|
+
var tokens, imageTarget;
|
|
1521
|
+
return __generator(this, function (_a) {
|
|
1522
|
+
tokens = [time(), type];
|
|
1523
|
+
switch (type) {
|
|
1524
|
+
case 31 /* ScriptError */:
|
|
1525
|
+
tokens.push(data$8.message);
|
|
1526
|
+
tokens.push(data$8.line);
|
|
1527
|
+
tokens.push(data$8.column);
|
|
1528
|
+
tokens.push(data$8.stack);
|
|
1529
|
+
tokens.push(data$8.source);
|
|
1530
|
+
queue(tokens);
|
|
1531
|
+
break;
|
|
1532
|
+
case 32 /* ImageError */:
|
|
1533
|
+
if (data$b) {
|
|
1534
|
+
imageTarget = metadata(data$b.target, type);
|
|
1535
|
+
tokens.push(data$b.source);
|
|
1536
|
+
tokens.push(imageTarget.id);
|
|
1537
|
+
queue(tokens);
|
|
1538
|
+
}
|
|
1539
|
+
break;
|
|
1540
|
+
case 33 /* Log */:
|
|
1541
|
+
if (data$7) {
|
|
1542
|
+
tokens.push(data$7.code);
|
|
1543
|
+
tokens.push(data$7.name);
|
|
1544
|
+
tokens.push(data$7.message);
|
|
1545
|
+
tokens.push(data$7.stack);
|
|
1546
|
+
tokens.push(data$7.severity);
|
|
1547
|
+
queue(tokens, false);
|
|
1548
|
+
}
|
|
1549
|
+
break;
|
|
1550
|
+
}
|
|
1551
|
+
return [2 /*return*/];
|
|
1552
|
+
});
|
|
1553
|
+
});
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
var history$3 = {};
|
|
1557
|
+
var data$7;
|
|
1558
|
+
function start$o() {
|
|
1559
|
+
history$3 = {};
|
|
1560
|
+
bind(document, "securitypolicyviolation", csp);
|
|
1561
|
+
}
|
|
1562
|
+
function log(code, severity, name, message, stack) {
|
|
1563
|
+
if (name === void 0) { name = null; }
|
|
1564
|
+
if (message === void 0) { message = null; }
|
|
1565
|
+
if (stack === void 0) { stack = null; }
|
|
1566
|
+
var key = name ? name + "|" + message : "";
|
|
1567
|
+
// While rare, it's possible for code to fail repeatedly during the lifetime of the same page
|
|
1568
|
+
// In those cases, we only want to log the failure once and not spam logs with redundant information.
|
|
1569
|
+
if (code in history$3 && history$3[code].indexOf(key) >= 0) {
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
data$7 = { code: code, name: name, message: message, stack: stack, severity: severity };
|
|
1573
|
+
// Maintain history of errors in memory to avoid sending redundant information
|
|
1574
|
+
if (code in history$3) {
|
|
1575
|
+
history$3[code].push(key);
|
|
1576
|
+
}
|
|
1577
|
+
else {
|
|
1578
|
+
history$3[code] = [key];
|
|
1579
|
+
}
|
|
1580
|
+
encode$3(33 /* Log */);
|
|
1581
|
+
}
|
|
1582
|
+
function csp(e) {
|
|
1583
|
+
var upload = config$1.upload;
|
|
1584
|
+
var parts = upload ? upload.substr(0, upload.indexOf("/", "https://" /* HTTPS */.length)).split("." /* Dot */) : []; // Look for first "/" starting after initial "https://" string
|
|
1585
|
+
var domain = parts.length >= 2 ? parts.splice(-2).join("." /* Dot */) : null;
|
|
1586
|
+
// Capture content security policy violation only if disposition value is not explicitly set to "report"
|
|
1587
|
+
if (domain && e.blockedURI && e.blockedURI.indexOf(domain) >= 0 && e["disposition"] !== "report" /* Report */) {
|
|
1588
|
+
log(7 /* ContentSecurityPolicy */, 1 /* Warning */, e.blockedURI);
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
function stop$n() {
|
|
1592
|
+
history$3 = {};
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
var formatRegex = /1/g;
|
|
1596
|
+
var digitsRegex$1 = /[^0-9\.]/g;
|
|
1597
|
+
var digitsWithCommaRegex = /[^0-9\.,]/g;
|
|
1598
|
+
var regexCache = {};
|
|
1599
|
+
function regions$1(root, value) {
|
|
1600
|
+
var _loop_1 = function (v) {
|
|
1601
|
+
var regionId = v[0], selector = v[1], filter = v[2], match = v[3];
|
|
1602
|
+
var valid = true;
|
|
1603
|
+
switch (filter) {
|
|
1604
|
+
case 0 /* Url */:
|
|
1605
|
+
valid = match && !!top.location.href.match(regex(match));
|
|
1606
|
+
break;
|
|
1607
|
+
case 1 /* Javascript */:
|
|
1608
|
+
valid = match && !!evaluate(match);
|
|
1609
|
+
break;
|
|
1610
|
+
}
|
|
1611
|
+
if (valid) {
|
|
1612
|
+
root.querySelectorAll(selector).forEach(function (e) { return observe$9(e, regionId.toString()); });
|
|
1613
|
+
}
|
|
1614
|
+
};
|
|
1615
|
+
for (var _i = 0, value_1 = value; _i < value_1.length; _i++) {
|
|
1616
|
+
var v = value_1[_i];
|
|
1617
|
+
_loop_1(v);
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
function metrics(root, value) {
|
|
1621
|
+
var _loop_2 = function (v) {
|
|
1622
|
+
var metricId = v[0], source = v[1], match = v[2], scale = v[3];
|
|
1623
|
+
if (match) {
|
|
1624
|
+
switch (source) {
|
|
1625
|
+
case 0 /* Text */:
|
|
1626
|
+
root.querySelectorAll(match).forEach(function (e) { max(metricId, num$1(e.innerText, scale)); });
|
|
1627
|
+
break;
|
|
1628
|
+
case 2 /* Attribute */:
|
|
1629
|
+
root.querySelectorAll("[" + match + "]").forEach(function (e) { max(metricId, num$1(e.getAttribute(match), scale, false)); });
|
|
1630
|
+
break;
|
|
1631
|
+
case 1 /* Javascript */:
|
|
1632
|
+
max(metricId, evaluate(match, "number" /* Number */));
|
|
1633
|
+
break;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
};
|
|
1637
|
+
for (var _i = 0, value_2 = value; _i < value_2.length; _i++) {
|
|
1638
|
+
var v = value_2[_i];
|
|
1639
|
+
_loop_2(v);
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
function regex(match) {
|
|
1643
|
+
regexCache[match] = match in regexCache ? regexCache[match] : new RegExp(match);
|
|
1644
|
+
return regexCache[match];
|
|
1645
|
+
}
|
|
1646
|
+
// The function below takes in a variable name in following format: "a.b.c" and safely evaluates its value in javascript context
|
|
1647
|
+
// 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,
|
|
1648
|
+
// return the value for window["a"]["b"]["c"].
|
|
1649
|
+
function evaluate(variable, type, base) {
|
|
1650
|
+
if (type === void 0) { type = null; }
|
|
1651
|
+
if (base === void 0) { base = window; }
|
|
1652
|
+
var parts = variable.split("." /* Dot */);
|
|
1653
|
+
var first = parts.shift();
|
|
1654
|
+
if (base && base[first]) {
|
|
1655
|
+
if (parts.length > 0) {
|
|
1656
|
+
return evaluate(parts.join("." /* Dot */), type, base[first]);
|
|
1657
|
+
}
|
|
1658
|
+
var output = type === null || type === typeof base[first] ? base[first] : null;
|
|
1659
|
+
return output;
|
|
1660
|
+
}
|
|
1661
|
+
return null;
|
|
1662
|
+
}
|
|
1663
|
+
function num$1(text, scale, localize) {
|
|
1664
|
+
if (localize === void 0) { localize = true; }
|
|
1665
|
+
try {
|
|
1666
|
+
scale = scale || 1;
|
|
1667
|
+
// Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat
|
|
1668
|
+
var lang = document.documentElement.lang;
|
|
1669
|
+
if (Intl && Intl.NumberFormat && lang && localize) {
|
|
1670
|
+
text = text.replace(digitsWithCommaRegex, "" /* Empty */);
|
|
1671
|
+
// Infer current group and decimal separator from current locale
|
|
1672
|
+
var group = Intl.NumberFormat(lang).format(11111).replace(formatRegex, "" /* Empty */);
|
|
1673
|
+
var decimal = Intl.NumberFormat(lang).format(1.1).replace(formatRegex, "" /* Empty */);
|
|
1674
|
+
// Parse number using inferred group and decimal separators
|
|
1675
|
+
return Math.round(parseFloat(text
|
|
1676
|
+
.replace(new RegExp('\\' + group, 'g'), "" /* Empty */)
|
|
1677
|
+
.replace(new RegExp('\\' + decimal), "." /* Dot */)) * scale);
|
|
1678
|
+
}
|
|
1679
|
+
// Fallback to en locale
|
|
1680
|
+
return Math.round(parseFloat(text.replace(digitsRegex$1, "" /* Empty */)) * scale);
|
|
1681
|
+
}
|
|
1682
|
+
catch (_a) {
|
|
1683
|
+
return null;
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
function selector (tag, prefix, attributes, position) {
|
|
1688
|
+
var suffix = position ? ":nth-of-type(" + position + ")" : "" /* Empty */;
|
|
1689
|
+
switch (tag) {
|
|
1690
|
+
case "STYLE":
|
|
1691
|
+
case "TITLE":
|
|
1692
|
+
case "LINK":
|
|
1693
|
+
case "META":
|
|
1694
|
+
case "*T" /* TextTag */:
|
|
1695
|
+
case "*D" /* DocumentTag */:
|
|
1696
|
+
return "" /* Empty */;
|
|
1697
|
+
case "HTML":
|
|
1698
|
+
return "HTML" /* HTML */;
|
|
1699
|
+
default:
|
|
1700
|
+
if (prefix === null) {
|
|
1701
|
+
return "" /* Empty */;
|
|
1702
|
+
}
|
|
1703
|
+
tag = tag.indexOf("svg:" /* SvgPrefix */) === 0 ? tag.substr("svg:" /* SvgPrefix */.length) : tag;
|
|
1704
|
+
var selector = "" + prefix + tag + suffix;
|
|
1705
|
+
if ("class" /* Class */ in attributes && attributes["class" /* Class */].length > 0) {
|
|
1706
|
+
selector = "" + prefix + tag + "." + attributes.class.trim().split(/\s+/).join(".") + suffix;
|
|
1707
|
+
}
|
|
1708
|
+
return selector;
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
var index = 1;
|
|
1713
|
+
// Reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#%3Cinput%3E_types
|
|
1714
|
+
var DISALLOWED_TYPES = ["password", "hidden", "email", "tel"];
|
|
1715
|
+
var DISALLOWED_NAMES = ["addr", "cell", "code", "dob", "email", "mob", "name", "phone", "secret", "social", "ssn", "tel", "zip", "pass"];
|
|
1716
|
+
var DISALLOWED_MATCH = ["address", "password", "contact"];
|
|
1717
|
+
var nodes = [];
|
|
1718
|
+
var values = [];
|
|
1719
|
+
var changes = [];
|
|
1720
|
+
var updateMap = [];
|
|
1721
|
+
var selectorMap = [];
|
|
1722
|
+
// The WeakMap object is a collection of key/value pairs in which the keys are weakly referenced
|
|
1723
|
+
var idMap = null; // Maps node => id.
|
|
1724
|
+
var iframeMap = null; // Maps iframe's contentDocument => parent iframe element
|
|
1725
|
+
var privacyMap = null; // Maps node => Privacy (enum)
|
|
1726
|
+
var urlMap = {};
|
|
1727
|
+
function start$n() {
|
|
1728
|
+
reset$e();
|
|
1729
|
+
parse(document);
|
|
1730
|
+
}
|
|
1731
|
+
function stop$m() {
|
|
1732
|
+
reset$e();
|
|
1733
|
+
}
|
|
1734
|
+
function reset$e() {
|
|
1735
|
+
index = 1;
|
|
1736
|
+
nodes = [];
|
|
1737
|
+
values = [];
|
|
1738
|
+
updateMap = [];
|
|
1739
|
+
changes = [];
|
|
1740
|
+
selectorMap = [];
|
|
1741
|
+
urlMap = {};
|
|
1742
|
+
idMap = new WeakMap();
|
|
1743
|
+
iframeMap = new WeakMap();
|
|
1744
|
+
privacyMap = new WeakMap();
|
|
1745
|
+
if ("__CLARITY_DEVTOOLS_HOOK__" /* DevHook */ in window) {
|
|
1746
|
+
window["__CLARITY_DEVTOOLS_HOOK__" /* DevHook */] = { get: get, getNode: getNode, history: history$2 };
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
// We parse new root nodes for any regions or masked nodes in the beginning (document) and
|
|
1750
|
+
// later whenever there are new additions or modifications to DOM (mutations)
|
|
1751
|
+
function parse(root) {
|
|
1752
|
+
// Wrap selectors in a try / catch block.
|
|
1753
|
+
// It's possible for script to receive invalid selectors, e.g. "'#id'" with extra quotes, and cause the code below to fail
|
|
1754
|
+
try {
|
|
1755
|
+
// Since mutations may happen on leaf nodes too, e.g. text nodes, which may not support all selector APIs.
|
|
1756
|
+
// We ensure that the root note supports querySelectorAll API before executing the code below to identify new regions.
|
|
1757
|
+
if ("querySelectorAll" in root) {
|
|
1758
|
+
regions$1(root, config$1.regions);
|
|
1759
|
+
metrics(root, config$1.metrics);
|
|
1760
|
+
config$1.mask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 3 /* TextImage */); }); }); // Masked Elements
|
|
1761
|
+
config$1.unmask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 0 /* None */); }); }); // Unmasked Elements
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
catch (e) {
|
|
1765
|
+
log(5 /* Selector */, 1 /* Warning */, e ? e.name : null);
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
function getId(node, autogen) {
|
|
1769
|
+
if (autogen === void 0) { autogen = false; }
|
|
1770
|
+
if (node === null) {
|
|
1771
|
+
return null;
|
|
1772
|
+
}
|
|
1773
|
+
var id = idMap.get(node);
|
|
1774
|
+
if (!id && autogen) {
|
|
1775
|
+
id = index++;
|
|
1776
|
+
idMap.set(node, id);
|
|
1777
|
+
}
|
|
1778
|
+
return id ? id : null;
|
|
1779
|
+
}
|
|
1780
|
+
function add(node, parent, data, source) {
|
|
1781
|
+
var id = getId(node, true);
|
|
1782
|
+
var parentId = parent ? getId(parent) : null;
|
|
1783
|
+
var previousId = getPreviousId(node);
|
|
1784
|
+
var privacy = config$1.content ? 1 /* Sensitive */ : 2 /* Text */;
|
|
1785
|
+
var parentValue = null;
|
|
1786
|
+
var parentTag = "" /* Empty */;
|
|
1787
|
+
var regionId = exists(node) ? id : null;
|
|
1788
|
+
if (parentId >= 0 && values[parentId]) {
|
|
1789
|
+
parentValue = values[parentId];
|
|
1790
|
+
parentTag = parentValue.data.tag;
|
|
1791
|
+
parentValue.children.push(id);
|
|
1792
|
+
regionId = regionId === null ? parentValue.region : regionId;
|
|
1793
|
+
privacy = parentValue.metadata.privacy;
|
|
1794
|
+
}
|
|
1795
|
+
// Check to see if this particular node should be masked or not
|
|
1796
|
+
privacy = getPrivacy(node, data, parentTag, privacy);
|
|
1797
|
+
// If there's an explicit region attribute set on the element, use it to mark a region on the page
|
|
1798
|
+
if (data.attributes && "data-clarity-region" /* RegionData */ in data.attributes) {
|
|
1799
|
+
observe$9(node, data.attributes["data-clarity-region" /* RegionData */]);
|
|
1800
|
+
regionId = id;
|
|
1801
|
+
}
|
|
1802
|
+
nodes[id] = node;
|
|
1803
|
+
values[id] = {
|
|
1804
|
+
id: id,
|
|
1805
|
+
parent: parentId,
|
|
1806
|
+
previous: previousId,
|
|
1807
|
+
children: [],
|
|
1808
|
+
position: null,
|
|
1809
|
+
data: data,
|
|
1810
|
+
selector: "" /* Empty */,
|
|
1811
|
+
region: regionId,
|
|
1812
|
+
metadata: { active: true, privacy: privacy, size: null }
|
|
1813
|
+
};
|
|
1814
|
+
updateSelector(values[id]);
|
|
1815
|
+
size(values[id], parentValue);
|
|
1816
|
+
metadata$1(data.tag, id, parentId);
|
|
1817
|
+
track$4(id, source);
|
|
1818
|
+
}
|
|
1819
|
+
function update(node, parent, data, source) {
|
|
1820
|
+
var id = getId(node);
|
|
1821
|
+
var parentId = parent ? getId(parent) : null;
|
|
1822
|
+
var previousId = getPreviousId(node);
|
|
1823
|
+
var changed = false;
|
|
1824
|
+
var parentChanged = false;
|
|
1825
|
+
if (id in values) {
|
|
1826
|
+
var value = values[id];
|
|
1827
|
+
value.metadata.active = true;
|
|
1828
|
+
// Handle case where internal ordering may have changed
|
|
1829
|
+
if (value.previous !== previousId) {
|
|
1830
|
+
changed = true;
|
|
1831
|
+
value.previous = previousId;
|
|
1832
|
+
}
|
|
1833
|
+
// Handle case where parent might have been updated
|
|
1834
|
+
if (value.parent !== parentId) {
|
|
1835
|
+
changed = true;
|
|
1836
|
+
var oldParentId = value.parent;
|
|
1837
|
+
value.parent = parentId;
|
|
1838
|
+
// Move this node to the right location under new parent
|
|
1839
|
+
if (parentId !== null && parentId >= 0) {
|
|
1840
|
+
var childIndex = previousId === null ? 0 : values[parentId].children.indexOf(previousId) + 1;
|
|
1841
|
+
values[parentId].children.splice(childIndex, 0, id);
|
|
1842
|
+
// Update region after the move
|
|
1843
|
+
value.region = exists(node) ? id : values[parentId].region;
|
|
1844
|
+
}
|
|
1845
|
+
else {
|
|
1846
|
+
// Mark this element as deleted if the parent has been updated to null
|
|
1847
|
+
remove(id, source);
|
|
1848
|
+
}
|
|
1849
|
+
// Remove reference to this node from the old parent
|
|
1850
|
+
if (oldParentId !== null && oldParentId >= 0) {
|
|
1851
|
+
var nodeIndex = values[oldParentId].children.indexOf(id);
|
|
1852
|
+
if (nodeIndex >= 0) {
|
|
1853
|
+
values[oldParentId].children.splice(nodeIndex, 1);
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
parentChanged = true;
|
|
1857
|
+
}
|
|
1858
|
+
// Update data
|
|
1859
|
+
for (var key in data) {
|
|
1860
|
+
if (diff(value["data"], data, key)) {
|
|
1861
|
+
changed = true;
|
|
1862
|
+
value["data"][key] = data[key];
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
// Update selector
|
|
1866
|
+
updateSelector(value);
|
|
1867
|
+
metadata$1(data.tag, id, parentId);
|
|
1868
|
+
track$4(id, source, changed, parentChanged);
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
function sameorigin(node) {
|
|
1872
|
+
var output = false;
|
|
1873
|
+
if (node.nodeType === Node.ELEMENT_NODE && node.tagName === "IFRAME" /* IFrameTag */) {
|
|
1874
|
+
var frame = node;
|
|
1875
|
+
// To determine if the iframe is same-origin or not, we try accessing it's contentDocument.
|
|
1876
|
+
// If the browser throws an exception, we assume it's cross-origin and move on.
|
|
1877
|
+
// However, if we do a get a valid document object back, we assume the contents are accessible and iframe is same-origin.
|
|
1878
|
+
try {
|
|
1879
|
+
var doc = frame.contentDocument;
|
|
1880
|
+
if (doc) {
|
|
1881
|
+
iframeMap.set(frame.contentDocument, frame);
|
|
1882
|
+
output = true;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
catch ( /* do nothing */_a) { /* do nothing */ }
|
|
1886
|
+
}
|
|
1887
|
+
return output;
|
|
1888
|
+
}
|
|
1889
|
+
function iframe(node) {
|
|
1890
|
+
var doc = node.nodeType === Node.DOCUMENT_NODE ? node : null;
|
|
1891
|
+
return doc && iframeMap.has(doc) ? iframeMap.get(doc) : null;
|
|
1892
|
+
}
|
|
1893
|
+
function getPrivacy(node, data, parentTag, privacy) {
|
|
1894
|
+
var attributes = data.attributes;
|
|
1895
|
+
var tag = data.tag.toUpperCase();
|
|
1896
|
+
// If this node was explicitly configured to contain sensitive content, use that information and return the value
|
|
1897
|
+
if (privacyMap.has(node)) {
|
|
1898
|
+
return privacyMap.get(node);
|
|
1899
|
+
}
|
|
1900
|
+
// Do not proceed if attributes are missing for the node
|
|
1901
|
+
if (attributes === null || attributes === undefined) {
|
|
1902
|
+
return privacy;
|
|
1903
|
+
}
|
|
1904
|
+
// Look up for sensitive fields
|
|
1905
|
+
if ("class" /* Class */ in attributes && privacy === 1 /* Sensitive */) {
|
|
1906
|
+
for (var _i = 0, DISALLOWED_MATCH_1 = DISALLOWED_MATCH; _i < DISALLOWED_MATCH_1.length; _i++) {
|
|
1907
|
+
var match = DISALLOWED_MATCH_1[_i];
|
|
1908
|
+
if (attributes["class" /* Class */].indexOf(match) >= 0) {
|
|
1909
|
+
privacy = 2 /* Text */;
|
|
1910
|
+
break;
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
// Check for disallowed list of fields (e.g. address, phone, etc.) only if the input node is not already masked
|
|
1915
|
+
if (tag === "INPUT" /* InputTag */) {
|
|
1916
|
+
if (privacy === 0 /* None */) {
|
|
1917
|
+
var field = "" /* Empty */;
|
|
1918
|
+
// Be aggressive in looking up any attribute (id, class, name, etc.) for disallowed names
|
|
1919
|
+
for (var _a = 0, _b = Object.keys(attributes); _a < _b.length; _a++) {
|
|
1920
|
+
var attribute = _b[_a];
|
|
1921
|
+
field += attributes[attribute].toLowerCase();
|
|
1922
|
+
}
|
|
1923
|
+
for (var _c = 0, DISALLOWED_NAMES_1 = DISALLOWED_NAMES; _c < DISALLOWED_NAMES_1.length; _c++) {
|
|
1924
|
+
var name_1 = DISALLOWED_NAMES_1[_c];
|
|
1925
|
+
if (field.indexOf(name_1) >= 0) {
|
|
1926
|
+
privacy = 2 /* Text */;
|
|
1927
|
+
break;
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
else if (privacy === 1 /* Sensitive */) {
|
|
1932
|
+
// Mask all input fields with an exception of type=submit; since they do not accept user input
|
|
1933
|
+
privacy = attributes && attributes["type" /* Type */] === "submit" /* Submit */ ? 0 /* None */ : 2 /* Text */;
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
// Check for disallowed list of types (e.g. password, email, etc.) and set the masked property appropriately
|
|
1937
|
+
if ("type" /* Type */ in attributes && DISALLOWED_TYPES.indexOf(attributes["type" /* Type */]) >= 0) {
|
|
1938
|
+
privacy = 2 /* Text */;
|
|
1939
|
+
}
|
|
1940
|
+
// Following two conditions supersede any of the above. If there are explicit instructions to mask / unmask a field, we honor that.
|
|
1941
|
+
if ("data-clarity-mask" /* MaskData */ in attributes) {
|
|
1942
|
+
privacy = 3 /* TextImage */;
|
|
1943
|
+
}
|
|
1944
|
+
if ("data-clarity-unmask" /* UnmaskData */ in attributes) {
|
|
1945
|
+
privacy = 0 /* None */;
|
|
1946
|
+
}
|
|
1947
|
+
// If it's a text node belonging to a STYLE or TITLE tag; then reset the privacy setting to ensure we capture the content
|
|
1948
|
+
var cTag = tag === "*T" /* TextTag */ ? parentTag : tag;
|
|
1949
|
+
if (cTag === "STYLE" /* StyleTag */ || cTag === "TITLE" /* TitleTag */) {
|
|
1950
|
+
privacy = 0 /* None */;
|
|
1951
|
+
}
|
|
1952
|
+
return privacy;
|
|
1953
|
+
}
|
|
1954
|
+
function diff(a, b, field) {
|
|
1955
|
+
if (typeof a[field] === "object" && typeof b[field] === "object") {
|
|
1956
|
+
for (var key in a[field]) {
|
|
1957
|
+
if (a[field][key] !== b[field][key]) {
|
|
1958
|
+
return true;
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
for (var key in b[field]) {
|
|
1962
|
+
if (b[field][key] !== a[field][key]) {
|
|
1963
|
+
return true;
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return false;
|
|
1967
|
+
}
|
|
1968
|
+
return a[field] !== b[field];
|
|
1969
|
+
}
|
|
1970
|
+
function position(parent, child) {
|
|
1971
|
+
var tag = child.data.tag;
|
|
1972
|
+
var hasClassName = child.data.attributes && !("class" /* Class */ in child.data.attributes);
|
|
1973
|
+
// Find relative position of the element to generate :nth-of-type selector
|
|
1974
|
+
// We restrict relative positioning to two cases:
|
|
1975
|
+
// a) For specific whitelist of tags
|
|
1976
|
+
// b) And, for remaining tags, only if they don't have a valid class name
|
|
1977
|
+
if (parent && (["DIV", "TR", "P", "LI", "UL", "A", "BUTTON"].indexOf(tag) >= 0 || hasClassName)) {
|
|
1978
|
+
child.position = 1;
|
|
1979
|
+
var idx = parent ? parent.children.indexOf(child.id) : -1;
|
|
1980
|
+
while (idx-- > 0) {
|
|
1981
|
+
var sibling = values[parent.children[idx]];
|
|
1982
|
+
if (child.data.tag === sibling.data.tag) {
|
|
1983
|
+
child.position = sibling.position + 1;
|
|
1984
|
+
break;
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
return child.position;
|
|
1989
|
+
}
|
|
1990
|
+
function updateSelector(value) {
|
|
1991
|
+
var parent = value.parent && value.parent in values ? values[value.parent] : null;
|
|
1992
|
+
var prefix = parent ? parent.selector + ">" : null;
|
|
1993
|
+
var ex = value.selector;
|
|
1994
|
+
var current = selector(value.data.tag, prefix, value.data.attributes, position(parent, value));
|
|
1995
|
+
if (current !== ex && selectorMap.indexOf(value.id) === -1) {
|
|
1996
|
+
selectorMap.push(value.id);
|
|
1997
|
+
}
|
|
1998
|
+
value.selector = current;
|
|
1999
|
+
}
|
|
2000
|
+
function getNode(id) {
|
|
2001
|
+
if (id in nodes) {
|
|
2002
|
+
return nodes[id];
|
|
2003
|
+
}
|
|
2004
|
+
return null;
|
|
2005
|
+
}
|
|
2006
|
+
function getMatch(url) {
|
|
2007
|
+
if (url in urlMap) {
|
|
2008
|
+
return getNode(urlMap[url]);
|
|
2009
|
+
}
|
|
2010
|
+
return null;
|
|
2011
|
+
}
|
|
2012
|
+
function getValue(id) {
|
|
2013
|
+
if (id in values) {
|
|
2014
|
+
return values[id];
|
|
2015
|
+
}
|
|
2016
|
+
return null;
|
|
2017
|
+
}
|
|
2018
|
+
function get(node) {
|
|
2019
|
+
var id = getId(node);
|
|
2020
|
+
return id in values ? values[id] : null;
|
|
2021
|
+
}
|
|
2022
|
+
function has(node) {
|
|
2023
|
+
return getId(node) in nodes;
|
|
2024
|
+
}
|
|
2025
|
+
function updates$2() {
|
|
2026
|
+
var output = [];
|
|
2027
|
+
for (var _i = 0, updateMap_1 = updateMap; _i < updateMap_1.length; _i++) {
|
|
2028
|
+
var id = updateMap_1[_i];
|
|
2029
|
+
if (id in values) {
|
|
2030
|
+
var v = values[id];
|
|
2031
|
+
var p = v.parent;
|
|
2032
|
+
v.data.path = p === null || updateMap.indexOf(p) >= 0 || v.selector.length === 0 ? null : values[p].selector;
|
|
2033
|
+
output.push(values[id]);
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
updateMap = [];
|
|
2037
|
+
return output;
|
|
2038
|
+
}
|
|
2039
|
+
function remove(id, source) {
|
|
2040
|
+
if (id in values) {
|
|
2041
|
+
var value = values[id];
|
|
2042
|
+
value.metadata.active = false;
|
|
2043
|
+
value.parent = null;
|
|
2044
|
+
track$4(id, source);
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
function size(value, parent) {
|
|
2048
|
+
var data = value.data;
|
|
2049
|
+
var tag = data.tag;
|
|
2050
|
+
// If this element is a text node, is masked, and longer than configured length, then track box model for the parent element
|
|
2051
|
+
var isLongText = tag === "*T" /* TextTag */ && data.value && data.value.length > 15 /* ResizeObserverThreshold */;
|
|
2052
|
+
var isMasked = value.metadata.privacy === 2 /* Text */ || value.metadata.privacy === 3 /* TextImage */;
|
|
2053
|
+
if (isLongText && isMasked && parent && parent.metadata.size === null) {
|
|
2054
|
+
parent.metadata.size = [];
|
|
2055
|
+
}
|
|
2056
|
+
// If this element is a image node, and is masked, then track box model for the current element
|
|
2057
|
+
if (data.tag === "IMG" /* ImageTag */ && value.metadata.privacy === 3 /* TextImage */) {
|
|
2058
|
+
value.metadata.size = [];
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
function metadata$1(tag, id, parentId) {
|
|
2062
|
+
if (id !== null && parentId !== null) {
|
|
2063
|
+
var value = values[id];
|
|
2064
|
+
var attributes = "attributes" in value.data ? value.data.attributes : {};
|
|
2065
|
+
switch (tag) {
|
|
2066
|
+
case "VIDEO":
|
|
2067
|
+
case "AUDIO":
|
|
2068
|
+
case "LINK":
|
|
2069
|
+
// Track mapping between URL and corresponding nodes
|
|
2070
|
+
if ("href" /* Href */ in attributes && attributes["href" /* Href */].length > 0) {
|
|
2071
|
+
urlMap[getFullUrl(attributes["href" /* Href */])] = id;
|
|
2072
|
+
}
|
|
2073
|
+
if ("src" /* Src */ in attributes && attributes["src" /* Src */].length > 0) {
|
|
2074
|
+
if (attributes["src" /* Src */].indexOf("data:" /* DataPrefix */) !== 0) {
|
|
2075
|
+
urlMap[getFullUrl(attributes["src" /* Src */])] = id;
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
if ("srcset" /* Srcset */ in attributes && attributes["srcset" /* Srcset */].length > 0) {
|
|
2079
|
+
var srcset = attributes["srcset" /* Srcset */];
|
|
2080
|
+
var urls = srcset.split(",");
|
|
2081
|
+
for (var _i = 0, urls_1 = urls; _i < urls_1.length; _i++) {
|
|
2082
|
+
var u = urls_1[_i];
|
|
2083
|
+
var parts = u.trim().split(" ");
|
|
2084
|
+
if (parts.length === 2 && parts[0].length > 0) {
|
|
2085
|
+
urlMap[getFullUrl(parts[0])] = id;
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
break;
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
function getFullUrl(relative) {
|
|
2094
|
+
var a = document.createElement("a");
|
|
2095
|
+
a.href = relative;
|
|
2096
|
+
return a.href;
|
|
2097
|
+
}
|
|
2098
|
+
function getPreviousId(node) {
|
|
2099
|
+
var id = null;
|
|
2100
|
+
// Some nodes may not have an ID by design since Clarity skips over tags like SCRIPT, NOSCRIPT, META, COMMENTS, etc..
|
|
2101
|
+
// In that case, we keep going back and check for their sibling until we find a sibling with ID or no more sibling nodes are left.
|
|
2102
|
+
while (id === null && node.previousSibling) {
|
|
2103
|
+
id = getId(node.previousSibling);
|
|
2104
|
+
node = node.previousSibling;
|
|
2105
|
+
}
|
|
2106
|
+
return id;
|
|
2107
|
+
}
|
|
2108
|
+
function copy(input) {
|
|
2109
|
+
return JSON.parse(JSON.stringify(input));
|
|
2110
|
+
}
|
|
2111
|
+
function track$4(id, source, changed, parentChanged) {
|
|
2112
|
+
if (changed === void 0) { changed = true; }
|
|
2113
|
+
if (parentChanged === void 0) { parentChanged = false; }
|
|
2114
|
+
// Keep track of the order in which mutations happened, they may not be sequential
|
|
2115
|
+
// Edge case: If an element is added later on, and pre-discovered element is moved as a child.
|
|
2116
|
+
// In that case, we need to reorder the pre-discovered element in the update list to keep visualization consistent.
|
|
2117
|
+
var uIndex = updateMap.indexOf(id);
|
|
2118
|
+
if (uIndex >= 0 && source === 1 /* ChildListAdd */ && parentChanged) {
|
|
2119
|
+
updateMap.splice(uIndex, 1);
|
|
2120
|
+
updateMap.push(id);
|
|
2121
|
+
}
|
|
2122
|
+
else if (uIndex === -1 && changed) {
|
|
2123
|
+
updateMap.push(id);
|
|
2124
|
+
}
|
|
2125
|
+
if ("__CLARITY_DEVTOOLS_HOOK__" /* DevHook */ in window) {
|
|
2126
|
+
var value = copy([values[id]])[0];
|
|
2127
|
+
var change = { time: time(), source: source, value: value };
|
|
2128
|
+
if (!(id in changes)) {
|
|
2129
|
+
changes[id] = [];
|
|
2130
|
+
}
|
|
2131
|
+
changes[id].push(change);
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
function history$2(id) {
|
|
2135
|
+
if (id in changes) {
|
|
2136
|
+
return changes[id];
|
|
2137
|
+
}
|
|
2138
|
+
return [];
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
var dom = /*#__PURE__*/Object.freeze({
|
|
2142
|
+
__proto__: null,
|
|
2143
|
+
start: start$n,
|
|
2144
|
+
stop: stop$m,
|
|
2145
|
+
parse: parse,
|
|
2146
|
+
getId: getId,
|
|
2147
|
+
add: add,
|
|
2148
|
+
update: update,
|
|
2149
|
+
sameorigin: sameorigin,
|
|
2150
|
+
iframe: iframe,
|
|
2151
|
+
getNode: getNode,
|
|
2152
|
+
getMatch: getMatch,
|
|
2153
|
+
getValue: getValue,
|
|
2154
|
+
get: get,
|
|
2155
|
+
has: has,
|
|
2156
|
+
updates: updates$2
|
|
2157
|
+
});
|
|
2158
|
+
|
|
2159
|
+
var state$5 = [];
|
|
2160
|
+
var regionMap = null; // Maps region nodes => region name
|
|
2161
|
+
var regions = {};
|
|
2162
|
+
var queue$2 = [];
|
|
2163
|
+
var watch = false;
|
|
2164
|
+
var observer$1 = null;
|
|
2165
|
+
function start$m() {
|
|
2166
|
+
reset$d();
|
|
2167
|
+
observer$1 = null;
|
|
2168
|
+
regionMap = new WeakMap();
|
|
2169
|
+
regions = {};
|
|
2170
|
+
queue$2 = [];
|
|
2171
|
+
watch = window["IntersectionObserver"] ? true : false;
|
|
2172
|
+
}
|
|
2173
|
+
function observe$9(node, name) {
|
|
2174
|
+
if (regionMap.has(node) === false) {
|
|
2175
|
+
regionMap.set(node, name);
|
|
2176
|
+
observer$1 = observer$1 === null && watch ? new IntersectionObserver(handler$2, {
|
|
2177
|
+
// Get notified as intersection continues to change
|
|
2178
|
+
// This allows us to process regions that get partially hidden during the lifetime of the page
|
|
2179
|
+
// See: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#creating_an_intersection_observer
|
|
2180
|
+
// By default, intersection observers only fire an event when even a single pixel is visible and not thereafter.
|
|
2181
|
+
threshold: [0, 0.2, 0.4, 0.6, 0.8, 1]
|
|
2182
|
+
}) : observer$1;
|
|
2183
|
+
if (observer$1 && node && node.nodeType === Node.ELEMENT_NODE) {
|
|
2184
|
+
observer$1.observe(node);
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
function exists(node) {
|
|
2189
|
+
// Check if regionMap is not null before looking up a node
|
|
2190
|
+
// Since, dom module stops after region module, it's possible that we may set regionMap to be null
|
|
2191
|
+
// and still attempt to call exists on a late coming DOM mutation (or addition), effectively causing a script error
|
|
2192
|
+
return regionMap && regionMap.has(node);
|
|
2193
|
+
}
|
|
2194
|
+
function track$3(id, event) {
|
|
2195
|
+
var node = getNode(id);
|
|
2196
|
+
var data = id in regions ? regions[id] : { id: id, state: 0 /* Rendered */, name: regionMap.get(node) };
|
|
2197
|
+
// Determine the interaction state based on incoming event
|
|
2198
|
+
var interactionState = 0 /* Rendered */;
|
|
2199
|
+
switch (event) {
|
|
2200
|
+
case 9 /* Click */:
|
|
2201
|
+
interactionState = 20 /* Clicked */;
|
|
2202
|
+
break;
|
|
2203
|
+
case 27 /* Input */:
|
|
2204
|
+
interactionState = 30 /* Input */;
|
|
2205
|
+
break;
|
|
2206
|
+
}
|
|
2207
|
+
// Process updates to this region, if applicable
|
|
2208
|
+
process$6(node, data, interactionState);
|
|
2209
|
+
}
|
|
2210
|
+
function compute$4() {
|
|
2211
|
+
// Process any regions where we couldn't resolve an "id" for at the time of last intersection observer event
|
|
2212
|
+
// This could happen in cases where elements are not yet processed by Clarity's virtual DOM but browser reports a change, regardless.
|
|
2213
|
+
// For those cases we add them to the queue and re-process them below
|
|
2214
|
+
var q = [];
|
|
2215
|
+
for (var _i = 0, queue_1 = queue$2; _i < queue_1.length; _i++) {
|
|
2216
|
+
var r = queue_1[_i];
|
|
2217
|
+
var id = getId(r.node);
|
|
2218
|
+
if (!(id in regions)) {
|
|
2219
|
+
if (id) {
|
|
2220
|
+
r.data.id = id;
|
|
2221
|
+
regions[id] = r.data;
|
|
2222
|
+
state$5.push(clone(r.data));
|
|
2223
|
+
}
|
|
2224
|
+
else {
|
|
2225
|
+
q.push(r);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
queue$2 = q;
|
|
2230
|
+
// Schedule encode only when we have at least one valid data entry
|
|
2231
|
+
if (state$5.length > 0) {
|
|
2232
|
+
encode$4(7 /* Region */);
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
function handler$2(entries) {
|
|
2236
|
+
for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
|
|
2237
|
+
var entry = entries_1[_i];
|
|
2238
|
+
var target = entry.target;
|
|
2239
|
+
var rect = entry.boundingClientRect;
|
|
2240
|
+
var overlap = entry.intersectionRect;
|
|
2241
|
+
var viewport = entry.rootBounds;
|
|
2242
|
+
// Only capture regions that have non-zero width or height to avoid tracking and sending regions
|
|
2243
|
+
// that cannot ever be seen by the user. In some cases, websites will have a multiple copy of the same region
|
|
2244
|
+
// like search box - one for desktop, and another for mobile. In those cases, CSS media queries determine which one should be visible.
|
|
2245
|
+
// Also, if these regions ever become non-zero width or height (through AJAX, user action or orientation change) - we will automatically start monitoring them from that point onwards
|
|
2246
|
+
if (regionMap.has(target) && rect.width + rect.height > 0 && viewport.width > 0 && viewport.height > 0) {
|
|
2247
|
+
var id = target ? getId(target) : null;
|
|
2248
|
+
var data = id in regions ? regions[id] : { id: id, name: regionMap.get(target), state: 0 /* Rendered */ };
|
|
2249
|
+
// For regions that have relatively smaller area, we look at intersection ratio and see the overlap relative to element's area
|
|
2250
|
+
// However, for larger regions, area of regions could be bigger than viewport and therefore comparison is relative to visible area
|
|
2251
|
+
var viewportRatio = overlap ? (overlap.width * overlap.height * 1.0) / (viewport.width * viewport.height) : 0;
|
|
2252
|
+
var visible = viewportRatio > 0.25 /* ViewportIntersectionRatio */ || entry.intersectionRatio > 0.8 /* IntersectionRatio */;
|
|
2253
|
+
// Process updates to this region, if applicable
|
|
2254
|
+
process$6(target, data, visible ? 10 /* Visible */ : 0 /* Rendered */);
|
|
2255
|
+
// Stop observing this element now that we have already received visibility signal
|
|
2256
|
+
if (data.state >= 10 /* Visible */ && observer$1) {
|
|
2257
|
+
observer$1.unobserve(target);
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
if (state$5.length > 0) {
|
|
2262
|
+
encode$4(7 /* Region */);
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
function process$6(n, d, s) {
|
|
2266
|
+
// Check if received a state that supersedes existing state
|
|
2267
|
+
var updated = s > d.state;
|
|
2268
|
+
d.state = updated ? s : d.state;
|
|
2269
|
+
// If the corresponding node is already discovered, update the internal state
|
|
2270
|
+
// Otherwise, track it in a queue to reprocess later.
|
|
2271
|
+
if (d.id) {
|
|
2272
|
+
if ((d.id in regions && updated) || !(d.id in regions)) {
|
|
2273
|
+
regions[d.id] = d;
|
|
2274
|
+
state$5.push(clone(d));
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
else {
|
|
2278
|
+
queue$2.push({ node: n, data: d });
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
function clone(r) {
|
|
2282
|
+
return { time: time(), data: { id: r.id, state: r.state, name: r.name } };
|
|
2283
|
+
}
|
|
2284
|
+
function reset$d() {
|
|
2285
|
+
state$5 = [];
|
|
2286
|
+
}
|
|
2287
|
+
function stop$l() {
|
|
2288
|
+
reset$d();
|
|
2289
|
+
regionMap = null;
|
|
2290
|
+
regions = {};
|
|
2291
|
+
queue$2 = [];
|
|
2292
|
+
if (observer$1) {
|
|
2293
|
+
observer$1.disconnect();
|
|
2294
|
+
observer$1 = null;
|
|
2295
|
+
}
|
|
2296
|
+
watch = false;
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
function offset (element) {
|
|
2300
|
+
var output = { x: 0, y: 0 };
|
|
2301
|
+
// Walk up the chain to ensure we compute offset distance correctly
|
|
2302
|
+
// In case where we may have nested IFRAMEs, we keep walking up until we get to the top most parent page
|
|
2303
|
+
if (element && element.offsetParent) {
|
|
2304
|
+
do {
|
|
2305
|
+
var parent_1 = element.offsetParent;
|
|
2306
|
+
var frame = parent_1 === null ? iframe(element.ownerDocument) : null;
|
|
2307
|
+
output.x += element.offsetLeft;
|
|
2308
|
+
output.y += element.offsetTop;
|
|
2309
|
+
element = frame ? frame : parent_1;
|
|
2310
|
+
} while (element);
|
|
2311
|
+
}
|
|
2312
|
+
return output;
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
var UserInputTags = ["input", "textarea", "radio", "button", "canvas"];
|
|
2316
|
+
var state$4 = [];
|
|
2317
|
+
function start$l() {
|
|
2318
|
+
reset$c();
|
|
2319
|
+
}
|
|
2320
|
+
function observe$8(root) {
|
|
2321
|
+
bind(root, "click", handler$1.bind(this, 9 /* Click */, root), true);
|
|
2322
|
+
}
|
|
2323
|
+
function handler$1(event, root, evt) {
|
|
2324
|
+
var frame = iframe(root);
|
|
2325
|
+
var d = frame ? frame.contentDocument.documentElement : document.documentElement;
|
|
2326
|
+
var x = "pageX" in evt ? Math.round(evt.pageX) : ("clientX" in evt ? Math.round(evt["clientX"] + d.scrollLeft) : null);
|
|
2327
|
+
var y = "pageY" in evt ? Math.round(evt.pageY) : ("clientY" in evt ? Math.round(evt["clientY"] + d.scrollTop) : null);
|
|
2328
|
+
// In case of iframe, we adjust (x,y) to be relative to top parent's origin
|
|
2329
|
+
if (frame) {
|
|
2330
|
+
var distance = offset(frame);
|
|
2331
|
+
x = x ? x + Math.round(distance.x) : x;
|
|
2332
|
+
y = y ? y + Math.round(distance.y) : y;
|
|
2333
|
+
}
|
|
2334
|
+
var t = target(evt);
|
|
2335
|
+
// Find nearest anchor tag (<a/>) parent if current target node is part of one
|
|
2336
|
+
// If present, we use the returned link element to populate text and link properties below
|
|
2337
|
+
var a = link(t);
|
|
2338
|
+
// Get layout rectangle for the target element
|
|
2339
|
+
var l = layout$1(t);
|
|
2340
|
+
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
|
|
2341
|
+
// This property helps differentiate between a keyboard navigation vs. pointer click
|
|
2342
|
+
// In case of a keyboard navigation, we use center of target element as (x,y)
|
|
2343
|
+
if (evt.detail === 0 && l) {
|
|
2344
|
+
x = Math.round(l.x + (l.w / 2));
|
|
2345
|
+
y = Math.round(l.y + (l.h / 2));
|
|
2346
|
+
}
|
|
2347
|
+
var eX = l ? Math.max(Math.floor(((x - l.x) / l.w) * 32767 /* ClickPrecision */), 0) : 0;
|
|
2348
|
+
var eY = l ? Math.max(Math.floor(((y - l.y) / l.h) * 32767 /* ClickPrecision */), 0) : 0;
|
|
2349
|
+
// Check for null values before processing this event
|
|
2350
|
+
if (x !== null && y !== null) {
|
|
2351
|
+
state$4.push({
|
|
2352
|
+
time: time(),
|
|
2353
|
+
event: event, data: {
|
|
2354
|
+
target: t,
|
|
2355
|
+
x: x,
|
|
2356
|
+
y: y,
|
|
2357
|
+
eX: eX,
|
|
2358
|
+
eY: eY,
|
|
2359
|
+
button: evt.button,
|
|
2360
|
+
reaction: reaction(t),
|
|
2361
|
+
context: context(a),
|
|
2362
|
+
text: text(t),
|
|
2363
|
+
link: a ? a.href : null,
|
|
2364
|
+
hash: null
|
|
2365
|
+
}
|
|
2366
|
+
});
|
|
2367
|
+
schedule$1(encode$2.bind(this, event));
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
function text(element) {
|
|
2371
|
+
var output = null;
|
|
2372
|
+
if (element) {
|
|
2373
|
+
// Grab text using "textContent" for most HTMLElements, however, use "value" for HTMLInputElements and "alt" for HTMLImageElement.
|
|
2374
|
+
var t = element.textContent || element.value || element.alt;
|
|
2375
|
+
if (t) {
|
|
2376
|
+
// Trim any spaces at the beginning or at the end of string
|
|
2377
|
+
// Also, replace multiple occurrence of space characters with a single white space
|
|
2378
|
+
// Finally, send only first few characters as specified by the Setting
|
|
2379
|
+
output = t.trim().replace(/\s+/g, " " /* Space */).substr(0, 25 /* ClickText */);
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
return output;
|
|
2383
|
+
}
|
|
2384
|
+
function reaction(element) {
|
|
2385
|
+
if (element.nodeType === Node.ELEMENT_NODE) {
|
|
2386
|
+
var tag = element.tagName.toLowerCase();
|
|
2387
|
+
if (UserInputTags.indexOf(tag) >= 0) {
|
|
2388
|
+
return 0 /* False */;
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
return 1 /* True */;
|
|
2392
|
+
}
|
|
2393
|
+
function layout$1(element) {
|
|
2394
|
+
var box = null;
|
|
2395
|
+
var de = document.documentElement;
|
|
2396
|
+
if (typeof element.getBoundingClientRect === "function") {
|
|
2397
|
+
// getBoundingClientRect returns rectangle relative positioning to viewport
|
|
2398
|
+
var rect = element.getBoundingClientRect();
|
|
2399
|
+
if (rect && rect.width > 0 && rect.height > 0) {
|
|
2400
|
+
// Add viewport's scroll position to rectangle to get position relative to document origin
|
|
2401
|
+
// Also: using Math.floor() instead of Math.round() because in Edge,
|
|
2402
|
+
// getBoundingClientRect returns partial pixel values (e.g. 162.5px) and Chrome already
|
|
2403
|
+
// floors the value (e.g. 162px). This keeps consistent behavior across browsers.
|
|
2404
|
+
box = {
|
|
2405
|
+
x: Math.floor(rect.left + ("pageXOffset" in window ? window.pageXOffset : de.scrollLeft)),
|
|
2406
|
+
y: Math.floor(rect.top + ("pageYOffset" in window ? window.pageYOffset : de.scrollTop)),
|
|
2407
|
+
w: Math.floor(rect.width),
|
|
2408
|
+
h: Math.floor(rect.height)
|
|
2409
|
+
};
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
return box;
|
|
2413
|
+
}
|
|
2414
|
+
function context(a) {
|
|
2415
|
+
if (a && a.hasAttribute("target" /* Target */)) {
|
|
2416
|
+
switch (a.getAttribute("target" /* Target */)) {
|
|
2417
|
+
case "_blank" /* Blank */: return 1 /* Blank */;
|
|
2418
|
+
case "_parent" /* Parent */: return 2 /* Parent */;
|
|
2419
|
+
case "_top" /* Top */: return 3 /* Top */;
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
return 0 /* Self */;
|
|
2423
|
+
}
|
|
2424
|
+
function reset$c() {
|
|
2425
|
+
state$4 = [];
|
|
2426
|
+
}
|
|
2427
|
+
function stop$k() {
|
|
2428
|
+
reset$c();
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
var timeout$5 = null;
|
|
2432
|
+
var state$3 = [];
|
|
2433
|
+
function start$k() {
|
|
2434
|
+
reset$b();
|
|
2435
|
+
}
|
|
2436
|
+
function observe$7(root) {
|
|
2437
|
+
bind(root, "input", recompute$6, true);
|
|
2438
|
+
}
|
|
2439
|
+
function recompute$6(evt) {
|
|
2440
|
+
var input = target(evt);
|
|
2441
|
+
var value = get(input);
|
|
2442
|
+
if (input && input.type && value) {
|
|
2443
|
+
var v = void 0;
|
|
2444
|
+
switch (input.type) {
|
|
2445
|
+
case "radio":
|
|
2446
|
+
case "checkbox":
|
|
2447
|
+
v = input.checked ? "true" : "false";
|
|
2448
|
+
break;
|
|
2449
|
+
case "range":
|
|
2450
|
+
v = input.value;
|
|
2451
|
+
break;
|
|
2452
|
+
default:
|
|
2453
|
+
v = scrub(input.value, "input", value.metadata.privacy);
|
|
2454
|
+
break;
|
|
2455
|
+
}
|
|
2456
|
+
var data = { target: input, value: v };
|
|
2457
|
+
// If last entry in the queue is for the same target node as the current one, remove it so we can later swap it with current data.
|
|
2458
|
+
if (state$3.length > 0 && (state$3[state$3.length - 1].data.target === data.target)) {
|
|
2459
|
+
state$3.pop();
|
|
2460
|
+
}
|
|
2461
|
+
state$3.push({ time: time(), event: 27 /* Input */, data: data });
|
|
2462
|
+
clearTimeout(timeout$5);
|
|
2463
|
+
timeout$5 = setTimeout(process$5, 500 /* LookAhead */, 27 /* Input */);
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
function process$5(event) {
|
|
2467
|
+
schedule$1(encode$2.bind(this, event));
|
|
2468
|
+
}
|
|
2469
|
+
function reset$b() {
|
|
2470
|
+
state$3 = [];
|
|
2471
|
+
}
|
|
2472
|
+
function stop$j() {
|
|
2473
|
+
clearTimeout(timeout$5);
|
|
2474
|
+
reset$b();
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
var state$2 = [];
|
|
2478
|
+
var timeout$4 = null;
|
|
2479
|
+
function start$j() {
|
|
2480
|
+
reset$a();
|
|
2481
|
+
}
|
|
2482
|
+
function observe$6(root) {
|
|
2483
|
+
bind(root, "mousedown", mouse.bind(this, 13 /* MouseDown */, root), true);
|
|
2484
|
+
bind(root, "mouseup", mouse.bind(this, 14 /* MouseUp */, root), true);
|
|
2485
|
+
bind(root, "mousemove", mouse.bind(this, 12 /* MouseMove */, root), true);
|
|
2486
|
+
bind(root, "mousewheel", mouse.bind(this, 15 /* MouseWheel */, root), true);
|
|
2487
|
+
bind(root, "dblclick", mouse.bind(this, 16 /* DoubleClick */, root), true);
|
|
2488
|
+
bind(root, "touchstart", touch.bind(this, 17 /* TouchStart */, root), true);
|
|
2489
|
+
bind(root, "touchend", touch.bind(this, 18 /* TouchEnd */, root), true);
|
|
2490
|
+
bind(root, "touchmove", touch.bind(this, 19 /* TouchMove */, root), true);
|
|
2491
|
+
bind(root, "touchcancel", touch.bind(this, 20 /* TouchCancel */, root), true);
|
|
2492
|
+
}
|
|
2493
|
+
function mouse(event, root, evt) {
|
|
2494
|
+
var frame = iframe(root);
|
|
2495
|
+
var d = frame ? frame.contentDocument.documentElement : document.documentElement;
|
|
2496
|
+
var x = "pageX" in evt ? Math.round(evt.pageX) : ("clientX" in evt ? Math.round(evt["clientX"] + d.scrollLeft) : null);
|
|
2497
|
+
var y = "pageY" in evt ? Math.round(evt.pageY) : ("clientY" in evt ? Math.round(evt["clientY"] + d.scrollTop) : null);
|
|
2498
|
+
// In case of iframe, we adjust (x,y) to be relative to top parent's origin
|
|
2499
|
+
if (frame) {
|
|
2500
|
+
var distance = offset(frame);
|
|
2501
|
+
x = x ? x + Math.round(distance.x) : x;
|
|
2502
|
+
y = y ? y + Math.round(distance.y) : y;
|
|
2503
|
+
}
|
|
2504
|
+
// Check for null values before processing this event
|
|
2505
|
+
if (x !== null && y !== null) {
|
|
2506
|
+
handler({ time: time(), event: event, data: { target: target(evt), x: x, y: y } });
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
function touch(event, root, evt) {
|
|
2510
|
+
var frame = iframe(root);
|
|
2511
|
+
var d = frame ? frame.contentDocument.documentElement : document.documentElement;
|
|
2512
|
+
var touches = evt.changedTouches;
|
|
2513
|
+
var t = time();
|
|
2514
|
+
if (touches) {
|
|
2515
|
+
for (var i = 0; i < touches.length; i++) {
|
|
2516
|
+
var entry = touches[i];
|
|
2517
|
+
var x = "clientX" in entry ? Math.round(entry["clientX"] + d.scrollLeft) : null;
|
|
2518
|
+
var y = "clientY" in entry ? Math.round(entry["clientY"] + d.scrollTop) : null;
|
|
2519
|
+
x = x && frame ? x + Math.round(frame.offsetLeft) : x;
|
|
2520
|
+
y = y && frame ? y + Math.round(frame.offsetTop) : y;
|
|
2521
|
+
// Check for null values before processing this event
|
|
2522
|
+
if (x !== null && y !== null) {
|
|
2523
|
+
handler({ time: t, event: event, data: { target: target(evt), x: x, y: y } });
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
function handler(current) {
|
|
2529
|
+
switch (current.event) {
|
|
2530
|
+
case 12 /* MouseMove */:
|
|
2531
|
+
case 15 /* MouseWheel */:
|
|
2532
|
+
case 19 /* TouchMove */:
|
|
2533
|
+
var length_1 = state$2.length;
|
|
2534
|
+
var last = length_1 > 1 ? state$2[length_1 - 2] : null;
|
|
2535
|
+
if (last && similar$1(last, current)) {
|
|
2536
|
+
state$2.pop();
|
|
2537
|
+
}
|
|
2538
|
+
state$2.push(current);
|
|
2539
|
+
clearTimeout(timeout$4);
|
|
2540
|
+
timeout$4 = setTimeout(process$4, 500 /* LookAhead */, current.event);
|
|
2541
|
+
break;
|
|
2542
|
+
default:
|
|
2543
|
+
state$2.push(current);
|
|
2544
|
+
process$4(current.event);
|
|
2545
|
+
break;
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
function process$4(event) {
|
|
2549
|
+
schedule$1(encode$2.bind(this, event));
|
|
2550
|
+
}
|
|
2551
|
+
function reset$a() {
|
|
2552
|
+
state$2 = [];
|
|
2553
|
+
}
|
|
2554
|
+
function similar$1(last, current) {
|
|
2555
|
+
var dx = last.data.x - current.data.x;
|
|
2556
|
+
var dy = last.data.y - current.data.y;
|
|
2557
|
+
var distance = Math.sqrt(dx * dx + dy * dy);
|
|
2558
|
+
var gap = current.time - last.time;
|
|
2559
|
+
var match = current.data.target === last.data.target;
|
|
2560
|
+
return current.event === last.event && match && distance < 20 /* Distance */ && gap < 25 /* Interval */;
|
|
2561
|
+
}
|
|
2562
|
+
function stop$i() {
|
|
2563
|
+
clearTimeout(timeout$4);
|
|
2564
|
+
// Send out any pending pointer events in the pipeline
|
|
2565
|
+
if (state$2.length > 0) {
|
|
2566
|
+
process$4(state$2[state$2.length - 1].event);
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
var data$6;
|
|
2571
|
+
function start$i() {
|
|
2572
|
+
bind(window, "resize", recompute$5);
|
|
2573
|
+
recompute$5();
|
|
2574
|
+
}
|
|
2575
|
+
function recompute$5() {
|
|
2576
|
+
var de = document.documentElement;
|
|
2577
|
+
// window.innerWidth includes width of the scrollbar and is not a true representation of the viewport width.
|
|
2578
|
+
// Therefore, when possible, use documentElement's clientWidth property.
|
|
2579
|
+
data$6 = {
|
|
2580
|
+
width: de && "clientWidth" in de ? Math.min(de.clientWidth, window.innerWidth) : window.innerWidth,
|
|
2581
|
+
height: de && "clientHeight" in de ? Math.min(de.clientHeight, window.innerHeight) : window.innerHeight,
|
|
2582
|
+
};
|
|
2583
|
+
encode$2(11 /* Resize */);
|
|
2584
|
+
}
|
|
2585
|
+
function reset$9() {
|
|
2586
|
+
data$6 = null;
|
|
2587
|
+
}
|
|
2588
|
+
function stop$h() {
|
|
2589
|
+
reset$9();
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2592
|
+
var state$1 = [];
|
|
2593
|
+
var timeout$3 = null;
|
|
2594
|
+
function start$h() {
|
|
2595
|
+
state$1 = [];
|
|
2596
|
+
recompute$4();
|
|
2597
|
+
}
|
|
2598
|
+
function observe$5(root) {
|
|
2599
|
+
var frame = iframe(root);
|
|
2600
|
+
var node = frame ? frame.contentWindow : (root === document ? window : root);
|
|
2601
|
+
bind(node, "scroll", recompute$4, true);
|
|
2602
|
+
}
|
|
2603
|
+
function recompute$4(event) {
|
|
2604
|
+
if (event === void 0) { event = null; }
|
|
2605
|
+
var w = window;
|
|
2606
|
+
var de = document.documentElement;
|
|
2607
|
+
var element = event ? target(event) : de;
|
|
2608
|
+
// If the target is a Document node, then identify corresponding documentElement and window for this document
|
|
2609
|
+
if (element && element.nodeType === Node.DOCUMENT_NODE) {
|
|
2610
|
+
var frame = iframe(element);
|
|
2611
|
+
w = frame ? frame.contentWindow : w;
|
|
2612
|
+
element = de = element.documentElement;
|
|
2613
|
+
}
|
|
2614
|
+
// Edge doesn't support scrollTop position on document.documentElement.
|
|
2615
|
+
// For cross browser compatibility, looking up pageYOffset on window if the scroll is on document.
|
|
2616
|
+
// And, if for some reason that is not available, fall back to looking up scrollTop on document.documentElement.
|
|
2617
|
+
var x = element === de && "pageXOffset" in w ? Math.round(w.pageXOffset) : Math.round(element.scrollLeft);
|
|
2618
|
+
var y = element === de && "pageYOffset" in w ? Math.round(w.pageYOffset) : Math.round(element.scrollTop);
|
|
2619
|
+
var current = { time: time(), event: 10 /* Scroll */, data: { target: element, x: x, y: y } };
|
|
2620
|
+
// We don't send any scroll events if this is the first event and the current position is top (0,0)
|
|
2621
|
+
if ((event === null && x === 0 && y === 0) || (x === null || y === null)) {
|
|
2622
|
+
return;
|
|
2623
|
+
}
|
|
2624
|
+
var length = state$1.length;
|
|
2625
|
+
var last = length > 1 ? state$1[length - 2] : null;
|
|
2626
|
+
if (last && similar(last, current)) {
|
|
2627
|
+
state$1.pop();
|
|
2628
|
+
}
|
|
2629
|
+
state$1.push(current);
|
|
2630
|
+
clearTimeout(timeout$3);
|
|
2631
|
+
timeout$3 = setTimeout(process$3, 500 /* LookAhead */, 10 /* Scroll */);
|
|
2632
|
+
}
|
|
2633
|
+
function reset$8() {
|
|
2634
|
+
state$1 = [];
|
|
2635
|
+
}
|
|
2636
|
+
function process$3(event) {
|
|
2637
|
+
schedule$1(encode$2.bind(this, event));
|
|
2638
|
+
}
|
|
2639
|
+
function similar(last, current) {
|
|
2640
|
+
var dx = last.data.x - current.data.x;
|
|
2641
|
+
var dy = last.data.y - current.data.y;
|
|
2642
|
+
return (dx * dx + dy * dy < 20 /* Distance */ * 20 /* Distance */) && (current.time - last.time < 25 /* Interval */);
|
|
2643
|
+
}
|
|
2644
|
+
function stop$g() {
|
|
2645
|
+
clearTimeout(timeout$3);
|
|
2646
|
+
state$1 = [];
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
var data$5 = null;
|
|
2650
|
+
var previous = null;
|
|
2651
|
+
var timeout$2 = null;
|
|
2652
|
+
function start$g() {
|
|
2653
|
+
reset$7();
|
|
2654
|
+
}
|
|
2655
|
+
function observe$4(root) {
|
|
2656
|
+
bind(root, "selectstart", recompute$3.bind(this, root), true);
|
|
2657
|
+
bind(root, "selectionchange", recompute$3.bind(this, root), true);
|
|
2658
|
+
}
|
|
2659
|
+
function recompute$3(root) {
|
|
2660
|
+
var doc = root.nodeType === Node.DOCUMENT_NODE ? root : document;
|
|
2661
|
+
var current = doc.getSelection();
|
|
2662
|
+
// Bail out if we don't have a valid selection
|
|
2663
|
+
if (current === null) {
|
|
2664
|
+
return;
|
|
2665
|
+
}
|
|
2666
|
+
// Bail out if we got a valid selection but not valid nodes
|
|
2667
|
+
// In Edge, selectionchange gets fired even on interactions like right clicks and
|
|
2668
|
+
// can result in null anchorNode and focusNode if there was no previous selection on page
|
|
2669
|
+
// Also, ignore any selections that start and end at the exact same point
|
|
2670
|
+
if ((current.anchorNode === null && current.focusNode === null) ||
|
|
2671
|
+
(current.anchorNode === current.focusNode && current.anchorOffset === current.focusOffset)) {
|
|
2672
|
+
return;
|
|
2673
|
+
}
|
|
2674
|
+
var startNode = data$5.start ? data$5.start : null;
|
|
2675
|
+
if (previous !== null && data$5.start !== null && startNode !== current.anchorNode) {
|
|
2676
|
+
clearTimeout(timeout$2);
|
|
2677
|
+
process$2(21 /* Selection */);
|
|
2678
|
+
}
|
|
2679
|
+
data$5 = {
|
|
2680
|
+
start: current.anchorNode,
|
|
2681
|
+
startOffset: current.anchorOffset,
|
|
2682
|
+
end: current.focusNode,
|
|
2683
|
+
endOffset: current.focusOffset
|
|
2684
|
+
};
|
|
2685
|
+
previous = current;
|
|
2686
|
+
clearTimeout(timeout$2);
|
|
2687
|
+
timeout$2 = setTimeout(process$2, 500 /* LookAhead */, 21 /* Selection */);
|
|
2688
|
+
}
|
|
2689
|
+
function process$2(event) {
|
|
2690
|
+
schedule$1(encode$2.bind(this, event));
|
|
2691
|
+
}
|
|
2692
|
+
function reset$7() {
|
|
2693
|
+
previous = null;
|
|
2694
|
+
data$5 = { start: 0, startOffset: 0, end: 0, endOffset: 0 };
|
|
2695
|
+
}
|
|
2696
|
+
function stop$f() {
|
|
2697
|
+
reset$7();
|
|
2698
|
+
clearTimeout(timeout$2);
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2701
|
+
var data$4;
|
|
2702
|
+
function start$f() {
|
|
2703
|
+
bind(window, "pagehide", recompute$2);
|
|
2704
|
+
}
|
|
2705
|
+
function recompute$2(evt) {
|
|
2706
|
+
data$4 = { name: evt.type };
|
|
2707
|
+
encode$2(26 /* Unload */);
|
|
2708
|
+
stop();
|
|
2709
|
+
}
|
|
2710
|
+
function reset$6() {
|
|
2711
|
+
data$4 = null;
|
|
2712
|
+
}
|
|
2713
|
+
function stop$e() {
|
|
2714
|
+
reset$6();
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
var data$3;
|
|
2718
|
+
function start$e() {
|
|
2719
|
+
bind(document, "visibilitychange", recompute$1);
|
|
2720
|
+
recompute$1();
|
|
2721
|
+
}
|
|
2722
|
+
function recompute$1() {
|
|
2723
|
+
data$3 = { visible: "visibilityState" in document ? document.visibilityState : "default" };
|
|
2724
|
+
encode$2(28 /* Visibility */);
|
|
2725
|
+
}
|
|
2726
|
+
function reset$5() {
|
|
2727
|
+
data$3 = null;
|
|
2728
|
+
}
|
|
2729
|
+
function stop$d() {
|
|
2730
|
+
reset$5();
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
function start$d() {
|
|
2734
|
+
start$b();
|
|
2735
|
+
start$l();
|
|
2736
|
+
start$j();
|
|
2737
|
+
start$k();
|
|
2738
|
+
start$i();
|
|
2739
|
+
start$e();
|
|
2740
|
+
start$h();
|
|
2741
|
+
start$g();
|
|
2742
|
+
start$f();
|
|
2743
|
+
}
|
|
2744
|
+
function stop$c() {
|
|
2745
|
+
stop$a();
|
|
2746
|
+
stop$k();
|
|
2747
|
+
stop$i();
|
|
2748
|
+
stop$j();
|
|
2749
|
+
stop$h();
|
|
2750
|
+
stop$d();
|
|
2751
|
+
stop$g();
|
|
2752
|
+
stop$f();
|
|
2753
|
+
stop$e();
|
|
2754
|
+
}
|
|
2755
|
+
function observe$3(root) {
|
|
2756
|
+
observe$5(root);
|
|
2757
|
+
// Only monitor following interactions if the root node is a document
|
|
2758
|
+
// In case of shadow DOM, following events automatically bubble up to the parent document.
|
|
2759
|
+
if (root.nodeType === Node.DOCUMENT_NODE) {
|
|
2760
|
+
observe$8(root);
|
|
2761
|
+
observe$6(root);
|
|
2762
|
+
observe$7(root);
|
|
2763
|
+
observe$4(root);
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
|
|
2767
|
+
var interaction = /*#__PURE__*/Object.freeze({
|
|
2768
|
+
__proto__: null,
|
|
2769
|
+
start: start$d,
|
|
2770
|
+
stop: stop$c,
|
|
2771
|
+
observe: observe$3
|
|
2772
|
+
});
|
|
2773
|
+
|
|
2774
|
+
var digitsRegex = /[^0-9\.]/g;
|
|
2775
|
+
/* JSON+LD (Linked Data) Recursive Parser */
|
|
2776
|
+
function ld(json) {
|
|
2777
|
+
for (var _i = 0, _a = Object.keys(json); _i < _a.length; _i++) {
|
|
2778
|
+
var key = _a[_i];
|
|
2779
|
+
var value = json[key];
|
|
2780
|
+
if (key === "@type" /* Type */ && typeof value === "string") {
|
|
2781
|
+
value = value.toLowerCase();
|
|
2782
|
+
/* Normalizations */
|
|
2783
|
+
value = value.indexOf("article" /* Article */) >= 0 || value.indexOf("posting" /* Posting */) >= 0 ? "article" /* Article */ : value;
|
|
2784
|
+
switch (value) {
|
|
2785
|
+
case "article" /* Article */:
|
|
2786
|
+
case "recipe" /* Recipe */:
|
|
2787
|
+
log$1(5 /* SchemaType */, json[key]);
|
|
2788
|
+
log$1(8 /* AuthorName */, json["creator" /* Creator */]);
|
|
2789
|
+
log$1(18 /* Headline */, json["headline" /* Headline */]);
|
|
2790
|
+
break;
|
|
2791
|
+
case "product" /* Product */:
|
|
2792
|
+
log$1(5 /* SchemaType */, json[key]);
|
|
2793
|
+
log$1(10 /* ProductName */, json["name" /* Name */]);
|
|
2794
|
+
log$1(12 /* ProductSku */, json["sku" /* Sku */]);
|
|
2795
|
+
if (json["brand" /* Brand */]) {
|
|
2796
|
+
log$1(6 /* ProductBrand */, json["brand" /* Brand */]["name" /* Name */]);
|
|
2797
|
+
}
|
|
2798
|
+
break;
|
|
2799
|
+
case "aggregaterating" /* AggregateRating */:
|
|
2800
|
+
if (json["ratingValue" /* RatingValue */]) {
|
|
2801
|
+
max(11 /* RatingValue */, num(json["ratingValue" /* RatingValue */], 100 /* RatingScale */));
|
|
2802
|
+
max(18 /* BestRating */, num(json["bestRating" /* BestRating */]));
|
|
2803
|
+
max(19 /* WorstRating */, num(json["worstRating" /* WorstRating */]));
|
|
2804
|
+
}
|
|
2805
|
+
max(12 /* RatingCount */, num(json["ratingCount" /* RatingCount */]));
|
|
2806
|
+
max(17 /* ReviewCount */, num(json["reviewCount" /* ReviewCount */]));
|
|
2807
|
+
break;
|
|
2808
|
+
case "person" /* Author */:
|
|
2809
|
+
log$1(8 /* AuthorName */, json["name" /* Name */]);
|
|
2810
|
+
break;
|
|
2811
|
+
case "offer" /* Offer */:
|
|
2812
|
+
log$1(7 /* ProductAvailability */, json["availability" /* Availability */]);
|
|
2813
|
+
log$1(14 /* ProductCondition */, json["itemCondition" /* ItemCondition */]);
|
|
2814
|
+
log$1(13 /* ProductCurrency */, json["priceCurrency" /* PriceCurrency */]);
|
|
2815
|
+
log$1(12 /* ProductSku */, json["sku" /* Sku */]);
|
|
2816
|
+
max(13 /* ProductPrice */, num(json["price" /* Price */]));
|
|
2817
|
+
break;
|
|
2818
|
+
case "brand" /* Brand */:
|
|
2819
|
+
log$1(6 /* ProductBrand */, json["name" /* Name */]);
|
|
2820
|
+
break;
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
// Continue parsing nested objects
|
|
2824
|
+
if (value !== null && typeof (value) === "object" /* Object */) {
|
|
2825
|
+
ld(value);
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
function num(input, scale) {
|
|
2830
|
+
if (scale === void 0) { scale = 1; }
|
|
2831
|
+
if (input !== null) {
|
|
2832
|
+
switch (typeof input) {
|
|
2833
|
+
case "number" /* Number */: return Math.round(input * scale);
|
|
2834
|
+
case "string" /* String */: return Math.round(parseFloat(input.replace(digitsRegex, "" /* Empty */)) * scale);
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
return null;
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
var IGNORE_ATTRIBUTES = ["title", "alt", "onload", "onfocus", "onerror"];
|
|
2841
|
+
function processNode (node, source) {
|
|
2842
|
+
var child = null;
|
|
2843
|
+
// Do not track this change if we are attempting to remove a node before discovering it
|
|
2844
|
+
if (source === 2 /* ChildListRemove */ && has(node) === false) {
|
|
2845
|
+
return child;
|
|
2846
|
+
}
|
|
2847
|
+
// Special handling for text nodes that belong to style nodes
|
|
2848
|
+
if (source !== 0 /* Discover */ &&
|
|
2849
|
+
node.nodeType === Node.TEXT_NODE &&
|
|
2850
|
+
node.parentElement &&
|
|
2851
|
+
node.parentElement.tagName === "STYLE") {
|
|
2852
|
+
node = node.parentNode;
|
|
2853
|
+
}
|
|
2854
|
+
var add = has(node) === false;
|
|
2855
|
+
var call = add ? "add" : "update";
|
|
2856
|
+
var parent = node.parentElement ? node.parentElement : null;
|
|
2857
|
+
var insideFrame = node.ownerDocument !== document;
|
|
2858
|
+
switch (node.nodeType) {
|
|
2859
|
+
case Node.DOCUMENT_TYPE_NODE:
|
|
2860
|
+
parent = insideFrame && node.parentNode ? iframe(node.parentNode) : parent;
|
|
2861
|
+
var docTypePrefix = insideFrame ? "iframe:" /* IFramePrefix */ : "" /* Empty */;
|
|
2862
|
+
var doctype = node;
|
|
2863
|
+
var docAttributes = { name: doctype.name, publicId: doctype.publicId, systemId: doctype.systemId };
|
|
2864
|
+
var docData = { tag: docTypePrefix + "*D" /* DocumentTag */, attributes: docAttributes };
|
|
2865
|
+
dom[call](node, parent, docData, source);
|
|
2866
|
+
break;
|
|
2867
|
+
case Node.DOCUMENT_NODE:
|
|
2868
|
+
// We check for regions in the beginning when discovering document and
|
|
2869
|
+
// later whenever there are new additions or modifications to DOM (mutations)
|
|
2870
|
+
if (node === document)
|
|
2871
|
+
parse(document);
|
|
2872
|
+
observe$2(node);
|
|
2873
|
+
break;
|
|
2874
|
+
case Node.DOCUMENT_FRAGMENT_NODE:
|
|
2875
|
+
var shadowRoot = node;
|
|
2876
|
+
if (shadowRoot.host) {
|
|
2877
|
+
var type = typeof (shadowRoot.constructor);
|
|
2878
|
+
if (type === "function" /* Function */ && shadowRoot.constructor.toString().indexOf("[native code]" /* NativeCode */) >= 0) {
|
|
2879
|
+
observe$2(shadowRoot);
|
|
2880
|
+
// See: https://wicg.github.io/construct-stylesheets/ for more details on adoptedStyleSheets.
|
|
2881
|
+
// At the moment, we are only able to capture "open" shadow DOM nodes. If they are closed, they are not accessible.
|
|
2882
|
+
// In future we may decide to proxy "attachShadow" call to gain access, but at the moment, we don't want to
|
|
2883
|
+
// cause any unintended side effect to the page. We will re-evaluate after we gather more real world data on this.
|
|
2884
|
+
var style = "" /* Empty */;
|
|
2885
|
+
var adoptedStyleSheets = "adoptedStyleSheets" in shadowRoot ? shadowRoot["adoptedStyleSheets"] : [];
|
|
2886
|
+
for (var _i = 0, adoptedStyleSheets_1 = adoptedStyleSheets; _i < adoptedStyleSheets_1.length; _i++) {
|
|
2887
|
+
var styleSheet = adoptedStyleSheets_1[_i];
|
|
2888
|
+
style += getCssRules(styleSheet);
|
|
2889
|
+
}
|
|
2890
|
+
var fragementData = { tag: "*S" /* ShadowDomTag */, attributes: { style: style } };
|
|
2891
|
+
dom[call](node, shadowRoot.host, fragementData, source);
|
|
2892
|
+
}
|
|
2893
|
+
else {
|
|
2894
|
+
// If the browser doesn't support shadow DOM natively, we detect that, and send appropriate tag back.
|
|
2895
|
+
// The differentiation is important because we don't have to observe pollyfill shadow DOM nodes,
|
|
2896
|
+
// the same way we observe real shadow DOM nodes (encapsulation provided by the browser).
|
|
2897
|
+
dom[call](node, shadowRoot.host, { tag: "*P" /* PolyfillShadowDomTag */, attributes: {} }, source);
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
break;
|
|
2901
|
+
case Node.TEXT_NODE:
|
|
2902
|
+
// In IE11 TEXT_NODE doesn't expose a valid parentElement property. Instead we need to lookup parentNode property.
|
|
2903
|
+
parent = parent ? parent : node.parentNode;
|
|
2904
|
+
// Account for this text node only if we are tracking the parent node
|
|
2905
|
+
// We do not wish to track text nodes for ignored parent nodes, like script tags
|
|
2906
|
+
// Also, we do not track text nodes for STYLE tags
|
|
2907
|
+
// The only exception is when we receive a mutation to remove the text node, in that case
|
|
2908
|
+
// parent will be null, but we can still process the node by checking it's an update call.
|
|
2909
|
+
if (call === "update" || (parent && has(parent) && parent.tagName !== "STYLE")) {
|
|
2910
|
+
var textData = { tag: "*T" /* TextTag */, value: node.nodeValue };
|
|
2911
|
+
dom[call](node, parent, textData, source);
|
|
2912
|
+
}
|
|
2913
|
+
break;
|
|
2914
|
+
case Node.ELEMENT_NODE:
|
|
2915
|
+
var element = node;
|
|
2916
|
+
var tag = element.tagName;
|
|
2917
|
+
var attributes = getAttributes(element);
|
|
2918
|
+
// In some cases, external libraries like vue-fragment, can modify parentNode property to not be in sync with the DOM
|
|
2919
|
+
// For correctness, we first look at parentElement and if it not present then fall back to using parentNode
|
|
2920
|
+
parent = node.parentElement ? node.parentElement : (node.parentNode ? node.parentNode : null);
|
|
2921
|
+
// If we encounter a node that is part of SVG namespace, prefix the tag with SVG_PREFIX
|
|
2922
|
+
if (element.namespaceURI === "http://www.w3.org/2000/svg" /* SvgNamespace */) {
|
|
2923
|
+
tag = "svg:" /* SvgPrefix */ + tag;
|
|
2924
|
+
}
|
|
2925
|
+
switch (tag) {
|
|
2926
|
+
case "HTML":
|
|
2927
|
+
parent = insideFrame && parent ? iframe(parent) : null;
|
|
2928
|
+
var htmlPrefix = insideFrame ? "iframe:" /* IFramePrefix */ : "" /* Empty */;
|
|
2929
|
+
var htmlData = { tag: htmlPrefix + tag, attributes: attributes };
|
|
2930
|
+
dom[call](node, parent, htmlData, source);
|
|
2931
|
+
break;
|
|
2932
|
+
case "SCRIPT":
|
|
2933
|
+
if ("type" /* Type */ in attributes && attributes["type" /* Type */] === "application/ld+json" /* JsonLD */) {
|
|
2934
|
+
try {
|
|
2935
|
+
ld(JSON.parse(element.text));
|
|
2936
|
+
}
|
|
2937
|
+
catch ( /* do nothing */_a) { /* do nothing */ }
|
|
2938
|
+
}
|
|
2939
|
+
break;
|
|
2940
|
+
case "NOSCRIPT":
|
|
2941
|
+
break;
|
|
2942
|
+
case "META":
|
|
2943
|
+
if ("property" /* Property */ in attributes && "content" /* Content */ in attributes) {
|
|
2944
|
+
var content = attributes["content" /* Content */];
|
|
2945
|
+
switch (attributes["property" /* Property */]) {
|
|
2946
|
+
case "og:title" /* ogTitle */:
|
|
2947
|
+
log$1(20 /* MetaTitle */, content);
|
|
2948
|
+
break;
|
|
2949
|
+
case "og:type" /* ogType */:
|
|
2950
|
+
log$1(19 /* MetaType */, content);
|
|
2951
|
+
break;
|
|
2952
|
+
case "generator" /* Generator */:
|
|
2953
|
+
log$1(21 /* Generator */, content);
|
|
2954
|
+
break;
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
break;
|
|
2958
|
+
case "HEAD":
|
|
2959
|
+
var head = { tag: tag, attributes: attributes };
|
|
2960
|
+
if (location) {
|
|
2961
|
+
head.attributes["*B" /* Base */] = location.protocol + "//" + location.hostname;
|
|
2962
|
+
}
|
|
2963
|
+
dom[call](node, parent, head, source);
|
|
2964
|
+
break;
|
|
2965
|
+
case "STYLE":
|
|
2966
|
+
var styleData = { tag: tag, attributes: attributes, value: getStyleValue(element) };
|
|
2967
|
+
dom[call](node, parent, styleData, source);
|
|
2968
|
+
break;
|
|
2969
|
+
case "IFRAME":
|
|
2970
|
+
var iframe$1 = node;
|
|
2971
|
+
var frameData = { tag: tag, attributes: attributes };
|
|
2972
|
+
if (sameorigin(iframe$1)) {
|
|
2973
|
+
monitor(iframe$1);
|
|
2974
|
+
frameData.attributes["*O" /* SameOrigin */] = "true";
|
|
2975
|
+
if (iframe$1.contentDocument && iframe$1.contentWindow && iframe$1.contentDocument.readyState !== "loading") {
|
|
2976
|
+
child = iframe$1.contentDocument;
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
dom[call](node, parent, frameData, source);
|
|
2980
|
+
break;
|
|
2981
|
+
default:
|
|
2982
|
+
var data = { tag: tag, attributes: attributes };
|
|
2983
|
+
if (element.shadowRoot) {
|
|
2984
|
+
child = element.shadowRoot;
|
|
2985
|
+
}
|
|
2986
|
+
dom[call](node, parent, data, source);
|
|
2987
|
+
break;
|
|
2988
|
+
}
|
|
2989
|
+
break;
|
|
2990
|
+
}
|
|
2991
|
+
return child;
|
|
2992
|
+
}
|
|
2993
|
+
function observe$2(root) {
|
|
2994
|
+
if (has(root)) {
|
|
2995
|
+
return;
|
|
2996
|
+
}
|
|
2997
|
+
observe$1(root); // Observe mutations for this root node
|
|
2998
|
+
observe$3(root); // Observe interactions for this root node
|
|
2999
|
+
}
|
|
3000
|
+
function getStyleValue(style) {
|
|
3001
|
+
// Call trim on the text content to ensure we do not process white spaces ( , \n, \r\n, \t, etc.)
|
|
3002
|
+
// Also, check if stylesheet has any data-* attribute, if so process rules instead of looking up text
|
|
3003
|
+
var value = style.textContent ? style.textContent.trim() : "" /* Empty */;
|
|
3004
|
+
var dataset = style.dataset ? Object.keys(style.dataset).length : 0;
|
|
3005
|
+
if (value.length === 0 || dataset > 0 || config$1.cssRules) {
|
|
3006
|
+
value = getCssRules(style.sheet);
|
|
3007
|
+
}
|
|
3008
|
+
return value;
|
|
3009
|
+
}
|
|
3010
|
+
function getCssRules(sheet) {
|
|
3011
|
+
var value = "" /* Empty */;
|
|
3012
|
+
var cssRules = null;
|
|
3013
|
+
// Firefox throws a SecurityError when trying to access cssRules of a stylesheet from a different domain
|
|
3014
|
+
try {
|
|
3015
|
+
cssRules = sheet ? sheet.cssRules : [];
|
|
3016
|
+
}
|
|
3017
|
+
catch (e) {
|
|
3018
|
+
log(1 /* CssRules */, 1 /* Warning */, e ? e.name : null);
|
|
3019
|
+
if (e && e.name !== "SecurityError") {
|
|
3020
|
+
throw e;
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
3023
|
+
if (cssRules !== null) {
|
|
3024
|
+
for (var i = 0; i < cssRules.length; i++) {
|
|
3025
|
+
value += cssRules[i].cssText;
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
return value;
|
|
3029
|
+
}
|
|
3030
|
+
function getAttributes(element) {
|
|
3031
|
+
var output = {};
|
|
3032
|
+
var attributes = element.attributes;
|
|
3033
|
+
if (attributes && attributes.length > 0) {
|
|
3034
|
+
for (var i = 0; i < attributes.length; i++) {
|
|
3035
|
+
var name_1 = attributes[i].name;
|
|
3036
|
+
if (IGNORE_ATTRIBUTES.indexOf(name_1) < 0) {
|
|
3037
|
+
output[name_1] = attributes[i].value;
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
// For INPUT tags read the dynamic "value" property if an explicit "value" attribute is not set
|
|
3042
|
+
if (element.tagName === "INPUT" /* InputTag */ && !("value" /* Value */ in output) && element.value) {
|
|
3043
|
+
output["value" /* Value */] = element.value;
|
|
3044
|
+
}
|
|
3045
|
+
return output;
|
|
3046
|
+
}
|
|
3047
|
+
|
|
3048
|
+
function traverse (root, timer, source) {
|
|
3049
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
3050
|
+
var queue, node, next, state, subnode;
|
|
3051
|
+
return __generator(this, function (_a) {
|
|
3052
|
+
switch (_a.label) {
|
|
3053
|
+
case 0:
|
|
3054
|
+
queue = [root];
|
|
3055
|
+
_a.label = 1;
|
|
3056
|
+
case 1:
|
|
3057
|
+
if (!(queue.length > 0)) return [3 /*break*/, 4];
|
|
3058
|
+
node = queue.shift();
|
|
3059
|
+
next = node.firstChild;
|
|
3060
|
+
while (next) {
|
|
3061
|
+
queue.push(next);
|
|
3062
|
+
next = next.nextSibling;
|
|
3063
|
+
}
|
|
3064
|
+
state = state$6(timer);
|
|
3065
|
+
if (!(state === 0 /* Wait */)) return [3 /*break*/, 3];
|
|
3066
|
+
return [4 /*yield*/, suspend$1(timer)];
|
|
3067
|
+
case 2:
|
|
3068
|
+
state = _a.sent();
|
|
3069
|
+
_a.label = 3;
|
|
3070
|
+
case 3:
|
|
3071
|
+
if (state === 2 /* Stop */) {
|
|
3072
|
+
return [3 /*break*/, 4];
|
|
3073
|
+
}
|
|
3074
|
+
subnode = processNode(node, source);
|
|
3075
|
+
if (subnode) {
|
|
3076
|
+
queue.push(subnode);
|
|
3077
|
+
}
|
|
3078
|
+
return [3 /*break*/, 1];
|
|
3079
|
+
case 4: return [2 /*return*/];
|
|
3080
|
+
}
|
|
3081
|
+
});
|
|
3082
|
+
});
|
|
3083
|
+
}
|
|
3084
|
+
|
|
3085
|
+
var observers = [];
|
|
3086
|
+
var mutations = [];
|
|
3087
|
+
var insertRule = null;
|
|
3088
|
+
var deleteRule = null;
|
|
3089
|
+
var queue$1 = [];
|
|
3090
|
+
var timeout$1 = null;
|
|
3091
|
+
var activePeriod = null;
|
|
3092
|
+
var history$1 = {};
|
|
3093
|
+
function start$c() {
|
|
3094
|
+
observers = [];
|
|
3095
|
+
queue$1 = [];
|
|
3096
|
+
timeout$1 = null;
|
|
3097
|
+
activePeriod = 0;
|
|
3098
|
+
history$1 = {};
|
|
3099
|
+
if (insertRule === null) {
|
|
3100
|
+
insertRule = CSSStyleSheet.prototype.insertRule;
|
|
3101
|
+
}
|
|
3102
|
+
if (deleteRule === null) {
|
|
3103
|
+
deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
3104
|
+
}
|
|
3105
|
+
// Some popular open source libraries, like styled-components, optimize performance
|
|
3106
|
+
// by injecting CSS using insertRule API vs. appending text node. A side effect of
|
|
3107
|
+
// using javascript API is that it doesn't trigger DOM mutation and therefore we
|
|
3108
|
+
// need to override the insertRule API and listen for changes manually.
|
|
3109
|
+
CSSStyleSheet.prototype.insertRule = function () {
|
|
3110
|
+
schedule(this.ownerNode);
|
|
3111
|
+
return insertRule.apply(this, arguments);
|
|
3112
|
+
};
|
|
3113
|
+
CSSStyleSheet.prototype.deleteRule = function () {
|
|
3114
|
+
schedule(this.ownerNode);
|
|
3115
|
+
return deleteRule.apply(this, arguments);
|
|
3116
|
+
};
|
|
3117
|
+
}
|
|
3118
|
+
function observe$1(node) {
|
|
3119
|
+
// Create a new observer for every time a new DOM tree (e.g. root document or shadowdom root) is discovered on the page
|
|
3120
|
+
// In the case of shadow dom, any mutations that happen within the shadow dom are not bubbled up to the host document
|
|
3121
|
+
// For this reason, we need to wire up mutations every time we see a new shadow dom.
|
|
3122
|
+
// Also, wrap it inside a try / catch. In certain browsers (e.g. legacy Edge), observer on shadow dom can throw errors
|
|
3123
|
+
try {
|
|
3124
|
+
// In an edge case, it's possible to get stuck into infinite Mutation loop within Angular applications
|
|
3125
|
+
// This appears to be an issue with Zone.js package, see: https://github.com/angular/angular/issues/31712
|
|
3126
|
+
// As a temporary work around, ensuring Clarity can invoke MutationObserver outside of Zone (and use native implementation instead)
|
|
3127
|
+
var api = window["Zone" /* Zone */] && "__symbol__" /* Symbol */ in window["Zone" /* Zone */] ? window["Zone" /* Zone */]["__symbol__" /* Symbol */]("MutationObserver" /* MutationObserver */) : "MutationObserver" /* MutationObserver */;
|
|
3128
|
+
var observer = api in window ? new window[api](measure(handle$1)) : null;
|
|
3129
|
+
if (observer) {
|
|
3130
|
+
observer.observe(node, { attributes: true, childList: true, characterData: true, subtree: true });
|
|
3131
|
+
observers.push(observer);
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
catch (e) {
|
|
3135
|
+
log(2 /* MutationObserver */, 0 /* Info */, e ? e.name : null);
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
function monitor(frame) {
|
|
3139
|
+
// Bind to iframe's onload event so we get notified anytime there's an update to iframe content.
|
|
3140
|
+
// This includes cases where iframe location is updated without explicitly updating src attribute
|
|
3141
|
+
// E.g. iframe.contentWindow.location.href = "new-location";
|
|
3142
|
+
if (has(frame) === false) {
|
|
3143
|
+
bind(frame, "load" /* LoadEvent */, generate.bind(this, frame, "childList" /* ChildList */), true);
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
function stop$b() {
|
|
3147
|
+
for (var _i = 0, observers_1 = observers; _i < observers_1.length; _i++) {
|
|
3148
|
+
var observer = observers_1[_i];
|
|
3149
|
+
if (observer) {
|
|
3150
|
+
observer.disconnect();
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
observers = [];
|
|
3154
|
+
// Restoring original insertRule
|
|
3155
|
+
if (insertRule !== null) {
|
|
3156
|
+
CSSStyleSheet.prototype.insertRule = insertRule;
|
|
3157
|
+
insertRule = null;
|
|
3158
|
+
}
|
|
3159
|
+
// Restoring original deleteRule
|
|
3160
|
+
if (deleteRule !== null) {
|
|
3161
|
+
CSSStyleSheet.prototype.deleteRule = deleteRule;
|
|
3162
|
+
deleteRule = null;
|
|
3163
|
+
}
|
|
3164
|
+
history$1 = {};
|
|
3165
|
+
mutations = [];
|
|
3166
|
+
queue$1 = [];
|
|
3167
|
+
activePeriod = 0;
|
|
3168
|
+
timeout$1 = null;
|
|
3169
|
+
}
|
|
3170
|
+
function active$2() {
|
|
3171
|
+
activePeriod = time() + 3000 /* MutationActivePeriod */;
|
|
3172
|
+
}
|
|
3173
|
+
function handle$1(m) {
|
|
3174
|
+
// Queue up mutation records for asynchronous processing
|
|
3175
|
+
var now = time();
|
|
3176
|
+
track$5(6 /* Mutation */, now);
|
|
3177
|
+
mutations.push({ time: now, mutations: m });
|
|
3178
|
+
schedule$1(process$1, 1 /* High */).then(function () {
|
|
3179
|
+
measure(compute$6)();
|
|
3180
|
+
measure(compute$4)();
|
|
3181
|
+
});
|
|
3182
|
+
}
|
|
3183
|
+
function process$1() {
|
|
3184
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
3185
|
+
var timer, record, _i, _a, mutation, state, target, type, value;
|
|
3186
|
+
return __generator(this, function (_b) {
|
|
3187
|
+
switch (_b.label) {
|
|
3188
|
+
case 0:
|
|
3189
|
+
timer = { id: id(), cost: 3 /* LayoutCost */ };
|
|
3190
|
+
start$t(timer);
|
|
3191
|
+
_b.label = 1;
|
|
3192
|
+
case 1:
|
|
3193
|
+
if (!(mutations.length > 0)) return [3 /*break*/, 8];
|
|
3194
|
+
record = mutations.shift();
|
|
3195
|
+
_i = 0, _a = record.mutations;
|
|
3196
|
+
_b.label = 2;
|
|
3197
|
+
case 2:
|
|
3198
|
+
if (!(_i < _a.length)) return [3 /*break*/, 6];
|
|
3199
|
+
mutation = _a[_i];
|
|
3200
|
+
state = state$6(timer);
|
|
3201
|
+
if (!(state === 0 /* Wait */)) return [3 /*break*/, 4];
|
|
3202
|
+
return [4 /*yield*/, suspend$1(timer)];
|
|
3203
|
+
case 3:
|
|
3204
|
+
state = _b.sent();
|
|
3205
|
+
_b.label = 4;
|
|
3206
|
+
case 4:
|
|
3207
|
+
if (state === 2 /* Stop */) {
|
|
3208
|
+
return [3 /*break*/, 6];
|
|
3209
|
+
}
|
|
3210
|
+
target = mutation.target;
|
|
3211
|
+
type = track$2(mutation, timer);
|
|
3212
|
+
if (type && target && target.ownerDocument) {
|
|
3213
|
+
parse(target.ownerDocument);
|
|
3214
|
+
}
|
|
3215
|
+
switch (type) {
|
|
3216
|
+
case "attributes" /* Attributes */:
|
|
3217
|
+
processNode(target, 3 /* Attributes */);
|
|
3218
|
+
break;
|
|
3219
|
+
case "characterData" /* CharacterData */:
|
|
3220
|
+
processNode(target, 4 /* CharacterData */);
|
|
3221
|
+
break;
|
|
3222
|
+
case "childList" /* ChildList */:
|
|
3223
|
+
processNodeList(mutation.addedNodes, 1 /* ChildListAdd */, timer);
|
|
3224
|
+
processNodeList(mutation.removedNodes, 2 /* ChildListRemove */, timer);
|
|
3225
|
+
break;
|
|
3226
|
+
case "suspend" /* Suspend */:
|
|
3227
|
+
value = get(target);
|
|
3228
|
+
if (value) {
|
|
3229
|
+
value.data.tag = "*M" /* SuspendMutationTag */;
|
|
3230
|
+
}
|
|
3231
|
+
break;
|
|
3232
|
+
}
|
|
3233
|
+
_b.label = 5;
|
|
3234
|
+
case 5:
|
|
3235
|
+
_i++;
|
|
3236
|
+
return [3 /*break*/, 2];
|
|
3237
|
+
case 6: return [4 /*yield*/, encode$4(6 /* Mutation */, timer, record.time)];
|
|
3238
|
+
case 7:
|
|
3239
|
+
_b.sent();
|
|
3240
|
+
return [3 /*break*/, 1];
|
|
3241
|
+
case 8:
|
|
3242
|
+
stop$q(timer);
|
|
3243
|
+
return [2 /*return*/];
|
|
3244
|
+
}
|
|
3245
|
+
});
|
|
3246
|
+
});
|
|
3247
|
+
}
|
|
3248
|
+
function track$2(m, timer) {
|
|
3249
|
+
var value = m.target ? get(m.target.parentNode) : null;
|
|
3250
|
+
// Check if the parent is already discovered and that the parent is not the document root
|
|
3251
|
+
if (value && value.selector !== "HTML" /* HTML */) {
|
|
3252
|
+
var inactive = time() > activePeriod;
|
|
3253
|
+
var target = get(m.target);
|
|
3254
|
+
var element = target ? target.selector : m.target.nodeName;
|
|
3255
|
+
// We use selector, instead of id, to determine the key (signature for the mutation) because in some cases
|
|
3256
|
+
// repeated mutations can cause elements to be destroyed and then recreated as new DOM nodes
|
|
3257
|
+
// In those cases, IDs will change however the selector (which is relative to DOM xPath) remains the same
|
|
3258
|
+
var key = [value.selector, element, m.attributeName, names(m.addedNodes), names(m.removedNodes)].join();
|
|
3259
|
+
// Initialize an entry if it doesn't already exist
|
|
3260
|
+
history$1[key] = key in history$1 ? history$1[key] : [0];
|
|
3261
|
+
var h = history$1[key];
|
|
3262
|
+
// Lookup any pending nodes queued up for removal, and process them now if we suspended a mutation before
|
|
3263
|
+
if (inactive === false && h[0] >= 10 /* MutationSuspendThreshold */) {
|
|
3264
|
+
processNodeList(h[1], 2 /* ChildListRemove */, timer);
|
|
3265
|
+
}
|
|
3266
|
+
// Update the counter
|
|
3267
|
+
h[0] = inactive ? h[0] + 1 : 1;
|
|
3268
|
+
// Return updated mutation type based on if we have already hit the threshold or not
|
|
3269
|
+
if (h[0] === 10 /* MutationSuspendThreshold */) {
|
|
3270
|
+
// Store a reference to removedNodes so we can process them later
|
|
3271
|
+
// when we resume mutations again on user interactions
|
|
3272
|
+
h[1] = m.removedNodes;
|
|
3273
|
+
return "suspend" /* Suspend */;
|
|
3274
|
+
}
|
|
3275
|
+
else if (h[0] > 10 /* MutationSuspendThreshold */) {
|
|
3276
|
+
return "" /* Empty */;
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
return m.type;
|
|
3280
|
+
}
|
|
3281
|
+
function names(nodes) {
|
|
3282
|
+
var output = [];
|
|
3283
|
+
for (var i = 0; nodes && i < nodes.length; i++) {
|
|
3284
|
+
output.push(nodes[i].nodeName);
|
|
3285
|
+
}
|
|
3286
|
+
return output.join();
|
|
3287
|
+
}
|
|
3288
|
+
function processNodeList(list, source, timer) {
|
|
3289
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
3290
|
+
var length, i, state;
|
|
3291
|
+
return __generator(this, function (_a) {
|
|
3292
|
+
switch (_a.label) {
|
|
3293
|
+
case 0:
|
|
3294
|
+
length = list ? list.length : 0;
|
|
3295
|
+
i = 0;
|
|
3296
|
+
_a.label = 1;
|
|
3297
|
+
case 1:
|
|
3298
|
+
if (!(i < length)) return [3 /*break*/, 6];
|
|
3299
|
+
if (!(source === 1 /* ChildListAdd */)) return [3 /*break*/, 2];
|
|
3300
|
+
traverse(list[i], timer, source);
|
|
3301
|
+
return [3 /*break*/, 5];
|
|
3302
|
+
case 2:
|
|
3303
|
+
state = state$6(timer);
|
|
3304
|
+
if (!(state === 0 /* Wait */)) return [3 /*break*/, 4];
|
|
3305
|
+
return [4 /*yield*/, suspend$1(timer)];
|
|
3306
|
+
case 3:
|
|
3307
|
+
state = _a.sent();
|
|
3308
|
+
_a.label = 4;
|
|
3309
|
+
case 4:
|
|
3310
|
+
if (state === 2 /* Stop */) {
|
|
3311
|
+
return [3 /*break*/, 6];
|
|
3312
|
+
}
|
|
3313
|
+
processNode(list[i], source);
|
|
3314
|
+
_a.label = 5;
|
|
3315
|
+
case 5:
|
|
3316
|
+
i++;
|
|
3317
|
+
return [3 /*break*/, 1];
|
|
3318
|
+
case 6: return [2 /*return*/];
|
|
3319
|
+
}
|
|
3320
|
+
});
|
|
3321
|
+
});
|
|
3322
|
+
}
|
|
3323
|
+
function schedule(node) {
|
|
3324
|
+
// Only schedule manual trigger for this node if it's not already in the queue
|
|
3325
|
+
if (queue$1.indexOf(node) < 0) {
|
|
3326
|
+
queue$1.push(node);
|
|
3327
|
+
}
|
|
3328
|
+
// Cancel any previous trigger before scheduling a new one.
|
|
3329
|
+
// It's common for a webpage to call multiple synchronous "insertRule" / "deleteRule" calls.
|
|
3330
|
+
// And in those cases we do not wish to monitor changes multiple times for the same node.
|
|
3331
|
+
if (timeout$1) {
|
|
3332
|
+
clearTimeout(timeout$1);
|
|
3333
|
+
}
|
|
3334
|
+
timeout$1 = setTimeout(trigger, 33 /* LookAhead */);
|
|
3335
|
+
}
|
|
3336
|
+
function trigger() {
|
|
3337
|
+
for (var _i = 0, queue_1 = queue$1; _i < queue_1.length; _i++) {
|
|
3338
|
+
var node = queue_1[_i];
|
|
3339
|
+
generate(node, "characterData" /* CharacterData */);
|
|
3340
|
+
}
|
|
3341
|
+
queue$1 = [];
|
|
3342
|
+
}
|
|
3343
|
+
function generate(target, type) {
|
|
3344
|
+
measure(handle$1)([{
|
|
3345
|
+
addedNodes: [target],
|
|
3346
|
+
attributeName: null,
|
|
3347
|
+
attributeNamespace: null,
|
|
3348
|
+
nextSibling: null,
|
|
3349
|
+
oldValue: null,
|
|
3350
|
+
previousSibling: null,
|
|
3351
|
+
removedNodes: [],
|
|
3352
|
+
target: target,
|
|
3353
|
+
type: type
|
|
3354
|
+
}]);
|
|
3355
|
+
}
|
|
3356
|
+
|
|
3357
|
+
function target(evt) {
|
|
3358
|
+
var path = evt.composed && evt.composedPath ? evt.composedPath() : null;
|
|
3359
|
+
var node = (path && path.length > 0 ? path[0] : evt.target);
|
|
3360
|
+
active$2(); // Mark active periods of time so mutations can continue uninterrupted
|
|
3361
|
+
return node.nodeType === Node.DOCUMENT_NODE ? node.documentElement : node;
|
|
3362
|
+
}
|
|
3363
|
+
function link(node) {
|
|
3364
|
+
while (node && node !== document) {
|
|
3365
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
3366
|
+
var element = node;
|
|
3367
|
+
if (element.tagName === "A") {
|
|
3368
|
+
return element;
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
node = node.parentNode;
|
|
3372
|
+
}
|
|
3373
|
+
return null;
|
|
3374
|
+
}
|
|
3375
|
+
function metadata(node, event) {
|
|
3376
|
+
// If the node is null, we return a reserved value for id: 0. Valid assignment of id begins from 1+.
|
|
3377
|
+
var output = { id: 0, hash: null, selector: null, privacy: 2 /* Text */, node: node };
|
|
3378
|
+
if (node) {
|
|
3379
|
+
var value = get(node);
|
|
3380
|
+
if (value !== null) {
|
|
3381
|
+
output.id = value.id;
|
|
3382
|
+
output.hash = value.selector ? hash(value.selector) : null;
|
|
3383
|
+
output.selector = value.selector;
|
|
3384
|
+
output.privacy = value.metadata.privacy;
|
|
3385
|
+
if (value.region) {
|
|
3386
|
+
track$3(value.region, event);
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
return output;
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3393
|
+
function encode$2 (type) {
|
|
3394
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
3395
|
+
var t, tokens, i, entry, pTarget, i, entry, cTarget, r, u, i, entry, iTarget, s, startTarget, endTarget, i, entry, sTarget, i, entry, v;
|
|
3396
|
+
return __generator(this, function (_a) {
|
|
3397
|
+
t = time();
|
|
3398
|
+
tokens = [t, type];
|
|
3399
|
+
switch (type) {
|
|
3400
|
+
case 13 /* MouseDown */:
|
|
3401
|
+
case 14 /* MouseUp */:
|
|
3402
|
+
case 12 /* MouseMove */:
|
|
3403
|
+
case 15 /* MouseWheel */:
|
|
3404
|
+
case 16 /* DoubleClick */:
|
|
3405
|
+
case 17 /* TouchStart */:
|
|
3406
|
+
case 18 /* TouchEnd */:
|
|
3407
|
+
case 19 /* TouchMove */:
|
|
3408
|
+
case 20 /* TouchCancel */:
|
|
3409
|
+
for (i = 0; i < state$2.length; i++) {
|
|
3410
|
+
entry = state$2[i];
|
|
3411
|
+
pTarget = metadata(entry.data.target, entry.event);
|
|
3412
|
+
if (pTarget.id > 0) {
|
|
3413
|
+
tokens = [entry.time, entry.event];
|
|
3414
|
+
tokens.push(pTarget.id);
|
|
3415
|
+
tokens.push(entry.data.x);
|
|
3416
|
+
tokens.push(entry.data.y);
|
|
3417
|
+
queue(tokens);
|
|
3418
|
+
track$7(entry.event, entry.data.x, entry.data.y);
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
reset$a();
|
|
3422
|
+
break;
|
|
3423
|
+
case 9 /* Click */:
|
|
3424
|
+
for (i = 0; i < state$4.length; i++) {
|
|
3425
|
+
entry = state$4[i];
|
|
3426
|
+
cTarget = metadata(entry.data.target, entry.event);
|
|
3427
|
+
tokens = [entry.time, entry.event];
|
|
3428
|
+
tokens.push(cTarget.id);
|
|
3429
|
+
tokens.push(entry.data.x);
|
|
3430
|
+
tokens.push(entry.data.y);
|
|
3431
|
+
tokens.push(entry.data.eX);
|
|
3432
|
+
tokens.push(entry.data.eY);
|
|
3433
|
+
tokens.push(entry.data.button);
|
|
3434
|
+
tokens.push(entry.data.reaction);
|
|
3435
|
+
tokens.push(entry.data.context);
|
|
3436
|
+
tokens.push(scrub(entry.data.text, "click", cTarget.privacy));
|
|
3437
|
+
tokens.push(entry.data.link);
|
|
3438
|
+
tokens.push(cTarget.hash);
|
|
3439
|
+
queue(tokens);
|
|
3440
|
+
track$1(entry.time, entry.event, cTarget.hash, entry.data.x, entry.data.y, entry.data.reaction, entry.data.context);
|
|
3441
|
+
}
|
|
3442
|
+
reset$c();
|
|
3443
|
+
break;
|
|
3444
|
+
case 11 /* Resize */:
|
|
3445
|
+
r = data$6;
|
|
3446
|
+
tokens.push(r.width);
|
|
3447
|
+
tokens.push(r.height);
|
|
3448
|
+
track$7(type, r.width, r.height);
|
|
3449
|
+
reset$9();
|
|
3450
|
+
queue(tokens);
|
|
3451
|
+
break;
|
|
3452
|
+
case 26 /* Unload */:
|
|
3453
|
+
u = data$4;
|
|
3454
|
+
tokens.push(u.name);
|
|
3455
|
+
reset$6();
|
|
3456
|
+
queue(tokens);
|
|
3457
|
+
break;
|
|
3458
|
+
case 27 /* Input */:
|
|
3459
|
+
for (i = 0; i < state$3.length; i++) {
|
|
3460
|
+
entry = state$3[i];
|
|
3461
|
+
iTarget = metadata(entry.data.target, entry.event);
|
|
3462
|
+
tokens = [entry.time, entry.event];
|
|
3463
|
+
tokens.push(iTarget.id);
|
|
3464
|
+
tokens.push(entry.data.value);
|
|
3465
|
+
queue(tokens);
|
|
3466
|
+
}
|
|
3467
|
+
reset$b();
|
|
3468
|
+
break;
|
|
3469
|
+
case 21 /* Selection */:
|
|
3470
|
+
s = data$5;
|
|
3471
|
+
if (s) {
|
|
3472
|
+
startTarget = metadata(s.start, type);
|
|
3473
|
+
endTarget = metadata(s.end, type);
|
|
3474
|
+
tokens.push(startTarget.id);
|
|
3475
|
+
tokens.push(s.startOffset);
|
|
3476
|
+
tokens.push(endTarget.id);
|
|
3477
|
+
tokens.push(s.endOffset);
|
|
3478
|
+
reset$7();
|
|
3479
|
+
queue(tokens);
|
|
3480
|
+
}
|
|
3481
|
+
break;
|
|
3482
|
+
case 10 /* Scroll */:
|
|
3483
|
+
for (i = 0; i < state$1.length; i++) {
|
|
3484
|
+
entry = state$1[i];
|
|
3485
|
+
sTarget = metadata(entry.data.target, entry.event);
|
|
3486
|
+
if (sTarget.id > 0) {
|
|
3487
|
+
tokens = [entry.time, entry.event];
|
|
3488
|
+
tokens.push(sTarget.id);
|
|
3489
|
+
tokens.push(entry.data.x);
|
|
3490
|
+
tokens.push(entry.data.y);
|
|
3491
|
+
queue(tokens);
|
|
3492
|
+
track$7(entry.event, entry.data.x, entry.data.y);
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
reset$8();
|
|
3496
|
+
break;
|
|
3497
|
+
case 22 /* Timeline */:
|
|
3498
|
+
for (i = 0; i < updates$1.length; i++) {
|
|
3499
|
+
entry = updates$1[i];
|
|
3500
|
+
tokens = [entry.time, entry.event];
|
|
3501
|
+
tokens.push(entry.data.type);
|
|
3502
|
+
tokens.push(entry.data.hash);
|
|
3503
|
+
tokens.push(entry.data.x);
|
|
3504
|
+
tokens.push(entry.data.y);
|
|
3505
|
+
tokens.push(entry.data.reaction);
|
|
3506
|
+
tokens.push(entry.data.context);
|
|
3507
|
+
queue(tokens, false);
|
|
3508
|
+
}
|
|
3509
|
+
reset$4();
|
|
3510
|
+
break;
|
|
3511
|
+
case 28 /* Visibility */:
|
|
3512
|
+
v = data$3;
|
|
3513
|
+
tokens.push(v.visible);
|
|
3514
|
+
queue(tokens);
|
|
3515
|
+
visibility(t, v.visible);
|
|
3516
|
+
reset$5();
|
|
3517
|
+
break;
|
|
3518
|
+
}
|
|
3519
|
+
return [2 /*return*/];
|
|
3520
|
+
});
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
3523
|
+
|
|
3524
|
+
var state = [];
|
|
3525
|
+
var updates$1 = [];
|
|
3526
|
+
function start$b() {
|
|
3527
|
+
state = [];
|
|
3528
|
+
reset$4();
|
|
3529
|
+
}
|
|
3530
|
+
function reset$4() {
|
|
3531
|
+
updates$1 = [];
|
|
3532
|
+
}
|
|
3533
|
+
function track$1(time, event, hash, x, y, reaction, context) {
|
|
3534
|
+
if (reaction === void 0) { reaction = 1 /* True */; }
|
|
3535
|
+
if (context === void 0) { context = 0 /* Self */; }
|
|
3536
|
+
state.push({
|
|
3537
|
+
time: time,
|
|
3538
|
+
event: 22 /* Timeline */,
|
|
3539
|
+
data: {
|
|
3540
|
+
type: event,
|
|
3541
|
+
hash: hash,
|
|
3542
|
+
x: x,
|
|
3543
|
+
y: y,
|
|
3544
|
+
reaction: reaction,
|
|
3545
|
+
context: context
|
|
3546
|
+
}
|
|
3547
|
+
});
|
|
3548
|
+
// Since timeline only keeps the data for configured time, we still want to continue tracking these values
|
|
3549
|
+
// as part of the baseline. For instance, in a scenario where last scroll happened 5s ago.
|
|
3550
|
+
// We would still need to capture the last scroll position as part of the baseline event, even when timeline will be empty.
|
|
3551
|
+
track$7(event, x, y);
|
|
3552
|
+
}
|
|
3553
|
+
function compute$3() {
|
|
3554
|
+
var temp = [];
|
|
3555
|
+
updates$1 = [];
|
|
3556
|
+
var max = data$h.start + data$h.duration;
|
|
3557
|
+
var min = Math.max(max - 2000 /* TimelineSpan */, 0);
|
|
3558
|
+
for (var _i = 0, state_1 = state; _i < state_1.length; _i++) {
|
|
3559
|
+
var s = state_1[_i];
|
|
3560
|
+
if (s.time >= min) {
|
|
3561
|
+
if (s.time <= max) {
|
|
3562
|
+
updates$1.push(s);
|
|
3563
|
+
}
|
|
3564
|
+
temp.push(s);
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
state = temp; // Drop events less than the min time
|
|
3568
|
+
encode$2(22 /* Timeline */);
|
|
3569
|
+
}
|
|
3570
|
+
function stop$a() {
|
|
3571
|
+
state = [];
|
|
3572
|
+
reset$4();
|
|
3573
|
+
}
|
|
3574
|
+
|
|
3575
|
+
var discoverBytes = 0;
|
|
3576
|
+
var playbackBytes = 0;
|
|
3577
|
+
var playback;
|
|
3578
|
+
var analysis;
|
|
3579
|
+
var timeout = null;
|
|
3580
|
+
var transit;
|
|
3581
|
+
var active$1;
|
|
3582
|
+
var queuedTime = 0;
|
|
3583
|
+
var track;
|
|
3584
|
+
function start$a() {
|
|
3585
|
+
active$1 = true;
|
|
3586
|
+
discoverBytes = 0;
|
|
3587
|
+
playbackBytes = 0;
|
|
3588
|
+
queuedTime = 0;
|
|
3589
|
+
playback = [];
|
|
3590
|
+
analysis = [];
|
|
3591
|
+
transit = {};
|
|
3592
|
+
track = null;
|
|
3593
|
+
}
|
|
3594
|
+
function queue(tokens, transmit) {
|
|
3595
|
+
if (transmit === void 0) { transmit = true; }
|
|
3596
|
+
if (active$1) {
|
|
3597
|
+
var now = time();
|
|
3598
|
+
var type = tokens.length > 1 ? tokens[1] : null;
|
|
3599
|
+
var event_1 = JSON.stringify(tokens);
|
|
3600
|
+
switch (type) {
|
|
3601
|
+
case 5 /* Discover */:
|
|
3602
|
+
discoverBytes += event_1.length;
|
|
3603
|
+
case 37 /* Box */:
|
|
3604
|
+
case 6 /* Mutation */:
|
|
3605
|
+
playbackBytes += event_1.length;
|
|
3606
|
+
playback.push(event_1);
|
|
3607
|
+
break;
|
|
3608
|
+
default:
|
|
3609
|
+
analysis.push(event_1);
|
|
3610
|
+
break;
|
|
3611
|
+
}
|
|
3612
|
+
// Following two checks are precautionary and act as a fail safe mechanism to get out of unexpected situations.
|
|
3613
|
+
// Check 1: If for any reason the upload hasn't happened after waiting for 2x the config.delay time,
|
|
3614
|
+
// reset the timer. This allows Clarity to attempt an upload again.
|
|
3615
|
+
var gap = delay();
|
|
3616
|
+
if (now - queuedTime > (gap * 2)) {
|
|
3617
|
+
clearTimeout(timeout);
|
|
3618
|
+
timeout = null;
|
|
3619
|
+
}
|
|
3620
|
+
// Transmit Check: When transmit is set to true (default), it indicates that we should schedule an upload
|
|
3621
|
+
// However, in certain scenarios - like metric calculation - which are triggered as part of an existing upload
|
|
3622
|
+
// We enrich the data going out with the existing upload. In these cases, call to upload comes with 'transmit' set to false.
|
|
3623
|
+
if (transmit && timeout === null) {
|
|
3624
|
+
if (type !== 25 /* Ping */) {
|
|
3625
|
+
reset$j();
|
|
3626
|
+
}
|
|
3627
|
+
timeout = setTimeout(upload, gap);
|
|
3628
|
+
queuedTime = now;
|
|
3629
|
+
check$3(playbackBytes);
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
function stop$9() {
|
|
3634
|
+
clearTimeout(timeout);
|
|
3635
|
+
upload(true);
|
|
3636
|
+
discoverBytes = 0;
|
|
3637
|
+
playbackBytes = 0;
|
|
3638
|
+
queuedTime = 0;
|
|
3639
|
+
playback = [];
|
|
3640
|
+
analysis = [];
|
|
3641
|
+
transit = {};
|
|
3642
|
+
track = null;
|
|
3643
|
+
active$1 = false;
|
|
3644
|
+
}
|
|
3645
|
+
function upload(final) {
|
|
3646
|
+
if (final === void 0) { final = false; }
|
|
3647
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
3648
|
+
var sendPlaybackBytes, last, e, a, p, encoded, payload, zipped, _a;
|
|
3649
|
+
return __generator(this, function (_b) {
|
|
3650
|
+
switch (_b.label) {
|
|
3651
|
+
case 0:
|
|
3652
|
+
timeout = null;
|
|
3653
|
+
sendPlaybackBytes = config$1.lean === false && playbackBytes > 0 && (playbackBytes < 1048576 /* MaxFirstPayloadBytes */ || data$h.sequence > 0);
|
|
3654
|
+
if (sendPlaybackBytes) {
|
|
3655
|
+
max(1 /* Playback */, 1 /* True */);
|
|
3656
|
+
}
|
|
3657
|
+
// CAUTION: Ensure "transmit" is set to false in the queue function for following events
|
|
3658
|
+
// Otherwise you run a risk of infinite loop.
|
|
3659
|
+
compute$4();
|
|
3660
|
+
compute$3();
|
|
3661
|
+
compute$7();
|
|
3662
|
+
last = final === true;
|
|
3663
|
+
e = JSON.stringify(envelope(last));
|
|
3664
|
+
a = "[" + analysis.join() + "]";
|
|
3665
|
+
p = sendPlaybackBytes ? "[" + playback.join() + "]" : "" /* Empty */;
|
|
3666
|
+
encoded = { e: e, a: a, p: p };
|
|
3667
|
+
payload = stringify(encoded);
|
|
3668
|
+
if (!last) return [3 /*break*/, 1];
|
|
3669
|
+
_a = null;
|
|
3670
|
+
return [3 /*break*/, 3];
|
|
3671
|
+
case 1: return [4 /*yield*/, compress(payload)];
|
|
3672
|
+
case 2:
|
|
3673
|
+
_a = _b.sent();
|
|
3674
|
+
_b.label = 3;
|
|
3675
|
+
case 3:
|
|
3676
|
+
zipped = _a;
|
|
3677
|
+
sum(2 /* TotalBytes */, zipped ? zipped.length : payload.length);
|
|
3678
|
+
send(payload, zipped, data$h.sequence, last);
|
|
3679
|
+
// Clear out events now that payload has been dispatched
|
|
3680
|
+
analysis = [];
|
|
3681
|
+
if (sendPlaybackBytes) {
|
|
3682
|
+
playback = [];
|
|
3683
|
+
playbackBytes = 0;
|
|
3684
|
+
discoverBytes = 0;
|
|
3685
|
+
}
|
|
3686
|
+
return [2 /*return*/];
|
|
3687
|
+
}
|
|
3688
|
+
});
|
|
3689
|
+
});
|
|
3690
|
+
}
|
|
3691
|
+
function stringify(encoded) {
|
|
3692
|
+
return encoded.p.length > 0 ? "{\"e\":" + encoded.e + ",\"a\":" + encoded.a + ",\"p\":" + encoded.p + "}" : "{\"e\":" + encoded.e + ",\"a\":" + encoded.a + "}";
|
|
3693
|
+
}
|
|
3694
|
+
function send(payload, zipped, sequence, beacon) {
|
|
3695
|
+
if (beacon === void 0) { beacon = false; }
|
|
3696
|
+
// Upload data if a valid URL is defined in the config
|
|
3697
|
+
if (typeof config$1.upload === "string" /* String */) {
|
|
3698
|
+
var url = config$1.upload;
|
|
3699
|
+
var dispatched = false;
|
|
3700
|
+
// If it's the last payload, attempt to upload using sendBeacon first.
|
|
3701
|
+
// The advantage to using sendBeacon is that browser can decide to upload asynchronously, improving chances of success
|
|
3702
|
+
// However, we don't want to rely on it for every payload, since we have no ability to retry if the upload failed.
|
|
3703
|
+
// Also, in case of sendBeacon, we do not have a way to alter HTTP headers and therefore can't send compressed payload
|
|
3704
|
+
if (beacon && "sendBeacon" in navigator) {
|
|
3705
|
+
dispatched = navigator.sendBeacon(url, payload);
|
|
3706
|
+
if (dispatched) {
|
|
3707
|
+
done(sequence);
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
// Before initiating XHR upload, we check if the data has already been uploaded using sendBeacon
|
|
3711
|
+
// There are two cases when dispatched could still be false:
|
|
3712
|
+
// a) It's not the last payload, and therefore we didn't attempt sending sendBeacon
|
|
3713
|
+
// b) It's the last payload, however, we failed to queue sendBeacon call and need to now fall back to XHR.
|
|
3714
|
+
// E.g. if data is over 64KB, several user agents (like Chrome) will reject to queue the sendBeacon call.
|
|
3715
|
+
if (dispatched === false) {
|
|
3716
|
+
// While tracking payload for retry, we only track string value of the payload to err on the safe side
|
|
3717
|
+
// Not all browsers support compression API and the support for it in supported browsers is still experimental
|
|
3718
|
+
if (sequence in transit) {
|
|
3719
|
+
transit[sequence].attempts++;
|
|
3720
|
+
}
|
|
3721
|
+
else {
|
|
3722
|
+
transit[sequence] = { data: payload, attempts: 1 };
|
|
3723
|
+
}
|
|
3724
|
+
var xhr_1 = new XMLHttpRequest();
|
|
3725
|
+
xhr_1.open("POST", url);
|
|
3726
|
+
if (sequence !== null) {
|
|
3727
|
+
xhr_1.onreadystatechange = function () { measure(check$2)(xhr_1, sequence); };
|
|
3728
|
+
}
|
|
3729
|
+
xhr_1.withCredentials = true;
|
|
3730
|
+
if (zipped) {
|
|
3731
|
+
// If we do have valid compressed array, send it with appropriate HTTP headers so server can decode it appropriately
|
|
3732
|
+
xhr_1.setRequestHeader("Accept" /* Accept */, "application/x-clarity-gzip" /* ClarityGzip */);
|
|
3733
|
+
xhr_1.send(zipped);
|
|
3734
|
+
}
|
|
3735
|
+
else {
|
|
3736
|
+
// In all other cases, continue sending string back to the server
|
|
3737
|
+
xhr_1.send(payload);
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
}
|
|
3741
|
+
else if (config$1.upload) {
|
|
3742
|
+
var callback = config$1.upload;
|
|
3743
|
+
callback(payload);
|
|
3744
|
+
done(sequence);
|
|
3745
|
+
}
|
|
3746
|
+
}
|
|
3747
|
+
function check$2(xhr, sequence) {
|
|
3748
|
+
var transitData = transit[sequence];
|
|
3749
|
+
if (xhr && xhr.readyState === 4 /* Done */ && transitData) {
|
|
3750
|
+
// Attempt send payload again (as configured in settings) if we do not receive a success (2XX) response code back from the server
|
|
3751
|
+
if ((xhr.status < 200 || xhr.status > 208) && transitData.attempts <= 1 /* RetryLimit */) {
|
|
3752
|
+
// We re-attempt in all cases except when server explicitly rejects our request with 4XX error
|
|
3753
|
+
if (xhr.status >= 400 && xhr.status < 500) {
|
|
3754
|
+
// In case of a 4XX response from the server, we bail out instead of trying again
|
|
3755
|
+
trigger$1(6 /* Server */);
|
|
3756
|
+
}
|
|
3757
|
+
else {
|
|
3758
|
+
// Browser will send status = 0 when it refuses to put network request over the wire
|
|
3759
|
+
// This could happen for several reasons, couple of known ones are:
|
|
3760
|
+
// 1: Browsers block upload because of content security policy violation
|
|
3761
|
+
// 2: Safari will terminate pending XHR requests with status code 0 if the user navigates away from the page
|
|
3762
|
+
// In any case, we switch the upload URL to fallback configuration (if available) before re-trying one more time
|
|
3763
|
+
if (xhr.status === 0) {
|
|
3764
|
+
config$1.upload = config$1.fallback ? config$1.fallback : config$1.upload;
|
|
3765
|
+
}
|
|
3766
|
+
// In all other cases, re-attempt sending the same data
|
|
3767
|
+
// For retry we always fallback to string payload, even though we may have attempted
|
|
3768
|
+
// sending zipped payload earlier
|
|
3769
|
+
send(transitData.data, null, sequence);
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3772
|
+
else {
|
|
3773
|
+
track = { sequence: sequence, attempts: transitData.attempts, status: xhr.status };
|
|
3774
|
+
// Send back an event only if we were not successful in our first attempt
|
|
3775
|
+
if (transitData.attempts > 1) {
|
|
3776
|
+
encode$1(2 /* Upload */);
|
|
3777
|
+
}
|
|
3778
|
+
// Handle response if it was a 200 response with a valid body
|
|
3779
|
+
if (xhr.status === 200 && xhr.responseText) {
|
|
3780
|
+
response(xhr.responseText);
|
|
3781
|
+
}
|
|
3782
|
+
// If we exhausted our retries then trigger Clarity's shutdown for this page since the data will be incomplete
|
|
3783
|
+
if (xhr.status === 0) {
|
|
3784
|
+
// And, right before we terminate the session, we will attempt one last time to see if we can use
|
|
3785
|
+
// different transport option (sendBeacon vs. XHR) to get this data to the server for analysis purposes
|
|
3786
|
+
send(transitData.data, null, sequence, true);
|
|
3787
|
+
trigger$1(3 /* Retry */);
|
|
3788
|
+
}
|
|
3789
|
+
// Signal that this request completed successfully
|
|
3790
|
+
if (xhr.status >= 200 && xhr.status <= 208) {
|
|
3791
|
+
done(sequence);
|
|
3792
|
+
}
|
|
3793
|
+
// Stop tracking this payload now that it's all done
|
|
3794
|
+
delete transit[sequence];
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
}
|
|
3798
|
+
function done(sequence) {
|
|
3799
|
+
// If we everything went successfully, and it is the first sequence, save this session for future reference
|
|
3800
|
+
if (sequence === 1) {
|
|
3801
|
+
save();
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
function delay() {
|
|
3805
|
+
// Progressively increase delay as we continue to send more payloads from the client to the server
|
|
3806
|
+
// If we are not uploading data to a server, and instead invoking UploadCallback, in that case keep returning configured value
|
|
3807
|
+
var gap = config$1.lean === false && discoverBytes > 0 ? 100 /* MinUploadDelay */ : data$h.sequence * config$1.delay;
|
|
3808
|
+
return typeof config$1.upload === "string" /* String */ ? Math.max(Math.min(gap, 30000 /* MaxUploadDelay */), 100 /* MinUploadDelay */) : config$1.delay;
|
|
3809
|
+
}
|
|
3810
|
+
function response(payload) {
|
|
3811
|
+
var key = payload && payload.length > 0 ? payload.split(" ")[0] : "" /* Empty */;
|
|
3812
|
+
switch (key) {
|
|
3813
|
+
case "END" /* End */:
|
|
3814
|
+
// Clear out session storage and end the session so we can start fresh the next time
|
|
3815
|
+
trigger$1(6 /* Server */);
|
|
3816
|
+
break;
|
|
3817
|
+
case "UPGRADE" /* Upgrade */:
|
|
3818
|
+
// Upgrade current session to send back playback information
|
|
3819
|
+
upgrade("Auto" /* Auto */);
|
|
3820
|
+
break;
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3823
|
+
|
|
3824
|
+
function encode$1 (event) {
|
|
3825
|
+
var t = time();
|
|
3826
|
+
var tokens = [t, event];
|
|
3827
|
+
switch (event) {
|
|
3828
|
+
case 4 /* Baseline */:
|
|
3829
|
+
var b = state$7;
|
|
3830
|
+
if (b) {
|
|
3831
|
+
tokens = [b.time, b.event];
|
|
3832
|
+
tokens.push(b.data.visible);
|
|
3833
|
+
tokens.push(b.data.docWidth);
|
|
3834
|
+
tokens.push(b.data.docHeight);
|
|
3835
|
+
tokens.push(b.data.screenWidth);
|
|
3836
|
+
tokens.push(b.data.screenHeight);
|
|
3837
|
+
tokens.push(b.data.scrollX);
|
|
3838
|
+
tokens.push(b.data.scrollY);
|
|
3839
|
+
tokens.push(b.data.pointerX);
|
|
3840
|
+
tokens.push(b.data.pointerY);
|
|
3841
|
+
tokens.push(b.data.activityTime);
|
|
3842
|
+
queue(tokens, false);
|
|
3843
|
+
}
|
|
3844
|
+
reset$n();
|
|
3845
|
+
break;
|
|
3846
|
+
case 25 /* Ping */:
|
|
3847
|
+
tokens.push(data$e.gap);
|
|
3848
|
+
queue(tokens);
|
|
3849
|
+
break;
|
|
3850
|
+
case 35 /* Limit */:
|
|
3851
|
+
tokens.push(data$g.check);
|
|
3852
|
+
queue(tokens, false);
|
|
3853
|
+
break;
|
|
3854
|
+
case 3 /* Upgrade */:
|
|
3855
|
+
tokens.push(data$c.key);
|
|
3856
|
+
queue(tokens);
|
|
3857
|
+
break;
|
|
3858
|
+
case 2 /* Upload */:
|
|
3859
|
+
tokens.push(track.sequence);
|
|
3860
|
+
tokens.push(track.attempts);
|
|
3861
|
+
tokens.push(track.status);
|
|
3862
|
+
queue(tokens, false);
|
|
3863
|
+
break;
|
|
3864
|
+
case 24 /* Custom */:
|
|
3865
|
+
tokens.push(data$k.key);
|
|
3866
|
+
tokens.push(data$k.value);
|
|
3867
|
+
queue(tokens);
|
|
3868
|
+
break;
|
|
3869
|
+
case 34 /* Variable */:
|
|
3870
|
+
var variableKeys = Object.keys(data$j);
|
|
3871
|
+
if (variableKeys.length > 0) {
|
|
3872
|
+
for (var _i = 0, variableKeys_1 = variableKeys; _i < variableKeys_1.length; _i++) {
|
|
3873
|
+
var v = variableKeys_1[_i];
|
|
3874
|
+
tokens.push(v);
|
|
3875
|
+
tokens.push(data$j[v]);
|
|
3876
|
+
}
|
|
3877
|
+
reset$m();
|
|
3878
|
+
queue(tokens, false);
|
|
3879
|
+
}
|
|
3880
|
+
break;
|
|
3881
|
+
case 0 /* Metric */:
|
|
3882
|
+
var metricKeys = Object.keys(updates);
|
|
3883
|
+
if (metricKeys.length > 0) {
|
|
3884
|
+
for (var _a = 0, metricKeys_1 = metricKeys; _a < metricKeys_1.length; _a++) {
|
|
3885
|
+
var m = metricKeys_1[_a];
|
|
3886
|
+
var key = parseInt(m, 10);
|
|
3887
|
+
tokens.push(key);
|
|
3888
|
+
// For computation, we need microseconds precision that performance.now() API offers
|
|
3889
|
+
// However, for data over the wire, we round it off to milliseconds precision.
|
|
3890
|
+
tokens.push(Math.round(updates[m]));
|
|
3891
|
+
}
|
|
3892
|
+
reset$3();
|
|
3893
|
+
queue(tokens, false);
|
|
3894
|
+
}
|
|
3895
|
+
break;
|
|
3896
|
+
case 1 /* Dimension */:
|
|
3897
|
+
var dimensionKeys = Object.keys(updates$3);
|
|
3898
|
+
if (dimensionKeys.length > 0) {
|
|
3899
|
+
for (var _b = 0, dimensionKeys_1 = dimensionKeys; _b < dimensionKeys_1.length; _b++) {
|
|
3900
|
+
var d = dimensionKeys_1[_b];
|
|
3901
|
+
var key = parseInt(d, 10);
|
|
3902
|
+
tokens.push(key);
|
|
3903
|
+
tokens.push(updates$3[d]);
|
|
3904
|
+
}
|
|
3905
|
+
reset$k();
|
|
3906
|
+
queue(tokens, false);
|
|
3907
|
+
}
|
|
3908
|
+
break;
|
|
3909
|
+
case 36 /* Summary */:
|
|
3910
|
+
var eventKeys = Object.keys(data$d);
|
|
3911
|
+
if (eventKeys.length > 0) {
|
|
3912
|
+
for (var _c = 0, eventKeys_1 = eventKeys; _c < eventKeys_1.length; _c++) {
|
|
3913
|
+
var e = eventKeys_1[_c];
|
|
3914
|
+
var key = parseInt(e, 10);
|
|
3915
|
+
tokens.push(key);
|
|
3916
|
+
tokens.push([].concat.apply([], data$d[e]));
|
|
3917
|
+
}
|
|
3918
|
+
reset$i();
|
|
3919
|
+
queue(tokens, false);
|
|
3920
|
+
}
|
|
3921
|
+
break;
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
|
|
3925
|
+
var data$2 = null;
|
|
3926
|
+
var updates = null;
|
|
3927
|
+
function start$9() {
|
|
3928
|
+
data$2 = {};
|
|
3929
|
+
updates = {};
|
|
3930
|
+
count$1(5 /* InvokeCount */);
|
|
3931
|
+
}
|
|
3932
|
+
function stop$8() {
|
|
3933
|
+
data$2 = {};
|
|
3934
|
+
updates = {};
|
|
3935
|
+
}
|
|
3936
|
+
function count$1(metric, increment) {
|
|
3937
|
+
if (increment === void 0) { increment = 1; }
|
|
3938
|
+
if (!(metric in data$2)) {
|
|
3939
|
+
data$2[metric] = 0;
|
|
3940
|
+
}
|
|
3941
|
+
if (!(metric in updates)) {
|
|
3942
|
+
updates[metric] = 0;
|
|
3943
|
+
}
|
|
3944
|
+
data$2[metric] += increment;
|
|
3945
|
+
updates[metric] += increment;
|
|
3946
|
+
}
|
|
3947
|
+
function sum(metric, value) {
|
|
3948
|
+
if (value !== null) {
|
|
3949
|
+
if (!(metric in data$2)) {
|
|
3950
|
+
data$2[metric] = 0;
|
|
3951
|
+
}
|
|
3952
|
+
if (!(metric in updates)) {
|
|
3953
|
+
updates[metric] = 0;
|
|
3954
|
+
}
|
|
3955
|
+
data$2[metric] += value;
|
|
3956
|
+
updates[metric] += value;
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
function max(metric, value) {
|
|
3960
|
+
// Ensure that we do not process null or NaN values
|
|
3961
|
+
if (value !== null && isNaN(value) === false) {
|
|
3962
|
+
if (!(metric in data$2)) {
|
|
3963
|
+
data$2[metric] = 0;
|
|
3964
|
+
}
|
|
3965
|
+
if (value > data$2[metric] || data$2[metric] === 0) {
|
|
3966
|
+
updates[metric] = value;
|
|
3967
|
+
data$2[metric] = value;
|
|
3968
|
+
}
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
function compute$2() {
|
|
3972
|
+
encode$1(0 /* Metric */);
|
|
3973
|
+
}
|
|
3974
|
+
function reset$3() {
|
|
3975
|
+
updates = {};
|
|
3976
|
+
}
|
|
3977
|
+
|
|
3978
|
+
// tslint:disable-next-line: ban-types
|
|
3979
|
+
function measure (method) {
|
|
3980
|
+
return function () {
|
|
3981
|
+
var start = performance.now();
|
|
3982
|
+
method.apply(this, arguments);
|
|
3983
|
+
var duration = performance.now() - start;
|
|
3984
|
+
sum(4 /* TotalCost */, duration);
|
|
3985
|
+
if (duration > 30 /* LongTask */) {
|
|
3986
|
+
count$1(7 /* LongTaskCount */);
|
|
3987
|
+
max(6 /* ThreadBlockedTime */, duration);
|
|
3988
|
+
}
|
|
3989
|
+
};
|
|
3990
|
+
}
|
|
3991
|
+
|
|
3992
|
+
var bindings = [];
|
|
3993
|
+
function bind(target, event, listener, capture) {
|
|
3994
|
+
if (capture === void 0) { capture = false; }
|
|
3995
|
+
listener = measure(listener);
|
|
3996
|
+
// Wrapping following lines inside try / catch to cover edge cases where we might try to access an inaccessible element.
|
|
3997
|
+
// E.g. Iframe may start off as same-origin but later turn into cross-origin, and the following lines will throw an exception.
|
|
3998
|
+
try {
|
|
3999
|
+
target.addEventListener(event, listener, capture);
|
|
4000
|
+
bindings.push({ event: event, target: target, listener: listener, capture: capture });
|
|
4001
|
+
}
|
|
4002
|
+
catch ( /* do nothing */_a) { /* do nothing */ }
|
|
4003
|
+
}
|
|
4004
|
+
function reset$2() {
|
|
4005
|
+
// Walk through existing list of bindings and remove them all
|
|
4006
|
+
for (var _i = 0, bindings_1 = bindings; _i < bindings_1.length; _i++) {
|
|
4007
|
+
var binding = bindings_1[_i];
|
|
4008
|
+
// Wrapping inside try / catch to avoid situations where the element may be destroyed before we get a chance to unbind
|
|
4009
|
+
try {
|
|
4010
|
+
binding.target.removeEventListener(binding.event, binding.listener, binding.capture);
|
|
4011
|
+
}
|
|
4012
|
+
catch ( /* do nothing */_a) { /* do nothing */ }
|
|
4013
|
+
}
|
|
4014
|
+
bindings = [];
|
|
4015
|
+
}
|
|
4016
|
+
|
|
4017
|
+
var pushState = null;
|
|
4018
|
+
var replaceState = null;
|
|
4019
|
+
var url = null;
|
|
4020
|
+
var count = 0;
|
|
4021
|
+
function start$8() {
|
|
4022
|
+
url = getCurrentUrl();
|
|
4023
|
+
count = 0;
|
|
4024
|
+
bind(window, "popstate", compute$1);
|
|
4025
|
+
// Add a proxy to history.pushState function
|
|
4026
|
+
if (pushState === null) {
|
|
4027
|
+
pushState = history.pushState;
|
|
4028
|
+
}
|
|
4029
|
+
history.pushState = function () {
|
|
4030
|
+
if (check$1()) {
|
|
4031
|
+
pushState.apply(this, arguments);
|
|
4032
|
+
compute$1();
|
|
4033
|
+
}
|
|
4034
|
+
};
|
|
4035
|
+
// Add a proxy to history.replaceState function
|
|
4036
|
+
if (replaceState === null) {
|
|
4037
|
+
replaceState = history.replaceState;
|
|
4038
|
+
}
|
|
4039
|
+
history.replaceState = function () {
|
|
4040
|
+
if (check$1()) {
|
|
4041
|
+
replaceState.apply(this, arguments);
|
|
4042
|
+
compute$1();
|
|
4043
|
+
}
|
|
4044
|
+
};
|
|
4045
|
+
}
|
|
4046
|
+
function check$1() {
|
|
4047
|
+
if (count++ > 20 /* CallStackDepth */) {
|
|
4048
|
+
log(4 /* CallStackDepth */, 0 /* Info */);
|
|
4049
|
+
return false;
|
|
4050
|
+
}
|
|
4051
|
+
return true;
|
|
4052
|
+
}
|
|
4053
|
+
function compute$1() {
|
|
4054
|
+
if (url !== getCurrentUrl() && count <= 20 /* CallStackDepth */) {
|
|
4055
|
+
stop();
|
|
4056
|
+
window.setTimeout(start, 250 /* RestartDelay */);
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
function getCurrentUrl() {
|
|
4060
|
+
return location.href ? location.href.replace(location.hash, "" /* Empty */) : location.href;
|
|
4061
|
+
}
|
|
4062
|
+
function stop$7() {
|
|
4063
|
+
// Restore original function definition of history.pushState
|
|
4064
|
+
if (pushState !== null) {
|
|
4065
|
+
history.pushState = pushState;
|
|
4066
|
+
pushState = null;
|
|
4067
|
+
}
|
|
4068
|
+
// Restore original function definition of history.replaceState
|
|
4069
|
+
if (replaceState !== null) {
|
|
4070
|
+
history.replaceState = replaceState;
|
|
4071
|
+
replaceState = null;
|
|
4072
|
+
}
|
|
4073
|
+
url = null;
|
|
4074
|
+
count = 0;
|
|
4075
|
+
}
|
|
4076
|
+
|
|
4077
|
+
var status = false;
|
|
4078
|
+
function start$7() {
|
|
4079
|
+
status = true;
|
|
4080
|
+
start$E();
|
|
4081
|
+
reset$h();
|
|
4082
|
+
reset$2();
|
|
4083
|
+
reset$l();
|
|
4084
|
+
start$8();
|
|
4085
|
+
}
|
|
4086
|
+
function stop$6() {
|
|
4087
|
+
stop$7();
|
|
4088
|
+
reset$l();
|
|
4089
|
+
reset$2();
|
|
4090
|
+
reset$h();
|
|
4091
|
+
stop$B();
|
|
4092
|
+
status = false;
|
|
4093
|
+
}
|
|
4094
|
+
function active() {
|
|
4095
|
+
return status;
|
|
4096
|
+
}
|
|
4097
|
+
function check() {
|
|
4098
|
+
try {
|
|
4099
|
+
return status === false &&
|
|
4100
|
+
typeof Promise !== "undefined" &&
|
|
4101
|
+
window["MutationObserver"] &&
|
|
4102
|
+
document["createTreeWalker"] &&
|
|
4103
|
+
"now" in Date &&
|
|
4104
|
+
"now" in performance &&
|
|
4105
|
+
typeof WeakMap !== "undefined";
|
|
4106
|
+
}
|
|
4107
|
+
catch (ex) {
|
|
4108
|
+
return false;
|
|
4109
|
+
}
|
|
4110
|
+
}
|
|
4111
|
+
function config(override) {
|
|
4112
|
+
// Process custom configuration overrides, if available
|
|
4113
|
+
if (override === null || status) {
|
|
4114
|
+
return false;
|
|
4115
|
+
}
|
|
4116
|
+
for (var key in override) {
|
|
4117
|
+
if (key in config$1) {
|
|
4118
|
+
config$1[key] = override[key];
|
|
4119
|
+
}
|
|
4120
|
+
}
|
|
4121
|
+
return true;
|
|
4122
|
+
}
|
|
4123
|
+
// Suspend ends the current Clarity instance after a configured timeout period
|
|
4124
|
+
// The way it differs from the "end" call is that it starts listening to
|
|
4125
|
+
// user interaction events as soon as it terminates existing clarity instance.
|
|
4126
|
+
// On the next interaction, it automatically starts another instance under a different page id
|
|
4127
|
+
// E.g. if configured timeout is 10m, and user stays inactive for an hour.
|
|
4128
|
+
// In this case, we will suspend clarity after 10m of inactivity and after another 50m when user interacts again
|
|
4129
|
+
// Clarity will restart and start another instance seamlessly. Effectively not missing any active time, but also
|
|
4130
|
+
// not holding the session during inactive time periods.
|
|
4131
|
+
function suspend() {
|
|
4132
|
+
if (status) {
|
|
4133
|
+
event("clarity" /* Clarity */, "suspend" /* Suspend */);
|
|
4134
|
+
stop();
|
|
4135
|
+
["document", "touchstart"].forEach(function (x) { return bind(document, x, restart); });
|
|
4136
|
+
["resize", "scroll", "pageshow"].forEach(function (x) { return bind(window, x, restart); });
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
function restart() {
|
|
4140
|
+
start();
|
|
4141
|
+
event("clarity" /* Clarity */, "restart" /* Restart */);
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
function start$6() {
|
|
4145
|
+
start$p();
|
|
4146
|
+
start$s();
|
|
4147
|
+
start$o();
|
|
4148
|
+
}
|
|
4149
|
+
function stop$5() {
|
|
4150
|
+
stop$p();
|
|
4151
|
+
stop$n();
|
|
4152
|
+
}
|
|
4153
|
+
|
|
4154
|
+
var diagnostic = /*#__PURE__*/Object.freeze({
|
|
4155
|
+
__proto__: null,
|
|
4156
|
+
start: start$6,
|
|
4157
|
+
stop: stop$5
|
|
4158
|
+
});
|
|
4159
|
+
|
|
4160
|
+
function start$5() {
|
|
4161
|
+
schedule$1(discover, 1 /* High */).then(function () {
|
|
4162
|
+
measure(compute$6)();
|
|
4163
|
+
measure(compute$4)();
|
|
4164
|
+
});
|
|
4165
|
+
}
|
|
4166
|
+
function discover() {
|
|
4167
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
4168
|
+
var ts, timer;
|
|
4169
|
+
return __generator(this, function (_a) {
|
|
4170
|
+
switch (_a.label) {
|
|
4171
|
+
case 0:
|
|
4172
|
+
ts = time();
|
|
4173
|
+
timer = { id: id(), cost: 3 /* LayoutCost */ };
|
|
4174
|
+
start$t(timer);
|
|
4175
|
+
return [4 /*yield*/, traverse(document, timer, 0 /* Discover */)];
|
|
4176
|
+
case 1:
|
|
4177
|
+
_a.sent();
|
|
4178
|
+
return [4 /*yield*/, encode$4(5 /* Discover */, timer, ts)];
|
|
4179
|
+
case 2:
|
|
4180
|
+
_a.sent();
|
|
4181
|
+
stop$q(timer);
|
|
4182
|
+
return [2 /*return*/];
|
|
4183
|
+
}
|
|
4184
|
+
});
|
|
4185
|
+
});
|
|
4186
|
+
}
|
|
4187
|
+
|
|
4188
|
+
function start$4() {
|
|
4189
|
+
// The order below is important
|
|
4190
|
+
// and is determined by interdependencies of modules
|
|
4191
|
+
start$r();
|
|
4192
|
+
start$m();
|
|
4193
|
+
start$n();
|
|
4194
|
+
start$c();
|
|
4195
|
+
start$5();
|
|
4196
|
+
start$q();
|
|
4197
|
+
}
|
|
4198
|
+
function stop$4() {
|
|
4199
|
+
stop$l();
|
|
4200
|
+
stop$m();
|
|
4201
|
+
stop$b();
|
|
4202
|
+
stop$o();
|
|
4203
|
+
end();
|
|
4204
|
+
}
|
|
4205
|
+
|
|
4206
|
+
var layout = /*#__PURE__*/Object.freeze({
|
|
4207
|
+
__proto__: null,
|
|
4208
|
+
start: start$4,
|
|
4209
|
+
stop: stop$4
|
|
4210
|
+
});
|
|
4211
|
+
|
|
4212
|
+
var data$1 = null;
|
|
4213
|
+
function reset$1() {
|
|
4214
|
+
data$1 = null;
|
|
4215
|
+
}
|
|
4216
|
+
function compute(entry) {
|
|
4217
|
+
data$1 = {
|
|
4218
|
+
fetchStart: Math.round(entry.fetchStart),
|
|
4219
|
+
connectStart: Math.round(entry.connectStart),
|
|
4220
|
+
connectEnd: Math.round(entry.connectEnd),
|
|
4221
|
+
requestStart: Math.round(entry.requestStart),
|
|
4222
|
+
responseStart: Math.round(entry.responseStart),
|
|
4223
|
+
responseEnd: Math.round(entry.responseEnd),
|
|
4224
|
+
domInteractive: Math.round(entry.domInteractive),
|
|
4225
|
+
domComplete: Math.round(entry.domComplete),
|
|
4226
|
+
loadEventStart: Math.round(entry.loadEventStart),
|
|
4227
|
+
loadEventEnd: Math.round(entry.loadEventEnd),
|
|
4228
|
+
redirectCount: Math.round(entry.redirectCount),
|
|
4229
|
+
size: entry.transferSize ? entry.transferSize : 0,
|
|
4230
|
+
type: entry.type,
|
|
4231
|
+
protocol: entry.nextHopProtocol,
|
|
4232
|
+
encodedSize: entry.encodedBodySize ? entry.encodedBodySize : 0,
|
|
4233
|
+
decodedSize: entry.decodedBodySize ? entry.decodedBodySize : 0
|
|
4234
|
+
};
|
|
4235
|
+
encode(29 /* Navigation */);
|
|
4236
|
+
}
|
|
4237
|
+
|
|
4238
|
+
function encode (type) {
|
|
4239
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
4240
|
+
var t, tokens;
|
|
4241
|
+
return __generator(this, function (_a) {
|
|
4242
|
+
t = time();
|
|
4243
|
+
tokens = [t, type];
|
|
4244
|
+
switch (type) {
|
|
4245
|
+
case 30 /* Connection */:
|
|
4246
|
+
tokens.push(data.downlink);
|
|
4247
|
+
tokens.push(data.rtt);
|
|
4248
|
+
tokens.push(data.saveData);
|
|
4249
|
+
tokens.push(data.type);
|
|
4250
|
+
reset();
|
|
4251
|
+
queue(tokens, false);
|
|
4252
|
+
break;
|
|
4253
|
+
case 29 /* Navigation */:
|
|
4254
|
+
tokens.push(data$1.fetchStart);
|
|
4255
|
+
tokens.push(data$1.connectStart);
|
|
4256
|
+
tokens.push(data$1.connectEnd);
|
|
4257
|
+
tokens.push(data$1.requestStart);
|
|
4258
|
+
tokens.push(data$1.responseStart);
|
|
4259
|
+
tokens.push(data$1.responseEnd);
|
|
4260
|
+
tokens.push(data$1.domInteractive);
|
|
4261
|
+
tokens.push(data$1.domComplete);
|
|
4262
|
+
tokens.push(data$1.loadEventStart);
|
|
4263
|
+
tokens.push(data$1.loadEventEnd);
|
|
4264
|
+
tokens.push(data$1.redirectCount);
|
|
4265
|
+
tokens.push(data$1.size);
|
|
4266
|
+
tokens.push(data$1.type);
|
|
4267
|
+
tokens.push(data$1.protocol);
|
|
4268
|
+
tokens.push(data$1.encodedSize);
|
|
4269
|
+
tokens.push(data$1.decodedSize);
|
|
4270
|
+
reset$1();
|
|
4271
|
+
queue(tokens, false);
|
|
4272
|
+
break;
|
|
4273
|
+
}
|
|
4274
|
+
return [2 /*return*/];
|
|
4275
|
+
});
|
|
4276
|
+
});
|
|
4277
|
+
}
|
|
4278
|
+
|
|
4279
|
+
// Reference: https://wicg.github.io/netinfo/
|
|
4280
|
+
var data;
|
|
4281
|
+
function start$3() {
|
|
4282
|
+
// Check if the client supports Navigator.Connection: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/connection
|
|
4283
|
+
// This is an experimental API so we go a bit deeper in our check and ensure that values returned are valid
|
|
4284
|
+
if (navigator &&
|
|
4285
|
+
"connection" in navigator &&
|
|
4286
|
+
"downlink" in navigator["connection"] &&
|
|
4287
|
+
typeof navigator["connection"]["downlink"] === "number") {
|
|
4288
|
+
navigator["connection"].addEventListener("change", recompute);
|
|
4289
|
+
recompute();
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
4292
|
+
function recompute() {
|
|
4293
|
+
var connection = navigator["connection"];
|
|
4294
|
+
data = {
|
|
4295
|
+
downlink: connection.downlink,
|
|
4296
|
+
rtt: connection.rtt,
|
|
4297
|
+
saveData: connection.saveData ? 1 /* True */ : 0 /* False */,
|
|
4298
|
+
type: connection.effectiveType
|
|
4299
|
+
};
|
|
4300
|
+
encode(30 /* Connection */);
|
|
4301
|
+
}
|
|
4302
|
+
function reset() {
|
|
4303
|
+
data = null;
|
|
4304
|
+
}
|
|
4305
|
+
function stop$3() {
|
|
4306
|
+
reset();
|
|
4307
|
+
}
|
|
4308
|
+
|
|
4309
|
+
var observer;
|
|
4310
|
+
var types = ["navigation" /* Navigation */, "resource" /* Resource */, "longtask" /* LongTask */, "first-input" /* FID */, "layout-shift" /* CLS */, "largest-contentful-paint" /* LCP */];
|
|
4311
|
+
function start$2() {
|
|
4312
|
+
// Check the browser support performance observer as a pre-requisite for any performance measurement
|
|
4313
|
+
if (window["PerformanceObserver"] && PerformanceObserver.supportedEntryTypes) {
|
|
4314
|
+
// Start monitoring performance data after page has finished loading.
|
|
4315
|
+
// If the document.readyState is not yet complete, we intentionally call observe using a setTimeout.
|
|
4316
|
+
// This allows us to capture loadEventEnd on navigation timeline.
|
|
4317
|
+
if (document.readyState !== "complete") {
|
|
4318
|
+
bind(window, "load", setTimeout.bind(this, observe, 0));
|
|
4319
|
+
}
|
|
4320
|
+
else {
|
|
4321
|
+
observe();
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
else {
|
|
4325
|
+
log(3 /* PerformanceObserver */, 0 /* Info */);
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
function observe() {
|
|
4329
|
+
// Some browsers will throw an error for unsupported entryType, e.g. "layout-shift"
|
|
4330
|
+
// In those cases, we log it as a warning and continue with rest of the Clarity processing
|
|
4331
|
+
try {
|
|
4332
|
+
if (observer) {
|
|
4333
|
+
observer.disconnect();
|
|
4334
|
+
}
|
|
4335
|
+
observer = new PerformanceObserver(measure(handle));
|
|
4336
|
+
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver/observe
|
|
4337
|
+
// "buffered" flag indicates whether buffered entries should be queued into the observer's buffer.
|
|
4338
|
+
// It must only be used only with the "type" option, and cannot be used with entryTypes.
|
|
4339
|
+
// This is why we need to individually "observe" each supported type
|
|
4340
|
+
for (var _i = 0, types_1 = types; _i < types_1.length; _i++) {
|
|
4341
|
+
var x = types_1[_i];
|
|
4342
|
+
if (PerformanceObserver.supportedEntryTypes.indexOf(x) >= 0) {
|
|
4343
|
+
// Initialize CLS with a value of zero. It's possible (and recommended) for sites to not have any cumulative layout shift.
|
|
4344
|
+
// In those cases, we want to still initialize the metric in Clarity
|
|
4345
|
+
if (x === "layout-shift" /* CLS */) {
|
|
4346
|
+
sum(9 /* CumulativeLayoutShift */, 0);
|
|
4347
|
+
}
|
|
4348
|
+
observer.observe({ type: x, buffered: true });
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
}
|
|
4352
|
+
catch (_a) {
|
|
4353
|
+
log(3 /* PerformanceObserver */, 1 /* Warning */);
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
function handle(entries) {
|
|
4357
|
+
process(entries.getEntries());
|
|
4358
|
+
}
|
|
4359
|
+
function process(entries) {
|
|
4360
|
+
var visible = "visibilityState" in document ? document.visibilityState === "visible" : true;
|
|
4361
|
+
for (var i = 0; i < entries.length; i++) {
|
|
4362
|
+
var entry = entries[i];
|
|
4363
|
+
switch (entry.entryType) {
|
|
4364
|
+
case "navigation" /* Navigation */:
|
|
4365
|
+
compute(entry);
|
|
4366
|
+
break;
|
|
4367
|
+
case "resource" /* Resource */:
|
|
4368
|
+
log$1(4 /* NetworkHosts */, host(entry.name));
|
|
4369
|
+
break;
|
|
4370
|
+
case "longtask" /* LongTask */:
|
|
4371
|
+
count$1(7 /* LongTaskCount */);
|
|
4372
|
+
break;
|
|
4373
|
+
case "first-input" /* FID */:
|
|
4374
|
+
if (visible) {
|
|
4375
|
+
max(10 /* FirstInputDelay */, entry["processingStart"] - entry.startTime);
|
|
4376
|
+
}
|
|
4377
|
+
break;
|
|
4378
|
+
case "layout-shift" /* CLS */:
|
|
4379
|
+
// Scale the value to avoid sending back floating point number
|
|
4380
|
+
if (visible && !entry["hadRecentInput"]) {
|
|
4381
|
+
sum(9 /* CumulativeLayoutShift */, entry["value"] * 1000);
|
|
4382
|
+
}
|
|
4383
|
+
break;
|
|
4384
|
+
case "largest-contentful-paint" /* LCP */:
|
|
4385
|
+
if (visible) {
|
|
4386
|
+
max(8 /* LargestPaint */, entry.startTime);
|
|
4387
|
+
}
|
|
4388
|
+
break;
|
|
4389
|
+
}
|
|
4390
|
+
}
|
|
4391
|
+
}
|
|
4392
|
+
function stop$2() {
|
|
4393
|
+
if (observer) {
|
|
4394
|
+
observer.disconnect();
|
|
4395
|
+
}
|
|
4396
|
+
observer = null;
|
|
4397
|
+
}
|
|
4398
|
+
function host(url) {
|
|
4399
|
+
var a = document.createElement("a");
|
|
4400
|
+
a.href = url;
|
|
4401
|
+
return a.hostname;
|
|
4402
|
+
}
|
|
4403
|
+
|
|
4404
|
+
function start$1() {
|
|
4405
|
+
reset$1();
|
|
4406
|
+
start$3();
|
|
4407
|
+
start$2();
|
|
4408
|
+
}
|
|
4409
|
+
function stop$1() {
|
|
4410
|
+
stop$2();
|
|
4411
|
+
stop$3();
|
|
4412
|
+
reset$1();
|
|
4413
|
+
}
|
|
4414
|
+
|
|
4415
|
+
var performance$1 = /*#__PURE__*/Object.freeze({
|
|
4416
|
+
__proto__: null,
|
|
4417
|
+
start: start$1,
|
|
4418
|
+
stop: stop$1
|
|
4419
|
+
});
|
|
4420
|
+
|
|
4421
|
+
var modules = [diagnostic, layout, interaction, performance$1];
|
|
4422
|
+
function start(config$1) {
|
|
4423
|
+
if (config$1 === void 0) { config$1 = null; }
|
|
4424
|
+
// Check that browser supports required APIs and we do not attempt to start Clarity multiple times
|
|
4425
|
+
if (check()) {
|
|
4426
|
+
config(config$1);
|
|
4427
|
+
start$7();
|
|
4428
|
+
start$u();
|
|
4429
|
+
modules.forEach(function (x) { return measure(x.start)(); });
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
// By default Clarity is asynchronous and will yield by looking for requestIdleCallback.
|
|
4433
|
+
// However, there can still be situations with single page apps where a user action can result
|
|
4434
|
+
// in the whole DOM being destroyed and reconstructed. While Clarity will perform favorably out of the box,
|
|
4435
|
+
// we do allow external clients to manually pause Clarity for that short burst of time and minimize
|
|
4436
|
+
// performance impact even further. For reference, we are talking single digit milliseconds optimization here, not seconds.
|
|
4437
|
+
function pause() {
|
|
4438
|
+
if (active()) {
|
|
4439
|
+
event("clarity" /* Clarity */, "pause" /* Pause */);
|
|
4440
|
+
pause$1();
|
|
4441
|
+
}
|
|
4442
|
+
}
|
|
4443
|
+
// This is how external clients can get out of pause state, and resume Clarity to continue monitoring the page
|
|
4444
|
+
function resume() {
|
|
4445
|
+
if (active()) {
|
|
4446
|
+
resume$1();
|
|
4447
|
+
event("clarity" /* Clarity */, "resume" /* Resume */);
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
function stop() {
|
|
4451
|
+
if (active()) {
|
|
4452
|
+
// Stop modules in the reverse order of their initialization
|
|
4453
|
+
modules.slice().reverse().forEach(function (x) { return measure(x.stop)(); });
|
|
4454
|
+
stop$r();
|
|
4455
|
+
stop$6();
|
|
4456
|
+
}
|
|
4457
|
+
}
|
|
4458
|
+
|
|
4459
|
+
var clarity = /*#__PURE__*/Object.freeze({
|
|
4460
|
+
__proto__: null,
|
|
4461
|
+
version: version$1,
|
|
4462
|
+
start: start,
|
|
4463
|
+
pause: pause,
|
|
4464
|
+
resume: resume,
|
|
4465
|
+
stop: stop,
|
|
4466
|
+
consent: consent,
|
|
4467
|
+
event: event,
|
|
4468
|
+
identify: identify,
|
|
4469
|
+
set: set,
|
|
4470
|
+
upgrade: upgrade,
|
|
4471
|
+
metadata: metadata$2
|
|
4472
|
+
});
|
|
4473
|
+
|
|
4474
|
+
var helper = { hash: hash, selector: selector };
|
|
4475
|
+
var version = version$1;
|
|
4476
|
+
|
|
4477
|
+
exports.clarity = clarity;
|
|
4478
|
+
exports.helper = helper;
|
|
4479
|
+
exports.version = version;
|