govuk_publishing_components 35.1.1 → 35.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/component_guide/application.js +1 -0
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-core.js +34 -4
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js +20 -2
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/init-ga4.js +5 -0
- data/app/assets/javascripts/govuk_publishing_components/components/intervention.js +69 -0
- data/app/assets/javascripts/govuk_publishing_components/components/step-by-step-nav.js +5 -2
- data/app/assets/javascripts/govuk_publishing_components/lib/cookie-functions.js +1 -0
- 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/_accordion.html.erb +25 -1
- data/app/views/govuk_publishing_components/components/_intervention.html.erb +15 -7
- 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.html.erb +23 -3
- data/app/views/govuk_publishing_components/components/_step_by_step_nav_related.html.erb +24 -4
- data/app/views/govuk_publishing_components/components/docs/intervention.yml +11 -6
- data/lib/govuk_publishing_components/presenters/component_wrapper_helper.rb +35 -12
- data/lib/govuk_publishing_components/presenters/intervention_helper.rb +16 -5
- data/lib/govuk_publishing_components/presenters/step_by_step_nav_helper.rb +0 -16
- data/lib/govuk_publishing_components/version.rb +1 -1
- metadata +5 -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
|