govuk_publishing_components 35.15.0 → 35.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 999c5822c246101234a2c8d42828e3ee8b17df824b0472c12b55df5c2d81c4be
4
- data.tar.gz: e6d08b1e863e2ded1152342176e3e7c506f3a89baf06a1c3b2b45c7c73c46ce0
3
+ metadata.gz: e84a39ca858aeb5f82b99db7e36787fcb9de0789d216a01ae705edc8b6412e50
4
+ data.tar.gz: cd621c972ba4b393cd8ca2921a43e45101dcdd1330c5d1dc80eee74b11ac1556
5
5
  SHA512:
6
- metadata.gz: 6fe723d3ea44de844e2228dbbbcfa815148df3b96b94edb58acba736815ab6f92142bf5f3853d0da0d2bca8f730f765414ea7d1c05db738d18c830bfadc88235
7
- data.tar.gz: c06d8fbd16d112658797943def5f8b817f5c2c7e0424381cf16e8fb5c920d47a4ed8e88411be7509793da277f0f2d2f609765b6eb37d49550352b19be310d10b
6
+ metadata.gz: ac457ab2307e9a0c5e38b494b54268c34113521a93e25d1d0bc99378b075b8ae8a9a3ba4477a6dc7249fc58e1d42be51600f3746019109eff8b31460d3ae8a6d
7
+ data.tar.gz: 8369bcf1d142762cd85e4c5e9a483560b1e904071dd73e500407c8abfffa692cc7f60745debae002861850a08a170a1fbc90c5b0ae7f72abe972e5ba089de898
@@ -205,6 +205,10 @@ window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {};
205
205
  }
206
206
  },
207
207
 
208
+ getPathname: function () {
209
+ return window.location.pathname
210
+ },
211
+
208
212
  getProtocol: function () {
209
213
  return window.location.protocol
210
214
  },
@@ -252,6 +256,13 @@ window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {};
252
256
 
253
257
  applyRedactionIfRequired: function (PIIRemover, element, data) {
254
258
  return element.closest('[data-ga4-do-not-redact]') ? data : PIIRemover.stripPIIWithOverride(data, true, true)
259
+ },
260
+
261
+ appendPathToAnchorLinks: function (url) {
262
+ if (!this.stringStartsWith(url, '#') || this.getPathname() === '/') {
263
+ return url
264
+ }
265
+ return this.getPathname() + url
255
266
  }
256
267
  },
257
268
 
@@ -74,7 +74,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
74
74
  if (aTag) {
75
75
  var href = aTag.getAttribute('href')
76
76
  if (href) {
77
- schema.event_data.url = href
77
+ schema.event_data.url = window.GOVUK.analyticsGa4.core.trackFunctions.appendPathToAnchorLinks(href)
78
78
  }
79
79
  }
80
80
  }
@@ -62,13 +62,13 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
62
62
 
