govuk_publishing_components 35.11.0 → 35.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-core.js +2 -48
  3. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-form-tracker.js +5 -0
  4. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js +2 -2
  5. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-schemas.js +51 -5
  6. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-scroll-tracker.js +225 -0
  7. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/init-ga4.js +0 -5
  8. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4.js +1 -0
  9. data/app/assets/stylesheets/govuk_publishing_components/components/_document-list.scss +3 -1
  10. data/app/assets/stylesheets/govuk_publishing_components/components/_search.scss +8 -2
  11. data/app/controllers/govuk_publishing_components/audit_controller.rb +3 -2
  12. data/app/models/govuk_publishing_components/audit_applications.rb +3 -1
  13. data/app/models/govuk_publishing_components/audit_comparer.rb +1 -1
  14. data/app/models/govuk_publishing_components/audit_components.rb +3 -2
  15. data/app/models/govuk_publishing_components/component_wrapper_helper_options.rb +1 -0
  16. data/app/views/govuk_publishing_components/audit/_applications.html.erb +1 -1
  17. data/app/views/govuk_publishing_components/components/_attachment.html.erb +3 -1
  18. data/app/views/govuk_publishing_components/components/_document_list.html.erb +29 -27
  19. data/app/views/govuk_publishing_components/components/_heading.html.erb +8 -5
  20. data/app/views/govuk_publishing_components/components/_tabs.html.erb +30 -14
  21. data/app/views/govuk_publishing_components/components/docs/heading.yml +1 -4
  22. data/app/views/govuk_publishing_components/components/docs/single_page_notification_button.yml +1 -6
  23. data/app/views/govuk_publishing_components/components/docs/tabs.yml +26 -3
  24. data/lib/govuk_publishing_components/config.rb +3 -0
  25. data/lib/govuk_publishing_components/presenters/component_wrapper_helper.rb +17 -1
  26. data/lib/govuk_publishing_components/version.rb +1 -1
  27. data/node_modules/govuk-frontend/govuk/all.js +406 -1
  28. data/node_modules/govuk-frontend/govuk/all.js.map +1 -1
  29. data/node_modules/govuk-frontend/govuk/common/govuk-frontend-version.js +1 -1
  30. data/node_modules/govuk-frontend/govuk/components/_all.scss +2 -1
  31. data/node_modules/govuk-frontend/govuk/components/back-link/_index.scss +8 -0
  32. data/node_modules/govuk-frontend/govuk/components/back-link/fixtures.json +9 -0
  33. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +12 -0
  34. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/fixtures.json +21 -0
  35. data/node_modules/govuk-frontend/govuk/components/button/_index.scss +41 -3
  36. data/node_modules/govuk-frontend/govuk/components/button/fixtures.json +44 -0
  37. data/node_modules/govuk-frontend/govuk/components/checkboxes/macro-options.json +9 -8
  38. data/node_modules/govuk-frontend/govuk/components/exit-this-page/README.md +15 -0
  39. data/node_modules/govuk-frontend/govuk/components/exit-this-page/_exit-this-page.scss +2 -0
  40. data/node_modules/govuk-frontend/govuk/components/exit-this-page/_index.scss +97 -0
  41. data/node_modules/govuk-frontend/govuk/components/exit-this-page/exit-this-page.js +2120 -0
  42. data/node_modules/govuk-frontend/govuk/components/exit-this-page/exit-this-page.js.map +1 -0
  43. data/node_modules/govuk-frontend/govuk/components/exit-this-page/fixtures.json +50 -0
  44. data/node_modules/govuk-frontend/govuk/components/exit-this-page/macro-options.json +62 -0
  45. data/node_modules/govuk-frontend/govuk/components/exit-this-page/macro.njk +3 -0
  46. data/node_modules/govuk-frontend/govuk/components/exit-this-page/template.njk +16 -0
  47. data/node_modules/govuk-frontend/govuk/components/radios/macro-options.json +9 -8
  48. data/node_modules/govuk-frontend/govuk/core/_govuk-frontend-version.scss +1 -1
  49. data/node_modules/govuk-frontend/govuk/helpers/_visually-hidden.scss +12 -0
  50. data/node_modules/govuk-frontend/govuk/objects/_template.scss +20 -0
  51. data/node_modules/govuk-frontend/govuk-esm/all.mjs +8 -0
  52. data/node_modules/govuk-frontend/govuk-esm/all.mjs.map +1 -1
  53. data/node_modules/govuk-frontend/govuk-esm/common/govuk-frontend-version.mjs +1 -1
  54. data/node_modules/govuk-frontend/govuk-esm/components/exit-this-page/exit-this-page.mjs +406 -0
  55. data/node_modules/govuk-frontend/govuk-esm/components/exit-this-page/exit-this-page.mjs.map +1 -0
  56. data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +4 -0
  57. data/node_modules/govuk-frontend/package.json +4 -2
  58. metadata +14 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc2a2a38c6182ba05ad0863d7f1b4d47bda4c31726559b42d3e9095fc7d984a7
