govuk_publishing_components 34.14.0 → 35.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-form-tracker.js +9 -7
  3. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js +6 -1
  4. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/pii-remover.js +4 -2
  5. data/app/assets/javascripts/govuk_publishing_components/components/accordion.js +1 -1
  6. data/app/models/govuk_publishing_components/audit_applications.rb +10 -19
  7. data/app/models/govuk_publishing_components/audit_comparer.rb +28 -23
  8. data/app/models/govuk_publishing_components/component_wrapper_helper_options.rb +2 -1
  9. data/app/views/govuk_publishing_components/audit/_applications.html.erb +2 -2
  10. data/app/views/govuk_publishing_components/components/_accordion.html.erb +18 -39
  11. data/app/views/govuk_publishing_components/components/_cards.html.erb +4 -4
  12. data/app/views/govuk_publishing_components/components/_checkboxes.html.erb +5 -3
  13. data/app/views/govuk_publishing_components/components/_contents_list.html.erb +9 -15
  14. data/app/views/govuk_publishing_components/components/_step_by_step_nav.html.erb +3 -1
  15. data/app/views/govuk_publishing_components/components/_tabs.html.erb +20 -2
  16. data/app/views/govuk_publishing_components/components/docs/accordion.yml +1 -0
  17. data/app/views/govuk_publishing_components/components/docs/cards.yml +1 -0
  18. data/app/views/govuk_publishing_components/components/docs/checkboxes.yml +1 -0
  19. data/app/views/govuk_publishing_components/components/docs/contents_list.yml +1 -12
  20. data/app/views/govuk_publishing_components/components/docs/step_by_step_nav.yml +20 -0
  21. data/app/views/govuk_publishing_components/components/docs/tabs.yml +15 -0
  22. data/lib/govuk_publishing_components/presenters/accordion_helper.rb +38 -0
  23. data/lib/govuk_publishing_components/presenters/component_wrapper_helper.rb +25 -8
  24. data/lib/govuk_publishing_components/presenters/step_by_step_nav_helper.rb +16 -0
  25. data/lib/govuk_publishing_components/version.rb +1 -1
  26. data/lib/govuk_publishing_components.rb +2 -1
  27. metadata +5 -4
  28. /data/lib/govuk_publishing_components/presenters/{breadcrumbs.rb → breadcrumbs_helper.rb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4137db9fa2f61ba41157832c2d8a959756eb36e11837e4d58654b264d68a3f0
4
- data.tar.gz: a3eb50516bf440839af9b74e1fc5ab44e9fc21ee0afb7910cdb742d10a6d3182
3
+ metadata.gz: 90043704d7994696d49541ef766ca866648e3594be347483450194425d229dc7
4
+ data.tar.gz: 43f81d610ba1484584043399cd9b69219aaa010f00241dcb11fbffc24d6ea2de
5
5
  SHA512:
6
- metadata.gz: 3e780d3b9f9f2e72c471767c7be3bb611bae0eb7f2b211e19ae85b6fdae4338ae20d346c53b72c6d1b1d0e3d06447084eb389aeb64960df48b68d60bdaa4ed7e
7
- data.tar.gz: 7cfd8703805c415ffad093fd18dc104d6d41c7e51305673c178b90778eb52bf3037b52ea2550cdb42c0ba4291d6e53c95c577800f2b8fe398ee503c1a3910b76
6
+ metadata.gz: a656046225d2491310ba439b342b639844dbdcdfcf908ace0d26a2db995c2aa4813a9273298591a595b2224a018167f17a3aea2ae67555b472f2ac75f7f26e5e
7
+ data.tar.gz: 6f1110a0611153a5d1d494f7afc38523efb1db88949757756b11acfad77306408d12794be83753aed7bc618f10a30c6463e0719e8a7f4f24a67328a071d147c2
@@ -8,6 +8,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
8
8
  this.module = module
9
9
  this.trackingTrigger = 'data-ga4-form' // elements with this attribute get tracked
10
10
  this.includeTextInputValues = this.module.hasAttribute('data-ga4-form-include-text')
11
+ this.redacted = false
11
12
  }
12
13
 
13
14
  Ga4FormTracker.prototype.init = function () {
@@ -88,7 +89,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
88
89
  var PIIRemover = new window.GOVUK.analyticsGa4.PIIRemover()
89
90
  input.answer = PIIRemover.stripPIIWithOverride(elem.value, true, true)
90
91
  } else {
91
- input.answer = '[REDACTED]'
92
+ this.redacted = true
92
93
  }
93
94
  } else if (inputType === 'radio' && elem.checked) {
94
95
  input.answer = labelText
@@ -101,18 +102,19 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
101
102
  }
102
103
 