63
63
  Ga4LinkTracker.prototype.trackClick = function (event) {
64
64
  var element = event.target
65
-
65
+ var trackFunctions = window.GOVUK.analyticsGa4.core.trackFunctions
66
66
  // don't track this link if it's already being tracked by the ecommerce tracker
67
67
  if (element.closest('[data-ga4-ecommerce-path]')) {
68
68
  return
69
69
  }
70
70
 
71
- var target = window.GOVUK.analyticsGa4.core.trackFunctions.findTrackingAttributes(event.target, this.trackingTrigger)
71
+ var target = trackFunctions.findTrackingAttributes(event.target, this.trackingTrigger)
72
72
  if (target) {
73
73
  try {
74
74
  var data = target.getAttribute(this.trackingTrigger)
@@ -80,17 +80,19 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
80
80
  }
81
81
 
82
82
  var text = data.text || event.target.textContent
83
- data.text = window.GOVUK.analyticsGa4.core.trackFunctions.removeLinesAndExtraSpaces(text)
84
- data.text = window.GOVUK.analyticsGa4.core.trackFunctions.applyRedactionIfRequired(this.PIIRemover, element, data.text)
83
+ data.text = trackFunctions.removeLinesAndExtraSpaces(text)
84
+ data.text = trackFunctions.applyRedactionIfRequired(this.PIIRemover, element, data.text)
85
85
  if (!data.text && (element.querySelector('img') || element.querySelector('svg') || element.tagName === 'IMG' || element.closest('svg'))) {
86
86
  data.text = 'image'
87
87
  }
88
88
  var url = data.url || this.findLink(event.target).getAttribute('href')
89
- data.url = window.GOVUK.analyticsGa4.core.trackFunctions.applyRedactionIfRequired(this.PIIRemover, element, window.GOVUK.analyticsGa4.core.trackFunctions.removeCrossDomainParams(url))
90
- data.link_domain = window.GOVUK.analyticsGa4.core.trackFunctions.populateLinkDomain(data.url)
91
- data.link_path_parts = window.GOVUK.analyticsGa4.core.trackFunctions.populateLinkPathParts(data.url)
92
- data.method = window.GOVUK.analyticsGa4.core.trackFunctions.getClickType(event)
93
- data.external = window.GOVUK.analyticsGa4.core.trackFunctions.isExternalLink(data.url) ? 'true' : 'false'
89
+ data.url = trackFunctions.removeCrossDomainParams(url)
90
+ data.url = trackFunctions.applyRedactionIfRequired(this.PIIRemover, element, data.url)
91
+ data.url = trackFunctions.appendPathToAnchorLinks(data.url)
92
+ data.link_domain = trackFunctions.populateLinkDomain(data.url)
93
+ data.link_path_parts = trackFunctions.populateLinkPathParts(data.url)
94
+ data.method = trackFunctions.getClickType(event)
95
+ data.external = trackFunctions.isExternalLink(data.url) ? 'true' : 'false'
94
96
  data.index = this.setIndex(data.index, event.target)
95
97
 
96
98
  if (data.type === 'smart answer' && data.action === 'change response') {
@@ -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
  }
@@ -537,15 +538,27 @@
537
538
  // -------------------------------------------------------------------------
538
539
  // Settings
539
540
  // -------------------------------------------------------------------------
541
+ // This ID usually appended to the end of the lux.js as a query string when
542
+ // using the SpeedCurve hosted version - but we have to include it here as
543
+ // this is self hosted.
544
+ LUX.customerid = 47044334;
540
545
  // Set the sample rate to 1% to avoid all events being sent.
541
546
  LUX.samplerate = 1;
542
547
  // -------------------------------------------------------------------------
543
548
  /// End
544
549
  // -------------------------------------------------------------------------
545
- var SCRIPT_VERSION = "309";
550
+ var SCRIPT_VERSION = "311";
546
551
  var logger = new Logger();
547
552
  var globalConfig = fromObject(LUX);
548
553
  logger.logEvent(LogEvent.EvaluationStart, [SCRIPT_VERSION]);
554
+ // Variable aliases that allow the minifier to reduce file size.
555
+ var document = window.document;
556
+ var addEventListener = window.addEventListener;
557
+ var removeEventListener = window.removeEventListener;
558
+ var setTimeout = window.setTimeout;
559
+ var clearTimeout = window.clearTimeout;
560
+ var encodeURIComponent = window.encodeURIComponent;
561
+ var thisScript = document.currentScript || {};
549
562
  // Log JS errors.
550
563
  var nErrors = 0;
551
564
  function errorHandler(e) {
@@ -560,30 +573,30 @@
560
573
  // Sample & limit other errors.
561
574
  // Send the error beacon.
562
575
  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);
576
+ globalConfig.errorBeaconUrl +
577
+ "?v=" +
578
+ SCRIPT_VERSION +
579
+ "&id=" +
580
+ getCustomerId() +
581
+ "&fn=" +
582
+ encodeURIComponent(e.filename) +
583
+ "&ln=" +
584
+ e.lineno +
585
+ "&cn=" +
586
+ e.colno +
587
+ "&msg=" +
588
+ encodeURIComponent(e.message) +
589
+ "&l=" +
590
+ encodeURIComponent(_getPageLabel()) +
591
+ (connectionType() ? "&ct=" + connectionType() : "") +
592
+ "&HN=" +
593
+ encodeURIComponent(document.location.hostname) +
594
+ "&PN=" +
595
+ encodeURIComponent(document.location.pathname);
596
+ }
597
+ }
598
+ }
599
+ addEventListener("error", errorHandler);
587
600
  var logEntry = function (entry) {
588
601
  logger.logEvent(LogEvent.PerformanceEntryReceived, [entry]);
589
602
  };
@@ -611,9 +624,9 @@
611
624
  logEntry(entry);
612
625
  });
613
626
  observe("first-input", function (entry) {
614
- var fid = entry.processingStart - entry.startTime;
615
- if (!gFirstInputDelay || gFirstInputDelay < fid) {
616
- gFirstInputDelay = floor(fid);
627
+ var entryTime = entry.processingStart - entry.startTime;
628
+ if (!gFirstInputDelay || gFirstInputDelay < entryTime) {
629
+ gFirstInputDelay = floor(entryTime);
617
630
  }
618
631
  // Allow first-input events to be considered for INP
619
632
  addEntry$1(entry);
@@ -642,11 +655,24 @@
642
655
  var gMaxMeasureTimeout; // setTimeout timer for sending the beacon after a maximum measurement time
643
656
  var pageRestoreTime; // ms since navigationStart representing when the page was restored from the bfcache
644
657
  /**
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; };
658
+ * To measure the way a user experienced a metric, we measure metrics relative to the time the user
659
+ * started viewing the page. On prerendered pages, this is activationStart. On bfcache restores, this
660
+ * is the page restore time. On all other pages this value will be zero.
661
+ */
662
+ var getZeroTime = function () {
663
+ var _a;
664
+ return Math.max(pageRestoreTime || 0, getNavigationEntry().activationStart, ((_a = _getMark(START_MARK)) === null || _a === void 0 ? void 0 : _a.startTime) || 0);
665
+ };
666
+ /**
667
+ * Most time-based metrics that LUX reports should be relative to the "zero" marker, rounded down
668
+ * to the nearest unit so as not to report times in the future, and clamped to zero.
669
+ */
670
+ var processTimeMetric = function (value) { return clamp(floor(value - getZeroTime())); };
671
+ /**
672
+ * Some values should only be reported if they are non-zero. The exception to this is when the page
673
+ * was prerendered or restored from BF cache
674
+ */
675
+ var shouldReportValue = function (value) { return value > 0 || pageRestoreTime || wasPrerendered(); };
650
676
  if (_sample()) {
651
677
  logger.logEvent(LogEvent.SessionIsSampled, [globalConfig.samplerate]);
652
678
  }
@@ -688,11 +714,11 @@
688
714
  removeListeners();
689
715
  }
690
716
  function removeListeners() {
691
- window.removeEventListener("pointerup", onPointerUp, ghListenerOptions);
692
- window.removeEventListener("pointercancel", onPointerCancel, ghListenerOptions);
717
+ removeEventListener("pointerup", onPointerUp, ghListenerOptions);
718
+ removeEventListener("pointercancel", onPointerCancel, ghListenerOptions);
693
719
  }
694
- window.addEventListener("pointerup", onPointerUp, ghListenerOptions);
695
- window.addEventListener("pointercancel", onPointerCancel, ghListenerOptions);
720
+ addEventListener("pointerup", onPointerUp, ghListenerOptions);
721
+ addEventListener("pointercancel", onPointerCancel, ghListenerOptions);
696
722
  }
697
723
  // Record FID as the delta between when the event happened and when the
698
724
  // listener was able to execute.
@@ -732,16 +758,16 @@
732
758
  }
