govuk_publishing_components 29.7.0 → 29.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (182) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/analytics/explicit-cross-domain-links.js +72 -73
  3. data/app/assets/javascripts/govuk_publishing_components/analytics/page-content.js +13 -2
  4. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/gtm-click-tracking.js +49 -0
  5. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4.js +1 -0
  6. data/app/assets/javascripts/govuk_publishing_components/components/accordion.js +0 -1
  7. data/app/assets/javascripts/govuk_publishing_components/modules.js +0 -1
  8. data/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-measurer.js +37 -0
  9. data/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-reporter.js +166 -142
  10. data/app/assets/stylesheets/govuk_publishing_components/components/_cards.scss +11 -4
  11. data/app/assets/stylesheets/govuk_publishing_components/components/_contextual-sidebar.scss +20 -0
  12. data/app/assets/stylesheets/govuk_publishing_components/components/_layout-super-navigation-header.scss +3 -8
  13. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_attachment.scss +8 -2
  14. data/app/controllers/govuk_publishing_components/audit_controller.rb +3 -2
  15. data/app/controllers/govuk_publishing_components/component_guide_controller.rb +0 -9
  16. data/app/models/govuk_publishing_components/audit_comparer.rb +92 -34
  17. data/app/views/govuk_publishing_components/audit/_applications.html.erb +20 -9
  18. data/app/views/govuk_publishing_components/component_guide/index.html.erb +3 -21
  19. data/app/views/govuk_publishing_components/component_guide/show.html.erb +1 -1
  20. data/app/views/govuk_publishing_components/components/_cards.html.erb +13 -11
  21. data/app/views/govuk_publishing_components/components/_layout_footer.html.erb +20 -2
  22. data/app/views/govuk_publishing_components/components/_summary_list.html.erb +4 -5
  23. data/app/views/govuk_publishing_components/components/contextual_sidebar/_ukraine_cta.html.erb +18 -19
  24. data/app/views/govuk_publishing_components/components/docs/contents_list.yml +1 -1
  25. data/app/views/govuk_publishing_components/components/docs/document_list.yml +4 -4
  26. data/app/views/govuk_publishing_components/components/docs/heading.yml +1 -1
  27. data/app/views/govuk_publishing_components/components/docs/image_card.yml +1 -1
  28. data/app/views/govuk_publishing_components/components/docs/meta_tags.yml +4 -4
  29. data/app/views/govuk_publishing_components/components/docs/metadata.yml +1 -1
  30. data/app/views/govuk_publishing_components/components/docs/share_links.yml +1 -1
  31. data/app/views/govuk_publishing_components/components/docs/subscription_links.yml +1 -1
  32. data/app/views/govuk_publishing_components/components/docs/translation_nav.yml +1 -2
  33. data/config/locales/ar.yml +1 -2
  34. data/config/locales/az.yml +1 -2
  35. data/config/locales/be.yml +1 -2
  36. data/config/locales/bg.yml +1 -2
  37. data/config/locales/bn.yml +1 -2
  38. data/config/locales/cs.yml +1 -2
  39. data/config/locales/cy.yml +1 -2
  40. data/config/locales/da.yml +1 -2
  41. data/config/locales/de.yml +1 -2
  42. data/config/locales/dr.yml +1 -2
  43. data/config/locales/el.yml +1 -2
  44. data/config/locales/en.yml +9 -2
  45. data/config/locales/es-419.yml +1 -2
  46. data/config/locales/es.yml +1 -2
  47. data/config/locales/et.yml +1 -2
  48. data/config/locales/fa.yml +1 -2
  49. data/config/locales/fi.yml +1 -2
  50. data/config/locales/fr.yml +1 -2
  51. data/config/locales/gd.yml +1 -2
  52. data/config/locales/gu.yml +1 -2
  53. data/config/locales/he.yml +1 -2
  54. data/config/locales/hi.yml +1 -2
  55. data/config/locales/hr.yml +1 -2
  56. data/config/locales/hu.yml +1 -2
  57. data/config/locales/hy.yml +1 -2
  58. data/config/locales/id.yml +1 -2
  59. data/config/locales/is.yml +1 -2
  60. data/config/locales/it.yml +1 -2
  61. data/config/locales/ja.yml +1 -2
  62. data/config/locales/ka.yml +1 -2
  63. data/config/locales/kk.yml +1 -2
  64. data/config/locales/ko.yml +1 -2
  65. data/config/locales/lt.yml +1 -2
  66. data/config/locales/lv.yml +1 -2
  67. data/config/locales/ms.yml +1 -2
  68. data/config/locales/mt.yml +1 -2
  69. data/config/locales/nl.yml +1 -2
  70. data/config/locales/no.yml +1 -2
  71. data/config/locales/pa-pk.yml +1 -2
  72. data/config/locales/pa.yml +1 -2
  73. data/config/locales/pl.yml +1 -2
  74. data/config/locales/ps.yml +1 -2
  75. data/config/locales/pt.yml +1 -2
  76. data/config/locales/ro.yml +1 -2
  77. data/config/locales/ru.yml +1 -2
  78. data/config/locales/si.yml +1 -2
  79. data/config/locales/sk.yml +1 -2
  80. data/config/locales/sl.yml +1 -2
  81. data/config/locales/so.yml +1 -2
  82. data/config/locales/sq.yml +1 -2
  83. data/config/locales/sr.yml +1 -2
  84. data/config/locales/sv.yml +1 -2
  85. data/config/locales/sw.yml +1 -2
  86. data/config/locales/ta.yml +1 -2
  87. data/config/locales/th.yml +1 -2
  88. data/config/locales/tk.yml +1 -2
  89. data/config/locales/tr.yml +1 -2
  90. data/config/locales/uk.yml +1 -2
  91. data/config/locales/ur.yml +1 -2
  92. data/config/locales/uz.yml +1 -2
  93. data/config/locales/vi.yml +1 -2
  94. data/config/locales/zh-hk.yml +1 -2
  95. data/config/locales/zh-tw.yml +1 -2
  96. data/config/locales/zh.yml +1 -2
  97. data/lib/generators/govuk_publishing_components/templates/_component.html.erb +1 -1
  98. data/lib/govuk_publishing_components/app_helpers/brand_helper.rb +1 -1
  99. data/lib/govuk_publishing_components/presenters/attachment_helper.rb +1 -3
  100. data/lib/govuk_publishing_components/presenters/public_layout_helper.rb +35 -16
  101. data/lib/govuk_publishing_components/version.rb +1 -1
  102. data/node_modules/govuk-frontend/govuk/all.js +120 -49
  103. data/node_modules/govuk-frontend/govuk/components/back-link/macro-options.json +2 -2
  104. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +0 -2
  105. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/macro-options.json +2 -2
  106. data/node_modules/govuk-frontend/govuk/components/button/_index.scss +6 -16
  107. data/node_modules/govuk-frontend/govuk/components/button/macro-options.json +2 -2
  108. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +120 -49
  109. data/node_modules/govuk-frontend/govuk/components/character-count/fixtures.json +33 -17
  110. data/node_modules/govuk-frontend/govuk/components/character-count/macro-options.json +2 -2
  111. data/node_modules/govuk-frontend/govuk/components/character-count/template.njk +1 -4
  112. data/node_modules/govuk-frontend/govuk/components/checkboxes/_index.scss +3 -2
  113. data/node_modules/govuk-frontend/govuk/components/checkboxes/fixtures.json +22 -10
  114. data/node_modules/govuk-frontend/govuk/components/checkboxes/macro-options.json +2 -2
  115. data/node_modules/govuk-frontend/govuk/components/date-input/fixtures.json +23 -23
  116. data/node_modules/govuk-frontend/govuk/components/date-input/template.njk +1 -1
  117. data/node_modules/govuk-frontend/govuk/components/details/macro-options.json +4 -4
  118. data/node_modules/govuk-frontend/govuk/components/error-message/macro-options.json +2 -2
  119. data/node_modules/govuk-frontend/govuk/components/error-summary/macro-options.json +3 -3
  120. data/node_modules/govuk-frontend/govuk/components/fieldset/macro-options.json +2 -2
  121. data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +12 -22
  122. data/node_modules/govuk-frontend/govuk/components/header/_index.scss +13 -3
  123. data/node_modules/govuk-frontend/govuk/components/header/macro-options.json +2 -2
  124. data/node_modules/govuk-frontend/govuk/components/hint/macro-options.json +2 -2
  125. data/node_modules/govuk-frontend/govuk/components/input/_index.scss +4 -13
  126. data/node_modules/govuk-frontend/govuk/components/input/macro-options.json +5 -5
  127. data/node_modules/govuk-frontend/govuk/components/inset-text/macro-options.json +2 -2
  128. data/node_modules/govuk-frontend/govuk/components/label/macro-options.json +2 -2
  129. data/node_modules/govuk-frontend/govuk/components/panel/_index.scss +1 -1
  130. data/node_modules/govuk-frontend/govuk/components/panel/macro-options.json +4 -4
  131. data/node_modules/govuk-frontend/govuk/components/phase-banner/macro-options.json +2 -2
  132. data/node_modules/govuk-frontend/govuk/components/radios/_index.scss +5 -4
  133. data/node_modules/govuk-frontend/govuk/components/radios/fixtures.json +17 -12
  134. data/node_modules/govuk-frontend/govuk/components/radios/macro-options.json +2 -2
  135. data/node_modules/govuk-frontend/govuk/components/skip-link/_index.scss +1 -3
  136. data/node_modules/govuk-frontend/govuk/components/skip-link/macro-options.json +2 -2
  137. data/node_modules/govuk-frontend/govuk/components/summary-list/macro-options.json +5 -5
  138. data/node_modules/govuk-frontend/govuk/components/table/macro-options.json +4 -4
  139. data/node_modules/govuk-frontend/govuk/components/tabs/macro-options.json +2 -2
  140. data/node_modules/govuk-frontend/govuk/components/tag/macro-options.json +2 -2
  141. data/node_modules/govuk-frontend/govuk/components/warning-text/macro-options.json +2 -2
  142. data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +3 -3
  143. data/node_modules/govuk-frontend/govuk/helpers/_links.scss +7 -5
  144. data/node_modules/govuk-frontend/govuk/helpers/_media-queries.scss +2 -2
  145. data/node_modules/govuk-frontend/govuk/helpers/_shape-arrow.scss +1 -1
  146. data/node_modules/govuk-frontend/govuk/helpers/_spacing.scss +3 -3
  147. data/node_modules/govuk-frontend/govuk/helpers/_typography.scss +2 -2
  148. data/node_modules/govuk-frontend/govuk/objects/_button-group.scss +10 -26
  149. data/node_modules/govuk-frontend/govuk/objects/_template.scss +1 -1
  150. data/node_modules/govuk-frontend/govuk/objects/_width-container.scss +0 -4
  151. data/node_modules/govuk-frontend/govuk/tools/_exports.scss +1 -1
  152. data/node_modules/govuk-frontend/govuk/tools/_font-url.scss +1 -1
  153. data/node_modules/govuk-frontend/govuk/tools/_image-url.scss +1 -1
  154. data/node_modules/govuk-frontend/govuk/tools/_px-to-em.scss +2 -2
  155. data/node_modules/govuk-frontend/govuk/tools/_px-to-rem.scss +1 -1
  156. data/node_modules/govuk-frontend/govuk-esm/all.mjs +88 -0
  157. data/node_modules/govuk-frontend/govuk-esm/common.mjs +28 -0
  158. data/node_modules/govuk-frontend/govuk-esm/components/accordion/accordion.mjs +374 -0
  159. data/node_modules/govuk-frontend/govuk-esm/components/button/button.mjs +64 -0
  160. data/node_modules/govuk-frontend/govuk-esm/components/character-count/character-count.mjs +251 -0
  161. data/node_modules/govuk-frontend/govuk-esm/components/checkboxes/checkboxes.mjs +164 -0
  162. data/node_modules/govuk-frontend/govuk-esm/components/details/details.mjs +147 -0
  163. data/node_modules/govuk-frontend/govuk-esm/components/error-summary/error-summary.mjs +168 -0
  164. data/node_modules/govuk-frontend/govuk-esm/components/header/header.mjs +52 -0
  165. data/node_modules/govuk-frontend/govuk-esm/components/notification-banner/notification-banner.mjs +55 -0
  166. data/node_modules/govuk-frontend/govuk-esm/components/radios/radios.mjs +122 -0
  167. data/node_modules/govuk-frontend/govuk-esm/components/skip-link/skip-link.mjs +94 -0
  168. data/node_modules/govuk-frontend/govuk-esm/components/tabs/tabs.mjs +282 -0
  169. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/DOMTokenList.js +264 -0
  170. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Document.js +26 -0
  171. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Element/prototype/classList.js +93 -0
  172. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Element/prototype/closest.js +24 -0
  173. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Element/prototype/matches.js +23 -0
  174. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Element/prototype/nextElementSibling.js +22 -0
  175. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Element/prototype/previousElementSibling.js +22 -0
  176. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Element.js +114 -0
  177. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Event.js +252 -0
  178. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Function/prototype/bind.js +159 -0
  179. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Object/defineProperty.js +86 -0
  180. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Window.js +20 -0
  181. data/node_modules/govuk-frontend/package.json +8 -1
  182. metadata +30 -3
@@ -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