govuk_publishing_components 37.1.1 → 37.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-core.js +6 -0
  3. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-schemas.js +2 -2
  4. data/app/assets/javascripts/govuk_publishing_components/lib/cookie-settings.js +109 -0
  5. data/app/assets/javascripts/govuk_publishing_components/load-analytics.js +83 -60
  6. data/app/assets/stylesheets/component_guide/application.scss +1 -1
  7. data/app/assets/stylesheets/govuk_publishing_components/components/_contents-list.scss +1 -1
  8. data/app/assets/stylesheets/govuk_publishing_components/components/_image-card.scss +3 -3
  9. data/app/assets/stylesheets/govuk_publishing_components/components/_modal-dialogue.scss +1 -1
  10. data/app/assets/stylesheets/govuk_publishing_components/components/_search.scss +2 -2
  11. data/app/assets/stylesheets/govuk_publishing_components/components/_share-links.scss +1 -1
  12. data/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav-related.scss +1 -1
  13. data/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav.scss +10 -10
  14. data/app/assets/stylesheets/govuk_publishing_components/components/_table.scss +1 -1
  15. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_warning-callout.scss +2 -2
  16. data/app/assets/stylesheets/govuk_publishing_components/components/helpers/_markdown-typography.scss +1 -1
  17. data/app/assets/stylesheets/govuk_publishing_components/components/mixins/_grid-helper.scss +1 -1
  18. data/app/models/govuk_publishing_components/audit_applications.rb +1 -1
  19. data/app/models/govuk_publishing_components/component_docs.rb +1 -1
  20. data/app/views/govuk_publishing_components/components/_details.html.erb +18 -2
  21. data/app/views/govuk_publishing_components/components/_image_card.html.erb +11 -11
  22. data/app/views/govuk_publishing_components/components/docs/details.yml +21 -0
  23. data/app/views/govuk_publishing_components/components/docs/image_card.yml +18 -11
  24. data/lib/govuk_publishing_components/version.rb +1 -1
  25. data/node_modules/axe-core/axe.js +604 -440
  26. data/node_modules/axe-core/axe.min.js +2 -2
  27. data/node_modules/axe-core/package.json +1 -1
  28. data/node_modules/axe-core/sri-history.json +4 -0
  29. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6371bbc7ca91fdd7a004050d47b2f09ac4d55244a8c7475692022e87af313b80
4
- data.tar.gz: aa375ef7ebb426df626123c3832df1b926b562633c36d8af8202a82cff4d1f65
3
+ metadata.gz: 638e22aafc5fdc6f80b61babb5bcddf89bc41213e5e49afaf95c23a8ca62d5ea
4
+ data.tar.gz: 3af560c10c9beb1da8db5d930d5bd02b530f5ceeaa65734b5432baf2651a7e9b
5
5
  SHA512:
6
- metadata.gz: 7bc4e2777a12f8a6e6a68de36a0d4bb92d6d5f97e2b16e1a07eb264285c0a5f97c2b0b0d205946c570436368dc7319da9c5796de4c97a700939e3be39f27b120
7
- data.tar.gz: 24472468c3ebe08a695d1a1f3b03f7e2a21a1850257d8ca0a121663a1ff3d9176de1421746c0e292b589d7f08f7127ec1670946349e2e830ebb080cd1964e9a8
6
+ metadata.gz: 3b4d262a5afcc7a3b436b9142daa46e994bbbda7bb5e780a8c98d95df894d9ae6d3a8ae46a62fac7daea39d33006311843d231f786f1b2ba5ebcd47c76a41d3d
7
+ data.tar.gz: f7274e4d9d134c750ae933b717b7a6efae8fb126c1c5c290646454ab35b153108d2ccda6971f702abea7e6554f079ce68e395fff789c2ff763d0f8a7df9c350f
@@ -34,8 +34,14 @@ window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {};
34
34
  return navigator.userAgent
35
35
  },
36
36
 