733
759
  // Attach event listener to input events.
734
760
  gaEventTypes.forEach(function (eventType) {
735
- window.addEventListener(eventType, onInput, ghListenerOptions);
761
+ addEventListener(eventType, onInput, ghListenerOptions);
736
762
  });
737
763
  ////////////////////// FID END
738
764
  /**
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
- */
765
+ * Returns the time elapsed (in ms) since navigationStart. For SPAs, returns
766
+ * the time elapsed since the last LUX.init call.
767
+ *
768
+ * When `absolute = true` the time is always relative to navigationStart, even
769
+ * in SPAs.
770
+ */
745
771
  function _now(absolute) {
746
772
  var sinceNavigationStart = msSinceNavigationStart();
747
773
  var startMark = _getMark(START_MARK);
@@ -766,7 +792,7 @@
766
792
  return performance.mark.apply(performance, args);
767
793
  }
768
794
  // ...Otherwise provide a polyfill
769
- if (__ENABLE_POLYFILLS) {
795
+ {
770
796
  var name_1 = args[0];
771
797
  var detail = ((_a = args[1]) === null || _a === void 0 ? void 0 : _a.detail) || null;
772
798
  var startTime = ((_b = args[1]) === null || _b === void 0 ? void 0 : _b.startTime) || _now();
@@ -829,14 +855,14 @@
829
855
  return performance.measure.apply(performance, args);
830
856
  }
831
857
  // ...Otherwise provide a polyfill
832
- if (__ENABLE_POLYFILLS) {
858
+ {
833
859
  var navEntry = getNavigationEntry();
834
860
  var startTime = typeof startMarkName === "number" ? startMarkName : 0;
835
861
  var endTime = typeof endMarkName === "number" ? endMarkName : _now();
836
862
  var throwError = function (missingMark) {
837
863
  throw new DOMException("Failed to execute 'measure' on 'Performance': The mark '" +
838
- missingMark +
839
- "' does not exist");
864
+ missingMark +
865
+ "' does not exist");
840
866
  };
841
867
  if (typeof startMarkName === "string") {
842
868
  var startMark = _getMark(startMarkName);
@@ -924,7 +950,7 @@
924
950
  var startMark = _getMark(START_MARK);
925
951
  // For user timing values taken in a SPA page load, we need to adjust them
926
952
  // so that they're zeroed against the last LUX.init() call.
927
- var tZero = startMark ? startMark.startTime : 0;
953
+ var tZero = getZeroTime();
928
954
  // marks
929
955
  _getMarks().forEach(function (mark) {
930
956
  var name = mark.name;
@@ -973,12 +999,13 @@
973
999
  // Return a string of Element Timing Metrics formatted for beacon querystring.
974
1000
  function elementTimingValues() {
975
1001
  var aET = [];
976
- var startMark = _getMark(START_MARK);
977
- var tZero = startMark ? startMark.startTime : getZeroTime();
978
1002
  getEntries("element").forEach(function (entry) {
979
1003
  if (entry.identifier && entry.startTime) {
980
- logger.logEvent(LogEvent.PerformanceEntryProcessed, [entry]);
981
- aET.push(entry.identifier + "|" + floor(entry.startTime - tZero));
1004
+ var value = processTimeMetric(entry.startTime);
1005
+ if (shouldReportValue(value)) {
1006
+ logger.logEvent(LogEvent.PerformanceEntryProcessed, [entry]);
1007
+ aET.push(entry.identifier + "|" + value);
1008
+ }
982
1009
  }
983
1010
  });
984
1011
  return aET.join(",");
@@ -995,20 +1022,7 @@
995
1022
  var longTaskEntries = getEntries("longtask");
996
1023
  // Add up totals for each "type" of long task
997
1024
  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
- }
1025
+ var tZero_1 = getZeroTime();
1012
1026
  longTaskEntries.forEach(function (entry) {
1013
1027
  var dur = floor(entry.duration);
1014
1028
  if (entry.startTime < tZero_1) {
@@ -1016,21 +1030,18 @@
1016
1030
  // LUX.init() was called. If so, only include the duration after tZero.
1017
1031
  dur -= tZero_1 - entry.startTime;
1018
1032
  }
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] = "";
1033
+ // Only process entries that we calculated to have a valid duration
1034
+ if (dur > 0) {
1035
+ logger.logEvent(LogEvent.PerformanceEntryProcessed, [entry]);
1036
+ var type = entry.attribution[0].name;
1037
+ if (!hCPU[type]) {
1038
+ hCPU[type] = 0;
1039
+ hCPUDetails[type] = "";
1040
+ }
1041
+ hCPU[type] += dur;
1042
+ // Send back the raw startTime and duration, as well as the adjusted duration.
1043
+ hCPUDetails[type] += "," + floor(entry.startTime) + "|" + dur;
1030
1044
  }
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
1045
  });
1035
1046
  }
1036
1047
  // TODO - Add more types if/when they become available.
@@ -1042,12 +1053,12 @@
1042
1053
  }
1043
1054
  var hStats = cpuStats(hCPUDetails[jsType]);
1044
1055
  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
1056
+ hStats.count +
1057
+ ",d|" +
1058
+ hStats.median +
1059
+ ",x|" +
1060
+ hStats.max +
1061
+ (typeof hStats.fci === "undefined" ? "" : ",i|" + hStats.fci);
1051
1062
  sCPU += "s|" + hCPU[jsType] + sStats + hCPUDetails[jsType];
1052
1063
  return sCPU;
1053
1064
  }
@@ -1055,11 +1066,11 @@
1055
1066
  function cpuStats(sDetails) {
1056
1067
  // tuples of starttime|duration, eg: ,456|250,789|250,1012|250
1057
1068
  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;
1069
+ // FCI is beginning of 5 second window of no Long Tasks _after_ first contentful paint
1070
+ var fcp = getFcp();
1071
+ var fci = fcp || 0;
1072
+ // If FCP is not supported, we can't calculate a valid FCI.
1073
+ var bFoundFci = typeof fcp === "undefined";
1063
1074
  var aValues = [];
1064
1075
  var aTuples = sDetails.split(",");
1065
1076
  for (var i = 0; i < aTuples.length; i++) {
@@ -1079,7 +1090,10 @@
1079
1090
  }
1080
1091
  else {
1081
1092
  // Less than 5 seconds of inactivity
1082
- fci = start + dur; // FCI is now the end of this Long Task
1093
+ var val = processTimeMetric(start + dur);
1094
+ if (shouldReportValue(val)) {
1095
+ fci = val; // FCI is now the end of this Long Task
1096
+ }
1083
1097
  }
1084
1098
  }
1085
1099
  }