4
- data.tar.gz: 5bfaa98a5688a6e4d6c7f37a3f1b9099bbdb96e051dd83371da64f67040a723a
3
+ metadata.gz: b6417c1bd3d66d89500aac39c49427caa95791623fe26f1ee4844c025ef3f3c7
4
+ data.tar.gz: d21986e9895007dc2560b4aacd1eb28ff7f43251519029672b85d13d91211d94
5
5
  SHA512:
6
- metadata.gz: cee017c867881cb78d2c39357c94a6400d4abf6bd725cd8a2449c44044460ab260d6bd7fab87c6246e4ca8340417e04c1855108ad32329bca72d1e846801aaa1
7
- data.tar.gz: 917e293b5ae5ae0b228f7b66bbae838913213fb8fe4eccf82d92a0d2ae87344b85328e9f2f83296c9de13d22a24c72829e60158c64366dddb8b8d2d4e0332dea
6
+ metadata.gz: 7ca4a123db1c519256eb7ee46ff97e940d69c161f687611fb3b46915acee3454b995f2793e763ed82f5d87ae8a32d2df074b4c72587ca5c0a3c02ee858026a79
7
+ data.tar.gz: b1cc9c87e984de69229d5b6807d81eca27802b35a3be15caaaea249388fc0ce9934be7a4d75006e2a93c5374fc48738d9f8e8dbbc624955b2a14da78a01df8a8
@@ -30,32 +30,7 @@ window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {};
30
30
  firstScript.parentNode.insertBefore(newScript, firstScript)
31
31
  },
32
32
 
33
- ensureIndexesArePopulated: function (data) {
34
- if (!data.event_data) {
35
- return data
36
- }
37
-
38
- if (!data.event_data.index) {
39
- return data
40
- }
41
-
42
- var indexKeys = ['index_link', 'index_section', 'index_section_count']
43
-
44
- for (var i = 0; i < indexKeys.length; i++) {
45
- var indexKey = indexKeys[i]
46
-
47
- // If the index key isn't in the object, populate it. However if it's set to 0, leave it as 0. 0 is falsy so we have to add this extra check.
48
- if (!data.event_data.index[indexKey] && data.event_data.index[indexKey] !== 0) {
49
- data.event_data.index[indexKey] = undefined
50
- }
51
- }
52
-
53
- return data
54
- },
55
-
56
33
  sendData: function (data) {
57
- data = this.ensureIndexesArePopulated(data)
58
-
59
34
  data.govuk_gem_version = this.getGemVersion()
60
35
  // set this in the console as a debugging aid
61
36
  if (window.GOVUK.analyticsGa4.showDebug) {
@@ -274,29 +249,8 @@ window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {};
274
249
  }
275
250
  },
276
251
 