103
104
  Ga4FormTracker.prototype.combineGivenAnswers = function (data) {
104
- var answers = ''
105
+ var answers = []
105
106
  for (var i = 0; i < data.length; i++) {
106
107
  var answer = data[i].answer
107
108
  if (answer) {
108
- answers += answer + ','
109
+ answers.push(answer)
109
110
  }
110
111
  }
111
- // remove the trailing comma
112
- if (answers.length) {
113
- answers = answers.slice(0, -1)
114
- return answers
112
+ if (this.redacted) {
113
+ answers.push('[REDACTED]')
115
114
  }
115
+
116
+ answers = answers.join(',')
117
+ return answers
116
118
  }
117
119
 
118
120
  Modules.Ga4FormTracker = Ga4FormTracker
@@ -61,6 +61,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
61
61
 
62
62
  Ga4LinkTracker.prototype.trackClick = function (event) {
63
63
  var element = event.target
64
+ var PIIRemover = new window.GOVUK.analyticsGa4.PIIRemover()
64
65
 
65
66
  // don't track this link if it's already being tracked by the ecommerce tracker
66
67
  if (element.closest('[data-ga4-ecommerce-path]')) {
@@ -81,7 +82,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
81
82
  var text = data.text || event.target.textContent
82
83
  data.text = window.GOVUK.analyticsGa4.core.trackFunctions.removeLinesAndExtraSpaces(text)
83
84
  var url = data.url || this.findLink(event.target).getAttribute('href')
84
- data.url = window.GOVUK.analyticsGa4.core.trackFunctions.removeCrossDomainParams(url)
85
+ data.url = window.GOVUK.analyticsGa4.core.trackFunctions.removeCrossDomainParams(PIIRemover.stripPII(url))
85
86
  data.link_domain = window.GOVUK.analyticsGa4.core.trackFunctions.populateLinkDomain(data.url)
86
87
  data.link_path_parts = window.GOVUK.analyticsGa4.core.trackFunctions.populateLinkPathParts(data.url)
87
88
  data.method = window.GOVUK.analyticsGa4.core.trackFunctions.getClickType(event)
@@ -89,6 +90,10 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
89
90
  data.index = event.target.getAttribute('data-ga4-index') ? parseInt(event.target.getAttribute('data-ga4-index')) : data.index || undefined
90
91
  data.index = window.GOVUK.analyticsGa4.core.trackFunctions.createIndexObject(data.index)
91
92
 
93
+ if (data.type === 'smart answer' && data.action === 'change response') {
94
+ data.section = PIIRemover.stripPIIWithOverride(data.section, true, true)
95
+ }
96
+
92
97
  var schemas = new window.GOVUK.analyticsGa4.Schemas()
93
98
  var schema = schemas.mergeProperties(data, 'event_data')
94
99
  window.GOVUK.analyticsGa4.core.sendData(schema)
@@ -4,7 +4,8 @@
4
4
  var GOVUK = global.GOVUK || {}
5
5
  var EMAIL_PATTERN = /[^\s=/?&#]+(?:@|%40)[^\s=/?&]+/g
6
6
  var POSTCODE_PATTERN = /\b[A-PR-UWYZ][A-HJ-Z]?[0-9][0-9A-HJKMNPR-Y]?(?:[\s+]|%20)*[0-9](?!refund)[ABD-HJLNPQ-Z]{2,3}\b/gi
7
- var DATE_PATTERN = /\d{4}(-?)\d{2}(-?)\d{2}/g
7
+ var DATE_PATTERN_NUMERIC = /\d{4}(-?)\d{2}(-?)\d{2}/g
8
+ var DATE_PATTERN_STRING = /\d{1,2}\s(January|February|March|April|May|June|July|August|September|October|November|December)\s\d{4}/g
8
9
  var ESCAPE_REGEX_PATTERN = /[|\\{}()[\]^$+*?.]/g
9
10
 
10
11
  // specific URL parameters to be redacted from accounts URLs
@@ -85,7 +86,8 @@
85
86
  stripped = this.stripQueryStringParameters(stripped)
86
87
 
87
88
  if (this.stripDatePII === true) {
88
- stripped = stripped.replace(DATE_PATTERN, '[date]')
89
+ stripped = stripped.replace(DATE_PATTERN_NUMERIC, '[date]')
90
+ stripped = stripped.replace(DATE_PATTERN_STRING, '[date]')
89
91
  }
90
92
  if (this.stripPostcodePII === true) {
91
93
  stripped = stripped.replace(POSTCODE_PATTERN, '[postcode]')
@@ -62,7 +62,7 @@ window.GOVUK.Modules.GovukAccordion = window.GOVUKFrontend.Accordion;
62
62
  var isGa4Enabled = dataModule ? dataModule.indexOf('ga4-event-tracker') !== -1 : false
63
63
  if (isGa4Enabled) {
64
64
  var indexTotal = this.$module.querySelectorAll('.govuk-accordion__section').length
65
- var showAllAttributesGa4 = { event_name: 'select_content', type: 'accordion', index: 0, index_total: indexTotal }
65
+ var showAllAttributesGa4 = { event_name: 'select_content', type: 'accordion', index: { index_section: 0, index_section_count: indexTotal } }
66
66
  showAll = this.$module.querySelector(this.showAllControls)
67
67
  showAll.setAttribute('data-ga4-event', JSON.stringify(showAllAttributesGa4))
68
68
  }
@@ -21,16 +21,12 @@ module GovukPublishingComponents
21
21
  @find_all_stylesheets = /@import ["']{1}govuk_publishing_components\/all_components/
22
22
  find_stylesheets = /(?<=@import ["']{1}govuk_publishing_components\/components\/)(?!print\/)+[a-zA-Z_-]+(?=['"])/
23
23
 
24
- @find_all_print_stylesheets = /@import ["']{1}govuk_publishing_components\/all_components_print/
25
- find_print_stylesheets = /(?<=@import ["']{1}govuk_publishing_components\/components\/print\/)[a-zA-Z_-]+(?=['"])/
26
-
27
24
  @find_all_javascripts = /\/\/ *= require govuk_publishing_components\/all_components/
28
25
  find_javascripts = /(?<=require govuk_publishing_components\/components\/)[a-zA-Z_-]+/
29
26
 
30
- components_in_templates = find_components(templates, find_components, "templates", true) || []
31
- components_in_stylesheets = find_components(stylesheets, find_stylesheets, "stylesheets", false) || []
32
- components_in_print_stylesheets = find_components(stylesheets, find_print_stylesheets, "print_stylesheets", false) || []
33
- components_in_javascripts = find_components(javascripts, find_javascripts, "javascripts", false) || []
27
+ components_in_templates = find_components(templates, find_components, "template", true) || []
28
+ components_in_stylesheets = find_components(stylesheets, find_stylesheets, "stylesheet", false) || []
29
+ components_in_javascripts = find_components(javascripts, find_javascripts, "javascript", false) || []
34
30
 
35
31
  ruby_paths = %w[/app/helpers/ /app/presenters/ /lib/]
36
32
  components_in_ruby = []
@@ -41,19 +37,15 @@ module GovukPublishingComponents
41
37
 
42
38
  components_found = [
43
39
  {
44
- location: "templates",
40
+ location: "template",
45
41
  components: components_in_templates,
46
42
  },
47
43
  {
48
- location: "stylesheets",
44
+ location: "stylesheet",
49
45
  components: components_in_stylesheets,
50
46
  },
51
47
  {
52
- location: "print_stylesheets",
53
- components: components_in_print_stylesheets,
54
- },
55
- {
56
- location: "javascripts",
48
+ location: "javascript",
57
49
  components: components_in_javascripts,
58
50
  },
59
51
  {
@@ -97,9 +89,9 @@ module GovukPublishingComponents
97
89
  components_found << find_match(find, src, type)
98
90
  end
99
91
 
100
- get_helper_references(file, src) if %w[ruby templates].include?(type)
92
+ get_helper_references(file, src) if %w[ruby template].include?(type)
101
93
 
102
- if type == "javascripts"
94
+ if type == "javascript"
103
95
  jquery_references = find_code_references(file, src, /\$\(/)
104
96
  @jquery_references << jquery_references if jquery_references
105
97
  else
@@ -130,9 +122,8 @@ module GovukPublishingComponents
130
122
  # looks for components in the given src of a file
131
123
  # returns an array of component names or an empty array
132
124
  def find_match(find, src, type)
133
- return %w[all] if src.match(@find_all_stylesheets) && type == "stylesheets"
134
- return %w[all] if src.match(@find_all_print_stylesheets) && type == "print_stylesheets"
135
- return %w[all] if src.match(@find_all_javascripts) && type == "javascripts"
125
+ return %w[all] if src.match(@find_all_stylesheets) && type == "stylesheet"
126
+ return %w[all] if src.match(@find_all_javascripts) && type == "javascript"
136
127
 
137
128
  matches = src.scan(find)
138
129
  return [] unless matches.any?
@@ -40,7 +40,7 @@ module GovukPublishingComponents
40
40
  end
41
41
 
42
42
  # turn static data into an object so locations can be easily referenced
43
- # should give object of form { "templates" => [], "stylesheets" => [] }
43
+ # should give object of form { "template" => [], "stylesheet" => [] }
44
44
  def clean_static(data)
45
45
  Hash[data[:components_found].map { |d| [d[:location], d[:components]] }]
46
46
  end
@@ -55,14 +55,12 @@ module GovukPublishingComponents
55
55
  results.each do |result|
56
56
  if result[:application_found]
57
57
  application_uses_static = @applications_using_static.include?(result[:name])
58
- templates = result[:components_found].find { |c| c[:location] == "templates" }
59
- stylesheets = result[:components_found].find { |c| c[:location] == "stylesheets" }
60
- print_stylesheets = result[:components_found].find { |c| c[:location] == "print_stylesheets" }
61
- javascripts = result[:components_found].find { |c| c[:location] == "javascripts" }
58
+ templates = result[:components_found].find { |c| c[:location] == "template" }
59
+ stylesheets = result[:components_found].find { |c| c[:location] == "stylesheet" }
60
+ javascripts = result[:components_found].find { |c| c[:location] == "javascript" }
62
61
  ruby = result[:components_found].find { |c| c[:location] == "ruby" }
63
62
 
64
63
  @all_stylesheets = true if stylesheets[:components].include?("all")
65
- @all_print_stylesheets = true if print_stylesheets[:components].include?("all")
66
64
  @all_javascripts = true if javascripts[:components].include?("all")
67
65
 
68
66
  templates[:components] = include_any_components_within_components(templates[:components])
@@ -77,24 +75,20 @@ module GovukPublishingComponents
77
75
 
78
76
  summary = [
79
77
  {
80
- name: "Components in templates",
81
- value: templates[:components].flatten.uniq.sort.join(", "),
78
+ name: "In templates",
79
+ value: templates[:components],
82
80
  },
83
81
  {
84
- name: "Components in stylesheets",
85
- value: stylesheets[:components].join(", "),
82
+ name: "In stylesheets",
83
+ value: stylesheets[:components],
86
84
  },
87
85
  {
88
- name: "Components in print stylesheets",
89
- value: print_stylesheets[:components].join(", "),
86
+ name: "In javascripts",
87
+ value: javascripts[:components],
90
88
  },
91
89
  {
92
- name: "Components in javascripts",
93
- value: javascripts[:components].join(", "),
94
- },
95
- {
96
- name: "Components in ruby",
97
- value: ruby[:components].join(", "),
90
+ name: "In ruby",
91
+ value: ruby[:components],
98
92
  },
99
93
  ]
100
94
 
@@ -145,7 +139,7 @@ module GovukPublishingComponents
145
139
 
146
140
  second_group.each do |second|
147
141
  second_location = second[:location]
148
- second_location = "code" if %w[templates ruby].include?(second_location)
142
+ second_location = "code" if %w[template ruby].include?(second_location)
149
143
  # subtract one group from the other, leaving only those not in both
150
144
  in_current = find_missing(second[:components].clone, first[:components].clone)
151
145
 
@@ -153,7 +147,18 @@ module GovukPublishingComponents
153
147
 
154
148
  # now we have a list of 'missing' component assets, check the gem to see if that asset exists
155
149
  in_current.each do |component|
156
- asset_in_gem = @gem_data.include?("component_#{second_location}".to_sym) && @gem_data["component_#{second_location}".to_sym].include?(component)
150
+ component_assets = @gem_data[:component_file_details].select { |c| c[:name] == component }
151
+ if !component_assets.empty?
152
+ component_assets = component_assets[0]
153
+ asset_in_gem = if second_location == "code"
154
+ component_assets["template_exists".to_sym]
155
+ else
156
+ component_assets["#{second_location}_exists".to_sym]
157
+ end
158
+ else
159
+ asset_in_gem = false
160
+ end
161
+
157
162
  check_static = @static_data && second_location != "code"
158
163
  asset_in_static = asset_already_in_static(second_location, component) if check_static
159
164
  raise_warning = asset_in_gem && !asset_in_static
@@ -177,7 +182,7 @@ module GovukPublishingComponents
177
182
  warnings = []
178
183
 
179
184
  locations.each do |location|
180
- next if location[:location] == "templates" || location[:location] == "ruby"
185
+ next if location[:location] == "template" || location[:location] == "ruby"
181
186
 
182
187
  location[:components].each do |component|
183
188
  raise_warning = asset_already_in_static(location[:location], component)
@@ -191,14 +196,14 @@ module GovukPublishingComponents
191
196
  def warn_about_missing_assets(components)
192
197
  warnings = []
193
198
 
194
- code = components.select { |c| c[:location] == "templates" || c[:location] == "ruby" }
199
+ code = components.select { |c| c[:location] == "template" || c[:location] == "ruby" }
195
200
  code = [
196
201
  {
197
202
  location: "code",
198
203
  components: code.map { |c| c[:components] }.flatten.uniq.sort,
199
204
  },
200
205
  ]
201
- assets = components.select { |c| c[:location] == "stylesheets" || c[:location] == "print_stylesheets" || c[:location] == "javascripts" }
206
+ assets = components.select { |c| c[:location] == "stylesheet" || c[:location] == "javascript" }
202
207
 
203
208
  warnings << find_missing_items(code, assets)
204
209
  warnings << find_missing_items(assets, code)
@@ -5,9 +5,10 @@ module GovukPublishingComponents
5
5
  This component uses the component wrapper helper. It accepts the following options and applies them to the parent element of the component. See the [component wrapper helper documentation](https://github.com/alphagov/govuk_publishing_components/blob/main/docs/component-wrapper-helper.md) for more detail.
6
6
 
7
7
  - `id` - accepts a string for the element ID attribute
8
- - `data` - accepts a hash of data attributes
8
+ - `data_attributes` - accepts a hash of data attributes
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
+ - `role` - accepts a space separated string of roles
11
12
  "
12
13
  end
13
14
  end
@@ -62,11 +62,11 @@
62
62
  <% application[:summary].each do |item| %>
63
63
  <div class="govuk-summary-list__row">
64
64
  <dt class="govuk-summary-list__key">
65
- <%= item[:name] %>
65
+ <%= item[:name] %> (<%= item[:value].length %>)
66
66
  </dt>
67
67
  <dd class="govuk-summary-list__value">
68
68
  <% if item[:value].length > 0 %>
69
- <%= item[:value] %>
69
+ <%= item[:value].join(", ") %>
70
70
  <% else %>
71
71
  None
72
72
  <% end %>
@@ -3,55 +3,32 @@
3
3
 
4
4
  local_assigns[:margin_bottom] ||= 6
5
5
  shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new(local_assigns)
6
+ accordion_helper = GovukPublishingComponents::Presenters::AccordionHelper.new()
6
7
 
7
8
  id ||= "default-id-#{SecureRandom.hex(4)}"
8
9
  items ||= []
9
10
  anchor_navigation ||= false
10
11
  track_show_all_clicks ||= false
11
12
  track_sections ||= false
12
-
13
- accordion_classes = %w(gem-c-accordion govuk-accordion)
14
- accordion_classes << (shared_helper.get_margin_bottom)
15
-
16
- translations = {
17
- show_text: "common.show",
18
- hide_text: "common.hide",
19
- show_all_text: "components.accordion.show_all",
20
- hide_all_text: "components.accordion.hide_all",
21
- this_section_visually_hidden: "components.accordion.this_section_visually_hidden",
22
- }
23
-
24
- locales = {}
25
-
26
- data_attributes ||= {}
27
- ((data_attributes[:module] ||= "") << " " << "govuk-accordion gem-accordion").strip!
28
13
  ga4_tracking ||= false
29
- data_attributes[:module] << " ga4-event-tracker" if ga4_tracking
30
- data_attributes[:ga4_expandable] = '' if ga4_tracking
31
- data_attributes[:anchor_navigation] = anchor_navigation
32
- data_attributes[:track_show_all_clicks] = track_show_all_clicks
33
- data_attributes[:track_sections] = track_sections
34
14
  data_attributes_show_all ||= nil
35
- data_attributes[:show_all_attributes] = data_attributes_show_all if data_attributes_show_all
36
-
37
- translations.each do |key, translation|
38
- locales[key] = shared_helper.t_locale(translation)
39
- data_attributes[key] = t(translation)
40
- end
41
-
42
- unique_locales = locales.values.uniq
43
15
 
44
- if unique_locales.length > 1
45
- data_attributes[:locale] = locales
46
- else
47
- if unique_locales[0] != I18n.locale
48
- data_attributes[:locale] = unique_locales[0]
49
- end
50
- end
16
+ component_helper = GovukPublishingComponents::Presenters::ComponentWrapperHelper.new(local_assigns)
17
+ component_helper.set_id(id)
18
+ component_helper.add_class("gem-c-accordion govuk-accordion")
19
+ component_helper.add_class(shared_helper.get_margin_bottom)
51
20
 
21
+ component_helper.add_data_attribute({ module: "govuk-accordion gem-accordion" })
22
+ component_helper.add_data_attribute({ module: "ga4-event-tracker" }) if ga4_tracking
23
+ component_helper.add_data_attribute({ ga4_expandable: "" }) if ga4_tracking
24
+ component_helper.add_data_attribute({ anchor_navigation: anchor_navigation }) if anchor_navigation
25
+ component_helper.add_data_attribute({ track_show_all_clicks: track_show_all_clicks }) if track_show_all_clicks
26
+ component_helper.add_data_attribute({ track_sections: track_sections }) if track_sections
27
+ component_helper.add_data_attribute({ show_all_attributes: data_attributes_show_all }) if data_attributes_show_all
28
+ component_helper.add_data_attribute(accordion_helper.apply_translations)
52
29
  %>
53
30
  <% if items.any? %>
54
- <%= tag.div(class: accordion_classes, id: id, data: data_attributes) do %>
31
+ <%= tag.div(**component_helper.all_attributes) do %>
55
32
  <% items.each_with_index do |item, i| %>
56
33
  <%
57
34
  # The GOVUK Frontend JavaScript for this component
@@ -67,8 +44,10 @@
67
44
  event_name: "select_content",
68
45
  type: "accordion",
69
46
  text: item[:heading][:text],
70
- index: index,
71
- index_total: items.length
47
+ index: {
48
+ index_section: index,
49
+ index_section_count: items.length,
50
+ },
72
51
  }.to_json
73
52
  end
74
53
 
@@ -5,16 +5,16 @@
5
5
  items ||= nil
6
6
  sub_heading_level ||= 3
7
7
  two_column_layout ||= false
8
- local_assigns ||= nil
9
- data_attributes ||= nil
10
8
 
11
9
  ul_classes = %w[gem-c-cards__list]
12
10
  ul_classes << 'gem-c-cards__list--two-column-desktop' if two_column_layout
13
11
 
14
12
  shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new(local_assigns)
13
+ component_helper = GovukPublishingComponents::Presenters::ComponentWrapperHelper.new(local_assigns)
14
+ component_helper.add_class("gem-c-cards")
15
15
  %>
16
16
  <% if items.present? %>
17
- <div class="gem-c-cards">
17
+ <%= tag.div(**component_helper.all_attributes) do %>
18
18
  <% if heading %>
19
19
  <%= content_tag(shared_helper.get_heading_level, class: "gem-c-cards__heading govuk-heading-m") do %>
20
20
  <%= heading %>
@@ -49,5 +49,5 @@
49
49
  </li>
50
50
  <% end %>
51
51
  <% end %>
52
- </div>
52
+ <% end %>
53
53
  <% end %>
@@ -1,12 +1,14 @@
1
1
  <%
2
2
  add_gem_component_stylesheet("checkboxes")
3
-
4
- # cb_helper.css_classes generates "gem-c-checkboxes"
5
3
  cb_helper = GovukPublishingComponents::Presenters::CheckboxesHelper.new(local_assigns)
6
4
  id = cb_helper.id
5
+ component_helper = GovukPublishingComponents::Presenters::ComponentWrapperHelper.new(local_assigns)
6
+ component_helper.set_id(id)
7
+ component_helper.add_class(cb_helper.css_classes.join(" ")) # cb_helper.css_classes generates "gem-c-checkboxes"
8
+ component_helper.add_data_attribute({ module: "gem-checkboxes govuk-checkboxes" })
7
9
  %>
8
10
 
9
- <%= tag.div id: id, class: cb_helper.css_classes, data: { module: "gem-checkboxes govuk-checkboxes" } do %>
11
+ <%= tag.div(**component_helper.all_attributes) do %>
10
12
  <% if cb_helper.should_have_fieldset %>
11
13
  <% if cb_helper.heading_markup %>
12
14
  <%= tag.fieldset class: "govuk-fieldset", "aria-describedby": cb_helper.fieldset_describedby do %>
@@ -3,30 +3,24 @@
3
3
 
4
4
  cl_helper = GovukPublishingComponents::Presenters::ContentsListHelper.new(local_assigns)
5
5
  underline_links ||= false
6
- aria_label ||= t("components.contents_list.contents")
7
6
  format_numbers ||= false
8
7
  brand ||= false
9
8
  brand_helper = GovukPublishingComponents::AppHelpers::BrandHelper.new(brand)
10
9
  title_fallback = t("components.contents_list.contents", locale: I18n.locale, fallback: false, default: "en")
11
10
  classes = %w[gem-c-contents-list]
12
- classes << brand_helper.brand_class
13
- link_classes = %w[
14
- gem-c-contents-list__link
15
- govuk-link
16
- ]
11
+ link_classes = %w[gem-c-contents-list__link govuk-link]
17
12
  link_classes << brand_helper.color_class
18
13
  link_classes << "govuk-link--no-underline" unless underline_links
14
+
15
+ local_assigns[:aria] ||= {}
16
+ component_helper = GovukPublishingComponents::Presenters::ComponentWrapperHelper.new(local_assigns)
17
+ component_helper.add_class("gem-c-contents-list #{brand_helper.brand_class}")
18
+ component_helper.add_data_attribute({ module: "gem-track-click" })
19
+ component_helper.add_aria_attribute({ label: t("components.contents_list.contents") }) unless local_assigns[:aria][:label]
20
+ component_helper.add_role("navigation")
19
21
  -%>
20
22
  <% if cl_helper.contents.any? %>
21
- <%= content_tag(
22
- :nav,
23
- class: classes,
24
- "aria-label": aria_label,
25
- role: "navigation",
26
- data: {
27
- module: "gem-track-click"
28
- }
29
- ) do %>
23
+ <%= tag.nav(**component_helper.all_attributes) do %>
30
24
  <%= content_tag(
31
25
  :h2, {class: "gem-c-contents-list__title"}.merge(
32
26
  title_fallback == "en" ? {:lang => "en",} : {}
@@ -22,7 +22,7 @@
22
22
  %>
23
23
  <% if steps %>
24
24
  <div
25
- data-module="gemstepnav<% if ga4_tracking %> ga4-event-tracker<% end %>"
25
+ data-module="gemstepnav<% if ga4_tracking %> ga4-event-tracker ga4-link-tracker<% end %>"
26
26
  <%= "data-ga4-expandable" if ga4_tracking %>
27
27
  class="gem-c-step-nav js-hidden <% if small %>govuk-!-display-none-print<% end %> <% unless small %>gem-c-step-nav--large<% end %>"
28
28
  <%= "data-remember" if remember_last_step %>
@@ -77,8 +77,10 @@
77
77
  <%
78
78
  in_substep = false
79
79
  options[:step_nav_content_id] = step_nav_content_id
80
+ options[:step_title] = step[:title]
80
81
  options[:step_index] = step_index
81
82
  options[:link_index] = 0
83
+ options[:ga4_tracking] = ga4_tracking
82
84
  %>
83
85
  <% step[:contents].each do |element| %>
84
86
  <%= step_nav_helper.render_step_nav_element(element, options) %>
@@ -6,15 +6,33 @@
6
6
  panel_css_classes = %w(govuk-tabs__panel)
7
7
  panel_css_classes << "gem-c-tabs__panel--no-border" if panel_border == false
8
8
  panel_css_classes = panel_css_classes.join(" ")
9
+
10
+ ga4_tracking ||= false
11
+ data_module = "govuk-tabs"
12
+ data_module << " ga4-event-tracker" if ga4_tracking
9
13
  %>
10
14
  <% if tabs.count > 1 %>
11
- <div class="govuk-tabs gem-c-tabs" data-module="govuk-tabs">
15
+ <div class="govuk-tabs gem-c-tabs" data-module="<%= data_module %>">
12
16
  <h2 class="govuk-tabs__title">
13
17
  <%= t("components.tabs.contents") %>
14
18
  </h2>
15
19
  <ul class="govuk-tabs__list">
16
- <% tabs.each do |tab| %>
20
+ <% tabs.each_with_index do |tab, index| %>
17
21
  <li class="govuk-tabs__list-item">
22
+ <%
23
+ tab[:tab_data_attributes] ||= {}
24
+ if ga4_tracking
25
+ tab[:tab_data_attributes][:ga4_event] = {
26
+ event_name: "select_content",
27
+ type: "tabs",
28
+ text: tab[:label],
29
+ index: {
30
+ index_section: index + 1,
31
+ index_section_count: tabs.length,
32
+ },
33
+ }
34
+ end
35
+ %>
18
36
  <%= link_to(tab[:label],
19
37
  "##{tab[:id]}",
20
38
  class: "govuk-tabs__tab",
@@ -34,6 +34,7 @@ accessibility_criteria: |
34
34
 
35
35
  * be fully expanded
36
36
  * not be marked as expandable
37
+ uses_component_wrapper_helper: true
37
38
  shared_accessibility_criteria:
38
39
  - link
39
40
  examples:
@@ -16,6 +16,7 @@ accessibility_criteria: |
16
16
  It is also good practise to include a heading above the list to tell users what the list contains
17
17
  shared_accessibility_criteria:
18
18
  - link
19
+ uses_component_wrapper_helper: true
19
20
  examples:
20
21
  default:
21
22
  data:
@@ -15,6 +15,7 @@ accessibility_criteria: |
15
15
  - have correctly associated labels
16
16
 
17
17
  Labels use the [label component](/component-guide/label).
18
+ uses_component_wrapper_helper: true
18
19
  examples:
19
20
  default:
20
21
  data:
@@ -24,6 +24,7 @@ shared_accessibility_criteria:
24
24
  - link
25
25
  accessibility_excluded_rules:
26
26
  - skip-link # The examples for this component are using references to sections on the page that do not exist in examples
27
+ uses_component_wrapper_helper: true
27
28
  examples:
28
29
  default:
29
30
  data:
@@ -65,18 +66,6 @@ examples:
65
66
  active: true
66
67
  - href: "#third-thing"
67
68
  text: Third thing
68
- with_custom_aria_label:
69
- description: 'An `aria-label` string should be used to contextualise the navigation for assistive technology. Defaults to `Contents` if `aria-label` is not passed.'
70
- data:
71
- aria_label: "Pages in this guide"
72
- contents:
73
- - href: "#first-thing"
74
- text: First
75
- - href: "#two"
76
- text: Second
77
- active: true
78
- - href: "#third-thing"
79
- text: Third thing
80
69
  nested_contents_lists:
81
70
  data:
82
71
  contents:
@@ -79,6 +79,8 @@ examples:
79
79
  GA4 will then track these elements when they are expanded or collapsed.
80
80
  `data-ga4-event` contains a JSON with event data relevant to our tracking. `data-ga4-expandable` enables the value of `aria-expanded` to be captured.
81
81
  See the [ga4-event-tracker](https://github.com/alphagov/govuk_publishing_components/blob/main/docs/analytics-ga4/ga4-event-tracker.md) docs for more information.
82
+ Links are also tracked with the [ga4-link-tracker](https://github.com/alphagov/govuk_publishing_components/blob/main/docs/analytics-ga4/ga4-link-tracker.md).
83
+ Therefore the `ga4-link-tracker` data module also exists on these step by step components. Any links will contain a data attribute of `ga4-link`, which contains the relevant tracking data as a JSON.
82
84
  data:
83
85
  ga4_tracking: true
84
86
  steps: [
@@ -92,6 +94,15 @@ examples:
92
94
  {
93
95
  type: 'paragraph',
94
96
  text: 'This is also a paragraph of text that intentionally contains lots of words in order to fill the width of the page successfully to check layout and so forth.'
97
+ },
98
+ {
99
+ type: 'list',
100
+ contents: [
101
+ {
102
+ href: 'https://www.gov.uk/learn-to-drive-a-car',
103
+ text: 'This is a link with GA4 tracking attributes on it.'
104
+ }
105
+ ]
95
106
  }
96
107
  ],
97
108
  },
@@ -103,6 +114,15 @@ examples:
103
114
  type: 'paragraph',
104
115
  text: 'Some more text.'
105
116
  },
117
+ {
118
+ type: 'list',
119
+ contents: [
120
+ {
121
+ href: 'https://www.nationalarchives.gov.uk',
122
+ text: 'This is another link with GA4 tracking attributes on it.'
123
+ }
124
+ ]
125
+ }
106
126
  ]
107
127
  },
108
128
  ]
@@ -84,3 +84,18 @@ examples:
84
84
  tracking: GTM-123AB
85
85
  content: |
86
86
  <p class="govuk-body-m">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam congue elementum commodo. Vestibulum elit turpis, efficitur quis posuere vitae, commodo vitae augue. Donec ut pharetra ligula. Phasellus ac mauris eu felis bibendum dapibus rutrum sed quam. Pellentesque posuere ante id consequat pretium.</p>
87
+ with_ga4_tracking:
88
+ description: Enables GA4 tracking. This will add the required data module and data attributes to the tabs. See the [ga4-event-tracker documentation](https://github.com/alphagov/govuk_publishing_components/blob/main/docs/analytics-ga4/ga4-event-tracker.md) for more information.
89
+ data:
90
+ ga4_tracking: true
91
+ tabs:
92
+ - id: "tab-with-ga4-tracking-1"
93
+ label: "First section"
94
+ title: "First section"
95
+ content: |
96
+ <p class="govuk-body-m">Fusce at dictum tellus, ac accumsan est. Nulla vitae turpis in nulla gravida tincidunt. Duis lectus felis, tempus id bibendum sit amet, posuere ut elit. Donec enim odio, eleifend in urna a, sagittis egestas est. Proin id ex ultricies, porta eros id, vehicula quam. Morbi non sagittis velit.</p>
97
+ - id: "tab-with-ga4-tracking-2"
98
+ label: "Second section"
99
+ title: "Second section"
100
+ content: |
101
+ <p class="govuk-body-m">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam congue elementum commodo. Vestibulum elit turpis, efficitur quis posuere vitae, commodo vitae augue. Donec ut pharetra ligula. Phasellus ac mauris eu felis bibendum dapibus rutrum sed quam. Pellentesque posuere ante id consequat pretium.</p>
@@ -0,0 +1,38 @@
1
+ module GovukPublishingComponents
2
+ module Presenters
3
+ class AccordionHelper
4
+ def initialise; end
5
+
6
+ def translations
7
+ {
8
+ show_text: "common.show",
9
+ hide_text: "common.hide",
10
+ show_all_text: "components.accordion.show_all",
11
+ hide_all_text: "components.accordion.hide_all",
12
+ this_section_visually_hidden: "components.accordion.this_section_visually_hidden",
13
+ }
14
+ end
15
+
16
+ def apply_translations
17
+ shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new({})
18
+ locales = {}
19
+ data_attributes = {}
20
+
21
+ translations.each do |key, translation|
22
+ locales[key] = shared_helper.t_locale(translation)
23
+ data_attributes[key] = I18n.translate(translation)
24
+ end
25
+
26
+ unique_locales = locales.values.uniq
27
+
28
+ if unique_locales.length > 1
29
+ data_attributes[:locale] = locales
30
+ elsif unique_locales[0] != I18n.locale
31
+ data_attributes[:locale] = unique_locales[0]
32
+ end
33
+
34
+ data_attributes
35
+ end
36
+ end
37
+ end
38
+ end
@@ -7,15 +7,19 @@ module GovukPublishingComponents
7
7
  check_id_is_valid(@options[:id]) if @options.include?(:id)
8
8
  check_classes_are_valid(@options[:classes]) if @options.include?(:classes)
9
9
  check_aria_is_valid(@options[:aria]) if @options.include?(:aria)
10
+ check_role_is_valid(@options[:role]) if @options.include?(:role)
10
11
  end
11
12
 
12
13
  def all_attributes
13
- {
14
- id: @options[:id],
15
- data: @options[:data],
16
- aria: @options[:aria],
17
- class: @options[:classes],
18
- }
14
+ attributes = {}
15
+
16
+ attributes[:id] = @options[:id] if @options[:id]
17
+ attributes[:data] = @options[:data_attributes] if @options[:data_attributes]
18
+ attributes[:aria] = @options[:aria] if @options[:aria]
19
+ attributes[:class] = @options[:classes] if @options[:classes]
20
+ attributes[:role] = @options[:role] if @options[:role]
21
+
22
+ attributes
19
23
  end
20
24
 
21
25
  def set_id(id)
@@ -29,7 +33,7 @@ module GovukPublishingComponents
29
33
  end
30
34
 
31
35
  def add_data_attribute(attributes)
32
- extend_object(:data, attributes)
36
+ extend_object(:data_attributes, attributes)
33
37
  end
34
38
 
35
39
  def add_aria_attribute(attributes)
@@ -37,6 +41,11 @@ module GovukPublishingComponents
37
41
  extend_object(:aria, attributes)
38
42
  end
39
43
 
44
+ def add_role(role)
45
+ check_role_is_valid(role)
46
+ extend_string(:role, role)
47
+ end
48
+
40
49
  private
41
50
 
42
51
  def check_id_is_valid(id)
@@ -45,7 +54,7 @@ module GovukPublishingComponents
45
54
 
46
55
  def check_classes_are_valid(classes)
47
56
  classes = classes.split(" ")
48
- unless classes.all? { |c| c.start_with?("js-", "gem-c-", "govuk-") }
57
+ unless classes.all? { |c| c.start_with?("js-", "gem-c-", "govuk-", "brand--") }
49
58
  raise(ArgumentError, "Passed classes must be prefixed with `js-`")
50
59
  end
51
60
  end
@@ -58,6 +67,14 @@ module GovukPublishingComponents
58
67
  end
59
68
  end
60
69
 
70
+ def check_role_is_valid(role)
71
+ roles = %w[alert alertdialog application article associationlist associationlistitemkey associationlistitemvalue banner blockquote caption cell code columnheader combobox complementary contentinfo definition deletion dialog directory document emphasis feed figure form group heading img insertion list listitem log main marquee math menu menubar meter navigation none note paragraph presentation region row rowgroup rowheader scrollbar search searchbox separator separator slider spinbutton status strong subscript superscript switch tab table tablist tabpanel term time timer toolbar tooltip tree treegrid treeitem]
72
+ role = role.split(" ") # can have more than one role
73
+ unless role.all? { |r| roles.include? r }
74
+ raise(ArgumentError, "Role attribute is not recognised")
75
+ end
76
+ end
77
+
61
78
  def extend_string(option, string)
62
79
  ((@options[option] ||= "") << " #{string}").strip!
63
80
  end
@@ -46,6 +46,7 @@ module GovukPublishingComponents
46
46
  :li,
47
47
  class: "gem-c-step-nav__list-item js-list-item #{link_active(contents[:active])}",
48
48
  ) do
49
+ @options[:ga4_index_total] = element[:contents].length if @options[:ga4_tracking]
49
50
  create_list_item_content(contents)
50
51
  end,
51
52
  )
@@ -64,11 +65,26 @@ module GovukPublishingComponents
64
65
  concat create_context(link[:context])
65
66
  end
66
67
 
68
+ ga4_link_data ||= nil
69
+ if @options[:ga4_tracking]
70
+ ga4_link_data = {
71
+ "event_name": "navigation",
72
+ "type": "step by step",
73
+ "index": {
74
+ "index_section": (@options[:step_index] + 1).to_s,
75
+ "index_link": @link_index.to_s,
76
+ },
77
+ "index_total": @options[:ga4_index_total].to_s,
78
+ "section": @options[:step_title],
79
+ }.to_json
80
+ end
81
+
67
82
  link_to(
68
83
  href,
69
84
  rel: ("external" if href.start_with?("http")),
70
85
  data: {
71
86
  position: "#{@options[:step_index] + 1}.#{@link_index}",
87
+ ga4_link: ga4_link_data,
72
88
  },
73
89
  class: "gem-c-step-nav__link js-link",
74
90
  ) do
@@ -1,3 +1,3 @@
1
1
  module GovukPublishingComponents
2
- VERSION = "34.14.0".freeze
2
+ VERSION = "35.0.0".freeze
3
3
  end
@@ -7,9 +7,10 @@ require "govuk_publishing_components/engine"
7
7
  require "govuk_publishing_components/version"
8
8
  require "govuk_publishing_components/presenters/shared_helper"
9
9
  require "govuk_publishing_components/presenters/component_wrapper_helper"
10
+ require "govuk_publishing_components/presenters/accordion_helper"
10
11
  require "govuk_publishing_components/presenters/attachment_helper"
11
12
  require "govuk_publishing_components/presenters/big_number_helper"
12
- require "govuk_publishing_components/presenters/breadcrumbs"
13
+ require "govuk_publishing_components/presenters/breadcrumbs_helper"
13
14
  require "govuk_publishing_components/presenters/breadcrumb_selector"
14
15
  require "govuk_publishing_components/presenters/button_helper"
15
16
  require "govuk_publishing_components/presenters/contextual_navigation"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: govuk_publishing_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 34.14.0
4
+ version: 35.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GOV.UK Dev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-06 00:00:00.000000000 Z
11
+ date: 2023-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: govuk_app_config
@@ -914,10 +914,11 @@ files:
914
914
  - lib/govuk_publishing_components/config.rb
915
915
  - lib/govuk_publishing_components/engine.rb
916
916
  - lib/govuk_publishing_components/minitest/component_guide_test.rb
917
+ - lib/govuk_publishing_components/presenters/accordion_helper.rb
917
918
  - lib/govuk_publishing_components/presenters/attachment_helper.rb
918
919
  - lib/govuk_publishing_components/presenters/big_number_helper.rb
919
920
  - lib/govuk_publishing_components/presenters/breadcrumb_selector.rb
920
- - lib/govuk_publishing_components/presenters/breadcrumbs.rb
921
+ - lib/govuk_publishing_components/presenters/breadcrumbs_helper.rb
921
922
  - lib/govuk_publishing_components/presenters/button_helper.rb
922
923
  - lib/govuk_publishing_components/presenters/checkboxes_helper.rb
923
924
  - lib/govuk_publishing_components/presenters/component_wrapper_helper.rb
@@ -1414,7 +1415,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1414
1415
  - !ruby/object:Gem::Version
1415
1416
  version: '0'
1416
1417
  requirements: []
1417
- rubygems_version: 3.4.7
1418
+ rubygems_version: 3.4.8
1418
1419
  signing_key:
1419
1420
  specification_version: 4
1420
1421
  summary: A gem to document components in GOV.UK frontend applications