govuk_publishing_components 35.11.0 → 35.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 %>