277
- addAttributesToElements: function (selector, dataAttributes) {
278
- var targetElements = document.querySelectorAll(selector)
279
-
280
- for (var i = 0; i < targetElements.length; i++) {
281
- var element = targetElements[i]
282
-
283
- for (var j = 0; j < dataAttributes.length; j++) {
284
- var key = dataAttributes[j].key
285
- var value = dataAttributes[j].value
286
-
287
- // value must check for undefined only as it would return false on an empty string, the number 0, etc.
288
- if (key && value !== undefined) {
289
- var existingAttributeValue = element.getAttribute(key)
290
-
291
- if (key === 'data-module' && existingAttributeValue) {
292
- // Combines values to prevent replacing any existing data-module values.
293
- element.setAttribute(key, existingAttributeValue + ' ' + value)
294
- } else {
295
- element.setAttribute(key, value)
296
- }
297
- }
298
- }
299
- }
252
+ applyRedactionIfRequired: function (PIIRemover, element, data) {
253
+ return element.closest('[data-ga4-do-not-redact]') ? data : PIIRemover.stripPIIWithOverride(data, true, true)
300
254
  }
301
255
  },
302
256
 
@@ -45,6 +45,11 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
45
45
  var formData = this.getInputValues(formInputs)
46
46
  data.text = data.text || (this.combineGivenAnswers(formData) || 'No answer given')
47
47
 
48
+ if (data.action === 'search') {
49
+ data.text = data.text.toLowerCase()
50
+ data.text = window.GOVUK.analyticsGa4.core.trackFunctions.removeLinesAndExtraSpaces(data.text)
51
+ }
52
+
48
53
  var schemas = new window.GOVUK.analyticsGa4.Schemas()
49
54
  var schema = schemas.mergeProperties(data, 'event_data')
50
55
  window.GOVUK.analyticsGa4.core.sendData(schema)
@@ -81,12 +81,12 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
81
81
 
82
82
  var text = data.text || event.target.textContent
83
83
  data.text = window.GOVUK.analyticsGa4.core.trackFunctions.removeLinesAndExtraSpaces(text)
84
- data.text = this.PIIRemover.stripPIIWithOverride(data.text, true, true)
84
+ data.text = window.GOVUK.analyticsGa4.core.trackFunctions.applyRedactionIfRequired(this.PIIRemover, element, data.text)
85
85
  if (!data.text && (element.querySelector('img') || element.querySelector('svg') || element.tagName === 'IMG' || element.closest('svg'))) {
86
86
  data.text = 'image'
87
87
  }
88
88
  var url = data.url || this.findLink(event.target).getAttribute('href')
89
- data.url = window.GOVUK.analyticsGa4.core.trackFunctions.removeCrossDomainParams(this.PIIRemover.stripPIIWithOverride(url, true, true))
89
+ data.url = window.GOVUK.analyticsGa4.core.trackFunctions.applyRedactionIfRequired(this.PIIRemover, element, window.GOVUK.analyticsGa4.core.trackFunctions.removeCrossDomainParams(url))
90
90
  data.link_domain = window.GOVUK.analyticsGa4.core.trackFunctions.populateLinkDomain(data.url)
91
91
  data.link_path_parts = window.GOVUK.analyticsGa4.core.trackFunctions.populateLinkPathParts(data.url)
92
92
  data.method = window.GOVUK.analyticsGa4.core.trackFunctions.getClickType(event)
@@ -16,7 +16,11 @@
16
16
  type: this.undefined,
17
17
  url: this.undefined,
18
18
  text: this.undefined,
19
- index: this.undefined,
19
+ index: {
20
+ index_link: this.undefined,
21
+ index_section: this.undefined,
22
+ index_section_count: this.undefined
23
+ },
20
24
  index_total: this.undefined,
21
25
  section: this.undefined,
22
26
  action: this.undefined,
@@ -24,7 +28,8 @@
24
28
  method: this.undefined,
25
29
  link_domain: this.undefined,
26
30
  link_path_parts: this.undefined,
27
- tool_name: this.undefined
31
+ tool_name: this.undefined,
32
+ percent_scrolled: this.undefined
28
33
  }
29
34
  }
30
35
  }
@@ -45,19 +50,60 @@
45
50
  }
46
51
  }
47
52
 
48
- // get attributes from the data attribute to send to GA
53
+ // merge data attributes data into the event schema
49
54
  // only allow it if it already exists in the schema