@@ -1102,9 +1116,7 @@
1102
1116
  return 0;
1103
1117
  }
1104
1118
  var half = floor(aValues.length / 2);
1105
- aValues.sort(function (a, b) {
1106
- return a - b;
1107
- });
1119
+ aValues.sort(sortNumeric);
1108
1120
  if (aValues.length % 2) {
1109
1121
  // Return the middle value.
1110
1122
  return aValues[half];
@@ -1119,42 +1131,39 @@
1119
1131
  var sLuxjs = "";
1120
1132
  if (performance.getEntriesByName) {
1121
1133
  // 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
- }
1134
+ var aResources = performance.getEntriesByName(thisScript.src);
1135
+ if (aResources && aResources.length) {
1136
+ var r = aResources[0];
1137
+ // DO NOT USE DURATION!!!!!
1138
+ // See https://www.stevesouders.com/blog/2014/11/25/serious-confusion-with-resource-timing/
1139
+ var dns = floor(r.domainLookupEnd - r.domainLookupStart);
1140
+ var tcp = floor(r.connectEnd - r.connectStart);
1141
+ var fb = floor(r.responseStart - r.requestStart);
1142
+ var content = floor(r.responseEnd - r.responseStart);
1143
+ var networkDuration = dns + tcp + fb + content;
1144
+ var parseEval = scriptEndTime - scriptStartTime;
1145
+ var transferSize = r.encodedBodySize ? r.encodedBodySize : 0;
1146
+ // Instead of a delimiter use a 1-letter abbreviation as a separator.
1147
+ sLuxjs =
1148
+ "d" +
1149
+ dns +
1150
+ "t" +
1151
+ tcp +
1152
+ "f" +
1153
+ fb +
1154
+ "c" +
1155
+ content +
1156
+ "n" +
1157
+ networkDuration +
1158
+ "e" +
1159
+ parseEval +
1160
+ "r" +
1161
+ globalConfig.samplerate + // sample rate
1162
+ (typeof transferSize === "number" ? "x" + transferSize : "") +
1163
+ (typeof gLuxSnippetStart === "number" ? "l" + gLuxSnippetStart : "") +
1164
+ "s" +
1165
+ (scriptStartTime - timing.navigationStart) + // when lux.js started getting evaluated relative to navigationStart
1166
+ "";
1158
1167
  }
1159
1168
  }
1160
1169
  return sLuxjs;
@@ -1185,9 +1194,9 @@
1185
1194
  if (gCustomerDataTimeout) {
1186
1195
  // Cancel the timer for any previous beacons so that if they have not
1187
1196
  // yet been sent we can combine all the data in a new beacon.
1188
- window.clearTimeout(gCustomerDataTimeout);
1197
+ clearTimeout(gCustomerDataTimeout);
1189
1198
  }
1190
- gCustomerDataTimeout = window.setTimeout(_sendCustomerData, 100);
1199
+ gCustomerDataTimeout = setTimeout(_sendCustomerData, 100);
1191
1200
  }
1192
1201
  }
1193
1202
  // _sample()
@@ -1200,9 +1209,9 @@
1200
1209
  return parseInt(nThis) < globalConfig.samplerate;
1201
1210
  }
