govuk_publishing_components 35.14.0 → 35.15.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (19) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-page-views.js +15 -5
  3. data/app/assets/javascripts/govuk_publishing_components/components/cookie-banner.js +4 -5
  4. data/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-reporter.js +327 -321
  5. data/app/assets/stylesheets/govuk_publishing_components/components/_accordion.scss +6 -0
  6. data/app/assets/stylesheets/govuk_publishing_components/components/_govspeak.scss +6 -0
  7. data/app/assets/stylesheets/govuk_publishing_components/components/_layout-super-navigation-header.scss +1 -1
  8. data/app/views/govuk_publishing_components/components/_attachment.html.erb +2 -1
  9. data/app/views/govuk_publishing_components/components/_cookie_banner.html.erb +30 -2
  10. data/app/views/govuk_publishing_components/components/_devolved_nations.html.erb +15 -1
  11. data/app/views/govuk_publishing_components/components/_layout_super_navigation_header.html.erb +2 -2
  12. data/app/views/govuk_publishing_components/components/docs/cards.yml +2 -2
  13. data/app/views/govuk_publishing_components/components/docs/cookie_banner.yml +5 -0
  14. data/app/views/govuk_publishing_components/components/docs/devolved_nations.yml +16 -0
  15. data/app/views/govuk_publishing_components/components/layout_for_public/_account-layout.html.erb +1 -0
  16. data/config/locales/en.yml +2 -2
  17. data/lib/govuk_publishing_components/presenters/devolved_nations_helper.rb +16 -4
  18. data/lib/govuk_publishing_components/version.rb +1 -1
  19. metadata +3 -3
@@ -21,33 +21,34 @@
21
21
 