37
+ getTimestamp: function () {
38
+ return Date.now().toString()
39
+ },
40
+
37
41
  sendData: function (data) {
38
42
  data.govuk_gem_version = this.getGemVersion()
43
+ data.timestamp = this.getTimestamp()
44
+
39
45
  // set this in the console as a debugging aid
40
46
  if (window.GOVUK.analyticsGa4.showDebug) {
41
47
  if (data.event_data) {
@@ -75,14 +75,14 @@
75
75
  // given an object and a key, insert a value into object[key] if it exists
76
76
  Schemas.prototype.addToObject = function (obj, key, value) {
77
77
  if (key in obj) {
78
- obj[key] = value
78
+ obj[key] = value + '' // ensure is a string
79
79
  return obj
80
80
  } else {
81
81
  // check for one level of nesting in the object
82
82
  for (var property in obj) {
83
83
  if (this.isAnObject(obj[property])) {
84
84
  if (key in obj[property]) {
85
- obj[property][key] = value
85
+ obj[property][key] = value + '' // ensure is a string
86
86
  return obj
87
87
  }
88
88
  }
@@ -0,0 +1,109 @@
1
+ window.GOVUK = window.GOVUK || {}
2
+ window.GOVUK.Modules = window.GOVUK.Modules || {};
3
+
4
+ (function (Modules) {
5
+ function CookieSettings ($module) {
6
+ this.$module = $module
7
+ }
8
+
9
+ CookieSettings.prototype.init = function () {
10
+ this.$module.submitSettingsForm = this.submitSettingsForm.bind(this)
11
+
12
+ document.querySelector('form[data-module=cookie-settings]')
13
+ .addEventListener('submit', this.$module.submitSettingsForm)
14
+
15
+ this.setInitialFormValues()
16
+ }
17
+
18
+ CookieSettings.prototype.setInitialFormValues = function () {
19
+ if (!window.GOVUK.cookie('cookies_policy')) {
20
+ window.GOVUK.setDefaultConsentCookie()
21
+ }
22
+
23
+ var currentConsentCookie = window.GOVUK.cookie('cookies_policy')
24
+ var currentConsentCookieJSON = JSON.parse(currentConsentCookie)
25
+
26
+ // We don't need the essential value as this cannot be changed by the user
27
+ delete currentConsentCookieJSON.essential
28
+
29
+ for (var cookieType in currentConsentCookieJSON) {
30
+ var radioButton
31
+
32
+ if (currentConsentCookieJSON[cookieType]) {
33
+ radioButton = document.querySelector('input[name=cookies-' + cookieType + '][value=on]')
34
+ } else {
35
+ radioButton = document.querySelector('input[name=cookies-' + cookieType + '][value=off]')
36
+ }
37
+
38
+ if (radioButton) {
39
+ radioButton.checked = true
40
+ }
41
+ }
42
+ }
43
+
44
+ CookieSettings.prototype.submitSettingsForm = function (event) {
45
+ event.preventDefault()
46
+
47
+ var formInputs = event.target.getElementsByTagName('input')
48
+ var options = {}
49
+
50
+ for (var i = 0; i < formInputs.length; i++) {
51
+ var input = formInputs[i]
52
+ if (input.checked) {
53
+ var name = input.name.replace('cookies-', '')
54
+ var value = input.value === 'on'
55
+
56
+ options[name] = value
57
+ }
58
+ }
59
+
60
+ window.GOVUK.setConsentCookie(options)
61
+ window.GOVUK.setCookie('cookies_preferences_set', true, { days: 365 })
62
+
63
+ this.fireAnalyticsEvent(options)
64
+
65
+ this.showConfirmationMessage()
66
+
67
+ return false
68
+ }
69
+
70
+ CookieSettings.prototype.fireAnalyticsEvent = function (consent) {
71
+ var eventLabel = ''
72
+
73
+ for (var option in consent) {
74
+ var optionValue = consent[option] ? 'yes' : 'no'
75
+ eventLabel += option + '-' + optionValue + ' '
76
+ }
77
+
78
+ if (window.GOVUK.analytics && window.GOVUK.analytics.trackEvent) {
79
+ window.GOVUK.analytics.trackEvent('cookieSettings', 'Save changes', { label: eventLabel })
80
+ }
81
+ }
82
+
83
+ CookieSettings.prototype.showConfirmationMessage = function () {
84
+ var confirmationMessage = document.querySelector('div[data-cookie-confirmation]')
85
+ // hide the message if already visible so assistive tech is triggered when it appears
86
+ confirmationMessage.style.display = 'none'
87
+ var previousPageLink = document.querySelector('.cookie-settings__prev-page')
88
+ var referrer = CookieSettings.prototype.getReferrerLink()
89
+
90
+ document.body.scrollTop = document.documentElement.scrollTop = 0
91
+
92
+ if (previousPageLink) {
93
+ if (referrer && referrer !== document.location.pathname) {
94
+ previousPageLink.href = referrer
95
+ previousPageLink.style.display = 'inline'
96
+ } else {
97
+ previousPageLink.style.display = 'none'
98
+ }
99
+ }
100
+
101
+ confirmationMessage.style.display = 'block'
102
+ }
103
+
104
+ CookieSettings.prototype.getReferrerLink = function () {
105
+ return document.referrer ? new URL(document.referrer).pathname : false
106
+ }
107
+
108
+ Modules.CookieSettings = CookieSettings
109
+ })(window.GOVUK.Modules)
@@ -3,49 +3,75 @@
3
3
  //= require govuk_publishing_components/analytics/linked-domains
4
4
 
5
5
  window.GOVUK.loadAnalytics = {
6
- productionDomains: [
7
- 'www.gov.uk',
8
- 'www-origin.publishing.service.gov.uk',
9
- 'assets.publishing.service.gov.uk'
10
- ],
11
- stagingDomains: [
12
- 'www.staging.publishing.service.gov.uk',
13
- 'www-origin.staging.publishing.service.gov.uk',
14
- 'assets.staging.publishing.service.gov.uk'
15
- ],
16
- integrationDomains: [
17
- 'www.integration.publishing.service.gov.uk',
18
- 'www-origin.integration.publishing.service.gov.uk',
19
- 'assets.integration.publishing.service.gov.uk'
20
- ],
21
- developmentDomains: [
22
- 'localhost', '127.0.0.1', '0.0.0.0'
23
- ],
24
-
25
- // For Universal Analytics' cross domain tracking. linkedDomains is defined by the require statement at the top of the file.
26
- linkedDomains: window.GOVUK.analytics.linkedDomains,
27
-
28
- ga4EnvironmentVariables: {
29
- // initialiseGA4 is used to enable/disable GA4 on specific environments
30
- production: {
31
- initialiseGA4: true
6
+ domains: [
7
+ {
8
+ // need to have this one at the start, see loadGa4 function
9
+ name: 'development',
10
+ domains: [
11
+ 'localhost',
12
+ '127.0.0.1',
13
+ '0.0.0.0',
14
+ 'dev.gov.uk'
15
+ ],
16
+ initialiseGA4: true,
17
+ id: 'GTM-MG7HG5W',
18
+ auth: 'bRiZ-jiEHtw6hHpGd6dF9w',
19
+ preview: 'env-3',
20
+ gaProperty: 'UA-UNSET',
21
+ gaPropertyCrossDomain: 'UA-UNSET'
22
+ },
23
+ {
24
+ name: 'production',
25
+ domains: [
26
+ 'www.gov.uk',
27
+ 'www-origin.publishing.service.gov.uk',
28
+ 'assets.publishing.service.gov.uk'
29
+ ],
30
+ initialiseGA4: true,
31
+ id: 'GTM-MG7HG5W',
32
+ gaProperty: 'UA-26179049-1',
33
+ gaPropertyCrossDomain: 'UA-145652997-1'
32
34
  },
33
- staging: {
35
+ {
36
+ name: 'staging',
37
+ domains: [
38
+ 'www.staging.publishing.service.gov.uk',
39
+ 'www-origin.staging.publishing.service.gov.uk',
40
+ 'assets.staging.publishing.service.gov.uk'
41
+ ],
34
42
  initialiseGA4: true,
43
+ id: 'GTM-MG7HG5W',
35
44
  auth: 'oJWs562CxSIjZKn_GlB5Bw',
36
- preview: 'env-5'
45
+ preview: 'env-5',
46
+ gaProperty: 'UA-26179049-20',
47
+ gaPropertyCrossDomain: 'UA-145652997-1'
37
48
  },
38
- integration: {
49
+ {
50
+ name: 'integration',
51
+ domains: [
52
+ 'www.integration.publishing.service.gov.uk',
53
+ 'www-origin.integration.publishing.service.gov.uk',
54
+ 'assets.integration.publishing.service.gov.uk'
55
+ ],
39
56
  initialiseGA4: true,
57
+ id: 'GTM-MG7HG5W',
40
58
  auth: 'C7iYdcsOlYgGmiUJjZKrHQ',
41
- preview: 'env-4'
59
+ preview: 'env-4',
60
+ gaProperty: 'UA-26179049-22',
61
+ gaPropertyCrossDomain: 'UA-145652997-1'
42
62
  },
43
- development: {
63
+ {
64
+ name: 'devdocs',
65
+ domains: [
66
+ 'docs.publishing.service.gov.uk'
67
+ ],
44
68
  initialiseGA4: true,
45
- auth: 'bRiZ-jiEHtw6hHpGd6dF9w',
46
- preview: 'env-3'
69
+ id: 'GTM-TNKCK97'
47
70
  }
48
- },
71
+ ],
72
+
73
+ // For Universal Analytics' cross domain tracking. linkedDomains is defined by the require statement at the top of the file.
74
+ linkedDomains: window.GOVUK.analytics.linkedDomains,
49
75
 
50
76
  loadUa: function (currentDomain) {
51
77
  currentDomain = currentDomain || window.location.hostname
@@ -57,17 +83,14 @@ window.GOVUK.loadAnalytics = {
57
83
  window.GOVUK.analyticsVars.gaProperty = 'UA-UNSET'
58
84
  window.GOVUK.analyticsVars.gaPropertyCrossDomain = 'UA-UNSET'
59
85
 
60
- if (this.arrayContains(currentDomain, this.productionDomains)) {
61
- window.GOVUK.analyticsVars.gaProperty = 'UA-26179049-1'
62
- window.GOVUK.analyticsVars.gaPropertyCrossDomain = 'UA-145652997-1'
63
- } else if (this.arrayContains(currentDomain, this.stagingDomains)) {
64
- window.GOVUK.analyticsVars.gaProperty = 'UA-26179049-20'
65
- window.GOVUK.analyticsVars.gaPropertyCrossDomain = 'UA-145652997-1'
66
- } else if (this.arrayContains(currentDomain, this.integrationDomains)) {
67
- window.GOVUK.analyticsVars.gaProperty = 'UA-26179049-22'
68
- window.GOVUK.analyticsVars.gaPropertyCrossDomain = 'UA-145652997-1'
86
+ for (var i = 0; i < this.domains.length; i++) {
87
+ var current = this.domains[i]
88
+ if (this.arrayContains(currentDomain, current.domains)) {
89
+ window.GOVUK.analyticsVars.gaProperty = current.gaProperty
90
+ window.GOVUK.analyticsVars.gaPropertyCrossDomain = current.gaPropertyCrossDomain
91
+ break
92
+ }
69
93
  }
70
-
71
94
  // Load universal analytics
72
95
  if (typeof window.GOVUK.analyticsInit !== 'undefined') {
73
96
  window.GOVUK.analyticsInit()
@@ -76,29 +99,29 @@ window.GOVUK.loadAnalytics = {
76
99
 
77
100
  loadGa4: function (currentDomain) {
78
101
  currentDomain = currentDomain || window.location.hostname
79
- var environment = ''
80
-
81
- // Categorise current environment
82
- if (this.arrayContains(currentDomain, this.productionDomains)) {
83
- environment = 'production'
84
- } else if (this.arrayContains(currentDomain, this.stagingDomains)) {
85
- environment = 'staging'
86
- } else if (this.arrayContains(currentDomain, this.integrationDomains)) {
87
- environment = 'integration'
88
- } else if (this.arrayContains(currentDomain, this.developmentDomains) || currentDomain.indexOf('.dev.gov.uk') !== -1) {
89
- environment = 'development'
102
+ var environment = false
103
+ // lots of dev domains, so simplify the matching process
104
+ if (currentDomain.match(/\/{2}[a-zA-Z0-9.]+dev\.gov\.uk/)) {
105
+ environment = this.domains[0]
106
+ } else {
107
+ for (var i = 0; i < this.domains.length; i++) {
108
+ if (this.arrayContains(currentDomain, this.domains[i].domains)) {
109
+ environment = this.domains[i]
110
+ break
111
+ }
112
+ }
90
113
  }
91
114
 
92
115
  // If we recognise the environment (i.e. the string isn't empty), load in GA4
93
116
  if (environment) {
94
117
  // If analytics-ga4.js exists and our detected environment has 'initialiseGA4' set to true, load GA4.
95
- if (typeof window.GOVUK.analyticsGa4.init !== 'undefined' && this.ga4EnvironmentVariables[environment].initialiseGA4) {
118
+ if (typeof window.GOVUK.analyticsGa4.init !== 'undefined' && environment.initialiseGA4) {
96
119
  window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {}
97
120
  window.GOVUK.analyticsGa4.vars = window.GOVUK.analyticsGa4.vars || {}
98
- window.GOVUK.analyticsGa4.vars.id = 'GTM-MG7HG5W'
99
- window.GOVUK.analyticsGa4.vars.auth = this.ga4EnvironmentVariables[environment].auth
100
- window.GOVUK.analyticsGa4.vars.preview = this.ga4EnvironmentVariables[environment].preview
101
- window.GOVUK.analyticsGa4.vars.environment = environment // Used for testing and debugging
121
+ window.GOVUK.analyticsGa4.vars.id = environment.id
122
+ window.GOVUK.analyticsGa4.vars.auth = environment.auth
123
+ window.GOVUK.analyticsGa4.vars.preview = environment.preview
124
+ window.GOVUK.analyticsGa4.vars.environment = environment.name // Used for testing and debugging
102
125
 
103
126
  window.GOVUK.analyticsGa4.vars.gem_version = 'not found'
104
127
  var gemMeta = document.querySelector('meta[name="govuk:components_gem_version"]')
@@ -165,7 +165,7 @@ $gem-guide-border-width: 1px;
165
165
  h3,
166
166
  h4 {
167
167
  margin-top: 0;
168
- margin-bottom: $govuk-gutter / 2;
168
+ margin-bottom: calc($govuk-gutter / 2);
169
169
  }
170
170
 
171
171
  h3 a {
@@ -40,7 +40,7 @@
40
40
  list-style-type: none;
41
41
 
42
42
  @include govuk-media-query($from: tablet) {
43
- padding-top: govuk-spacing(6) / 4;
43
+ padding-top: calc(govuk-spacing(6) / 4);
44
44
  }
45
45
  }
46
46
 
@@ -186,7 +186,7 @@
186
186
  @include govuk-font($size: false);
187
187
  font-size: 16px;
188
188
  font-size: govuk-px-to-rem(16px);
189
- margin: 0 0 (govuk-spacing(3) / 2);
189
+ margin: 0 0 calc(govuk-spacing(3) / 2);
190
190
  color: govuk-colour("dark-grey", $legacy: "grey-1");
191
191
 
192
192
  @include govuk-media-query($from: tablet) {
@@ -196,7 +196,7 @@
196
196
 
197
197
  .gem-c-image-card__description {
198
198
  @include govuk-font($size: 19);
199
- padding-top: (govuk-spacing(3) / 2);
199
+ padding-top: calc(govuk-spacing(3) / 2);
200
200
  word-wrap: break-word;
201
201
  }
202
202
 
@@ -204,7 +204,7 @@
204
204
  @include govuk-font($size: 19);
205
205
  position: relative;
206
206
  z-index: 2;
207
- padding: (govuk-spacing(3) / 2) 0 0 0;
207
+ padding: calc(govuk-spacing(3) / 2) 0 0 0;
208
208
  margin: 0;
209
209
  list-style: none;
210
210
 
@@ -46,7 +46,7 @@ $govuk-modal-wide-breakpoint: $govuk-page-width + $govuk-modal-margin * 2 + $gov
46
46
  bottom: inherit;
47
47
  left: inherit;
48
48
  width: auto;
49
- max-width: $govuk-page-width * 2 / 3;
49
+ max-width: $govuk-page-width * calc(2 / 3);
50
50
  height: auto;
51
51
  margin: $govuk-modal-margin auto;
52
52
  border: $govuk-border-width-form-element solid $govuk-input-border-colour;
@@ -65,7 +65,7 @@ $large-input-size: 50px;
65
65
  }
66
66
 
67
67
  .gem-c-search__input[type="search"] { // overly specific to prevent some overrides from outside
68
- @include govuk-font($size: 19, $line-height: (28 / 19));
68
+ @include govuk-font($size: 19, $line-height: calc(28 / 19));
69
69
  margin: 0;
70
70
  width: 100%;
71
71
  height: govuk-em(40, 16);
@@ -108,7 +108,7 @@ $large-input-size: 50px;
108
108
 
109
109
  @mixin icon-positioning($container-size) {
110
110
  $icon-dimension: 20px;
111
- $icon-position: ($container-size - $icon-dimension) / 2;
111
+ $icon-position: calc(($container-size - $icon-dimension) / 2);
112
112
 
113
113
  display: block;
114
114
  pointer-events: none;
@@ -18,7 +18,7 @@ $share-button-height: 30px;
18
18
  padding-left: ($share-button-width + govuk-spacing(2));
19
19
  padding-right: govuk-spacing(2);
20
20
  margin-bottom: govuk-spacing(2);
21
- font-size: $share-button-height / 2;
21
+ font-size: calc($share-button-height / 2);
22
22
  }
23
23
 
24
24
  .gem-c-share-links__link {
@@ -32,7 +32,7 @@
32
32
  }
33
33
 
34
34
  .gem-c-step-nav-related__pretitle {
35
- margin-bottom: govuk-spacing(6) / 4;
35
+ margin-bottom: calc(govuk-spacing(6) / 4);
36
36
  }
37
37
  }
38
38
 
@@ -17,12 +17,12 @@ $top-border: solid 1px govuk-colour("mid-grey", $legacy: "grey-3");
17
17
 
18
18
  @mixin step-nav-line-position {
19
19
  left: 0;
20
- margin-left: govuk-em(($number-circle-size / 2) - ($stroke-width / 2), 16);
20
+ margin-left: govuk-em(calc($number-circle-size / 2) - calc($stroke-width / 2), 16);
21
21
  }
22
22
 
23
23
  @mixin step-nav-line-position-large {
24
24
  left: 0;
25
- margin-left: govuk-em(($number-circle-size-large / 2) - ($stroke-width / 2), 16);
25
+ margin-left: govuk-em(calc($number-circle-size-large / 2) - calc($stroke-width / 2), 16);
26
26
  }
27
27
 
28
28
  // custom mixin as govuk-font does undesirable things at different breakpoints
@@ -260,8 +260,8 @@ $top-border: solid 1px govuk-colour("mid-grey", $legacy: "grey-3");
260
260
  z-index: 6;
261
261
  bottom: 0;
262
262
  left: 0;
263
- margin-left: $number-circle-size / 4;
264
- width: $number-circle-size / 2;
263
+ margin-left: calc($number-circle-size / 4);
264
+ width: calc($number-circle-size / 2);
265
265
  height: 0;
266
266
  border-bottom: solid $stroke-width govuk-colour("mid-grey", $legacy: "grey-2");
267
267
  }
@@ -278,8 +278,8 @@ $top-border: solid 1px govuk-colour("mid-grey", $legacy: "grey-3");
278
278
  .gem-c-step-nav--large & {
279
279
  @include govuk-media-query($from: tablet) {
280
280
  &::before {
281
- margin-left: $number-circle-size-large / 4;
282
- width: $number-circle-size-large / 2;
281
+ margin-left: calc($number-circle-size-large / 4);
282
+ width: calc($number-circle-size-large / 2);
283
283
  }
284
284
 
285
285
  &::after {
@@ -508,9 +508,9 @@ $top-border: solid 1px govuk-colour("mid-grey", $legacy: "grey-3");
508
508
  z-index: 5;
509
509
  top: .6em; // position the dot to align with the first row of text in the link
510
510
  left: -(govuk-spacing(6) + govuk-spacing(3));
511
- margin-top: -($stroke-width / 2);
512
- margin-left: ($number-circle-size / 2);
513
- width: $number-circle-size / 2;
511
+ margin-top: - calc($stroke-width / 2);
512
+ margin-left: calc($number-circle-size / 2);
513
+ width: calc($number-circle-size / 2);
514
514
  height: $stroke-width;
515
515
  background: govuk-colour("black");
516
516
  }
@@ -519,7 +519,7 @@ $top-border: solid 1px govuk-colour("mid-grey", $legacy: "grey-3");
519
519
  @include govuk-media-query($from: tablet) {
520
520
  &::before {
521
521
  left: -(govuk-spacing(9));
522
- margin-left: ($number-circle-size-large / 2);
522
+ margin-left: calc($number-circle-size-large / 2);
523
523
  }
524
524
  }
525
525
  }
@@ -8,7 +8,7 @@ $table-header-background-colour: govuk-colour("light-grey", $legacy: "grey-3");
8
8
  $sort-link-active-colour: govuk-colour("white");
9
9
  $sort-link-arrow-size: 14px;
10
10
  $sort-link-arrow-size-small: 8px;
11
- $sort-link-arrow-spacing: $sort-link-arrow-size / 2;
11
+ $sort-link-arrow-spacing: calc($sort-link-arrow-size / 2);
12
12
  $table-row-hover-background-colour: rgba(43, 140, 196, .2);
13
13
  $table-row-even-background-colour: govuk-colour("light-grey", $legacy: "grey-4");
14
14
 
@@ -23,10 +23,10 @@
23
23
  padding-left: $icon-size;
24
24
 
25
25
  // Center the icon around the baseline
26
- padding-top: ($icon-size - $line-height-mobile) / 2;
26
+ padding-top: calc(($icon-size - $line-height-mobile) / 2);
27
27
 
28
28
  @include govuk-media-query($from: tablet) {
29
- padding-top: ($icon-size - $line-height-tablet) / 2;
29
+ padding-top: calc(($icon-size - $line-height-tablet) / 2);
30
30
  }
31
31
 
32
32
  p {
@@ -3,7 +3,7 @@
3
3
 
4
4
  @include govuk-font($size: 16);
5
5
 
6
- $gutter-two-thirds: $govuk-gutter - ($govuk-gutter / 3);
6
+ $gutter-two-thirds: $govuk-gutter - calc($govuk-gutter / 3);
7
7
 
8
8
  ol,
9
9
  ul,
@@ -48,7 +48,7 @@
48
48
  /// }
49
49
  ///
50
50
  @mixin columns($items, $columns, $selector: "*", $flow: row) {
51
- $rows: ceil($items / $columns);
51
+ $rows: ceil(calc($items / $columns));
52
52
 
53
53
  display: -ms-grid;
54
54
  display: grid;
@@ -157,7 +157,7 @@ module GovukPublishingComponents
157
157
  end
158
158
 
159
159
  def find_code_references(file, src, regex)
160
- return clean_file_path(file) if regex.match?(src)
160
+ clean_file_path(file) if regex.match?(src)
161
161
  end
162
162
 
163
163
  def clean_file_path(file)
@@ -31,7 +31,7 @@ module GovukPublishingComponents
31
31
  end
32
32
 
33
33
  def component_in_use(component)
34
- return true if @limit_to.include?(component)
34
+ true if @limit_to.include?(component)
35
35
  end
36
36
 
37
37
  def fetch_component_doc(id)
@@ -2,23 +2,39 @@
2
2
  add_gem_component_stylesheet("details")
3
3
 
4
4
  shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new(local_assigns)
5
-
6
5
  open ||= nil
6
+ disable_ga4 ||= false
7
+ @ga4 ||= OpenStruct.new(index_section: 0) unless disable_ga4
8
+ @ga4[:index_section] += 1 unless disable_ga4
9
+ ga4_attributes ||= {}
10
+
7
11
  margin_bottom ||= 3
8
12
  css_classes = %w(gem-c-details govuk-details)
9
13
  css_classes << shared_helper.get_margin_bottom
10
14
 
11
15
  details_data_attributes = {}
12
16
  details_data_attributes[:module] = 'govuk-details gem-details'
17
+ details_data_attributes[:module] = 'govuk-details gem-details ga4-event-tracker' unless disable_ga4
13
18
 
14
19
  data_attributes ||= {}
15
20
  data_attributes[:details_track_click] = ''
21
+ unless disable_ga4
22
+ ga4_event = {
23
+ event_name: "select_content",
24
+ type: "detail",
25
+ text: title,
26
+ section: title,
27
+ index_section: @ga4[:index_section],
28
+ }
29
+ ga4_event.merge!(ga4_attributes)
30
+ data_attributes[:ga4_event] = ga4_event
31
+ end
16
32
 
17
33
  summary_aria_attributes ||= {}
18
34
  %>
19
35
  <%= tag.details class: css_classes, data: details_data_attributes, open: open do %>
20
36
  <%= tag.summary class: "govuk-details__summary", data: data_attributes, aria: summary_aria_attributes do %>
21
- <span class="govuk-details__summary-text">
37
+ <span class="govuk-details__summary-text" <% unless disable_ga4 %>data-ga4-expandable<% end %>>
22
38
  <%= title %>
23
39
  </span>
24
40
  <% end %>
@@ -7,13 +7,13 @@
7
7
  brand_helper = GovukPublishingComponents::AppHelpers::BrandHelper.new(brand)
8
8
  card_helper = GovukPublishingComponents::Presenters::ImageCardHelper.new(local_assigns, brand_helper)
9
9
  shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new(local_assigns)
10
-
11
- classes = %w[gem-c-image-card]
12
- classes << "govuk-grid-row" if card_helper.two_thirds
13
- classes << "gem-c-image-card--large" if card_helper.large
14
- classes << "gem-c-image-card--two-thirds" if card_helper.two_thirds
15
- classes << "gem-c-image-card--no-image" unless (card_helper.image_src || card_helper.youtube_video_id)
16
- classes << brand_helper.brand_class if brand_helper.brand_class
10
+ component_helper = GovukPublishingComponents::Presenters::ComponentWrapperHelper.new(local_assigns)
11
+ component_helper.add_class("gem-c-image-card")
12
+ component_helper.add_class("govuk-grid-row") if card_helper.two_thirds
13
+ component_helper.add_class("gem-c-image-card--large") if card_helper.large
14
+ component_helper.add_class("gem-c-image-card--two-thirds") if card_helper.two_thirds
15
+ component_helper.add_class("gem-c-image-card--no-image") unless (card_helper.image_src || card_helper.youtube_video_id)
16
+ component_helper.add_class(brand_helper.brand_class) if brand_helper.brand_class
17
17
 
18
18
  text_wrapper_classes = %w[gem-c-image-card__text-wrapper]
19
19
  text_wrapper_classes << "gem-c-image-card__text-wrapper--two-thirds" if card_helper.two_thirds
@@ -34,12 +34,12 @@
34
34
  ]
35
35
  extra_link_classes << brand_helper.color_class
36
36
 
37
- data_modules = %w[]
38
- data_modules << "gem-track-click ga4-link-tracker" if card_helper.is_tracking?
39
- data_modules << "image-card" if card_helper.youtube_video_id
37
+ component_helper.add_data_attribute({ module: "gem-track-click" }) if card_helper.is_tracking?
38
+ component_helper.add_data_attribute({ module: "image-card" }) if card_helper.youtube_video_id
39
+ component_helper.set_lang(card_helper.lang)
40
40
  %>
41
41
  <% if card_helper.href || card_helper.extra_details.any? %>
42
- <%= content_tag(:div, class: classes, "data-module": data_modules, lang: card_helper.lang) do %>
42
+ <%= tag.div(**component_helper.all_attributes) do %>
43
43
  <%= content_tag(:div, class: text_wrapper_classes) do %>
44
44
  <div class="gem-c-image-card__header-and-context-wrapper">
45
45
  <% if card_helper.heading_text %>