1202
1211
  /**
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
- */
1212
+ * Re-initialize lux.js to start a new "page". This is typically called within a SPA at the
1213
+ * beginning of a page transition, but is also called internally when the BF cache is restored.
1214
+ */
1206
1215
  function _init(startTime) {
1207
1216
  // Some customers (incorrectly) call LUX.init on the very first page load of a SPA. This would
1208
1217
  // cause some first-page-only data (like paint metrics) to be lost. To prevent this, we silently
@@ -1232,7 +1241,6 @@
1232
1241
  gbFirstPV = 0;
1233
1242
  gSyncId = createSyncId();
1234
1243
  gUid = refreshUniqueId(gSyncId);
1235
- clearEntries();
1236
1244
  reset$1();
1237
1245
  reset();
1238
1246
  nErrors = 0;
@@ -1353,14 +1361,17 @@
1353
1361
  ns += start; // "navigationStart" for a SPA is the real navigationStart plus the start mark
1354
1362
  var end = floor(endMark.startTime) - start; // delta from start mark
1355
1363
  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
- "";
1364
+ ns +
1365
+ // fetchStart and activationStart are the same as navigationStart for a SPA
1366
+ "as" +
1367
+ 0 +
1368
+ "fs" +
1369
+ 0 +
1370
+ "ls" +
1371
+ end +
1372
+ "le" +
1373
+ end +
1374
+ "";
1364
1375
  }
1365
1376
  else if (performance.timing) {
1366
1377
  // Return the real Nav Timing metrics because this is the "main" page view (not a SPA)
@@ -1368,17 +1379,20 @@
1368
1379
  var startRender = getStartRender();
1369
1380
  var fcp = getFcp();
1370
1381
  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();
1382
+ var prefixNTValue = function (key, prefix, ignoreZero) {
1374
1383
  if (typeof navEntry_1[key] === "number") {
1375
- var value = clamp(floor(navEntry_1[key] - zero));
1376
- return prefix + value;
1384
+ var value = navEntry_1[key];
1385
+ // We allow zero values for most navigation timing metrics, but for some metrics we want
1386
+ // to ignore zeroes. The exceptions are that all metrics can be zero if the page was either
1387
+ // prerendered or restored from the BF cache.
1388
+ if (shouldReportValue(value) || !ignoreZero) {
1389
+ return prefix + processTimeMetric(value);
1390
+ }
1377
1391
  }
1378
1392
  return "";
1379
1393
  };
1380
- var loadEventStartStr = prefixNTValue("loadEventStart", "ls");
1381
- var loadEventEndStr = prefixNTValue("loadEventEnd", "le");
1394
+ var loadEventStartStr = prefixNTValue("loadEventStart", "ls", true);
1395
+ var loadEventEndStr = prefixNTValue("loadEventEnd", "le", true);
1382
1396
  if (pageRestoreTime && startMark && endMark) {
1383
1397
  // For bfcache restores, we set the load time to the time it took for the page to be restored.
1384
1398
  var loadTime = floor(endMark.startTime - startMark.startTime);
@@ -1386,43 +1400,44 @@
1386
1400
  loadEventEndStr = "le" + loadTime;
1387
1401
  }
1388
1402
  var redirect = wasRedirected();
1403
+ var isSecure = document.location.protocol === "https:";
1389
1404
  s = [
1390
1405
  ns,
1391
- prefixNTValue("activationStart", "as"),
1392
- redirect ? prefixNTValue("redirectStart", "rs") : "",
1393
- redirect ? prefixNTValue("redirectEnd", "re") : "",
1406
+ "as" + clamp(navEntry_1.activationStart),
1407
+ redirect && !pageRestoreTime ? prefixNTValue("redirectStart", "rs") : "",
1408
+ redirect && !pageRestoreTime ? prefixNTValue("redirectEnd", "re") : "",
1394
1409
  prefixNTValue("fetchStart", "fs"),
1395
1410
  prefixNTValue("domainLookupStart", "ds"),
1396
1411
  prefixNTValue("domainLookupEnd", "de"),
1397
1412
  prefixNTValue("connectStart", "cs"),
1398
- prefixNTValue("secureConnectionStart", "sc"),
1413
+ isSecure ? prefixNTValue("secureConnectionStart", "sc") : "",
1399
1414
  prefixNTValue("connectEnd", "ce"),
1400
1415
  prefixNTValue("requestStart", "qs"),
1401
1416
  prefixNTValue("responseStart", "bs"),
1402
1417
  prefixNTValue("responseEnd", "be"),
1403
- prefixNTValue("domInteractive", "oi"),
1404
- prefixNTValue("domContentLoadedEventStart", "os"),
1405
- prefixNTValue("domContentLoadedEventEnd", "oe"),
1406
- prefixNTValue("domComplete", "oc"),
1418
+ prefixNTValue("domInteractive", "oi", true),
1419
+ prefixNTValue("domContentLoadedEventStart", "os", true),
1420
+ prefixNTValue("domContentLoadedEventEnd", "oe", true),
1421
+ prefixNTValue("domComplete", "oc", true),
1407
1422
  loadEventStartStr,
1408
1423
  loadEventEndStr,
1409
- typeof startRender !== "undefined" ? "sr" + clamp(startRender) : "",
1410
- typeof fcp !== "undefined" ? "fc" + clamp(fcp) : "",
1411
- typeof lcp !== "undefined" ? "lc" + clamp(lcp) : "",
1424
+ typeof startRender !== "undefined" ? "sr" + startRender : "",
1425
+ typeof fcp !== "undefined" ? "fc" + fcp : "",
1426
+ typeof lcp !== "undefined" ? "lc" + lcp : "",
1412
1427
  ].join("");
1413
1428
  }