50
55
  Schemas.prototype.mergeProperties = function (data, eventAttribute) {
51
56
  var schema = this.eventSchema()
52
57
  schema.event = eventAttribute
58
+ // exceptions should be inserted without checking for sub parameters
59
+ // exceptions should only come from code, not directly from data attributes
60
+ // e.g. link_path_parts is generated by JS and contains potentially non-unique
61
+ // sub parameter names i.e. '1', '2'
62
+ var exceptions = ['link_path_parts']
63
+
53
64
  for (var property in data) {
54
- if (property in schema.event_data) {
55
- schema.event_data[property] = data[property]
65
+ // some passed data might be undefined, don't want it to overwrite e.g. the index sub parameters
66
+ if (data[property] !== undefined) {
67
+ if (exceptions.indexOf(property) >= 0 || !this.isAnObject(data[property])) {
68
+ schema.event_data = this.addToObject(schema.event_data, property, data[property])
69
+ } else {
70
+ // we check for one level of nesting in the data attributes data
71
+ // this check can be removed once nesting is removed from all data attributes
72
+ for (var subproperty in data[property]) {
73
+ schema.event_data = this.addToObject(schema.event_data, subproperty, data[property][subproperty])
74
+ }
75
+ }
56
76
  }
57
77
  }
58
78
  return schema
59
79
  }
60
80
 
81
+ // might be easier to check if it's not a string or a number?
82
+ Schemas.prototype.isAnObject = function (item) {
83
+ if (typeof item === 'object' && !Array.isArray(item) && item !== null) {
84
+ return true
85
+ }
86
+ }
87
+
88
+ // given an object and a key, insert a value into that object for that key
89
+ // we check for one level of nesting in the object
90
+ Schemas.prototype.addToObject = function (obj, key, value) {
91
+ if (key in obj) {
92
+ obj[key] = value
93
+ return obj
94
+ } else {
95
+ for (var property in obj) {
96
+ if (this.isAnObject(obj[property])) {
97
+ if (key in obj[property]) {
98
+ obj[property][key] = value
99
+ return obj
100
+ }
101
+ }
102
+ }
103
+ }
104
+ return obj
105
+ }
106
+
61
107
  GOVUK.analyticsGa4 = GOVUK.analyticsGa4 || {}
62
108
  GOVUK.analyticsGa4.Schemas = Schemas
63
109
 
@@ -0,0 +1,225 @@
1
+ window.GOVUK = window.GOVUK || {}
2
+ window.GOVUK.Modules = window.GOVUK.Modules || {};
3
+
4
+ (function (Modules) {
5
+ function Ga4ScrollTracker ($module) {
6
+ this.$module = $module
7
+ this.pageHeight = document.querySelector('body').clientHeight
8
+ this.trackedNodes = []
9
+ this.config = {
10
+ allowHeadingsInside: ['main'],
11
+ percentages: [20, 40, 60, 80, 100],
12
+ scrollTimeoutDelay: 20,
13
+ resizeTimeoutDelay: 100,
14
+ pageHeightTimeoutDelay: 500,
15
+ markerAttribute: 'data-ga4-scroll-marker'
16
+ }
17
+ }
18
+
19
+ Ga4ScrollTracker.prototype.init = function () {
20
+ var consentCookie = window.GOVUK.getConsentCookie()
21
+
22
+ if (consentCookie && consentCookie.settings) {
23
+ this.startModule()
24
+ } else {
25
+ this.startModule = this.startModule.bind(this)
26
+ window.addEventListener('cookie-consent', this.startModule)
27
+ }
28
+ }
29
+
30
+ Ga4ScrollTracker.prototype.startModule = function () {
31
+ if (window.GOVUK.analyticsGa4.vars.scrollTrackerStarted) {
32
+ return
33
+ }
34
+
35
+ this.trackType = this.$module.getAttribute('data-ga4-track-type')
36
+ window.GOVUK.analyticsGa4.vars.scrollTrackerStarted = true
37
+
38
+ if (this.trackType === 'headings') {
39
+ this.track = new Ga4ScrollTracker.Heading(this.config)
40
+ } else if (this.trackType === 'markers') {
41
+ this.config.trackMarkers = true
42
+ this.track = new Ga4ScrollTracker.Heading(this.config)
43
+ } else {
44
+ this.track = new Ga4ScrollTracker.Percentage(this.config)
45
+ }
46
+
47
+ this.getWindowDetails()
48
+ // if the URL has a hash we want to prevent tracking on initial page load
49
+ // until the browser jumps down the page, at which point a scroll event
50
+ // will happen and tracking will continue normally
51
+ var windowHash = window.location.hash
52
+ var dontTrackOnLoad = windowHash && document.getElementById(windowHash.substring(1))
53
+ if (!dontTrackOnLoad) {
54
+ this.trackVisibleNodes()
55
+ }
56
+
57
+ if (this.trackedNodes.length) {
58
+ // store event listener functions as variables so they can be removed if needed
59
+ this.scrollEvent = this.onScroll.bind(this)
60
+ window.addEventListener('scroll', this.scrollEvent)
61
+ this.resizeEvent = this.onResize.bind(this)
62
+ window.addEventListener('resize', this.resizeEvent)
63
+
64
+ // check if the page height changes e.g. accordion opened
65
+ this.interval = window.setInterval(function () {
66
+ var pageHeight = document.querySelector('body').clientHeight
67
+ if (pageHeight !== this.pageHeight) {
68
+ this.pageHeight = pageHeight
69
+ this.getWindowDetails()
70
+ this.trackVisibleNodes()
71
+ }
72
+ }.bind(this), this.config.pageHeightTimeoutDelay)
73
+ }
74
+ }
75
+
76
+ Ga4ScrollTracker.prototype.onScroll = function () {
77
+ clearTimeout(this.scrollTimeout)
78
+ this.scrollTimeout = setTimeout(function () {
79
+ this.trackVisibleNodes()
80
+ }.bind(this), this.config.scrollTimeoutDelay)
81
+ }
82
+
83
+ Ga4ScrollTracker.prototype.onResize = function () {
84
+ clearTimeout(this.resizeTimeout)
85
+ this.resizeTimeout = setTimeout(function () {
86
+ this.getWindowDetails()
87
+ this.trackVisibleNodes()
88
+ }.bind(this), this.config.resizeTimeoutDelay)
89
+ }
90
+
91
+ Ga4ScrollTracker.prototype.getWindowDetails = function () {
92
+ this.pageHeight = document.querySelector('body').clientHeight
93
+ this.windowHeight = window.innerHeight
94
+ this.trackedNodes = this.track.getTrackingNodes(this.trackedNodes)
95
+ }
96
+
97
+ Ga4ScrollTracker.prototype.trackVisibleNodes = function () {
98
+ var data = {
99
+ event_name: 'scroll',
100
+ action: 'scroll',
101
+ type: this.config.type
102
+ }
103
+ for (var i = 0; i < this.trackedNodes.length; i++) {
104
+ var node = this.trackedNodes[i]
105
+ if (this.isVisible(node.top, node.bottom) && !node.alreadySeen) {
106
+ node.alreadySeen = true
107
+ // we store whether a heading has been tracked or not on the heading
108
+ // because if headings appear/disappear (e.g. inside an accordion)
109
+ // the order changes, so we can't refer to the previous trackedNodes
110
+ // as we do with percentages
111
+ if (node.element) {
112
+ node.element.setAttribute('data-ga4-scrolltracker-already-seen', true)
113
+ }
114
+
115
+ data.type = node.eventData.type
116
+ // following will be undefined if tracking percentages
117
+ data.text = node.eventData.text
118
+ data.index = node.eventData.index
119
+ // following will be undefined if tracking headings
120
+ data.percent_scrolled = node.eventData.percent_scrolled
121
+
122
+ var schemas = new window.GOVUK.analyticsGa4.Schemas()
123
+ var schema = schemas.mergeProperties(data, 'event_data')
124
+ window.GOVUK.analyticsGa4.core.sendData(schema)
125
+ }
126
+ }
127
+ }
128
+
129
+ Ga4ScrollTracker.prototype.isVisible = function (top, bottom) {
130
+ var scroll = window.scrollY || document.documentElement.scrollTop // IE fallback
131
+ return scroll <= top && (scroll + this.windowHeight) >= bottom
132
+ }
133
+
134
+ Ga4ScrollTracker.Heading = function (config) {
135
+ this.config = config
136
+ }
137
+
138
+ Ga4ScrollTracker.Heading.prototype.getTrackingNodes = function () {
139
+ var headingsDetails = []
140
+ var headingsFound = this.findAllowedHeadings()
141
+ var totalHeadings = headingsFound.length
142
+
143
+ for (var i = 0; i < totalHeadings; i++) {
144
+ var heading = headingsFound[i]
145
+ var type = this.config.trackMarkers ? 'marker' : 'heading'
146
+ // only track headings that are visible i.e. not inside display: none
147
+ if (this.visible(heading)) {
148
+ var pos = heading.getBoundingClientRect()
149
+ headingsDetails.push({
150
+ element: heading,
151
+ alreadySeen: heading.getAttribute('data-ga4-scrolltracker-already-seen'),
152
+ top: pos.top + document.documentElement.scrollTop,
153
+ bottom: pos.bottom + document.documentElement.scrollTop,
154
+ eventData: {
155
+ type: type,
156
+ text: heading.textContent.replace(/\s+/g, ' ').trim(),
157
+ index: {
158
+ index_section: i + 1,
159
+ index_section_count: totalHeadings
160
+ }
161
+ }
162
+ })
163
+ }
164
+ }
165
+ return headingsDetails
166
+ }
167
+
168
+ // check heading is inside allowed elements, generally ignores everything outside of page content
169
+ Ga4ScrollTracker.Heading.prototype.findAllowedHeadings = function () {
170
+ var headingsFound = []
171
+ var headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
172
+ if (this.config.trackMarkers) {
173
+ headings = ['[' + this.config.markerAttribute + ']']
174
+ }
175
+
176
+ // this is a loop that only happens once as we currently only have one
177
+ // allowed element for headings to be in - 'main'
178
+ for (var h = 0; h < this.config.allowHeadingsInside.length; h++) {
179
+ var insideElements = document.querySelectorAll(this.config.allowHeadingsInside[h])
180
+ for (var e = 0; e < insideElements.length; e++) {
181
+ var found = insideElements[e].querySelectorAll(headings)
182
+ for (var f = 0; f < found.length; f++) {
183
+ headingsFound.push(found[f])
184
+ }
185
+ }
186
+ }
187
+ return headingsFound
188
+ }
189
+
190
+ // this is bit more verbose than checking offsetParent !== null but more reliable for IE10+
191
+ Ga4ScrollTracker.Heading.prototype.visible = function (el) {
192
+ return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length)
193
+ }
194
+
195
+ Ga4ScrollTracker.Percentage = function (config) {
196
+ this.config = config
197
+ }
198
+
199
+ Ga4ScrollTracker.Percentage.prototype.getTrackingNodes = function (trackedNodes) {
200
+ var body = document.body
201
+ var html = document.documentElement
202
+ // remove 20px from the calculated page height to allow for a possible horizontal scrollbar
203
+ var pageHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight) - 20
204
+
205
+ var percentDetails = []
206
+
207
+ for (var i = 0; i < this.config.percentages.length; i++) {
208
+ var percent = this.config.percentages[i]
209
+ var pos = ((pageHeight / 100) * percent)
210
+ var alreadySeen = false
211
+ if (trackedNodes.length) {
212
+ alreadySeen = trackedNodes[i].alreadySeen
213
+ }
214
+ percentDetails.push({
215
+ alreadySeen: alreadySeen,
216
+ top: pos,
217
+ bottom: pos,
218
+ eventData: { type: 'percent', percent_scrolled: String(percent) }
219
+ })
220
+ }
221
+ return percentDetails
222
+ }
223
+
224
+ Modules.Ga4ScrollTracker = Ga4ScrollTracker
225
+ })(window.GOVUK.Modules)
@@ -8,11 +8,6 @@ var initFunction = function () {
8
8
  window.GOVUK.analyticsGa4.vars.internalDomains = []
9
9
  window.GOVUK.analyticsGa4.vars.internalDomains.push(window.GOVUK.analyticsGa4.core.trackFunctions.getHostname())
10
10
  window.GOVUK.analyticsGa4.core.trackFunctions.appendDomainsWithoutWWW(window.GOVUK.analyticsGa4.vars.internalDomains)
11
- var attachmentLinkData = [
12
- { key: 'data-module', value: 'ga4-link-tracker' },
13
- { key: 'data-ga4-track-links-only', value: '' },
14
- { key: 'data-ga4-link', value: JSON.stringify({ event_name: 'navigation', type: 'attachment' }) }]
15
- window.GOVUK.analyticsGa4.core.trackFunctions.addAttributesToElements('[data-ga4-attachment-link]', attachmentLinkData)
16
11
  window.GOVUK.analyticsGa4.core.load()
17
12
 
18
13
  var analyticsModules = window.GOVUK.analyticsGa4.analyticsModules
@@ -10,4 +10,5 @@
10
10
  //= require ./analytics-ga4/ga4-form-tracker
11
11
  //= require ./analytics-ga4/ga4-auto-tracker
12
12
  //= require ./analytics-ga4/ga4-smart-answer-results-tracker
13
+ //= require ./analytics-ga4/ga4-scroll-tracker
13
14
  //= require ./analytics-ga4/init-ga4
@@ -25,7 +25,9 @@
25
25
 
26
26
  .gem-c-document-list--no-underline {
27
27
  .gem-c-document-list__item-title {
28
- text-decoration: none;
28
+ .govuk-link {
29
+ text-decoration: none;
30
+ }
29
31
  }
30
32
  }
31
33
 
@@ -110,6 +110,10 @@ $large-input-size: 50px;
110
110
  border: 0;
111
111
  cursor: pointer;
112
112
  border-radius: 0;
113
+ // render a border in high contrast mode
114
+ outline: $govuk-border-width-form-element solid transparent;
115
+ // Ensure outline appears outside of the element
116
+ outline-offset: 0;
113
117
  position: relative;
114
118
  padding: 0;
115
119
  width: $input-size;
@@ -124,8 +128,6 @@ $large-input-size: 50px;
124
128
  &:focus {
125
129
  z-index: 2;
126
130
  outline: $govuk-focus-width solid $govuk-focus-colour;
127
- // Ensure outline appears outside of the element
128
- outline-offset: 0;
129
131
  // Double the border by adding its width again. Use `box-shadow` for this // instead of changing `border-width` - this is for consistency with
130
132
  // Also, `outline` cannot be utilised
131
133
  // here as it is already used for the yellow focus state.
@@ -161,6 +163,10 @@ $large-input-size: 50px;
161
163
 
162
164
  .gem-c-search__input {
163
165
  border-width: 0;
166
+ // Render a border in high contrast mode
167
+ outline: $govuk-border-width-form-element solid transparent;
168
+ // Ensure outline appears outside of the element
169
+ outline-offset: 0;
164
170
 
165
171
  // no need for black outline as there is enough contrast
166
172
  // with the blue background
@@ -14,7 +14,6 @@ module GovukPublishingComponents
14
14
  government-frontend
15
15
  govspeak-preview
16
16
  info-frontend
17
- licence-finder
18
17
  release
19
18
  search-admin
20
19
  signon
@@ -49,7 +48,9 @@ module GovukPublishingComponents
49
48
 
50
49
  application_dirs.each do |application|
51
50
  application_path = [path, application].join("/")
52
- app = AuditApplications.new(application_path, application)
51
+ dir = application
52
+ dir = Rails.application.class.module_parent_name.underscore.dasherize unless ENV["MAIN_COMPONENT_GUIDE"]
53
+ app = AuditApplications.new(application_path, application, dir)
53
54
  applications_found += 1 if app.data[:application_found]
54
55
  results << app.data
55
56
  end
@@ -2,7 +2,7 @@ module GovukPublishingComponents
2
2
  class AuditApplications
3
3
  attr_reader :data
4
4
 
5
- def initialize(path, name)
5
+ def initialize(path, name, dir)
6
6
  @path = path
7
7
  application_found = application_exists(path)
8
8
  components_found = []
@@ -59,6 +59,7 @@ module GovukPublishingComponents
59
59
  # applications might not have all of these things for all components
60
60
  options = {
61
61
  application_name: name,
62
+ application_dir: dir,
62
63
  templates_path: "app/views/components",
63
64
  stylesheets_path: "app/assets/stylesheets/components",
64
65
  javascripts_path: "app/assets/javascripts/components/",
@@ -72,6 +73,7 @@ module GovukPublishingComponents
72
73
 
73
74
  @data = {
74
75
  name: name,
76
+ dir: dir,
75
77
  application_found: application_found,
76
78
  components_found: components_found,
77
79
  gem_style_references: @gem_style_references.flatten.uniq.sort,
@@ -12,7 +12,6 @@ module GovukPublishingComponents
12
12
  frontend
13
13
  government-frontend
14
14
  info-frontend
15
- licence-finder
16
15
  service-manual-frontend
17
16
  smart-answers
18
17
  whitehall
@@ -93,6 +92,7 @@ module GovukPublishingComponents
93
92
 
94
93
  data << {
95
94
  name: result[:name],
95
+ dir: result[:dir],
96
96
  application_found: result[:application_found],
97
97
  uses_static: application_uses_static,
98
98
  summary: summary,
@@ -13,6 +13,7 @@ module GovukPublishingComponents
13
13
  @helpers_path = options[:helpers_path] || "lib/govuk_publishing_components/presenters"
14
14
 
15
15
  @application_name = options[:application_name] || "govuk_publishing_components"
16
+ @application_dir = options[:application_dir] || "govuk_publishing_components"
16
17
  @all_templates = Dir["#{path}/#{@templates_path}/*.erb"].sort
17
18
  @templates_full_path = "#{path}/#{@templates_path}/"
18
19
 
@@ -57,7 +58,7 @@ module GovukPublishingComponents
57
58
  component_templates.each do |component|
58
59
  component_detail = {}
59
60
  component_detail[:name] = component
60
- component_detail[:application] = @application_name
61
+ component_detail[:application] = @application_dir
61
62
  component_detail[:link] = get_component_link(component) unless @auditing_an_application
62
63
  file_details = [
63
64
  {
@@ -214,7 +215,7 @@ module GovukPublishingComponents
214
215
 
215
216
  def get_asset_link(a_thing, component)
216
217
  url = "https://github.com/alphagov"
217
- repo = @application_name
218
+ repo = @application_dir
218
219
  blob = "blob/main"
219
220
  link = nil
220
221
  link = "#{url}/#{repo}/#{blob}/#{@templates_path}/_#{component.gsub(' ', '_')}.html.erb" if a_thing == "template"
@@ -9,6 +9,7 @@ This component uses the component wrapper helper. It accepts the following optio
9
9
  - `aria` - accepts a hash of aria attributes
10
10
  - `classes` - accepts a space separated string of classes, these should not be used for styling and must be prefixed with `js-`
11
11
  - `role` - accepts a space separated string of roles
12
+ - `lang` - accepts a language attribute value
12
13
  "
13
14
  end
14
15
  end
@@ -34,7 +34,7 @@
34
34
 
35
35
  <% accordion_content = capture do %>
36
36
  <% if application[:application_found] %>
37
- <% github_link = 'https://github.com/alphagov/' + application[:name] + '/blob/main/' %>
37
+ <% github_link = 'https://github.com/alphagov/' + application[:dir] + '/blob/main/' %>
38
38
 
39
39
  <% if @other_applications %>
40
40
  <% if application[:uses_individual_asset_model] %>
@@ -43,13 +43,15 @@
43
43
  "HTML",
44
44
  class: "gem-c-attachment__attribute",
45
45
  )
46
+ data_attributes[:module] ? data_attributes[:module] << " ga4-link-tracker" : data_attributes[:module] = "ga4-link-tracker"
47
+ data_attributes[:ga4_link] = { "event_name": "navigation", "type": "attachment" }.to_json
46
48
  when "external"
47
49
  attributes << tag.span(
48
50
  attachment.url,
49
51
  class: "gem-c-attachment__attribute",
50
52
  )
51
53
  end
52
-
54
+
53
55
  %>
54
56
  <%= tag.section class: class_names(container_class_names) do %>
55
57
  <%= tag.div class: "gem-c-attachment__thumbnail" do %>