govuk_publishing_components 35.7.0 → 35.8.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: 19aaa8a186568f17fc86baced60aab3d35f790e35f819702736f6dc861f64bcb
4
- data.tar.gz: 947c684323444fb20d04063a801f71868193ca46ee7dfba877a26b05c235ae5f
3
+ metadata.gz: fb44475cd33bb952348a502c37c3efd863abe1725c3eb74e52542b84c333c2b5
4
+ data.tar.gz: 9625af4c341034a1a2b3f690ef08c286baaf740f5aaf972d7f8da5259d90487b
5
5
  SHA512:
6
- metadata.gz: 4c151b005305fa534de28d3769131a41334c3a39b64e89a8f737f6e59747ba03d28d24e62fcdf122fb9b290c5a3d3596842aa973100a208144c83280dcf12fb1
7
- data.tar.gz: 1ef830fa00101728968b9bc2e0d865f923cf00cbd265b33d5e8958f18539938146a1b802e6e6d42a0ee269fc2be3664ba89734d67dbcabef04187a46caa22df8
6
+ metadata.gz: e4ef66116738fae07573951c81aad049cb817f05c525ad987c2060f4617583a7858d9cc01a085d3c9a18a20d6c768fe319754e6885046194ca0bb85c98de5454
7
+ data.tar.gz: 55cebac0cd80a787a1e057cb671ea33b1e0c9e8da029472ba9b1518cf46cc6a0bdd1bf9e15bedf91107e8ec365a703809498cd6bec9be896fddf55283427a0d0
@@ -42,7 +42,6 @@
42
42
  var autoMode = getProperty(obj, "auto", true);
43
43
  return {
44
44
  auto: autoMode,
45
- autoWhenHidden: getProperty(obj, "autoWhenHidden", false),
46
45
  beaconUrl: getProperty(obj, "beaconUrl", "https://lux.speedcurve.com/lux/"),
47
46
  conversions: getProperty(obj, "conversions", undefined),
48
47
  customerid: getProperty(obj, "customerid", undefined),
@@ -54,9 +53,12 @@
54
53
  maxErrors: getProperty(obj, "maxErrors", 5),
55
54
  maxMeasureTime: getProperty(obj, "maxMeasureTime", 60000),
56
55
  minMeasureTime: getProperty(obj, "minMeasureTime", 0),
56
+ newBeaconOnPageShow: getProperty(obj, "newBeaconOnPageShow", false),
57
57
  samplerate: getProperty(obj, "samplerate", 100),
58
58
  sendBeaconOnPageHidden: getProperty(obj, "sendBeaconOnPageHidden", autoMode),
59
+ serverTiming: getProperty(obj, "serverTiming", undefined),
59
60
  trackErrors: getProperty(obj, "trackErrors", true),
61
+ trackHiddenPages: getProperty(obj, "trackHiddenPages", false),
60
62
  pagegroups: getProperty(obj, "pagegroups", undefined),
61
63
  };
62
64
  }