1414
1429
  else if (endMark) {
1415
1430
  // This is a "main" page view that does NOT support Navigation Timing - strange.
1416
1431
  var end = floor(endMark.startTime);
1417
1432
  s =
1418
- ns +
1419
- "fs" +
1420
- 0 + // fetchStart is the same as navigationStart
1421
- "ls" +
1422
- end +
1423
- "le" +
1424
- end +
1425
- "";
1433
+ ns +
1434
+ "fs" +
1435
+ 0 + // fetchStart is the same as navigationStart
1436
+ "ls" +
1437
+ end +
1438
+ "le" +
1439
+ end +
1440
+ "";
1426
1441
  }
1427
1442
  return s;
1428
1443
  }
@@ -1432,7 +1447,10 @@
1432
1447
  for (var i = 0; i < paintEntries.length; i++) {
1433
1448
  var entry = paintEntries[i];
1434
1449
  if (entry.name === "first-contentful-paint") {
1435
- return floor(entry.startTime - getZeroTime());
1450
+ var value = processTimeMetric(entry.startTime);
1451
+ if (shouldReportValue(value)) {
1452
+ return value;
1453
+ }
1436
1454
  }
1437
1455
  }
1438
1456
  return undefined;
@@ -1442,8 +1460,11 @@
1442
1460
  var lcpEntries = getEntries("largest-contentful-paint");
1443
1461
  if (lcpEntries.length) {
1444
1462
  var lastEntry = lcpEntries[lcpEntries.length - 1];
1445
- logger.logEvent(LogEvent.PerformanceEntryProcessed, [lastEntry]);
1446
- return floor(lastEntry.startTime - getZeroTime());
1463
+ var value = processTimeMetric(lastEntry.startTime);
1464
+ if (shouldReportValue(value)) {
1465
+ logger.logEvent(LogEvent.PerformanceEntryProcessed, [lastEntry]);
1466
+ return value;
1467
+ }
1447
1468
  }
1448
1469
  return undefined;
1449
1470
  }
@@ -1454,12 +1475,17 @@
1454
1475
  if ("PerformancePaintTiming" in self) {
1455
1476
  var paintEntries = getEntriesByType("paint");
1456
1477
  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());
1478
+ var paintValues = paintEntries.map(function (entry) { return entry.startTime; }).sort(sortNumeric);
1479
+ // Use the earliest valid paint entry as the start render time.
1480
+ for (var i = 0; i < paintValues.length; i++) {
1481
+ var value = processTimeMetric(paintValues[i]);
1482
+ if (shouldReportValue(value)) {
1483
+ return value;
1484
+ }
1485
+ }
1460
1486
  }
1461
1487
  }
1462
- if (performance.timing && timing.msFirstPaint && __ENABLE_POLYFILLS) {
1488
+ if (performance.timing && timing.msFirstPaint && true) {
1463
1489
  // If IE/Edge, use the prefixed `msFirstPaint` property (see http://msdn.microsoft.com/ff974719).
1464
1490
  return floor(timing.msFirstPaint - timing.navigationStart);
1465
1491
  }
@@ -1472,41 +1498,11 @@
1472
1498
  }
1473
1499
  return getHighPercentileINP();
1474
1500
  }
1501
+ // function simplified for our use, original would get the customerid from the script src URL
1502
+ // but we set it inside the code in this file, so this function just returns that
1475
1503
  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
- }
1482
- }
1483
1504
  return LUX.customerid || "";
1484
1505
  }
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
1506
  function avgDomDepth() {
1511
1507
  var aElems = document.getElementsByTagName("*");
1512
1508
  var i = aElems.length;
@@ -1645,14 +1641,14 @@
1645
1641
  }
