govuk_publishing_components 35.1.1 → 35.2.0
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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-core.js +9 -4
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js +18 -2
- data/app/assets/javascripts/govuk_publishing_components/components/step-by-step-nav.js +5 -2
- data/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-reporter.js +430 -313
- data/app/assets/stylesheets/govuk_publishing_components/components/_layout-super-navigation-header.scss +2 -3
- data/app/controllers/govuk_publishing_components/component_guide_controller.rb +1 -1
- data/app/models/govuk_publishing_components/audit_applications.rb +5 -1
- data/app/models/govuk_publishing_components/audit_comparer.rb +4 -4
- data/app/views/govuk_publishing_components/audit/_applications.html.erb +22 -4
- data/app/views/govuk_publishing_components/components/_layout_super_navigation_header.html.erb +19 -5
- data/app/views/govuk_publishing_components/components/_step_by_step_nav_related.html.erb +24 -4
- data/lib/govuk_publishing_components/presenters/component_wrapper_helper.rb +35 -12
- data/lib/govuk_publishing_components/version.rb +1 -1
- metadata +4 -4
@@ -21,13 +21,23 @@
|
|
21
21
|
|
22
22
|
(function () {
|
23
23
|
'use strict';
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
/**
|
25
|
+
* Fit an array of user timing delimited strings into a URL and return both the entries that fit and
|
26
|
+
* the remaining entries that didn't fit.
|
27
|
+
*/
|
28
|
+
function fitUserTimingEntries(utValues, config, url) {
|
29
|
+
// Start with the maximum allowed UT entries per beacon
|
30
|
+
var beaconUtValues = utValues.slice(0, config.maxBeaconUTEntries);
|
31
|
+
var remainingUtValues = utValues.slice(config.maxBeaconUTEntries);
|
32
|
+
// Trim UT entries until they fit within the maximum URL length, ensuring at least one UT entry
|
33
|
+
// is included.
|
34
|
+
while ((url + "&UT=" + beaconUtValues.join(",")).length > config.maxBeaconUrlLength &&
|
35
|
+
beaconUtValues.length > 1) {
|
36
|
+
remainingUtValues.unshift(beaconUtValues.pop());
|
37
|
+
}
|
38
|
+
return [beaconUtValues, remainingUtValues];
|
27
39
|
}
|
28
40
|
|
29
|
-
var scriptStartTime = now();
|
30
|
-
|
31
41
|
function fromObject(obj) {
|
32
42
|
var autoMode = getProperty(obj, "auto", true);
|
33
43
|
return {
|
@@ -57,60 +67,50 @@
|
|
57
67
|
return defaultValue;
|
58
68
|
}
|
59
69
|
|
60
|
-
var LogEvent = {
|
61
|
-
// Internal events
|
62
|
-
EvaluationStart: 1,
|
63
|
-
EvaluationEnd: 2,
|
64
|
-
InitCalled: 3,
|
65
|
-
MarkCalled: 4,
|
66
|
-
MeasureCalled: 5,
|
67
|
-
AddDataCalled: 6,
|
68
|
-
SendCalled: 7,
|
69
|
-
ForceSampleCalled: 8,
|
70
|
-
DataCollectionStart: 9,
|
71
|
-
UnloadHandlerTriggered: 10,
|
72
|
-
OnloadHandlerTriggered: 11,
|
73
|
-
MarkLoadTimeCalled: 12,
|
74
|
-
// Data collection events
|
75
|
-
SessionIsSampled: 21,
|
76
|
-
SessionIsNotSampled: 22,
|
77
|
-
MainBeaconSent: 23,
|
78
|
-
UserTimingBeaconSent: 24,
|
79
|
-
InteractionBeaconSent: 25,
|
80
|
-
CustomDataBeaconSent: 26,
|
81
|
-
// Metric information
|
82
|
-
NavigationStart: 41,
|
83
|
-
PerformanceEntryReceived: 42,
|
84
|
-
PerformanceEntryProcessed: 43,
|
85
|
-
// Errors
|
86
|
-
PerformanceObserverError: 51,
|
87
|
-
InputEventPermissionError: 52,
|
88
|
-
InnerHtmlAccessError: 53,
|
89
|
-
EventTargetAccessError: 54,
|
90
|
-
CookieReadError: 55,
|
91
|
-
CookieSetError: 56,
|
92
|
-
PageLabelEvaluationError: 57,
|
93
|
-
// Browser support messages
|
94
|
-
NavTimingNotSupported: 71,
|
95
|
-
PaintTimingNotSupported: 72,
|
96
|
-
};
|
97
|
-
var Logger = /** @class */ (function () {
|
98
|
-
function Logger() {
|
99
|
-
this.events = [];
|
100
|
-
}
|
101
|
-
Logger.prototype.logEvent = function (event, args) {
|
102
|
-
if (args === void 0) { args = []; }
|
103
|
-
this.events.push([now(), event, args]);
|
104
|
-
};
|
105
|
-
Logger.prototype.getEvents = function () {
|
106
|
-
return this.events;
|
107
|
-
};
|
108
|
-
return Logger;
|
109
|
-
}());
|
110
|
-
|
111
70
|
var START_MARK = "LUX_start";
|
112
71
|
var END_MARK = "LUX_end";
|
113
72
|
|
73
|
+
var customDataValues = {};
|
74
|
+
var updatedCustomData = {};
|
75
|
+
function addCustomDataValue(name, value) {
|
76
|
+
var typeV = typeof value;
|
77
|
+
if (customDataValues[name] !== value) {
|
78
|
+
// If the value is new or different to the previous value, record it so that later we can send
|
79
|
+
// only the values that have changed.
|
80
|
+
updatedCustomData[name] = value;
|
81
|
+
}
|
82
|
+
if (typeV === "string" || typeV === "number" || typeV === "boolean") {
|
83
|
+
customDataValues[name] = value;
|
84
|
+
}
|
85
|
+
if (typeV === "undefined" || value === null) {
|
86
|
+
delete customDataValues[name];
|
87
|
+
}
|
88
|
+
}
|
89
|
+
function getAllCustomData() {
|
90
|
+
return customDataValues;
|
91
|
+
}
|
92
|
+
function getUpdatedCustomData() {
|
93
|
+
return updatedCustomData;
|
94
|
+
}
|
95
|
+
function clearUpdateCustomData() {
|
96
|
+
updatedCustomData = {};
|
97
|
+
}
|
98
|
+
/**
|
99
|
+
* Convert a set of custom data values to the string format expected by the backend.
|
100
|
+
*/
|
101
|
+
function valuesToString(values) {
|
102
|
+
var strings = [];
|
103
|
+
for (var key in values) {
|
104
|
+
// Convert all values to strings
|
105
|
+
var value = "" + values[key];
|
106
|
+
// Strip out reserved characters (, and | are used as delimiters)
|
107
|
+
key = key.replace(/,/g, "").replace(/\|/g, "");
|
108
|
+
value = value.replace(/,/g, "").replace(/\|/g, "");
|
109
|
+
strings.push(key + "|" + value);
|
110
|
+
}
|
111
|
+
return encodeURIComponent(strings.join(","));
|
112
|
+
}
|
113
|
+
|
114
114
|
var Flags = {
|
115
115
|
InitCalled: 1 << 0,
|
116
116
|
NavTimingNotSupported: 1 << 1,
|
@@ -177,6 +177,85 @@
|
|
177
177
|
return null;
|
178
178
|
}
|
179
179
|
|
180
|
+
function now() {
|
181
|
+
return Date.now ? Date.now() : +new Date();
|
182
|
+
}
|
183
|
+
|
184
|
+
var LogEvent = {
|
185
|
+
// Internal events
|
186
|
+
EvaluationStart: 1,
|
187
|
+
EvaluationEnd: 2,
|
188
|
+
InitCalled: 3,
|
189
|
+
MarkCalled: 4,
|
190
|
+
MeasureCalled: 5,
|
191
|
+
AddDataCalled: 6,
|
192
|
+
SendCalled: 7,
|
193
|
+
ForceSampleCalled: 8,
|
194
|
+
DataCollectionStart: 9,
|
195
|
+
UnloadHandlerTriggered: 10,
|
196
|
+
OnloadHandlerTriggered: 11,
|
197
|
+
MarkLoadTimeCalled: 12,
|
198
|
+
// Data collection events
|
199
|
+
SessionIsSampled: 21,
|
200
|
+
SessionIsNotSampled: 22,
|
201
|
+
MainBeaconSent: 23,
|
202
|
+
UserTimingBeaconSent: 24,
|
203
|
+
InteractionBeaconSent: 25,
|
204
|
+
CustomDataBeaconSent: 26,
|
205
|
+
// Metric information
|
206
|
+
NavigationStart: 41,
|
207
|
+
PerformanceEntryReceived: 42,
|
208
|
+
PerformanceEntryProcessed: 43,
|
209
|
+
// Errors
|
210
|
+
PerformanceObserverError: 51,
|
211
|
+
InputEventPermissionError: 52,
|
212
|
+
InnerHtmlAccessError: 53,
|
213
|
+
EventTargetAccessError: 54,
|
214
|
+
CookieReadError: 55,
|
215
|
+
CookieSetError: 56,
|
216
|
+
PageLabelEvaluationError: 57,
|
217
|
+
// Browser support messages
|
218
|
+
NavTimingNotSupported: 71,
|
219
|
+
PaintTimingNotSupported: 72,
|
220
|
+
};
|
221
|
+
var Logger = /** @class */ (function () {
|
222
|
+
function Logger() {
|
223
|
+
this.events = [];
|
224
|
+
}
|
225
|
+
Logger.prototype.logEvent = function (event, args) {
|
226
|
+
if (args === void 0) { args = []; }
|
227
|
+
this.events.push([now(), event, args]);
|
228
|
+
};
|
229
|
+
Logger.prototype.getEvents = function () {
|
230
|
+
return this.events;
|
231
|
+
};
|
232
|
+
return Logger;
|
233
|
+
}());
|
234
|
+
var sessionValue = 0;
|
235
|
+
var sessionEntries = [];
|
236
|
+
function addEntry$2(entry) {
|
237
|
+
if (!entry.hadRecentInput) {
|
238
|
+
var firstEntry = sessionEntries[0];
|
239
|
+
var latestEntry = sessionEntries[sessionEntries.length - 1];
|
240
|
+
if (sessionEntries.length &&
|
241
|
+
(entry.startTime - latestEntry.startTime >= 1000 ||
|
242
|
+
entry.startTime - firstEntry.startTime >= 5000)) {
|
243
|
+
reset$1();
|
244
|
+
}
|
245
|
+
sessionValue += entry.value;
|
246
|
+
sessionEntries.push(entry);
|
247
|
+
}
|
248
|
+
}
|
249
|
+
function reset$1() {
|
250
|
+
sessionValue = 0;
|
251
|
+
sessionEntries = [];
|
252
|
+
}
|
253
|
+
function getCLS() {
|
254
|
+
return sessionValue;
|
255
|
+
}
|
256
|
+
|
257
|
+
var scriptStartTime = now();
|
258
|
+
|
180
259
|
var _a;
|
181
260
|
// If the various performance APIs aren't available, we export an empty object to
|
182
261
|
// prevent having to make regular typeof checks.
|
@@ -193,6 +272,32 @@
|
|
193
272
|
}
|
194
273
|
return now() - timing.navigationStart;
|
195
274
|
}
|
275
|
+
function navigationType() {
|
276
|
+
if (performance.navigation && typeof performance.navigation.type !== "undefined") {
|
277
|
+
return performance.navigation.type;
|
278
|
+
}
|
279
|
+
return "";
|
280
|
+
}
|
281
|
+
function getNavigationEntry() {
|
282
|
+
var navEntries = getEntriesByType("navigation");
|
283
|
+
if (navEntries.length) {
|
284
|
+
return navEntries[0];
|
285
|
+
}
|
286
|
+
var navType = navigationType();
|
287
|
+
var entry = {
|
288
|
+
activationStart: 0,
|
289
|
+
startTime: 0,
|
290
|
+
type: navType == 2 ? "back_forward" : navType === 1 ? "reload" : "navigate",
|
291
|
+
};
|
292
|
+
if (__ENABLE_POLYFILLS) {
|
293
|
+
for (var key in timing) {
|
294
|
+
if (typeof timing[key] === "number" && key !== "navigationStart") {
|
295
|
+
entry[key] = Math.max(0, timing[key] - timing.navigationStart);
|
296
|
+
}
|
297
|
+
}
|
298
|
+
}
|
299
|
+
return entry;
|
300
|
+
}
|
196
301
|
/**
|
197
302
|
* Simple wrapper around performance.getEntriesByType to provide fallbacks for
|
198
303
|
* legacy browsers, and work around edge cases where undefined is returned instead
|
@@ -208,91 +313,124 @@
|
|
208
313
|
return [];
|
209
314
|
}
|
210
315
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
316
|
+
/**
|
317
|
+
* This implementation is based on the web-vitals implementation, however it is stripped back to the
|
318
|
+
* bare minimum required to measure just the INP value and does not store the actual event entries.
|
319
|
+
*/
|
320
|
+
// The maximum number of interactions to store
|
321
|
+
var MAX_INTERACTIONS = 10;
|
322
|
+
// A list of the slowest interactions
|
323
|
+
var slowestEntries = [];
|
324
|
+
// A map of the slowest interactions by ID
|
325
|
+
var slowestEntriesMap = {};
|
326
|
+
// The total number of interactions recorded on the page
|
327
|
+
var interactionCountEstimate = 0;
|
328
|
+
function reset() {
|
329
|
+
interactionCountEstimate = 0;
|
330
|
+
slowestEntries = [];
|
331
|
+
slowestEntriesMap = {};
|
332
|
+
}
|
333
|
+
function addEntry$1(entry) {
|
334
|
+
if (entry.interactionId || (entry.entryType === "first-input" && !entryExists(entry))) {
|
335
|
+
var duration = entry.duration, startTime = entry.startTime, interactionId = entry.interactionId;
|
336
|
+
var existingEntry = slowestEntriesMap[interactionId];
|
337
|
+
if (existingEntry) {
|
338
|
+
existingEntry.duration = Math.max(duration, existingEntry.duration);
|
229
339
|
}
|
230
340
|
else {
|
231
|
-
|
341
|
+
interactionCountEstimate++;
|
342
|
+
slowestEntriesMap[interactionId] = { duration: duration, interactionId: interactionId, startTime: startTime };
|
343
|
+
slowestEntries.push(slowestEntriesMap[interactionId]);
|
344
|
+
}
|
345
|
+
// Only store the longest <MAX_INTERACTIONS> interactions
|
346
|
+
slowestEntries.sort(function (a, b) { return b.duration - a.duration; });
|
347
|
+
slowestEntries.splice(MAX_INTERACTIONS).forEach(function (entry) {
|
348
|
+
delete slowestEntriesMap[entry.interactionId];
|
349
|
+
});
|
350
|
+
}
|
351
|
+
}
|
352
|
+
function entryExists(e1) {
|
353
|
+
return slowestEntries.some(function (e2) { return e1.startTime === e2.startTime && e1.duration === e2.duration; });
|
354
|
+
}
|
355
|
+
/**
|
356
|
+
* Returns an estimated high percentile INP value based on the total number of interactions on the
|
357
|
+
* current page.
|
358
|
+
*/
|
359
|
+
function getHighPercentileINP() {
|
360
|
+
var _a;
|
361
|
+
var index = Math.min(slowestEntries.length - 1, Math.floor(getInteractionCount() / 50));
|
362
|
+
return (_a = slowestEntries[index]) === null || _a === void 0 ? void 0 : _a.duration;
|
363
|
+
}
|
364
|
+
function getInteractionCount() {
|
365
|
+
if ("interactionCount" in performance) {
|
366
|
+
return performance.interactionCount;
|
367
|
+
}
|
368
|
+
return interactionCountEstimate;
|
369
|
+
}
|
370
|
+
|
371
|
+
/******************************************************************************
|
372
|
+
Copyright (c) Microsoft Corporation.
|
373
|
+
|
374
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
375
|
+
purpose with or without fee is hereby granted.
|
376
|
+
|
377
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
378
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
379
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
380
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
381
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
382
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
383
|
+
PERFORMANCE OF THIS SOFTWARE.
|
384
|
+
***************************************************************************** */
|
385
|
+
|
386
|
+
var __assign = function() {
|
387
|
+
__assign = Object.assign || function __assign(t) {
|
388
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
389
|
+
s = arguments[i];
|
390
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
232
391
|
}
|
233
|
-
return
|
392
|
+
return t;
|
234
393
|
};
|
235
|
-
|
236
|
-
|
237
|
-
* Multile wildcards (*) are supported
|
238
|
-
* @return RegExp
|
239
|
-
*/
|
240
|
-
Matching.createRegexpFromPathname = function (pattern) {
|
241
|
-
var anyDomain = pattern.charAt(0) == "/";
|
242
|
-
pattern = this.escapeStringForRegexp(pattern);
|
243
|
-
var expression = "^" +
|
244
|
-
(anyDomain ? Matching.domainExpression : "") +
|
245
|
-
pattern.replaceAll(Matching.wildcard, ".*?") +
|
246
|
-
"$";
|
247
|
-
return new RegExp(expression, "i");
|
248
|
-
};
|
249
|
-
/**
|
250
|
-
* Matches hostname root (e.g. "/", "somedomain.com/", "www.somedomain.co.nz/")
|
251
|
-
* Trailing slash is mandatory
|
252
|
-
* @return RegExp
|
253
|
-
*/
|
254
|
-
Matching.getRegexpForHostnameRoot = function () {
|
255
|
-
return new RegExp("^" + Matching.domainExpression + "/$", "i");
|
256
|
-
};
|
257
|
-
/**
|
258
|
-
* Matches exact string (no wildcard provided)
|
259
|
-
* @return RegExp
|
260
|
-
*/
|
261
|
-
Matching.getRegexpForExactString = function (string) {
|
262
|
-
var anyDomain = string.charAt(0) == "/";
|
263
|
-
return new RegExp("^" +
|
264
|
-
(anyDomain ? Matching.domainExpression : "") +
|
265
|
-
this.escapeStringForRegexp(string) +
|
266
|
-
"/?$", "i");
|
267
|
-
};
|
268
|
-
/**
|
269
|
-
* Escape special symbols in regexp string
|
270
|
-
* @param string
|
271
|
-
*/
|
272
|
-
Matching.escapeStringForRegexp = function (string) {
|
273
|
-
// we don't escape * because it's our own special symbol!
|
274
|
-
return string.replace(/[-/\\^$+?.()|[\]{}]/g, "\\$&");
|
275
|
-
};
|
276
|
-
Matching.wildcard = "*";
|
277
|
-
Matching.domainExpression = "[a-zA-Z0-9-.]{1,61}[a-zA-Z0-9]\\.[a-zA-Z]{2,}";
|
278
|
-
return Matching;
|
279
|
-
}());
|
394
|
+
return __assign.apply(this, arguments);
|
395
|
+
};
|
280
396
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
}
|
295
|
-
|
397
|
+
var ALL_ENTRIES = [];
|
398
|
+
function observe(type, callback, options) {
|
399
|
+
if (typeof PerformanceObserver === "function" &&
|
400
|
+
PerformanceObserver.supportedEntryTypes.includes(type)) {
|
401
|
+
var po = new PerformanceObserver(function (list) {
|
402
|
+
list.getEntries().forEach(function (entry) { return callback(entry); });
|
403
|
+
});
|
404
|
+
po.observe(__assign({ type: type, buffered: true }, options));
|
405
|
+
return po;
|
406
|
+
}
|
407
|
+
return undefined;
|
408
|
+
}
|
409
|
+
function getEntries(type) {
|
410
|
+
return ALL_ENTRIES.filter(function (entry) { return entry.entryType === type; });
|
411
|
+
}
|
412
|
+
function addEntry(entry) {
|
413
|
+
ALL_ENTRIES.push(entry);
|
414
|
+
}
|
415
|
+
function clearEntries() {
|
416
|
+
ALL_ENTRIES.splice(0);
|
417
|
+
}
|
418
|
+
|
419
|
+
function patternMatchesUrl(pattern, hostname, pathname) {
|
420
|
+
var regex = createRegExpFromPattern(pattern);
|
421
|
+
if (pattern.charAt(0) === "/") {
|
422
|
+
// Rule is a pathname only
|
423
|
+
return regex.test(pathname);
|
424
|
+
}
|
425
|
+
// Rule is a hostname and pathname
|
426
|
+
return regex.test(hostname + pathname);
|
427
|
+
}
|
428
|
+
function createRegExpFromPattern(pattern) {
|
429
|
+
return new RegExp("^" + escapeStringForRegExp(pattern).replaceAll("*", ".*") + "$", "i");
|
430
|
+
}
|
431
|
+
function escapeStringForRegExp(str) {
|
432
|
+
// Note: we don't escape * because it's our own special symbol!
|
433
|
+
return str.replace(/[-/\\^$+?.()|[\]{}]/g, "\\$&");
|
296
434
|
}
|
297
435
|
|
298
436
|
var LUX = window.LUX || {};
|
@@ -306,8 +444,7 @@
|
|
306
444
|
// -------------------------------------------------------------------------
|
307
445
|
/// End
|
308
446
|
// -------------------------------------------------------------------------
|
309
|
-
|
310
|
-
var SCRIPT_VERSION = "305";
|
447
|
+
var SCRIPT_VERSION = "307";
|
311
448
|
var logger = new Logger();
|
312
449
|
var globalConfig = fromObject(LUX);
|
313
450
|
logger.logEvent(LogEvent.EvaluationStart, [SCRIPT_VERSION]);
|
@@ -349,49 +486,53 @@
|
|
349
486
|
}
|
350
487
|
}
|
351
488
|
window.addEventListener("error", errorHandler);
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
//
|
356
|
-
var
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
if (typeof PerformanceLongTaskTiming === "function") {
|
370
|
-
perfObserver.observe({ type: "longtask", buffered: true });
|
371
|
-
}
|
372
|
-
if (typeof LargestContentfulPaint === "function") {
|
373
|
-
perfObserver.observe({ type: "largest-contentful-paint", buffered: true });
|
374
|
-
}
|
375
|
-
if (typeof PerformanceElementTiming === "function") {
|
376
|
-
perfObserver.observe({ type: "element", buffered: true });
|
377
|
-
}
|
378
|
-
if (typeof PerformancePaintTiming === "function") {
|
379
|
-
perfObserver.observe({ type: "paint", buffered: true });
|
489
|
+
var logEntry = function (entry) {
|
490
|
+
logger.logEvent(LogEvent.PerformanceEntryReceived, [entry]);
|
491
|
+
};
|
492
|
+
// Most PerformanceEntry types we log an event for and add it to the global entry store.
|
493
|
+
var processAndLogEntry = function (entry) {
|
494
|
+
addEntry(entry);
|
495
|
+
logEntry(entry);
|
496
|
+
};
|
497
|
+
// Before long tasks were buffered, we added a PerformanceObserver to the lux.js snippet to capture
|
498
|
+
// any long tasks that occurred before the full script was loaded. To deal with this, we process
|
499
|
+
// all of the snippet long tasks, and we check for double-ups in the new PerformanceObserver.
|
500
|
+
var snippetLongTasks = typeof window.LUX_al === "object" ? window.LUX_al : [];
|
501
|
+
snippetLongTasks.forEach(processAndLogEntry);
|
502
|
+
try {
|
503
|
+
observe("longtask", function (entry) {
|
504
|
+
if (ALL_ENTRIES.indexOf(entry) === -1) {
|
505
|
+
processAndLogEntry(entry);
|
380
506
|
}
|
381
|
-
|
382
|
-
|
507
|
+
});
|
508
|
+
observe("largest-contentful-paint", processAndLogEntry);
|
509
|
+
observe("element", processAndLogEntry);
|
510
|
+
observe("paint", processAndLogEntry);
|
511
|
+
observe("layout-shift", function (entry) {
|
512
|
+
addEntry$2(entry);
|
513
|
+
logEntry(entry);
|
514
|
+
});
|
515
|
+
observe("first-input", function (entry) {
|
516
|
+
var fid = entry.processingStart - entry.startTime;
|
517
|
+
if (!gFirstInputDelay || gFirstInputDelay < fid) {
|
518
|
+
gFirstInputDelay = fid;
|
383
519
|
}
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
}
|
520
|
+
// Allow first-input events to be considered for INP
|
521
|
+
addEntry$1(entry);
|
522
|
+
});
|
523
|
+
// TODO: Add { durationThreshold: 40 } once performance.interactionCount is widely supported.
|
524
|
+
// Right now we have to count every event to get the total interaction count so that we can
|
525
|
+
// estimate a high percentile value for INP.
|
526
|
+
observe("event", addEntry$1);
|
527
|
+
}
|
528
|
+
catch (e) {
|
529
|
+
logger.logEvent(LogEvent.PerformanceObserverError, [e]);
|
388
530
|
}
|
389
531
|
// Bitmask of flags for this session & page
|
390
532
|
var gFlags = 0;
|
391
533
|
var gaMarks = [];
|
392
534
|
var gaMeasures = [];
|
393
535
|
var ghIx = {}; // hash for Interaction Metrics (scroll, click, keyboard)
|
394
|
-
var ghData = {}; // hash for data that is specific to the customer (eg, userid, conversion info)
|
395
536
|
var gbLuxSent = 0; // have we sent the LUX data? (avoid sending twice in unload)
|
396
537
|
var gbNavSent = 0; // have we sent the Nav Timing beacon yet? (avoid sending twice for SPA)
|
397
538
|
var gbIxSent = 0; // have we sent the IX data? (avoid sending twice for SPA)
|
@@ -417,7 +558,7 @@
|
|
417
558
|
// FIRST INPUT DELAY (FID)
|
418
559
|
// The basic idea behind FID is to attach various input event listeners and measure the time
|
419
560
|
// between when the event happens and when the handler executes. That is FID.
|
420
|
-
var gFirstInputDelay;
|
561
|
+
var gFirstInputDelay;
|
421
562
|
var gaEventTypes = ["click", "mousedown", "keydown", "touchstart", "pointerdown"]; // NOTE: does NOT include scroll!
|
422
563
|
var ghListenerOptions = { passive: true, capture: true };
|
423
564
|
// Record the FIRST input delay.
|
@@ -587,7 +728,9 @@
|
|
587
728
|
var startTime = typeof startMarkName === "number" ? startMarkName : 0;
|
588
729
|
var endTime = typeof endMarkName === "number" ? endMarkName : _now();
|
589
730
|
var throwError = function (missingMark) {
|
590
|
-
throw new DOMException("Failed to execute 'measure' on 'Performance': The mark '"
|
731
|
+
throw new DOMException("Failed to execute 'measure' on 'Performance': The mark '" +
|
732
|
+
missingMark +
|
733
|
+
"' does not exist");
|
591
734
|
};
|
592
735
|
if (typeof startMarkName === "string") {
|
593
736
|
var startMark = _getMark(startMarkName);
|
@@ -724,60 +867,56 @@
|
|
724
867
|
// Return a string of Element Timing Metrics formatted for beacon querystring.
|
725
868
|
function elementTimingValues() {
|
726
869
|
var aET = [];
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
}
|
870
|
+
var startMark = _getMark(START_MARK);
|
871
|
+
var tZero = startMark ? startMark.startTime : 0;
|
872
|
+
getEntries("element").forEach(function (entry) {
|
873
|
+
if (entry.identifier && entry.startTime) {
|
874
|
+
logger.logEvent(LogEvent.PerformanceEntryProcessed, [entry]);
|
875
|
+
aET.push(entry.identifier + "|" + Math.round(entry.startTime - tZero));
|
734
876
|
}
|
735
|
-
}
|
877
|
+
});
|
736
878
|
return aET.join(",");
|
737
879
|
}
|
738
880
|
// Return a string of CPU times formatted for beacon querystring.
|
739
881
|
function cpuTimes() {
|
740
|
-
if (
|
882
|
+
if (!("PerformanceLongTaskTiming" in self)) {
|
741
883
|
// Do not return any CPU metrics if Long Tasks API is not supported.
|
742
884
|
return "";
|
743
885
|
}
|
744
886
|
var sCPU = "";
|
745
887
|
var hCPU = {};
|
746
888
|
var hCPUDetails = {}; // TODO - Could remove this later after large totals go away.
|
889
|
+
var longTaskEntries = getEntries("longtask");
|
747
890
|
// Add up totals for each "type" of long task
|
748
|
-
if (
|
891
|
+
if (longTaskEntries.length) {
|
749
892
|
// Long Task start times are relative to NavigationStart which is "0".
|
750
893
|
// But if it is a SPA then the relative start time is gStartMark.
|
751
894
|
var startMark = _getMark(START_MARK);
|
752
|
-
var
|
895
|
+
var tZero_1 = startMark ? startMark.startTime : 0;
|
753
896
|
// Do not include Long Tasks that start after the page is done.
|
754
897
|
// For full page loads, "done" is loadEventEnd.
|
755
|
-
var
|
898
|
+
var tEnd_1 = timing.loadEventEnd - timing.navigationStart;
|
756
899
|
if (startMark) {
|
757
900
|
// For SPA page loads (determined by the presence of a start mark), "done" is gEndMark.
|
758
901
|
var endMark = _getMark(END_MARK);
|
759
902
|
if (endMark) {
|
760
|
-
|
903
|
+
tEnd_1 = endMark.startTime;
|
761
904
|
}
|
762
905
|
}
|
763
|
-
|
764
|
-
var
|
765
|
-
if (
|
766
|
-
continue;
|
767
|
-
}
|
768
|
-
var dur = Math.round(p.duration);
|
769
|
-
if (p.startTime < tZero) {
|
906
|
+
longTaskEntries.forEach(function (entry) {
|
907
|
+
var dur = Math.round(entry.duration);
|
908
|
+
if (entry.startTime < tZero_1) {
|
770
909
|
// In a SPA it is possible that we were in the middle of a Long Task when
|
771
910
|
// LUX.init() was called. If so, only include the duration after tZero.
|
772
|
-
dur -=
|
911
|
+
dur -= tZero_1 - entry.startTime;
|
773
912
|
}
|
774
|
-
else if (
|
913
|
+
else if (entry.startTime >= tEnd_1) {
|
775
914
|
// In a SPA it is possible that a Long Task started after loadEventEnd but before our
|
776
915
|
// callback from setTimeout(200) happened. Do not include anything that started after tEnd.
|
777
|
-
|
916
|
+
return;
|
778
917
|
}
|
779
|
-
logger.logEvent(LogEvent.PerformanceEntryProcessed, [
|
780
|
-
var type =
|
918
|
+
logger.logEvent(LogEvent.PerformanceEntryProcessed, [entry]);
|
919
|
+
var type = entry.attribution[0].name; // TODO - is there ever more than 1 attribution???
|
781
920
|
if (!hCPU[type]) {
|
782
921
|
// initialize this category
|
783
922
|
hCPU[type] = 0;
|
@@ -785,8 +924,8 @@
|
|
785
924
|
}
|
786
925
|
hCPU[type] += dur;
|
787
926
|
// Send back the raw startTime and duration, as well as the adjusted duration.
|
788
|
-
hCPUDetails[type] += "," + Math.round(
|
789
|
-
}
|
927
|
+
hCPUDetails[type] += "," + Math.round(entry.startTime) + "|" + dur;
|
928
|
+
});
|
790
929
|
}
|
791
930
|
// TODO - Add more types if/when they become available.
|
792
931
|
var jsType = typeof hCPU["script"] !== "undefined" ? "script" : "unknown"; // spec changed from "script" to "unknown" Nov 2018
|
@@ -803,14 +942,14 @@
|
|
803
942
|
",x|" +
|
804
943
|
hStats["max"] +
|
805
944
|
(0 === hStats["fci"] ? "" : ",i|" + hStats["fci"]); // only add FCI if it is non-zero
|
806
|
-
|
945
|
+
sCPU += "s|" + hCPU[jsType] + sStats + hCPUDetails[jsType];
|
807
946
|
return sCPU;
|
808
947
|
}
|
809
948
|
// Return a hash of "stats" about the CPU details incl. count, max, and median.
|
810
949
|
function cpuStats(sDetails) {
|
811
950
|
// tuples of starttime|duration, eg: ,456|250,789|250,1012|250
|
812
951
|
var max = 0;
|
813
|
-
var fci = getFcp(); // FCI is beginning of 5 second window of no Long Tasks _after_ first contentful paint
|
952
|
+
var fci = getFcp() || 0; // FCI is beginning of 5 second window of no Long Tasks _after_ first contentful paint
|
814
953
|
// If FCP is 0 then that means FCP is not supported.
|
815
954
|
// If FCP is not supported then we can NOT calculate a valid FCI.
|
816
955
|
// Thus, leave FCI = 0 and exclude it from the beacon above.
|
@@ -843,22 +982,13 @@
|
|
843
982
|
var median = arrayMedian(aValues);
|
844
983
|
return { count: count, median: median, max: max, fci: fci };
|
845
984
|
}
|
846
|
-
function
|
847
|
-
if (
|
848
|
-
return
|
985
|
+
function getCLS$1() {
|
986
|
+
if (!("LayoutShift" in self)) {
|
987
|
+
return undefined;
|
849
988
|
}
|
850
|
-
|
851
|
-
for (var i = 0; i < gaPerfEntries.length; i++) {
|
852
|
-
var p = gaPerfEntries[i];
|
853
|
-
if ("layout-shift" !== p.entryType || p.hadRecentInput) {
|
854
|
-
continue;
|
855
|
-
}
|
856
|
-
logger.logEvent(LogEvent.PerformanceEntryProcessed, [p]);
|
857
|
-
DCLS += p.value;
|
858
|
-
}
|
859
|
-
// The DCL column in Redshift is REAL (FLOAT4) which stores a maximum
|
989
|
+
// The DCLS column in Redshift is REAL (FLOAT4) which stores a maximum
|
860
990
|
// of 6 significant digits.
|
861
|
-
return
|
991
|
+
return getCLS().toFixed(6);
|
862
992
|
}
|
863
993
|
// Return the median value from an array of integers.
|
864
994
|
function arrayMedian(aValues) {
|
@@ -935,17 +1065,10 @@
|
|
935
1065
|
}
|
936
1066
|
return aIx.join(",");
|
937
1067
|
}
|
938
|
-
// _addData()
|
939
1068
|
function _addData(name, value) {
|
940
1069
|
logger.logEvent(LogEvent.AddDataCalled, [name, value]);
|
941
|
-
var typeV = typeof value;
|
942
1070
|
if (typeof name === "string") {
|
943
|
-
|
944
|
-
ghData[name] = value;
|
945
|
-
}
|
946
|
-
if (typeV === "undefined" || value === null) {
|
947
|
-
delete ghData[name];
|
948
|
-
}
|
1071
|
+
addCustomDataValue(name, value);
|
949
1072
|
}
|
950
1073
|
if (gbLuxSent) {
|
951
1074
|
// This is special: We want to allow customers to call LUX.addData()
|
@@ -956,7 +1079,7 @@
|
|
956
1079
|
if (gCustomerDataTimeout) {
|
957
1080
|
// Cancel the timer for any previous beacons so that if they have not
|
958
1081
|
// yet been sent we can combine all the data in a new beacon.
|
959
|
-
clearTimeout(gCustomerDataTimeout);
|
1082
|
+
window.clearTimeout(gCustomerDataTimeout);
|
960
1083
|
}
|
961
1084
|
gCustomerDataTimeout = window.setTimeout(_sendCustomerData, 100);
|
962
1085
|
}
|
@@ -970,18 +1093,6 @@
|
|
970
1093
|
var nThis = ("" + gUid).substr(-2); // number for THIS page - from 00 to 99
|
971
1094
|
return parseInt(nThis) < globalConfig.samplerate;
|
972
1095
|
}
|
973
|
-
// Return a string of Customer Data formatted for beacon querystring.
|
974
|
-
function customerDataValues() {
|
975
|
-
var aData = [];
|
976
|
-
for (var key in ghData) {
|
977
|
-
var value = "" + ghData[key]; // convert to string (eg for ints and booleans)
|
978
|
-
// strip delimiters (instead of escaping)
|
979
|
-
key = key.replace(/,/g, "").replace(/\|/g, "");
|
980
|
-
value = value.replace(/,/g, "").replace(/\|/g, "");
|
981
|
-
aData.push(key + "|" + value);
|
982
|
-
}
|
983
|
-
return encodeURIComponent(aData.join(","));
|
984
|
-
}
|
985
1096
|
// _init()
|
986
1097
|
// Use this function in Single Page Apps to reset things.
|
987
1098
|
// This function should ONLY be called within a SPA!
|
@@ -1007,8 +1118,11 @@
|
|
1007
1118
|
gbFirstPV = 0;
|
1008
1119
|
gSyncId = createSyncId();
|
1009
1120
|
gUid = refreshUniqueId(gSyncId);
|
1010
|
-
|
1121
|
+
clearEntries();
|
1122
|
+
reset$1();
|
1123
|
+
reset();
|
1011
1124
|
nErrors = 0;
|
1125
|
+
gFirstInputDelay = undefined;
|
1012
1126
|
// Clear flags then set the flag that init was called (ie, this is a SPA).
|
1013
1127
|
gFlags = 0;
|
1014
1128
|
gFlags = addFlag(gFlags, Flags.InitCalled);
|
@@ -1031,9 +1145,12 @@
|
|
1031
1145
|
var num = 0;
|
1032
1146
|
for (var i = 0, len = aElems.length; i < len; i++) {
|
1033
1147
|
var e = aElems[i];
|
1034
|
-
if (e.src &&
|
1035
|
-
|
1036
|
-
|
1148
|
+
if (e.src &&
|
1149
|
+
!e.async &&
|
1150
|
+
!e.defer &&
|
1151
|
+
0 !== (e.compareDocumentPosition(lastViewportElem) & 4)) {
|
1152
|
+
// If the script has a SRC and async is false and it occurs BEFORE the last viewport element,
|
1153
|
+
// then increment the counter.
|
1037
1154
|
num++;
|
1038
1155
|
}
|
1039
1156
|
}
|
@@ -1158,9 +1275,9 @@
|
|
1158
1275
|
(t.domComplete ? "oc" + (t.domComplete - ns) : "") +
|
1159
1276
|
(t.loadEventStart ? "ls" + (t.loadEventStart - ns) : "") +
|
1160
1277
|
(t.loadEventEnd ? "le" + (t.loadEventEnd - ns) : "") +
|
1161
|
-
(startRender ? "sr" + startRender : "") +
|
1162
|
-
(fcp ? "fc" + fcp : "") +
|
1163
|
-
(lcp ? "lc" + lcp : "") +
|
1278
|
+
(typeof startRender !== "undefined" ? "sr" + startRender : "") +
|
1279
|
+
(typeof fcp !== "undefined" ? "fc" + fcp : "") +
|
1280
|
+
(typeof lcp !== "undefined" ? "lc" + lcp : "") +
|
1164
1281
|
"";
|
1165
1282
|
}
|
1166
1283
|
else if (endMark) {
|
@@ -1178,7 +1295,7 @@
|
|
1178
1295
|
}
|
1179
1296
|
return s;
|
1180
1297
|
}
|
1181
|
-
// Return First Contentful Paint or
|
1298
|
+
// Return First Contentful Paint or undefined if not supported.
|
1182
1299
|
function getFcp() {
|
1183
1300
|
var paintEntries = getEntriesByType("paint");
|
1184
1301
|
for (var i = 0; i < paintEntries.length; i++) {
|
@@ -1187,25 +1304,21 @@
|
|
1187
1304
|
return Math.round(entry.startTime);
|
1188
1305
|
}
|
1189
1306
|
}
|
1190
|
-
return
|
1307
|
+
return undefined;
|
1191
1308
|
}
|
1192
|
-
// Return Largest Contentful Paint or
|
1309
|
+
// Return Largest Contentful Paint or undefined if not supported.
|
1193
1310
|
function getLcp() {
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
logger.logEvent(LogEvent.PerformanceEntryProcessed, [pe]);
|
1200
|
-
return Math.round(pe.startTime);
|
1201
|
-
}
|
1202
|
-
}
|
1311
|
+
var lcpEntries = getEntries("largest-contentful-paint");
|
1312
|
+
if (lcpEntries.length) {
|
1313
|
+
var lastEntry = lcpEntries[lcpEntries.length - 1];
|
1314
|
+
logger.logEvent(LogEvent.PerformanceEntryProcessed, [lastEntry]);
|
1315
|
+
return Math.max(0, Math.round(lastEntry.startTime - getNavigationEntry().activationStart));
|
1203
1316
|
}
|
1204
|
-
return
|
1317
|
+
return undefined;
|
1205
1318
|
}
|
1206
1319
|
// Return best guess at Start Render time (in ms).
|
1207
1320
|
// Mostly works on just Chrome and IE.
|
1208
|
-
// Return
|
1321
|
+
// Return undefined if not supported.
|
1209
1322
|
function getStartRender() {
|
1210
1323
|
if (performance.timing) {
|
1211
1324
|
var paintEntries = getEntriesByType("paint");
|
@@ -1224,20 +1337,23 @@
|
|
1224
1337
|
}
|
1225
1338
|
}
|
1226
1339
|
logger.logEvent(LogEvent.PaintTimingNotSupported);
|
1227
|
-
return
|
1340
|
+
return undefined;
|
1228
1341
|
}
|
1229
|
-
function
|
1230
|
-
if (
|
1231
|
-
|
1232
|
-
return LUX.customerid;
|
1342
|
+
function getINP() {
|
1343
|
+
if (!("PerformanceEventTiming" in self)) {
|
1344
|
+
return undefined;
|
1233
1345
|
}
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1346
|
+
return getHighPercentileINP();
|
1347
|
+
}
|
1348
|
+
function getCustomerId() {
|
1349
|
+
if (typeof LUX.customerid === "undefined") {
|
1350
|
+
// Extract the id of the lux.js script element.
|
1351
|
+
var luxScript = getScriptElement("/js/lux.js");
|
1352
|
+
if (luxScript) {
|
1353
|
+
LUX.customerid = getQuerystringParam(luxScript.src, "id");
|
1354
|
+
}
|
1239
1355
|
}
|
1240
|
-
return "";
|
1356
|
+
return LUX.customerid || "";
|
1241
1357
|
}
|
1242
1358
|
// Return the SCRIPT DOM element whose SRC contains the URL snippet.
|
1243
1359
|
// This is used to find the LUX script element.
|
@@ -1249,7 +1365,7 @@
|
|
1249
1365
|
return script;
|
1250
1366
|
}
|
1251
1367
|
}
|
1252
|
-
return
|
1368
|
+
return undefined;
|
1253
1369
|
}
|
1254
1370
|
function getQuerystringParam(url, name) {
|
1255
1371
|
var qs = url.split("?")[1];
|
@@ -1295,19 +1411,7 @@
|
|
1295
1411
|
}
|
1296
1412
|
// Return the main HTML document transfer size (in bytes).
|
1297
1413
|
function docSize() {
|
1298
|
-
|
1299
|
-
if (aEntries.length && aEntries[0]["encodedBodySize"]) {
|
1300
|
-
return aEntries[0]["encodedBodySize"];
|
1301
|
-
}
|
1302
|
-
return 0; // ERROR - NOT FOUND
|
1303
|
-
}
|
1304
|
-
// Return the navigation type. 0 = normal, 1 = reload, etc.
|
1305
|
-
// Return empty string if not available.
|
1306
|
-
function navigationType() {
|
1307
|
-
if (performance.navigation && typeof performance.navigation.type !== "undefined") {
|
1308
|
-
return performance.navigation.type;
|
1309
|
-
}
|
1310
|
-
return "";
|
1414
|
+
return getNavigationEntry().encodedBodySize || 0;
|
1311
1415
|
}
|
1312
1416
|
// Return the connection type based on Network Information API.
|
1313
1417
|
// Note this API is in flux.
|
@@ -1421,10 +1525,10 @@
|
|
1421
1525
|
}
|
1422
1526
|
function clearMaxMeasureTimeout() {
|
1423
1527
|
if (gMaxMeasureTimeout) {
|
1424
|
-
clearTimeout(gMaxMeasureTimeout);
|
1528
|
+
window.clearTimeout(gMaxMeasureTimeout);
|
1425
1529
|
}
|
1426
1530
|
}
|
1427
|
-
function _getBeaconUrl() {
|
1531
|
+
function _getBeaconUrl(customData) {
|
1428
1532
|
var queryParams = [
|
1429
1533
|
"v=" + SCRIPT_VERSION,
|
1430
1534
|
"id=" + getCustomerId(),
|
@@ -1437,9 +1541,10 @@
|
|
1437
1541
|
if (gFlags) {
|
1438
1542
|
queryParams.push("fl=" + gFlags);
|
1439
1543
|
}
|
1440
|
-
var customerData =
|
1544
|
+
var customerData = valuesToString(customData);
|
1441
1545
|
if (customerData) {
|
1442
1546
|
queryParams.push("CD=" + customerData);
|
1547
|
+
clearUpdateCustomData();
|
1443
1548
|
}
|
1444
1549
|
return globalConfig.beaconUrl + "?" + queryParams.join("&");
|
1445
1550
|
}
|
@@ -1463,22 +1568,28 @@
|
|
1463
1568
|
// with LUX.markLoadTime()
|
1464
1569
|
_markLoadTime();
|
1465
1570
|
}
|
1466
|
-
var
|
1467
|
-
var
|
1571
|
+
var sIx = "";
|
1572
|
+
var INP = getINP();
|
1573
|
+
// It's possible that the interaction beacon has been sent before the main beacon. We don't want
|
1574
|
+
// to send the interaction metrics twice, so we only include them here if the interaction beacon
|
1575
|
+
// has not been sent.
|
1468
1576
|
if (!gbIxSent) {
|
1469
|
-
// It is possible for the IX beacon to be sent BEFORE the "main" window.onload LUX beacon.
|
1470
|
-
// Make sure we do not send the IX data twice.
|
1471
1577
|
sIx = ixValues();
|
1578
|
+
if (sIx === "") {
|
1579
|
+
// If there are no interaction metrics, we
|
1580
|
+
INP = undefined;
|
1581
|
+
}
|
1472
1582
|
}
|
1583
|
+
var sET = elementTimingValues(); // Element Timing data
|
1473
1584
|
var sCPU = cpuTimes();
|
1474
|
-
var
|
1585
|
+
var CLS = getCLS$1();
|
1475
1586
|
var sLuxjs = selfLoading();
|
1476
1587
|
if (document.visibilityState && "visible" !== document.visibilityState) {
|
1477
1588
|
gFlags = addFlag(gFlags, Flags.VisibilityStateNotVisible);
|
1478
1589
|
}
|
1479
1590
|
// We want ALL beacons to have ALL the data used for query filters (geo, pagelabel, browser, & customerdata).
|
1480
1591
|
// So we create a base URL that has all the necessary information:
|
1481
|
-
var baseUrl = _getBeaconUrl();
|
1592
|
+
var baseUrl = _getBeaconUrl(getAllCustomData());
|
1482
1593
|
var is = inlineTagSize("script");
|
1483
1594
|
var ic = inlineTagSize("style");
|
1484
1595
|
var metricsQueryString =
|
@@ -1517,13 +1628,14 @@
|
|
1517
1628
|
"er" +
|
1518
1629
|
nErrors +
|
1519
1630
|
"nt" +
|
1520
|
-
navigationType() +
|
1631
|
+
navigationType() +
|
1521
1632
|
(navigator.deviceMemory ? "dm" + Math.round(navigator.deviceMemory) : "") + // device memory (GB)
|
1522
1633
|
(sIx ? "&IX=" + sIx : "") +
|
1523
1634
|
(typeof gFirstInputDelay !== "undefined" ? "&FID=" + gFirstInputDelay : "") +
|
1524
1635
|
(sCPU ? "&CPU=" + sCPU : "") +
|
1525
1636
|
(sET ? "&ET=" + sET : "") + // element timing
|
1526
|
-
(
|
1637
|
+
(typeof CLS !== "undefined" ? "&CLS=" + CLS : "") +
|
1638
|
+
(typeof INP !== "undefined" ? "&INP=" + INP : "");
|
1527
1639
|
// We add the user timing entries last so that we can split them to reduce the URL size if necessary.
|
1528
1640
|
var utValues = userTimingValues();
|
1529
1641
|
var _b = fitUserTimingEntries(utValues, globalConfig, baseUrl + metricsQueryString), beaconUtValues = _b[0], remainingUtValues = _b[1];
|
@@ -1545,6 +1657,11 @@
|
|
1545
1657
|
_sendBeacon(utBeaconUrl);
|
1546
1658
|
}
|
1547
1659
|
}
|
1660
|
+
var ixTimerId;
|
1661
|
+
function _sendIxAfterDelay() {
|
1662
|
+
window.clearTimeout(ixTimerId);
|
1663
|
+
ixTimerId = window.setTimeout(_sendIx, 100);
|
1664
|
+
}
|
1548
1665
|
// Beacon back the IX data separately (need to sync with LUX beacon on the backend).
|
1549
1666
|
function _sendIx() {
|
1550
1667
|
var customerid = getCustomerId();
|
@@ -1557,11 +1674,13 @@
|
|
1557
1674
|
return;
|
1558
1675
|
}
|
1559
1676
|
var sIx = ixValues(); // Interaction Metrics
|
1677
|
+
var INP = getINP();
|
1560
1678
|
if (sIx) {
|
1561
|
-
var beaconUrl = _getBeaconUrl() +
|
1679
|
+
var beaconUrl = _getBeaconUrl(getUpdatedCustomData()) +
|
1562
1680
|
"&IX=" +
|
1563
1681
|
sIx +
|
1564
|
-
(typeof gFirstInputDelay !== "undefined" ? "&FID=" + gFirstInputDelay : "")
|
1682
|
+
(typeof gFirstInputDelay !== "undefined" ? "&FID=" + gFirstInputDelay : "") +
|
1683
|
+
(typeof INP !== "undefined" ? "&INP=" + INP : "");
|
1565
1684
|
logger.logEvent(LogEvent.InteractionBeaconSent, [beaconUrl]);
|
1566
1685
|
_sendBeacon(beaconUrl);
|
1567
1686
|
gbIxSent = 1;
|
@@ -1578,9 +1697,9 @@
|
|
1578
1697
|
) {
|
1579
1698
|
return;
|
1580
1699
|
}
|
1581
|
-
var sCustomerData =
|
1700
|
+
var sCustomerData = valuesToString(getUpdatedCustomData());
|
1582
1701
|
if (sCustomerData) {
|
1583
|
-
var beaconUrl = _getBeaconUrl();
|
1702
|
+
var beaconUrl = _getBeaconUrl(getUpdatedCustomData());
|
1584
1703
|
logger.logEvent(LogEvent.CustomDataBeaconSent, [beaconUrl]);
|
1585
1704
|
_sendBeacon(beaconUrl);
|
1586
1705
|
}
|
@@ -1596,11 +1715,10 @@
|
|
1596
1715
|
// Most of the time, however, IX happens *after* LUX, so we send a separate IX beacon but
|
1597
1716
|
// only beacon back the first interaction that happens.
|
1598
1717
|
function _scrollHandler() {
|
1599
|
-
//
|
1600
|
-
//
|
1718
|
+
// Note for scroll input we don't remove the handlers or send the IX beacon because we want to
|
1719
|
+
// capture click and key events as well, since these are typically more important than scrolls.
|
1601
1720
|
if (typeof ghIx["s"] === "undefined") {
|
1602
1721
|
ghIx["s"] = Math.round(_now());
|
1603
|
-
// _sendIx(); // wait for key or click to send the IX beacon
|
1604
1722
|
}
|
1605
1723
|
}
|
1606
1724
|
function _keyHandler(e) {
|
@@ -1613,7 +1731,7 @@
|
|
1613
1731
|
ghIx["ki"] = trackId;
|
1614
1732
|
}
|
1615
1733
|
}
|
1616
|
-
|
1734
|
+
_sendIxAfterDelay();
|
1617
1735
|
}
|
1618
1736
|
}
|
1619
1737
|
function _clickHandler(e) {
|
@@ -1641,7 +1759,7 @@
|
|
1641
1759
|
ghIx["ci"] = trackId;
|
1642
1760
|
}
|
1643
1761
|
}
|
1644
|
-
|
1762
|
+
_sendIxAfterDelay();
|
1645
1763
|
}
|
1646
1764
|
}
|
1647
1765
|
// Wrapper to support older browsers (<= IE8)
|
@@ -1706,9 +1824,9 @@
|
|
1706
1824
|
if (inSampleBucket === void 0) { inSampleBucket = false; }
|
1707
1825
|
if (inSampleBucket) {
|
1708
1826
|
// "00" matches all sample rates
|
1709
|
-
return
|
1827
|
+
return Number(new Date()) + "00000";
|
1710
1828
|
}
|
1711
|
-
return
|
1829
|
+
return Number(new Date()) + _padLeft(String(Math.round(100000 * Math.random())), "00000");
|
1712
1830
|
}
|
1713
1831
|
// Unique ID (also known as Session ID)
|
1714
1832
|
// We use this to track all the page views in a single user session.
|
@@ -1749,13 +1867,12 @@
|
|
1749
1867
|
}
|
1750
1868
|
else if (typeof LUX.pagegroups !== "undefined") {
|
1751
1869
|
var pagegroups = LUX.pagegroups;
|
1752
|
-
var url_1 = "".concat(document.location.hostname).concat(document.location.pathname);
|
1753
1870
|
var label_1 = "";
|
1754
1871
|
var _loop_1 = function (pagegroup) {
|
1755
1872
|
var rules = pagegroups[pagegroup];
|
1756
1873
|
if (Array.isArray(rules)) {
|
1757
1874
|
rules.every(function (rule) {
|
1758
|
-
if (
|
1875
|
+
if (patternMatchesUrl(rule, document.location.hostname, document.location.pathname)) {
|
1759
1876
|
label_1 = pagegroup;
|
1760
1877
|
return false; // stop when first match is found
|
1761
1878
|
}
|
@@ -1763,7 +1880,7 @@
|
|
1763
1880
|
});
|
1764
1881
|
}
|
1765
1882
|
// exits loop when first match is found
|
1766
|
-
if (label_1
|
1883
|
+
if (label_1) {
|
1767
1884
|
gFlags = addFlag(gFlags, Flags.PageLabelFromPagegroup);
|
1768
1885
|
return { value: label_1 };
|
1769
1886
|
}
|
@@ -1771,11 +1888,11 @@
|
|
1771
1888
|
for (var pagegroup in pagegroups) {
|
1772
1889
|
var state_1 = _loop_1(pagegroup);
|
1773
1890
|
if (typeof state_1 === "object")
|
1774
|
-
|
1891
|
+
return state_1.value;
|
1775
1892
|
}
|
1776
1893
|
}
|
1777
1894
|
if (typeof LUX.jspagelabel !== "undefined") {
|
1778
|
-
var evaluateJsPageLabel = Function("
|
1895
|
+
var evaluateJsPageLabel = Function('"use strict"; return ' + LUX.jspagelabel);
|
1779
1896
|
try {
|
1780
1897
|
var label = evaluateJsPageLabel();
|
1781
1898
|
if (label) {
|
@@ -1912,7 +2029,6 @@
|
|
1912
2029
|
})();
|
1913
2030
|
window.LUX = LUX;
|
1914
2031
|
scriptEndTime = now();
|
1915
|
-
|
1916
2032
|
// ---------------------------------------------------------------------------
|
1917
2033
|
// More settings
|
1918
2034
|
// ---------------------------------------------------------------------------
|
@@ -1934,3 +2050,4 @@
|
|
1934
2050
|
// End of more settings
|
1935
2051
|
// ---------------------------------------------------------------------------
|
1936
2052
|
})();
|
2053
|
+
//# sourceMappingURL=lux.js.map
|