22
22
  (function () {
23
23
  'use strict';
24
+
24
25
  /**
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
- */
26
+ * Fit an array of user timing delimited strings into a URL and return both the entries that fit and
27
+ * the remaining entries that didn't fit.
28
+ */
28
29
  function fitUserTimingEntries(utValues, config, url) {
29
30
  // Start with the maximum allowed UT entries per beacon
30
31
  var beaconUtValues = utValues.slice(0, config.maxBeaconUTEntries);
31
32
  var remainingUtValues = utValues.slice(config.maxBeaconUTEntries);
32
33
  // Trim UT entries until they fit within the maximum URL length, ensuring at least one UT entry
33
34
  // is included.
34
- while ((url + "&UT=" + beaconUtValues.join(",")).length > config.maxBeaconUrlLength &&
35
- beaconUtValues.length > 1) {
35
+ while ((url + "&UT=" + beaconUtValues.join(",")).length > config.maxBeaconUrlLength && beaconUtValues.length > 1) {
36
36
  remainingUtValues.unshift(beaconUtValues.pop());
37
37
  }
38
38
  return [beaconUtValues, remainingUtValues];
39
39
  }
40
40
 
41
+ var luxOrigin = "https://lux.speedcurve.com";
41
42
  function fromObject(obj) {
42
43
  var autoMode = getProperty(obj, "auto", true);
43
44
  return {
44
45
  auto: autoMode,
45
- beaconUrl: getProperty(obj, "beaconUrl", "https://lux.speedcurve.com/lux/"),
46
- conversions: getProperty(obj, "conversions", undefined),
47
- customerid: getProperty(obj, "customerid", undefined),
48
- errorBeaconUrl: getProperty(obj, "errorBeaconUrl", "https://lux.speedcurve.com/error/"),
49
- jspagelabel: getProperty(obj, "jspagelabel", undefined),
50
- label: getProperty(obj, "label", undefined),
46
+ beaconUrl: getProperty(obj, "beaconUrl", luxOrigin + "/lux/"),
47
+ conversions: getProperty(obj, "conversions"),
48
+ customerid: getProperty(obj, "customerid"),
49
+ errorBeaconUrl: getProperty(obj, "errorBeaconUrl", luxOrigin + "/error/"),
50
+ jspagelabel: getProperty(obj, "jspagelabel"),
51
+ label: getProperty(obj, "label"),
51
52
  maxBeaconUrlLength: getProperty(obj, "maxBeaconUrlLength", 8190),
52
53
  maxBeaconUTEntries: getProperty(obj, "maxBeaconUTEntries", 20),
53
54
  maxErrors: getProperty(obj, "maxErrors", 5),
@@ -56,10 +57,10 @@
56
57
  newBeaconOnPageShow: getProperty(obj, "newBeaconOnPageShow", false),
57
58
  samplerate: getProperty(obj, "samplerate", 100),
58
59
  sendBeaconOnPageHidden: getProperty(obj, "sendBeaconOnPageHidden", autoMode),
59
- serverTiming: getProperty(obj, "serverTiming", undefined),
60
+ serverTiming: getProperty(obj, "serverTiming"),
60
61
  trackErrors: getProperty(obj, "trackErrors", true),
61
62
  trackHiddenPages: getProperty(obj, "trackHiddenPages", false),
62
- pagegroups: getProperty(obj, "pagegroups", undefined),
63
+ pagegroups: getProperty(obj, "pagegroups"),
63
64
  };
64
65
  }
65
66
  function getProperty(obj, key, defaultValue) {
@@ -99,8 +100,8 @@
99
100
  updatedCustomData = {};
100
101
  }
101
102
  /**
102
- * Convert a set of custom data values to the string format expected by the backend.
103
- */
103
+ * Convert a set of custom data values to the string format expected by the backend.
104
+ */
104
105
  function valuesToString(values) {
105
106
  var strings = [];
106
107
  for (var key in values) {
@@ -119,11 +120,14 @@
119
120
  }
120
121
  var max = Math.max;
121
122
  /**
122
- * Clamp a number so that it is never less than 0
123
- */
123
+ * Clamp a number so that it is never less than 0
124
+ */
124
125
  function clamp(x) {
125
126
  return max(0, x);
126
127
  }
128
+ function sortNumeric(a, b) {
129
+ return a - b;
130
+ }
127
131
 
128
132
  function now() {
129
133
  return Date.now ? Date.now() : +new Date();
@@ -173,7 +177,7 @@
173
177
  startTime: 0,
174
178
  type: navType == 2 ? "back_forward" : navType === 1 ? "reload" : "navigate",
175
179
  };
176
- if (__ENABLE_POLYFILLS) {
180
+ {
177
181
  for (var key in timing) {
178
182
  if (typeof timing[key] === "number" && key !== "navigationStart") {
179
183
  entry[key] = floor(timing[key] - timing.navigationStart);
@@ -183,10 +187,10 @@
183
187
  return entry;
184
188
  }
185
189
  /**
186
- * Simple wrapper around performance.getEntriesByType to provide fallbacks for
187
- * legacy browsers, and work around edge cases where undefined is returned instead
188
- * of an empty PerformanceEntryList.
189
- */
190
+ * Simple wrapper around performance.getEntriesByType to provide fallbacks for
191
+ * legacy browsers, and work around edge cases where undefined is returned instead
192
+ * of an empty PerformanceEntryList.
193
+ */
190
194
  function getEntriesByType(type) {
191
195
  if (typeof performance.getEntriesByType === "function") {
192
196
  var entries = performance.getEntriesByType(type);
@@ -245,7 +249,7 @@
245
249
  PageLabelFromDocumentTitle: 1 << 6,
246
250
  PageLabelFromLabelProp: 1 << 7,
247
251
  PageLabelFromGlobalVariable: 1 << 8,
248
- PageLabelFromPagegroup: 1 << 9,
252
+ PageLabelFromUrlPattern: 1 << 9,
249
253
  PageWasPrerendered: 1 << 10,
250
254
  PageWasBfCacheRestored: 1 << 11,
251
255
  };
@@ -261,8 +265,8 @@
261
265
  }
262
266
 
263
267
  /**
264
- * Get the interaction attribution name for an element
265
- */
268
+ * Get the interaction attribution name for an element
269
+ */
266
270
  function interactionAttributionForElement(el) {
267
271
  // Our first preference is to use the data-sctrack attribute from anywhere in the tree
268
272
  var trackId = getClosestScTrackAttribute(el);
@@ -354,6 +358,7 @@
354
358
  };
355
359
  return Logger;
356
360
  }());
361
+
357
362
  var sessionValue = 0;
358
363
  var sessionEntries = [];
359
364
  var maximumSessionValue = 0;
@@ -363,9 +368,9 @@
363
368
  var latestEntry = sessionEntries[sessionEntries.length - 1];
364
369
  if (sessionEntries.length &&
365
370
  (entry.startTime - latestEntry.startTime >= 1000 ||
366
- entry.startTime - firstEntry.startTime >= 5000)) {
367
- sessionValue = entry.value;
368
- sessionEntries = [entry];
371
+ entry.startTime - firstEntry.startTime >= 5000)) {
372
+ sessionValue = entry.value;
373
+ sessionEntries = [entry];
369
374
  }
370
375
  else {
371
376
  sessionValue += entry.value;
@@ -384,9 +389,9 @@
384
389
  }
385
390
 
386
391
  /**
387
- * This implementation is based on the web-vitals implementation, however it is stripped back to the
388
- * bare minimum required to measure just the INP value and does not store the actual event entries.
389
- */
392
+ * This implementation is based on the web-vitals implementation, however it is stripped back to the
393
+ * bare minimum required to measure just the INP value and does not store the actual event entries.
394
+ */
390
395
  // The maximum number of interactions to store
391
396
  var MAX_INTERACTIONS = 10;
392
397
  // A list of the slowest interactions
@@ -423,9 +428,9 @@
423
428
  return slowestEntries.some(function (e2) { return e1.startTime === e2.startTime && e1.duration === e2.duration; });
424
429
  }
425
430
  /**
426
- * Returns an estimated high percentile INP value based on the total number of interactions on the
427
- * current page.
428
- */
431
+ * Returns an estimated high percentile INP value based on the total number of interactions on the
432
+ * current page.
433
+ */
429
434
  function getHighPercentileINP() {
430
435
  var _a;
431
436
  var index = Math.min(slowestEntries.length - 1, Math.floor(getInteractionCount() / 50));
@@ -440,8 +445,7 @@
440
445
 
441
446
  var ALL_ENTRIES = [];
442
447
  function observe(type, callback, options) {
443
- if (typeof PerformanceObserver === "function" &&
444
- PerformanceObserver.supportedEntryTypes.includes(type)) {
448
+ if (typeof PerformanceObserver === "function" && PerformanceObserver.supportedEntryTypes.includes(type)) {
445
449
  var po = new PerformanceObserver(function (list) {
446
450
  list.getEntries().forEach(function (entry) { return callback(entry); });
447
451
  });
@@ -456,17 +460,14 @@
456
460
  function addEntry(entry) {
457
461
  ALL_ENTRIES.push(entry);
458
462
  }
459
- function clearEntries() {
460
- ALL_ENTRIES.splice(0);
461
- }
462
463
 
463
464
  /**
464
- * A server timing metric that has its value set to the duration field
465
- */
465
+ * A server timing metric that has its value set to the duration field
466
+ */
466
467
  var TYPE_DURATION = "r";
467
468
  /**
468
- * When a description metric has no value, we consider it to be a boolean and set it to this value.
469
- */
469
+ * When a description metric has no value, we consider it to be a boolean and set it to this value.
470
+ */
470
471
  var BOOLEAN_TRUE_VALUE = "true";
471
472
  function getKeyValuePairs(config, serverTiming) {
472
473
  var pairs = {};
@@ -500,7 +501,7 @@
500
501
  if (Array.isArray(patterns)) {
501
502
  for (var i in patterns) {
502
503
  var pattern = patterns[i];
503
- if (patternMatchesUrl(pattern, hostname, pathname)) {
504
+ if (typeof pattern === "string" && patternMatchesUrl(pattern, hostname, pathname)) {
504
505
  if (firstOnly) {
505
506
  return key;
506
507
  }
@@ -542,10 +543,18 @@
542
543
  // -------------------------------------------------------------------------
543
544
  /// End
544
545
  // -------------------------------------------------------------------------
545
- var SCRIPT_VERSION = "309";
546
+ var SCRIPT_VERSION = "311";
546
547
  var logger = new Logger();
547
548
  var globalConfig = fromObject(LUX);
548
549
  logger.logEvent(LogEvent.EvaluationStart, [SCRIPT_VERSION]);
550
+ // Variable aliases that allow the minifier to reduce file size.
551
+ var document = window.document;
552
+ var addEventListener = window.addEventListener;
553
+ var removeEventListener = window.removeEventListener;
554
+ var setTimeout = window.setTimeout;
555
+ var clearTimeout = window.clearTimeout;
556
+ var encodeURIComponent = window.encodeURIComponent;
557
+ var thisScript = document.currentScript || {};
549
558
  // Log JS errors.
550
559
  var nErrors = 0;
551
560
  function errorHandler(e) {
@@ -560,30 +569,30 @@
560
569
  // Sample & limit other errors.
561
570
  // Send the error beacon.
562
571
  new Image().src =
563
- globalConfig.errorBeaconUrl +
564
- "?v=" +
565
- SCRIPT_VERSION +
566
- "&id=" +
567
- getCustomerId() +
568
- "&fn=" +
569
- encodeURIComponent(e.filename) +
570
- "&ln=" +
571
- e.lineno +
572
- "&cn=" +
573
- e.colno +
574
- "&msg=" +
575
- encodeURIComponent(e.message) +
576
- "&l=" +
577
- encodeURIComponent(_getPageLabel()) +
578
- (connectionType() ? "&ct=" + connectionType() : "") +
579
- "&HN=" +
580
- encodeURIComponent(document.location.hostname) +
581
- "&PN=" +
582
- encodeURIComponent(document.location.pathname);
583
- }
584
- }
585
- }
586
- window.addEventListener("error", errorHandler);
572
+ globalConfig.errorBeaconUrl +
573
+ "?v=" +
574
+ SCRIPT_VERSION +
575
+ "&id=" +
576
+ getCustomerId() +
577
+ "&fn=" +
578
+ encodeURIComponent(e.filename) +
579
+ "&ln=" +
580
+ e.lineno +
581
+ "&cn=" +
582
+ e.colno +
583
+ "&msg=" +
584
+ encodeURIComponent(e.message) +
585
+ "&l=" +
586
+ encodeURIComponent(_getPageLabel()) +
587
+ (connectionType() ? "&ct=" + connectionType() : "") +
588
+ "&HN=" +
589
+ encodeURIComponent(document.location.hostname) +
590
+ "&PN=" +
591
+ encodeURIComponent(document.location.pathname);
592
+ }
593
+ }
594
+ }
595
+ addEventListener("error", errorHandler);
587
596
  var logEntry = function (entry) {
588
597
  logger.logEvent(LogEvent.PerformanceEntryReceived, [entry]);
589
598
  };
@@ -611,9 +620,9 @@
611
620
  logEntry(entry);
612
621
  });
613
622
  observe("first-input", function (entry) {
614
- var fid = entry.processingStart - entry.startTime;
615
- if (!gFirstInputDelay || gFirstInputDelay < fid) {
616
- gFirstInputDelay = floor(fid);
623
+ var entryTime = entry.processingStart - entry.startTime;
624
+ if (!gFirstInputDelay || gFirstInputDelay < entryTime) {
625
+ gFirstInputDelay = floor(entryTime);
617
626
  }
618
627
  // Allow first-input events to be considered for INP
619
628
  addEntry$1(entry);
@@ -642,11 +651,24 @@
642
651
  var gMaxMeasureTimeout; // setTimeout timer for sending the beacon after a maximum measurement time
643
652
  var pageRestoreTime; // ms since navigationStart representing when the page was restored from the bfcache
644
653
  /**
645
- * To measure the way a user experienced a metric, we measure metrics relative to the time the user
646
- * started viewing the page. On prerendered pages, this is activationStart. On bfcache restores, this
647
- * is the page restore time. On all other pages this value will be zero.
648
- */
649
- var getZeroTime = function () { return pageRestoreTime || getNavigationEntry().activationStart; };
654
+ * To measure the way a user experienced a metric, we measure metrics relative to the time the user
655
+ * started viewing the page. On prerendered pages, this is activationStart. On bfcache restores, this
656
+ * is the page restore time. On all other pages this value will be zero.
657
+ */
658
+ var getZeroTime = function () {
659
+ var _a;
660
+ return Math.max(pageRestoreTime || 0, getNavigationEntry().activationStart, ((_a = _getMark(START_MARK)) === null || _a === void 0 ? void 0 : _a.startTime) || 0);
661
+ };
662
+ /**
663
+ * Most time-based metrics that LUX reports should be relative to the "zero" marker, rounded down
664
+ * to the nearest unit so as not to report times in the future, and clamped to zero.
665
+ */
666
+ var processTimeMetric = function (value) { return clamp(floor(value - getZeroTime())); };
667
+ /**
668
+ * Some values should only be reported if they are non-zero. The exception to this is when the page
669
+ * was prerendered or restored from BF cache
670
+ */
671
+ var shouldReportValue = function (value) { return value > 0 || pageRestoreTime || wasPrerendered(); };
650
672
  if (_sample()) {
651
673
  logger.logEvent(LogEvent.SessionIsSampled, [globalConfig.samplerate]);
652
674
  }
@@ -688,11 +710,11 @@
688
710
  removeListeners();
689
711
  }
690
712
  function removeListeners() {
691
- window.removeEventListener("pointerup", onPointerUp, ghListenerOptions);
692
- window.removeEventListener("pointercancel", onPointerCancel, ghListenerOptions);
713
+ removeEventListener("pointerup", onPointerUp, ghListenerOptions);
714
+ removeEventListener("pointercancel", onPointerCancel, ghListenerOptions);
693
715
  }
694
- window.addEventListener("pointerup", onPointerUp, ghListenerOptions);
695
- window.addEventListener("pointercancel", onPointerCancel, ghListenerOptions);
716
+ addEventListener("pointerup", onPointerUp, ghListenerOptions);
717
+ addEventListener("pointercancel", onPointerCancel, ghListenerOptions);
696
718
  }
697
719
  // Record FID as the delta between when the event happened and when the
698
720
  // listener was able to execute.
@@ -732,16 +754,16 @@
732
754
  }
733
755
  // Attach event listener to input events.
734
756
  gaEventTypes.forEach(function (eventType) {
735
- window.addEventListener(eventType, onInput, ghListenerOptions);
757
+ addEventListener(eventType, onInput, ghListenerOptions);
736
758
  });
737
759
  ////////////////////// FID END
738
760
  /**
739
- * Returns the time elapsed (in ms) since navigationStart. For SPAs, returns
740
- * the time elapsed since the last LUX.init call.
741
- *
742
- * When `absolute = true` the time is always relative to navigationStart, even
743
- * in SPAs.
744
- */
761
+ * Returns the time elapsed (in ms) since navigationStart. For SPAs, returns
762
+ * the time elapsed since the last LUX.init call.
763
+ *
764
+ * When `absolute = true` the time is always relative to navigationStart, even
765
+ * in SPAs.
766
+ */
745
767
  function _now(absolute) {
746
768
  var sinceNavigationStart = msSinceNavigationStart();
747
769
  var startMark = _getMark(START_MARK);
@@ -766,7 +788,7 @@
766
788
  return performance.mark.apply(performance, args);
767
789
  }
768
790
  // ...Otherwise provide a polyfill
769
- if (__ENABLE_POLYFILLS) {
791
+ {
770
792
  var name_1 = args[0];
771
793
  var detail = ((_a = args[1]) === null || _a === void 0 ? void 0 : _a.detail) || null;
772
794
  var startTime = ((_b = args[1]) === null || _b === void 0 ? void 0 : _b.startTime) || _now();
@@ -829,14 +851,14 @@
829
851
  return performance.measure.apply(performance, args);
830
852
  }
831
853
  // ...Otherwise provide a polyfill
832
- if (__ENABLE_POLYFILLS) {
854
+ {
833
855
  var navEntry = getNavigationEntry();
834
856
  var startTime = typeof startMarkName === "number" ? startMarkName : 0;
835
857
  var endTime = typeof endMarkName === "number" ? endMarkName : _now();
836
858
  var throwError = function (missingMark) {
837
859
  throw new DOMException("Failed to execute 'measure' on 'Performance': The mark '" +
838
- missingMark +
839
- "' does not exist");
860
+ missingMark +
861
+ "' does not exist");
840
862
  };
841
863
  if (typeof startMarkName === "string") {
842
864
  var startMark = _getMark(startMarkName);
@@ -924,7 +946,7 @@
924
946
  var startMark = _getMark(START_MARK);
925
947
  // For user timing values taken in a SPA page load, we need to adjust them
926
948
  // so that they're zeroed against the last LUX.init() call.
927
- var tZero = startMark ? startMark.startTime : 0;
949
+ var tZero = getZeroTime();
928
950
  // marks
929
951
  _getMarks().forEach(function (mark) {
930
952
  var name = mark.name;
@@ -973,12 +995,13 @@
973
995
  // Return a string of Element Timing Metrics formatted for beacon querystring.
974
996
  function elementTimingValues() {
975
997
  var aET = [];
976
- var startMark = _getMark(START_MARK);
977
- var tZero = startMark ? startMark.startTime : getZeroTime();
978
998
  getEntries("element").forEach(function (entry) {
979
999
  if (entry.identifier && entry.startTime) {
980
- logger.logEvent(LogEvent.PerformanceEntryProcessed, [entry]);
981
- aET.push(entry.identifier + "|" + floor(entry.startTime - tZero));
1000
+ var value = processTimeMetric(entry.startTime);
1001
+ if (shouldReportValue(value)) {
1002
+ logger.logEvent(LogEvent.PerformanceEntryProcessed, [entry]);
1003
+ aET.push(entry.identifier + "|" + value);
1004
+ }
982
1005
  }
983
1006
  });
984
1007
  return aET.join(",");
@@ -995,20 +1018,7 @@
995
1018
  var longTaskEntries = getEntries("longtask");
996
1019
  // Add up totals for each "type" of long task
997
1020
  if (longTaskEntries.length) {
998
- // Long Task start times are relative to NavigationStart which is "0".
999
- // But if it is a SPA then the relative start time is gStartMark.
1000
- var startMark = _getMark(START_MARK);
1001
- var tZero_1 = startMark ? startMark.startTime : 0;
1002
- // Do not include Long Tasks that start after the page is done.
1003
- // For full page loads, "done" is loadEventEnd.
1004
- var tEnd_1 = timing.loadEventEnd - timing.navigationStart;
1005
- if (startMark) {
1006
- // For SPA page loads (determined by the presence of a start mark), "done" is gEndMark.
1007
- var endMark = _getMark(END_MARK);
1008
- if (endMark) {
1009
- tEnd_1 = endMark.startTime;
1010
- }
1011
- }
1021
+ var tZero_1 = getZeroTime();
1012
1022
  longTaskEntries.forEach(function (entry) {
1013
1023
  var dur = floor(entry.duration);
1014
1024
  if (entry.startTime < tZero_1) {
@@ -1016,21 +1026,18 @@
1016
1026
  // LUX.init() was called. If so, only include the duration after tZero.
1017
1027
  dur -= tZero_1 - entry.startTime;
1018
1028
  }
1019
- else if (entry.startTime >= tEnd_1) {
1020
- // In a SPA it is possible that a Long Task started after loadEventEnd but before our
1021
- // callback from setTimeout(200) happened. Do not include anything that started after tEnd.
1022
- return;
1023
- }
1024
- logger.logEvent(LogEvent.PerformanceEntryProcessed, [entry]);
1025
- var type = entry.attribution[0].name; // TODO - is there ever more than 1 attribution???
1026
- if (!hCPU[type]) {
1027
- // initialize this category
1028
- hCPU[type] = 0;
1029
- hCPUDetails[type] = "";
1029
+ // Only process entries that we calculated to have a valid duration
1030
+ if (dur > 0) {
1031
+ logger.logEvent(LogEvent.PerformanceEntryProcessed, [entry]);
1032
+ var type = entry.attribution[0].name;
1033
+ if (!hCPU[type]) {
1034
+ hCPU[type] = 0;
1035
+ hCPUDetails[type] = "";
1036
+ }
1037
+ hCPU[type] += dur;
1038
+ // Send back the raw startTime and duration, as well as the adjusted duration.
1039
+ hCPUDetails[type] += "," + floor(entry.startTime) + "|" + dur;
1030
1040
  }
1031
- hCPU[type] += dur;
1032
- // Send back the raw startTime and duration, as well as the adjusted duration.
1033
- hCPUDetails[type] += "," + floor(entry.startTime) + "|" + dur;
1034
1041
  });
1035
1042
  }
1036
1043
  // TODO - Add more types if/when they become available.
@@ -1042,12 +1049,12 @@
1042
1049
  }
1043
1050
  var hStats = cpuStats(hCPUDetails[jsType]);
1044
1051
  var sStats = ",n|" +
1045
- hStats["count"] +
1046
- ",d|" +
1047
- hStats["median"] +
1048
- ",x|" +
1049
- hStats["max"] +
1050
- (0 === hStats["fci"] ? "" : ",i|" + hStats["fci"]); // only add FCI if it is non-zero
1052
+ hStats.count +
1053
+ ",d|" +
1054
+ hStats.median +
1055
+ ",x|" +
1056
+ hStats.max +
1057
+ (typeof hStats.fci === "undefined" ? "" : ",i|" + hStats.fci);
1051
1058
  sCPU += "s|" + hCPU[jsType] + sStats + hCPUDetails[jsType];
1052
1059
  return sCPU;
1053
1060
  }
@@ -1055,11 +1062,11 @@
1055
1062
  function cpuStats(sDetails) {
1056
1063
  // tuples of starttime|duration, eg: ,456|250,789|250,1012|250
1057
1064
  var max = 0;
1058
- var fci = getFcp() || 0; // FCI is beginning of 5 second window of no Long Tasks _after_ first contentful paint
1059
- // If FCP is 0 then that means FCP is not supported.
1060
- // If FCP is not supported then we can NOT calculate a valid FCI.
1061
- // Thus, leave FCI = 0 and exclude it from the beacon above.
1062
- var bFoundFci = 0 === fci ? true : false;
1065
+ // FCI is beginning of 5 second window of no Long Tasks _after_ first contentful paint
1066
+ var fcp = getFcp();
1067
+ var fci = fcp || 0;
1068
+ // If FCP is not supported, we can't calculate a valid FCI.
1069
+ var bFoundFci = typeof fcp === "undefined";
1063
1070
  var aValues = [];
1064
1071
  var aTuples = sDetails.split(",");
1065
1072
  for (var i = 0; i < aTuples.length; i++) {
@@ -1079,7 +1086,10 @@
1079
1086
  }
1080
1087
  else {
1081
1088
  // Less than 5 seconds of inactivity
1082
- fci = start + dur; // FCI is now the end of this Long Task
1089
+ var val = processTimeMetric(start + dur);
1090
+ if (shouldReportValue(val)) {
1091
+ fci = val; // FCI is now the end of this Long Task
1092
+ }
1083
1093
  }
1084
1094
  }
1085
1095
  }
@@ -1102,9 +1112,7 @@
1102
1112
  return 0;
1103
1113
  }
1104
1114
  var half = floor(aValues.length / 2);
1105
- aValues.sort(function (a, b) {
1106
- return a - b;
1107
- });
1115
+ aValues.sort(sortNumeric);
1108
1116
  if (aValues.length % 2) {
1109
1117
  // Return the middle value.
1110
1118
  return aValues[half];
@@ -1119,42 +1127,39 @@
1119
1127
  var sLuxjs = "";
1120
1128
  if (performance.getEntriesByName) {
1121
1129
  // Get the lux script URL (including querystring params).
1122
- var luxScript = getScriptElement("/js/lux.js");
1123
- if (luxScript) {
1124
- var aResources = performance.getEntriesByName(luxScript.src);
1125
- if (aResources && aResources.length) {
1126
- var r = aResources[0];
1127
- // DO NOT USE DURATION!!!!!
1128
- // See https://www.stevesouders.com/blog/2014/11/25/serious-confusion-with-resource-timing/
1129
- var dns = floor(r.domainLookupEnd - r.domainLookupStart);
1130
- var tcp = floor(r.connectEnd - r.connectStart);
1131
- var fb = floor(r.responseStart - r.requestStart);
1132
- var content = floor(r.responseEnd - r.responseStart);
1133
- var networkDuration = dns + tcp + fb + content;
1134
- var parseEval = scriptEndTime - scriptStartTime;
1135
- var transferSize = r.encodedBodySize ? r.encodedBodySize : 0;
1136
- // Instead of a delimiter use a 1-letter abbreviation as a separator.
1137
- sLuxjs =
1138
- "d" +
1139
- dns +
1140
- "t" +
1141
- tcp +
1142
- "f" +
1143
- fb +
1144
- "c" +
1145
- content +
1146
- "n" +
1147
- networkDuration +
1148
- "e" +
1149
- parseEval +
1150
- "r" +
1151
- globalConfig.samplerate + // sample rate
1152
- (typeof transferSize === "number" ? "x" + transferSize : "") +
1153
- (typeof gLuxSnippetStart === "number" ? "l" + gLuxSnippetStart : "") +
1154
- "s" +
1155
- (scriptStartTime - timing.navigationStart) + // when lux.js started getting evaluated relative to navigationStart
1156
- "";
1157
- }
1130
+ var aResources = performance.getEntriesByName(thisScript.src);
1131
+ if (aResources && aResources.length) {
1132
+ var r = aResources[0];
1133
+ // DO NOT USE DURATION!!!!!
1134
+ // See https://www.stevesouders.com/blog/2014/11/25/serious-confusion-with-resource-timing/
1135
+ var dns = floor(r.domainLookupEnd - r.domainLookupStart);
1136
+ var tcp = floor(r.connectEnd - r.connectStart);
1137
+ var fb = floor(r.responseStart - r.requestStart);
1138
+ var content = floor(r.responseEnd - r.responseStart);
1139
+ var networkDuration = dns + tcp + fb + content;
1140
+ var parseEval = scriptEndTime - scriptStartTime;
1141
+ var transferSize = r.encodedBodySize ? r.encodedBodySize : 0;
1142
+ // Instead of a delimiter use a 1-letter abbreviation as a separator.
1143
+ sLuxjs =
1144
+ "d" +
1145
+ dns +
1146
+ "t" +
1147
+ tcp +
1148
+ "f" +
1149
+ fb +
1150
+ "c" +
1151
+ content +
1152
+ "n" +
1153
+ networkDuration +
1154
+ "e" +
1155
+ parseEval +
1156
+ "r" +
1157
+ globalConfig.samplerate + // sample rate
1158
+ (typeof transferSize === "number" ? "x" + transferSize : "") +
1159
+ (typeof gLuxSnippetStart === "number" ? "l" + gLuxSnippetStart : "") +
1160
+ "s" +
1161
+ (scriptStartTime - timing.navigationStart) + // when lux.js started getting evaluated relative to navigationStart
1162
+ "";
1158
1163
  }
1159
1164
  }
1160
1165
  return sLuxjs;
@@ -1185,9 +1190,9 @@
1185
1190
  if (gCustomerDataTimeout) {
1186
1191
  // Cancel the timer for any previous beacons so that if they have not
1187
1192
  // yet been sent we can combine all the data in a new beacon.
1188
- window.clearTimeout(gCustomerDataTimeout);
1193
+ clearTimeout(gCustomerDataTimeout);
1189
1194
  }
1190
- gCustomerDataTimeout = window.setTimeout(_sendCustomerData, 100);
1195
+ gCustomerDataTimeout = setTimeout(_sendCustomerData, 100);
1191
1196
  }
1192
1197
  }
1193
1198
  // _sample()
@@ -1200,9 +1205,9 @@
1200
1205
  return parseInt(nThis) < globalConfig.samplerate;
1201
1206
  }
1202
1207
  /**
1203
- * Re-initialize lux.js to start a new "page". This is typically called within a SPA at the
1204
- * beginning of a page transition, but is also called internally when the BF cache is restored.
1205
- */
1208
+ * Re-initialize lux.js to start a new "page". This is typically called within a SPA at the
1209
+ * beginning of a page transition, but is also called internally when the BF cache is restored.
1210
+ */
1206
1211
  function _init(startTime) {
1207
1212
  // Some customers (incorrectly) call LUX.init on the very first page load of a SPA. This would
1208
1213
  // cause some first-page-only data (like paint metrics) to be lost. To prevent this, we silently
@@ -1232,7 +1237,6 @@
1232
1237
  gbFirstPV = 0;
1233
1238
  gSyncId = createSyncId();
1234
1239
  gUid = refreshUniqueId(gSyncId);
1235
- clearEntries();
1236
1240
  reset$1();
1237
1241
  reset();
1238
1242
  nErrors = 0;
@@ -1353,14 +1357,17 @@
1353
1357
  ns += start; // "navigationStart" for a SPA is the real navigationStart plus the start mark
1354
1358
  var end = floor(endMark.startTime) - start; // delta from start mark
1355
1359
  s =
1356
- ns +
1357
- "fs" +
1358
- 0 + // fetchStart is the same as navigationStart for a SPA
1359
- "ls" +
1360
- end +
1361
- "le" +
1362
- end +
1363
- "";
1360
+ ns +
1361
+ // fetchStart and activationStart are the same as navigationStart for a SPA
1362
+ "as" +
1363
+ 0 +
1364
+ "fs" +
1365
+ 0 +
1366
+ "ls" +
1367
+ end +
1368
+ "le" +
1369
+ end +
1370
+ "";
1364
1371
  }
1365
1372
  else if (performance.timing) {
1366
1373
  // Return the real Nav Timing metrics because this is the "main" page view (not a SPA)
@@ -1368,17 +1375,20 @@
1368
1375
  var startRender = getStartRender();
1369
1376
  var fcp = getFcp();
1370
1377
  var lcp = getLcp();
1371
- var prefixNTValue = function (key, prefix) {
1372
- // activationStart is always absolute. Other values are relative to activationStart.
1373
- var zero = key === "activationStart" ? 0 : getZeroTime();
1378
+ var prefixNTValue = function (key, prefix, ignoreZero) {
1374
1379
  if (typeof navEntry_1[key] === "number") {
1375
- var value = clamp(floor(navEntry_1[key] - zero));
1376
- return prefix + value;
1380
+ var value = navEntry_1[key];
1381
+ // We allow zero values for most navigation timing metrics, but for some metrics we want
1382
+ // to ignore zeroes. The exceptions are that all metrics can be zero if the page was either
1383
+ // prerendered or restored from the BF cache.
1384
+ if (shouldReportValue(value) || !ignoreZero) {
1385
+ return prefix + processTimeMetric(value);
1386
+ }
1377
1387
  }
1378
1388
  return "";
1379
1389
  };
1380
- var loadEventStartStr = prefixNTValue("loadEventStart", "ls");
1381
- var loadEventEndStr = prefixNTValue("loadEventEnd", "le");
1390
+ var loadEventStartStr = prefixNTValue("loadEventStart", "ls", true);
1391
+ var loadEventEndStr = prefixNTValue("loadEventEnd", "le", true);
1382
1392
  if (pageRestoreTime && startMark && endMark) {
1383
1393
  // For bfcache restores, we set the load time to the time it took for the page to be restored.
1384
1394
  var loadTime = floor(endMark.startTime - startMark.startTime);
@@ -1386,43 +1396,44 @@
1386
1396
  loadEventEndStr = "le" + loadTime;
1387
1397
  }
1388
1398
  var redirect = wasRedirected();
1399
+ var isSecure = document.location.protocol === "https:";
1389
1400
  s = [
1390
1401
  ns,
1391
- prefixNTValue("activationStart", "as"),
1392
- redirect ? prefixNTValue("redirectStart", "rs") : "",
1393
- redirect ? prefixNTValue("redirectEnd", "re") : "",
1402
+ "as" + clamp(navEntry_1.activationStart),
1403
+ redirect && !pageRestoreTime ? prefixNTValue("redirectStart", "rs") : "",
1404
+ redirect && !pageRestoreTime ? prefixNTValue("redirectEnd", "re") : "",
1394
1405
  prefixNTValue("fetchStart", "fs"),
1395
1406
  prefixNTValue("domainLookupStart", "ds"),
1396
1407
  prefixNTValue("domainLookupEnd", "de"),
1397
1408
  prefixNTValue("connectStart", "cs"),
1398
- prefixNTValue("secureConnectionStart", "sc"),
1409
+ isSecure ? prefixNTValue("secureConnectionStart", "sc") : "",
1399
1410
  prefixNTValue("connectEnd", "ce"),
1400
1411
  prefixNTValue("requestStart", "qs"),
1401
1412
  prefixNTValue("responseStart", "bs"),
1402
1413
  prefixNTValue("responseEnd", "be"),
1403
- prefixNTValue("domInteractive", "oi"),
1404
- prefixNTValue("domContentLoadedEventStart", "os"),
1405
- prefixNTValue("domContentLoadedEventEnd", "oe"),
1406
- prefixNTValue("domComplete", "oc"),
1414
+ prefixNTValue("domInteractive", "oi", true),
1415
+ prefixNTValue("domContentLoadedEventStart", "os", true),
1416
+ prefixNTValue("domContentLoadedEventEnd", "oe", true),
1417
+ prefixNTValue("domComplete", "oc", true),
1407
1418
  loadEventStartStr,
1408
1419
  loadEventEndStr,
1409
- typeof startRender !== "undefined" ? "sr" + clamp(startRender) : "",
1410
- typeof fcp !== "undefined" ? "fc" + clamp(fcp) : "",
1411
- typeof lcp !== "undefined" ? "lc" + clamp(lcp) : "",
1420
+ typeof startRender !== "undefined" ? "sr" + startRender : "",
1421
+ typeof fcp !== "undefined" ? "fc" + fcp : "",
1422
+ typeof lcp !== "undefined" ? "lc" + lcp : "",
1412
1423
  ].join("");
1413
1424
  }
1414
1425
  else if (endMark) {
1415
1426
  // This is a "main" page view that does NOT support Navigation Timing - strange.
1416
1427
  var end = floor(endMark.startTime);
1417
1428
  s =
1418
- ns +
1419
- "fs" +
1420
- 0 + // fetchStart is the same as navigationStart
1421
- "ls" +
1422
- end +
1423
- "le" +
1424
- end +
1425
- "";
1429
+ ns +
1430
+ "fs" +
1431
+ 0 + // fetchStart is the same as navigationStart
1432
+ "ls" +
1433
+ end +
1434
+ "le" +
1435
+ end +
1436
+ "";
1426
1437
  }
1427
1438
  return s;
1428
1439
  }
@@ -1432,7 +1443,10 @@
1432
1443
  for (var i = 0; i < paintEntries.length; i++) {
1433
1444
  var entry = paintEntries[i];
1434
1445
  if (entry.name === "first-contentful-paint") {
1435
- return floor(entry.startTime - getZeroTime());
1446
+ var value = processTimeMetric(entry.startTime);
1447
+ if (shouldReportValue(value)) {
1448
+ return value;
1449
+ }
1436
1450
  }
1437
1451
  }
1438
1452
  return undefined;
@@ -1442,8 +1456,11 @@
1442
1456
  var lcpEntries = getEntries("largest-contentful-paint");
1443
1457
  if (lcpEntries.length) {
1444
1458
  var lastEntry = lcpEntries[lcpEntries.length - 1];
1445
- logger.logEvent(LogEvent.PerformanceEntryProcessed, [lastEntry]);
1446
- return floor(lastEntry.startTime - getZeroTime());
1459
+ var value = processTimeMetric(lastEntry.startTime);
1460
+ if (shouldReportValue(value)) {
1461
+ logger.logEvent(LogEvent.PerformanceEntryProcessed, [lastEntry]);
1462
+ return value;
1463
+ }
1447
1464
  }
1448
1465
  return undefined;
1449
1466
  }
@@ -1454,12 +1471,17 @@
1454
1471
  if ("PerformancePaintTiming" in self) {
1455
1472
  var paintEntries = getEntriesByType("paint");
1456
1473
  if (paintEntries.length) {
1457
- // If the Paint Timing API is supported, use the value of the first paint event
1458
- var paintValues = paintEntries.map(function (entry) { return entry.startTime; });
1459
- return floor(Math.min.apply(null, paintValues) - getZeroTime());
1474
+ var paintValues = paintEntries.map(function (entry) { return entry.startTime; }).sort(sortNumeric);
1475
+ // Use the earliest valid paint entry as the start render time.
1476
+ for (var i = 0; i < paintValues.length; i++) {
1477
+ var value = processTimeMetric(paintValues[i]);
1478
+ if (shouldReportValue(value)) {
1479
+ return value;
1480
+ }
1481
+ }
1460
1482
  }
1461
1483
  }
1462
- if (performance.timing && timing.msFirstPaint && __ENABLE_POLYFILLS) {
1484
+ if (performance.timing && timing.msFirstPaint && true) {
1463
1485
  // If IE/Edge, use the prefixed `msFirstPaint` property (see http://msdn.microsoft.com/ff974719).
1464
1486
  return floor(timing.msFirstPaint - timing.navigationStart);
1465
1487
  }
@@ -1473,40 +1495,11 @@
1473
1495
  return getHighPercentileINP();
1474
1496
  }
1475
1497
  function getCustomerId() {
1476
- if (typeof LUX.customerid === "undefined") {
1477
- // Extract the id of the lux.js script element.
1478
- var luxScript = getScriptElement("/js/lux.js");
1479
- if (luxScript) {
1480
- LUX.customerid = getQuerystringParam(luxScript.src, "id");
1481
- }
1498
+ if (!LUX.customerid) {
1499
+ LUX.customerid = thisScript.src.match(/id=(\d+)/).pop();
1482
1500
  }
1483
1501
  return LUX.customerid || "";
1484
1502
  }
1485
- // Return the SCRIPT DOM element whose SRC contains the URL snippet.
1486
- // This is used to find the LUX script element.
1487
- function getScriptElement(urlsnippet) {
1488
- var aScripts = document.getElementsByTagName("script");
1489
- for (var i = 0, len = aScripts.length; i < len; i++) {
1490
- var script = aScripts[i];
1491
- if (script.src && -1 !== script.src.indexOf(urlsnippet)) {
1492
- return script;
1493
- }
1494
- }
1495
- return undefined;
1496
- }
1497
- function getQuerystringParam(url, name) {
1498
- var qs = url.split("?")[1];
1499
- var aTuples = qs.split("&");
1500
- for (var i = 0, len = aTuples.length; i < len; i++) {
1501
- var tuple = aTuples[i];
1502
- var aTuple = tuple.split("=");
1503
- var key = aTuple[0];
1504
- if (name === key) {
1505
- return aTuple[1];
1506
- }
1507
- }
1508
- return undefined;
1509
- }
1510
1503
  function avgDomDepth() {
1511
1504
  var aElems = document.getElementsByTagName("*");
1512
1505
  var i = aElems.length;
@@ -1645,14 +1638,14 @@
1645
1638
  }
1646
1639
  function createMaxMeasureTimeout() {
1647
1640
  clearMaxMeasureTimeout();
1648
- gMaxMeasureTimeout = window.setTimeout(function () {
1641
+ gMaxMeasureTimeout = setTimeout(function () {
1649
1642
  gFlags = addFlag(gFlags, Flags.BeaconSentAfterTimeout);
1650
1643
  _sendLux();
1651
1644
  }, globalConfig.maxMeasureTime - _now());
1652
1645
  }
1653
1646
  function clearMaxMeasureTimeout() {
1654
1647
  if (gMaxMeasureTimeout) {
1655
- window.clearTimeout(gMaxMeasureTimeout);
1648
+ clearTimeout(gMaxMeasureTimeout);
1656
1649
  }
1657
1650
  }
1658
1651
  function _getBeaconUrl(customData) {
@@ -1688,7 +1681,7 @@
1688
1681
  !gSyncId ||
1689
1682
  !_sample() || // OUTSIDE the sampled range
1690
1683
  gbLuxSent // LUX data already sent
1691
- ) {
1684
+ ) {
1692
1685
  return;
1693
1686
  }
1694
1687
  logger.logEvent(LogEvent.DataCollectionStart);
@@ -1741,49 +1734,49 @@
1741
1734
  var is = inlineTagSize("script");
1742
1735
  var ic = inlineTagSize("style");
1743
1736
  var metricsQueryString =
1744
- // only send Nav Timing and lux.js metrics on initial pageload (not for SPA page views)
1745
- (gbNavSent ? "" : "&NT=" + getNavTiming()) +
1746
- (gbFirstPV ? "&LJS=" + sLuxjs : "") +
1747
- // Page Stats
1748
- "&PS=ns" +
1749
- numScripts() +
1750
- "bs" +
1751
- blockingScripts() +
1752
- (is > -1 ? "is" + is : "") +
1753
- "ss" +
1754
- numStylesheets() +
1755
- "bc" +
1756
- blockingStylesheets() +
1757
- (ic > -1 ? "ic" + ic : "") +
1758
- "ia" +
1759
- imagesATF().length +
1760
- "it" +
1761
- document.getElementsByTagName("img").length + // total number of images
1762
- "dd" +
1763
- avgDomDepth() +
1764
- "nd" +
1765
- document.getElementsByTagName("*").length + // numdomelements
1766
- "vh" +
1767
- document.documentElement.clientHeight + // see http://www.quirksmode.org/mobile/viewports.html
1768
- "vw" +
1769
- document.documentElement.clientWidth +
1770
- "dh" +
1771
- docHeight(document) +
1772
- "dw" +
1773
- docWidth(document) +
1774
- (docSize() ? "ds" + docSize() : "") + // document HTTP transfer size (bytes)
1775
- (connectionType() ? "ct" + connectionType() + "_" : "") + // delimit with "_" since values can be non-numeric so need a way to extract with regex in VCL
1776
- "er" +
1777
- nErrors +
1778
- "nt" +
1779
- navigationType() +
1780
- (navigator.deviceMemory ? "dm" + Math.round(navigator.deviceMemory) : "") + // device memory (GB)
1781
- (sIx ? "&IX=" + sIx : "") +
1782
- (typeof gFirstInputDelay !== "undefined" ? "&FID=" + gFirstInputDelay : "") +
1783
- (sCPU ? "&CPU=" + sCPU : "") +
1784
- (sET ? "&ET=" + sET : "") + // element timing
1785
- (typeof CLS !== "undefined" ? "&CLS=" + CLS : "") +
1786
- (typeof INP !== "undefined" ? "&INP=" + INP : "");
1737
+ // only send Nav Timing and lux.js metrics on initial pageload (not for SPA page views)
1738
+ (gbNavSent ? "" : "&NT=" + getNavTiming()) +
1739
+ (gbFirstPV ? "&LJS=" + sLuxjs : "") +
1740
+ // Page Stats
1741
+ "&PS=ns" +
1742
+ numScripts() +
1743
+ "bs" +
1744
+ blockingScripts() +
1745
+ (is > -1 ? "is" + is : "") +
1746
+ "ss" +
1747
+ numStylesheets() +
1748
+ "bc" +
1749
+ blockingStylesheets() +
1750
+ (ic > -1 ? "ic" + ic : "") +
1751
+ "ia" +
1752
+ imagesATF().length +
1753
+ "it" +
1754
+ document.getElementsByTagName("img").length + // total number of images
1755
+ "dd" +
1756
+ avgDomDepth() +
1757
+ "nd" +
1758
+ document.getElementsByTagName("*").length + // numdomelements
1759
+ "vh" +
1760
+ document.documentElement.clientHeight + // see http://www.quirksmode.org/mobile/viewports.html
1761
+ "vw" +
1762
+ document.documentElement.clientWidth +
1763
+ "dh" +
1764
+ docHeight(document) +
1765
+ "dw" +
1766
+ docWidth(document) +
1767
+ (docSize() ? "ds" + docSize() : "") + // document HTTP transfer size (bytes)
1768
+ (connectionType() ? "ct" + connectionType() + "_" : "") + // delimit with "_" since values can be non-numeric so need a way to extract with regex in VCL
1769
+ "er" +
1770
+ nErrors +
1771
+ "nt" +
1772
+ navigationType() +
1773
+ (navigator.deviceMemory ? "dm" + Math.round(navigator.deviceMemory) : "") + // device memory (GB)
1774
+ (sIx ? "&IX=" + sIx : "") +
1775
+ (typeof gFirstInputDelay !== "undefined" ? "&FID=" + gFirstInputDelay : "") +
1776
+ (sCPU ? "&CPU=" + sCPU : "") +
1777
+ (sET ? "&ET=" + sET : "") + // element timing
1778
+ (typeof CLS !== "undefined" ? "&CLS=" + CLS : "") +
1779
+ (typeof INP !== "undefined" ? "&INP=" + INP : "");
1787
1780
  // We add the user timing entries last so that we can split them to reduce the URL size if necessary.
1788
1781
  var utValues = userTimingValues();
1789
1782
  var _b = fitUserTimingEntries(utValues, globalConfig, baseUrl + metricsQueryString), beaconUtValues = _b[0], remainingUtValues = _b[1];
@@ -1807,8 +1800,8 @@
1807
1800
  }
1808
1801
  var ixTimerId;
1809
1802
  function _sendIxAfterDelay() {
1810
- window.clearTimeout(ixTimerId);
1811
- ixTimerId = window.setTimeout(_sendIx, 100);
1803
+ clearTimeout(ixTimerId);
1804
+ ixTimerId = setTimeout(_sendIx, 100);
1812
1805
  }
1813
1806
  // Beacon back the IX data separately (need to sync with LUX beacon on the backend).
1814
1807
  function _sendIx() {
@@ -1842,7 +1835,7 @@
1842
1835
  !gSyncId ||
1843
1836
  !_sample() || // OUTSIDE the sampled range
1844
1837
  !gbLuxSent // LUX has NOT been sent yet, so wait to include it there
1845
- ) {
1838
+ ) {
1846
1839
  return;
1847
1840
  }
1848
1841
  var sCustomerData = valuesToString(getUpdatedCustomData());
@@ -1870,6 +1863,19 @@
1870
1863
  }
1871
1864
  }
1872
1865
  function _keyHandler(e) {
1866
+ var keyCode = e.keyCode;
1867
+ /**
1868
+ * Ignore modifier keys
1869
+ *
1870
+ * 16 = Shift
1871
+ * 17 = Control
1872
+ * 18 = Alt
1873
+ * 20 = Caps Lock
1874
+ * 224 = Meta/Command
1875
+ */
1876
+ if (keyCode === 16 || keyCode === 17 || keyCode === 18 || keyCode === 20 || keyCode === 224) {
1877
+ return;
1878
+ }
1873
1879
  _removeIxHandlers();
1874
1880
  if (typeof ghIx["k"] === "undefined") {
1875
1881
  ghIx["k"] = _now();
@@ -1914,10 +1920,10 @@
1914
1920
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1915
1921
  function addListener(type, callback, useCapture) {
1916
1922
  if (useCapture === void 0) { useCapture = false; }
1917
- if (window.addEventListener) {
1918
- window.addEventListener(type, callback, useCapture);
1923
+ if (addEventListener) {
1924
+ addEventListener(type, callback, useCapture);
1919
1925
  }
1920
- else if (window.attachEvent && __ENABLE_POLYFILLS) {
1926
+ else if (window.attachEvent && true) {
1921
1927
  window.attachEvent("on" + type, callback);
1922
1928
  }
1923
1929
  }
@@ -1925,10 +1931,10 @@
1925
1931
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1926
1932
  function removeListener(type, callback, useCapture) {
1927
1933
  if (useCapture === void 0) { useCapture = false; }
1928
- if (window.removeEventListener) {
1929
- window.removeEventListener(type, callback, useCapture);
1934
+ if (removeEventListener) {
1935
+ removeEventListener(type, callback, useCapture);
1930
1936
  }
1931
- else if (window.detachEvent && __ENABLE_POLYFILLS) {
1937
+ else if (window.detachEvent && true) {
1932
1938
  window.detachEvent("on" + type, callback);
1933
1939
  }
1934
1940
  }
@@ -2016,7 +2022,7 @@
2016
2022
  if (typeof LUX.pagegroups !== "undefined") {
2017
2023
  var label = getMatchesFromPatternMap(LUX.pagegroups, location.hostname, location.pathname, true);
2018
2024
  if (label) {
2019
- gFlags = addFlag(gFlags, Flags.PageLabelFromPagegroup);
2025
+ gFlags = addFlag(gFlags, Flags.PageLabelFromUrlPattern);
2020
2026
  return label;
2021
2027
  }
2022
2028
  }
@@ -2057,11 +2063,11 @@
2057
2063
  function _setCookie(name, value, seconds) {
2058
2064
  try {
2059
2065
  document.cookie =
2060
- name +
2061
- "=" +
2062
- escape(value) +
2063
- (seconds ? "; max-age=" + seconds : "") +
2064
- "; path=/; SameSite=Lax";
2066
+ name +
2067
+ "=" +
2068
+ escape(value) +
2069
+ (seconds ? "; max-age=" + seconds : "") +
2070
+ "; path=/; SameSite=Lax";
2065
2071
  }
2066
2072
  catch (e) {
2067
2073
  logger.logEvent(LogEvent.CookieSetError);
@@ -2111,7 +2117,7 @@
2111
2117
  // bfcache. Since we have no "onload" event to hook into after a bfcache restore, we rely on the
2112
2118
  // unload and maxMeasureTime handlers to send the beacon.
2113
2119
  if (globalConfig.newBeaconOnPageShow) {
2114
- window.addEventListener("pageshow", function (event) {
2120
+ addEventListener("pageshow", function (event) {
2115
2121
  if (event.persisted) {
2116
2122
  // Record the timestamp of the bfcache restore
2117
2123
  pageRestoreTime = event.timeStamp;
@@ -2141,9 +2147,9 @@
2141
2147
  // Set the maximum measurement timer
2142
2148
  createMaxMeasureTimeout();
2143
2149
  /**
2144
- * LUX functions and properties must be attached to the existing global object to ensure that
2145
- * changes made to the global object are reflected in the "internal" LUX object, and vice versa.
2146
- */
2150
+ * LUX functions and properties must be attached to the existing global object to ensure that
2151
+ * changes made to the global object are reflected in the "internal" LUX object, and vice versa.
2152
+ */
2147
2153
  var globalLux = globalConfig;
2148
2154
  // Functions
2149
2155
  globalLux.mark = _mark;
@@ -2168,8 +2174,8 @@
2168
2174
  // Public properties
2169
2175
  globalLux.version = SCRIPT_VERSION;
2170
2176
  /**
2171
- * Run a command from the command queue
2172
- */
2177
+ * Run a command from the command queue
2178
+ */
2173
2179
  function _runCommand(_a) {
2174
2180
  var fn = _a[0], args = _a.slice(1);
2175
2181
  if (typeof globalLux[fn] === "function") {