1646
1642
  function createMaxMeasureTimeout() {
1647
1643
  clearMaxMeasureTimeout();
1648
- gMaxMeasureTimeout = window.setTimeout(function () {
1644
+ gMaxMeasureTimeout = setTimeout(function () {
1649
1645
  gFlags = addFlag(gFlags, Flags.BeaconSentAfterTimeout);
1650
1646
  _sendLux();
1651
1647
  }, globalConfig.maxMeasureTime - _now());
1652
1648
  }
1653
1649
  function clearMaxMeasureTimeout() {
1654
1650
  if (gMaxMeasureTimeout) {
1655
- window.clearTimeout(gMaxMeasureTimeout);
1651
+ clearTimeout(gMaxMeasureTimeout);
1656
1652
  }
1657
1653
  }
1658
1654
  function _getBeaconUrl(customData) {
@@ -1688,7 +1684,7 @@
1688
1684
  !gSyncId ||
1689
1685
  !_sample() || // OUTSIDE the sampled range
1690
1686
  gbLuxSent // LUX data already sent
1691
- ) {
1687
+ ) {
1692
1688
  return;
1693
1689
  }
1694
1690
  logger.logEvent(LogEvent.DataCollectionStart);
@@ -1741,49 +1737,49 @@
1741
1737
  var is = inlineTagSize("script");
1742
1738
  var ic = inlineTagSize("style");
1743
1739
  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 : "");
1740
+ // only send Nav Timing and lux.js metrics on initial pageload (not for SPA page views)
1741
+ (gbNavSent ? "" : "&NT=" + getNavTiming()) +
1742
+ (gbFirstPV ? "&LJS=" + sLuxjs : "") +
1743
+ // Page Stats
1744
+ "&PS=ns" +
1745
+ numScripts() +
1746
+ "bs" +
1747
+ blockingScripts() +
1748
+ (is > -1 ? "is" + is : "") +
1749
+ "ss" +
1750
+ numStylesheets() +
1751
+ "bc" +
1752
+ blockingStylesheets() +
1753
+ (ic > -1 ? "ic" + ic : "") +
1754
+ "ia" +
1755
+ imagesATF().length +
1756
+ "it" +
1757
+ document.getElementsByTagName("img").length + // total number of images
1758
+ "dd" +
1759
+ avgDomDepth() +
1760
+ "nd" +
1761
+ document.getElementsByTagName("*").length + // numdomelements
1762
+ "vh" +
1763
+ document.documentElement.clientHeight + // see http://www.quirksmode.org/mobile/viewports.html
1764
+ "vw" +
1765
+ document.documentElement.clientWidth +
1766
+ "dh" +
1767
+ docHeight(document) +
1768
+ "dw" +
1769
+ docWidth(document) +
1770
+ (docSize() ? "ds" + docSize() : "") + // document HTTP transfer size (bytes)
1771
+ (connectionType() ? "ct" + connectionType() + "_" : "") + // delimit with "_" since values can be non-numeric so need a way to extract with regex in VCL
1772
+ "er" +
1773
+ nErrors +
1774
+ "nt" +
1775
+ navigationType() +
1776
+ (navigator.deviceMemory ? "dm" + Math.round(navigator.deviceMemory) : "") + // device memory (GB)
1777
+ (sIx ? "&IX=" + sIx : "") +
1778
+ (typeof gFirstInputDelay !== "undefined" ? "&FID=" + gFirstInputDelay : "") +
1779
+ (sCPU ? "&CPU=" + sCPU : "") +
1780
+ (sET ? "&ET=" + sET : "") + // element timing
1781
+ (typeof CLS !== "undefined" ? "&CLS=" + CLS : "") +
1782
+ (typeof INP !== "undefined" ? "&INP=" + INP : "");
1787
1783
  // We add the user timing entries last so that we can split them to reduce the URL size if necessary.
1788
1784
  var utValues = userTimingValues();
1789
1785
  var _b = fitUserTimingEntries(utValues, globalConfig, baseUrl + metricsQueryString), beaconUtValues = _b[0], remainingUtValues = _b[1];
@@ -1807,8 +1803,8 @@
1807
1803
  }
1808
1804
  var ixTimerId;
1809
1805
  function _sendIxAfterDelay() {
1810
- window.clearTimeout(ixTimerId);
1811
- ixTimerId = window.setTimeout(_sendIx, 100);
1806
+ clearTimeout(ixTimerId);
1807
+ ixTimerId = setTimeout(_sendIx, 100);
1812
1808
  }
1813
1809
  // Beacon back the IX data separately (need to sync with LUX beacon on the backend).
1814
1810
  function _sendIx() {
@@ -1842,7 +1838,7 @@
1842
1838
  !gSyncId ||
1843
1839
  !_sample() || // OUTSIDE the sampled range
1844
1840
  !gbLuxSent // LUX has NOT been sent yet, so wait to include it there
1845
- ) {
1841
+ ) {
1846
1842
  return;
1847
1843
  }
1848
1844
  var sCustomerData = valuesToString(getUpdatedCustomData());
@@ -1870,6 +1866,19 @@
1870
1866
  }
1871
1867
  }
