govuk_publishing_components 35.15.0 → 35.15.2

Sign up to get free protection for your applications and to get access to all the features.
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