@@ -102,9 +104,9 @@
102
104
  function valuesToString(values) {
103
105
  var strings = [];
104
106
  for (var key in values) {
105
- // Convert all values to strings
107
+ // Convert all values to strings
106
108
  var value = "" + values[key];
107
- // Strip out reserved characters (, and | are used as delimiters)
109
+ // Strip out reserved characters (, and | are used as delimiters)
108
110
  key = key.replace(/,/g, "").replace(/\|/g, "");
109
111
  value = value.replace(/,/g, "").replace(/\|/g, "");
110
112
  strings.push(key + "|" + value);
@@ -115,6 +117,13 @@
115
117
  function floor(x) {
116
118
  return Math.floor(x);
117
119
  }
120
+ var max = Math.max;
121
+ /**
122
+ * Clamp a number so that it is never less than 0
123
+ */
124
+ function clamp(x) {
125
+ return max(0, x);
126
+ }
118
127
 
119
128
  function now() {
120
129
  return Date.now ? Date.now() : +new Date();
@@ -147,10 +156,13 @@
147
156
  function getNavigationEntry() {
148
157
  var navEntries = getEntriesByType("navigation");
149
158
  if (navEntries.length) {
150
- var entry_1 = navEntries[0];
151
- entry_1.navigationStart = 0;
152
- if (typeof entry_1.activationStart === "undefined") {
153
- entry_1.activationStart = 0;
159
+ var nativeEntry = navEntries[0];
160
+ var entry_1 = {
161
+ navigationStart: 0,
162
+ activationStart: 0,
163
+ };
164
+ for (var key in nativeEntry) {
165
+ entry_1[key] = nativeEntry[key];
154
166
  }
155
167
  return entry_1;
156
168
  }
@@ -164,7 +176,7 @@
164
176
  if (__ENABLE_POLYFILLS) {
165
177
  for (var key in timing) {
166
178
  if (typeof timing[key] === "number" && key !== "navigationStart") {
167
- entry[key] = Math.max(0, timing[key] - timing.navigationStart);
179
+ entry[key] = floor(timing[key] - timing.navigationStart);
168
180
  }
169
181
  }
170
182
  }
@@ -189,26 +201,39 @@
189
201
  if (document.visibilityState) {
190
202
  return document.visibilityState === "visible";
191
203
  }
192
- // For browsers that don't support document.visibilityState, we assume the page is visible.
204
+ // For browsers that don't support document.visibilityState, we assume the page is visible.
193
205
  return true;
194
206
  }
195
207
  function onVisible(cb) {
196
- if (isVisible()) {
197
- cb();
208
+ afterPrerender(function () {
209
+ if (isVisible()) {
210
+ cb();
211
+ }
212
+ else {
213
+ var onVisibleCallback_1 = function () {
214
+ if (isVisible()) {
215
+ cb();
216
+ removeEventListener("visibilitychange", onVisibleCallback_1);
217
+ }
218
+ };
219
+ addEventListener("visibilitychange", onVisibleCallback_1, true);
220
+ }
221
+ });
222
+ }
223
+ function afterPrerender(cb) {
224
+ if (document.prerendering) {
225
+ document.addEventListener("prerenderingchange", cb, true);
198
226
  }
199
227
  else {
200
- var onVisibleCallback_1 = function () {
201
- if (isVisible()) {
202
- cb();
203
- removeEventListener("visibilitychange", onVisibleCallback_1);
204
- }
205
- };
206
- addEventListener("visibilitychange", onVisibleCallback_1, true);
228
+ cb();
207
229
  }
208
230
  }
209
231
  function wasPrerendered() {
210
232
  return document.prerendering || getNavigationEntry().activationStart > 0;
211
233
  }
234
+ function wasRedirected() {
235
+ return getNavigationEntry().redirectCount > 0 || timing.redirectEnd > 0;
236
+ }
212
237
 
213
238
  var Flags = {
214
239
  InitCalled: 1 << 0,
@@ -222,6 +247,7 @@
222
247
  PageLabelFromGlobalVariable: 1 << 8,
223
248
  PageLabelFromPagegroup: 1 << 9,
224
249
  PageWasPrerendered: 1 << 10,
250
+ PageWasBfCacheRestored: 1 << 11,
225
251
  };
226
252
  function addFlag(flags, flag) {
227
253
  return flags | flag;
@@ -235,8 +261,8 @@
235
261
  }
236
262
 
237
263
  /**
238
- * Get the interaction attribution name for an element
239
- */
264
+ * Get the interaction attribution name for an element
265
+ */
240
266
  function interactionAttributionForElement(el) {
241
267
  // Our first preference is to use the data-sctrack attribute from anywhere in the tree
242
268
  var trackId = getClosestScTrackAttribute(el);
@@ -291,6 +317,7 @@
291
317
  UnloadHandlerTriggered: 10,
292
318
  OnloadHandlerTriggered: 11,
293
319
  MarkLoadTimeCalled: 12,
320
+ SendCancelledPageHidden: 13,
294
321
  // Data collection events
295
322
  SessionIsSampled: 21,
296
323
  SessionIsNotSampled: 22,
@@ -315,39 +342,45 @@
315
342
  PaintTimingNotSupported: 72,
316
343
  };
317
344
  var Logger = /** @class */ (function () {
318
- function Logger() {
319
- this.events = [];
320
- }
321
- Logger.prototype.logEvent = function (event, args) {
322
- if (args === void 0) { args = []; }
323
- this.events.push([now(), event, args]);
324
- };
325
- Logger.prototype.getEvents = function () {
326
- return this.events;
327
- };
328
- return Logger;
345
+ function Logger() {
346
+ this.events = [];
347
+ }
348
+ Logger.prototype.logEvent = function (event, args) {
349
+ if (args === void 0) { args = []; }
350
+ this.events.push([now(), event, args]);
351
+ };
352
+ Logger.prototype.getEvents = function () {
353
+ return this.events;
354
+ };
355
+ return Logger;
329
356
  }());
330
357
  var sessionValue = 0;
331
358
  var sessionEntries = [];
359
+ var maximumSessionValue = 0;
332
360
  function addEntry$2(entry) {
333
361
  if (!entry.hadRecentInput) {
334
362
  var firstEntry = sessionEntries[0];
335
363
  var latestEntry = sessionEntries[sessionEntries.length - 1];
336
364
  if (sessionEntries.length &&
337
365
  (entry.startTime - latestEntry.startTime >= 1000 ||
338
- entry.startTime - firstEntry.startTime >= 5000)) {
339
- reset$1();
366
+ entry.startTime - firstEntry.startTime >= 5000)) {
367
+ sessionValue = entry.value;
368
+ sessionEntries = [entry];
340
369
  }
341
- sessionValue += entry.value;
342
- sessionEntries.push(entry);
370
+ else {
371
+ sessionValue += entry.value;
372
+ sessionEntries.push(entry);
373
+ }
374
+ maximumSessionValue = max(maximumSessionValue, sessionValue);
343
375
  }
344
376
  }
345
377
  function reset$1() {
346
378
  sessionValue = 0;
347
379
  sessionEntries = [];
380
+ maximumSessionValue = 0;
348
381
  }
349
382
  function getCLS() {
350
- return sessionValue;
383
+ return maximumSessionValue;
351
384
  }
352
385
 
353
386
  /**
@@ -372,7 +405,7 @@
372
405
  var duration = entry.duration, startTime = entry.startTime, interactionId = entry.interactionId;
373
406
  var existingEntry = slowestEntriesMap[interactionId];
374
407
  if (existingEntry) {
375
- existingEntry.duration = Math.max(duration, existingEntry.duration);
408
+ existingEntry.duration = max(duration, existingEntry.duration);
376
409
  }
377
410
  else {
378
411
  interactionCountEstimate++;
@@ -405,44 +438,6 @@
405
438
  return interactionCountEstimate;
406
439
  }
407
440
 
408
- /**
409
- * Get the number of milliseconds between navigationStart and the given PerformanceNavigationTiming key
410
- */
411
- function getNavTimingValue(key) {
412
- var navEntry = getNavigationEntry();
413
- var relativeTo = key === "activationStart" ? 0 : navEntry.activationStart;
414
- if (typeof navEntry[key] === "number") {
415
- return Math.max(0, navEntry[key] - relativeTo);
416
- }
417
- return undefined;
418
- }
419
-
420
- /******************************************************************************
421
- Copyright (c) Microsoft Corporation.
422
-
423
- Permission to use, copy, modify, and/or distribute this software for any
424
- purpose with or without fee is hereby granted.
425
-
426
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
427
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
428
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
429
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
430
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
431
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
432
- PERFORMANCE OF THIS SOFTWARE.
433
- ***************************************************************************** */
434
-
435
- var __assign = function() {
436
- __assign = Object.assign || function __assign(t) {
437
- for (var s, i = 1, n = arguments.length; i < n; i++) {
438
- s = arguments[i];
439
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
440
- }
441
- return t;
442
- };
443
- return __assign.apply(this, arguments);
444
- };
445
-
446
441
  var ALL_ENTRIES = [];
447
442
  function observe(type, callback, options) {
448
443
  if (typeof PerformanceObserver === "function" &&
@@ -450,10 +445,10 @@
450
445
  var po = new PerformanceObserver(function (list) {
451
446
  list.getEntries().forEach(function (entry) { return callback(entry); });
452
447
  });
453
- po.observe(__assign({ type: type, buffered: true }, options));
454
- return po;
455
- }
456
- return undefined;
448
+ po.observe(Object.assign({ type: type, buffered: true }, { options: options }));
449
+ return po;
450
+ }
451
+ return undefined;
457
452
  }
458
453
  function getEntries(type) {
459
454
  return ALL_ENTRIES.filter(function (entry) { return entry.entryType === type; });
@@ -465,6 +460,39 @@
465
460
  ALL_ENTRIES.splice(0);
466
461
  }
467
462
 
463
+ /**
464
+ * A server timing metric that has its value set to the duration field
465
+ */
466
+ var TYPE_DURATION = "r";
467
+ /**
468
+ * When a description metric has no value, we consider it to be a boolean and set it to this value.
469
+ */
470
+ var BOOLEAN_TRUE_VALUE = "true";
471
+ function getKeyValuePairs(config, serverTiming) {
472
+ var pairs = {};
473
+ serverTiming.forEach(function (stEntry) {
474
+ var name = stEntry.name;
475
+ var description = stEntry.description;
476
+ if (name in config) {
477
+ var spec = config[name];
478
+ var multiplier = spec[1];
479
+ if (spec[0] === TYPE_DURATION) {
480
+ pairs[name] = stEntry.duration * (multiplier || 1);
481
+ }
482
+ else if (description && multiplier) {
483
+ var numericValue = parseFloat(description);
484
+ if (!isNaN(numericValue)) {
485
+ pairs[name] = numericValue * multiplier;
486
+ }
487
+ }
488
+ else {
489
+ pairs[name] = description || BOOLEAN_TRUE_VALUE;
490
+ }
491
+ }
492
+ });
493
+ return pairs;
494
+ }
495
+
468
496
  function getMatchesFromPatternMap(patternMap, hostname, pathname, firstOnly) {
469
497
  var matches = [];
470
498
  for (var key in patternMap) {
@@ -496,7 +524,7 @@
496
524
  return regex.test(hostname + pathname);
497
525
  }
498
526
  function createRegExpFromPattern(pattern) {
499
- return new RegExp("^" + escapeStringForRegExp(pattern).replaceAll("*", ".*") + "$", "i");
527
+ return new RegExp("^" + escapeStringForRegExp(pattern).replace(/\*/g, ".*") + "$", "i");
500
528
  }
501
529
  function escapeStringForRegExp(str) {
502
530
  // Note: we don't escape * because it's our own special symbol!
@@ -514,7 +542,7 @@
514
542
  // -------------------------------------------------------------------------
515
543
  /// End
516
544
  // -------------------------------------------------------------------------
517
- var SCRIPT_VERSION = "308";
545
+ var SCRIPT_VERSION = "309";
518
546
  var logger = new Logger();
519
547
  var globalConfig = fromObject(LUX);
520
548
  logger.logEvent(LogEvent.EvaluationStart, [SCRIPT_VERSION]);
@@ -585,7 +613,7 @@
585
613
  observe("first-input", function (entry) {
586
614
  var fid = entry.processingStart - entry.startTime;
587
615
  if (!gFirstInputDelay || gFirstInputDelay < fid) {
588
- gFirstInputDelay = fid;
616
+ gFirstInputDelay = floor(fid);
589
617
  }
590
618
  // Allow first-input events to be considered for INP
591
619
  addEntry$1(entry);
@@ -612,7 +640,13 @@
612
640
  var gUid = refreshUniqueId(gSyncId); // cookie for this session ("Unique ID")
613
641
  var gCustomerDataTimeout; // setTimeout timer for sending a Customer Data beacon after onload
614
642
  var gMaxMeasureTimeout; // setTimeout timer for sending the beacon after a maximum measurement time
615
- var navEntry = getNavigationEntry();
643
+ var pageRestoreTime; // ms since navigationStart representing when the page was restored from the bfcache
644
+ /**
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; };
616
650
  if (_sample()) {
617
651
  logger.logEvent(LogEvent.SessionIsSampled, [globalConfig.samplerate]);
618
652
  }
@@ -713,7 +747,7 @@
713
747
  var startMark = _getMark(START_MARK);
714
748
  // For SPA page views, we use our internal mark as a reference point
715
749
  if (startMark && !absolute) {
716
- return sinceNavigationStart - startMark.startTime;
750
+ return floor(sinceNavigationStart - startMark.startTime);
717
751
  }
718
752
  // For "regular" page views, we can use performance.now() if it's available...
719
753
  return sinceNavigationStart;
@@ -796,6 +830,7 @@
796
830
  }
797
831
  // ...Otherwise provide a polyfill
798
832
  if (__ENABLE_POLYFILLS) {
833
+ var navEntry = getNavigationEntry();
799
834
  var startTime = typeof startMarkName === "number" ? startMarkName : 0;
800
835
  var endTime = typeof endMarkName === "number" ? endMarkName : _now();
801
836
  var throwError = function (missingMark) {
@@ -906,7 +941,7 @@
906
941
  hUT[name] = { startTime: startTime };
907
942
  }
908
943
  else {
909
- hUT[name].startTime = Math.max(startTime, hUT[name].startTime);
944
+ hUT[name].startTime = max(startTime, hUT[name].startTime);
910
945
  }
911
946
  });
912
947
  // measures
@@ -939,7 +974,7 @@
939
974
  function elementTimingValues() {
940
975
  var aET = [];
941
976
  var startMark = _getMark(START_MARK);
942
- var tZero = startMark ? startMark.startTime : 0;
977
+ var tZero = startMark ? startMark.startTime : getZeroTime();
943
978
  getEntries("element").forEach(function (entry) {
944
979
  if (entry.identifier && entry.startTime) {
945
980
  logger.logEvent(LogEvent.PerformanceEntryProcessed, [entry]);
@@ -1164,11 +1199,11 @@
1164
1199
  var nThis = ("" + gUid).substr(-2); // number for THIS page - from 00 to 99
1165
1200
  return parseInt(nThis) < globalConfig.samplerate;
1166
1201
  }
1167
- // _init()
1168
- // Use this function in Single Page Apps to reset things.
1169
- // This function should ONLY be called within a SPA!
1170
- // Otherwise, you might clear marks & measures that were set by a shim.
1171
- function _init() {
1202
+ /**
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
+ */
1206
+ function _init(startTime) {
1172
1207
  // Some customers (incorrectly) call LUX.init on the very first page load of a SPA. This would
1173
1208
  // cause some first-page-only data (like paint metrics) to be lost. To prevent this, we silently
1174
1209
  // bail from this function when we detect an unnecessary LUX.init call.
@@ -1176,6 +1211,14 @@
1176
1211
  if (!endMark) {
1177
1212
  return;
1178
1213
  }
1214
+ // Mark the "navigationStart" for this SPA page. A start time can be passed through, for example
1215
+ // to set a page's start time as an event timestamp.
1216
+ if (startTime) {
1217
+ _mark(START_MARK, { startTime: startTime });
1218
+ }
1219
+ else {
1220
+ _mark(START_MARK);
1221
+ }
1179
1222
  logger.logEvent(LogEvent.InitCalled);
1180
1223
  // Clear all interactions from the previous "page".
1181
1224
  _clearIx();
@@ -1197,8 +1240,6 @@
1197
1240
  // Clear flags then set the flag that init was called (ie, this is a SPA).
1198
1241
  gFlags = 0;
1199
1242
  gFlags = addFlag(gFlags, Flags.InitCalled);
1200
- // Mark the "navigationStart" for this SPA page.
1201
- _mark(START_MARK);
1202
1243
  // Reset the maximum measure timeout
1203
1244
  createMaxMeasureTimeout();
1204
1245
  }
@@ -1305,8 +1346,9 @@
1305
1346
  var ns = timing.navigationStart;
1306
1347
  var startMark = _getMark(START_MARK);
1307
1348
  var endMark = _getMark(END_MARK);
1308
- if (startMark && endMark) {
1349
+ if (startMark && endMark && !pageRestoreTime) {
1309
1350
  // This is a SPA page view, so send the SPA marks & measures instead of Nav Timing.
1351
+ // Note: pageRestoreTime indicates this was a bfcache restore, which we don't want to treat as a SPA.
1310
1352
  var start = floor(startMark.startTime); // the start mark is "zero"
1311
1353
  ns += start; // "navigationStart" for a SPA is the real navigationStart plus the start mark
1312
1354
  var end = floor(endMark.startTime) - start; // delta from start mark
@@ -1322,21 +1364,33 @@
1322
1364
  }
1323
1365
  else if (performance.timing) {
1324
1366
  // Return the real Nav Timing metrics because this is the "main" page view (not a SPA)
1367
+ var navEntry_1 = getNavigationEntry();
1325
1368
  var startRender = getStartRender();
1326
1369
  var fcp = getFcp();
1327
1370
  var lcp = getLcp();
1328
1371
  var prefixNTValue = function (key, prefix) {
1329
- var value = getNavTimingValue(key);
1330
- if (typeof value === "undefined") {
1331
- return "";
1372
+ // activationStart is always absolute. Other values are relative to activationStart.
1373
+ var zero = key === "activationStart" ? 0 : getZeroTime();
1374
+ if (typeof navEntry_1[key] === "number") {
1375
+ var value = clamp(floor(navEntry_1[key] - zero));
1376
+ return prefix + value;
1332
1377
  }
1333
- return prefix + value;
1378
+ return "";
1334
1379
  };
1380
+ var loadEventStartStr = prefixNTValue("loadEventStart", "ls");
1381
+ var loadEventEndStr = prefixNTValue("loadEventEnd", "le");
1382
+ if (pageRestoreTime && startMark && endMark) {
1383
+ // For bfcache restores, we set the load time to the time it took for the page to be restored.
1384
+ var loadTime = floor(endMark.startTime - startMark.startTime);
1385
+ loadEventStartStr = "ls" + loadTime;
1386
+ loadEventEndStr = "le" + loadTime;
1387
+ }
1388
+ var redirect = wasRedirected();
1335
1389
  s = [
1336
1390
  ns,
1337
1391
  prefixNTValue("activationStart", "as"),
1338
- prefixNTValue("redirectStart", "rs"),
1339
- prefixNTValue("redirectEnd", "re"),
1392
+ redirect ? prefixNTValue("redirectStart", "rs") : "",
1393
+ redirect ? prefixNTValue("redirectEnd", "re") : "",
1340
1394
  prefixNTValue("fetchStart", "fs"),
1341
1395
  prefixNTValue("domainLookupStart", "ds"),
1342
1396
  prefixNTValue("domainLookupEnd", "de"),
@@ -1350,11 +1404,11 @@
1350
1404
  prefixNTValue("domContentLoadedEventStart", "os"),
1351
1405
  prefixNTValue("domContentLoadedEventEnd", "oe"),
1352
1406
  prefixNTValue("domComplete", "oc"),
1353
- prefixNTValue("loadEventStart", "ls"),
1354
- prefixNTValue("loadEventEnd", "le"),
1355
- typeof startRender !== "undefined" ? "sr" + startRender : "",
1356
- typeof fcp !== "undefined" ? "fc" + fcp : "",
1357
- typeof lcp !== "undefined" ? "lc" + lcp : "",
1407
+ loadEventStartStr,
1408
+ loadEventEndStr,
1409
+ typeof startRender !== "undefined" ? "sr" + clamp(startRender) : "",
1410
+ typeof fcp !== "undefined" ? "fc" + clamp(fcp) : "",
1411
+ typeof lcp !== "undefined" ? "lc" + clamp(lcp) : "",
1358
1412
  ].join("");
1359
1413
  }
1360
1414
  else if (endMark) {
@@ -1378,7 +1432,7 @@
1378
1432
  for (var i = 0; i < paintEntries.length; i++) {
1379
1433
  var entry = paintEntries[i];
1380
1434
  if (entry.name === "first-contentful-paint") {
1381
- return floor(entry.startTime);
1435
+ return floor(entry.startTime - getZeroTime());
1382
1436
  }
1383
1437
  }
1384
1438
  return undefined;
@@ -1389,7 +1443,7 @@
1389
1443
  if (lcpEntries.length) {
1390
1444
  var lastEntry = lcpEntries[lcpEntries.length - 1];
1391
1445
  logger.logEvent(LogEvent.PerformanceEntryProcessed, [lastEntry]);
1392
- return floor(lastEntry.startTime);
1446
+ return floor(lastEntry.startTime - getZeroTime());
1393
1447
  }
1394
1448
  return undefined;
1395
1449
  }
@@ -1402,7 +1456,7 @@
1402
1456
  if (paintEntries.length) {
1403
1457
  // If the Paint Timing API is supported, use the value of the first paint event
1404
1458
  var paintValues = paintEntries.map(function (entry) { return entry.startTime; });
1405
- return floor(Math.min.apply(null, paintValues));
1459
+ return floor(Math.min.apply(null, paintValues) - getZeroTime());
1406
1460
  }
1407
1461
  }
1408
1462
  if (performance.timing && timing.msFirstPaint && __ENABLE_POLYFILLS) {
@@ -1474,17 +1528,17 @@
1474
1528
  }
1475
1529
  function docHeight(doc) {
1476
1530
  var body = doc.body, docelem = doc.documentElement;
1477
- var height = Math.max(body ? body.scrollHeight : 0, body ? body.offsetHeight : 0, docelem ? docelem.clientHeight : 0, docelem ? docelem.scrollHeight : 0, docelem ? docelem.offsetHeight : 0);
1531
+ var height = max(body ? body.scrollHeight : 0, body ? body.offsetHeight : 0, docelem ? docelem.clientHeight : 0, docelem ? docelem.scrollHeight : 0, docelem ? docelem.offsetHeight : 0);
1478
1532
  return height;
1479
1533
  }
1480
1534
  function docWidth(doc) {
1481
1535
  var body = doc.body, docelem = doc.documentElement;
1482
- var width = Math.max(body ? body.scrollWidth : 0, body ? body.offsetWidth : 0, docelem ? docelem.clientWidth : 0, docelem ? docelem.scrollWidth : 0, docelem ? docelem.offsetWidth : 0);
1536
+ var width = max(body ? body.scrollWidth : 0, body ? body.offsetWidth : 0, docelem ? docelem.clientWidth : 0, docelem ? docelem.scrollWidth : 0, docelem ? docelem.offsetWidth : 0);
1483
1537
  return width;
1484
1538
  }
1485
1539
  // Return the main HTML document transfer size (in bytes).
1486
1540
  function docSize() {
1487
- return navEntry.encodedBodySize || 0;
1541
+ return getNavigationEntry().encodedBodySize || 0;
1488
1542
  }
1489
1543
  // Return the connection type based on Network Information API.
1490
1544
  // Note this API is in flux.
@@ -1624,6 +1678,10 @@
1624
1678
  // Beacon back the LUX data.
1625
1679
  function _sendLux() {
1626
1680
  var _a;
1681
+ if (!isVisible() && !globalConfig.trackHiddenPages) {
1682
+ logger.logEvent(LogEvent.SendCancelledPageHidden);
1683
+ return;
1684
+ }
1627
1685
  clearMaxMeasureTimeout();
1628
1686
  var customerid = getCustomerId();
1629
1687
  if (!customerid ||
@@ -1663,6 +1721,15 @@
1663
1721
  if (wasPrerendered()) {
1664
1722
  gFlags = addFlag(gFlags, Flags.PageWasPrerendered);
1665
1723
  }
1724
+ if (globalConfig.serverTiming) {
1725
+ var navEntry = getNavigationEntry();
1726
+ if (navEntry.serverTiming) {
1727
+ var stPairs = getKeyValuePairs(globalConfig.serverTiming, navEntry.serverTiming);
1728
+ for (var name_2 in stPairs) {
1729
+ _addData(name_2, stPairs[name_2]);
1730
+ }
1731
+ }
1732
+ }
1666
1733
  if (LUX.conversions) {
1667
1734
  getMatchesFromPatternMap(LUX.conversions, location.hostname, location.pathname).forEach(function (conversion) {
1668
1735
  LUX.addData(conversion, BOOLEAN_TRUE);
@@ -1757,7 +1824,7 @@
1757
1824
  var sIx = ixValues(); // Interaction Metrics
1758
1825
  var INP = getINP();
1759
1826
  if (sIx) {
1760
- var beaconUrl = _getBeaconUrl(getUpdatedCustomData()) +
1827
+ var beaconUrl = _getBeaconUrl(getUpdatedCustomData()) +
1761
1828
  "&IX=" +
1762
1829
  sIx +
1763
1830
  (typeof gFirstInputDelay !== "undefined" ? "&FID=" + gFirstInputDelay : "") +
@@ -2031,8 +2098,8 @@
2031
2098
  setTimeout(sendBeaconAfterMinimumMeasureTime_1, timeRemaining);
2032
2099
  }
2033
2100
  };
2034
- if (globalConfig.autoWhenHidden) {
2035
- // The autoWhenHidden config forces the beacon to be sent even when the page is not visible.
2101
+ if (globalConfig.trackHiddenPages) {
2102
+ // The trackHiddenPages config forces the beacon to be sent even when the page is not visible.
2036
2103
  sendBeaconAfterMinimumMeasureTime_1();
2037
2104
  }
2038
2105
  else {
@@ -2040,6 +2107,31 @@
2040
2107
  onVisible(sendBeaconAfterMinimumMeasureTime_1);
2041
2108
  }
2042
2109
  }
2110
+ // When newBeaconOnPageShow = true, we initiate a new page view whenever a page is restored from
2111
+ // bfcache. Since we have no "onload" event to hook into after a bfcache restore, we rely on the
2112
+ // unload and maxMeasureTime handlers to send the beacon.
2113
+ if (globalConfig.newBeaconOnPageShow) {
2114
+ window.addEventListener("pageshow", function (event) {
2115
+ if (event.persisted) {
2116
+ // Record the timestamp of the bfcache restore
2117
+ pageRestoreTime = event.timeStamp;
2118
+ // In Chromium, document.visibilityState is still "hidden" when pageshow fires after a bfcache
2119
+ // restore. Wrapping this in a setTimeout ensures the browser has enough time to update the
2120
+ // visibility.
2121
+ // See https://bugs.chromium.org/p/chromium/issues/detail?id=1133363
2122
+ setTimeout(function () {
2123
+ if (gbLuxSent) {
2124
+ // If the beacon was already sent for this page, we start a new page view and mark the
2125
+ // load time as the time it took to restore the page.
2126
+ _init(pageRestoreTime);
2127
+ _markLoadTime();
2128
+ }
2129
+ // Flag the current page as a bfcache restore
2130
+ gFlags = addFlag(gFlags, Flags.PageWasBfCacheRestored);
2131
+ }, 0);
2132
+ }
2133
+ });
2134
+ }
2043
2135
  // Add the unload handlers when sendBeaconOnPageHidden is enabled
2044
2136
  if (globalConfig.sendBeaconOnPageHidden) {
2045
2137
  _addUnloadHandlers();
@@ -8,10 +8,14 @@
8
8
  }
9
9
 
10
10
  .gem-c-document-list__item {
11
- margin-bottom: govuk-spacing(5);
11
+ margin-top: govuk-spacing(5);
12
12
  padding-top: govuk-spacing(2);
13
13
  border-top: 1px solid $govuk-border-colour;
14
14
  list-style: none;
15
+
16
+ &:first-child {
17
+ margin-top: 0;
18
+ }
15
19
  }
16
20
 
17
21
  .gem-c-document-list__item-title {
@@ -86,14 +90,6 @@
86
90
  }
87
91
  }
88
92
 
89
- .gem-c-document-list--bottom-margin {
90
- margin-bottom: govuk-spacing(4);
91
- }
92
-
93
- .gem-c-document-list--top-margin {
94
- margin-top: govuk-spacing(4);
95
- }
96
-
97
93
  .gem-c-document-list__multi-list {
98
94
  width: 100%;
99
95
  margin-right: 25px;
@@ -9,6 +9,10 @@
9
9
  height: govuk-spacing(2);
10
10
  }
11
11
 
12
+ .gem-c-layout-for-public__blue-bar-wrapper--browse {
13
+ background-color: #263135;
14
+ }
15
+
12
16
  .js-enabled .gem-c-layout-for-public__global-banner-wrapper {
13
17
  margin-top: - govuk-spacing(2);
14
18
  min-height: govuk-spacing(2);
@@ -1,6 +1,7 @@
1
- <%
1
+ <%
2
2
  add_gem_component_stylesheet("table")
3
3
  add_gem_component_stylesheet("select")
4
+ add_gem_component_stylesheet("summary-list")
4
5
  %>
5
6
 
6
7
  <% content_for :title, "Component audit" %>
@@ -1,14 +1,15 @@
1
1
  <%
2
2
  add_gem_component_stylesheet("document-list")
3
3
 
4
+ local_assigns[:margin_bottom] ||= 5
5
+ shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new(local_assigns)
4
6
  items ||= []
5
7
 
6
- classes = "gem-c-document-list"
7
- classes << " gem-c-document-list--top-margin" if local_assigns[:margin_top]
8
- classes << " gem-c-document-list--bottom-margin" if local_assigns[:margin_bottom]
9
- classes << " gem-c-document-list--no-underline" if local_assigns[:remove_underline]
10
- classes << " gem-c-document-list--no-top-border" if local_assigns[:remove_top_border]
11
- classes << " gem-c-document-list--no-top-border-first-child" if local_assigns[:remove_top_border_from_first_child]
8
+ classes = %w[gem-c-document-list]
9
+ classes << "gem-c-document-list--no-underline" if local_assigns[:remove_underline]
10
+ classes << "gem-c-document-list--no-top-border" if local_assigns[:remove_top_border]
11
+ classes << "gem-c-document-list--no-top-border-first-child" if local_assigns[:remove_top_border_from_first_child]
12
+ classes << shared_helper.get_margin_bottom
12
13
 
13
14
  within_multitype_list ||= false
14
15
  within_multitype_list_class = " gem-c-document-list__multi-list" if within_multitype_list
@@ -19,7 +20,7 @@
19
20
  %>
20
21
  <% if items.any? %>
21
22
  <% unless within_multitype_list %>
22
- <ul class="<%= classes %>">
23
+ <ul class="<%= classes.join(" ") %>">
23
24
  <% end %>
24
25
  <% items.each do |item| %>
25
26
  <% highlight_class = " gem-c-document-list__item--highlight" if item[:highlight] %>
@@ -3,9 +3,11 @@
3
3
 
4
4
  emergency_banner ||= nil
5
5
  full_width ||= false
6
+ blue_bar ||= local_assigns.include?(:blue_bar) ? local_assigns[:blue_bar] : !full_width
6
7
  global_bar ||= nil
7
8
  html_lang ||= "en"
8
9
  layout_helper = GovukPublishingComponents::Presenters::PublicLayoutHelper.new(local_assigns)
10
+ blue_bar_background_colour = layout_helper.blue_bar_background_colours.include?(blue_bar_background_colour) ? blue_bar_background_colour : nil
9
11
  logo_link ||= "/"
10
12
  navigation_items ||= []
11
13
  omit_feedback_form ||= false
@@ -44,6 +46,9 @@
44
46
  blue_bar_dedupe = !full_width && global_bar.present?
45
47
  body_css_classes = %w(gem-c-layout-for-public govuk-template__body)
46
48
  body_css_classes << "draft" if draft_watermark
49
+
50
+ blue_bar_wrapper_classes = %w()
51
+ blue_bar_wrapper_classes << "gem-c-layout-for-public__blue-bar-wrapper--#{blue_bar_background_colour}" if blue_bar_background_colour
47
52
  -%>
48
53
  <!DOCTYPE html>
49
54
  <!--[if lt IE 9]><html class="lte-ie8 govuk-template" lang="<%= html_lang %>"><![endif]-->
@@ -117,8 +122,10 @@
117
122
 
118
123
  <%= raw(emergency_banner) %>
119
124
 
120
- <% unless full_width %>
121
- <div class="gem-c-layout-for-public__blue-bar govuk-width-container"></div>
125
+ <% if (blue_bar && !global_bar.present?) || (blue_bar_dedupe) %>
126
+ <%= content_tag(:div, class: blue_bar_wrapper_classes) do %>
127
+ <div class="gem-c-layout-for-public__blue-bar govuk-width-container"></div>
128
+ <% end %>
122
129
  <% end %>
123
130
 
124
131
  <% if global_bar.present? %>
@@ -20,6 +20,11 @@
20
20
  classes << shared_helper.get_margin_bottom if local_assigns[:margin_bottom]
21
21
 
22
22
  ga4_tracking ||= false
23
+ ga4_object = {
24
+ event_name: "navigation",
25
+ type: "content",
26
+ section: "Top"
27
+ }.to_json
23
28
  %>
24
29
  <%= content_tag :div, class: classes, data: { module: "gem-toggle metadata" } do %>
25
30
  <dl class="gem-c-metadata__list" data-module="gem-track-click">
@@ -48,19 +53,15 @@
48
53
  <dd class="gem-c-metadata__definition">
49
54
  <%= last_updated %>
50
55
  <% if local_assigns.include?(:see_updates_link) %>
51
- &#8212; <a href="#full-publication-update-history" class="gem-c-metadata__definition-link govuk-!-display-none-print js-see-all-updates-link"
52
- data-track-category="content-history"
53
- data-track-action="see-all-updates-link-clicked"
54
- data-track-label="history"
55
- <% if ga4_tracking %>
56
- data-module="ga4-link-tracker"
57
- data-ga4-link="<%= {
58
- event_name: "navigation",
59
- type: "content",
60
- section: "Top"
61
- }.to_json %>"
62
- <% end%>
63
- >
56
+ &#8212; <a href="#full-publication-update-history"
57
+ class="gem-c-metadata__definition-link govuk-!-display-none-print js-see-all-updates-link"
58
+ data-track-category="content-history"
59
+ data-track-action="see-all-updates-link-clicked"
60
+ data-track-label="history"
61
+ <% if ga4_tracking %>
62
+ data-module="ga4-link-tracker"
63
+ data-ga4-link="<%= ga4_object %>"
64
+ <% end%>>
64
65
  <%= t("components.metadata.see_all_updates") %>
65
66
  </a>
66
67
  <% end %>
@@ -74,7 +75,12 @@
74
75
  %>
75
76
  <% if definition.any? %>
76
77
  <dt class="gem-c-metadata__term"><%= title %>:</dt>
77
- <dd class="gem-c-metadata__definition">
78
+ <dd class="gem-c-metadata__definition"
79
+ <% if ga4_tracking %>
80
+ data-module="ga4-link-tracker"
81
+ data-ga4-track-links-only
82
+ data-ga4-link="<%= ga4_object %>"
83
+ <% end%>>
78
84
  <%= render 'govuk_publishing_components/components/metadata/sentence', items: definition, toggle_id: "#{index}-#{SecureRandom.hex(4)}" %>
79
85
  </dd>
80
86
  <% end %>
@@ -26,7 +26,7 @@
26
26
  <% if ga4_tracking
27
27
  ga4_attributes = {
28
28
  event_name: "navigation",
29
- type: "related content",
29
+ type: "part of",
30
30
  index:{
31
31
  "index_link": "1"
32
32
  },
@@ -56,7 +56,7 @@
56
56
  <% if ga4_tracking
57
57
  ga4_attributes = {
58
58
  event_name: "navigation",
59
- type: "related content",
59
+ type: "part of",
60
60
  index:{
61
61
  "index_link": (index + 1).to_s
62
62
  },
@@ -37,6 +37,23 @@ examples:
37
37
  metadata:
38
38
  public_updated_at: 2016-09-05 16:48:27
39
39
  document_type: 'Statutory guidance'
40
+ with_margin:
41
+ description: The component accepts a number for margin bottom from `0` to `9` (`0px` to `60px`) using the [GOV.UK Frontend spacing scale](https://design-system.service.gov.uk/styles/spacing/#the-responsive-spacing-scale). It defaults to having a margin bottom of 5 (25px).
42
+ data:
43
+ margin_bottom: 9
44
+ items:
45
+ - link:
46
+ text: 'Alternative provision'
47
+ path: '/government/publications/alternative-provision'
48
+ metadata:
49
+ public_updated_at: 2016-06-27 10:29:44
50
+ document_type: 'Statutory guidance'
51
+ - link:
52
+ text: 'Behaviour and discipline in schools: guide for governing bodies'
53
+ path: '/government/publications/behaviour-and-discipline-in-schools-guidance-for-governing-bodies'
54
+ metadata:
55
+ public_updated_at: 2015-09-24 16:42:48
56
+ document_type: 'Statutory guidance'
40
57
  without_links:
41
58
  data:
42
59
  items:
@@ -27,6 +27,12 @@ examples:
27
27
  description: This allows the header to be omitted which is currently used when rendering CSV previews from Whitehall
28
28
  data:
29
29
  omit_header: true
30
+ blue_bar_background:
31
+ description: For use when a page has a heading component with a background colour.
32
+ data:
33
+ full_width: true
34
+ blue_bar: true
35
+ blue_bar_background_colour: "no"
30
36
  omit_feedback:
31
37
  description: This allows the feedback form to be omitted
32
38
  data:
@@ -87,7 +87,7 @@ module GovukPublishingComponents
87
87
  end
88
88
 
89
89
  def viewing_component_guide?
90
- request.path.include?("/component-guide")
90
+ request&.path&.include?("/component-guide")
91
91
  end
92
92
  end
93
93
  end
@@ -1,6 +1,7 @@
1
1
  module GovukPublishingComponents
2
2
  module Presenters
3
3
  class PublicLayoutHelper
4
+ BLUE_BAR_BACKGROUND_COLOURS = %w[browse].freeze
4
5
  FOOTER_NAVIGATION_COLUMNS = [2, 1].freeze
5
6
  FOOTER_TRACK_ACTIONS = %w[topicsLink governmentactivityLink].freeze
6
7
  FOOTER_META = {
@@ -69,6 +70,10 @@ module GovukPublishingComponents
69
70
  FOOTER_TRACK_ACTIONS
70
71
  end
71
72
 
73
+ def blue_bar_background_colours
74
+ BLUE_BAR_BACKGROUND_COLOURS
75
+ end
76
+
72
77
  def generate_data_attribute(link, track_action)
73
78
  {
74
79
  track_category: "footerClicked",
@@ -1,3 +1,3 @@
1
1
  module GovukPublishingComponents
2
- VERSION = "35.7.0".freeze
2
+ VERSION = "35.8.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: 35.7.0
4
+ version: 35.8.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: 2023-06-14 00:00:00.000000000 Z
11
+ date: 2023-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: govuk_app_config