1872
1868
  function _keyHandler(e) {
1869
+ var keyCode = e.keyCode;
1870
+ /**
1871
+ * Ignore modifier keys
1872
+ *
1873
+ * 16 = Shift
1874
+ * 17 = Control
1875
+ * 18 = Alt
1876
+ * 20 = Caps Lock
1877
+ * 224 = Meta/Command
1878
+ */
1879
+ if (keyCode === 16 || keyCode === 17 || keyCode === 18 || keyCode === 20 || keyCode === 224) {
1880
+ return;
1881
+ }
1873
1882
  _removeIxHandlers();
1874
1883
  if (typeof ghIx["k"] === "undefined") {
1875
1884
  ghIx["k"] = _now();
@@ -1914,10 +1923,10 @@
1914
1923
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1915
1924
  function addListener(type, callback, useCapture) {
1916
1925
  if (useCapture === void 0) { useCapture = false; }
1917
- if (window.addEventListener) {
1918
- window.addEventListener(type, callback, useCapture);
1926
+ if (addEventListener) {
1927
+ addEventListener(type, callback, useCapture);
1919
1928
  }
1920
- else if (window.attachEvent && __ENABLE_POLYFILLS) {
1929
+ else if (window.attachEvent && true) {
1921
1930
  window.attachEvent("on" + type, callback);
1922
1931
  }
1923
1932
  }
@@ -1925,10 +1934,10 @@
1925
1934
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1926
1935
  function removeListener(type, callback, useCapture) {
1927
1936
  if (useCapture === void 0) { useCapture = false; }
1928
- if (window.removeEventListener) {
1929
- window.removeEventListener(type, callback, useCapture);
1937
+ if (removeEventListener) {
1938
+ removeEventListener(type, callback, useCapture);
1930
1939
  }
1931
- else if (window.detachEvent && __ENABLE_POLYFILLS) {
1940
+ else if (window.detachEvent && true) {
1932
1941
  window.detachEvent("on" + type, callback);
1933
1942
  }
1934
1943
  }
@@ -2016,7 +2025,7 @@
2016
2025
  if (typeof LUX.pagegroups !== "undefined") {
2017
2026
  var label = getMatchesFromPatternMap(LUX.pagegroups, location.hostname, location.pathname, true);
2018
2027
  if (label) {
2019
- gFlags = addFlag(gFlags, Flags.PageLabelFromPagegroup);
2028
+ gFlags = addFlag(gFlags, Flags.PageLabelFromUrlPattern);
2020
2029
  return label;
2021
2030
  }
2022
2031
  }
@@ -2057,11 +2066,11 @@
2057
2066
  function _setCookie(name, value, seconds) {
2058
2067
  try {
2059
2068
  document.cookie =
2060
- name +
2061
- "=" +
2062
- escape(value) +
2063
- (seconds ? "; max-age=" + seconds : "") +
2064
- "; path=/; SameSite=Lax";
2069
+ name +
2070
+ "=" +
2071
+ escape(value) +
2072
+ (seconds ? "; max-age=" + seconds : "") +
2073
+ "; path=/; SameSite=Lax";
2065
2074
  }
2066
2075
  catch (e) {
2067
2076
  logger.logEvent(LogEvent.CookieSetError);
@@ -2111,7 +2120,7 @@
2111
2120
  // bfcache. Since we have no "onload" event to hook into after a bfcache restore, we rely on the
2112
2121
  // unload and maxMeasureTime handlers to send the beacon.
2113
2122
  if (globalConfig.newBeaconOnPageShow) {
2114
- window.addEventListener("pageshow", function (event) {
2123
+ addEventListener("pageshow", function (event) {
2115
2124
  if (event.persisted) {
2116
2125
  // Record the timestamp of the bfcache restore
2117
2126
  pageRestoreTime = event.timeStamp;
@@ -2141,9 +2150,9 @@
2141
2150
  // Set the maximum measurement timer
2142
2151
  createMaxMeasureTimeout();
2143
2152
  /**
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
- */
2153
+ * LUX functions and properties must be attached to the existing global object to ensure that
2154
+ * changes made to the global object are reflected in the "internal" LUX object, and vice versa.
2155
+ */
2147
2156
  var globalLux = globalConfig;
2148
2157
  // Functions
2149
2158
  globalLux.mark = _mark;
@@ -2168,8 +2177,8 @@
2168
2177
  // Public properties
2169
2178
  globalLux.version = SCRIPT_VERSION;
2170
2179
  /**
2171
- * Run a command from the command queue
2172
- */
2180
+ * Run a command from the command queue
2181
+ */
2173
2182
  function _runCommand(_a) {
2174
2183
  var fn = _a[0], args = _a.slice(1);
2175
2184
  if (typeof globalLux[fn] === "function") {
@@ -2194,11 +2203,6 @@
2194
2203
  // More settings
2195
2204
  // ---------------------------------------------------------------------------
2196
2205
  //
2197
- // This ID usually appended to the end of the lux.js as a query string when
2198
- // using the SpeedCurve hosted version - but we have to include it here as
2199
- // this is self hosted.
2200
- LUX.customerid = 47044334;
2201
-
2202
2206
  // Setting debug to `true` shows what happening as it happens. Running
2203
2207
  // `LUX.getDebug()` in the browser's console will show the history of what's
2204
2208
  // happened.
@@ -17,6 +17,12 @@
17
17
  display: block !important; // stylelint-disable-line declaration-no-important
18
18
  }
19
19
 
20
+ .js-enabled .govuk-accordion__section-content[hidden] {
21
+ @supports (content-visibility: hidden) {
22
+ content-visibility: auto;
23
+ }
24
+ }
25
+
20
26
  // Change the colour from the blue link colour to black.
21
27
  .govuk-accordion__section-button {
22
28
  color: govuk-colour("black") !important; // stylelint-disable-line declaration-no-important
@@ -34,6 +34,12 @@
34
34
  // stylelint-disable max-nesting-depth
35
35
 
36
36
  .gem-c-govspeak {
37
+ a[href^="/"]:after,a[href^="http://"]:after,a[href^="https://"]:after {
38
+ content: " (" attr(href) ")";
39
+ font-size: 90%;
40
+ word-wrap: break-word;
41
+ }
42
+
37
43
  .media-player {
38
44
  display: none;
39
45
  }
@@ -54,8 +54,9 @@
54
54
  )
55
55
  end
56
56
 
57
+ data_attributes[:ga4_link] = ga4_link
57
58
  %>
58
- <%= tag.section class: class_names(container_class_names), data: { module: "ga4-link-tracker", ga4_track_links_only: "", ga4_link: ga4_link } do %>
59
+ <%= tag.section class: class_names(container_class_names), data: { module: "ga4-link-tracker" } do %>
59
60
  <%= tag.div class: "gem-c-attachment__thumbnail" do %>
60
61
  <%= link_to attachment.url,
61
62
  class: "govuk-link",
@@ -1,6 +1,7 @@
1
1
  <div class="govuk-width-container">
2
2
  <%= render "govuk_publishing_components/components/phase_banner", {
3
3
  phase: "beta",
4
+ ga4_tracking: true,
4
5
  message: sanitize(t("components.layout_for_public.account_layout.feedback.banners.phase_banner_html"))
5
6
  } unless omit_account_phase_banner %>
6
7
 
@@ -1,3 +1,3 @@
1
1
  module GovukPublishingComponents
2
- VERSION = "35.15.0".freeze
2
+ VERSION = "35.15.2".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: govuk_publishing_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 35.15.0
4
+ version: 35.15.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - GOV.UK Dev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-31 00:00:00.000000000 Z
11
+ date: 2023-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: govuk_app_config