Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to LUX 305 #3096

Merged
merged 1 commit into from
Nov 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

## Unreleased

* Update to LUX 305 ([PR #3096](https://github.com/alphagov/govuk_publishing_components/pull/3096))
* Add the keyboard shim for link buttons ([PR #3027](https://github.com/alphagov/govuk_publishing_components/pull/3027))

## 33.0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
errorBeaconUrl: getProperty(obj, "errorBeaconUrl", "https://lux.speedcurve.com/error/"),
jspagelabel: getProperty(obj, "jspagelabel", undefined),
label: getProperty(obj, "label", undefined),
maxBeaconUrlLength: getProperty(obj, "maxBeaconUrlLength", 8190),
maxBeaconUTEntries: getProperty(obj, "maxBeaconUTEntries", 20),
maxErrors: getProperty(obj, "maxErrors", 5),
maxMeasureTime: getProperty(obj, "maxMeasureTime", 60000),
measureUntil: getProperty(obj, "measureUntil", "onload"),
Expand Down Expand Up @@ -276,6 +278,23 @@
return Matching;
}());

/**
* Fit an array of user timing delimited strings into a URL and return both the entries that fit and
* the remaining entries that didn't fit.
*/
function fitUserTimingEntries(utValues, config, url) {
// Start with the maximum allowed UT entries per beacon
var beaconUtValues = utValues.slice(0, config.maxBeaconUTEntries);
var remainingUtValues = utValues.slice(config.maxBeaconUTEntries);
// Trim UT entries until they fit within the maximum URL length, ensuring at least one UT entry
// is included.
while ((url + "&UT=" + beaconUtValues.join(",")).length > config.maxBeaconUrlLength &&
beaconUtValues.length > 1) {
remainingUtValues.unshift(beaconUtValues.pop());
}
return [beaconUtValues, remainingUtValues];
}

var LUX = window.LUX || {};
var scriptEndTime = scriptStartTime;
LUX = (function () {
Expand All @@ -288,7 +307,7 @@
/// End
// -------------------------------------------------------------------------

var SCRIPT_VERSION = "304";
var SCRIPT_VERSION = "305";
var logger = new Logger();
var globalConfig = fromObject(LUX);
logger.logEvent(LogEvent.EvaluationStart, [SCRIPT_VERSION]);
Expand Down Expand Up @@ -382,7 +401,6 @@
var gUid = refreshUniqueId(gSyncId); // cookie for this session ("Unique ID")
var gCustomerDataTimeout; // setTimeout timer for sending a Customer Data beacon after onload
var gMaxMeasureTimeout; // setTimeout timer for sending the beacon after a maximum measurement time
var gMaxQuerystring = 8190; // split the beacon querystring if it gets longer than this
if (_sample()) {
logger.logEvent(LogEvent.SessionIsSampled, [globalConfig.samplerate]);
}
Expand Down Expand Up @@ -701,7 +719,7 @@
}
aUT.push(utParts.join("|"));
}
return aUT.join(",");
return aUT;
}
// Return a string of Element Timing Metrics formatted for beacon querystring.
function elementTimingValues() {
Expand Down Expand Up @@ -1406,8 +1424,28 @@
clearTimeout(gMaxMeasureTimeout);
}
}
function _getBeaconUrl() {
var queryParams = [
"v=" + SCRIPT_VERSION,
"id=" + getCustomerId(),
"sid=" + gSyncId,
"uid=" + gUid,
"l=" + encodeURIComponent(_getPageLabel()),
"HN=" + encodeURIComponent(document.location.hostname),
"PN=" + encodeURIComponent(document.location.pathname),
];
if (gFlags) {
queryParams.push("fl=" + gFlags);
}
var customerData = customerDataValues();
if (customerData) {
queryParams.push("CD=" + customerData);
}
return globalConfig.beaconUrl + "?" + queryParams.join("&");
}
// Beacon back the LUX data.
function _sendLux() {
var _a;
clearMaxMeasureTimeout();
var customerid = getCustomerId();
if (!customerid ||
Expand All @@ -1425,9 +1463,7 @@
// with LUX.markLoadTime()
_markLoadTime();
}
var sUT = userTimingValues(); // User Timing data
var sET = elementTimingValues(); // Element Timing data
var sCustomerData = customerDataValues(); // customer data
var sIx = ""; // Interaction Metrics
if (!gbIxSent) {
// It is possible for the IX beacon to be sent BEFORE the "main" window.onload LUX beacon.
Expand All @@ -1442,21 +1478,10 @@
}
// We want ALL beacons to have ALL the data used for query filters (geo, pagelabel, browser, & customerdata).
// So we create a base URL that has all the necessary information:
var baseUrl = globalConfig.beaconUrl +
"?v=" +
SCRIPT_VERSION +
"&id=" +
customerid +
"&sid=" +
gSyncId +
"&uid=" +
gUid +
(sCustomerData ? "&CD=" + sCustomerData : "") +
"&l=" +
encodeURIComponent(_getPageLabel());
var baseUrl = _getBeaconUrl();
var is = inlineTagSize("script");
var ic = inlineTagSize("style");
var querystring =
var metricsQueryString =
// only send Nav Timing and lux.js metrics on initial pageload (not for SPA page views)
(gbNavSent ? "" : "&NT=" + getNavTiming()) +
(gbFirstPV ? "&LJS=" + sLuxjs : "") +
Expand Down Expand Up @@ -1497,66 +1522,25 @@
(sIx ? "&IX=" + sIx : "") +
(typeof gFirstInputDelay !== "undefined" ? "&FID=" + gFirstInputDelay : "") +
(sCPU ? "&CPU=" + sCPU : "") +
(gFlags ? "&fl=" + gFlags : "") +
(sET ? "&ET=" + sET : "") + // element timing
"&HN=" +
encodeURIComponent(document.location.hostname) +
(DCLS !== false ? "&CLS=" + DCLS : "") +
"&PN=" +
encodeURIComponent(document.location.pathname);
// User Timing marks & measures
var sUT_remainder = "";
if (sUT) {
var curLen = baseUrl.length + querystring.length;
if (curLen + sUT.length <= gMaxQuerystring) {
// Add all User Timing
querystring += "&UT=" + sUT;
}
else {
// Only add a substring of User Timing
var avail_1 = gMaxQuerystring - curLen; // how much room is left in the querystring
var iComma = sUT.lastIndexOf(",", avail_1); // as many UT tuples as possible
querystring += "&UT=" + sUT.substring(0, iComma);
sUT_remainder = sUT.substring(iComma + 1);
}
}
(DCLS !== false ? "&CLS=" + DCLS : "");
// We add the user timing entries last so that we can split them to reduce the URL size if necessary.
var utValues = userTimingValues();
var _b = fitUserTimingEntries(utValues, globalConfig, baseUrl + metricsQueryString), beaconUtValues = _b[0], remainingUtValues = _b[1];
// Send the MAIN LUX beacon.
var mainBeaconUrl = baseUrl + querystring;
var mainBeaconUrl = baseUrl +
metricsQueryString +
(beaconUtValues.length > 0 ? "&UT=" + beaconUtValues.join(",") : "");
logger.logEvent(LogEvent.MainBeaconSent, [mainBeaconUrl]);
_sendBeacon(mainBeaconUrl);
// Set some states.
gbLuxSent = 1;
gbNavSent = 1;
gbIxSent = sIx ? 1 : 0;
// Send other beacons for JUST User Timing.
var avail = gMaxQuerystring - baseUrl.length;
while (sUT_remainder) {
var sUT_cur = "";
if (sUT_remainder.length <= avail) {
// We can fit ALL the remaining UT params.
sUT_cur = sUT_remainder;
sUT_remainder = "";
}
else {
// We have to take a subset of the remaining UT params.
var iComma = sUT_remainder.lastIndexOf(",", avail); // as many UT tuples as possible
if (-1 === iComma) {
// Trouble: we have SO LITTLE available space we can not fit the first UT tuple.
// Try it anyway but find it by searching from the front.
iComma = sUT_remainder.indexOf(",");
}
if (-1 === iComma) {
// The is only one UT tuple left, but it is bigger than the available space.
// Take the whole tuple even tho it is too big.
sUT_cur = sUT_remainder;
sUT_remainder = "";
}
else {
sUT_cur = sUT_remainder.substring(0, iComma);
sUT_remainder = sUT_remainder.substring(iComma + 1);
}
}
var utBeaconUrl = baseUrl + "&UT=" + sUT_cur;
while (remainingUtValues.length) {
_a = fitUserTimingEntries(remainingUtValues, globalConfig, baseUrl), beaconUtValues = _a[0], remainingUtValues = _a[1];
var utBeaconUrl = baseUrl + "&UT=" + beaconUtValues.join(",");
logger.logEvent(LogEvent.UserTimingBeaconSent, [utBeaconUrl]);
_sendBeacon(utBeaconUrl);
}
Expand All @@ -1574,26 +1558,10 @@
}
var sIx = ixValues(); // Interaction Metrics
if (sIx) {
var sCustomerData = customerDataValues(); // customer data
var querystring = "?v=" +
SCRIPT_VERSION +
"&id=" +
customerid +
"&sid=" +
gSyncId +
"&uid=" +
gUid +
(sCustomerData ? "&CD=" + sCustomerData : "") +
"&l=" +
encodeURIComponent(_getPageLabel()) +
"&IX=" +
sIx +
(gFirstInputDelay ? "&FID=" + gFirstInputDelay : "") +
"&HN=" +
encodeURIComponent(document.location.hostname) +
"&PN=" +
encodeURIComponent(document.location.pathname);
var beaconUrl = globalConfig.beaconUrl + querystring;
var beaconUrl = _getBeaconUrl() +
"&IX=" +
sIx +
(typeof gFirstInputDelay !== "undefined" ? "&FID=" + gFirstInputDelay : "");
logger.logEvent(LogEvent.InteractionBeaconSent, [beaconUrl]);
_sendBeacon(beaconUrl);
gbIxSent = 1;
Expand All @@ -1612,23 +1580,7 @@
}
var sCustomerData = customerDataValues(); // customer data
if (sCustomerData) {
var querystring = "?v=" +
SCRIPT_VERSION +
"&id=" +
customerid +
"&sid=" +
gSyncId +
"&uid=" +
gUid +
"&CD=" +
sCustomerData +
"&l=" +
encodeURIComponent(_getPageLabel()) +
"&HN=" +
encodeURIComponent(document.location.hostname) +
"&PN=" +
encodeURIComponent(document.location.pathname);
var beaconUrl = globalConfig.beaconUrl + querystring;
var beaconUrl = _getBeaconUrl();
logger.logEvent(LogEvent.CustomDataBeaconSent, [beaconUrl]);
_sendBeacon(beaconUrl);
}
Expand Down