clarity-js 0.7.70 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,23 @@
1
+ var dom = /*#__PURE__*/Object.freeze({
2
+ __proto__: null,
3
+ get add () { return add; },
4
+ get get () { return get; },
5
+ get getId () { return getId; },
6
+ get getNode () { return getNode; },
7
+ get getValue () { return getValue; },
8
+ get has () { return has$1; },
9
+ get hashText () { return hashText; },
10
+ get iframe () { return iframe; },
11
+ get iframeContent () { return iframeContent; },
12
+ get lookup () { return lookup; },
13
+ get parse () { return parse$1; },
14
+ get removeIFrame () { return removeIFrame; },
15
+ get sameorigin () { return sameorigin; },
16
+ get start () { return start$i; },
17
+ get stop () { return stop$g; },
18
+ get update () { return update$1; },
19
+ get updates () { return updates$2; }
20
+ });
1
21
  var upload$1 = /*#__PURE__*/Object.freeze({
2
22
  __proto__: null,
3
23
  get queue () { return queue; },
@@ -167,7 +187,7 @@ function stop$F() {
167
187
  startTime = 0;
168
188
  }
169
189
 
170
- var version$1 = "0.7.70";
190
+ var version$1 = "0.8.1";
171
191
 
172
192
  // tslint:disable: no-bitwise
173
193
  function hash (input, precision) {
@@ -430,19 +450,19 @@ function reset$s() {
430
450
  pointerY: 0,
431
451
  activityTime: 0,
432
452
  scrollTime: 0,
433
- pointerTime: 0,
434
- moveX: 0,
435
- moveY: 0,
436
- moveTime: 0,
437
- downX: 0,
438
- downY: 0,
439
- downTime: 0,
440
- upX: 0,
441
- upY: 0,
442
- upTime: 0,
443
- pointerPrevX: 0,
444
- pointerPrevY: 0,
445
- pointerPrevTime: 0,
453
+ pointerTime: undefined,
454
+ moveX: undefined,
455
+ moveY: undefined,
456
+ moveTime: undefined,
457
+ downX: undefined,
458
+ downY: undefined,
459
+ downTime: undefined,
460
+ upX: undefined,
461
+ upY: undefined,
462
+ upTime: undefined,
463
+ pointerPrevX: undefined,
464
+ pointerPrevY: undefined,
465
+ pointerPrevTime: undefined,
446
466
  };
447
467
  }
448
468
  function track$8(event, x, y, time) {
@@ -1028,1440 +1048,1355 @@ function check$4(id, target, input) {
1028
1048
  }
1029
1049
  }
1030
1050
 
1031
- var excludeClassNames = "load,active,fixed,visible,focus,show,collaps,animat" /* Constant.ExcludeClassNames */.split("," /* Constant.Comma */);
1032
- var selectorMap = {};
1051
+ // Track the start time to be able to compute duration at the end of the task
1052
+ var idleTimeout = 5000;
1053
+ var tracker = {};
1054
+ var queuedTasks = [];
1055
+ var activeTask = null;
1056
+ var pauseTask = null;
1057
+ var resumeResolve = null;
1058
+ function pause$1() {
1059
+ if (pauseTask === null) {
1060
+ pauseTask = new Promise(function (resolve) {
1061
+ resumeResolve = resolve;
1062
+ });
1063
+ }
1064
+ }
1065
+ function resume$1() {
1066
+ if (pauseTask) {
1067
+ resumeResolve();
1068
+ pauseTask = null;
1069
+ if (activeTask === null) {
1070
+ run();
1071
+ }
1072
+ }
1073
+ }
1033
1074
  function reset$n() {
1034
- selectorMap = {};
1075
+ tracker = {};
1076
+ queuedTasks = [];
1077
+ activeTask = null;
1078
+ pauseTask = null;
1035
1079
  }
1036
- function get$1(input, type) {
1037
- var a = input.attributes;
1038
- var prefix = input.prefix ? input.prefix[type] : null;
1039
- var suffix = type === 0 /* Selector.Alpha */ ? "".concat("~" /* Constant.Tilde */).concat(input.position - 1) : ":nth-of-type(".concat(input.position, ")");
1040
- switch (input.tag) {
1041
- case "STYLE":
1042
- case "TITLE":
1043
- case "LINK":
1044
- case "META":
1045
- case "*T" /* Constant.TextTag */:
1046
- case "*D" /* Constant.DocumentTag */:
1047
- return "" /* Constant.Empty */;
1048
- case "HTML":
1049
- return "HTML" /* Constant.HTML */;
1050
- default:
1051
- if (prefix === null) {
1052
- return "" /* Constant.Empty */;
1053
- }
1054
- prefix = "".concat(prefix).concat(">" /* Constant.Separator */);
1055
- input.tag = input.tag.indexOf("svg:" /* Constant.SvgPrefix */) === 0 ? input.tag.substr("svg:" /* Constant.SvgPrefix */.length) : input.tag;
1056
- var selector = "".concat(prefix).concat(input.tag).concat(suffix);
1057
- var id = "id" /* Constant.Id */ in a && a["id" /* Constant.Id */].length > 0 ? a["id" /* Constant.Id */] : null;
1058
- var classes = input.tag !== "BODY" /* Constant.BodyTag */ && "class" /* Constant.Class */ in a && a["class" /* Constant.Class */].length > 0 ? a["class" /* Constant.Class */].trim().split(/\s+/).filter(function (c) { return filter(c); }).join("." /* Constant.Period */) : null;
1059
- if (classes && classes.length > 0) {
1060
- if (type === 0 /* Selector.Alpha */) {
1061
- // In Alpha mode, update selector to use class names, with relative positioning within the parent id container.
1062
- // If the node has valid class name(s) then drop relative positioning within the parent path to keep things simple.
1063
- var key = "".concat(getDomPath(prefix)).concat(input.tag).concat("." /* Constant.Dot */).concat(classes);
1064
- if (!(key in selectorMap)) {
1065
- selectorMap[key] = [];
1066
- }
1067
- if (selectorMap[key].indexOf(input.id) < 0) {
1068
- selectorMap[key].push(input.id);
1069
- }
1070
- selector = "".concat(key).concat("~" /* Constant.Tilde */).concat(selectorMap[key].indexOf(input.id));
1071
- }
1072
- else {
1073
- // In Beta mode, we continue to look at query selectors in context of the full page
1074
- selector = "".concat(prefix).concat(input.tag, ".").concat(classes).concat(suffix);
1080
+ function schedule$1(task, priority) {
1081
+ if (priority === void 0) { priority = 0 /* Priority.Normal */; }
1082
+ return __awaiter(this, void 0, void 0, function () {
1083
+ var _i, queuedTasks_1, q, promise;
1084
+ return __generator(this, function (_a) {
1085
+ // If this task is already scheduled, skip it
1086
+ for (_i = 0, queuedTasks_1 = queuedTasks; _i < queuedTasks_1.length; _i++) {
1087
+ q = queuedTasks_1[_i];
1088
+ if (q.task === task) {
1089
+ return [2 /*return*/];
1075
1090
  }
1076
1091
  }
1077
- // Update selector to use "id" field when available. There are two exceptions:
1078
- // (1) if "id" appears to be an auto generated string token, e.g. guid or a random id containing digits
1079
- // (2) if "id" appears inside a shadow DOM, in which case we continue to prefix up to shadow DOM to prevent conflicts
1080
- selector = id && filter(id) ? "".concat(getDomPrefix(prefix)).concat("#" /* Constant.Hash */).concat(id) : selector;
1081
- return selector;
1082
- }
1092
+ promise = new Promise(function (resolve) {
1093
+ var insert = priority === 1 /* Priority.High */ ? "unshift" : "push";
1094
+ // Queue this task for asynchronous execution later
1095
+ // We also store a unique page identifier (id) along with the task to ensure
1096
+ // ensure that we do not accidentally execute this task in context of a different page
1097
+ queuedTasks[insert]({ task: task, resolve: resolve, id: id() });
1098
+ });
1099
+ // If there is no active task running, and Clarity is not in pause state,
1100
+ // invoke the first task in the queue synchronously. This ensures that we don't yield the thread during unload event
1101
+ if (activeTask === null && pauseTask === null) {
1102
+ run();
1103
+ }
1104
+ return [2 /*return*/, promise];
1105
+ });
1106
+ });
1083
1107
  }
1084
- function getDomPrefix(prefix) {
1085
- var shadowDomStart = prefix.lastIndexOf("*S" /* Constant.ShadowDomTag */);
1086
- var iframeDomStart = prefix.lastIndexOf("".concat("iframe:" /* Constant.IFramePrefix */).concat("HTML" /* Constant.HTML */));
1087
- var domStart = Math.max(shadowDomStart, iframeDomStart);
1088
- if (domStart < 0) {
1089
- return "" /* Constant.Empty */;
1108
+ function run() {
1109
+ var entry = queuedTasks.shift();
1110
+ if (entry) {
1111
+ activeTask = entry;
1112
+ entry.task().then(function () {
1113
+ // Bail out if the context in which this task was operating is different from the current page
1114
+ // An example scenario where task could span across pages is Single Page Applications (SPA)
1115
+ // A task that started on page #1, but completes on page #2
1116
+ if (entry.id !== id()) {
1117
+ return;
1118
+ }
1119
+ entry.resolve();
1120
+ activeTask = null; // Reset active task back to null now that the promise is resolved
1121
+ run();
1122
+ }).catch(function (error) {
1123
+ // If one of the scheduled tasks failed, log, recover and continue processing rest of the tasks
1124
+ if (entry.id !== id()) {
1125
+ return;
1126
+ }
1127
+ if (error) {
1128
+ log$1(0 /* Code.RunTask */, 1 /* Severity.Warning */, error.name, error.message, error.stack);
1129
+ }
1130
+ activeTask = null;
1131
+ run();
1132
+ });
1090
1133
  }
1091
- return prefix.substring(0, prefix.indexOf(">" /* Constant.Separator */, domStart) + 1);
1092
1134
  }
1093
- function getDomPath(input) {
1094
- var parts = input.split(">" /* Constant.Separator */);
1095
- for (var i = 0; i < parts.length; i++) {
1096
- var tIndex = parts[i].indexOf("~" /* Constant.Tilde */);
1097
- var dIndex = parts[i].indexOf("." /* Constant.Dot */);
1098
- parts[i] = parts[i].substring(0, dIndex > 0 ? dIndex : (tIndex > 0 ? tIndex : parts[i].length));
1135
+ function state$a(timer) {
1136
+ var id = key(timer);
1137
+ if (id in tracker) {
1138
+ var elapsed = performance.now() - tracker[id].start;
1139
+ return (elapsed > tracker[id].yield) ? 0 /* Task.Wait */ : 1 /* Task.Run */;
1099
1140
  }
1100
- return parts.join(">" /* Constant.Separator */);
1141
+ // If this task is no longer being tracked, send stop message to the caller
1142
+ return 2 /* Task.Stop */;
1101
1143
  }
1102
- // Check if the given input string has digits or excluded class names
1103
- function filter(value) {
1104
- if (!value) {
1105
- return false;
1106
- } // Do not process empty strings
1107
- if (excludeClassNames.some(function (x) { return value.toLowerCase().indexOf(x) >= 0; })) {
1108
- return false;
1109
- }
1110
- for (var i = 0; i < value.length; i++) {
1111
- var c = value.charCodeAt(i);
1112
- if (c >= 48 /* Character.Zero */ && c <= 57 /* Character.Nine */) {
1113
- return false;
1114
- }
1144
+ function start$z(timer) {
1145
+ tracker[key(timer)] = { start: performance.now(), calls: 0, yield: 30 /* Setting.LongTask */ };
1146
+ }
1147
+ function restart$2(timer) {
1148
+ var id = key(timer);
1149
+ if (tracker && tracker[id]) {
1150
+ var c = tracker[id].calls;
1151
+ var y = tracker[id].yield;
1152
+ start$z(timer);
1153
+ tracker[id].calls = c + 1;
1154
+ tracker[id].yield = y;
1115
1155
  }
1116
- return true;
1117
1156
  }
1118
-
1119
- var selector = /*#__PURE__*/Object.freeze({
1120
- __proto__: null,
1121
- get: get$1,
1122
- reset: reset$n
1123
- });
1124
-
1125
- var index = 1;
1126
- var nodesMap = null; // Maps id => node to retrieve further node details using id.
1127
- var values = [];
1128
- var updateMap = [];
1129
- var hashMap = {};
1130
- var override = [];
1131
- var unmask = [];
1132
- var maskText = [];
1133
- var maskExclude = [];
1134
- var maskDisable = [];
1135
- var maskTags = [];
1136
- // The WeakMap object is a collection of key/value pairs in which the keys are weakly referenced
1137
- var idMap = null; // Maps node => id.
1138
- var iframeMap = null; // Maps iframe's contentDocument => parent iframe element
1139
- var privacyMap = null; // Maps node => Privacy (enum)
1140
- var fraudMap = null; // Maps node => FraudId (number)
1141
- function start$z() {
1142
- reset$m();
1143
- parse$1(document, true);
1157
+ function stop$x(timer) {
1158
+ var end = performance.now();
1159
+ var id = key(timer);
1160
+ var duration = end - tracker[id].start;
1161
+ sum(timer.cost, duration);
1162
+ count$1(5 /* Metric.InvokeCount */);
1163
+ // For the first execution, which is synchronous, time is automatically counted towards TotalDuration.
1164
+ // However, for subsequent asynchronous runs, we need to manually update TotalDuration metric.
1165
+ if (tracker[id].calls > 0) {
1166
+ sum(4 /* Metric.TotalCost */, duration);
1167
+ }
1144
1168
  }
1145
- function stop$x() {
1146
- reset$m();
1169
+ function suspend$1(timer) {
1170
+ return __awaiter(this, void 0, void 0, function () {
1171
+ var id, _a;
1172
+ return __generator(this, function (_b) {
1173
+ switch (_b.label) {
1174
+ case 0:
1175
+ id = key(timer);
1176
+ if (!(id in tracker)) return [3 /*break*/, 2];
1177
+ stop$x(timer);
1178
+ _a = tracker[id];
1179
+ return [4 /*yield*/, wait()];
1180
+ case 1:
1181
+ _a.yield = (_b.sent()).timeRemaining();
1182
+ restart$2(timer);
1183
+ _b.label = 2;
1184
+ case 2:
1185
+ // After we are done with suspending task, ensure that we are still operating in the right context
1186
+ // If the task is still being tracked, continue running the task, otherwise ask caller to stop execution
1187
+ return [2 /*return*/, id in tracker ? 1 /* Task.Run */ : 2 /* Task.Stop */];
1188
+ }
1189
+ });
1190
+ });
1147
1191
  }
1148
- function reset$m() {
1149
- index = 1;
1150
- values = [];
1151
- updateMap = [];
1152
- hashMap = {};
1153
- override = [];
1154
- unmask = [];
1155
- maskText = "address,password,contact" /* Mask.Text */.split("," /* Constant.Comma */);
1156
- maskExclude = "password,secret,pass,social,ssn,code,hidden" /* Mask.Exclude */.split("," /* Constant.Comma */);
1157
- maskDisable = "radio,checkbox,range,button,reset,submit" /* Mask.Disable */.split("," /* Constant.Comma */);
1158
- maskTags = "INPUT,SELECT,TEXTAREA" /* Mask.Tags */.split("," /* Constant.Comma */);
1159
- nodesMap = new Map();
1160
- idMap = new WeakMap();
1161
- iframeMap = new WeakMap();
1162
- privacyMap = new WeakMap();
1163
- fraudMap = new WeakMap();
1164
- reset$n();
1192
+ function key(timer) {
1193
+ return "".concat(timer.id, ".").concat(timer.cost);
1165
1194
  }
1166
- // We parse new root nodes for any regions or masked nodes in the beginning (document) and
1167
- // later whenever there are new additions or modifications to DOM (mutations)
1168
- function parse$1(root, init) {
1169
- if (init === void 0) { init = false; }
1170
- // Wrap selectors in a try / catch block.
1171
- // It's possible for script to receive invalid selectors, e.g. "'#id'" with extra quotes, and cause the code below to fail
1172
- try {
1173
- // Parse unmask configuration into separate query selectors and override tokens as part of initialization
1174
- if (init) {
1175
- config$2.unmask.forEach(function (x) { return x.indexOf("!" /* Constant.Bang */) < 0 ? unmask.push(x) : override.push(x.substr(1)); });
1195
+ function wait() {
1196
+ return __awaiter(this, void 0, void 0, function () {
1197
+ return __generator(this, function (_a) {
1198
+ switch (_a.label) {
1199
+ case 0:
1200
+ if (!pauseTask) return [3 /*break*/, 2];
1201
+ return [4 /*yield*/, pauseTask];
1202
+ case 1:
1203
+ _a.sent();
1204
+ _a.label = 2;
1205
+ case 2: return [2 /*return*/, new Promise(function (resolve) {
1206
+ requestIdleCallback(resolve, { timeout: idleTimeout });
1207
+ })];
1208
+ }
1209
+ });
1210
+ });
1211
+ }
1212
+ // Use native implementation of requestIdleCallback if it exists.
1213
+ // Otherwise, fall back to a custom implementation using requestAnimationFrame & MessageChannel.
1214
+ // While it's not possible to build a perfect polyfill given the nature of this API, the following code attempts to get close.
1215
+ // Background context: requestAnimationFrame invokes the js code right before: style, layout and paint computation within the frame.
1216
+ // This means, that any code that runs as part of requestAnimationFrame will by default be blocking in nature. Not what we want.
1217
+ // For non-blocking behavior, We need to know when browser has finished painting. This can be accomplished in two different ways (hacks):
1218
+ // (1) Use MessageChannel to pass the message, and browser will receive the message right after paint event has occured.
1219
+ // (2) Use setTimeout call within requestAnimationFrame. This also works, but there's a risk that browser may throttle setTimeout calls.
1220
+ // Given this information, we are currently using (1) from above. More information on (2) as well as some additional context is below:
1221
+ // https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Performance_best_practices_for_Firefox_fe_engineers
1222
+ function requestIdleCallbackPolyfill(callback, options) {
1223
+ var startTime = performance.now();
1224
+ var channel = new MessageChannel();
1225
+ var incoming = channel.port1;
1226
+ var outgoing = channel.port2;
1227
+ incoming.onmessage = function (event) {
1228
+ var currentTime = performance.now();
1229
+ var elapsed = currentTime - startTime;
1230
+ var duration = currentTime - event.data;
1231
+ if (duration > 30 /* Setting.LongTask */ && elapsed < options.timeout) {
1232
+ requestAnimationFrame(function () { outgoing.postMessage(currentTime); });
1176
1233
  }
1177
- // Since mutations may happen on leaf nodes too, e.g. text nodes, which may not support all selector APIs.
1178
- // We ensure that the root note supports querySelectorAll API before executing the code below to identify new regions.
1179
- if ("querySelectorAll" in root) {
1180
- config$2.regions.forEach(function (x) { return root.querySelectorAll(x[1]).forEach(function (e) { return observe$1(e, "".concat(x[0])); }); }); // Regions
1181
- config$2.mask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 3 /* Privacy.TextImage */); }); }); // Masked Elements
1182
- config$2.checksum.forEach(function (x) { return root.querySelectorAll(x[1]).forEach(function (e) { return fraudMap.set(e, x[0]); }); }); // Fraud Checksum Check
1183
- unmask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 0 /* Privacy.None */); }); }); // Unmasked Elements
1234
+ else {
1235
+ var didTimeout_1 = elapsed > options.timeout;
1236
+ callback({
1237
+ didTimeout: didTimeout_1,
1238
+ timeRemaining: function () { return didTimeout_1 ? 30 /* Setting.LongTask */ : Math.max(0, 30 /* Setting.LongTask */ - duration); }
1239
+ });
1184
1240
  }
1185
- }
1186
- catch (e) {
1187
- log$1(5 /* Code.Selector */, 1 /* Severity.Warning */, e ? e.name : null);
1188
- }
1241
+ };
1242
+ requestAnimationFrame(function () { outgoing.postMessage(performance.now()); });
1189
1243
  }
1190
- function getId(node, autogen) {
1191
- if (autogen === void 0) { autogen = false; }
1192
- if (node === null) {
1193
- return null;
1244
+ var requestIdleCallback = window["requestIdleCallback"] || requestIdleCallbackPolyfill;
1245
+
1246
+ var state$9 = [];
1247
+ function start$y() {
1248
+ reset$m();
1249
+ }
1250
+ function observe$c(root) {
1251
+ bind(root, "change", recompute$8, true);
1252
+ }
1253
+ function recompute$8(evt) {
1254
+ recompute$8.dn = 5 /* FunctionNames.ChangeRecompute */;
1255
+ var element = target(evt);
1256
+ if (element) {
1257
+ var value = element.value;
1258
+ var checksum = value && value.length >= 5 /* Setting.WordLength */ && config$2.fraud && "password,secret,pass,social,ssn,code,hidden" /* Mask.Exclude */.indexOf(element.type) === -1 ? hash(value, 28 /* Setting.ChecksumPrecision */) : "" /* Constant.Empty */;
1259
+ state$9.push({ time: time(evt), event: 42 /* Event.Change */, data: { target: target(evt), type: element.type, value: value, checksum: checksum } });
1260
+ schedule$1(encode$3.bind(this, 42 /* Event.Change */));
1194
1261
  }
1195
- var id = idMap.get(node);
1196
- if (!id && autogen) {
1197
- id = index++;
1198
- idMap.set(node, id);
1262
+ }
1263
+ function reset$m() {
1264
+ state$9 = [];
1265
+ }
1266
+ function stop$w() {
1267
+ reset$m();
1268
+ }
1269
+
1270
+ function offset(element) {
1271
+ var output = { x: 0, y: 0 };
1272
+ // Walk up the chain to ensure we compute offset distance correctly
1273
+ // In case where we may have nested IFRAMEs, we keep walking up until we get to the top most parent page
1274
+ if (element && element.offsetParent) {
1275
+ do {
1276
+ var parent_1 = element.offsetParent;
1277
+ var frame = parent_1 === null ? iframe(element.ownerDocument) : null;
1278
+ output.x += element.offsetLeft;
1279
+ output.y += element.offsetTop;
1280
+ element = frame ? frame : parent_1;
1281
+ } while (element);
1199
1282
  }
1200
- return id ? id : null;
1283
+ return output;
1201
1284
  }
1202
- function add(node, parent, data, source) {
1203
- var parentId = parent ? getId(parent) : null;
1204
- // Do not add detached nodes
1205
- if ((!parent || !parentId) && node.host == null && node.nodeType !== Node.DOCUMENT_TYPE_NODE) {
1206
- return;
1285
+
1286
+ var UserInputTags = ["input", "textarea", "radio", "button", "canvas"];
1287
+ var state$8 = [];
1288
+ function start$x() {
1289
+ reset$l();
1290
+ }
1291
+ function observe$b(root) {
1292
+ bind(root, "click", handler$3.bind(this, 9 /* Event.Click */, root), true);
1293
+ }
1294
+ function handler$3(event, root, evt) {
1295
+ handler$3.dn = 6 /* FunctionNames.ClickHandler */;
1296
+ var frame = iframe(root);
1297
+ var d = frame ? frame.contentDocument.documentElement : document.documentElement;
1298
+ var x = "pageX" in evt ? Math.round(evt.pageX) : ("clientX" in evt ? Math.round(evt["clientX"] + d.scrollLeft) : null);
1299
+ var y = "pageY" in evt ? Math.round(evt.pageY) : ("clientY" in evt ? Math.round(evt["clientY"] + d.scrollTop) : null);
1300
+ // In case of iframe, we adjust (x,y) to be relative to top parent's origin
1301
+ if (frame) {
1302
+ var distance = offset(frame);
1303
+ x = x ? x + Math.round(distance.x) : x;
1304
+ y = y ? y + Math.round(distance.y) : y;
1207
1305
  }
1208
- var id = getId(node, true);
1209
- var previousId = getPreviousId(node);
1210
- var parentValue = null;
1211
- var regionId = exists(node) ? id : null;
1212
- var fraudId = fraudMap.has(node) ? fraudMap.get(node) : null;
1213
- var privacyId = config$2.content ? 1 /* Privacy.Sensitive */ : 3 /* Privacy.TextImage */;
1214
- if (parentId >= 0 && values[parentId]) {
1215
- parentValue = values[parentId];
1216
- parentValue.children.push(id);
1217
- regionId = regionId === null ? parentValue.region : regionId;
1218
- fraudId = fraudId === null ? parentValue.metadata.fraud : fraudId;
1219
- privacyId = parentValue.metadata.privacy;
1306
+ var t = target(evt);
1307
+ // Find nearest anchor tag (<a/>) parent if current target node is part of one
1308
+ // If present, we use the returned link element to populate text and link properties below
1309
+ var a = link(t);
1310
+ // Get layout rectangle for the target element
1311
+ var l = layout$1(t);
1312
+ // Reference: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
1313
+ // This property helps differentiate between a keyboard navigation vs. pointer click
1314
+ // In case of a keyboard navigation, we use center of target element as (x,y)
1315
+ if (evt.detail === 0 && l) {
1316
+ x = Math.round(l.x + (l.w / 2));
1317
+ y = Math.round(l.y + (l.h / 2));
1220
1318
  }
1221
- // If there's an explicit region attribute set on the element, use it to mark a region on the page
1222
- if (data.attributes && "data-clarity-region" /* Constant.RegionData */ in data.attributes) {
1223
- observe$1(node, data.attributes["data-clarity-region" /* Constant.RegionData */]);
1224
- regionId = id;
1319
+ var eX = l ? Math.max(Math.floor(((x - l.x) / l.w) * 32767 /* Setting.ClickPrecision */), 0) : 0;
1320
+ var eY = l ? Math.max(Math.floor(((y - l.y) / l.h) * 32767 /* Setting.ClickPrecision */), 0) : 0;
1321
+ // Check for null values before processing this event
1322
+ if (x !== null && y !== null) {
1323
+ var textInfo = text(t);
1324
+ state$8.push({
1325
+ time: time(evt),
1326
+ event: event,
1327
+ data: {
1328
+ target: t,
1329
+ x: x,
1330
+ y: y,
1331
+ eX: eX,
1332
+ eY: eY,
1333
+ button: evt.button,
1334
+ reaction: reaction(t),
1335
+ context: context(a),
1336
+ text: textInfo.text,
1337
+ link: a ? a.href : null,
1338
+ hash: null,
1339
+ trust: evt.isTrusted ? 1 /* BooleanFlag.True */ : 0 /* BooleanFlag.False */,
1340
+ isFullText: textInfo.isFullText,
1341
+ }
1342
+ });
1343
+ schedule$1(encode$3.bind(this, event));
1225
1344
  }
1226
- nodesMap.set(id, node);
1227
- values[id] = {
1228
- id: id,
1229
- parent: parentId,
1230
- previous: previousId,
1231
- children: [],
1232
- data: data,
1233
- selector: null,
1234
- hash: null,
1235
- region: regionId,
1236
- metadata: { active: true, suspend: false, privacy: privacyId, position: null, fraud: fraudId, size: null },
1237
- };
1238
- privacy(node, values[id], parentValue);
1239
- updateSelector(values[id]);
1240
- updateImageSize(values[id]);
1241
- track$6(id, source);
1242
1345
  }
1243
- function update$1(node, parent, data, source) {
1244
- var id = getId(node);
1245
- var parentId = parent ? getId(parent) : null;
1246
- var previousId = getPreviousId(node);
1247
- var changed = false;
1248
- var parentChanged = false;
1249
- if (id in values) {
1250
- var value = values[id];
1251
- value.metadata.active = true;
1252
- // Handle case where internal ordering may have changed
1253
- if (value.previous !== previousId) {
1254
- changed = true;
1255
- value.previous = previousId;
1256
- }
1257
- // Handle case where parent might have been updated
1258
- if (value.parent !== parentId) {
1259
- changed = true;
1260
- var oldParentId = value.parent;
1261
- value.parent = parentId;
1262
- // Move this node to the right location under new parent
1263
- if (parentId !== null && parentId >= 0) {
1264
- var childIndex = previousId === null ? 0 : values[parentId].children.indexOf(previousId) + 1;
1265
- values[parentId].children.splice(childIndex, 0, id);
1266
- // Update region after the move
1267
- value.region = exists(node) ? id : values[parentId].region;
1268
- }
1269
- else {
1270
- // Mark this element as deleted if the parent has been updated to null
1271
- remove(id, source);
1272
- }
1273
- // Remove reference to this node from the old parent
1274
- if (oldParentId !== null && oldParentId >= 0) {
1275
- var nodeIndex = values[oldParentId].children.indexOf(id);
1276
- if (nodeIndex >= 0) {
1277
- values[oldParentId].children.splice(nodeIndex, 1);
1278
- }
1279
- }
1280
- parentChanged = true;
1281
- }
1282
- // Update data
1283
- for (var key in data) {
1284
- if (diff(value["data"], data, key)) {
1285
- changed = true;
1286
- value["data"][key] = data[key];
1346
+ function link(node) {
1347
+ while (node && node !== document) {
1348
+ if (node.nodeType === Node.ELEMENT_NODE) {
1349
+ var element = node;
1350
+ if (element.tagName === "A") {
1351
+ return element;
1287
1352
  }
1288
1353
  }
1289
- // Update selector
1290
- updateSelector(value);
1291
- track$6(id, source, changed, parentChanged);
1354
+ node = node.parentNode;
1292
1355
  }
1356
+ return null;
1293
1357
  }
1294
- function sameorigin(node) {
1295
- var output = false;
1296
- if (node.nodeType === Node.ELEMENT_NODE && node.tagName === "IFRAME" /* Constant.IFrameTag */) {
1297
- var frame = node;
1298
- // To determine if the iframe is same-origin or not, we try accessing it's contentDocument.
1299
- // If the browser throws an exception, we assume it's cross-origin and move on.
1300
- // However, if we do a get a valid document object back, we assume the contents are accessible and iframe is same-origin.
1301
- try {
1302
- var doc = frame.contentDocument;
1303
- if (doc) {
1304
- iframeMap.set(frame.contentDocument, frame);
1305
- output = true;
1306
- }
1358
+ function text(element) {
1359
+ var output = null;
1360
+ var isFullText = false;
1361
+ if (element) {
1362
+ // Grab text using "textContent" for most HTMLElements, however, use "value" for HTMLInputElements and "alt" for HTMLImageElement.
1363
+ var t = element.textContent || String(element.value || '') || element.alt;
1364
+ if (t) {
1365
+ // Replace multiple occurrence of space characters with a single white space
1366
+ // Also, trim any spaces at the beginning or at the end of string
1367
+ var trimmedText = t.replace(/\s+/g, " " /* Constant.Space */).trim();
1368
+ // Finally, send only first few characters as specified by the Setting
1369
+ output = trimmedText.substring(0, 25 /* Setting.ClickText */);
1370
+ isFullText = output.length === trimmedText.length;
1307
1371
  }
1308
- catch ( /* do nothing */_a) { /* do nothing */ }
1309
- }
1310
- return output;
1311
- }
1312
- function iframe(node) {
1313
- var doc = node.nodeType === Node.DOCUMENT_NODE ? node : null;
1314
- return doc && iframeMap.has(doc) ? iframeMap.get(doc) : null;
1315
- }
1316
- function privacy(node, value, parent) {
1317
- var _a;
1318
- var data = value.data;
1319
- var metadata = value.metadata;
1320
- var current = metadata.privacy;
1321
- var attributes = data.attributes || {};
1322
- var tag = data.tag.toUpperCase();
1323
- switch (true) {
1324
- case maskTags.indexOf(tag) >= 0:
1325
- var type = attributes["type" /* Constant.Type */];
1326
- var meta_1 = "" /* Constant.Empty */;
1327
- var excludedPrivacyAttributes_1 = ["class" /* Constant.Class */, "style" /* Constant.Style */];
1328
- Object.keys(attributes)
1329
- .filter(function (x) { return !excludedPrivacyAttributes_1.includes(x); })
1330
- .forEach(function (x) { return (meta_1 += attributes[x].toLowerCase()); });
1331
- var exclude = maskExclude.some(function (x) { return meta_1.indexOf(x) >= 0; });
1332
- // Regardless of privacy mode, always mask off user input from input boxes or drop downs with two exceptions:
1333
- // (1) The node is detected to be one of the excluded fields, in which case we drop everything
1334
- // (2) The node's type is one of the allowed types (like checkboxes)
1335
- metadata.privacy = tag === "INPUT" /* Constant.InputTag */ && maskDisable.indexOf(type) >= 0 ? current : (exclude ? 4 /* Privacy.Exclude */ : 2 /* Privacy.Text */);
1336
- break;
1337
- case "data-clarity-mask" /* Constant.MaskData */ in attributes:
1338
- metadata.privacy = 3 /* Privacy.TextImage */;
1339
- break;
1340
- case "data-clarity-unmask" /* Constant.UnmaskData */ in attributes:
1341
- metadata.privacy = 0 /* Privacy.None */;
1342
- break;
1343
- case privacyMap.has(node):
1344
- // If this node was explicitly configured to contain sensitive content, honor that privacy setting
1345
- metadata.privacy = privacyMap.get(node);
1346
- break;
1347
- case fraudMap.has(node):
1348
- // If this node was explicitly configured to be evaluated for fraud, then also mask content
1349
- metadata.privacy = 2 /* Privacy.Text */;
1350
- break;
1351
- case tag === "*T" /* Constant.TextTag */:
1352
- // If it's a text node belonging to a STYLE or TITLE tag or one of scrub exceptions, then capture content
1353
- var pTag = parent && parent.data ? parent.data.tag : "" /* Constant.Empty */;
1354
- var pSelector_1 = parent && parent.selector ? parent.selector[1 /* Selector.Default */] : "" /* Constant.Empty */;
1355
- var tags = ["STYLE" /* Constant.StyleTag */, "TITLE" /* Constant.TitleTag */, "svg:style" /* Constant.SvgStyle */];
1356
- metadata.privacy = tags.includes(pTag) || override.some(function (x) { return pSelector_1.indexOf(x) >= 0; }) ? 0 /* Privacy.None */ : current;
1357
- break;
1358
- case current === 1 /* Privacy.Sensitive */:
1359
- // In a mode where we mask sensitive information by default, look through class names to aggressively mask content
1360
- metadata.privacy = inspect(attributes["class" /* Constant.Class */], maskText, metadata);
1361
- break;
1362
- case tag === "IMG" /* Constant.ImageTag */:
1363
- // Mask images with blob src as it is not publicly available anyway.
1364
- if ((_a = attributes.src) === null || _a === void 0 ? void 0 : _a.startsWith('blob:')) {
1365
- metadata.privacy = 3 /* Privacy.TextImage */;
1366
- }
1367
- break;
1368
1372
  }
1373
+ return { text: output, isFullText: isFullText ? 1 /* BooleanFlag.True */ : 0 /* BooleanFlag.False */ };
1369
1374
  }
1370
- function inspect(input, lookup, metadata) {
1371
- if (input && lookup.some(function (x) { return input.indexOf(x) >= 0; })) {
1372
- return 2 /* Privacy.Text */;
1375
+ function reaction(element) {
1376
+ if (element.nodeType === Node.ELEMENT_NODE) {
1377
+ var tag = element.tagName.toLowerCase();
1378
+ if (UserInputTags.indexOf(tag) >= 0) {
1379
+ return 0 /* BooleanFlag.False */;
1380
+ }
1373
1381
  }
1374
- return metadata.privacy;
1382
+ return 1 /* BooleanFlag.True */;
1375
1383
  }
1376
- function diff(a, b, field) {
1377
- if (typeof a[field] === "object" && typeof b[field] === "object") {
1378
- for (var key in a[field]) {
1379
- if (a[field][key] !== b[field][key]) {
1380
- return true;
1381
- }
1382
- }
1383
- for (var key in b[field]) {
1384
- if (b[field][key] !== a[field][key]) {
1385
- return true;
1386
- }
1384
+ function layout$1(element) {
1385
+ var box = null;
1386
+ var de = document.documentElement;
1387
+ if (typeof element.getBoundingClientRect === "function") {
1388
+ // getBoundingClientRect returns rectangle relative positioning to viewport
1389
+ var rect = element.getBoundingClientRect();
1390
+ if (rect && rect.width > 0 && rect.height > 0) {
1391
+ // Add viewport's scroll position to rectangle to get position relative to document origin
1392
+ // Also: using Math.floor() instead of Math.round() because in Edge,
1393
+ // getBoundingClientRect returns partial pixel values (e.g. 162.5px) and Chrome already
1394
+ // floors the value (e.g. 162px). This keeps consistent behavior across browsers.
1395
+ box = {
1396
+ x: Math.floor(rect.left + ("pageXOffset" in window ? window.pageXOffset : de.scrollLeft)),
1397
+ y: Math.floor(rect.top + ("pageYOffset" in window ? window.pageYOffset : de.scrollTop)),
1398
+ w: Math.floor(rect.width),
1399
+ h: Math.floor(rect.height)
1400
+ };
1387
1401
  }
1388
- return false;
1389
1402
  }
1390
- return a[field] !== b[field];
1403
+ return box;
1391
1404
  }
1392
- function position(parent, child) {
1393
- child.metadata.position = 1;
1394
- var idx = parent ? parent.children.indexOf(child.id) : -1;
1395
- while (idx-- > 0) {
1396
- var sibling = values[parent.children[idx]];
1397
- if (child.data.tag === sibling.data.tag) {
1398
- child.metadata.position = sibling.metadata.position + 1;
1399
- break;
1405
+ function context(a) {
1406
+ if (a && a.hasAttribute("target" /* Constant.Target */)) {
1407
+ switch (a.getAttribute("target" /* Constant.Target */)) {
1408
+ case "_blank" /* Constant.Blank */: return 1 /* BrowsingContext.Blank */;
1409
+ case "_parent" /* Constant.Parent */: return 2 /* BrowsingContext.Parent */;
1410
+ case "_top" /* Constant.Top */: return 3 /* BrowsingContext.Top */;
1400
1411
  }
1401
1412
  }
1402
- return child.metadata.position;
1413
+ return 0 /* BrowsingContext.Self */;
1403
1414
  }
1404
- function updateSelector(value) {
1405
- var parent = value.parent && value.parent in values ? values[value.parent] : null;
1406
- var prefix = parent ? parent.selector : null;
1407
- var d = value.data;
1408
- var p = position(parent, value);
1409
- var s = { id: value.id, tag: d.tag, prefix: prefix, position: p, attributes: d.attributes };
1410
- value.selector = [get$1(s, 0 /* Selector.Alpha */), get$1(s, 1 /* Selector.Beta */)];
1411
- value.hash = value.selector.map(function (x) { return x ? hash(x) : null; });
1412
- value.hash.forEach(function (h) { return hashMap[h] = value.id; });
1415
+ function reset$l() {
1416
+ state$8 = [];
1413
1417
  }
1414
- function hashText(hash) {
1415
- var id = lookup(hash);
1416
- var node = getNode(id);
1417
- return node !== null && node.textContent !== null ? node.textContent.substr(0, 25 /* Setting.ClickText */) : '';
1418
+ function stop$v() {
1419
+ reset$l();
1418
1420
  }
1419
- function getNode(id) {
1420
- return nodesMap.has(id) ? nodesMap.get(id) : null;
1421
+
1422
+ var state$7 = [];
1423
+ function start$w() {
1424
+ reset$k();
1421
1425
  }
1422
- function getValue(id) {
1423
- if (id in values) {
1424
- return values[id];
1425
- }
1426
- return null;
1426
+ function observe$a(root) {
1427
+ bind(root, "cut", recompute$7.bind(this, 0 /* Clipboard.Cut */), true);
1428
+ bind(root, "copy", recompute$7.bind(this, 1 /* Clipboard.Copy */), true);
1429
+ bind(root, "paste", recompute$7.bind(this, 2 /* Clipboard.Paste */), true);
1427
1430
  }
1428
- function get(node) {
1429
- var id = getId(node);
1430
- return id in values ? values[id] : null;
1431
+ function recompute$7(action, evt) {
1432
+ recompute$7.dn = 7 /* FunctionNames.ClipboardRecompute */;
1433
+ state$7.push({ time: time(evt), event: 38 /* Event.Clipboard */, data: { target: target(evt), action: action } });
1434
+ schedule$1(encode$3.bind(this, 38 /* Event.Clipboard */));
1431
1435
  }
1432
- function lookup(hash) {
1433
- return hash in hashMap ? hashMap[hash] : null;
1436
+ function reset$k() {
1437
+ state$7 = [];
1434
1438
  }
1435
- function has(node) {
1436
- return nodesMap.has(getId(node));
1439
+ function stop$u() {
1440
+ reset$k();
1437
1441
  }
1438
- function updates$2() {
1439
- var output = [];
1440
- for (var _i = 0, updateMap_1 = updateMap; _i < updateMap_1.length; _i++) {
1441
- var id = updateMap_1[_i];
1442
- if (id in values) {
1443
- output.push(values[id]);
1444
- }
1445
- }
1446
- updateMap = [];
1447
- return output;
1442
+
1443
+ var timeout$6 = null;
1444
+ var state$6 = [];
1445
+ function start$v() {
1446
+ reset$j();
1448
1447
  }
1449
- function remove(id, source) {
1450
- if (id in values) {
1451
- var value = values[id];
1452
- value.metadata.active = false;
1453
- value.parent = null;
1454
- track$6(id, source);
1455
- // Clean up node references for removed nodes
1456
- removeNodeFromNodesMap(id);
1457
- }
1448
+ function observe$9(root) {
1449
+ bind(root, "input", recompute$6, true);
1458
1450
  }
1459
- function removeNodeFromNodesMap(id) {
1460
- // Shadow dom roots shouldn't be deleted,
1461
- // we should keep listening to the mutations there even they're not rendered in the DOM.
1462
- if (nodesMap.get(id).nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
1463
- return;
1464
- }
1465
- nodesMap.delete(id);
1466
- var value = id in values ? values[id] : null;
1467
- if (value && value.children) {
1468
- for (var _i = 0, _a = value.children; _i < _a.length; _i++) {
1469
- var childId = _a[_i];
1470
- removeNodeFromNodesMap(childId);
1451
+ function recompute$6(evt) {
1452
+ recompute$6.dn = 9 /* FunctionNames.InputRecompute */;
1453
+ var input = target(evt);
1454
+ var value = get(input);
1455
+ if (input && input.type && value) {
1456
+ var v = input.value;
1457
+ var t = input.type;
1458
+ switch (input.type) {
1459
+ case "radio":
1460
+ case "checkbox":
1461
+ v = input.checked ? "true" : "false";
1462
+ break;
1471
1463
  }
1472
- }
1473
- }
1474
- function updateImageSize(value) {
1475
- // If this element is a image node, and is masked, then track box model for the current element
1476
- if (value.data.tag === "IMG" /* Constant.ImageTag */ && value.metadata.privacy === 3 /* Privacy.TextImage */) {
1477
- var img_1 = getNode(value.id);
1478
- // We will not capture the natural image dimensions until it loads.
1479
- if (img_1 && (!img_1.complete || img_1.naturalWidth === 0)) {
1480
- // This will trigger mutation to update the original width and height after image loads.
1481
- bind(img_1, 'load', function () {
1482
- img_1.setAttribute('data-clarity-loaded', "".concat(shortid()));
1483
- });
1464
+ var data = { target: input, value: v, type: t };
1465
+ // 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.
1466
+ if (state$6.length > 0 && (state$6[state$6.length - 1].data.target === data.target)) {
1467
+ state$6.pop();
1484
1468
  }
1485
- value.metadata.size = [];
1469
+ state$6.push({ time: time(evt), event: 27 /* Event.Input */, data: data });
1470
+ clearTimeout(timeout$6);
1471
+ timeout$6 = setTimeout(process$7, 1000 /* Setting.InputLookAhead */, 27 /* Event.Input */);
1486
1472
  }
1487
1473
  }
1488
- function getPreviousId(node) {
1489
- var id = null;
1490
- // Some nodes may not have an ID by design since Clarity skips over tags like SCRIPT, NOSCRIPT, META, COMMENTS, etc..
1491
- // 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.
1492
- while (id === null && node.previousSibling) {
1493
- id = getId(node.previousSibling);
1494
- node = node.previousSibling;
1495
- }
1496
- return id;
1474
+ function process$7(event) {
1475
+ schedule$1(encode$3.bind(this, event));
1497
1476
  }
1498
- function track$6(id, source, changed, parentChanged) {
1499
- if (changed === void 0) { changed = true; }
1500
- if (parentChanged === void 0) { parentChanged = false; }
1501
- // Keep track of the order in which mutations happened, they may not be sequential
1502
- // Edge case: If an element is added later on, and pre-discovered element is moved as a child.
1503
- // In that case, we need to reorder the pre-discovered element in the update list to keep visualization consistent.
1504
- var uIndex = updateMap.indexOf(id);
1505
- if (uIndex >= 0 && source === 1 /* Source.ChildListAdd */ && parentChanged) {
1506
- updateMap.splice(uIndex, 1);
1507
- updateMap.push(id);
1508
- }
1509
- else if (uIndex === -1 && changed) {
1510
- updateMap.push(id);
1511
- }
1477
+ function reset$j() {
1478
+ state$6 = [];
1512
1479
  }
1513
-
1514
- var dom = /*#__PURE__*/Object.freeze({
1515
- __proto__: null,
1516
- add: add,
1517
- get: get,
1518
- getId: getId,
1519
- getNode: getNode,
1520
- getValue: getValue,
1521
- has: has,
1522
- hashText: hashText,
1523
- iframe: iframe,
1524
- lookup: lookup,
1525
- parse: parse$1,
1526
- sameorigin: sameorigin,
1527
- start: start$z,
1528
- stop: stop$x,
1529
- update: update$1,
1530
- updates: updates$2
1531
- });
1532
-
1533
- // Track the start time to be able to compute duration at the end of the task
1534
- var idleTimeout = 5000;
1535
- var tracker = {};
1536
- var queuedTasks = [];
1537
- var activeTask = null;
1538
- var pauseTask = null;
1539
- var resumeResolve = null;
1540
- function pause$1() {
1541
- if (pauseTask === null) {
1542
- pauseTask = new Promise(function (resolve) {
1543
- resumeResolve = resolve;
1544
- });
1545
- }
1480
+ function stop$t() {
1481
+ clearTimeout(timeout$6);
1482
+ reset$j();
1546
1483
  }
1547
- function resume$1() {
1548
- if (pauseTask) {
1549
- resumeResolve();
1550
- pauseTask = null;
1551
- if (activeTask === null) {
1552
- run();
1553
- }
1554
- }
1484
+
1485
+ var state$5 = [];
1486
+ var timeout$5 = null;
1487
+ var hasPrimaryTouch = false;
1488
+ var primaryTouchId = 0;
1489
+ var activeTouchPointIds = new Set();
1490
+ function start$u() {
1491
+ reset$i();
1555
1492
  }
1556
- function reset$l() {
1557
- tracker = {};
1558
- queuedTasks = [];
1559
- activeTask = null;
1560
- pauseTask = null;
1493
+ function observe$8(root) {
1494
+ bind(root, "mousedown", mouse.bind(this, 13 /* Event.MouseDown */, root), true);
1495
+ bind(root, "mouseup", mouse.bind(this, 14 /* Event.MouseUp */, root), true);
1496
+ bind(root, "mousemove", mouse.bind(this, 12 /* Event.MouseMove */, root), true);
1497
+ bind(root, "wheel", mouse.bind(this, 15 /* Event.MouseWheel */, root), true);
1498
+ bind(root, "dblclick", mouse.bind(this, 16 /* Event.DoubleClick */, root), true);
1499
+ bind(root, "touchstart", touch.bind(this, 17 /* Event.TouchStart */, root), true);
1500
+ bind(root, "touchend", touch.bind(this, 18 /* Event.TouchEnd */, root), true);
1501
+ bind(root, "touchmove", touch.bind(this, 19 /* Event.TouchMove */, root), true);
1502
+ bind(root, "touchcancel", touch.bind(this, 20 /* Event.TouchCancel */, root), true);
1561
1503
  }
1562
- function schedule$1(task, priority) {
1563
- if (priority === void 0) { priority = 0 /* Priority.Normal */; }
1564
- return __awaiter(this, void 0, void 0, function () {
1565
- var _i, queuedTasks_1, q, promise;
1566
- return __generator(this, function (_a) {
1567
- // If this task is already scheduled, skip it
1568
- for (_i = 0, queuedTasks_1 = queuedTasks; _i < queuedTasks_1.length; _i++) {
1569
- q = queuedTasks_1[_i];
1570
- if (q.task === task) {
1571
- return [2 /*return*/];
1572
- }
1573
- }
1574
- promise = new Promise(function (resolve) {
1575
- var insert = priority === 1 /* Priority.High */ ? "unshift" : "push";
1576
- // Queue this task for asynchronous execution later
1577
- // We also store a unique page identifier (id) along with the task to ensure
1578
- // ensure that we do not accidentally execute this task in context of a different page
1579
- queuedTasks[insert]({ task: task, resolve: resolve, id: id() });
1580
- });
1581
- // If there is no active task running, and Clarity is not in pause state,
1582
- // invoke the first task in the queue synchronously. This ensures that we don't yield the thread during unload event
1583
- if (activeTask === null && pauseTask === null) {
1584
- run();
1585
- }
1586
- return [2 /*return*/, promise];
1587
- });
1588
- });
1504
+ function mouse(event, root, evt) {
1505
+ mouse.dn = 10 /* FunctionNames.PointerMouse */;
1506
+ var frame = iframe(root);
1507
+ var d = frame ? frame.contentDocument.documentElement : document.documentElement;
1508
+ var x = "pageX" in evt ? Math.round(evt.pageX) : ("clientX" in evt ? Math.round(evt["clientX"] + d.scrollLeft) : null);
1509
+ var y = "pageY" in evt ? Math.round(evt.pageY) : ("clientY" in evt ? Math.round(evt["clientY"] + d.scrollTop) : null);
1510
+ // In case of iframe, we adjust (x,y) to be relative to top parent's origin
1511
+ if (frame) {
1512
+ var distance = offset(frame);
1513
+ x = x ? x + Math.round(distance.x) : x;
1514
+ y = y ? y + Math.round(distance.y) : y;
1515
+ }
1516
+ // Check for null values before processing this event
1517
+ if (x !== null && y !== null) {
1518
+ handler$2({ time: time(evt), event: event, data: { target: target(evt), x: x, y: y } });
1519
+ }
1589
1520
  }
1590
- function run() {
1591
- var entry = queuedTasks.shift();
1592
- if (entry) {
1593
- activeTask = entry;
1594
- entry.task().then(function () {
1595
- // Bail out if the context in which this task was operating is different from the current page
1596
- // An example scenario where task could span across pages is Single Page Applications (SPA)
1597
- // A task that started on page #1, but completes on page #2
1598
- if (entry.id !== id()) {
1599
- return;
1521
+ function touch(event, root, evt) {
1522
+ touch.dn = 11 /* FunctionNames.PointerTouch */;
1523
+ var frame = iframe(root);
1524
+ var d = frame ? frame.contentDocument.documentElement : document.documentElement;
1525
+ var touches = evt.changedTouches;
1526
+ var t = time(evt);
1527
+ if (touches) {
1528
+ for (var i = 0; i < touches.length; i++) {
1529
+ var entry = touches[i];
1530
+ var x = "clientX" in entry ? Math.round(entry["clientX"] + d.scrollLeft) : null;
1531
+ var y = "clientY" in entry ? Math.round(entry["clientY"] + d.scrollTop) : null;
1532
+ x = x && frame ? x + Math.round(frame.offsetLeft) : x;
1533
+ y = y && frame ? y + Math.round(frame.offsetTop) : y;
1534
+ // We cannot rely on identifier to determine primary touch as its value doesn't always start with 0.
1535
+ // Safari/Webkit uses the address of the UITouch object as the identifier value for each touch point.
1536
+ var id = "identifier" in entry ? entry["identifier"] : undefined;
1537
+ switch (event) {
1538
+ case 17 /* Event.TouchStart */:
1539
+ if (activeTouchPointIds.size === 0) {
1540
+ // Track presence of primary touch separately to handle scenarios when same id is repeated
1541
+ hasPrimaryTouch = true;
1542
+ primaryTouchId = id;
1543
+ }
1544
+ activeTouchPointIds.add(id);
1545
+ break;
1546
+ case 18 /* Event.TouchEnd */:
1547
+ case 20 /* Event.TouchCancel */:
1548
+ activeTouchPointIds.delete(id);
1549
+ break;
1600
1550
  }
1601
- entry.resolve();
1602
- activeTask = null; // Reset active task back to null now that the promise is resolved
1603
- run();
1604
- }).catch(function (error) {
1605
- // If one of the scheduled tasks failed, log, recover and continue processing rest of the tasks
1606
- if (entry.id !== id()) {
1607
- return;
1551
+ var isPrimary = hasPrimaryTouch && primaryTouchId === id;
1552
+ // Check for null values before processing this event
1553
+ if (x !== null && y !== null) {
1554
+ handler$2({ time: t, event: event, data: { target: target(evt), x: x, y: y, id: id, isPrimary: isPrimary } });
1608
1555
  }
1609
- if (error) {
1610
- log$1(0 /* Code.RunTask */, 1 /* Severity.Warning */, error.name, error.message, error.stack);
1556
+ // Reset primary touch point id once touch event ends
1557
+ if (event === 20 /* Event.TouchCancel */ || event === 18 /* Event.TouchEnd */) {
1558
+ if (primaryTouchId === id) {
1559
+ hasPrimaryTouch = false;
1560
+ }
1611
1561
  }
1612
- activeTask = null;
1613
- run();
1614
- });
1562
+ }
1615
1563
  }
1616
1564
  }
1617
- function state$a(timer) {
1618
- var id = key(timer);
1619
- if (id in tracker) {
1620
- var elapsed = performance.now() - tracker[id].start;
1621
- return (elapsed > tracker[id].yield) ? 0 /* Task.Wait */ : 1 /* Task.Run */;
1565
+ function handler$2(current) {
1566
+ switch (current.event) {
1567
+ case 12 /* Event.MouseMove */:
1568
+ case 15 /* Event.MouseWheel */:
1569
+ case 19 /* Event.TouchMove */:
1570
+ var length_1 = state$5.length;
1571
+ var last = length_1 > 1 ? state$5[length_1 - 2] : null;
1572
+ if (last && similar$1(last, current)) {
1573
+ state$5.pop();
1574
+ }
1575
+ state$5.push(current);
1576
+ clearTimeout(timeout$5);
1577
+ timeout$5 = setTimeout(process$6, 500 /* Setting.LookAhead */, current.event);
1578
+ break;
1579
+ default:
1580
+ state$5.push(current);
1581
+ process$6(current.event);
1582
+ break;
1622
1583
  }
1623
- // If this task is no longer being tracked, send stop message to the caller
1624
- return 2 /* Task.Stop */;
1625
1584
  }
1626
- function start$y(timer) {
1627
- tracker[key(timer)] = { start: performance.now(), calls: 0, yield: 30 /* Setting.LongTask */ };
1585
+ function process$6(event) {
1586
+ schedule$1(encode$3.bind(this, event));
1628
1587
  }
1629
- function restart$2(timer) {
1630
- var id = key(timer);
1631
- if (tracker && tracker[id]) {
1632
- var c = tracker[id].calls;
1633
- var y = tracker[id].yield;
1634
- start$y(timer);
1635
- tracker[id].calls = c + 1;
1636
- tracker[id].yield = y;
1637
- }
1588
+ function reset$i() {
1589
+ state$5 = [];
1638
1590
  }
1639
- function stop$w(timer) {
1640
- var end = performance.now();
1641
- var id = key(timer);
1642
- var duration = end - tracker[id].start;
1643
- sum(timer.cost, duration);
1644
- count$1(5 /* Metric.InvokeCount */);
1645
- // For the first execution, which is synchronous, time is automatically counted towards TotalDuration.
1646
- // However, for subsequent asynchronous runs, we need to manually update TotalDuration metric.
1647
- if (tracker[id].calls > 0) {
1648
- sum(4 /* Metric.TotalCost */, duration);
1591
+ function similar$1(last, current) {
1592
+ var dx = last.data.x - current.data.x;
1593
+ var dy = last.data.y - current.data.y;
1594
+ var distance = Math.sqrt(dx * dx + dy * dy);
1595
+ var gap = current.time - last.time;
1596
+ var match = current.data.target === last.data.target;
1597
+ return current.event === last.event && match && distance < 20 /* Setting.Distance */ && gap < 25 /* Setting.Interval */;
1598
+ }
1599
+ function stop$s() {
1600
+ clearTimeout(timeout$5);
1601
+ // Send out any pending pointer events in the pipeline
1602
+ if (state$5.length > 0) {
1603
+ process$6(state$5[state$5.length - 1].event);
1649
1604
  }
1650
1605
  }
1651
- function suspend$1(timer) {
1652
- return __awaiter(this, void 0, void 0, function () {
1653
- var id, _a;
1654
- return __generator(this, function (_b) {
1655
- switch (_b.label) {
1656
- case 0:
1657
- id = key(timer);
1658
- if (!(id in tracker)) return [3 /*break*/, 2];
1659
- stop$w(timer);
1660
- _a = tracker[id];
1661
- return [4 /*yield*/, wait()];
1662
- case 1:
1663
- _a.yield = (_b.sent()).timeRemaining();
1664
- restart$2(timer);
1665
- _b.label = 2;
1666
- case 2:
1667
- // After we are done with suspending task, ensure that we are still operating in the right context
1668
- // If the task is still being tracked, continue running the task, otherwise ask caller to stop execution
1669
- return [2 /*return*/, id in tracker ? 1 /* Task.Run */ : 2 /* Task.Stop */];
1670
- }
1671
- });
1672
- });
1606
+
1607
+ var data$c;
1608
+ var timeout$4 = null;
1609
+ var initialStateLogged = false;
1610
+ function start$t() {
1611
+ initialStateLogged = false;
1612
+ bind(window, "resize", recompute$5);
1613
+ recompute$5();
1673
1614
  }
1674
- function key(timer) {
1675
- return "".concat(timer.id, ".").concat(timer.cost);
1615
+ function recompute$5() {
1616
+ recompute$5.dn = 12 /* FunctionNames.ResizeRecompute */;
1617
+ var de = document.documentElement;
1618
+ // window.innerWidth includes width of the scrollbar and is not a true representation of the viewport width.
1619
+ // Therefore, when possible, use documentElement's clientWidth property.
1620
+ data$c = {
1621
+ width: de && "clientWidth" in de ? Math.min(de.clientWidth, window.innerWidth) : window.innerWidth,
1622
+ height: de && "clientHeight" in de ? Math.min(de.clientHeight, window.innerHeight) : window.innerHeight,
1623
+ };
1624
+ if (initialStateLogged) {
1625
+ clearTimeout(timeout$4);
1626
+ timeout$4 = setTimeout(process$5, 500 /* Setting.LookAhead */, 11 /* Event.Resize */);
1627
+ }
1628
+ else {
1629
+ encode$3(11 /* Event.Resize */);
1630
+ initialStateLogged = true;
1631
+ }
1676
1632
  }
1677
- function wait() {
1678
- return __awaiter(this, void 0, void 0, function () {
1679
- return __generator(this, function (_a) {
1680
- switch (_a.label) {
1681
- case 0:
1682
- if (!pauseTask) return [3 /*break*/, 2];
1683
- return [4 /*yield*/, pauseTask];
1684
- case 1:
1685
- _a.sent();
1686
- _a.label = 2;
1687
- case 2: return [2 /*return*/, new Promise(function (resolve) {
1688
- requestIdleCallback(resolve, { timeout: idleTimeout });
1689
- })];
1690
- }
1691
- });
1692
- });
1633
+ function process$5(event) {
1634
+ schedule$1(encode$3.bind(this, event));
1693
1635
  }
1694
- // Use native implementation of requestIdleCallback if it exists.
1695
- // Otherwise, fall back to a custom implementation using requestAnimationFrame & MessageChannel.
1696
- // While it's not possible to build a perfect polyfill given the nature of this API, the following code attempts to get close.
1697
- // Background context: requestAnimationFrame invokes the js code right before: style, layout and paint computation within the frame.
1698
- // This means, that any code that runs as part of requestAnimationFrame will by default be blocking in nature. Not what we want.
1699
- // For non-blocking behavior, We need to know when browser has finished painting. This can be accomplished in two different ways (hacks):
1700
- // (1) Use MessageChannel to pass the message, and browser will receive the message right after paint event has occured.
1701
- // (2) Use setTimeout call within requestAnimationFrame. This also works, but there's a risk that browser may throttle setTimeout calls.
1702
- // Given this information, we are currently using (1) from above. More information on (2) as well as some additional context is below:
1703
- // https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Performance_best_practices_for_Firefox_fe_engineers
1704
- function requestIdleCallbackPolyfill(callback, options) {
1705
- var startTime = performance.now();
1706
- var channel = new MessageChannel();
1707
- var incoming = channel.port1;
1708
- var outgoing = channel.port2;
1709
- incoming.onmessage = function (event) {
1710
- var currentTime = performance.now();
1711
- var elapsed = currentTime - startTime;
1712
- var duration = currentTime - event.data;
1713
- if (duration > 30 /* Setting.LongTask */ && elapsed < options.timeout) {
1714
- requestAnimationFrame(function () { outgoing.postMessage(currentTime); });
1715
- }
1716
- else {
1717
- var didTimeout_1 = elapsed > options.timeout;
1718
- callback({
1719
- didTimeout: didTimeout_1,
1720
- timeRemaining: function () { return didTimeout_1 ? 30 /* Setting.LongTask */ : Math.max(0, 30 /* Setting.LongTask */ - duration); }
1721
- });
1722
- }
1723
- };
1724
- requestAnimationFrame(function () { outgoing.postMessage(performance.now()); });
1636
+ function reset$h() {
1637
+ data$c = null;
1638
+ clearTimeout(timeout$4);
1725
1639
  }
1726
- var requestIdleCallback = window["requestIdleCallback"] || requestIdleCallbackPolyfill;
1727
-
1728
- // Following code takes an array of tokens and transforms it to optimize for repeating tokens and make it efficient to send over the wire
1729
- // 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
1730
- // If so, it replaces the token with its reference (index). This helps us save bytes by not repeating the same value twice.
1731
- // E.g. If tokens array is: ["hello", "world", "coding", "language", "world", "language", "example"]
1732
- // Then the resulting tokens array after following code execution would be: ["hello", "world", "coding", "language", [1, 3], "example"]
1733
- // Where [1,3] points to tokens[1] => "world" and tokens[3] => "language"
1734
- function tokenize (tokens) {
1735
- var output = [];
1736
- var lookup = {};
1737
- var pointer = 0;
1738
- var reference = null;
1739
- for (var i = 0; i < tokens.length; i++) {
1740
- // Only optimize for string values
1741
- if (typeof tokens[i] === "string" /* Constant.String */) {
1742
- var token = tokens[i];
1743
- var index = lookup[token] || -1;
1744
- if (index >= 0) {
1745
- if (reference) {
1746
- reference.push(index);
1747
- }
1748
- else {
1749
- reference = [index];
1750
- output.push(reference);
1751
- pointer++;
1752
- }
1753
- }
1754
- else {
1755
- reference = null;
1756
- output.push(token);
1757
- lookup[token] = pointer++;
1758
- }
1759
- }
1760
- else {
1761
- // If the value is anything other than string, append it as it is to the output array
1762
- // And, also increment the pointer to stay in sync with output array
1763
- reference = null;
1764
- output.push(tokens[i]);
1765
- pointer++;
1766
- }
1767
- }
1768
- return output;
1640
+ function stop$r() {
1641
+ reset$h();
1769
1642
  }
1770
1643
 
1771
- var data$c;
1772
- function reset$k() {
1773
- data$c = null;
1644
+ var state$4 = [];
1645
+ var initialTop = null;
1646
+ var initialBottom = null;
1647
+ var timeout$3 = null;
1648
+ function start$s() {
1649
+ state$4 = [];
1650
+ recompute$4();
1774
1651
  }
1775
- function start$x() {
1776
- reset$k();
1777
- compute$9();
1652
+ function observe$7(root) {
1653
+ var frame = iframe(root);
1654
+ var node = frame ? frame.contentWindow : (root === document ? window : root);
1655
+ bind(node, "scroll", recompute$4, true);
1778
1656
  }
1779
- function compute$9() {
1780
- compute$9.dn = 19 /* FunctionNames.DocumentCompute */;
1781
- var body = document.body;
1782
- var d = document.documentElement;
1783
- var bodyClientWidth = body ? body.clientWidth : null;
1784
- var bodyScrollWidth = body ? body.scrollWidth : null;
1785
- var bodyOffsetWidth = body ? body.offsetWidth : null;
1786
- var documentClientWidth = d ? d.clientWidth : null;
1787
- var documentScrollWidth = d ? d.scrollWidth : null;
1788
- var documentOffsetWidth = d ? d.offsetWidth : null;
1789
- var width = Math.max(bodyClientWidth, bodyScrollWidth, bodyOffsetWidth, documentClientWidth, documentScrollWidth, documentOffsetWidth);
1790
- var bodyClientHeight = body ? body.clientHeight : null;
1791
- var bodyScrollHeight = body ? body.scrollHeight : null;
1792
- var bodyOffsetHeight = body ? body.offsetHeight : null;
1793
- var documentClientHeight = d ? d.clientHeight : null;
1794
- var documentScrollHeight = d ? d.scrollHeight : null;
1795
- var documentOffsetHeight = d ? d.offsetHeight : null;
1796
- var height = Math.max(bodyClientHeight, bodyScrollHeight, bodyOffsetHeight, documentClientHeight, documentScrollHeight, documentOffsetHeight);
1797
- // Check that width or height has changed from before, and also that width & height are not null values
1798
- if ((data$c === null || width !== data$c.width || height !== data$c.height) && width !== null && height !== null) {
1799
- data$c = { width: width, height: height };
1800
- encode$4(8 /* Event.Document */);
1657
+ function recompute$4(event) {
1658
+ if (event === void 0) { event = null; }
1659
+ recompute$4.dn = 13 /* FunctionNames.ScrollRecompute */;
1660
+ var w = window;
1661
+ var de = document.documentElement;
1662
+ var element = event ? target(event) : de;
1663
+ // If the target is a Document node, then identify corresponding documentElement and window for this document
1664
+ if (element && element.nodeType === Node.DOCUMENT_NODE) {
1665
+ var frame = iframe(element);
1666
+ w = frame ? frame.contentWindow : w;
1667
+ element = de = element.documentElement;
1668
+ }
1669
+ // Edge doesn't support scrollTop position on document.documentElement.
1670
+ // For cross browser compatibility, looking up pageYOffset on window if the scroll is on document.
1671
+ // And, if for some reason that is not available, fall back to looking up scrollTop on document.documentElement.
1672
+ var x = element === de && "pageXOffset" in w ? Math.round(w.pageXOffset) : Math.round(element.scrollLeft);
1673
+ var y = element === de && "pageYOffset" in w ? Math.round(w.pageYOffset) : Math.round(element.scrollTop);
1674
+ var width = window.innerWidth;
1675
+ var height = window.innerHeight;
1676
+ var xPosition = width / 3;
1677
+ var yOffset = width > height ? height * 0.15 : height * 0.2;
1678
+ var startYPosition = yOffset;
1679
+ var endYPosition = height - yOffset;
1680
+ var top = getPositionNode(xPosition, startYPosition);
1681
+ var bottom = getPositionNode(xPosition, endYPosition);
1682
+ var current = { time: time(event), event: 10 /* Event.Scroll */, data: { target: element, x: x, y: y, top: top, bottom: bottom } };
1683
+ // We don't send any scroll events if this is the first event and the current position is top (0,0)
1684
+ if ((event === null && x === 0 && y === 0) || (x === null || y === null)) {
1685
+ initialTop = top;
1686
+ initialBottom = bottom;
1687
+ return;
1688
+ }
1689
+ var length = state$4.length;
1690
+ var last = length > 1 ? state$4[length - 2] : null;
1691
+ if (last && similar(last, current)) {
1692
+ state$4.pop();
1801
1693
  }
1694
+ state$4.push(current);
1695
+ clearTimeout(timeout$3);
1696
+ timeout$3 = setTimeout(process$4, 500 /* Setting.LookAhead */, 10 /* Event.Scroll */);
1802
1697
  }
1803
- function stop$v() {
1804
- reset$k();
1698
+ function getPositionNode(x, y) {
1699
+ var _a, _b;
1700
+ var node;
1701
+ if ("caretPositionFromPoint" in document) {
1702
+ node = (_a = document.caretPositionFromPoint(x, y)) === null || _a === void 0 ? void 0 : _a.offsetNode;
1703
+ }
1704
+ else if ("caretRangeFromPoint" in document) {
1705
+ node = (_b = document.caretRangeFromPoint(x, y)) === null || _b === void 0 ? void 0 : _b.startContainer;
1706
+ }
1707
+ if (!node) {
1708
+ node = document.elementFromPoint(x, y);
1709
+ }
1710
+ if (node && node.nodeType === Node.TEXT_NODE) {
1711
+ node = node.parentNode;
1712
+ }
1713
+ return node;
1805
1714
  }
1806
-
1807
- var state$9 = [];
1808
- function start$w() {
1809
- reset$j();
1715
+ function reset$g() {
1716
+ state$4 = [];
1717
+ initialTop = null;
1718
+ initialBottom = null;
1810
1719
  }
1811
- function observe$c(root) {
1812
- bind(root, "change", recompute$8, true);
1720
+ function process$4(event) {
1721
+ schedule$1(encode$3.bind(this, event));
1813
1722
  }
1814
- function recompute$8(evt) {
1815
- recompute$8.dn = 5 /* FunctionNames.ChangeRecompute */;
1816
- var element = target(evt);
1817
- if (element) {
1818
- var value = element.value;
1819
- var checksum = value && value.length >= 5 /* Setting.WordLength */ && config$2.fraud && "password,secret,pass,social,ssn,code,hidden" /* Mask.Exclude */.indexOf(element.type) === -1 ? hash(value, 28 /* Setting.ChecksumPrecision */) : "" /* Constant.Empty */;
1820
- state$9.push({ time: time(evt), event: 42 /* Event.Change */, data: { target: target(evt), type: element.type, value: value, checksum: checksum } });
1821
- schedule$1(encode$3.bind(this, 42 /* Event.Change */));
1723
+ function similar(last, current) {
1724
+ var dx = last.data.x - current.data.x;
1725
+ var dy = last.data.y - current.data.y;
1726
+ return (dx * dx + dy * dy < 20 /* Setting.Distance */ * 20 /* Setting.Distance */) && (current.time - last.time < 25 /* Setting.Interval */);
1727
+ }
1728
+ function compute$9() {
1729
+ var _a, _b;
1730
+ compute$9.dn = 14 /* FunctionNames.ScrollCompute */;
1731
+ if (initialTop) {
1732
+ var top_1 = metadata$2(initialTop, null);
1733
+ log(31 /* Dimension.InitialScrollTop */, (_a = top_1 === null || top_1 === void 0 ? void 0 : top_1.hash) === null || _a === void 0 ? void 0 : _a.join("." /* Constant.Dot */));
1734
+ }
1735
+ if (initialBottom) {
1736
+ var bottom = metadata$2(initialBottom, null);
1737
+ log(32 /* Dimension.InitialScrollBottom */, (_b = bottom === null || bottom === void 0 ? void 0 : bottom.hash) === null || _b === void 0 ? void 0 : _b.join("." /* Constant.Dot */));
1822
1738
  }
1823
1739
  }
1824
- function reset$j() {
1825
- state$9 = [];
1826
- }
1827
- function stop$u() {
1828
- reset$j();
1829
- }
1830
-
1831
- function offset(element) {
1832
- var output = { x: 0, y: 0 };
1833
- // Walk up the chain to ensure we compute offset distance correctly
1834
- // In case where we may have nested IFRAMEs, we keep walking up until we get to the top most parent page
1835
- if (element && element.offsetParent) {
1836
- do {
1837
- var parent_1 = element.offsetParent;
1838
- var frame = parent_1 === null ? iframe(element.ownerDocument) : null;
1839
- output.x += element.offsetLeft;
1840
- output.y += element.offsetTop;
1841
- element = frame ? frame : parent_1;
1842
- } while (element);
1843
- }
1844
- return output;
1740
+ function stop$q() {
1741
+ clearTimeout(timeout$3);
1742
+ state$4 = [];
1743
+ initialTop = null;
1744
+ initialBottom = null;
1845
1745
  }
1846
1746
 
1847
- var UserInputTags = ["input", "textarea", "radio", "button", "canvas"];
1848
- var state$8 = [];
1849
- function start$v() {
1850
- reset$i();
1747
+ var data$b = null;
1748
+ var previous = null;
1749
+ var timeout$2 = null;
1750
+ function start$r() {
1751
+ reset$f();
1851
1752
  }
1852
- function observe$b(root) {
1853
- bind(root, "click", handler$3.bind(this, 9 /* Event.Click */, root), true);
1753
+ function observe$6(root) {
1754
+ bind(root, "selectstart", recompute$3.bind(this, root), true);
1755
+ bind(root, "selectionchange", recompute$3.bind(this, root), true);
1854
1756
  }
1855
- function handler$3(event, root, evt) {
1856
- handler$3.dn = 6 /* FunctionNames.ClickHandler */;
1857
- var frame = iframe(root);
1858
- var d = frame ? frame.contentDocument.documentElement : document.documentElement;
1859
- var x = "pageX" in evt ? Math.round(evt.pageX) : ("clientX" in evt ? Math.round(evt["clientX"] + d.scrollLeft) : null);
1860
- var y = "pageY" in evt ? Math.round(evt.pageY) : ("clientY" in evt ? Math.round(evt["clientY"] + d.scrollTop) : null);
1861
- // In case of iframe, we adjust (x,y) to be relative to top parent's origin
1862
- if (frame) {
1863
- var distance = offset(frame);
1864
- x = x ? x + Math.round(distance.x) : x;
1865
- y = y ? y + Math.round(distance.y) : y;
1757
+ function recompute$3(root) {
1758
+ recompute$3.dn = 15 /* FunctionNames.SelectionRecompute */;
1759
+ var doc = root.nodeType === Node.DOCUMENT_NODE ? root : document;
1760
+ var current = doc.getSelection();
1761
+ // Bail out if we don't have a valid selection
1762
+ if (current === null) {
1763
+ return;
1866
1764
  }
1867
- var t = target(evt);
1868
- // Find nearest anchor tag (<a/>) parent if current target node is part of one
1869
- // If present, we use the returned link element to populate text and link properties below
1870
- var a = link(t);
1871
- // Get layout rectangle for the target element
1872
- var l = layout$1(t);
1873
- // Reference: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
1874
- // This property helps differentiate between a keyboard navigation vs. pointer click
1875
- // In case of a keyboard navigation, we use center of target element as (x,y)
1876
- if (evt.detail === 0 && l) {
1877
- x = Math.round(l.x + (l.w / 2));
1878
- y = Math.round(l.y + (l.h / 2));
1765
+ // Bail out if we got a valid selection but not valid nodes
1766
+ // In Edge, selectionchange gets fired even on interactions like right clicks and
1767
+ // can result in null anchorNode and focusNode if there was no previous selection on page
1768
+ // Also, ignore any selections that start and end at the exact same point
1769
+ if ((current.anchorNode === null && current.focusNode === null) ||
1770
+ (current.anchorNode === current.focusNode && current.anchorOffset === current.focusOffset)) {
1771
+ return;
1879
1772
  }
1880
- var eX = l ? Math.max(Math.floor(((x - l.x) / l.w) * 32767 /* Setting.ClickPrecision */), 0) : 0;
1881
- var eY = l ? Math.max(Math.floor(((y - l.y) / l.h) * 32767 /* Setting.ClickPrecision */), 0) : 0;
1882
- // Check for null values before processing this event
1883
- if (x !== null && y !== null) {
1884
- var textInfo = text(t);
1885
- state$8.push({
1886
- time: time(evt),
1887
- event: event,
1888
- data: {
1889
- target: t,
1890
- x: x,
1891
- y: y,
1892
- eX: eX,
1893
- eY: eY,
1894
- button: evt.button,
1895
- reaction: reaction(t),
1896
- context: context(a),
1897
- text: textInfo.text,
1898
- link: a ? a.href : null,
1899
- hash: null,
1900
- trust: evt.isTrusted ? 1 /* BooleanFlag.True */ : 0 /* BooleanFlag.False */,
1901
- isFullText: textInfo.isFullText,
1902
- }
1903
- });
1904
- schedule$1(encode$3.bind(this, event));
1773
+ var startNode = data$b.start ? data$b.start : null;
1774
+ if (previous !== null && data$b.start !== null && startNode !== current.anchorNode) {
1775
+ clearTimeout(timeout$2);
1776
+ process$3(21 /* Event.Selection */);
1905
1777
  }
1778
+ data$b = {
1779
+ start: current.anchorNode,
1780
+ startOffset: current.anchorOffset,
1781
+ end: current.focusNode,
1782
+ endOffset: current.focusOffset
1783
+ };
1784
+ previous = current;
1785
+ clearTimeout(timeout$2);
1786
+ timeout$2 = setTimeout(process$3, 500 /* Setting.LookAhead */, 21 /* Event.Selection */);
1906
1787
  }
1907
- function link(node) {
1908
- while (node && node !== document) {
1909
- if (node.nodeType === Node.ELEMENT_NODE) {
1910
- var element = node;
1911
- if (element.tagName === "A") {
1912
- return element;
1913
- }
1914
- }
1915
- node = node.parentNode;
1916
- }
1917
- return null;
1788
+ function process$3(event) {
1789
+ schedule$1(encode$3.bind(this, event));
1918
1790
  }
1919
- function text(element) {
1920
- var output = null;
1921
- var isFullText = false;
1922
- if (element) {
1923
- // Grab text using "textContent" for most HTMLElements, however, use "value" for HTMLInputElements and "alt" for HTMLImageElement.
1924
- var t = element.textContent || String(element.value || '') || element.alt;
1925
- if (t) {
1926
- // Replace multiple occurrence of space characters with a single white space
1927
- // Also, trim any spaces at the beginning or at the end of string
1928
- var trimmedText = t.replace(/\s+/g, " " /* Constant.Space */).trim();
1929
- // Finally, send only first few characters as specified by the Setting
1930
- output = trimmedText.substring(0, 25 /* Setting.ClickText */);
1931
- isFullText = output.length === trimmedText.length;
1932
- }
1933
- }
1934
- return { text: output, isFullText: isFullText ? 1 /* BooleanFlag.True */ : 0 /* BooleanFlag.False */ };
1791
+ function reset$f() {
1792
+ previous = null;
1793
+ data$b = { start: 0, startOffset: 0, end: 0, endOffset: 0 };
1935
1794
  }
1936
- function reaction(element) {
1937
- if (element.nodeType === Node.ELEMENT_NODE) {
1938
- var tag = element.tagName.toLowerCase();
1939
- if (UserInputTags.indexOf(tag) >= 0) {
1940
- return 0 /* BooleanFlag.False */;
1941
- }
1942
- }
1943
- return 1 /* BooleanFlag.True */;
1795
+ function stop$p() {
1796
+ reset$f();
1797
+ clearTimeout(timeout$2);
1944
1798
  }
1945
- function layout$1(element) {
1946
- var box = null;
1947
- var de = document.documentElement;
1948
- if (typeof element.getBoundingClientRect === "function") {
1949
- // getBoundingClientRect returns rectangle relative positioning to viewport
1950
- var rect = element.getBoundingClientRect();
1951
- if (rect && rect.width > 0 && rect.height > 0) {
1952
- // Add viewport's scroll position to rectangle to get position relative to document origin
1953
- // Also: using Math.floor() instead of Math.round() because in Edge,
1954
- // getBoundingClientRect returns partial pixel values (e.g. 162.5px) and Chrome already
1955
- // floors the value (e.g. 162px). This keeps consistent behavior across browsers.
1956
- box = {
1957
- x: Math.floor(rect.left + ("pageXOffset" in window ? window.pageXOffset : de.scrollLeft)),
1958
- y: Math.floor(rect.top + ("pageYOffset" in window ? window.pageYOffset : de.scrollTop)),
1959
- w: Math.floor(rect.width),
1960
- h: Math.floor(rect.height)
1961
- };
1962
- }
1963
- }
1964
- return box;
1799
+
1800
+ var state$3 = [];
1801
+ function start$q() {
1802
+ reset$e();
1965
1803
  }
1966
- function context(a) {
1967
- if (a && a.hasAttribute("target" /* Constant.Target */)) {
1968
- switch (a.getAttribute("target" /* Constant.Target */)) {
1969
- case "_blank" /* Constant.Blank */: return 1 /* BrowsingContext.Blank */;
1970
- case "_parent" /* Constant.Parent */: return 2 /* BrowsingContext.Parent */;
1971
- case "_top" /* Constant.Top */: return 3 /* BrowsingContext.Top */;
1972
- }
1973
- }
1974
- return 0 /* BrowsingContext.Self */;
1804
+ function observe$5(root) {
1805
+ bind(root, "submit", recompute$2, true);
1975
1806
  }
1976
- function reset$i() {
1977
- state$8 = [];
1807
+ function recompute$2(evt) {
1808
+ recompute$2.dn = 16 /* FunctionNames.SubmitRecompute */;
1809
+ state$3.push({ time: time(evt), event: 39 /* Event.Submit */, data: { target: target(evt) } });
1810
+ schedule$1(encode$3.bind(this, 39 /* Event.Submit */));
1978
1811
  }
1979
- function stop$t() {
1980
- reset$i();
1812
+ function reset$e() {
1813
+ state$3 = [];
1981
1814
  }
1982
-
1983
- var state$7 = [];
1984
- function start$u() {
1985
- reset$h();
1815
+ function stop$o() {
1816
+ reset$e();
1986
1817
  }
1987
- function observe$a(root) {
1988
- bind(root, "cut", recompute$7.bind(this, 0 /* Clipboard.Cut */), true);
1989
- bind(root, "copy", recompute$7.bind(this, 1 /* Clipboard.Copy */), true);
1990
- bind(root, "paste", recompute$7.bind(this, 2 /* Clipboard.Paste */), true);
1818
+
1819
+ var data$a;
1820
+ function start$p() {
1821
+ bind(window, "pagehide", recompute$1);
1991
1822
  }
1992
- function recompute$7(action, evt) {
1993
- recompute$7.dn = 7 /* FunctionNames.ClipboardRecompute */;
1994
- state$7.push({ time: time(evt), event: 38 /* Event.Clipboard */, data: { target: target(evt), action: action } });
1995
- schedule$1(encode$3.bind(this, 38 /* Event.Clipboard */));
1823
+ function recompute$1(evt) {
1824
+ recompute$1.dn = 17 /* FunctionNames.UnloadRecompute */;
1825
+ data$a = { name: evt.type, persisted: evt.persisted ? 1 /* BooleanFlag.True */ : 0 /* BooleanFlag.False */ };
1826
+ encode$3(26 /* Event.Unload */, time(evt));
1827
+ stop();
1996
1828
  }
1997
- function reset$h() {
1998
- state$7 = [];
1829
+ function reset$d() {
1830
+ data$a = null;
1999
1831
  }
2000
- function stop$s() {
2001
- reset$h();
1832
+ function stop$n() {
1833
+ reset$d();
2002
1834
  }
2003
1835
 
2004
- var timeout$6 = null;
2005
- var state$6 = [];
2006
- function start$t() {
2007
- reset$g();
1836
+ var data$9;
1837
+ function start$o() {
1838
+ bind(document, "visibilitychange", recompute);
1839
+ recompute();
2008
1840
  }
2009
- function observe$9(root) {
2010
- bind(root, "input", recompute$6, true);
1841
+ function recompute(evt) {
1842
+ if (evt === void 0) { evt = null; }
1843
+ recompute.dn = 18 /* FunctionNames.VisibilityRecompute */;
1844
+ data$9 = { visible: "visibilityState" in document ? document.visibilityState : "default" };
1845
+ encode$3(28 /* Event.Visibility */, time(evt));
2011
1846
  }
2012
- function recompute$6(evt) {
2013
- recompute$6.dn = 9 /* FunctionNames.InputRecompute */;
2014
- var input = target(evt);
2015
- var value = get(input);
2016
- if (input && input.type && value) {
2017
- var v = input.value;
2018
- var t = input.type;
2019
- switch (input.type) {
2020
- case "radio":
2021
- case "checkbox":
2022
- v = input.checked ? "true" : "false";
2023
- break;
2024
- }
2025
- var data = { target: input, value: v, type: t };
2026
- // 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.
2027
- if (state$6.length > 0 && (state$6[state$6.length - 1].data.target === data.target)) {
2028
- state$6.pop();
2029
- }
2030
- state$6.push({ time: time(evt), event: 27 /* Event.Input */, data: data });
2031
- clearTimeout(timeout$6);
2032
- timeout$6 = setTimeout(process$7, 1000 /* Setting.InputLookAhead */, 27 /* Event.Input */);
2033
- }
2034
- }
2035
- function process$7(event) {
2036
- schedule$1(encode$3.bind(this, event));
2037
- }
2038
- function reset$g() {
2039
- state$6 = [];
1847
+ function reset$c() {
1848
+ data$9 = null;
2040
1849
  }
2041
- function stop$r() {
2042
- clearTimeout(timeout$6);
2043
- reset$g();
1850
+ function stop$m() {
1851
+ reset$c();
2044
1852
  }
2045
1853
 
2046
- var state$5 = [];
2047
- var timeout$5 = null;
2048
- var hasPrimaryTouch = false;
2049
- var primaryTouchId = 0;
2050
- var activeTouchPointIds = new Set();
2051
- function start$s() {
2052
- reset$f();
1854
+ function start$n() {
1855
+ start$n.dn = 8 /* FunctionNames.InteractionStart */;
1856
+ start$g();
1857
+ start$x();
1858
+ start$w();
1859
+ start$u();
1860
+ start$v();
1861
+ start$t();
1862
+ start$o();
1863
+ start$s();
1864
+ start$r();
1865
+ start$y();
1866
+ start$q();
1867
+ start$p();
2053
1868
  }
2054
- function observe$8(root) {
2055
- bind(root, "mousedown", mouse.bind(this, 13 /* Event.MouseDown */, root), true);
2056
- bind(root, "mouseup", mouse.bind(this, 14 /* Event.MouseUp */, root), true);
2057
- bind(root, "mousemove", mouse.bind(this, 12 /* Event.MouseMove */, root), true);
2058
- bind(root, "wheel", mouse.bind(this, 15 /* Event.MouseWheel */, root), true);
2059
- bind(root, "dblclick", mouse.bind(this, 16 /* Event.DoubleClick */, root), true);
2060
- bind(root, "touchstart", touch.bind(this, 17 /* Event.TouchStart */, root), true);
2061
- bind(root, "touchend", touch.bind(this, 18 /* Event.TouchEnd */, root), true);
2062
- bind(root, "touchmove", touch.bind(this, 19 /* Event.TouchMove */, root), true);
2063
- bind(root, "touchcancel", touch.bind(this, 20 /* Event.TouchCancel */, root), true);
1869
+ function stop$l() {
1870
+ stop$e();
1871
+ stop$v();
1872
+ stop$u();
1873
+ stop$s();
1874
+ stop$t();
1875
+ stop$r();
1876
+ stop$m();
1877
+ stop$q();
1878
+ stop$p();
1879
+ stop$w();
1880
+ stop$o();
1881
+ stop$n();
2064
1882
  }
2065
- function mouse(event, root, evt) {
2066
- mouse.dn = 10 /* FunctionNames.PointerMouse */;
2067
- var frame = iframe(root);
2068
- var d = frame ? frame.contentDocument.documentElement : document.documentElement;
2069
- var x = "pageX" in evt ? Math.round(evt.pageX) : ("clientX" in evt ? Math.round(evt["clientX"] + d.scrollLeft) : null);
2070
- var y = "pageY" in evt ? Math.round(evt.pageY) : ("clientY" in evt ? Math.round(evt["clientY"] + d.scrollTop) : null);
2071
- // In case of iframe, we adjust (x,y) to be relative to top parent's origin
2072
- if (frame) {
2073
- var distance = offset(frame);
2074
- x = x ? x + Math.round(distance.x) : x;
2075
- y = y ? y + Math.round(distance.y) : y;
2076
- }
2077
- // Check for null values before processing this event
2078
- if (x !== null && y !== null) {
2079
- handler$2({ time: time(evt), event: event, data: { target: target(evt), x: x, y: y } });
1883
+ function observe$4(root) {
1884
+ observe$7(root);
1885
+ // Only monitor following interactions if the root node is a document
1886
+ // In case of shadow DOM, following events automatically bubble up to the parent document.
1887
+ if (root.nodeType === Node.DOCUMENT_NODE) {
1888
+ observe$b(root);
1889
+ observe$a(root);
1890
+ observe$8(root);
1891
+ observe$9(root);
1892
+ observe$6(root);
1893
+ observe$c(root);
1894
+ observe$5(root);
2080
1895
  }
2081
1896
  }
2082
- function touch(event, root, evt) {
2083
- touch.dn = 11 /* FunctionNames.PointerTouch */;
2084
- var frame = iframe(root);
2085
- var d = frame ? frame.contentDocument.documentElement : document.documentElement;
2086
- var touches = evt.changedTouches;
2087
- var t = time(evt);
2088
- if (touches) {
2089
- for (var i = 0; i < touches.length; i++) {
2090
- var entry = touches[i];
2091
- var x = "clientX" in entry ? Math.round(entry["clientX"] + d.scrollLeft) : null;
2092
- var y = "clientY" in entry ? Math.round(entry["clientY"] + d.scrollTop) : null;
2093
- x = x && frame ? x + Math.round(frame.offsetLeft) : x;
2094
- y = y && frame ? y + Math.round(frame.offsetTop) : y;
2095
- // We cannot rely on identifier to determine primary touch as its value doesn't always start with 0.
2096
- // Safari/Webkit uses the address of the UITouch object as the identifier value for each touch point.
2097
- var id = "identifier" in entry ? entry["identifier"] : undefined;
2098
- switch (event) {
2099
- case 17 /* Event.TouchStart */:
2100
- if (activeTouchPointIds.size === 0) {
2101
- // Track presence of primary touch separately to handle scenarios when same id is repeated
2102
- hasPrimaryTouch = true;
2103
- primaryTouchId = id;
2104
- }
2105
- activeTouchPointIds.add(id);
2106
- break;
2107
- case 18 /* Event.TouchEnd */:
2108
- case 20 /* Event.TouchCancel */:
2109
- activeTouchPointIds.delete(id);
2110
- break;
2111
- }
2112
- var isPrimary = hasPrimaryTouch && primaryTouchId === id;
2113
- // Check for null values before processing this event
2114
- if (x !== null && y !== null) {
2115
- handler$2({ time: t, event: event, data: { target: target(evt), x: x, y: y, id: id, isPrimary: isPrimary } });
2116
- }
2117
- // Reset primary touch point id once touch event ends
2118
- if (event === 20 /* Event.TouchCancel */ || event === 18 /* Event.TouchEnd */) {
2119
- if (primaryTouchId === id) {
2120
- hasPrimaryTouch = false;
1897
+
1898
+ var interaction = /*#__PURE__*/Object.freeze({
1899
+ __proto__: null,
1900
+ observe: observe$4,
1901
+ start: start$n,
1902
+ stop: stop$l
1903
+ });
1904
+
1905
+ // Following code takes an array of tokens and transforms it to optimize for repeating tokens and make it efficient to send over the wire
1906
+ // 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
1907
+ // If so, it replaces the token with its reference (index). This helps us save bytes by not repeating the same value twice.
1908
+ // E.g. If tokens array is: ["hello", "world", "coding", "language", "world", "language", "example"]
1909
+ // Then the resulting tokens array after following code execution would be: ["hello", "world", "coding", "language", [1, 3], "example"]
1910
+ // Where [1,3] points to tokens[1] => "world" and tokens[3] => "language"
1911
+ function tokenize (tokens) {
1912
+ var output = [];
1913
+ var lookup = {};
1914
+ var pointer = 0;
1915
+ var reference = null;
1916
+ for (var i = 0; i < tokens.length; i++) {
1917
+ // Only optimize for string values
1918
+ if (typeof tokens[i] === "string" /* Constant.String */) {
1919
+ var token = tokens[i];
1920
+ var index = lookup[token] || -1;
1921
+ if (index >= 0) {
1922
+ if (reference) {
1923
+ reference.push(index);
1924
+ }
1925
+ else {
1926
+ reference = [index];
1927
+ output.push(reference);
1928
+ pointer++;
2121
1929
  }
2122
1930
  }
1931
+ else {
1932
+ reference = null;
1933
+ output.push(token);
1934
+ lookup[token] = pointer++;
1935
+ }
1936
+ }
1937
+ else {
1938
+ // If the value is anything other than string, append it as it is to the output array
1939
+ // And, also increment the pointer to stay in sync with output array
1940
+ reference = null;
1941
+ output.push(tokens[i]);
1942
+ pointer++;
2123
1943
  }
2124
1944
  }
1945
+ return output;
2125
1946
  }
2126
- function handler$2(current) {
2127
- switch (current.event) {
2128
- case 12 /* Event.MouseMove */:
2129
- case 15 /* Event.MouseWheel */:
2130
- case 19 /* Event.TouchMove */:
2131
- var length_1 = state$5.length;
2132
- var last = length_1 > 1 ? state$5[length_1 - 2] : null;
2133
- if (last && similar$1(last, current)) {
2134
- state$5.pop();
2135
- }
2136
- state$5.push(current);
2137
- clearTimeout(timeout$5);
2138
- timeout$5 = setTimeout(process$6, 500 /* Setting.LookAhead */, current.event);
2139
- break;
2140
- default:
2141
- state$5.push(current);
2142
- process$6(current.event);
2143
- break;
1947
+
1948
+ var sheetUpdateState = [];
1949
+ var sheetAdoptionState = [];
1950
+ var replace = null;
1951
+ var replaceSync = null;
1952
+ var styleSheetId = 'claritySheetId';
1953
+ var styleSheetMap = {};
1954
+ var styleTimeMap = {};
1955
+ var documentNodes = [];
1956
+ var createdSheetIds = [];
1957
+ function start$m() {
1958
+ if (window['CSSStyleSheet'] && CSSStyleSheet.prototype) {
1959
+ if (replace === null) {
1960
+ replace = CSSStyleSheet.prototype.replace;
1961
+ CSSStyleSheet.prototype.replace = function () {
1962
+ if (active()) {
1963
+ max(36 /* Metric.ConstructedStyles */, 1);
1964
+ // if we haven't seen this stylesheet on this page yet, wait until the checkDocumentStyles has found it
1965
+ // and attached the sheet to a document. This way the timestamp of the style sheet creation will align
1966
+ // to when it is used in the document rather than potentially being misaligned during the traverse process.
1967
+ if (createdSheetIds.indexOf(this[styleSheetId]) > -1) {
1968
+ trackStyleChange(time(), this[styleSheetId], 1 /* StyleSheetOperation.Replace */, arguments[0]);
1969
+ }
1970
+ }
1971
+ return replace.apply(this, arguments);
1972
+ };
1973
+ }
1974
+ if (replaceSync === null) {
1975
+ replaceSync = CSSStyleSheet.prototype.replaceSync;
1976
+ CSSStyleSheet.prototype.replaceSync = function () {
1977
+ if (active()) {
1978
+ max(36 /* Metric.ConstructedStyles */, 1);
1979
+ // if we haven't seen this stylesheet on this page yet, wait until the checkDocumentStyles has found it
1980
+ // and attached the sheet to a document. This way the timestamp of the style sheet creation will align
1981
+ // to when it is used in the document rather than potentially being misaligned during the traverse process.
1982
+ if (createdSheetIds.indexOf(this[styleSheetId]) > -1) {
1983
+ trackStyleChange(time(), this[styleSheetId], 2 /* StyleSheetOperation.ReplaceSync */, arguments[0]);
1984
+ }
1985
+ }
1986
+ return replaceSync.apply(this, arguments);
1987
+ };
1988
+ }
2144
1989
  }
2145
1990
  }
2146
- function process$6(event) {
2147
- schedule$1(encode$3.bind(this, event));
2148
- }
2149
- function reset$f() {
2150
- state$5 = [];
2151
- }
2152
- function similar$1(last, current) {
2153
- var dx = last.data.x - current.data.x;
2154
- var dy = last.data.y - current.data.y;
2155
- var distance = Math.sqrt(dx * dx + dy * dy);
2156
- var gap = current.time - last.time;
2157
- var match = current.data.target === last.data.target;
2158
- return current.event === last.event && match && distance < 20 /* Setting.Distance */ && gap < 25 /* Setting.Interval */;
2159
- }
2160
- function stop$q() {
2161
- clearTimeout(timeout$5);
2162
- // Send out any pending pointer events in the pipeline
2163
- if (state$5.length > 0) {
2164
- process$6(state$5[state$5.length - 1].event);
1991
+ function checkDocumentStyles(documentNode, timestamp) {
1992
+ if (documentNodes.indexOf(documentNode) === -1) {
1993
+ documentNodes.push(documentNode);
2165
1994
  }
2166
- }
2167
-
2168
- var data$b;
2169
- var timeout$4 = null;
2170
- var initialStateLogged = false;
2171
- function start$r() {
2172
- initialStateLogged = false;
2173
- bind(window, "resize", recompute$5);
2174
- recompute$5();
2175
- }
2176
- function recompute$5() {
2177
- recompute$5.dn = 12 /* FunctionNames.ResizeRecompute */;
2178
- var de = document.documentElement;
2179
- // window.innerWidth includes width of the scrollbar and is not a true representation of the viewport width.
2180
- // Therefore, when possible, use documentElement's clientWidth property.
2181
- data$b = {
2182
- width: de && "clientWidth" in de ? Math.min(de.clientWidth, window.innerWidth) : window.innerWidth,
2183
- height: de && "clientHeight" in de ? Math.min(de.clientHeight, window.innerHeight) : window.innerHeight,
2184
- };
2185
- if (initialStateLogged) {
2186
- clearTimeout(timeout$4);
2187
- timeout$4 = setTimeout(process$5, 500 /* Setting.LookAhead */, 11 /* Event.Resize */);
2188
- }
2189
- else {
2190
- encode$3(11 /* Event.Resize */);
2191
- initialStateLogged = true;
2192
- }
2193
- }
2194
- function process$5(event) {
2195
- schedule$1(encode$3.bind(this, event));
2196
- }
2197
- function reset$e() {
2198
- data$b = null;
2199
- clearTimeout(timeout$4);
2200
- }
2201
- function stop$p() {
2202
- reset$e();
2203
- }
2204
-
2205
- var state$4 = [];
2206
- var initialTop = null;
2207
- var initialBottom = null;
2208
- var timeout$3 = null;
2209
- function start$q() {
2210
- state$4 = [];
2211
- recompute$4();
2212
- }
2213
- function observe$7(root) {
2214
- var frame = iframe(root);
2215
- var node = frame ? frame.contentWindow : (root === document ? window : root);
2216
- bind(node, "scroll", recompute$4, true);
2217
- }
2218
- function recompute$4(event) {
2219
- if (event === void 0) { event = null; }
2220
- recompute$4.dn = 13 /* FunctionNames.ScrollRecompute */;
2221
- var w = window;
2222
- var de = document.documentElement;
2223
- var element = event ? target(event) : de;
2224
- // If the target is a Document node, then identify corresponding documentElement and window for this document
2225
- if (element && element.nodeType === Node.DOCUMENT_NODE) {
2226
- var frame = iframe(element);
2227
- w = frame ? frame.contentWindow : w;
2228
- element = de = element.documentElement;
2229
- }
2230
- // Edge doesn't support scrollTop position on document.documentElement.
2231
- // For cross browser compatibility, looking up pageYOffset on window if the scroll is on document.
2232
- // And, if for some reason that is not available, fall back to looking up scrollTop on document.documentElement.
2233
- var x = element === de && "pageXOffset" in w ? Math.round(w.pageXOffset) : Math.round(element.scrollLeft);
2234
- var y = element === de && "pageYOffset" in w ? Math.round(w.pageYOffset) : Math.round(element.scrollTop);
2235
- var width = window.innerWidth;
2236
- var height = window.innerHeight;
2237
- var xPosition = width / 3;
2238
- var yOffset = width > height ? height * 0.15 : height * 0.2;
2239
- var startYPosition = yOffset;
2240
- var endYPosition = height - yOffset;
2241
- var top = getPositionNode(xPosition, startYPosition);
2242
- var bottom = getPositionNode(xPosition, endYPosition);
2243
- var current = { time: time(event), event: 10 /* Event.Scroll */, data: { target: element, x: x, y: y, top: top, bottom: bottom } };
2244
- // We don't send any scroll events if this is the first event and the current position is top (0,0)
2245
- if ((event === null && x === 0 && y === 0) || (x === null || y === null)) {
2246
- initialTop = top;
2247
- initialBottom = bottom;
1995
+ timestamp = timestamp || time();
1996
+ if (!(documentNode === null || documentNode === void 0 ? void 0 : documentNode.adoptedStyleSheets)) {
1997
+ // if we don't have adoptedStyledSheets on the Node passed to us, we can short circuit.
2248
1998
  return;
2249
1999
  }
2250
- var length = state$4.length;
2251
- var last = length > 1 ? state$4[length - 2] : null;
2252
- if (last && similar(last, current)) {
2253
- state$4.pop();
2254
- }
2255
- state$4.push(current);
2256
- clearTimeout(timeout$3);
2257
- timeout$3 = setTimeout(process$4, 500 /* Setting.LookAhead */, 10 /* Event.Scroll */);
2258
- }
2259
- function getPositionNode(x, y) {
2260
- var _a, _b;
2261
- var node;
2262
- if ("caretPositionFromPoint" in document) {
2263
- node = (_a = document.caretPositionFromPoint(x, y)) === null || _a === void 0 ? void 0 : _a.offsetNode;
2264
- }
2265
- else if ("caretRangeFromPoint" in document) {
2266
- node = (_b = document.caretRangeFromPoint(x, y)) === null || _b === void 0 ? void 0 : _b.startContainer;
2000
+ max(36 /* Metric.ConstructedStyles */, 1);
2001
+ var currentStyleSheets = [];
2002
+ for (var _i = 0, _a = documentNode.adoptedStyleSheets; _i < _a.length; _i++) {
2003
+ var styleSheet = _a[_i];
2004
+ // If we haven't seen this style sheet on this page yet, we create a reference to it for the visualizer.
2005
+ // For SPA or times in which Clarity restarts on a given page, our visualizer would lose context
2006
+ // on the previously created style sheet for page N-1.
2007
+ // Then we synthetically call replaceSync with its contents to bootstrap it
2008
+ if (!styleSheet[styleSheetId] || createdSheetIds.indexOf(styleSheet[styleSheetId]) === -1) {
2009
+ styleSheet[styleSheetId] = shortid();
2010
+ createdSheetIds.push(styleSheet[styleSheetId]);
2011
+ trackStyleChange(timestamp, styleSheet[styleSheetId], 0 /* StyleSheetOperation.Create */);
2012
+ trackStyleChange(timestamp, styleSheet[styleSheetId], 2 /* StyleSheetOperation.ReplaceSync */, getCssRules(styleSheet));
2013
+ }
2014
+ currentStyleSheets.push(styleSheet[styleSheetId]);
2267
2015
  }
2268
- if (!node) {
2269
- node = document.elementFromPoint(x, y);
2016
+ var documentId = getId(documentNode, true);
2017
+ if (!styleSheetMap[documentId]) {
2018
+ styleSheetMap[documentId] = [];
2270
2019
  }
2271
- if (node && node.nodeType === Node.TEXT_NODE) {
2272
- node = node.parentNode;
2020
+ if (!arraysEqual(currentStyleSheets, styleSheetMap[documentId])) {
2021
+ // Using -1 to signify the root document node as we don't track that as part of our nodeMap
2022
+ trackStyleAdoption(timestamp, documentNode == document ? -1 : getId(documentNode), 3 /* StyleSheetOperation.SetAdoptedStyles */, currentStyleSheets);
2023
+ styleSheetMap[documentId] = currentStyleSheets;
2024
+ styleTimeMap[documentId] = timestamp;
2273
2025
  }
2274
- return node;
2275
- }
2276
- function reset$d() {
2277
- state$4 = [];
2278
- initialTop = null;
2279
- initialBottom = null;
2280
- }
2281
- function process$4(event) {
2282
- schedule$1(encode$3.bind(this, event));
2283
- }
2284
- function similar(last, current) {
2285
- var dx = last.data.x - current.data.x;
2286
- var dy = last.data.y - current.data.y;
2287
- return (dx * dx + dy * dy < 20 /* Setting.Distance */ * 20 /* Setting.Distance */) && (current.time - last.time < 25 /* Setting.Interval */);
2288
2026
  }
2289
2027
  function compute$8() {
2290
- var _a, _b;
2291
- compute$8.dn = 14 /* FunctionNames.ScrollCompute */;
2292
- if (initialTop) {
2293
- var top_1 = metadata$2(initialTop, null);
2294
- log(31 /* Dimension.InitialScrollTop */, (_a = top_1 === null || top_1 === void 0 ? void 0 : top_1.hash) === null || _a === void 0 ? void 0 : _a.join("." /* Constant.Dot */));
2295
- }
2296
- if (initialBottom) {
2297
- var bottom = metadata$2(initialBottom, null);
2298
- log(32 /* Dimension.InitialScrollBottom */, (_b = bottom === null || bottom === void 0 ? void 0 : bottom.hash) === null || _b === void 0 ? void 0 : _b.join("." /* Constant.Dot */));
2028
+ for (var _i = 0, documentNodes_1 = documentNodes; _i < documentNodes_1.length; _i++) {
2029
+ var documentNode = documentNodes_1[_i];
2030
+ var docId = documentNode == document ? -1 : getId(documentNode);
2031
+ var ts = docId in styleTimeMap ? styleTimeMap[docId] : null;
2032
+ checkDocumentStyles(document, ts);
2299
2033
  }
2300
2034
  }
2301
- function stop$o() {
2302
- clearTimeout(timeout$3);
2303
- state$4 = [];
2304
- initialTop = null;
2305
- initialBottom = null;
2306
- }
2307
-
2308
- var data$a = null;
2309
- var previous = null;
2310
- var timeout$2 = null;
2311
- function start$p() {
2312
- reset$c();
2313
- }
2314
- function observe$6(root) {
2315
- bind(root, "selectstart", recompute$3.bind(this, root), true);
2316
- bind(root, "selectionchange", recompute$3.bind(this, root), true);
2035
+ function reset$b() {
2036
+ sheetAdoptionState = [];
2037
+ sheetUpdateState = [];
2317
2038
  }
2318
- function recompute$3(root) {
2319
- recompute$3.dn = 15 /* FunctionNames.SelectionRecompute */;
2320
- var doc = root.nodeType === Node.DOCUMENT_NODE ? root : document;
2321
- var current = doc.getSelection();
2322
- // Bail out if we don't have a valid selection
2323
- if (current === null) {
2324
- return;
2325
- }
2326
- // Bail out if we got a valid selection but not valid nodes
2327
- // In Edge, selectionchange gets fired even on interactions like right clicks and
2328
- // can result in null anchorNode and focusNode if there was no previous selection on page
2329
- // Also, ignore any selections that start and end at the exact same point
2330
- if ((current.anchorNode === null && current.focusNode === null) ||
2331
- (current.anchorNode === current.focusNode && current.anchorOffset === current.focusOffset)) {
2332
- return;
2333
- }
2334
- var startNode = data$a.start ? data$a.start : null;
2335
- if (previous !== null && data$a.start !== null && startNode !== current.anchorNode) {
2336
- clearTimeout(timeout$2);
2337
- process$3(21 /* Event.Selection */);
2338
- }
2339
- data$a = {
2340
- start: current.anchorNode,
2341
- startOffset: current.anchorOffset,
2342
- end: current.focusNode,
2343
- endOffset: current.focusOffset
2344
- };
2345
- previous = current;
2346
- clearTimeout(timeout$2);
2347
- timeout$2 = setTimeout(process$3, 500 /* Setting.LookAhead */, 21 /* Event.Selection */);
2039
+ function stop$k() {
2040
+ styleSheetMap = {};
2041
+ styleTimeMap = {};
2042
+ documentNodes = [];
2043
+ createdSheetIds = [];
2044
+ reset$b();
2348
2045
  }
2349
- function process$3(event) {
2350
- schedule$1(encode$3.bind(this, event));
2046
+ function trackStyleChange(time, id, operation, cssRules) {
2047
+ sheetUpdateState.push({
2048
+ time: time,
2049
+ event: 46 /* Event.StyleSheetUpdate */,
2050
+ data: {
2051
+ id: id,
2052
+ operation: operation,
2053
+ cssRules: cssRules
2054
+ }
2055
+ });
2056
+ encode$4(46 /* Event.StyleSheetUpdate */);
2351
2057
  }
2352
- function reset$c() {
2353
- previous = null;
2354
- data$a = { start: 0, startOffset: 0, end: 0, endOffset: 0 };
2058
+ function trackStyleAdoption(time, id, operation, newIds) {
2059
+ sheetAdoptionState.push({
2060
+ time: time,
2061
+ event: 45 /* Event.StyleSheetAdoption */,
2062
+ data: {
2063
+ id: id,
2064
+ operation: operation,
2065
+ newIds: newIds
2066
+ }
2067
+ });
2068
+ encode$4(45 /* Event.StyleSheetAdoption */);
2355
2069
  }
2356
- function stop$n() {
2357
- reset$c();
2358
- clearTimeout(timeout$2);
2070
+ function arraysEqual(a, b) {
2071
+ if (a.length !== b.length) {
2072
+ return false;
2073
+ }
2074
+ return a.every(function (value, index) { return value === b[index]; });
2359
2075
  }
2360
2076
 
2361
- var state$3 = [];
2362
- function start$o() {
2363
- reset$b();
2077
+ var state$2 = [];
2078
+ var elementAnimate = null;
2079
+ var animationPlay = null;
2080
+ var animationPause = null;
2081
+ var animationCommitStyles = null;
2082
+ var animationCancel = null;
2083
+ var animationFinish = null;
2084
+ var animationId = 'clarityAnimationId';
2085
+ var operationCount = 'clarityOperationCount';
2086
+ var maxOperations = 20;
2087
+ function start$l() {
2088
+ if (window["Animation"] &&
2089
+ window["Animation"].prototype &&
2090
+ window["KeyframeEffect"] &&
2091
+ window["KeyframeEffect"].prototype &&
2092
+ window["KeyframeEffect"].prototype.getKeyframes &&
2093
+ window["KeyframeEffect"].prototype.getTiming) {
2094
+ reset$a();
2095
+ overrideAnimationHelper(animationPlay, "play");
2096
+ overrideAnimationHelper(animationPause, "pause");
2097
+ overrideAnimationHelper(animationCommitStyles, "commitStyles");
2098
+ overrideAnimationHelper(animationCancel, "cancel");
2099
+ overrideAnimationHelper(animationFinish, "finish");
2100
+ if (elementAnimate === null) {
2101
+ elementAnimate = Element.prototype.animate;
2102
+ Element.prototype.animate = function () {
2103
+ var createdAnimation = elementAnimate.apply(this, arguments);
2104
+ trackAnimationOperation(createdAnimation, "play");
2105
+ return createdAnimation;
2106
+ };
2107
+ }
2108
+ if (document.getAnimations) {
2109
+ for (var _i = 0, _a = document.getAnimations(); _i < _a.length; _i++) {
2110
+ var animation = _a[_i];
2111
+ if (animation.playState === "finished") {
2112
+ trackAnimationOperation(animation, "finish");
2113
+ }
2114
+ else if (animation.playState === "paused" || animation.playState === "idle") {
2115
+ trackAnimationOperation(animation, "pause");
2116
+ }
2117
+ else if (animation.playState === "running") {
2118
+ trackAnimationOperation(animation, "play");
2119
+ }
2120
+ }
2121
+ }
2122
+ }
2364
2123
  }
2365
- function observe$5(root) {
2366
- bind(root, "submit", recompute$2, true);
2124
+ function reset$a() {
2125
+ state$2 = [];
2367
2126
  }
2368
- function recompute$2(evt) {
2369
- recompute$2.dn = 16 /* FunctionNames.SubmitRecompute */;
2370
- state$3.push({ time: time(evt), event: 39 /* Event.Submit */, data: { target: target(evt) } });
2371
- schedule$1(encode$3.bind(this, 39 /* Event.Submit */));
2127
+ function track$6(time, id, operation, keyFrames, timing, targetId, timeline) {
2128
+ state$2.push({
2129
+ time: time,
2130
+ event: 44 /* Event.Animation */,
2131
+ data: {
2132
+ id: id,
2133
+ operation: operation,
2134
+ keyFrames: keyFrames,
2135
+ timing: timing,
2136
+ targetId: targetId,
2137
+ timeline: timeline
2138
+ }
2139
+ });
2140
+ encode$4(44 /* Event.Animation */);
2372
2141
  }
2373
- function reset$b() {
2374
- state$3 = [];
2142
+ function stop$j() {
2143
+ reset$a();
2375
2144
  }
2376
- function stop$m() {
2377
- reset$b();
2145
+ function overrideAnimationHelper(functionToOverride, name) {
2146
+ if (functionToOverride === null) {
2147
+ functionToOverride = Animation.prototype[name];
2148
+ Animation.prototype[name] = function () {
2149
+ trackAnimationOperation(this, name);
2150
+ return functionToOverride.apply(this, arguments);
2151
+ };
2152
+ }
2153
+ }
2154
+ function trackAnimationOperation(animation, name) {
2155
+ if (active()) {
2156
+ var effect = animation.effect;
2157
+ var target = getId(effect.target);
2158
+ if (target !== null && effect.getKeyframes && effect.getTiming) {
2159
+ if (!animation[animationId]) {
2160
+ animation[animationId] = shortid();
2161
+ animation[operationCount] = 0;
2162
+ var keyframes = effect.getKeyframes();
2163
+ var timing = effect.getTiming();
2164
+ track$6(time(), animation[animationId], 0 /* AnimationOperation.Create */, JSON.stringify(keyframes), JSON.stringify(timing), target);
2165
+ }
2166
+ if (animation[operationCount]++ < maxOperations) {
2167
+ var operation = null;
2168
+ switch (name) {
2169
+ case "play":
2170
+ operation = 1 /* AnimationOperation.Play */;
2171
+ break;
2172
+ case "pause":
2173
+ operation = 2 /* AnimationOperation.Pause */;
2174
+ break;
2175
+ case "cancel":
2176
+ operation = 3 /* AnimationOperation.Cancel */;
2177
+ break;
2178
+ case "finish":
2179
+ operation = 4 /* AnimationOperation.Finish */;
2180
+ break;
2181
+ case "commitStyles":
2182
+ operation = 5 /* AnimationOperation.CommitStyles */;
2183
+ break;
2184
+ }
2185
+ if (operation) {
2186
+ track$6(time(), animation[animationId], operation);
2187
+ }
2188
+ }
2189
+ }
2190
+ }
2378
2191
  }
2379
2192
 
2380
- var data$9;
2381
- function start$n() {
2382
- bind(window, "pagehide", recompute$1);
2193
+ function encode$4 (type, timer, ts) {
2194
+ if (timer === void 0) { timer = null; }
2195
+ if (ts === void 0) { ts = null; }
2196
+ return __awaiter(this, void 0, void 0, function () {
2197
+ var eventTime, tokens, _a, d, _i, _b, r, _c, _d, entry, _e, _f, entry, _g, _h, entry, values, _j, values_1, value, state, data, active, suspend, privacy, mangle, keys, _k, keys_1, key, box, factor, attr;
2198
+ return __generator(this, function (_l) {
2199
+ switch (_l.label) {
2200
+ case 0:
2201
+ eventTime = ts || time();
2202
+ tokens = [eventTime, type];
2203
+ _a = type;
2204
+ switch (_a) {
2205
+ case 8 /* Event.Document */: return [3 /*break*/, 1];
2206
+ case 7 /* Event.Region */: return [3 /*break*/, 2];
2207
+ case 45 /* Event.StyleSheetAdoption */: return [3 /*break*/, 3];
2208
+ case 46 /* Event.StyleSheetUpdate */: return [3 /*break*/, 3];
2209
+ case 44 /* Event.Animation */: return [3 /*break*/, 4];
2210
+ case 5 /* Event.Discover */: return [3 /*break*/, 5];
2211
+ case 6 /* Event.Mutation */: return [3 /*break*/, 5];
2212
+ }
2213
+ return [3 /*break*/, 12];
2214
+ case 1:
2215
+ d = data$8;
2216
+ tokens.push(d.width);
2217
+ tokens.push(d.height);
2218
+ track$8(type, d.width, d.height);
2219
+ queue(tokens);
2220
+ return [3 /*break*/, 12];
2221
+ case 2:
2222
+ for (_i = 0, _b = state$1; _i < _b.length; _i++) {
2223
+ r = _b[_i];
2224
+ tokens = [r.time, 7 /* Event.Region */];
2225
+ tokens.push(r.data.id);
2226
+ tokens.push(r.data.interaction);
2227
+ tokens.push(r.data.visibility);
2228
+ tokens.push(r.data.name);
2229
+ queue(tokens);
2230
+ }
2231
+ reset$6();
2232
+ return [3 /*break*/, 12];
2233
+ case 3:
2234
+ for (_c = 0, _d = sheetAdoptionState; _c < _d.length; _c++) {
2235
+ entry = _d[_c];
2236
+ tokens = [entry.time, entry.event];
2237
+ tokens.push(entry.data.id);
2238
+ tokens.push(entry.data.operation);
2239
+ tokens.push(entry.data.newIds);
2240
+ queue(tokens);
2241
+ }
2242
+ for (_e = 0, _f = sheetUpdateState; _e < _f.length; _e++) {
2243
+ entry = _f[_e];
2244
+ tokens = [entry.time, entry.event];
2245
+ tokens.push(entry.data.id);
2246
+ tokens.push(entry.data.operation);
2247
+ tokens.push(entry.data.cssRules);
2248
+ queue(tokens);
2249
+ }
2250
+ reset$b();
2251
+ return [3 /*break*/, 12];
2252
+ case 4:
2253
+ for (_g = 0, _h = state$2; _g < _h.length; _g++) {
2254
+ entry = _h[_g];
2255
+ tokens = [entry.time, entry.event];
2256
+ tokens.push(entry.data.id);
2257
+ tokens.push(entry.data.operation);
2258
+ tokens.push(entry.data.keyFrames);
2259
+ tokens.push(entry.data.timing);
2260
+ tokens.push(entry.data.timeline);
2261
+ tokens.push(entry.data.targetId);
2262
+ queue(tokens);
2263
+ }
2264
+ reset$a();
2265
+ return [3 /*break*/, 12];
2266
+ case 5:
2267
+ // Check if we are operating within the context of the current page
2268
+ if (state$a(timer) === 2 /* Task.Stop */) {
2269
+ return [3 /*break*/, 12];
2270
+ }
2271
+ values = updates$2();
2272
+ if (!(values.length > 0)) return [3 /*break*/, 11];
2273
+ _j = 0, values_1 = values;
2274
+ _l.label = 6;
2275
+ case 6:
2276
+ if (!(_j < values_1.length)) return [3 /*break*/, 10];
2277
+ value = values_1[_j];
2278
+ state = state$a(timer);
2279
+ if (!(state === 0 /* Task.Wait */)) return [3 /*break*/, 8];
2280
+ return [4 /*yield*/, suspend$1(timer)];
2281
+ case 7:
2282
+ state = _l.sent();
2283
+ _l.label = 8;
2284
+ case 8:
2285
+ if (state === 2 /* Task.Stop */) {
2286
+ return [3 /*break*/, 10];
2287
+ }
2288
+ data = value.data;
2289
+ active = value.metadata.active;
2290
+ suspend = value.metadata.suspend;
2291
+ privacy = value.metadata.privacy;
2292
+ mangle = shouldMangle(value);
2293
+ keys = active ? ["tag", "attributes", "value"] : ["tag"];
2294
+ for (_k = 0, keys_1 = keys; _k < keys_1.length; _k++) {
2295
+ key = keys_1[_k];
2296
+ // we check for data[key] === '' because we want to encode empty strings as well, especially for value - which if skipped can cause our decoder to assume the final
2297
+ // attribute was the value for the node
2298
+ if (data[key] || data[key] === '') {
2299
+ switch (key) {
2300
+ case "tag":
2301
+ box = size(value);
2302
+ factor = mangle ? -1 : 1;
2303
+ tokens.push(value.id * factor);
2304
+ if (value.parent && active) {
2305
+ tokens.push(value.parent);
2306
+ if (value.previous) {
2307
+ tokens.push(value.previous);
2308
+ }
2309
+ }
2310
+ tokens.push(suspend ? "*M" /* Constant.SuspendMutationTag */ : data[key]);
2311
+ if (box && box.length === 2) {
2312
+ tokens.push("".concat("#" /* Constant.Hash */).concat(str$1(box[0]), ".").concat(str$1(box[1])));
2313
+ }
2314
+ break;
2315
+ case "attributes":
2316
+ for (attr in data[key]) {
2317
+ if (data[key][attr] !== undefined) {
2318
+ tokens.push(attribute(attr, data[key][attr], privacy));
2319
+ }
2320
+ }
2321
+ break;
2322
+ case "value":
2323
+ check$4(value.metadata.fraud, value.id, data[key]);
2324
+ tokens.push(text$1(data[key], data.tag, privacy, mangle));
2325
+ break;
2326
+ }
2327
+ }
2328
+ }
2329
+ _l.label = 9;
2330
+ case 9:
2331
+ _j++;
2332
+ return [3 /*break*/, 6];
2333
+ case 10:
2334
+ if (type === 6 /* Event.Mutation */) {
2335
+ activity(eventTime);
2336
+ }
2337
+ queue(tokenize(tokens), !config$2.lean);
2338
+ _l.label = 11;
2339
+ case 11: return [3 /*break*/, 12];
2340
+ case 12: return [2 /*return*/];
2341
+ }
2342
+ });
2343
+ });
2383
2344
  }
2384
- function recompute$1(evt) {
2385
- recompute$1.dn = 17 /* FunctionNames.UnloadRecompute */;
2386
- data$9 = { name: evt.type, persisted: evt.persisted ? 1 /* BooleanFlag.True */ : 0 /* BooleanFlag.False */ };
2387
- encode$3(26 /* Event.Unload */, time(evt));
2388
- stop();
2345
+ function shouldMangle(value) {
2346
+ var privacy = value.metadata.privacy;
2347
+ return value.data.tag === "*T" /* Constant.TextTag */ && !(privacy === 0 /* Privacy.None */ || privacy === 1 /* Privacy.Sensitive */);
2389
2348
  }
2390
- function reset$a() {
2391
- data$9 = null;
2349
+ function size(value) {
2350
+ if (value.metadata.size !== null && value.metadata.size.length === 0) {
2351
+ var img = getNode(value.id);
2352
+ if (img) {
2353
+ return [Math.floor(img.offsetWidth * 100 /* Setting.BoxPrecision */), Math.floor(img.offsetHeight * 100 /* Setting.BoxPrecision */)];
2354
+ }
2355
+ }
2356
+ return value.metadata.size;
2392
2357
  }
2393
- function stop$l() {
2394
- reset$a();
2358
+ function str$1(input) {
2359
+ return input.toString(36);
2360
+ }
2361
+ function attribute(key, value, privacy) {
2362
+ return "".concat(key, "=").concat(text$1(value, key.indexOf("data-" /* Constant.DataAttribute */) === 0 ? "data-" /* Constant.DataAttribute */ : key, privacy));
2395
2363
  }
2396
2364
 
2397
2365
  var data$8;
2398
- function start$m() {
2399
- bind(document, "visibilitychange", recompute);
2400
- recompute();
2401
- }
2402
- function recompute(evt) {
2403
- if (evt === void 0) { evt = null; }
2404
- recompute.dn = 18 /* FunctionNames.VisibilityRecompute */;
2405
- data$8 = { visible: "visibilityState" in document ? document.visibilityState : "default" };
2406
- encode$3(28 /* Event.Visibility */, time(evt));
2407
- }
2408
2366
  function reset$9() {
2409
2367
  data$8 = null;
2410
2368
  }
2411
- function stop$k() {
2369
+ function start$k() {
2412
2370
  reset$9();
2371
+ compute$7();
2413
2372
  }
2414
-
2415
- function start$l() {
2416
- start$l.dn = 8 /* FunctionNames.InteractionStart */;
2417
- start$g();
2418
- start$v();
2419
- start$u();
2420
- start$s();
2421
- start$t();
2422
- start$r();
2423
- start$m();
2424
- start$q();
2425
- start$p();
2426
- start$w();
2427
- start$o();
2428
- start$n();
2429
- }
2430
- function stop$j() {
2431
- stop$e();
2432
- stop$t();
2433
- stop$s();
2434
- stop$q();
2435
- stop$r();
2436
- stop$p();
2437
- stop$k();
2438
- stop$o();
2439
- stop$n();
2440
- stop$u();
2441
- stop$m();
2442
- stop$l();
2443
- }
2444
- function observe$4(root) {
2445
- observe$7(root);
2446
- // Only monitor following interactions if the root node is a document
2447
- // In case of shadow DOM, following events automatically bubble up to the parent document.
2448
- if (root.nodeType === Node.DOCUMENT_NODE) {
2449
- observe$b(root);
2450
- observe$a(root);
2451
- observe$8(root);
2452
- observe$9(root);
2453
- observe$6(root);
2454
- observe$c(root);
2455
- observe$5(root);
2373
+ function compute$7() {
2374
+ compute$7.dn = 19 /* FunctionNames.DocumentCompute */;
2375
+ var body = document.body;
2376
+ var d = document.documentElement;
2377
+ var bodyClientWidth = body ? body.clientWidth : null;
2378
+ var bodyScrollWidth = body ? body.scrollWidth : null;
2379
+ var bodyOffsetWidth = body ? body.offsetWidth : null;
2380
+ var documentClientWidth = d ? d.clientWidth : null;
2381
+ var documentScrollWidth = d ? d.scrollWidth : null;
2382
+ var documentOffsetWidth = d ? d.offsetWidth : null;
2383
+ var width = Math.max(bodyClientWidth, bodyScrollWidth, bodyOffsetWidth, documentClientWidth, documentScrollWidth, documentOffsetWidth);
2384
+ var bodyClientHeight = body ? body.clientHeight : null;
2385
+ var bodyScrollHeight = body ? body.scrollHeight : null;
2386
+ var bodyOffsetHeight = body ? body.offsetHeight : null;
2387
+ var documentClientHeight = d ? d.clientHeight : null;
2388
+ var documentScrollHeight = d ? d.scrollHeight : null;
2389
+ var documentOffsetHeight = d ? d.offsetHeight : null;
2390
+ var height = Math.max(bodyClientHeight, bodyScrollHeight, bodyOffsetHeight, documentClientHeight, documentScrollHeight, documentOffsetHeight);
2391
+ // Check that width or height has changed from before, and also that width & height are not null values
2392
+ if ((data$8 === null || width !== data$8.width || height !== data$8.height) && width !== null && height !== null) {
2393
+ data$8 = { width: width, height: height };
2394
+ encode$4(8 /* Event.Document */);
2456
2395
  }
2457
2396
  }
2458
-
2459
- var interaction = /*#__PURE__*/Object.freeze({
2460
- __proto__: null,
2461
- observe: observe$4,
2462
- start: start$l,
2463
- stop: stop$j
2464
- });
2397
+ function stop$i() {
2398
+ reset$9();
2399
+ }
2465
2400
 
2466
2401
  function traverse (root, timer, source, timestamp) {
2467
2402
  return __awaiter(this, void 0, void 0, function () {
@@ -2500,7 +2435,7 @@ function traverse (root, timer, source, timestamp) {
2500
2435
  });
2501
2436
  }
2502
2437
 
2503
- var observers = [];
2438
+ var observers = new Set();
2504
2439
  var mutations = [];
2505
2440
  var throttledMutations = {};
2506
2441
  var insertRule = null;
@@ -2513,18 +2448,16 @@ var timeout$1 = null;
2513
2448
  var throttleDelay = null;
2514
2449
  var activePeriod = null;
2515
2450
  var history$4 = {};
2516
- var criticalPeriod = null;
2517
2451
  var observedNodes = new WeakMap();
2518
2452
  // We ignore mutations if these attributes are updated
2519
2453
  var IGNORED_ATTRIBUTES = ["data-google-query-id", "data-load-complete", "data-google-container-id"];
2520
- function start$k() {
2521
- start$k.dn = 21 /* FunctionNames.MutationStart */;
2522
- observers = [];
2454
+ function start$j() {
2455
+ start$j.dn = 21 /* FunctionNames.MutationStart */;
2456
+ observers = new Set();
2523
2457
  queue$2 = [];
2524
2458
  timeout$1 = null;
2525
2459
  activePeriod = 0;
2526
2460
  history$4 = {};
2527
- criticalPeriod = 0;
2528
2461
  observedNodes = new WeakMap();
2529
2462
  // Some popular open source libraries, like styled-components, optimize performance
2530
2463
  // by injecting CSS using insertRule API vs. appending text node. A side effect of
@@ -2587,22 +2520,17 @@ function start$k() {
2587
2520
  }
2588
2521
  }
2589
2522
  function observe$3(node) {
2590
- var _a;
2591
2523
  // Create a new observer for every time a new DOM tree (e.g. root document or shadowdom root) is discovered on the page
2592
2524
  // In the case of shadow dom, any mutations that happen within the shadow dom are not bubbled up to the host document
2593
2525
  // For this reason, we need to wire up mutations every time we see a new shadow dom.
2594
2526
  // Also, wrap it inside a try / catch. In certain browsers (e.g. legacy Edge), observer on shadow dom can throw errors
2595
2527
  try {
2596
- // Cleanup old observer if present.
2597
- if (observedNodes.has(node)) {
2598
- (_a = observedNodes.get(node)) === null || _a === void 0 ? void 0 : _a.disconnect();
2599
- }
2600
2528
  var m = api("MutationObserver" /* Constant.MutationObserver */);
2601
2529
  var observer = m in window ? new window[m](measure(handle$1)) : null;
2602
2530
  if (observer) {
2603
2531
  observer.observe(node, { attributes: true, childList: true, characterData: true, subtree: true });
2604
2532
  observedNodes.set(node, observer);
2605
- observers.push(observer);
2533
+ observers.add(observer);
2606
2534
  }
2607
2535
  }
2608
2536
  catch (e) {
@@ -2613,29 +2541,36 @@ function monitor(frame) {
2613
2541
  // Bind to iframe's onload event so we get notified anytime there's an update to iframe content.
2614
2542
  // This includes cases where iframe location is updated without explicitly updating src attribute
2615
2543
  // E.g. iframe.contentWindow.location.href = "new-location";
2616
- if (has(frame) === false) {
2544
+ if (has$1(frame) === false) {
2617
2545
  bind(frame, "load" /* Constant.LoadEvent */, generate.bind(this, frame, "childList" /* Constant.ChildList */), true);
2618
2546
  }
2619
2547
  }
2620
- function stop$i() {
2621
- for (var _i = 0, observers_1 = observers; _i < observers_1.length; _i++) {
2622
- var observer = observers_1[_i];
2548
+ function stop$h() {
2549
+ for (var _i = 0, _a = Array.from(observers); _i < _a.length; _i++) {
2550
+ var observer = _a[_i];
2623
2551
  if (observer) {
2624
2552
  observer.disconnect();
2625
2553
  }
2626
2554
  }
2627
- observers = [];
2555
+ observers = new Set();
2628
2556
  history$4 = {};
2629
2557
  mutations = [];
2630
- throttledMutations = [];
2558
+ throttledMutations = {};
2631
2559
  queue$2 = [];
2632
2560
  activePeriod = 0;
2633
2561
  timeout$1 = null;
2634
- criticalPeriod = 0;
2562
+ observedNodes = new WeakMap();
2635
2563
  }
2636
2564
  function active$2() {
2637
2565
  activePeriod = time() + 3000 /* Setting.MutationActivePeriod */;
2638
- criticalPeriod = time() + config$2.criticalMs;
2566
+ }
2567
+ function disconnect(n) {
2568
+ var ob = observedNodes.get(n);
2569
+ if (ob) {
2570
+ ob.disconnect();
2571
+ observers.delete(ob);
2572
+ observedNodes.delete(n);
2573
+ }
2639
2574
  }
2640
2575
  function handle$1(m) {
2641
2576
  handle$1.dn = 22 /* FunctionNames.MutationHandle */;
@@ -2644,7 +2579,7 @@ function handle$1(m) {
2644
2579
  track$7(6 /* Event.Mutation */, now);
2645
2580
  mutations.push({ time: now, mutations: m });
2646
2581
  schedule$1(process$2, 1 /* Priority.High */).then(function () {
2647
- setTimeout(compute$9);
2582
+ setTimeout(compute$7);
2648
2583
  measure(compute$6)();
2649
2584
  });
2650
2585
  }
@@ -2698,7 +2633,7 @@ function process$2() {
2698
2633
  switch (_d.label) {
2699
2634
  case 0:
2700
2635
  timer = { id: id(), cost: 3 /* Metric.LayoutCost */ };
2701
- start$y(timer);
2636
+ start$z(timer);
2702
2637
  _d.label = 1;
2703
2638
  case 1:
2704
2639
  if (!(mutations.length > 0)) return [3 /*break*/, 7];
@@ -2748,7 +2683,7 @@ function process$2() {
2748
2683
  _d.label = 13;
2749
2684
  case 13:
2750
2685
  cleanHistory();
2751
- stop$w(timer);
2686
+ stop$x(timer);
2752
2687
  return [2 /*return*/];
2753
2688
  }
2754
2689
  });
@@ -2775,17 +2710,13 @@ function track$5(m, timer, instance, timestamp) {
2775
2710
  // calculate inactive period based on the timestamp of the mutation not when the mutation is processed
2776
2711
  var inactive = timestamp > activePeriod;
2777
2712
  // Calculate critical period based on when mutation is processed
2778
- var critical = instance < criticalPeriod;
2779
2713
  var target = get(m.target);
2780
- var element_1 = target && target.selector ? target.selector.join() : m.target.nodeName;
2714
+ var element = target && target.selector ? target.selector.join() : m.target.nodeName;
2781
2715
  var parent_1 = value.selector ? value.selector.join() : "" /* Constant.Empty */;
2782
- // Check if its a low priority (e.g., ads related) element mutation happening during critical period
2783
- // If the discard list is empty, we discard all mutations during critical period
2784
- var lowPriMutation = config$2.throttleMutations && critical && (config$2.discard.length === 0 || config$2.discard.some(function (key) { return element_1.includes(key); }));
2785
2716
  // We use selector, instead of id, to determine the key (signature for the mutation) because in some cases
2786
2717
  // repeated mutations can cause elements to be destroyed and then recreated as new DOM nodes
2787
2718
  // In those cases, IDs will change however the selector (which is relative to DOM xPath) remains the same
2788
- var key = [parent_1, element_1, m.attributeName, names(m.addedNodes), names(m.removedNodes)].join();
2719
+ var key = [parent_1, element, m.attributeName, names(m.addedNodes), names(m.removedNodes)].join();
2789
2720
  // Initialize an entry if it doesn't already exist
2790
2721
  history$4[key] = key in history$4 ? history$4[key] : [0, instance];
2791
2722
  var h = history$4[key];
@@ -2794,12 +2725,12 @@ function track$5(m, timer, instance, timestamp) {
2794
2725
  processNodeList(h[2], 2 /* Source.ChildListRemove */, timer, timestamp);
2795
2726
  }
2796
2727
  // Update the counter, do not reset counter if its critical period
2797
- h[0] = inactive || lowPriMutation ? (h[1] === instance ? h[0] : h[0] + 1) : 1;
2728
+ h[0] = inactive ? (h[1] === instance ? h[0] : h[0] + 1) : 1;
2798
2729
  h[1] = instance;
2799
2730
  // Return updated mutation type based on,
2800
2731
  // 1. if we have already hit the threshold or not
2801
2732
  // 2. if its a low priority mutation happening during critical time period
2802
- if (h[0] >= 10 /* Setting.MutationSuspendThreshold */ || lowPriMutation) {
2733
+ if (h[0] >= 10 /* Setting.MutationSuspendThreshold */) {
2803
2734
  // Store a reference to removedNodes so we can process them later
2804
2735
  // when we resume mutations again on user interactions
2805
2736
  h[2] = m.removedNodes;
@@ -2889,7 +2820,7 @@ function trigger$2() {
2889
2820
  if (node) {
2890
2821
  var shadowRoot = node.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
2891
2822
  // Skip re-processing shadowRoot if it was already discovered
2892
- if (shadowRoot && has(node)) {
2823
+ if (shadowRoot && has$1(node)) {
2893
2824
  continue;
2894
2825
  }
2895
2826
  generate(node, shadowRoot ? "childList" /* Constant.ChildList */ : "characterData" /* Constant.CharacterData */);
@@ -2983,7 +2914,7 @@ function processNode (node, source, timestamp) {
2983
2914
  var _a;
2984
2915
  var child = null;
2985
2916
  // Do not track this change if we are attempting to remove a node before discovering it
2986
- if (source === 2 /* Source.ChildListRemove */ && has(node) === false) {
2917
+ if (source === 2 /* Source.ChildListRemove */ && has$1(node) === false) {
2987
2918
  return child;
2988
2919
  }
2989
2920
  // Special handling for text nodes that belong to style nodes
@@ -2993,7 +2924,7 @@ function processNode (node, source, timestamp) {
2993
2924
  node.parentElement.tagName === "STYLE") {
2994
2925
  node = node.parentNode;
2995
2926
  }
2996
- var add = has(node) === false;
2927
+ var add = has$1(node) === false;
2997
2928
  var call = add ? "add" : "update";
2998
2929
  var parent = node.parentElement ? node.parentElement : null;
2999
2930
  var insideFrame = node.ownerDocument !== document;
@@ -3010,8 +2941,9 @@ function processNode (node, source, timestamp) {
3010
2941
  case Node.DOCUMENT_NODE:
3011
2942
  // We check for regions in the beginning when discovering document and
3012
2943
  // later whenever there are new additions or modifications to DOM (mutations)
3013
- if (node === document)
2944
+ if (node === document) {
3014
2945
  parse$1(document);
2946
+ }
3015
2947
  checkDocumentStyles(node, timestamp);
3016
2948
  observe$2(node);
3017
2949
  break;
@@ -3047,7 +2979,7 @@ function processNode (node, source, timestamp) {
3047
2979
  // Also, we do not track text nodes for STYLE tags
3048
2980
  // The only exception is when we receive a mutation to remove the text node, in that case
3049
2981
  // parent will be null, but we can still process the node by checking it's an update call.
3050
- if (call === "update" || (parent && has(parent) && parent.tagName !== "STYLE" && parent.tagName !== "NOSCRIPT")) {
2982
+ if (call === "update" || (parent && has$1(parent) && parent.tagName !== "STYLE" && parent.tagName !== "NOSCRIPT")) {
3051
2983
  var textData = { tag: "*T" /* Constant.TextTag */, value: node.nodeValue };
3052
2984
  dom[call](node, parent, textData, source);
3053
2985
  }
@@ -3133,6 +3065,9 @@ function processNode (node, source, timestamp) {
3133
3065
  child = iframe$1.contentDocument;
3134
3066
  }
3135
3067
  }
3068
+ if (source === 2 /* Source.ChildListRemove */) {
3069
+ removeObserver(iframe$1);
3070
+ }
3136
3071
  dom[call](node, parent, frameData, source);
3137
3072
  break;
3138
3073
  case "LINK":
@@ -3176,12 +3111,30 @@ function processNode (node, source, timestamp) {
3176
3111
  return child;
3177
3112
  }
3178
3113
  function observe$2(root) {
3179
- if (has(root)) {
3114
+ if (has$1(root) || has(root)) {
3180
3115
  return;
3181
3116
  }
3182
3117
  observe$3(root); // Observe mutations for this root node
3183
3118
  observe$4(root); // Observe interactions for this root node
3184
3119
  }
3120
+ function removeObserver(root) {
3121
+ // iframes will have load event listeners and they should be removed when iframe is removed
3122
+ // from the document
3123
+ unbind(root);
3124
+ var _a = iframeContent(root) || {}, _b = _a.doc, doc = _b === void 0 ? null : _b, _c = _a.win, win = _c === void 0 ? null : _c;
3125
+ if (win) {
3126
+ // For iframes, scroll event is observed on content window and this needs to be removed as well
3127
+ unbind(win);
3128
+ }
3129
+ if (doc) {
3130
+ // When an iframe is removed, we should also remove all listeners attached to its document
3131
+ // to avoid memory leaks.
3132
+ unbind(doc);
3133
+ disconnect(doc);
3134
+ // Remove iframe and content document from maps tracking them
3135
+ removeIFrame(root, doc);
3136
+ }
3137
+ }
3185
3138
  function getStyleValue(style) {
3186
3139
  // Call trim on the text content to ensure we do not process white spaces ( , \n, \r\n, \t, etc.)
3187
3140
  // Also, check if stylesheet has any data-* attribute, if so process rules instead of looking up text
@@ -3194,457 +3147,543 @@ function getStyleValue(style) {
3194
3147
  }
3195
3148
  return value;
3196
3149
  }
3197
- function getCssRules(sheet) {
3198
- var value = "" /* Constant.Empty */;
3199
- var cssRules = null;
3200
- // Firefox throws a SecurityError when trying to access cssRules of a stylesheet from a different domain
3150
+ function getCssRules(sheet) {
3151
+ var value = "" /* Constant.Empty */;
3152
+ var cssRules = null;
3153
+ // Firefox throws a SecurityError when trying to access cssRules of a stylesheet from a different domain
3154
+ try {
3155
+ cssRules = sheet ? sheet.cssRules : [];
3156
+ }
3157
+ catch (e) {
3158
+ log$1(1 /* Code.CssRules */, 1 /* Severity.Warning */, e ? e.name : null);
3159
+ if (e && e.name !== "SecurityError") {
3160
+ throw e;
3161
+ }
3162
+ }
3163
+ if (cssRules !== null) {
3164
+ for (var i = 0; i < cssRules.length; i++) {
3165
+ value += cssRules[i].cssText;
3166
+ }
3167
+ }
3168
+ return value;
3169
+ }
3170
+ function getAttributes(element) {
3171
+ var output = {};
3172
+ var attributes = element.attributes;
3173
+ if (attributes && attributes.length > 0) {
3174
+ for (var i = 0; i < attributes.length; i++) {
3175
+ var name_1 = attributes[i].name;
3176
+ if (IGNORE_ATTRIBUTES.indexOf(name_1) < 0) {
3177
+ output[name_1] = attributes[i].value;
3178
+ }
3179
+ }
3180
+ }
3181
+ // For INPUT tags read the dynamic "value" property if an explicit "value" attribute is not set
3182
+ if (element.tagName === "INPUT" /* Constant.InputTag */ && !("value" /* Constant.Value */ in output) && element.value) {
3183
+ output["value" /* Constant.Value */] = element.value;
3184
+ }
3185
+ return output;
3186
+ }
3187
+
3188
+ var excludeClassNames = "load,active,fixed,visible,focus,show,collaps,animat" /* Constant.ExcludeClassNames */.split("," /* Constant.Comma */);
3189
+ var selectorMap = {};
3190
+ function reset$8() {
3191
+ selectorMap = {};
3192
+ }
3193
+ function get$1(input, type) {
3194
+ var a = input.attributes;
3195
+ var prefix = input.prefix ? input.prefix[type] : null;
3196
+ var suffix = type === 0 /* Selector.Alpha */ ? "".concat("~" /* Constant.Tilde */).concat(input.position - 1) : ":nth-of-type(".concat(input.position, ")");
3197
+ switch (input.tag) {
3198
+ case "STYLE":
3199
+ case "TITLE":
3200
+ case "LINK":
3201
+ case "META":
3202
+ case "*T" /* Constant.TextTag */:
3203
+ case "*D" /* Constant.DocumentTag */:
3204
+ return "" /* Constant.Empty */;
3205
+ case "HTML":
3206
+ return "HTML" /* Constant.HTML */;
3207
+ default:
3208
+ if (prefix === null) {
3209
+ return "" /* Constant.Empty */;
3210
+ }
3211
+ prefix = "".concat(prefix).concat(">" /* Constant.Separator */);
3212
+ input.tag = input.tag.indexOf("svg:" /* Constant.SvgPrefix */) === 0 ? input.tag.substr("svg:" /* Constant.SvgPrefix */.length) : input.tag;
3213
+ var selector = "".concat(prefix).concat(input.tag).concat(suffix);
3214
+ var id = "id" /* Constant.Id */ in a && a["id" /* Constant.Id */].length > 0 ? a["id" /* Constant.Id */] : null;
3215
+ var classes = input.tag !== "BODY" /* Constant.BodyTag */ && "class" /* Constant.Class */ in a && a["class" /* Constant.Class */].length > 0 ? a["class" /* Constant.Class */].trim().split(/\s+/).filter(function (c) { return filter(c); }).join("." /* Constant.Period */) : null;
3216
+ if (classes && classes.length > 0) {
3217
+ if (type === 0 /* Selector.Alpha */) {
3218
+ // In Alpha mode, update selector to use class names, with relative positioning within the parent id container.
3219
+ // If the node has valid class name(s) then drop relative positioning within the parent path to keep things simple.
3220
+ var key = "".concat(getDomPath(prefix)).concat(input.tag).concat("." /* Constant.Dot */).concat(classes);
3221
+ if (!(key in selectorMap)) {
3222
+ selectorMap[key] = [];
3223
+ }
3224
+ if (selectorMap[key].indexOf(input.id) < 0) {
3225
+ selectorMap[key].push(input.id);
3226
+ }
3227
+ selector = "".concat(key).concat("~" /* Constant.Tilde */).concat(selectorMap[key].indexOf(input.id));
3228
+ }
3229
+ else {
3230
+ // In Beta mode, we continue to look at query selectors in context of the full page
3231
+ selector = "".concat(prefix).concat(input.tag, ".").concat(classes).concat(suffix);
3232
+ }
3233
+ }
3234
+ // Update selector to use "id" field when available. There are two exceptions:
3235
+ // (1) if "id" appears to be an auto generated string token, e.g. guid or a random id containing digits
3236
+ // (2) if "id" appears inside a shadow DOM, in which case we continue to prefix up to shadow DOM to prevent conflicts
3237
+ selector = id && filter(id) ? "".concat(getDomPrefix(prefix)).concat("#" /* Constant.Hash */).concat(id) : selector;
3238
+ return selector;
3239
+ }
3240
+ }
3241
+ function getDomPrefix(prefix) {
3242
+ var shadowDomStart = prefix.lastIndexOf("*S" /* Constant.ShadowDomTag */);
3243
+ var iframeDomStart = prefix.lastIndexOf("".concat("iframe:" /* Constant.IFramePrefix */).concat("HTML" /* Constant.HTML */));
3244
+ var domStart = Math.max(shadowDomStart, iframeDomStart);
3245
+ if (domStart < 0) {
3246
+ return "" /* Constant.Empty */;
3247
+ }
3248
+ return prefix.substring(0, prefix.indexOf(">" /* Constant.Separator */, domStart) + 1);
3249
+ }
3250
+ function getDomPath(input) {
3251
+ var parts = input.split(">" /* Constant.Separator */);
3252
+ for (var i = 0; i < parts.length; i++) {
3253
+ var tIndex = parts[i].indexOf("~" /* Constant.Tilde */);
3254
+ var dIndex = parts[i].indexOf("." /* Constant.Dot */);
3255
+ parts[i] = parts[i].substring(0, dIndex > 0 ? dIndex : (tIndex > 0 ? tIndex : parts[i].length));
3256
+ }
3257
+ return parts.join(">" /* Constant.Separator */);
3258
+ }
3259
+ // Check if the given input string has digits or excluded class names
3260
+ function filter(value) {
3261
+ if (!value) {
3262
+ return false;
3263
+ } // Do not process empty strings
3264
+ if (excludeClassNames.some(function (x) { return value.toLowerCase().indexOf(x) >= 0; })) {
3265
+ return false;
3266
+ }
3267
+ for (var i = 0; i < value.length; i++) {
3268
+ var c = value.charCodeAt(i);
3269
+ if (c >= 48 /* Character.Zero */ && c <= 57 /* Character.Nine */) {
3270
+ return false;
3271
+ }
3272
+ }
3273
+ return true;
3274
+ }
3275
+
3276
+ var selector = /*#__PURE__*/Object.freeze({
3277
+ __proto__: null,
3278
+ get: get$1,
3279
+ reset: reset$8
3280
+ });
3281
+
3282
+ var index = 1;
3283
+ var nodesMap = null; // Maps id => node to retrieve further node details using id.
3284
+ var values = [];
3285
+ var updateMap = [];
3286
+ var hashMap = {};
3287
+ var override = [];
3288
+ var unmask = [];
3289
+ var maskText = [];
3290
+ var maskExclude = [];
3291
+ var maskDisable = [];
3292
+ var maskTags = [];
3293
+ // The WeakMap object is a collection of key/value pairs in which the keys are weakly referenced
3294
+ var idMap = null; // Maps node => id.
3295
+ var iframeMap = null; // Maps iframe's contentDocument => parent iframe element
3296
+ var iframeContentMap = null; // Maps parent iframe element => iframe's contentDocument & contentWindow
3297
+ var privacyMap = null; // Maps node => Privacy (enum)
3298
+ var fraudMap = null; // Maps node => FraudId (number)
3299
+ function start$i() {
3300
+ reset$7();
3301
+ parse$1(document, true);
3302
+ }
3303
+ function stop$g() {
3304
+ reset$7();
3305
+ }
3306
+ function reset$7() {
3307
+ index = 1;
3308
+ values = [];
3309
+ updateMap = [];
3310
+ hashMap = {};
3311
+ override = [];
3312
+ unmask = [];
3313
+ maskText = "address,password,contact" /* Mask.Text */.split("," /* Constant.Comma */);
3314
+ maskExclude = "password,secret,pass,social,ssn,code,hidden" /* Mask.Exclude */.split("," /* Constant.Comma */);
3315
+ maskDisable = "radio,checkbox,range,button,reset,submit" /* Mask.Disable */.split("," /* Constant.Comma */);
3316
+ maskTags = "INPUT,SELECT,TEXTAREA" /* Mask.Tags */.split("," /* Constant.Comma */);
3317
+ nodesMap = new Map();
3318
+ idMap = new WeakMap();
3319
+ iframeMap = new WeakMap();
3320
+ iframeContentMap = new WeakMap();
3321
+ privacyMap = new WeakMap();
3322
+ fraudMap = new WeakMap();
3323
+ reset$8();
3324
+ }
3325
+ // We parse new root nodes for any regions or masked nodes in the beginning (document) and
3326
+ // later whenever there are new additions or modifications to DOM (mutations)
3327
+ function parse$1(root, init) {
3328
+ if (init === void 0) { init = false; }
3329
+ // Wrap selectors in a try / catch block.
3330
+ // It's possible for script to receive invalid selectors, e.g. "'#id'" with extra quotes, and cause the code below to fail
3201
3331
  try {
3202
- cssRules = sheet ? sheet.cssRules : [];
3332
+ // Parse unmask configuration into separate query selectors and override tokens as part of initialization
3333
+ if (init) {
3334
+ config$2.unmask.forEach(function (x) { return x.indexOf("!" /* Constant.Bang */) < 0 ? unmask.push(x) : override.push(x.substr(1)); });
3335
+ }
3336
+ // Since mutations may happen on leaf nodes too, e.g. text nodes, which may not support all selector APIs.
3337
+ // We ensure that the root note supports querySelectorAll API before executing the code below to identify new regions.
3338
+ if ("querySelectorAll" in root) {
3339
+ config$2.regions.forEach(function (x) { return root.querySelectorAll(x[1]).forEach(function (e) { return observe$1(e, "".concat(x[0])); }); }); // Regions
3340
+ config$2.mask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 3 /* Privacy.TextImage */); }); }); // Masked Elements
3341
+ config$2.checksum.forEach(function (x) { return root.querySelectorAll(x[1]).forEach(function (e) { return fraudMap.set(e, x[0]); }); }); // Fraud Checksum Check
3342
+ unmask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 0 /* Privacy.None */); }); }); // Unmasked Elements
3343
+ }
3203
3344
  }
3204
3345
  catch (e) {
3205
- log$1(1 /* Code.CssRules */, 1 /* Severity.Warning */, e ? e.name : null);
3206
- if (e && e.name !== "SecurityError") {
3207
- throw e;
3208
- }
3346
+ log$1(5 /* Code.Selector */, 1 /* Severity.Warning */, e ? e.name : null);
3209
3347
  }
3210
- if (cssRules !== null) {
3211
- for (var i = 0; i < cssRules.length; i++) {
3212
- value += cssRules[i].cssText;
3213
- }
3348
+ }
3349
+ function getId(node, autogen) {
3350
+ if (autogen === void 0) { autogen = false; }
3351
+ if (node === null) {
3352
+ return null;
3214
3353
  }
3215
- return value;
3354
+ var id = idMap.get(node);
3355
+ if (!id && autogen) {
3356
+ id = index++;
3357
+ idMap.set(node, id);
3358
+ }
3359
+ return id ? id : null;
3216
3360
  }
3217
- function getAttributes(element) {
3218
- var output = {};
3219
- var attributes = element.attributes;
3220
- if (attributes && attributes.length > 0) {
3221
- for (var i = 0; i < attributes.length; i++) {
3222
- var name_1 = attributes[i].name;
3223
- if (IGNORE_ATTRIBUTES.indexOf(name_1) < 0) {
3224
- output[name_1] = attributes[i].value;
3225
- }
3226
- }
3361
+ function add(node, parent, data, source) {
3362
+ var parentId = parent ? getId(parent) : null;
3363
+ // Do not add detached nodes
3364
+ if ((!parent || !parentId) && node.host == null && node.nodeType !== Node.DOCUMENT_TYPE_NODE) {
3365
+ return;
3227
3366
  }
3228
- // For INPUT tags read the dynamic "value" property if an explicit "value" attribute is not set
3229
- if (element.tagName === "INPUT" /* Constant.InputTag */ && !("value" /* Constant.Value */ in output) && element.value) {
3230
- output["value" /* Constant.Value */] = element.value;
3367
+ var id = getId(node, true);
3368
+ var previousId = getPreviousId(node);
3369
+ var parentValue = null;
3370
+ var regionId = exists(node) ? id : null;
3371
+ var fraudId = fraudMap.has(node) ? fraudMap.get(node) : null;
3372
+ var privacyId = config$2.content ? 1 /* Privacy.Sensitive */ : 3 /* Privacy.TextImage */;
3373
+ if (parentId >= 0 && values[parentId]) {
3374
+ parentValue = values[parentId];
3375
+ parentValue.children.push(id);
3376
+ regionId = regionId === null ? parentValue.region : regionId;
3377
+ fraudId = fraudId === null ? parentValue.metadata.fraud : fraudId;
3378
+ privacyId = parentValue.metadata.privacy;
3231
3379
  }
3232
- return output;
3380
+ // If there's an explicit region attribute set on the element, use it to mark a region on the page
3381
+ if (data.attributes && "data-clarity-region" /* Constant.RegionData */ in data.attributes) {
3382
+ observe$1(node, data.attributes["data-clarity-region" /* Constant.RegionData */]);
3383
+ regionId = id;
3384
+ }
3385
+ nodesMap.set(id, node);
3386
+ values[id] = {
3387
+ id: id,
3388
+ parent: parentId,
3389
+ previous: previousId,
3390
+ children: [],
3391
+ data: data,
3392
+ selector: null,
3393
+ hash: null,
3394
+ region: regionId,
3395
+ metadata: { active: true, suspend: false, privacy: privacyId, position: null, fraud: fraudId, size: null },
3396
+ };
3397
+ privacy(node, values[id], parentValue);
3398
+ updateSelector(values[id]);
3399
+ updateImageSize(values[id]);
3400
+ track$4(id, source);
3233
3401
  }
3234
-
3235
- var sheetUpdateState = [];
3236
- var sheetAdoptionState = [];
3237
- var replace = null;
3238
- var replaceSync = null;
3239
- var styleSheetId = 'claritySheetId';
3240
- var styleSheetMap = {};
3241
- var styleTimeMap = {};
3242
- var documentNodes = [];
3243
- var createdSheetIds = [];
3244
- function start$j() {
3245
- if (window['CSSStyleSheet'] && CSSStyleSheet.prototype) {
3246
- if (replace === null) {
3247
- replace = CSSStyleSheet.prototype.replace;
3248
- CSSStyleSheet.prototype.replace = function () {
3249
- if (active()) {
3250
- max(36 /* Metric.ConstructedStyles */, 1);
3251
- // if we haven't seen this stylesheet on this page yet, wait until the checkDocumentStyles has found it
3252
- // and attached the sheet to a document. This way the timestamp of the style sheet creation will align
3253
- // to when it is used in the document rather than potentially being misaligned during the traverse process.
3254
- if (createdSheetIds.indexOf(this[styleSheetId]) > -1) {
3255
- trackStyleChange(time(), this[styleSheetId], 1 /* StyleSheetOperation.Replace */, arguments[0]);
3256
- }
3257
- }
3258
- return replace.apply(this, arguments);
3259
- };
3402
+ function update$1(node, parent, data, source) {
3403
+ var id = getId(node);
3404
+ var parentId = parent ? getId(parent) : null;
3405
+ var previousId = getPreviousId(node);
3406
+ var changed = false;
3407
+ var parentChanged = false;
3408
+ if (id in values) {
3409
+ var value = values[id];
3410
+ value.metadata.active = true;
3411
+ // Handle case where internal ordering may have changed
3412
+ if (value.previous !== previousId) {
3413
+ changed = true;
3414
+ value.previous = previousId;
3260
3415
  }
3261
- if (replaceSync === null) {
3262
- replaceSync = CSSStyleSheet.prototype.replaceSync;
3263
- CSSStyleSheet.prototype.replaceSync = function () {
3264
- if (active()) {
3265
- max(36 /* Metric.ConstructedStyles */, 1);
3266
- // if we haven't seen this stylesheet on this page yet, wait until the checkDocumentStyles has found it
3267
- // and attached the sheet to a document. This way the timestamp of the style sheet creation will align
3268
- // to when it is used in the document rather than potentially being misaligned during the traverse process.
3269
- if (createdSheetIds.indexOf(this[styleSheetId]) > -1) {
3270
- trackStyleChange(time(), this[styleSheetId], 2 /* StyleSheetOperation.ReplaceSync */, arguments[0]);
3271
- }
3416
+ // Handle case where parent might have been updated
3417
+ if (value.parent !== parentId) {
3418
+ changed = true;
3419
+ var oldParentId = value.parent;
3420
+ value.parent = parentId;
3421
+ // Move this node to the right location under new parent
3422
+ if (parentId !== null && parentId >= 0) {
3423
+ var childIndex = previousId === null ? 0 : values[parentId].children.indexOf(previousId) + 1;
3424
+ values[parentId].children.splice(childIndex, 0, id);
3425
+ // Update region after the move
3426
+ value.region = exists(node) ? id : values[parentId].region;
3427
+ }
3428
+ else {
3429
+ // Mark this element as deleted if the parent has been updated to null
3430
+ remove(id, source);
3431
+ }
3432
+ // Remove reference to this node from the old parent
3433
+ if (oldParentId !== null && oldParentId >= 0) {
3434
+ var nodeIndex = values[oldParentId].children.indexOf(id);
3435
+ if (nodeIndex >= 0) {
3436
+ values[oldParentId].children.splice(nodeIndex, 1);
3272
3437
  }
3273
- return replaceSync.apply(this, arguments);
3274
- };
3438
+ }
3439
+ parentChanged = true;
3275
3440
  }
3276
- }
3277
- }
3278
- function checkDocumentStyles(documentNode, timestamp) {
3279
- if (documentNodes.indexOf(documentNode) === -1) {
3280
- documentNodes.push(documentNode);
3281
- }
3282
- timestamp = timestamp || time();
3283
- if (!(documentNode === null || documentNode === void 0 ? void 0 : documentNode.adoptedStyleSheets)) {
3284
- // if we don't have adoptedStyledSheets on the Node passed to us, we can short circuit.
3285
- return;
3286
- }
3287
- max(36 /* Metric.ConstructedStyles */, 1);
3288
- var currentStyleSheets = [];
3289
- for (var _i = 0, _a = documentNode.adoptedStyleSheets; _i < _a.length; _i++) {
3290
- var styleSheet = _a[_i];
3291
- // If we haven't seen this style sheet on this page yet, we create a reference to it for the visualizer.
3292
- // For SPA or times in which Clarity restarts on a given page, our visualizer would lose context
3293
- // on the previously created style sheet for page N-1.
3294
- // Then we synthetically call replaceSync with its contents to bootstrap it
3295
- if (!styleSheet[styleSheetId] || createdSheetIds.indexOf(styleSheet[styleSheetId]) === -1) {
3296
- styleSheet[styleSheetId] = shortid();
3297
- createdSheetIds.push(styleSheet[styleSheetId]);
3298
- trackStyleChange(timestamp, styleSheet[styleSheetId], 0 /* StyleSheetOperation.Create */);
3299
- trackStyleChange(timestamp, styleSheet[styleSheetId], 2 /* StyleSheetOperation.ReplaceSync */, getCssRules(styleSheet));
3441
+ // Update data
3442
+ for (var key in data) {
3443
+ if (diff(value["data"], data, key)) {
3444
+ changed = true;
3445
+ value["data"][key] = data[key];
3446
+ }
3300
3447
  }
3301
- currentStyleSheets.push(styleSheet[styleSheetId]);
3302
- }
3303
- var documentId = getId(documentNode, true);
3304
- if (!styleSheetMap[documentId]) {
3305
- styleSheetMap[documentId] = [];
3306
- }
3307
- if (!arraysEqual(currentStyleSheets, styleSheetMap[documentId])) {
3308
- // Using -1 to signify the root document node as we don't track that as part of our nodeMap
3309
- trackStyleAdoption(timestamp, documentNode == document ? -1 : getId(documentNode), 3 /* StyleSheetOperation.SetAdoptedStyles */, currentStyleSheets);
3310
- styleSheetMap[documentId] = currentStyleSheets;
3311
- styleTimeMap[documentId] = timestamp;
3448
+ // Update selector
3449
+ updateSelector(value);
3450
+ track$4(id, source, changed, parentChanged);
3312
3451
  }
3313
3452
  }
3314
- function compute$7() {
3315
- for (var _i = 0, documentNodes_1 = documentNodes; _i < documentNodes_1.length; _i++) {
3316
- var documentNode = documentNodes_1[_i];
3317
- var docId = documentNode == document ? -1 : getId(documentNode);
3318
- var ts = docId in styleTimeMap ? styleTimeMap[docId] : null;
3319
- checkDocumentStyles(document, ts);
3453
+ function sameorigin(node) {
3454
+ var output = false;
3455
+ if (node.nodeType === Node.ELEMENT_NODE && node.tagName === "IFRAME" /* Constant.IFrameTag */) {
3456
+ var frame = node;
3457
+ // To determine if the iframe is same-origin or not, we try accessing it's contentDocument.
3458
+ // If the browser throws an exception, we assume it's cross-origin and move on.
3459
+ // However, if we do a get a valid document object back, we assume the contents are accessible and iframe is same-origin.
3460
+ try {
3461
+ var doc = frame.contentDocument;
3462
+ if (doc) {
3463
+ iframeMap.set(frame.contentDocument, frame);
3464
+ iframeContentMap.set(frame, { doc: frame.contentDocument, win: frame.contentWindow });
3465
+ output = true;
3466
+ }
3467
+ }
3468
+ catch ( /* do nothing */_a) { /* do nothing */ }
3320
3469
  }
3470
+ return output;
3321
3471
  }
3322
- function reset$8() {
3323
- sheetAdoptionState = [];
3324
- sheetUpdateState = [];
3472
+ function iframe(node) {
3473
+ var doc = node.nodeType === Node.DOCUMENT_NODE ? node : null;
3474
+ return doc && iframeMap.has(doc) ? iframeMap.get(doc) : null;
3325
3475
  }
3326
- function stop$h() {
3327
- styleSheetMap = {};
3328
- styleTimeMap = {};
3329
- documentNodes = [];
3330
- createdSheetIds = [];
3331
- reset$8();
3476
+ function iframeContent(frame) {
3477
+ if (iframeContentMap.has(frame)) {
3478
+ return iframeContentMap.get(frame);
3479
+ }
3480
+ return null;
3332
3481
  }
3333
- function trackStyleChange(time, id, operation, cssRules) {
3334
- sheetUpdateState.push({
3335
- time: time,
3336
- event: 46 /* Event.StyleSheetUpdate */,
3337
- data: {
3338
- id: id,
3339
- operation: operation,
3340
- cssRules: cssRules
3341
- }
3342
- });
3343
- encode$4(46 /* Event.StyleSheetUpdate */);
3482
+ function removeIFrame(frame, doc) {
3483
+ iframeContentMap.delete(frame);
3484
+ iframeMap.delete(doc);
3344
3485
  }
3345
- function trackStyleAdoption(time, id, operation, newIds) {
3346
- sheetAdoptionState.push({
3347
- time: time,
3348
- event: 45 /* Event.StyleSheetAdoption */,
3349
- data: {
3350
- id: id,
3351
- operation: operation,
3352
- newIds: newIds
3353
- }
3354
- });
3355
- encode$4(45 /* Event.StyleSheetAdoption */);
3486
+ function privacy(node, value, parent) {
3487
+ var _a;
3488
+ var data = value.data;
3489
+ var metadata = value.metadata;
3490
+ var current = metadata.privacy;
3491
+ var attributes = data.attributes || {};
3492
+ var tag = data.tag.toUpperCase();
3493
+ switch (true) {
3494
+ case maskTags.indexOf(tag) >= 0:
3495
+ var type = attributes["type" /* Constant.Type */];
3496
+ var meta_1 = "" /* Constant.Empty */;
3497
+ var excludedPrivacyAttributes_1 = ["class" /* Constant.Class */, "style" /* Constant.Style */];
3498
+ Object.keys(attributes)
3499
+ .filter(function (x) { return !excludedPrivacyAttributes_1.includes(x); })
3500
+ .forEach(function (x) { return (meta_1 += attributes[x].toLowerCase()); });
3501
+ var exclude = maskExclude.some(function (x) { return meta_1.indexOf(x) >= 0; });
3502
+ // Regardless of privacy mode, always mask off user input from input boxes or drop downs with two exceptions:
3503
+ // (1) The node is detected to be one of the excluded fields, in which case we drop everything
3504
+ // (2) The node's type is one of the allowed types (like checkboxes)
3505
+ metadata.privacy = tag === "INPUT" /* Constant.InputTag */ && maskDisable.indexOf(type) >= 0 ? current : (exclude ? 4 /* Privacy.Exclude */ : 2 /* Privacy.Text */);
3506
+ break;
3507
+ case "data-clarity-mask" /* Constant.MaskData */ in attributes:
3508
+ metadata.privacy = 3 /* Privacy.TextImage */;
3509
+ break;
3510
+ case "data-clarity-unmask" /* Constant.UnmaskData */ in attributes:
3511
+ metadata.privacy = 0 /* Privacy.None */;
3512
+ break;
3513
+ case privacyMap.has(node):
3514
+ // If this node was explicitly configured to contain sensitive content, honor that privacy setting
3515
+ metadata.privacy = privacyMap.get(node);
3516
+ break;
3517
+ case fraudMap.has(node):
3518
+ // If this node was explicitly configured to be evaluated for fraud, then also mask content
3519
+ metadata.privacy = 2 /* Privacy.Text */;
3520
+ break;
3521
+ case tag === "*T" /* Constant.TextTag */:
3522
+ // If it's a text node belonging to a STYLE or TITLE tag or one of scrub exceptions, then capture content
3523
+ var pTag = parent && parent.data ? parent.data.tag : "" /* Constant.Empty */;
3524
+ var pSelector_1 = parent && parent.selector ? parent.selector[1 /* Selector.Default */] : "" /* Constant.Empty */;
3525
+ var tags = ["STYLE" /* Constant.StyleTag */, "TITLE" /* Constant.TitleTag */, "svg:style" /* Constant.SvgStyle */];
3526
+ metadata.privacy = tags.includes(pTag) || override.some(function (x) { return pSelector_1.indexOf(x) >= 0; }) ? 0 /* Privacy.None */ : current;
3527
+ break;
3528
+ case current === 1 /* Privacy.Sensitive */:
3529
+ // In a mode where we mask sensitive information by default, look through class names to aggressively mask content
3530
+ metadata.privacy = inspect(attributes["class" /* Constant.Class */], maskText, metadata);
3531
+ break;
3532
+ case tag === "IMG" /* Constant.ImageTag */:
3533
+ // Mask images with blob src as it is not publicly available anyway.
3534
+ if ((_a = attributes.src) === null || _a === void 0 ? void 0 : _a.startsWith('blob:')) {
3535
+ metadata.privacy = 3 /* Privacy.TextImage */;
3536
+ }
3537
+ break;
3538
+ }
3356
3539
  }
3357
- function arraysEqual(a, b) {
3358
- if (a.length !== b.length) {
3359
- return false;
3540
+ function inspect(input, lookup, metadata) {
3541
+ if (input && lookup.some(function (x) { return input.indexOf(x) >= 0; })) {
3542
+ return 2 /* Privacy.Text */;
3360
3543
  }
3361
- return a.every(function (value, index) { return value === b[index]; });
3544
+ return metadata.privacy;
3362
3545
  }
3363
-
3364
- var state$2 = [];
3365
- var elementAnimate = null;
3366
- var animationPlay = null;
3367
- var animationPause = null;
3368
- var animationCommitStyles = null;
3369
- var animationCancel = null;
3370
- var animationFinish = null;
3371
- var animationId = 'clarityAnimationId';
3372
- var operationCount = 'clarityOperationCount';
3373
- var maxOperations = 20;
3374
- function start$i() {
3375
- if (window["Animation"] &&
3376
- window["Animation"].prototype &&
3377
- window["KeyframeEffect"] &&
3378
- window["KeyframeEffect"].prototype &&
3379
- window["KeyframeEffect"].prototype.getKeyframes &&
3380
- window["KeyframeEffect"].prototype.getTiming) {
3381
- reset$7();
3382
- overrideAnimationHelper(animationPlay, "play");
3383
- overrideAnimationHelper(animationPause, "pause");
3384
- overrideAnimationHelper(animationCommitStyles, "commitStyles");
3385
- overrideAnimationHelper(animationCancel, "cancel");
3386
- overrideAnimationHelper(animationFinish, "finish");
3387
- if (elementAnimate === null) {
3388
- elementAnimate = Element.prototype.animate;
3389
- Element.prototype.animate = function () {
3390
- var createdAnimation = elementAnimate.apply(this, arguments);
3391
- trackAnimationOperation(createdAnimation, "play");
3392
- return createdAnimation;
3393
- };
3546
+ function diff(a, b, field) {
3547
+ if (typeof a[field] === "object" && typeof b[field] === "object") {
3548
+ for (var key in a[field]) {
3549
+ if (a[field][key] !== b[field][key]) {
3550
+ return true;
3551
+ }
3394
3552
  }
3395
- if (document.getAnimations) {
3396
- for (var _i = 0, _a = document.getAnimations(); _i < _a.length; _i++) {
3397
- var animation = _a[_i];
3398
- if (animation.playState === "finished") {
3399
- trackAnimationOperation(animation, "finish");
3400
- }
3401
- else if (animation.playState === "paused" || animation.playState === "idle") {
3402
- trackAnimationOperation(animation, "pause");
3403
- }
3404
- else if (animation.playState === "running") {
3405
- trackAnimationOperation(animation, "play");
3406
- }
3553
+ for (var key in b[field]) {
3554
+ if (b[field][key] !== a[field][key]) {
3555
+ return true;
3407
3556
  }
3408
3557
  }
3558
+ return false;
3409
3559
  }
3560
+ return a[field] !== b[field];
3410
3561
  }
3411
- function reset$7() {
3412
- state$2 = [];
3413
- }
3414
- function track$4(time, id, operation, keyFrames, timing, targetId, timeline) {
3415
- state$2.push({
3416
- time: time,
3417
- event: 44 /* Event.Animation */,
3418
- data: {
3419
- id: id,
3420
- operation: operation,
3421
- keyFrames: keyFrames,
3422
- timing: timing,
3423
- targetId: targetId,
3424
- timeline: timeline
3562
+ function position(parent, child) {
3563
+ child.metadata.position = 1;
3564
+ var idx = parent ? parent.children.indexOf(child.id) : -1;
3565
+ while (idx-- > 0) {
3566
+ var sibling = values[parent.children[idx]];
3567
+ if (child.data.tag === sibling.data.tag) {
3568
+ child.metadata.position = sibling.metadata.position + 1;
3569
+ break;
3425
3570
  }
3426
- });
3427
- encode$4(44 /* Event.Animation */);
3571
+ }
3572
+ return child.metadata.position;
3428
3573
  }
3429
- function stop$g() {
3430
- reset$7();
3574
+ function updateSelector(value) {
3575
+ var parent = value.parent && value.parent in values ? values[value.parent] : null;
3576
+ var prefix = parent ? parent.selector : null;
3577
+ var d = value.data;
3578
+ var p = position(parent, value);
3579
+ var s = { id: value.id, tag: d.tag, prefix: prefix, position: p, attributes: d.attributes };
3580
+ value.selector = [get$1(s, 0 /* Selector.Alpha */), get$1(s, 1 /* Selector.Beta */)];
3581
+ value.hash = value.selector.map(function (x) { return x ? hash(x) : null; });
3582
+ value.hash.forEach(function (h) { return hashMap[h] = value.id; });
3431
3583
  }
3432
- function overrideAnimationHelper(functionToOverride, name) {
3433
- if (functionToOverride === null) {
3434
- functionToOverride = Animation.prototype[name];
3435
- Animation.prototype[name] = function () {
3436
- trackAnimationOperation(this, name);
3437
- return functionToOverride.apply(this, arguments);
3438
- };
3584
+ function hashText(hash) {
3585
+ var id = lookup(hash);
3586
+ var node = getNode(id);
3587
+ return node !== null && node.textContent !== null ? node.textContent.substr(0, 25 /* Setting.ClickText */) : '';
3588
+ }
3589
+ function getNode(id) {
3590
+ return nodesMap.has(id) ? nodesMap.get(id) : null;
3591
+ }
3592
+ function getValue(id) {
3593
+ if (id in values) {
3594
+ return values[id];
3439
3595
  }
3596
+ return null;
3440
3597
  }
3441
- function trackAnimationOperation(animation, name) {
3442
- if (active()) {
3443
- var effect = animation.effect;
3444
- var target = getId(effect.target);
3445
- if (target !== null && effect.getKeyframes && effect.getTiming) {
3446
- if (!animation[animationId]) {
3447
- animation[animationId] = shortid();
3448
- animation[operationCount] = 0;
3449
- var keyframes = effect.getKeyframes();
3450
- var timing = effect.getTiming();
3451
- track$4(time(), animation[animationId], 0 /* AnimationOperation.Create */, JSON.stringify(keyframes), JSON.stringify(timing), target);
3452
- }
3453
- if (animation[operationCount]++ < maxOperations) {
3454
- var operation = null;
3455
- switch (name) {
3456
- case "play":
3457
- operation = 1 /* AnimationOperation.Play */;
3458
- break;
3459
- case "pause":
3460
- operation = 2 /* AnimationOperation.Pause */;
3461
- break;
3462
- case "cancel":
3463
- operation = 3 /* AnimationOperation.Cancel */;
3464
- break;
3465
- case "finish":
3466
- operation = 4 /* AnimationOperation.Finish */;
3467
- break;
3468
- case "commitStyles":
3469
- operation = 5 /* AnimationOperation.CommitStyles */;
3470
- break;
3471
- }
3472
- if (operation) {
3473
- track$4(time(), animation[animationId], operation);
3474
- }
3475
- }
3598
+ function get(node) {
3599
+ var id = getId(node);
3600
+ return id in values ? values[id] : null;
3601
+ }
3602
+ function lookup(hash) {
3603
+ return hash in hashMap ? hashMap[hash] : null;
3604
+ }
3605
+ function has$1(node) {
3606
+ return nodesMap.has(getId(node));
3607
+ }
3608
+ function updates$2() {
3609
+ var output = [];
3610
+ for (var _i = 0, updateMap_1 = updateMap; _i < updateMap_1.length; _i++) {
3611
+ var id = updateMap_1[_i];
3612
+ if (id in values) {
3613
+ output.push(values[id]);
3476
3614
  }
3477
3615
  }
3616
+ updateMap = [];
3617
+ return output;
3478
3618
  }
3479
-
3480
- function encode$4 (type, timer, ts) {
3481
- if (timer === void 0) { timer = null; }
3482
- if (ts === void 0) { ts = null; }
3483
- return __awaiter(this, void 0, void 0, function () {
3484
- var eventTime, tokens, _a, d, _i, _b, r, _c, _d, entry, _e, _f, entry, _g, _h, entry, values, _j, values_1, value, state, data, active, suspend, privacy, mangle, keys, _k, keys_1, key, box, factor, attr;
3485
- return __generator(this, function (_l) {
3486
- switch (_l.label) {
3487
- case 0:
3488
- eventTime = ts || time();
3489
- tokens = [eventTime, type];
3490
- _a = type;
3491
- switch (_a) {
3492
- case 8 /* Event.Document */: return [3 /*break*/, 1];
3493
- case 7 /* Event.Region */: return [3 /*break*/, 2];
3494
- case 45 /* Event.StyleSheetAdoption */: return [3 /*break*/, 3];
3495
- case 46 /* Event.StyleSheetUpdate */: return [3 /*break*/, 3];
3496
- case 44 /* Event.Animation */: return [3 /*break*/, 4];
3497
- case 5 /* Event.Discover */: return [3 /*break*/, 5];
3498
- case 6 /* Event.Mutation */: return [3 /*break*/, 5];
3499
- }
3500
- return [3 /*break*/, 12];
3501
- case 1:
3502
- d = data$c;
3503
- tokens.push(d.width);
3504
- tokens.push(d.height);
3505
- track$8(type, d.width, d.height);
3506
- queue(tokens);
3507
- return [3 /*break*/, 12];
3508
- case 2:
3509
- for (_i = 0, _b = state$1; _i < _b.length; _i++) {
3510
- r = _b[_i];
3511
- tokens = [r.time, 7 /* Event.Region */];
3512
- tokens.push(r.data.id);
3513
- tokens.push(r.data.interaction);
3514
- tokens.push(r.data.visibility);
3515
- tokens.push(r.data.name);
3516
- queue(tokens);
3517
- }
3518
- reset$6();
3519
- return [3 /*break*/, 12];
3520
- case 3:
3521
- for (_c = 0, _d = sheetAdoptionState; _c < _d.length; _c++) {
3522
- entry = _d[_c];
3523
- tokens = [entry.time, entry.event];
3524
- tokens.push(entry.data.id);
3525
- tokens.push(entry.data.operation);
3526
- tokens.push(entry.data.newIds);
3527
- queue(tokens);
3528
- }
3529
- for (_e = 0, _f = sheetUpdateState; _e < _f.length; _e++) {
3530
- entry = _f[_e];
3531
- tokens = [entry.time, entry.event];
3532
- tokens.push(entry.data.id);
3533
- tokens.push(entry.data.operation);
3534
- tokens.push(entry.data.cssRules);
3535
- queue(tokens);
3536
- }
3537
- reset$8();
3538
- return [3 /*break*/, 12];
3539
- case 4:
3540
- for (_g = 0, _h = state$2; _g < _h.length; _g++) {
3541
- entry = _h[_g];
3542
- tokens = [entry.time, entry.event];
3543
- tokens.push(entry.data.id);
3544
- tokens.push(entry.data.operation);
3545
- tokens.push(entry.data.keyFrames);
3546
- tokens.push(entry.data.timing);
3547
- tokens.push(entry.data.timeline);
3548
- tokens.push(entry.data.targetId);
3549
- queue(tokens);
3550
- }
3551
- reset$7();
3552
- return [3 /*break*/, 12];
3553
- case 5:
3554
- // Check if we are operating within the context of the current page
3555
- if (state$a(timer) === 2 /* Task.Stop */) {
3556
- return [3 /*break*/, 12];
3557
- }
3558
- values = updates$2();
3559
- if (!(values.length > 0)) return [3 /*break*/, 11];
3560
- _j = 0, values_1 = values;
3561
- _l.label = 6;
3562
- case 6:
3563
- if (!(_j < values_1.length)) return [3 /*break*/, 10];
3564
- value = values_1[_j];
3565
- state = state$a(timer);
3566
- if (!(state === 0 /* Task.Wait */)) return [3 /*break*/, 8];
3567
- return [4 /*yield*/, suspend$1(timer)];
3568
- case 7:
3569
- state = _l.sent();
3570
- _l.label = 8;
3571
- case 8:
3572
- if (state === 2 /* Task.Stop */) {
3573
- return [3 /*break*/, 10];
3574
- }
3575
- data = value.data;
3576
- active = value.metadata.active;
3577
- suspend = value.metadata.suspend;
3578
- privacy = value.metadata.privacy;
3579
- mangle = shouldMangle(value);
3580
- keys = active ? ["tag", "attributes", "value"] : ["tag"];
3581
- for (_k = 0, keys_1 = keys; _k < keys_1.length; _k++) {
3582
- key = keys_1[_k];
3583
- if (data[key]) {
3584
- switch (key) {
3585
- case "tag":
3586
- box = size(value);
3587
- factor = mangle ? -1 : 1;
3588
- tokens.push(value.id * factor);
3589
- if (value.parent && active) {
3590
- tokens.push(value.parent);
3591
- if (value.previous) {
3592
- tokens.push(value.previous);
3593
- }
3594
- }
3595
- tokens.push(suspend ? "*M" /* Constant.SuspendMutationTag */ : data[key]);
3596
- if (box && box.length === 2) {
3597
- tokens.push("".concat("#" /* Constant.Hash */).concat(str$1(box[0]), ".").concat(str$1(box[1])));
3598
- }
3599
- break;
3600
- case "attributes":
3601
- for (attr in data[key]) {
3602
- if (data[key][attr] !== undefined) {
3603
- tokens.push(attribute(attr, data[key][attr], privacy));
3604
- }
3605
- }
3606
- break;
3607
- case "value":
3608
- check$4(value.metadata.fraud, value.id, data[key]);
3609
- tokens.push(text$1(data[key], data.tag, privacy, mangle));
3610
- break;
3611
- }
3612
- }
3613
- }
3614
- _l.label = 9;
3615
- case 9:
3616
- _j++;
3617
- return [3 /*break*/, 6];
3618
- case 10:
3619
- if (type === 6 /* Event.Mutation */) {
3620
- activity(eventTime);
3621
- }
3622
- queue(tokenize(tokens), !config$2.lean);
3623
- _l.label = 11;
3624
- case 11: return [3 /*break*/, 12];
3625
- case 12: return [2 /*return*/];
3626
- }
3627
- });
3628
- });
3619
+ function remove(id, source) {
3620
+ if (id in values) {
3621
+ var value = values[id];
3622
+ value.metadata.active = false;
3623
+ value.parent = null;
3624
+ track$4(id, source);
3625
+ // Clean up node references for removed nodes
3626
+ removeNodeFromNodesMap(id);
3627
+ }
3629
3628
  }
3630
- function shouldMangle(value) {
3631
- var privacy = value.metadata.privacy;
3632
- return value.data.tag === "*T" /* Constant.TextTag */ && !(privacy === 0 /* Privacy.None */ || privacy === 1 /* Privacy.Sensitive */);
3629
+ function removeNodeFromNodesMap(id) {
3630
+ var nodeToBeRemoved = nodesMap.get(id);
3631
+ // Shadow dom roots shouldn't be deleted,
3632
+ // we should keep listening to the mutations there even they're not rendered in the DOM.
3633
+ if ((nodeToBeRemoved === null || nodeToBeRemoved === void 0 ? void 0 : nodeToBeRemoved.nodeType) === Node.DOCUMENT_FRAGMENT_NODE) {
3634
+ return;
3635
+ }
3636
+ if (nodeToBeRemoved && (nodeToBeRemoved === null || nodeToBeRemoved === void 0 ? void 0 : nodeToBeRemoved.nodeType) === Node.ELEMENT_NODE && nodeToBeRemoved["tagName"] === "IFRAME") {
3637
+ var iframe_1 = nodeToBeRemoved;
3638
+ removeObserver(iframe_1);
3639
+ }
3640
+ nodesMap.delete(id);
3641
+ var value = id in values ? values[id] : null;
3642
+ if (value && value.children) {
3643
+ for (var _i = 0, _a = value.children; _i < _a.length; _i++) {
3644
+ var childId = _a[_i];
3645
+ removeNodeFromNodesMap(childId);
3646
+ }
3647
+ }
3633
3648
  }
3634
- function size(value) {
3635
- if (value.metadata.size !== null && value.metadata.size.length === 0) {
3636
- var img = getNode(value.id);
3637
- if (img) {
3638
- return [Math.floor(img.offsetWidth * 100 /* Setting.BoxPrecision */), Math.floor(img.offsetHeight * 100 /* Setting.BoxPrecision */)];
3649
+ function updateImageSize(value) {
3650
+ // If this element is a image node, and is masked, then track box model for the current element
3651
+ if (value.data.tag === "IMG" /* Constant.ImageTag */ && value.metadata.privacy === 3 /* Privacy.TextImage */) {
3652
+ var img_1 = getNode(value.id);
3653
+ // We will not capture the natural image dimensions until it loads.
3654
+ if (img_1 && (!img_1.complete || img_1.naturalWidth === 0)) {
3655
+ // This will trigger mutation to update the original width and height after image loads.
3656
+ bind(img_1, 'load', function () {
3657
+ img_1.setAttribute('data-clarity-loaded', "".concat(shortid()));
3658
+ });
3639
3659
  }
3660
+ value.metadata.size = [];
3640
3661
  }
3641
- return value.metadata.size;
3642
3662
  }
3643
- function str$1(input) {
3644
- return input.toString(36);
3663
+ function getPreviousId(node) {
3664
+ var id = null;
3665
+ // Some nodes may not have an ID by design since Clarity skips over tags like SCRIPT, NOSCRIPT, META, COMMENTS, etc..
3666
+ // 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.
3667
+ while (id === null && node.previousSibling) {
3668
+ id = getId(node.previousSibling);
3669
+ node = node.previousSibling;
3670
+ }
3671
+ return id;
3645
3672
  }
3646
- function attribute(key, value, privacy) {
3647
- return "".concat(key, "=").concat(text$1(value, key.indexOf("data-" /* Constant.DataAttribute */) === 0 ? "data-" /* Constant.DataAttribute */ : key, privacy));
3673
+ function track$4(id, source, changed, parentChanged) {
3674
+ if (changed === void 0) { changed = true; }
3675
+ if (parentChanged === void 0) { parentChanged = false; }
3676
+ // Keep track of the order in which mutations happened, they may not be sequential
3677
+ // Edge case: If an element is added later on, and pre-discovered element is moved as a child.
3678
+ // In that case, we need to reorder the pre-discovered element in the update list to keep visualization consistent.
3679
+ var uIndex = updateMap.indexOf(id);
3680
+ if (uIndex >= 0 && source === 1 /* Source.ChildListAdd */ && parentChanged) {
3681
+ updateMap.splice(uIndex, 1);
3682
+ updateMap.push(id);
3683
+ }
3684
+ else if (uIndex === -1 && changed) {
3685
+ updateMap.push(id);
3686
+ }
3648
3687
  }
3649
3688
 
3650
3689
  var state$1 = [];
@@ -3803,7 +3842,7 @@ function target(evt) {
3803
3842
  function metadata$2(node, event, text) {
3804
3843
  if (text === void 0) { text = null; }
3805
3844
  // If the node is null, we return a reserved value for id: 0. Valid assignment of id begins from 1+.
3806
- var output = { id: 0, hash: null, privacy: 2 /* Privacy.Text */, node: node };
3845
+ var output = { id: 0, hash: null, privacy: 2 /* Privacy.Text */ };
3807
3846
  if (node) {
3808
3847
  var value = get(node);
3809
3848
  if (value !== null) {
@@ -3857,7 +3896,7 @@ function encode$3 (type, ts) {
3857
3896
  track$8(entry.event, entry.data.x, entry.data.y, entry.time);
3858
3897
  }
3859
3898
  }
3860
- reset$f();
3899
+ reset$i();
3861
3900
  break;
3862
3901
  case 9 /* Event.Click */:
3863
3902
  for (_b = 0, _c = state$8; _b < _c.length; _b++) {
@@ -3881,7 +3920,7 @@ function encode$3 (type, ts) {
3881
3920
  queue(tokens);
3882
3921
  track$2(entry.time, entry.event, cHash, entry.data.x, entry.data.y, entry.data.reaction, entry.data.context);
3883
3922
  }
3884
- reset$i();
3923
+ reset$l();
3885
3924
  break;
3886
3925
  case 38 /* Event.Clipboard */:
3887
3926
  for (_d = 0, _e = state$7; _d < _e.length; _d++) {
@@ -3894,21 +3933,21 @@ function encode$3 (type, ts) {
3894
3933
  queue(tokens);
3895
3934
  }
3896
3935
  }
3897
- reset$h();
3936
+ reset$k();
3898
3937
  break;
3899
3938
  case 11 /* Event.Resize */:
3900
- r = data$b;
3939
+ r = data$c;
3901
3940
  tokens.push(r.width);
3902
3941
  tokens.push(r.height);
3903
3942
  track$8(type, r.width, r.height);
3904
- reset$e();
3943
+ reset$h();
3905
3944
  queue(tokens);
3906
3945
  break;
3907
3946
  case 26 /* Event.Unload */:
3908
- u = data$9;
3947
+ u = data$a;
3909
3948
  tokens.push(u.name);
3910
3949
  tokens.push(u.persisted);
3911
- reset$a();
3950
+ reset$d();
3912
3951
  queue(tokens);
3913
3952
  break;
3914
3953
  case 27 /* Event.Input */:
@@ -3920,10 +3959,10 @@ function encode$3 (type, ts) {
3920
3959
  tokens.push(text$1(entry.data.value, "input", iTarget.privacy, false, entry.data.type));
3921
3960
  queue(tokens);
3922
3961
  }
3923
- reset$g();
3962
+ reset$j();
3924
3963
  break;
3925
3964
  case 21 /* Event.Selection */:
3926
- s = data$a;
3965
+ s = data$b;
3927
3966
  if (s) {
3928
3967
  startTarget = metadata$2(s.start, type);
3929
3968
  endTarget = metadata$2(s.end, type);
@@ -3931,7 +3970,7 @@ function encode$3 (type, ts) {
3931
3970
  tokens.push(s.startOffset);
3932
3971
  tokens.push(endTarget.id);
3933
3972
  tokens.push(s.endOffset);
3934
- reset$c();
3973
+ reset$f();
3935
3974
  queue(tokens);
3936
3975
  }
3937
3976
  break;
@@ -3954,7 +3993,7 @@ function encode$3 (type, ts) {
3954
3993
  track$8(entry.event, entry.data.x, entry.data.y, entry.time);
3955
3994
  }
3956
3995
  }
3957
- reset$d();
3996
+ reset$g();
3958
3997
  break;
3959
3998
  case 42 /* Event.Change */:
3960
3999
  for (_k = 0, _l = state$9; _k < _l.length; _k++) {
@@ -3970,7 +4009,7 @@ function encode$3 (type, ts) {
3970
4009
  queue(tokens);
3971
4010
  }
3972
4011
  }
3973
- reset$j();
4012
+ reset$m();
3974
4013
  break;
3975
4014
  case 39 /* Event.Submit */:
3976
4015
  for (_m = 0, _o = state$3; _m < _o.length; _m++) {
@@ -3982,7 +4021,7 @@ function encode$3 (type, ts) {
3982
4021
  queue(tokens);
3983
4022
  }
3984
4023
  }
3985
- reset$b();
4024
+ reset$e();
3986
4025
  break;
3987
4026
  case 22 /* Event.Timeline */:
3988
4027
  for (_p = 0, _q = updates$1; _p < _q.length; _p++) {
@@ -3999,11 +4038,11 @@ function encode$3 (type, ts) {
3999
4038
  reset$5();
4000
4039
  break;
4001
4040
  case 28 /* Event.Visibility */:
4002
- v = data$8;
4041
+ v = data$9;
4003
4042
  tokens.push(v.visible);
4004
4043
  queue(tokens);
4005
4044
  visibility(t, v.visible);
4006
- reset$9();
4045
+ reset$c();
4007
4046
  break;
4008
4047
  }
4009
4048
  return [2 /*return*/];
@@ -4154,7 +4193,7 @@ function upload(final) {
4154
4193
  compute$6();
4155
4194
  compute$5();
4156
4195
  compute$a();
4157
- compute$7();
4196
+ compute$8();
4158
4197
  last = final === true;
4159
4198
  e = JSON.stringify(envelope(last));
4160
4199
  a = "[".concat(analysis.join(), "]");
@@ -4481,15 +4520,15 @@ function trigger$1(input) {
4481
4520
  }
4482
4521
  switch (source) {
4483
4522
  case 0 /* ExtractSource.Javascript */:
4484
- var variable = value.substring(1, value.length);
4523
+ var variable = value.slice(1);
4485
4524
  variables[key][id] = parse(variable);
4486
4525
  break;
4487
4526
  case 2 /* ExtractSource.Text */:
4488
4527
  selectors[key][id] = value;
4489
4528
  break;
4490
4529
  case 4 /* ExtractSource.Hash */:
4491
- var hash = value.substring(1, value.length);
4492
- hashes[key][id] = hash;
4530
+ var hash_1 = value.slice(1);
4531
+ hashes[key][id] = hash_1;
4493
4532
  break;
4494
4533
  }
4495
4534
  }
@@ -4516,17 +4555,23 @@ function compute$4() {
4516
4555
  }
4517
4556
  var selectorData = selectors[key];
4518
4557
  for (var s in selectorData) {
4558
+ var shouldMask = false;
4519
4559
  var selectorKey = parseInt(s);
4520
- var nodes = document.querySelectorAll(selectorData[selectorKey]);
4560
+ var selector = selectorData[selectorKey];
4561
+ if (selector.startsWith("@" /* Constant.At */)) {
4562
+ shouldMask = true;
4563
+ selector = selector.slice(1);
4564
+ }
4565
+ var nodes = document.querySelectorAll(selector);
4521
4566
  if (nodes) {
4522
- var text = Array.from(nodes).map(function (e) { return e.textContent; });
4523
- update(key, selectorKey, text.join("<SEP>" /* Constant.Seperator */).substring(0, 10000 /* Setting.ExtractLimit */));
4567
+ var text = Array.from(nodes).map(function (e) { return e.textContent; }).join("<SEP>" /* Constant.Seperator */);
4568
+ update(key, selectorKey, (shouldMask ? hash(text).trim() : text).slice(0, 10000 /* Setting.ExtractLimit */));
4524
4569
  }
4525
4570
  }
4526
4571
  var hashData = hashes[key];
4527
4572
  for (var h in hashData) {
4528
4573
  var hashKey = parseInt(h);
4529
- var content = hashText(hashData[hashKey]).trim().substring(0, 10000 /* Setting.ExtractLimit */);
4574
+ var content = hashText(hashData[hashKey]).trim().slice(0, 10000 /* Setting.ExtractLimit */);
4530
4575
  update(key, hashKey, content);
4531
4576
  }
4532
4577
  }
@@ -4570,9 +4615,9 @@ function parse(variable) {
4570
4615
  var conditionStart = part.indexOf("{" /* Constant.ConditionStart */);
4571
4616
  var conditionEnd = part.indexOf("}" /* Constant.ConditionEnd */);
4572
4617
  syntax.push({
4573
- name: arrayStart > 0 ? part.substring(0, arrayStart) : (conditionStart > 0 ? part.substring(0, conditionStart) : part),
4618
+ name: arrayStart > 0 ? part.slice(0, arrayStart) : (conditionStart > 0 ? part.slice(0, conditionStart) : part),
4574
4619
  type: arrayStart > 0 ? 1 /* Type.Array */ : (conditionStart > 0 ? 2 /* Type.Object */ : 3 /* Type.Simple */),
4575
- condition: conditionStart > 0 ? part.substring(conditionStart + 1, conditionEnd) : null
4620
+ condition: conditionStart > 0 ? part.slice(conditionStart + 1, conditionEnd) : null
4576
4621
  });
4577
4622
  }
4578
4623
  return syntax;
@@ -4611,7 +4656,7 @@ function evaluate(variable, base) {
4611
4656
  }
4612
4657
  function str(input) {
4613
4658
  // Automatically trim string to max of Setting.ExtractLimit to avoid fetching long strings
4614
- return input ? JSON.stringify(input).substring(0, 10000 /* Setting.ExtractLimit */) : input;
4659
+ return input ? JSON.stringify(input).slice(0, 10000 /* Setting.ExtractLimit */) : input;
4615
4660
  }
4616
4661
  function match(base, condition) {
4617
4662
  if (condition) {
@@ -5283,7 +5328,7 @@ function measure (method) {
5283
5328
  };
5284
5329
  }
5285
5330
 
5286
- var bindings = [];
5331
+ var bindings = new Map();
5287
5332
  function bind(target, event, listener, capture, passive) {
5288
5333
  if (capture === void 0) { capture = false; }
5289
5334
  if (passive === void 0) { passive = true; }
@@ -5292,7 +5337,10 @@ function bind(target, event, listener, capture, passive) {
5292
5337
  // E.g. Iframe may start off as same-origin but later turn into cross-origin, and the following lines will throw an exception.
5293
5338
  try {
5294
5339
  target[api("addEventListener" /* Constant.AddEventListener */)](event, listener, { capture: capture, passive: passive });
5295
- bindings.push({ event: event, target: target, listener: listener, options: { capture: capture, passive: passive } });
5340
+ if (!has(target)) {
5341
+ bindings.set(target, []);
5342
+ }
5343
+ bindings.get(target).push({ event: event, listener: listener, options: { capture: capture, passive: passive } });
5296
5344
  }
5297
5345
  catch (_a) {
5298
5346
  /* do nothing */
@@ -5300,17 +5348,31 @@ function bind(target, event, listener, capture, passive) {
5300
5348
  }
5301
5349
  function reset$1() {
5302
5350
  // Walk through existing list of bindings and remove them all
5303
- for (var _i = 0, bindings_1 = bindings; _i < bindings_1.length; _i++) {
5304
- var binding = bindings_1[_i];
5351
+ bindings.forEach(function (bindingsPerTarget, target) {
5352
+ resetByTarget(bindingsPerTarget, target);
5353
+ });
5354
+ bindings = new Map();
5355
+ }
5356
+ function unbind(target) {
5357
+ if (!has(target)) {
5358
+ return;
5359
+ }
5360
+ resetByTarget(bindings.get(target), target);
5361
+ }
5362
+ function has(target) {
5363
+ return bindings.has(target);
5364
+ }
5365
+ function resetByTarget(bindingsPerTarget, target) {
5366
+ bindingsPerTarget.forEach(function (binding) {
5305
5367
  // Wrapping inside try / catch to avoid situations where the element may be destroyed before we get a chance to unbind
5306
5368
  try {
5307
- binding.target[api("removeEventListener" /* Constant.RemoveEventListener */)](binding.event, binding.listener, { capture: binding.options.capture, passive: binding.options.passive });
5369
+ target[api("removeEventListener" /* Constant.RemoveEventListener */)](binding.event, binding.listener, { capture: binding.options.capture, passive: binding.options.passive });
5308
5370
  }
5309
5371
  catch (_a) {
5310
5372
  /* do nothing */
5311
5373
  }
5312
- }
5313
- bindings = [];
5374
+ });
5375
+ bindings.delete(target);
5314
5376
  }
5315
5377
 
5316
5378
  var pushState = null;
@@ -5374,7 +5436,7 @@ var status = false;
5374
5436
  function start$6() {
5375
5437
  status = true;
5376
5438
  start$I();
5377
- reset$l();
5439
+ reset$n();
5378
5440
  reset$1();
5379
5441
  reset$2();
5380
5442
  start$7();
@@ -5383,7 +5445,7 @@ function stop$5() {
5383
5445
  stop$6();
5384
5446
  reset$2();
5385
5447
  reset$1();
5386
- reset$l();
5448
+ reset$n();
5387
5449
  stop$F();
5388
5450
  status = false;
5389
5451
  }
@@ -5458,9 +5520,9 @@ var diagnostic = /*#__PURE__*/Object.freeze({
5458
5520
 
5459
5521
  function start$4() {
5460
5522
  schedule$1(discover, 1 /* Priority.High */).then(function () {
5461
- measure(compute$9)();
5523
+ measure(compute$7)();
5462
5524
  measure(compute$6)();
5463
- measure(compute$8)();
5525
+ measure(compute$9)();
5464
5526
  });
5465
5527
  }
5466
5528
  function discover() {
@@ -5471,7 +5533,7 @@ function discover() {
5471
5533
  case 0:
5472
5534
  ts = time();
5473
5535
  timer = { id: id(), cost: 3 /* Metric.LayoutCost */ };
5474
- start$y(timer);
5536
+ start$z(timer);
5475
5537
  return [4 /*yield*/, traverse(document, timer, 0 /* Source.Discover */, ts)];
5476
5538
  case 1:
5477
5539
  _a.sent();
@@ -5479,7 +5541,7 @@ function discover() {
5479
5541
  return [4 /*yield*/, encode$4(5 /* Event.Discover */, timer, ts)];
5480
5542
  case 2:
5481
5543
  _a.sent();
5482
- stop$w(timer);
5544
+ stop$x(timer);
5483
5545
  return [2 /*return*/];
5484
5546
  }
5485
5547
  });
@@ -5490,29 +5552,29 @@ function start$3() {
5490
5552
  start$3.dn = 20 /* FunctionNames.LayoutStart */;
5491
5553
  // The order below is important
5492
5554
  // and is determined by interdependencies of modules
5493
- start$x();
5555
+ start$k();
5494
5556
  start$h();
5495
- start$z();
5557
+ start$i();
5496
5558
  if (config$2.delayDom) {
5497
5559
  // Lazy load layout module as part of page load time performance improvements experiment
5498
5560
  bind(window, 'load', function () {
5499
- start$k();
5561
+ start$j();
5500
5562
  });
5501
5563
  }
5502
5564
  else {
5503
- start$k();
5565
+ start$j();
5504
5566
  }
5505
5567
  start$4();
5506
- start$j();
5507
- start$i();
5568
+ start$m();
5569
+ start$l();
5508
5570
  }
5509
5571
  function stop$3() {
5510
5572
  stop$f();
5511
- stop$x();
5512
- stop$i();
5513
- stop$v();
5514
- stop$h();
5515
5573
  stop$g();
5574
+ stop$h();
5575
+ stop$i();
5576
+ stop$k();
5577
+ stop$j();
5516
5578
  }
5517
5579
 
5518
5580
  var layout = /*#__PURE__*/Object.freeze({