govuk_publishing_components 29.8.0 → 29.9.0

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: 4cef8771d15136a9e4ebbe4fc0cbedb616731c433ea12db09af6fa12c1613594
4
- data.tar.gz: 721a1fb8532f1952e49aa9ff61a6aa075d3719f8a774c387319858da6c153edf
3
+ metadata.gz: d0d30bd1a2b86ab711560f26438e2ba7907402831cc617b752d3e1fb05c2e6cc
4
+ data.tar.gz: e13d38616b71e39a1e3e23df2999eb88f9824a668dc8347a4b914a58e86bf2bb
5
5
  SHA512:
6
- metadata.gz: f1544190ffc2c00a4f1576c84c74c89e1bc647d4916bccd72deb7f571a9b3f010ebba18abec66a1d67868b86de280dd83cbe4c5bc34677b5a1150bf1a54fdf16
7
- data.tar.gz: 868c8e7d02ab075e08fa196c526c39f02e6583dada12cfbb70f0384326a22728471cffe310d16692712d985960c4f78ec1e0f3ad5e8daeae84a4596398cf21a9
6
+ metadata.gz: d91d69b91a14c9f6acaf230a32c9c75385f54cd7c2ff924860f87e3578ea32f58726d16e0de1d5ccbfbeb808da0ceba804adc9827cd5ae2370dae3b6b478090b
7
+ data.tar.gz: 036b79310b2cef0189a2536eab0d70bdf0d293cd079533da198f666c00ee04ddc7f34a22468ad4b853d2875fe1d44ec8ec305157c115ea19e0b2760e21ccd401
@@ -171,16 +171,25 @@ if (
171
171
  // `DOMContentReady` event before we can see what the HTTP version is.
172
172
  //
173
173
  // [1]: https://github.com/alphagov/govuk-rfcs/pull/148
174
- try {
175
- if (typeof performance !== 'undefined') {
176
- document.addEventListener('DOMContentLoaded', function () {
177
- var getEntriesByType = performance.getEntriesByType('navigation')
178
174
 
179
- if (getEntriesByType.length > 0) {
180
- var httpProtocol = performance.getEntriesByType('navigation')[0].nextHopProtocol
181
- LUX.addData("http-protocol", httpProtocol)
182
- }
183
- })
175
+ var measureHTTPProtocol = function () {
176
+ var getEntriesByType = performance.getEntriesByType('navigation')
177
+
178
+ if (getEntriesByType.length > 0) {
179
+ var httpProtocol = JSON.parse(JSON.stringify(performance.getEntriesByType('navigation')[0].nextHopProtocol))
180
+ LUX.addData("http-protocol", httpProtocol)
181
+ }
182
+ }
183
+
184
+ try {
185
+ if (typeof performance !== 'undefined' && typeof performance.getEntriesByType !== 'undefined') {
186
+ if (document.readyState === 'complete') {
187
+ measureHTTPProtocol()
188
+ } else {
189
+ window.addEventListener('load', function() {
190
+ measureHTTPProtocol()
191
+ })
192
+ }
184
193
  }
185
194
  } catch (e) {
186
195
  console.error('Error in LUX reporting the HTTP protocol (' + window.location + '):', e)
@@ -41,6 +41,7 @@
41
41
  maxErrors: getProperty(obj, "maxErrors", 5),
42
42
  maxMeasureTime: getProperty(obj, "maxMeasureTime", 60000),
43
43
  measureUntil: getProperty(obj, "measureUntil", "onload"),
44
+ minMeasureTime: getProperty(obj, "minMeasureTime", 0),
44
45
  samplerate: getProperty(obj, "samplerate", 100),
45
46
  sendBeaconOnPageHidden: getProperty(obj, "sendBeaconOnPageHidden", autoMode),
46
47
  trackErrors: getProperty(obj, "trackErrors", true),
@@ -63,6 +64,9 @@
63
64
  AddDataCalled: 6,
64
65
  SendCalled: 7,
65
66
  ForceSampleCalled: 8,
67
+ DataCollectionStart: 9,
68
+ UnloadHandlerTriggered: 10,
69
+ OnloadHandlerTriggered: 11,
66
70
  // Data collection events
67
71
  SessionIsSampled: 21,
68
72
  SessionIsNotSampled: 22,
@@ -70,6 +74,10 @@
70
74
  UserTimingBeaconSent: 24,
71
75
  InteractionBeaconSent: 25,
72
76
  CustomDataBeaconSent: 26,
77
+ // Metric information
78
+ NavigationStart: 41,
79
+ PerformanceEntryReceived: 42,
80
+ PerformanceEntryProcessed: 43,
73
81
  // Errors
74
82
  PerformanceObserverError: 51,
75
83
  InputEventPermissionError: 52,
@@ -82,7 +90,7 @@
82
90
  NavTimingNotSupported: 71,
83
91
  PaintTimingNotSupported: 72,
84
92
  };
85
- var Logger = (function () {
93
+ var Logger = /** @class */ (function () {
86
94
  function Logger() {
87
95
  this.events = [];
88
96
  }
@@ -90,7 +98,7 @@
90
98
  if (args === void 0) {
91
99
  args = [];
92
100
  }
93
- this.events.push([new Date(), event, args]);
101
+ this.events.push([now(), event, args]);
94
102
  };
95
103
  Logger.prototype.getEvents = function () {
96
104
  return this.events;
@@ -113,7 +121,34 @@
113
121
  return flags | flag;
114
122
  }
115
123
 
124
+ // If the various performance APIs aren't available, we export an empty object to
125
+ // prevent having to make regular typeof checks.
126
+ var performance = window.performance || {};
127
+ var timing = performance.timing || {};
128
+ /**
129
+ * Simple wrapper around performance.getEntriesByType to provide fallbacks for
130
+ * legacy browsers, and work around edge cases where undefined is returned instead
131
+ * of an empty PerformanceEntryList.
132
+ */
133
+ function getEntriesByType(type) {
134
+ if (typeof performance.getEntriesByType === "function") {
135
+ var entries = performance.getEntriesByType(type);
136
+ if (entries && entries.length) {
137
+ return entries;
138
+ }
139
+ } else if (typeof performance.webkitGetEntriesByType === "function") {
140
+ var entries = performance.webkitGetEntriesByType(type);
141
+ if (entries && entries.length) {
142
+ return entries;
143
+ }
144
+ }
145
+ return [];
146
+ }
147
+
116
148
  var LUX = window.LUX || {};
149
+ // Get a timestamp as close to navigationStart as possible.
150
+ var _navigationStart = LUX.ns ? LUX.ns : now();
151
+ var LUX_t_end = LUX_t_start;
117
152
  LUX = (function () {
118
153
  // -------------------------------------------------------------------------
119
154
  // Settings
@@ -124,7 +159,7 @@
124
159
  /// End
125
160
  // -------------------------------------------------------------------------
126
161
 
127
- var SCRIPT_VERSION = "300";
162
+ var SCRIPT_VERSION = "301";
128
163
  var logger = new Logger();
129
164
  var userConfig = fromObject(LUX);
130
165
  logger.logEvent(LogEvent.EvaluationStart, [SCRIPT_VERSION]);
@@ -137,17 +172,13 @@
137
172
  nErrors++;
138
173
  if (
139
174
  e &&
140
- "undefined" !== typeof e.filename &&
141
- "undefined" !== typeof e.message
175
+ typeof e.filename !== "undefined" &&
176
+ typeof e.message !== "undefined"
142
177
  ) {
143
- // it is a valid error object
144
- if (
145
- -1 !== e.filename.indexOf("/lux.js?") ||
146
- -1 !== e.message.indexOf("LUX") || // Always send LUX errors.
147
- (nErrors <= userConfig.maxErrors &&
148
- "function" === typeof _sample &&
149
- _sample())
150
- ) {
178
+ // Always send LUX errors
179
+ var isLuxError =
180
+ e.filename.indexOf("/lux.js?") > -1 || e.message.indexOf("LUX") > -1;
181
+ if (isLuxError || (nErrors <= userConfig.maxErrors && _sample())) {
151
182
  // Sample & limit other errors.
152
183
  // Send the error beacon.
153
184
  new Image().src =
@@ -184,8 +215,8 @@
184
215
  var gaPerfEntries = gaSnippetLongTasks.slice(); // array of Long Tasks (prefer the array from the snippet)
185
216
  if (typeof PerformanceObserver === "function") {
186
217
  var perfObserver = new PerformanceObserver(function (list) {
187
- // Keep an array of perf objects to process later.
188
218
  list.getEntries().forEach(function (entry) {
219
+ logger.logEvent(LogEvent.PerformanceEntryReceived, [entry]);
189
220
  // Only record long tasks that weren't already recorded by the PerformanceObserver in the snippet
190
221
  if (
191
222
  entry.entryType !== "longtask" ||
@@ -237,24 +268,23 @@
237
268
  var gSyncId = createSyncId(); // if we send multiple beacons, use this to sync them (eg, LUX & IX) (also called "luxid")
238
269
  var gUid = refreshUniqueId(gSyncId); // cookie for this session ("Unique ID")
239
270
  var gCustomerDataTimeout; // setTimeout timer for sending a Customer Data beacon after onload
240
- var perf = window.performance;
271
+ var gMaxMeasureTimeout; // setTimeout timer for sending the beacon after a maximum measurement time
241
272
  var gMaxQuerystring = 8190; // split the beacon querystring if it gets longer than this
242
273
  if (_sample()) {
243
274
  logger.logEvent(LogEvent.SessionIsSampled, [userConfig.samplerate]);
244
275
  } else {
245
276
  logger.logEvent(LogEvent.SessionIsNotSampled, [userConfig.samplerate]);
246
277
  }
247
- // Get a timestamp as close to navigationStart as possible.
248
- var _navigationStart = LUX.ns ? LUX.ns : now(); // create a _navigationStart
249
278
  var gLuxSnippetStart = 0;
250
- if (perf && perf.timing && perf.timing.navigationStart) {
251
- _navigationStart = perf.timing.navigationStart;
279
+ if (timing.navigationStart) {
280
+ _navigationStart = timing.navigationStart;
252
281
  // Record when the LUX snippet was evaluated relative to navigationStart.
253
282
  gLuxSnippetStart = LUX.ns ? LUX.ns - _navigationStart : 0;
254
283
  } else {
255
284
  logger.logEvent(LogEvent.NavTimingNotSupported);
256
285
  gFlags = addFlag(gFlags, Flags.NavTimingNotSupported);
257
286
  }
287
+ logger.logEvent(LogEvent.NavigationStart, [_navigationStart]);
258
288
  ////////////////////// FID BEGIN
259
289
  // FIRST INPUT DELAY (FID)
260
290
  // The basic idea behind FID is to attach various input event listeners and measure the time
@@ -351,16 +381,15 @@
351
381
  * in SPAs.
352
382
  */
353
383
  function _now(absolute) {
354
- var currentTimestamp = Date.now ? Date.now() : +new Date();
355
- var msSinceNavigationStart = currentTimestamp - _navigationStart;
384
+ var msSinceNavigationStart = now() - _navigationStart;
356
385
  var startMark = _getMark(gStartMark);
357
386
  // For SPA page views, we use our internal mark as a reference point
358
387
  if (startMark && !absolute) {
359
388
  return msSinceNavigationStart - startMark.startTime;
360
389
  }
361
390
  // For "regular" page views, we can use performance.now() if it's available...
362
- if (perf && perf.now) {
363
- return perf.now();
391
+ if (performance.now) {
392
+ return performance.now();
364
393
  }
365
394
  // ... or we can use navigationStart as a reference point
366
395
  return msSinceNavigationStart;
@@ -369,12 +398,10 @@
369
398
  // NOTE: It's possible to set multiple marks with the same name.
370
399
  function _mark(name) {
371
400
  logger.logEvent(LogEvent.MarkCalled, [name]);
372
- if (perf) {
373
- if (perf.mark) {
374
- return perf.mark(name);
375
- } else if (perf.webkitMark) {
376
- return perf.webkitMark(name);
377
- }
401
+ if (performance.mark) {
402
+ return performance.mark(name);
403
+ } else if (performance.webkitMark) {
404
+ return performance.webkitMark(name);
378
405
  }
379
406
  gFlags = addFlag(gFlags, Flags.UserTimingNotSupported);
380
407
  // Shim
@@ -395,26 +422,24 @@
395
422
  startMarkName,
396
423
  endMarkName,
397
424
  ]);
398
- if ("undefined" === typeof startMarkName && _getMark(gStartMark)) {
425
+ if (typeof startMarkName === "undefined" && _getMark(gStartMark)) {
399
426
  // If a start mark is not specified, but the user has called _init() to set a new start,
400
427
  // then use the new start base time (similar to navigationStart) as the start mark.
401
428
  startMarkName = gStartMark;
402
429
  }
403
- if (perf) {
404
- if (perf.measure) {
405
- // IE 11 does not handle null and undefined correctly
406
- if (startMarkName) {
407
- if (endMarkName) {
408
- return perf.measure(name, startMarkName, endMarkName);
409
- } else {
410
- return perf.measure(name, startMarkName);
411
- }
430
+ if (performance.measure) {
431
+ // IE 11 does not handle null and undefined correctly
432
+ if (startMarkName) {
433
+ if (endMarkName) {
434
+ return performance.measure(name, startMarkName, endMarkName);
412
435
  } else {
413
- return perf.measure(name);
436
+ return performance.measure(name, startMarkName);
414
437
  }
415
- } else if (perf.webkitMeasure) {
416
- return perf.webkitMeasure(name, startMarkName, endMarkName);
438
+ } else {
439
+ return performance.measure(name);
417
440
  }
441
+ } else if (performance.webkitMeasure) {
442
+ return performance.webkitMeasure(name, startMarkName, endMarkName);
418
443
  }
419
444
  // shim:
420
445
  var startTime = 0,
@@ -423,9 +448,9 @@
423
448
  var startMark = _getMark(startMarkName);
424
449
  if (startMark) {
425
450
  startTime = startMark.startTime;
426
- } else if (perf && perf.timing && perf.timing[startMarkName]) {
451
+ } else if (timing[startMarkName]) {
427
452
  // the mark name can also be a property from Navigation Timing
428
- startTime = perf.timing[startMarkName] - perf.timing.navigationStart;
453
+ startTime = timing[startMarkName] - timing.navigationStart;
429
454
  } else {
430
455
  throw new DOMException(
431
456
  "Failed to execute 'measure' on 'Performance': The mark '".concat(
@@ -439,9 +464,9 @@
439
464
  var endMark = _getMark(endMarkName);
440
465
  if (endMark) {
441
466
  endTime = endMark.startTime;
442
- } else if (perf && perf.timing && perf.timing[endMarkName]) {
467
+ } else if (timing[endMarkName]) {
443
468
  // the mark name can also be a property from Navigation Timing
444
- endTime = perf.timing[endMarkName] - perf.timing.navigationStart;
469
+ endTime = timing[endMarkName] - timing.navigationStart;
445
470
  } else {
446
471
  throw new DOMException(
447
472
  "Failed to execute 'measure' on 'Performance': The mark '".concat(
@@ -479,23 +504,17 @@
479
504
  }
480
505
  // Return an array of marks.
481
506
  function _getMarks() {
482
- if (perf) {
483
- if (perf.getEntriesByType) {
484
- return perf.getEntriesByType("mark");
485
- } else if (perf.webkitGetEntriesByType) {
486
- return perf.webkitGetEntriesByType("mark");
487
- }
507
+ var marks = getEntriesByType("mark");
508
+ if (marks.length) {
509
+ return marks;
488
510
  }
489
511
  return gaMarks;
490
512
  }
491
513
  // Return an array of measures.
492
514
  function _getMeasures() {
493
- if (perf) {
494
- if (perf.getEntriesByType) {
495
- return perf.getEntriesByType("measure");
496
- } else if (perf.webkitGetEntriesByType) {
497
- return perf.webkitGetEntriesByType("measure");
498
- }
515
+ var measures = getEntriesByType("measure");
516
+ if (measures.length) {
517
+ return measures;
499
518
  }
500
519
  return gaMeasures;
501
520
  }
@@ -568,6 +587,7 @@
568
587
  for (var i = 0; i < gaPerfEntries.length; i++) {
569
588
  var pe = gaPerfEntries[i];
570
589
  if ("element" === pe.entryType && pe.identifier && pe.startTime) {
590
+ logger.logEvent(LogEvent.PerformanceEntryProcessed, [pe]);
571
591
  aET.push(pe.identifier + "|" + Math.round(pe.startTime));
572
592
  }
573
593
  }
@@ -576,7 +596,7 @@
576
596
  }
577
597
  // Return a string of CPU times formatted for beacon querystring.
578
598
  function cpuTimes() {
579
- if ("function" !== typeof PerformanceLongTaskTiming) {
599
+ if (typeof PerformanceLongTaskTiming !== "function") {
580
600
  // Do not return any CPU metrics if Long Tasks API is not supported.
581
601
  return "";
582
602
  }
@@ -591,7 +611,7 @@
591
611
  var tZero = startMark ? startMark.startTime : 0;
592
612
  // Do not include Long Tasks that start after the page is done.
593
613
  // For full page loads, "done" is loadEventEnd.
594
- var tEnd = perf.timing.loadEventEnd - perf.timing.navigationStart;
614
+ var tEnd = timing.loadEventEnd - timing.navigationStart;
595
615
  if (startMark) {
596
616
  // For SPA page loads (determined by the presence of a start mark), "done" is gEndMark.
597
617
  var endMark = _getMark(gEndMark);
@@ -614,6 +634,7 @@
614
634
  // callback from setTimeout(200) happened. Do not include anything that started after tEnd.
615
635
  continue;
616
636
  }
637
+ logger.logEvent(LogEvent.PerformanceEntryProcessed, [p]);
617
638
  var type = p.attribution[0].name; // TODO - is there ever more than 1 attribution???
618
639
  if (!hCPU[type]) {
619
640
  // initialize this category
@@ -626,8 +647,8 @@
626
647
  }
627
648
  }
628
649
  // TODO - Add more types if/when they become available.
629
- var jsType = "undefined" !== typeof hCPU["script"] ? "script" : "unknown"; // spec changed from "script" to "unknown" Nov 2018
630
- if ("undefined" === typeof hCPU[jsType]) {
650
+ var jsType = typeof hCPU["script"] !== "undefined" ? "script" : "unknown"; // spec changed from "script" to "unknown" Nov 2018
651
+ if (typeof hCPU[jsType] === "undefined") {
631
652
  // Initialize default values for pages that have *no Long Tasks*.
632
653
  hCPU[jsType] = 0;
633
654
  hCPUDetails[jsType] = "";
@@ -681,7 +702,7 @@
681
702
  return { count: count, median: median, max: max, fci: fci };
682
703
  }
683
704
  function calculateDCLS() {
684
- if ("function" !== typeof LayoutShift) {
705
+ if (typeof LayoutShift !== "function") {
685
706
  return false;
686
707
  }
687
708
  var DCLS = 0;
@@ -690,6 +711,7 @@
690
711
  if ("layout-shift" !== p.entryType || p.hadRecentInput) {
691
712
  continue;
692
713
  }
714
+ logger.logEvent(LogEvent.PerformanceEntryProcessed, [p]);
693
715
  DCLS += p.value;
694
716
  }
695
717
  // The DCL column in Redshift is REAL (FLOAT4) which stores a maximum
@@ -716,11 +738,11 @@
716
738
  // Track how long it took lux.js to load via Resource Timing.
717
739
  function selfLoading() {
718
740
  var sLuxjs = "";
719
- if (perf && perf.getEntriesByName) {
741
+ if (performance.getEntriesByName) {
720
742
  // Get the lux script URL (including querystring params).
721
743
  var luxScript = getScriptElement("/js/lux.js");
722
744
  if (luxScript) {
723
- var aResources = perf.getEntriesByName(luxScript.src);
745
+ var aResources = performance.getEntriesByName(luxScript.src);
724
746
  if (aResources && aResources.length) {
725
747
  var r = aResources[0];
726
748
  // DO NOT USE DURATION!!!!!
@@ -799,8 +821,8 @@
799
821
  // Return true if beacons for this page should be sampled.
800
822
  function _sample() {
801
823
  if (
802
- "undefined" === typeof gUid ||
803
- "undefined" === typeof userConfig.samplerate
824
+ typeof gUid === "undefined" ||
825
+ typeof userConfig.samplerate === "undefined"
804
826
  ) {
805
827
  return false; // bail
806
828
  }
@@ -851,6 +873,8 @@
851
873
  gFlags = addFlag(gFlags, Flags.InitCalled);
852
874
  // Mark the "navigationStart" for this SPA page.
853
875
  _mark(gStartMark);
876
+ // Reset the maximum measure timeout
877
+ createMaxMeasureTimeout();
854
878
  }
855
879
  // Return the number of blocking (synchronous) external scripts in the page.
856
880
  function blockingScripts() {
@@ -891,7 +915,7 @@
891
915
  e.onloadcssdefined ||
892
916
  "print" === e.media ||
893
917
  "style" === e.as ||
894
- ("function" === typeof e.onload && "all" === e.media)
918
+ (typeof e.onload === "function" && e.media === "all")
895
919
  );
896
920
  else {
897
921
  nBlocking++;
@@ -971,9 +995,9 @@
971
995
  "le" +
972
996
  end +
973
997
  "";
974
- } else if (perf && perf.timing) {
998
+ } else if (performance.timing) {
975
999
  // Return the real Nav Timing metrics because this is the "main" page view (not a SPA)
976
- var t = perf.timing;
1000
+ var t = timing;
977
1001
  var startRender = getStartRender(); // first paint
978
1002
  var fcp = getFcp(); // first contentful paint
979
1003
  var lcp = getLcp(); // largest contentful paint
@@ -1024,20 +1048,11 @@
1024
1048
  }
1025
1049
  // Return First Contentful Paint or zero if not supported.
1026
1050
  function getFcp() {
1027
- if (
1028
- perf &&
1029
- perf.getEntriesByType &&
1030
- perf.getEntriesByType("paint").length
1031
- ) {
1032
- for (
1033
- var arr = perf.getEntriesByType("paint"), i = 0;
1034
- i < arr.length;
1035
- i++
1036
- ) {
1037
- var ppt = arr[i]; // PerformancePaintTiming object
1038
- if ("first-contentful-paint" === ppt.name) {
1039
- return Math.round(ppt.startTime);
1040
- }
1051
+ var paintEntries = getEntriesByType("paint");
1052
+ for (var i = 0; i < paintEntries.length; i++) {
1053
+ var entry = paintEntries[i];
1054
+ if (entry.name === "first-contentful-paint") {
1055
+ return Math.round(entry.startTime);
1041
1056
  }
1042
1057
  }
1043
1058
  return 0;
@@ -1049,6 +1064,7 @@
1049
1064
  for (var i = gaPerfEntries.length - 1; i >= 0; i--) {
1050
1065
  var pe = gaPerfEntries[i];
1051
1066
  if ("largest-contentful-paint" === pe.entryType) {
1067
+ logger.logEvent(LogEvent.PerformanceEntryProcessed, [pe]);
1052
1068
  return Math.round(pe.startTime);
1053
1069
  }
1054
1070
  }
@@ -1059,31 +1075,24 @@
1059
1075
  // Mostly works on just Chrome and IE.
1060
1076
  // Return null if not supported.
1061
1077
  function getStartRender() {
1062
- if (perf && perf.timing) {
1063
- var t = perf.timing;
1078
+ if (performance.timing) {
1079
+ var t = timing;
1064
1080
  var ns = t.navigationStart;
1065
1081
  var startRender = void 0;
1066
1082
  if (ns) {
1067
- if (
1068
- perf &&
1069
- perf.getEntriesByType &&
1070
- perf.getEntriesByType("paint").length
1071
- ) {
1083
+ var paintEntries = getEntriesByType("paint");
1084
+ if (paintEntries.length) {
1072
1085
  // If Paint Timing API is supported, use it.
1073
- for (
1074
- var arr = perf.getEntriesByType("paint"), i = 0;
1075
- i < arr.length;
1076
- i++
1077
- ) {
1078
- var ppt = arr[i]; // PerformancePaintTiming object
1079
- if ("first-paint" === ppt.name) {
1080
- startRender = Math.round(ppt.startTime);
1086
+ for (var i = 0; i < paintEntries.length; i++) {
1087
+ var entry = paintEntries[i];
1088
+ if (entry.name === "first-paint") {
1089
+ startRender = Math.round(entry.startTime);
1081
1090
  break;
1082
1091
  }
1083
1092
  }
1084
1093
  } else if (
1085
1094
  window.chrome &&
1086
- "function" === typeof window.chrome.loadTimes
1095
+ typeof window.chrome.loadTimes === "function"
1087
1096
  ) {
1088
1097
  // If chrome, get first paint time from `chrome.loadTimes`. Need extra error handling.
1089
1098
  var loadTimes = window.chrome.loadTimes();
@@ -1094,9 +1103,9 @@
1094
1103
  // If IE/Edge, use the prefixed `msFirstPaint` property (see http://msdn.microsoft.com/ff974719).
1095
1104
  startRender = Math.round(t.msFirstPaint - ns);
1096
1105
  }
1097
- if (startRender) {
1098
- return startRender;
1099
- }
1106
+ }
1107
+ if (startRender) {
1108
+ return startRender;
1100
1109
  }
1101
1110
  }
1102
1111
  logger.logEvent(LogEvent.PaintTimingNotSupported);
@@ -1185,15 +1194,9 @@
1185
1194
  }
1186
1195
  // Return the main HTML document transfer size (in bytes).
1187
1196
  function docSize() {
1188
- if (
1189
- perf &&
1190
- perf.getEntriesByType &&
1191
- perf.getEntriesByType("navigation").length
1192
- ) {
1193
- var aEntries = performance.getEntriesByType("navigation");
1194
- if (aEntries && aEntries.length > 0 && aEntries[0]["encodedBodySize"]) {
1195
- return aEntries[0]["encodedBodySize"];
1196
- }
1197
+ var aEntries = getEntriesByType("navigation");
1198
+ if (aEntries.length && aEntries[0]["encodedBodySize"]) {
1199
+ return aEntries[0]["encodedBodySize"];
1197
1200
  }
1198
1201
  return 0; // ERROR - NOT FOUND
1199
1202
  }
@@ -1201,11 +1204,10 @@
1201
1204
  // Return empty string if not available.
1202
1205
  function navigationType() {
1203
1206
  if (
1204
- perf &&
1205
- perf.navigation &&
1206
- "undefined" != typeof perf.navigation.type
1207
+ performance.navigation &&
1208
+ typeof performance.navigation.type !== "undefined"
1207
1209
  ) {
1208
- return perf.navigation.type;
1210
+ return performance.navigation.type;
1209
1211
  }
1210
1212
  return "";
1211
1213
  }
@@ -1310,19 +1312,31 @@
1310
1312
  function _markLoadTime() {
1311
1313
  _mark(gEndMark);
1312
1314
  }
1315
+ function createMaxMeasureTimeout() {
1316
+ clearMaxMeasureTimeout();
1317
+ gMaxMeasureTimeout = window.setTimeout(function () {
1318
+ gFlags = addFlag(gFlags, Flags.BeaconSentAfterTimeout);
1319
+ _sendLux();
1320
+ }, userConfig.maxMeasureTime - _now());
1321
+ }
1322
+ function clearMaxMeasureTimeout() {
1323
+ if (gMaxMeasureTimeout) {
1324
+ clearTimeout(gMaxMeasureTimeout);
1325
+ }
1326
+ }
1313
1327
  // Beacon back the LUX data.
1314
1328
  function _sendLux() {
1315
- logger.logEvent(LogEvent.SendCalled);
1329
+ clearMaxMeasureTimeout();
1316
1330
  var customerid = getCustomerId();
1317
1331
  if (
1318
1332
  !customerid ||
1319
1333
  !gSyncId ||
1320
- !validDomain() ||
1321
1334
  !_sample() || // OUTSIDE the sampled range
1322
1335
  gbLuxSent // LUX data already sent
1323
1336
  ) {
1324
1337
  return;
1325
1338
  }
1339
+ logger.logEvent(LogEvent.DataCollectionStart);
1326
1340
  var startMark = _getMark(gStartMark);
1327
1341
  var endMark = _getMark(gEndMark);
1328
1342
  if (!startMark || (endMark && endMark.startTime < startMark.startTime)) {
@@ -1472,7 +1486,6 @@
1472
1486
  if (
1473
1487
  !customerid ||
1474
1488
  !gSyncId ||
1475
- !validDomain() ||
1476
1489
  !_sample() || // OUTSIDE the sampled range
1477
1490
  gbIxSent || // IX data already sent
1478
1491
  !gbLuxSent // LUX has NOT been sent yet, so wait to include it there
@@ -1514,7 +1527,6 @@
1514
1527
  if (
1515
1528
  !customerid ||
1516
1529
  !gSyncId ||
1517
- !validDomain() ||
1518
1530
  !_sample() || // OUTSIDE the sampled range
1519
1531
  !gbLuxSent // LUX has NOT been sent yet, so wait to include it there
1520
1532
  ) {
@@ -1599,14 +1611,14 @@
1599
1611
  function _scrollHandler() {
1600
1612
  // Leave handlers IN PLACE so we can track which ID is clicked/keyed.
1601
1613
  // _removeIxHandlers();
1602
- if ("undefined" === typeof ghIx["s"]) {
1614
+ if (typeof ghIx["s"] === "undefined") {
1603
1615
  ghIx["s"] = Math.round(_now());
1604
1616
  // _sendIx(); // wait for key or click to send the IX beacon
1605
1617
  }
1606
1618
  }
1607
1619
  function _keyHandler(e) {
1608
1620
  _removeIxHandlers();
1609
- if ("undefined" === typeof ghIx["k"]) {
1621
+ if (typeof ghIx["k"] === "undefined") {
1610
1622
  ghIx["k"] = Math.round(_now());
1611
1623
  if (e && e.target) {
1612
1624
  var trackId = interactionAttributionForElement(e.target);
@@ -1619,7 +1631,7 @@
1619
1631
  }
1620
1632
  function _clickHandler(e) {
1621
1633
  _removeIxHandlers();
1622
- if ("undefined" === typeof ghIx["c"]) {
1634
+ if (typeof ghIx["c"] === "undefined") {
1623
1635
  ghIx["c"] = Math.round(_now());
1624
1636
  var target = null;
1625
1637
  try {
@@ -1672,6 +1684,7 @@
1672
1684
  function _addUnloadHandlers() {
1673
1685
  var onunload = function () {
1674
1686
  gFlags = addFlag(gFlags, Flags.BeaconSentFromUnloadHandler);
1687
+ logger.logEvent(LogEvent.UnloadHandlerTriggered);
1675
1688
  _sendLux();
1676
1689
  _sendIx();
1677
1690
  };
@@ -1775,14 +1788,6 @@
1775
1788
  gFlags = addFlag(gFlags, Flags.PageLabelFromDocumentTitle);
1776
1789
  return document.title;
1777
1790
  }
1778
- // Return true if the hostname of the current page is one of the listed domains.
1779
- function validDomain() {
1780
- // Our signup process is such that a customer almost always deploys lux.js BEFORE we
1781
- // enable LUX for their account. In which case, the list of domains is empty and no
1782
- // beacons will be sent. Further, that version of lux.js will be cached at the CDN
1783
- // and browser for a week. Instead, do the domain validation on the backend in VCL.
1784
- return true;
1785
- }
1786
1791
  function _getCookie(name) {
1787
1792
  try {
1788
1793
  // Seeing "Permission denied" errors, so do a simple try-catch.
@@ -1818,15 +1823,29 @@
1818
1823
  // Set "LUX.auto=false" to disable send results automatically and
1819
1824
  // instead you must call LUX.send() explicitly.
1820
1825
  if (userConfig.auto) {
1821
- if (document.readyState === "complete") {
1822
- // If onload has already passed, send the beacon now.
1823
- _sendLux();
1824
- } else {
1825
- // Ow, send the beacon slightly after window.onload.
1826
- addListener("load", function () {
1827
- setTimeout(_sendLux, 200);
1828
- });
1829
- }
1826
+ var sendBeaconAfterMinimumMeasureTime_1 = function () {
1827
+ var elapsedTime = _now();
1828
+ var timeRemaining = userConfig.minMeasureTime - elapsedTime;
1829
+ if (timeRemaining <= 0) {
1830
+ logger.logEvent(LogEvent.OnloadHandlerTriggered, [
1831
+ elapsedTime,
1832
+ userConfig.minMeasureTime,
1833
+ ]);
1834
+ if (document.readyState === "complete") {
1835
+ // If onload has already passed, send the beacon now.
1836
+ _sendLux();
1837
+ } else {
1838
+ // Ow, send the beacon slightly after window.onload.
1839
+ addListener("load", function () {
1840
+ setTimeout(_sendLux, 200);
1841
+ });
1842
+ }
1843
+ } else {
1844
+ // Try again after the minimum measurement time has elapsed
1845
+ setTimeout(sendBeaconAfterMinimumMeasureTime_1, timeRemaining);
1846
+ }
1847
+ };
1848
+ sendBeaconAfterMinimumMeasureTime_1();
1830
1849
  }
1831
1850
  // Add the unload handlers for auto mode, or when LUX.measureUntil is "pagehidden"
1832
1851
  if (userConfig.sendBeaconOnPageHidden) {
@@ -1834,6 +1853,8 @@
1834
1853
  }
1835
1854
  // Regardless of userConfig.auto, we need to register the IX handlers immediately.
1836
1855
  _addIxHandlers();
1856
+ // Set the maximum measurement timer
1857
+ createMaxMeasureTimeout();
1837
1858
  // This is the public API.
1838
1859
  var _LUX = userConfig;
1839
1860
  // Functions
@@ -1841,7 +1862,10 @@
1841
1862
  _LUX.measure = _measure;
1842
1863
  _LUX.init = _init;
1843
1864
  _LUX.markLoadTime = _markLoadTime;
1844
- _LUX.send = _sendLux;
1865
+ _LUX.send = function () {
1866
+ logger.logEvent(LogEvent.SendCalled);
1867
+ _sendLux();
1868
+ };
1845
1869
  _LUX.addData = _addData;
1846
1870
  _LUX.getSessionId = _getUniqueId; // so customers can do their own sampling
1847
1871
  _LUX.getDebug = function () {
@@ -1883,7 +1907,7 @@
1883
1907
  return _LUX;
1884
1908
  })();
1885
1909
  window.LUX = LUX;
1886
- var LUX_t_end = now();
1910
+ LUX_t_end = now();
1887
1911
 
1888
1912
  // ---------------------------------------------------------------------------
1889
1913
  // More settings
@@ -107,20 +107,19 @@
107
107
  <% if edit_link && delete_link %>
108
108
  <%= tag.dd class: "govuk-summary-list__actions" do %>
109
109
  <%= tag.ul class: "govuk-summary-list__actions-list" do %>
110
- <% if item.fetch(:edit, {}).any? %>
110
+ <% if edit_link %>
111
111
  <%= tag.li class: "govuk-summary-list__actions-list-item" do %>
112
112
  <%= edit_link %>
113
113
  <% end %>
114
114
  <% end %>
115
- <% if item.fetch(:delete, {}).any? %>
115
+ <% if delete_link %>
116
116
  <%= tag.li class: "govuk-summary-list__actions-list-item" do %>
117
117
  <%= delete_link %>
118
118
  <% end %>
119
119
  <% end %>
120
120
  <% end %>
121
121
  <% end %>
122
- <% else %>
123
- <% if edit_link || delete_link %>
122
+ <% elsif edit_link || delete_link %>
124
123
  <%= tag.dd class: "govuk-summary-list__actions" do %>
125
124
  <%= edit_link %>
126
125
  <%= delete_link %>
@@ -130,7 +129,7 @@
130
129
  <% end %>
131
130
  <% end %>
132
131
  <% end %>
133
- <% end %>
132
+
134
133
  <%= tag.div block, class: "gem-c-summary__block" if block %>
135
134
  <% end %>
136
135
  <% end %>
@@ -1,3 +1,3 @@
1
1
  module GovukPublishingComponents
2
- VERSION = "29.8.0".freeze
2
+ VERSION = "29.9.0".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: 29.8.0
4
+ version: 29.9.0
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: 2022-05-12 00:00:00.000000000 Z
11
+ date: 2022-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: govuk_app_config
@@ -1893,7 +1893,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1893
1893
  - !ruby/object:Gem::Version
1894
1894
  version: '0'
1895
1895
  requirements: []
1896
- rubygems_version: 3.3.13
1896
+ rubygems_version: 3.3.14
1897
1897
  signing_key:
1898
1898
  specification_version: 4
1899
1899
  summary: A gem to document components in GOV.UK frontend applications