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 +4 -4
- data/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-reporter.js +206 -114
- data/app/assets/stylesheets/govuk_publishing_components/components/_document-list.scss +5 -9
- data/app/assets/stylesheets/govuk_publishing_components/components/_layout-for-public.scss +4 -0
- data/app/views/govuk_publishing_components/audit/show.html.erb +2 -1
- data/app/views/govuk_publishing_components/components/_document_list.html.erb +8 -7
- data/app/views/govuk_publishing_components/components/_layout_for_public.html.erb +9 -2
- data/app/views/govuk_publishing_components/components/_metadata.html.erb +20 -14
- data/app/views/govuk_publishing_components/components/_step_by_step_nav_related.html.erb +2 -2
- data/app/views/govuk_publishing_components/components/docs/document_list.yml +17 -0
- data/app/views/govuk_publishing_components/components/docs/layout_for_public.yml +6 -0
- data/lib/govuk_publishing_components/app_helpers/asset_helper.rb +1 -1
- data/lib/govuk_publishing_components/presenters/public_layout_helper.rb +5 -0
- data/lib/govuk_publishing_components/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb44475cd33bb952348a502c37c3efd863abe1725c3eb74e52542b84c333c2b5
|
4
|
+
data.tar.gz: 9625af4c341034a1a2b3f690ef08c286baaf740f5aaf972d7f8da5259d90487b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
107
|
+
// Convert all values to strings
|
106
108
|
var value = "" + values[key];
|
107
|
-
|
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
|
151
|
-
entry_1
|
152
|
-
|
153
|
-
|
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] =
|
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
|
-
|
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
|
-
|
197
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
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
|
-
|
339
|
-
|
366
|
+
entry.startTime - firstEntry.startTime >= 5000)) {
|
367
|
+
sessionValue = entry.value;
|
368
|
+
sessionEntries = [entry];
|
340
369
|
}
|
341
|
-
|
342
|
-
|
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
|
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 =
|
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
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
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).
|
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 = "
|
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
|
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 =
|
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 :
|
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
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
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
|
-
|
1330
|
-
|
1331
|
-
|
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
|
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
|
-
|
1354
|
-
|
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 =
|
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 =
|
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
|
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
|
-
|
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.
|
2035
|
-
// The
|
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-
|
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,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 =
|
7
|
-
classes << "
|
8
|
-
classes << "
|
9
|
-
classes << "
|
10
|
-
classes <<
|
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
|
-
<%
|
121
|
-
|
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
|
-
— <a href="#full-publication-update-history"
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
section: "Top"
|
61
|
-
}.to_json %>"
|
62
|
-
<% end%>
|
63
|
-
>
|
56
|
+
— <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: "
|
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: "
|
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:
|
@@ -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",
|
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.
|
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-
|
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
|