govuk_publishing_components 34.7.0 → 34.7.1

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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/lib/govuk_publishing_components/presenters/related_navigation_helper.rb +0 -7
  3. data/lib/govuk_publishing_components/version.rb +1 -1
  4. data/node_modules/govuk-frontend/govuk/all.js +4029 -3792
  5. data/node_modules/govuk-frontend/govuk/all.js.map +1 -0
  6. data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js +52 -51
  7. data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js.map +1 -0
  8. data/node_modules/govuk-frontend/govuk/common/index.js +153 -145
  9. data/node_modules/govuk-frontend/govuk/common/index.js.map +1 -0
  10. data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js +324 -321
  11. data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js.map +1 -0
  12. data/node_modules/govuk-frontend/govuk/common.js +154 -146
  13. data/node_modules/govuk-frontend/govuk/common.js.map +1 -0
  14. data/node_modules/govuk-frontend/govuk/components/_all.scss +1 -1
  15. data/node_modules/govuk-frontend/govuk/components/accordion/_index.scss +23 -4
  16. data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +2059 -1654
  17. data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js.map +1 -0
  18. data/node_modules/govuk-frontend/govuk/components/accordion/fixtures.json +11 -11
  19. data/node_modules/govuk-frontend/govuk/components/accordion/template.njk +1 -1
  20. data/node_modules/govuk-frontend/govuk/components/back-link/_index.scss +19 -19
  21. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +21 -10
  22. data/node_modules/govuk-frontend/govuk/components/button/button.js +927 -917
  23. data/node_modules/govuk-frontend/govuk/components/button/button.js.map +1 -0
  24. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +2050 -2040
  25. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js.map +1 -0
  26. data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +1155 -1147
  27. data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js.map +1 -0
  28. data/node_modules/govuk-frontend/govuk/components/cookie-banner/fixtures.json +23 -23
  29. data/node_modules/govuk-frontend/govuk/components/cookie-banner/template.njk +1 -1
  30. data/node_modules/govuk-frontend/govuk/components/details/details.js +800 -799
  31. data/node_modules/govuk-frontend/govuk/components/details/details.js.map +1 -0
  32. data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js +1058 -1045
  33. data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js.map +1 -0
  34. data/node_modules/govuk-frontend/govuk/components/header/_index.scss +6 -0
  35. data/node_modules/govuk-frontend/govuk/components/header/header.js +646 -998
  36. data/node_modules/govuk-frontend/govuk/components/header/header.js.map +1 -0
  37. data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +760 -752
  38. data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js.map +1 -0
  39. data/node_modules/govuk-frontend/govuk/components/pagination/fixtures.json +61 -0
  40. data/node_modules/govuk-frontend/govuk/components/pagination/template.njk +1 -1
  41. data/node_modules/govuk-frontend/govuk/components/phase-banner/macro-options.json +1 -1
  42. data/node_modules/govuk-frontend/govuk/components/radios/radios.js +1110 -1107
  43. data/node_modules/govuk-frontend/govuk/components/radios/radios.js.map +1 -0
  44. data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js +1017 -1014
  45. data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js.map +1 -0
  46. data/node_modules/govuk-frontend/govuk/components/summary-list/_index.scss +107 -0
  47. data/node_modules/govuk-frontend/govuk/components/summary-list/fixtures.json +318 -23
  48. data/node_modules/govuk-frontend/govuk/components/summary-list/macro-options.json +110 -0
  49. data/node_modules/govuk-frontend/govuk/components/summary-list/template.njk +72 -28
  50. data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js +1392 -1264
  51. data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js.map +1 -0
  52. data/node_modules/govuk-frontend/govuk/i18n.js +363 -364
  53. data/node_modules/govuk-frontend/govuk/i18n.js.map +1 -0
  54. data/node_modules/govuk-frontend/govuk/settings/_measurements.scss +5 -5
  55. data/node_modules/govuk-frontend/govuk/vendor/polyfills/DOMTokenList.js +242 -241
  56. data/node_modules/govuk-frontend/govuk/vendor/polyfills/DOMTokenList.js.map +1 -0
  57. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js +13 -12
  58. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js.map +1 -0
  59. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Document.js +17 -16
  60. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Document.js.map +1 -0
  61. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/classList.js +547 -546
  62. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/classList.js.map +1 -0
  63. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/closest.js +37 -36
  64. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/closest.js.map +1 -0
  65. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js +251 -250
  66. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js.map +1 -0
  67. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/matches.js +21 -20
  68. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/matches.js.map +1 -0
  69. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/nextElementSibling.js +198 -197
  70. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/nextElementSibling.js.map +1 -0
  71. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/previousElementSibling.js +198 -197
  72. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/previousElementSibling.js.map +1 -0
  73. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element.js +106 -105
  74. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element.js.map +1 -0
  75. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Event.js +400 -399
  76. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Event.js.map +1 -0
  77. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Function/prototype/bind.js +239 -238
  78. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Function/prototype/bind.js.map +1 -0
  79. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Object/defineProperty.js +72 -71
  80. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Object/defineProperty.js.map +1 -0
  81. data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js +14 -13
  82. data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js.map +1 -0
  83. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Window.js +17 -16
  84. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Window.js.map +1 -0
  85. data/node_modules/govuk-frontend/govuk-esm/all.mjs +2 -2
  86. data/node_modules/govuk-frontend/govuk-esm/common/index.mjs +17 -10
  87. data/node_modules/govuk-frontend/govuk-esm/common/normalise-dataset.mjs +3 -1
  88. data/node_modules/govuk-frontend/govuk-esm/components/accordion/accordion.mjs +135 -52
  89. data/node_modules/govuk-frontend/govuk-esm/components/button/button.mjs +11 -9
  90. data/node_modules/govuk-frontend/govuk-esm/components/character-count/character-count.mjs +10 -7
  91. data/node_modules/govuk-frontend/govuk-esm/components/checkboxes/checkboxes.mjs +24 -18
  92. data/node_modules/govuk-frontend/govuk-esm/components/details/details.mjs +23 -16
  93. data/node_modules/govuk-frontend/govuk-esm/components/error-summary/error-summary.mjs +15 -11
  94. data/node_modules/govuk-frontend/govuk-esm/components/header/header.mjs +3 -2
  95. data/node_modules/govuk-frontend/govuk-esm/components/notification-banner/notification-banner.mjs +3 -4
  96. data/node_modules/govuk-frontend/govuk-esm/components/radios/radios.mjs +10 -9
  97. data/node_modules/govuk-frontend/govuk-esm/components/skip-link/skip-link.mjs +5 -3
  98. data/node_modules/govuk-frontend/govuk-esm/components/tabs/tabs.mjs +165 -38
  99. data/node_modules/govuk-frontend/govuk-esm/i18n.mjs +9 -11
  100. data/node_modules/govuk-frontend/package.json +1 -1
  101. metadata +34 -2
@@ -1,9 +1,14 @@
1
+ /* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */
2
+ /* eslint-disable es-x/no-string-prototype-trim -- Polyfill imported */
3
+
1
4
  import { nodeListForEach, mergeConfigs, extractConfigByNamespace } from '../../common/index.mjs'
5
+ import { normaliseDataset } from '../../common/normalise-dataset.mjs'
2
6
  import { I18n } from '../../i18n.mjs'
3
- import '../../vendor/polyfills/Function/prototype/bind.mjs'
4
7
  import '../../vendor/polyfills/Element/prototype/classList.mjs'
8
+ import '../../vendor/polyfills/Element/prototype/closest.mjs'
9
+ import '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded
10
+ import '../../vendor/polyfills/Function/prototype/bind.mjs'
5
11
  import '../../vendor/polyfills/String/prototype/trim.mjs'
6
- import { normaliseDataset } from '../../common/normalise-dataset.mjs'
7
12
 
8
13
  /**
9
14
  * @constant
@@ -38,27 +43,29 @@ var ACCORDION_TRANSLATIONS = {
38
43
  */
39
44
  function Accordion ($module, config) {
40
45
  this.$module = $module
41
- this.$sections = $module.querySelectorAll('.govuk-accordion__section')
42
- this.browserSupportsSessionStorage = helper.checkForSessionStorage()
43
46
 
44
47
  var defaultConfig = {
45
48
  i18n: ACCORDION_TRANSLATIONS
46
49
  }
50
+
47
51
  this.config = mergeConfigs(
48
52
  defaultConfig,
49
53
  config || {},
50
54
  normaliseDataset($module.dataset)
51
55
  )
56
+
52
57
  this.i18n = new I18n(extractConfigByNamespace(this.config, 'i18n'))
53
58
 
54
59
  this.controlsClass = 'govuk-accordion__controls'
55
60
  this.showAllClass = 'govuk-accordion__show-all'
56
61
  this.showAllTextClass = 'govuk-accordion__show-all-text'
57
62
 
63
+ this.sectionClass = 'govuk-accordion__section'
58
64
  this.sectionExpandedClass = 'govuk-accordion__section--expanded'
59
65
  this.sectionButtonClass = 'govuk-accordion__section-button'
60
66
  this.sectionHeaderClass = 'govuk-accordion__section-header'
61
67
  this.sectionHeadingClass = 'govuk-accordion__section-heading'
68
+ this.sectionHeadingDividerClass = 'govuk-accordion__section-heading-divider'
62
69
  this.sectionHeadingTextClass = 'govuk-accordion__section-heading-text'
63
70
  this.sectionHeadingTextFocusClass = 'govuk-accordion__section-heading-text-focus'
64
71
 
@@ -70,9 +77,15 @@ function Accordion ($module, config) {
70
77
 
71
78
  this.sectionSummaryClass = 'govuk-accordion__section-summary'
72
79
  this.sectionSummaryFocusClass = 'govuk-accordion__section-summary-focus'
80
+ this.sectionContentClass = 'govuk-accordion__section-content'
81
+
82
+ this.$sections = this.$module.querySelectorAll('.' + this.sectionClass)
83
+ this.browserSupportsSessionStorage = helper.checkForSessionStorage()
73
84
  }
74
85
 
75
- // Initialize component
86
+ /**
87
+ * Initialise component
88
+ */
76
89
  Accordion.prototype.init = function () {
77
90
  // Check for module
78
91
  if (!this.$module) {
@@ -87,7 +100,9 @@ Accordion.prototype.init = function () {
87
100
  this.updateShowAllButton(areAllSectionsOpen)
88
101
  }
89
102
 
90
- // Initialise controls and set attributes
103
+ /**
104
+ * Initialise controls and set attributes
105
+ */
91
106
  Accordion.prototype.initControls = function () {
92
107
  // Create "Show all" button and set attributes
93
108
  this.$showAllButton = document.createElement('button')
@@ -96,9 +111,9 @@ Accordion.prototype.initControls = function () {
96
111
  this.$showAllButton.setAttribute('aria-expanded', 'false')
97
112
 
98
113
  // Create icon, add to element
99
- var $icon = document.createElement('span')
100
- $icon.classList.add(this.upChevronIconClass)
101
- this.$showAllButton.appendChild($icon)
114
+ this.$showAllIcon = document.createElement('span')
115
+ this.$showAllIcon.classList.add(this.upChevronIconClass)
116
+ this.$showAllButton.appendChild(this.$showAllIcon)
102
117
 
103
118
  // Create control wrapper and add controls to it
104
119
  var $accordionControls = document.createElement('div')
@@ -107,15 +122,22 @@ Accordion.prototype.initControls = function () {
107
122
  this.$module.insertBefore($accordionControls, this.$module.firstChild)
108
123
 
109
124
  // Build additional wrapper for Show all toggle text and place after icon
110
- var $wrappershowAllText = document.createElement('span')
111
- $wrappershowAllText.classList.add(this.showAllTextClass)
112
- this.$showAllButton.appendChild($wrappershowAllText)
125
+ this.$showAllText = document.createElement('span')
126
+ this.$showAllText.classList.add(this.showAllTextClass)
127
+ this.$showAllButton.appendChild(this.$showAllText)
113
128
 
114
129
  // Handle click events on the show/hide all button
115
130
  this.$showAllButton.addEventListener('click', this.onShowOrHideAllToggle.bind(this))
131
+
132
+ // Handle 'beforematch' events, if the user agent supports them
133
+ if ('onbeforematch' in document) {
134
+ document.addEventListener('beforematch', this.onBeforeMatch.bind(this))
135
+ }
116
136
  }
117
137
 
118
- // Initialise section headers
138
+ /**
139
+ * Initialise section headers
140
+ */
119
141
  Accordion.prototype.initSectionHeaders = function () {
120
142
  // Loop through section headers
121
143
  nodeListForEach(this.$sections, function ($section, i) {
@@ -133,10 +155,16 @@ Accordion.prototype.initSectionHeaders = function () {
133
155
  }.bind(this))
134
156
  }
135
157
 
136
- Accordion.prototype.constructHeaderMarkup = function ($headerWrapper, index) {
137
- var $span = $headerWrapper.querySelector('.' + this.sectionButtonClass)
138
- var $heading = $headerWrapper.querySelector('.' + this.sectionHeadingClass)
139
- var $summary = $headerWrapper.querySelector('.' + this.sectionSummaryClass)
158
+ /**
159
+ * Construct section header
160
+ *
161
+ * @param {HTMLDivElement} $header - Section header
162
+ * @param {number} index - Section index
163
+ */
164
+ Accordion.prototype.constructHeaderMarkup = function ($header, index) {
165
+ var $span = $header.querySelector('.' + this.sectionButtonClass)
166
+ var $heading = $header.querySelector('.' + this.sectionHeadingClass)
167
+ var $summary = $header.querySelector('.' + this.sectionSummaryClass)
140
168
 
141
169
  // Create a button element that will replace the '.govuk-accordion__section-button' span
142
170
  var $button = document.createElement('button')
@@ -168,23 +196,23 @@ Accordion.prototype.constructHeaderMarkup = function ($headerWrapper, index) {
168
196
  $headingTextFocus.innerHTML = $span.innerHTML
169
197
 
170
198
  // Create container for show / hide icons and text.
171
- var $showToggle = document.createElement('span')
172
- $showToggle.classList.add(this.sectionShowHideToggleClass)
199
+ var $showHideToggle = document.createElement('span')
200
+ $showHideToggle.classList.add(this.sectionShowHideToggleClass)
173
201
  // Tell Google not to index the 'show' text as part of the heading
174
202
  // For the snippet to work with JavaScript, it must be added before adding the page element to the
175
203
  // page's DOM. See https://developers.google.com/search/docs/advanced/robots/robots_meta_tag#data-nosnippet-attr
176
- $showToggle.setAttribute('data-nosnippet', '')
204
+ $showHideToggle.setAttribute('data-nosnippet', '')
177
205
  // Create an inner container to limit the width of the focus state
178
- var $showToggleFocus = document.createElement('span')
179
- $showToggleFocus.classList.add(this.sectionShowHideToggleFocusClass)
180
- $showToggle.appendChild($showToggleFocus)
206
+ var $showHideToggleFocus = document.createElement('span')
207
+ $showHideToggleFocus.classList.add(this.sectionShowHideToggleFocusClass)
208
+ $showHideToggle.appendChild($showHideToggleFocus)
181
209
  // Create wrapper for the show / hide text. Append text after the show/hide icon
182
- var $showToggleText = document.createElement('span')
183
- var $icon = document.createElement('span')
184
- $icon.classList.add(this.upChevronIconClass)
185
- $showToggleFocus.appendChild($icon)
186
- $showToggleText.classList.add(this.sectionShowHideTextClass)
187
- $showToggleFocus.appendChild($showToggleText)
210
+ var $showHideText = document.createElement('span')
211
+ var $showHideIcon = document.createElement('span')
212
+ $showHideIcon.classList.add(this.upChevronIconClass)
213
+ $showHideToggleFocus.appendChild($showHideIcon)
214
+ $showHideText.classList.add(this.sectionShowHideTextClass)
215
+ $showHideToggleFocus.appendChild($showHideText)
188
216
 
189
217
  // Append elements to the button:
190
218
  // 1. Heading text
@@ -223,13 +251,29 @@ Accordion.prototype.constructHeaderMarkup = function ($headerWrapper, index) {
223
251
  $button.appendChild(this.getButtonPunctuationEl())
224
252
  }
225
253
 
226
- $button.appendChild($showToggle)
254
+ $button.appendChild($showHideToggle)
227
255
 
228
256
  $heading.removeChild($span)
229
257
  $heading.appendChild($button)
230
258
  }
231
259
 
232
- // When section toggled, set and store state
260
+ /**
261
+ * When a section is opened by the user agent via the 'beforematch' event
262
+ *
263
+ * @param {Event} event - Generic event
264
+ */
265
+ Accordion.prototype.onBeforeMatch = function (event) {
266
+ var $section = event.target.closest('.' + this.sectionClass)
267
+ if ($section) {
268
+ this.setExpanded(true, $section)
269
+ }
270
+ }
271
+
272
+ /**
273
+ * When section toggled, set and store state
274
+ *
275
+ * @param {HTMLElement} $section - Section element
276
+ */
233
277
  Accordion.prototype.onSectionToggle = function ($section) {
234
278
  var expanded = this.isExpanded($section)
235
279
  this.setExpanded(!expanded, $section)
@@ -238,7 +282,9 @@ Accordion.prototype.onSectionToggle = function ($section) {
238
282
  this.storeState($section)
239
283
  }
240
284
 
241
- // When Open/Close All toggled, set and store state
285
+ /**
286
+ * When Open/Close All toggled, set and store state
287
+ */
242
288
  Accordion.prototype.onShowOrHideAllToggle = function () {
243
289
  var $module = this
244
290
  var $sections = this.$sections
@@ -253,11 +299,18 @@ Accordion.prototype.onShowOrHideAllToggle = function () {
253
299
  $module.updateShowAllButton(nowExpanded)
254
300
  }
255
301
 
256
- // Set section attributes when opened/closed
302
+ /**
303
+ * Set section attributes when opened/closed
304
+ *
305
+ * @param {boolean} expanded - Section expanded
306
+ * @param {HTMLElement} $section - Section element
307
+ */
257
308
  Accordion.prototype.setExpanded = function (expanded, $section) {
258
- var $icon = $section.querySelector('.' + this.upChevronIconClass)
309
+ var $showHideIcon = $section.querySelector('.' + this.upChevronIconClass)
259
310
  var $showHideText = $section.querySelector('.' + this.sectionShowHideTextClass)
260
311
  var $button = $section.querySelector('.' + this.sectionButtonClass)
312
+ var $content = $section.querySelector('.' + this.sectionContentClass)
313
+
261
314
  var newButtonText = expanded
262
315
  ? this.i18n.t('hideSection')
263
316
  : this.i18n.t('showSection')
@@ -266,8 +319,12 @@ Accordion.prototype.setExpanded = function (expanded, $section) {
266
319
  $button.setAttribute('aria-expanded', expanded)
267
320
 
268
321
  // Update aria-label combining
269
- var $header = $section.querySelector('.' + this.sectionHeadingTextClass)
270
- var ariaLabelParts = [$header.innerText.trim()]
322
+ var ariaLabelParts = []
323
+
324
+ var $headingText = $section.querySelector('.' + this.sectionHeadingTextClass)
325
+ if ($headingText) {
326
+ ariaLabelParts.push($headingText.innerText.trim())
327
+ }
271
328
 
272
329
  var $summary = $section.querySelector('.' + this.sectionSummaryClass)
273
330
  if ($summary) {
@@ -288,11 +345,13 @@ Accordion.prototype.setExpanded = function (expanded, $section) {
288
345
 
289
346
  // Swap icon, change class
290
347
  if (expanded) {
348
+ $content.removeAttribute('hidden')
291
349
  $section.classList.add(this.sectionExpandedClass)
292
- $icon.classList.remove(this.downChevronIconClass)
350
+ $showHideIcon.classList.remove(this.downChevronIconClass)
293
351
  } else {
352
+ $content.setAttribute('hidden', 'until-found')
294
353
  $section.classList.remove(this.sectionExpandedClass)
295
- $icon.classList.add(this.downChevronIconClass)
354
+ $showHideIcon.classList.add(this.downChevronIconClass)
296
355
  }
297
356
 
298
357
  // See if "Show all sections" button text should be updated
@@ -300,12 +359,21 @@ Accordion.prototype.setExpanded = function (expanded, $section) {
300
359
  this.updateShowAllButton(areAllSectionsOpen)
301
360
  }
302
361
 
303
- // Get state of section
362
+ /**
363
+ * Get state of section
364
+ *
365
+ * @param {HTMLElement} $section - Section element
366
+ * @returns {boolean} True if expanded
367
+ */
304
368
  Accordion.prototype.isExpanded = function ($section) {
305
369
  return $section.classList.contains(this.sectionExpandedClass)
306
370
  }
307
371
 
308
- // Check if all sections are open
372
+ /**
373
+ * Check if all sections are open
374
+ *
375
+ * @returns {boolean} True if all sections are open
376
+ */
309
377
  Accordion.prototype.checkIfAllSectionsOpen = function () {
310
378
  // Get a count of all the Accordion sections
311
379
  var sectionsCount = this.$sections.length
@@ -316,26 +384,33 @@ Accordion.prototype.checkIfAllSectionsOpen = function () {
316
384
  return areAllSectionsOpen
317
385
  }
318
386
 
319
- // Update "Show all sections" button
387
+ /**
388
+ * Update "Show all sections" button
389
+ *
390
+ * @param {boolean} expanded - Section expanded
391
+ */
320
392
  Accordion.prototype.updateShowAllButton = function (expanded) {
321
- var $showAllIcon = this.$showAllButton.querySelector('.' + this.upChevronIconClass)
322
- var $showAllText = this.$showAllButton.querySelector('.' + this.showAllTextClass)
323
393
  var newButtonText = expanded
324
394
  ? this.i18n.t('hideAllSections')
325
395
  : this.i18n.t('showAllSections')
396
+
326
397
  this.$showAllButton.setAttribute('aria-expanded', expanded)
327
- $showAllText.innerText = newButtonText
398
+ this.$showAllText.innerText = newButtonText
328
399
 
329
400
  // Swap icon, toggle class
330
401
  if (expanded) {
331
- $showAllIcon.classList.remove(this.downChevronIconClass)
402
+ this.$showAllIcon.classList.remove(this.downChevronIconClass)
332
403
  } else {
333
- $showAllIcon.classList.add(this.downChevronIconClass)
404
+ this.$showAllIcon.classList.add(this.downChevronIconClass)
334
405
  }
335
406
  }
336
407
 
337
- // Check for `window.sessionStorage`, and that it actually works.
338
408
  var helper = {
409
+ /**
410
+ * Check for `window.sessionStorage`, and that it actually works.
411
+ *
412
+ * @returns {boolean} True if session storage is available
413
+ */
339
414
  checkForSessionStorage: function () {
340
415
  var testString = 'this is the test string'
341
416
  var result
@@ -350,7 +425,11 @@ var helper = {
350
425
  }
351
426
  }
352
427
 
353
- // Set the state of the accordions in sessionStorage
428
+ /**
429
+ * Set the state of the accordions in sessionStorage
430
+ *
431
+ * @param {HTMLElement} $section - Section element
432
+ */
354
433
  Accordion.prototype.storeState = function ($section) {
355
434
  if (this.browserSupportsSessionStorage) {
356
435
  // We need a unique way of identifying each content in the Accordion. Since
@@ -370,7 +449,11 @@ Accordion.prototype.storeState = function ($section) {
370
449
  }
371
450
  }
372
451
 
373
- // Read the state of the accordions from sessionStorage
452
+ /**
453
+ * Read the state of the accordions from sessionStorage
454
+ *
455
+ * @param {HTMLElement} $section - Section element
456
+ */
374
457
  Accordion.prototype.setInitialState = function ($section) {
375
458
  if (this.browserSupportsSessionStorage) {
376
459
  var $button = $section.querySelector('.' + this.sectionButtonClass)
@@ -389,15 +472,15 @@ Accordion.prototype.setInitialState = function ($section) {
389
472
  /**
390
473
  * Create an element to improve semantics of the section button with punctuation
391
474
  *
392
- * @returns {HTMLSpanElement} DOM element
393
- *
394
475
  * Adding punctuation to the button can also improve its general semantics by dividing its contents
395
476
  * into thematic chunks.
396
477
  * See https://github.com/alphagov/govuk-frontend/issues/2327#issuecomment-922957442
478
+ *
479
+ * @returns {HTMLElement} DOM element
397
480
  */
398
481
  Accordion.prototype.getButtonPunctuationEl = function () {
399
482
  var $punctuationEl = document.createElement('span')
400
- $punctuationEl.classList.add('govuk-visually-hidden', 'govuk-accordion__section-heading-divider')
483
+ $punctuationEl.classList.add('govuk-visually-hidden', this.sectionHeadingDividerClass)
401
484
  $punctuationEl.innerHTML = ', '
402
485
  return $punctuationEl
403
486
  }
@@ -1,6 +1,8 @@
1
+ /* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */
2
+
1
3
  import { mergeConfigs } from '../../common/index.mjs'
2
4
  import { normaliseDataset } from '../../common/normalise-dataset.mjs'
3
- import '../../vendor/polyfills/Event.mjs' // addEventListener and event.target normaliziation
5
+ import '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded
4
6
  import '../../vendor/polyfills/Function/prototype/bind.mjs'
5
7
 
6
8
  var KEY_SPACE = 32
@@ -10,8 +12,8 @@ var DEBOUNCE_TIMEOUT_IN_SECONDS = 1
10
12
  * JavaScript enhancements for the Button component
11
13
  *
12
14
  * @class
13
- * @param {HTMLElement} $module - The element this component controls
14
- * @param {ButtonConfig} config - Button config
15
+ * @param {HTMLElement} $module - HTML element to use for button
16
+ * @param {ButtonConfig} [config] - Button config
15
17
  */
16
18
  function Button ($module, config) {
17
19
  if (!$module) {
@@ -51,14 +53,14 @@ Button.prototype.init = function () {
51
53
  *
52
54
  * See https://github.com/alphagov/govuk_elements/pull/272#issuecomment-233028270
53
55
  *
54
- * @param {KeyboardEvent} event
56
+ * @param {KeyboardEvent} event - Keydown event
55
57
  */
56
58
  Button.prototype.handleKeyDown = function (event) {
57
- var target = event.target
59
+ var $target = event.target
58
60
 
59
- if (target.getAttribute('role') === 'button' && event.keyCode === KEY_SPACE) {
61
+ if ($target.getAttribute('role') === 'button' && event.keyCode === KEY_SPACE) {
60
62
  event.preventDefault() // prevent the page from scrolling
61
- target.click()
63
+ $target.click()
62
64
  }
63
65
  }
64
66
 
@@ -69,8 +71,8 @@ Button.prototype.handleKeyDown = function (event) {
69
71
  * stops people accidentally causing multiple form submissions by double
70
72
  * clicking buttons.
71
73
  *
72
- * @param {MouseEvent} event
73
- * @returns {undefined | false} - Returns undefined, or false when debounced
74
+ * @param {MouseEvent} event - Mouse click event
75
+ * @returns {undefined | false} Returns undefined, or false when debounced
74
76
  */
75
77
  Button.prototype.debounce = function (event) {
76
78
  // Check the button that was clicked has preventDoubleClick enabled
@@ -1,11 +1,14 @@
1
- import '../../vendor/polyfills/Date/now.mjs'
2
- import '../../vendor/polyfills/Function/prototype/bind.mjs'
3
- import '../../vendor/polyfills/Event.mjs' // addEventListener and event.target normalisation
4
- import '../../vendor/polyfills/Element/prototype/classList.mjs'
1
+ /* eslint-disable es-x/no-date-now -- Polyfill imported */
2
+ /* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */
3
+
4
+ import { closestAttributeValue } from '../../common/closest-attribute-value.mjs'
5
5
  import { extractConfigByNamespace, mergeConfigs } from '../../common/index.mjs'
6
- import { I18n } from '../../i18n.mjs'
7
6
  import { normaliseDataset } from '../../common/normalise-dataset.mjs'
8
- import { closestAttributeValue } from '../../common/closest-attribute-value.mjs'
7
+ import { I18n } from '../../i18n.mjs'
8
+ import '../../vendor/polyfills/Date/now.mjs'
9
+ import '../../vendor/polyfills/Element/prototype/classList.mjs'
10
+ import '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded
11
+ import '../../vendor/polyfills/Function/prototype/bind.mjs'
9
12
 
10
13
  /**
11
14
  * @constant
@@ -50,7 +53,7 @@ var CHARACTER_COUNT_TRANSLATIONS = {
50
53
  * of the available characters/words has been entered.
51
54
  *
52
55
  * @class
53
- * @param {HTMLElement} $module - The element this component controls
56
+ * @param {HTMLElement} $module - HTML element to use for character count
54
57
  * @param {CharacterCountConfig} [config] - Character count config
55
58
  */
56
59
  function CharacterCount ($module, config) {
@@ -1,8 +1,9 @@
1
- import '../../vendor/polyfills/Function/prototype/bind.mjs'
2
- // addEventListener, event.target normalization and DOMContentLoaded
3
- import '../../vendor/polyfills/Event.mjs'
4
- import '../../vendor/polyfills/Element/prototype/classList.mjs'
1
+ /* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */
2
+
5
3
  import { nodeListForEach } from '../../common/index.mjs'
4
+ import '../../vendor/polyfills/Element/prototype/classList.mjs'
5
+ import '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded
6
+ import '../../vendor/polyfills/Function/prototype/bind.mjs'
6
7
 
7
8
  /**
8
9
  * Checkboxes component
@@ -16,7 +17,7 @@ function Checkboxes ($module) {
16
17
  }
17
18
 
18
19
  /**
19
- * Initialise Checkboxes
20
+ * Initialise component
20
21
  *
21
22
  * Checkboxes can be associated with a 'conditionally revealed' content block –
22
23
  * for example, a checkbox for 'Phone' could reveal an additional form field for
@@ -34,17 +35,17 @@ Checkboxes.prototype.init = function () {
34
35
  var $inputs = this.$inputs
35
36
 
36
37
  nodeListForEach($inputs, function ($input) {
37
- var target = $input.getAttribute('data-aria-controls')
38
+ var targetId = $input.getAttribute('data-aria-controls')
38
39
 
39
40
  // Skip checkboxes without data-aria-controls attributes, or where the
40
41
  // target element does not exist.
41
- if (!target || !document.getElementById(target)) {
42
+ if (!targetId || !document.getElementById(targetId)) {
42
43
  return
43
44
  }
44
45
 
45
46
  // Promote the data-aria-controls attribute to a aria-controls attribute
46
47
  // so that the relationship is exposed in the AOM
47
- $input.setAttribute('aria-controls', target)
48
+ $input.setAttribute('aria-controls', targetId)
48
49
  $input.removeAttribute('data-aria-controls')
49
50
  })
50
51
 
@@ -63,11 +64,12 @@ Checkboxes.prototype.init = function () {
63
64
  // for example if they are added to the page dynamically, so sync now too.
64
65
  this.syncAllConditionalReveals()
65
66
 
67
+ // Handle events
66
68
  $module.addEventListener('click', this.handleClick.bind(this))
67
69
  }
68
70
 
69
71
  /**
70
- * Sync the conditional reveal states for all inputs in this $module.
72
+ * Sync the conditional reveal states for all checkboxes in this $module.
71
73
  */
72
74
  Checkboxes.prototype.syncAllConditionalReveals = function () {
73
75
  nodeListForEach(this.$inputs, this.syncConditionalRevealWithInputState.bind(this))
@@ -97,6 +99,8 @@ Checkboxes.prototype.syncConditionalRevealWithInputState = function ($input) {
97
99
  *
98
100
  * Find any other checkbox inputs with the same name value, and uncheck them.
99
101
  * This is useful for when a “None of these" checkbox is checked.
102
+ *
103
+ * @param {HTMLElement} $input - Checkbox input
100
104
  */
101
105
  Checkboxes.prototype.unCheckAllInputsExcept = function ($input) {
102
106
  var allInputsWithSameName = document.querySelectorAll('input[type="checkbox"][name="' + $input.name + '"]')
@@ -111,11 +115,13 @@ Checkboxes.prototype.unCheckAllInputsExcept = function ($input) {
111
115
  }
112
116
 
113
117
  /**
114
- * Uncheck exclusive inputs
118
+ * Uncheck exclusive checkboxes
115
119
  *
116
120
  * Find any checkbox inputs with the same name value and the 'exclusive' behaviour,
117
121
  * and uncheck them. This helps prevent someone checking both a regular checkbox and a
118
122
  * "None of these" checkbox in the same fieldset.
123
+ *
124
+ * @param {HTMLInputElement} $input - Checkbox input
119
125
  */
120
126
  Checkboxes.prototype.unCheckExclusiveInputs = function ($input) {
121
127
  var allInputsWithSameNameAndExclusiveBehaviour = document.querySelectorAll(
@@ -140,30 +146,30 @@ Checkboxes.prototype.unCheckExclusiveInputs = function ($input) {
140
146
  * @param {MouseEvent} event - Click event
141
147
  */
142
148
  Checkboxes.prototype.handleClick = function (event) {
143
- var $target = event.target
149
+ var $clickedInput = event.target
144
150
 
145
151
  // Ignore clicks on things that aren't checkbox inputs
146
- if ($target.type !== 'checkbox') {
152
+ if ($clickedInput.type !== 'checkbox') {
147
153
  return
148
154
  }
149
155
 
150
156
  // If the checkbox conditionally-reveals some content, sync the state
151
- var hasAriaControls = $target.getAttribute('aria-controls')
157
+ var hasAriaControls = $clickedInput.getAttribute('aria-controls')
152
158
  if (hasAriaControls) {
153
- this.syncConditionalRevealWithInputState($target)
159
+ this.syncConditionalRevealWithInputState($clickedInput)
154
160
  }
155
161
 
156
162
  // No further behaviour needed for unchecking
157
- if (!$target.checked) {
163
+ if (!$clickedInput.checked) {
158
164
  return
159
165
  }
160
166
 
161
167
  // Handle 'exclusive' checkbox behaviour (ie "None of these")
162
- var hasBehaviourExclusive = ($target.getAttribute('data-behaviour') === 'exclusive')
168
+ var hasBehaviourExclusive = ($clickedInput.getAttribute('data-behaviour') === 'exclusive')
163
169
  if (hasBehaviourExclusive) {
164
- this.unCheckAllInputsExcept($target)
170
+ this.unCheckAllInputsExcept($clickedInput)
165
171
  } else {
166
- this.unCheckExclusiveInputs($target)
172
+ this.unCheckExclusiveInputs($clickedInput)
167
173
  }
168
174
  }
169
175
 
@@ -1,12 +1,14 @@
1
+ /* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */
2
+
1
3
  /**
2
4
  * JavaScript 'polyfill' for HTML5's <details> and <summary> elements
3
5
  * and 'shim' to add accessiblity enhancements for all browsers
4
6
  *
5
7
  * http://caniuse.com/#feat=details
6
8
  */
7
- import '../../vendor/polyfills/Function/prototype/bind.mjs'
8
- import '../../vendor/polyfills/Event.mjs' // addEventListener and event.target normaliziation
9
9
  import { generateUniqueID } from '../../common/index.mjs'
10
+ import '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded
11
+ import '../../vendor/polyfills/Function/prototype/bind.mjs'
10
12
 
11
13
  var KEY_ENTER = 13
12
14
  var KEY_SPACE = 32
@@ -21,6 +23,9 @@ function Details ($module) {
21
23
  this.$module = $module
22
24
  }
23
25
 
26
+ /**
27
+ * Initialise component
28
+ */
24
29
  Details.prototype.init = function () {
25
30
  if (!this.$module) {
26
31
  return
@@ -36,6 +41,9 @@ Details.prototype.init = function () {
36
41
  this.polyfillDetails()
37
42
  }
38
43
 
44
+ /**
45
+ * Polyfill component in older browsers
46
+ */
39
47
  Details.prototype.polyfillDetails = function () {
40
48
  var $module = this.$module
41
49
 
@@ -79,7 +87,7 @@ Details.prototype.polyfillDetails = function () {
79
87
  }
80
88
 
81
89
  // Bind an event to handle summary elements
82
- this.polyfillHandleInputs($summary, this.polyfillSetAttributes.bind(this))
90
+ this.polyfillHandleInputs(this.polyfillSetAttributes.bind(this))
83
91
  }
84
92
 
85
93
  /**
@@ -104,21 +112,20 @@ Details.prototype.polyfillSetAttributes = function () {
104
112
  /**
105
113
  * Handle cross-modal click events
106
114
  *
107
- * @param {object} node - element
108
115
  * @param {polyfillHandleInputsCallback} callback - function
109
116
  */
110
- Details.prototype.polyfillHandleInputs = function (node, callback) {
111
- node.addEventListener('keypress', function (event) {
112
- var target = event.target
117
+ Details.prototype.polyfillHandleInputs = function (callback) {
118
+ this.$summary.addEventListener('keypress', function (event) {
119
+ var $target = event.target
113
120
  // When the key gets pressed - check if it is enter or space
114
121
  if (event.keyCode === KEY_ENTER || event.keyCode === KEY_SPACE) {
115
- if (target.nodeName.toLowerCase() === 'summary') {
122
+ if ($target.nodeName.toLowerCase() === 'summary') {
116
123
  // Prevent space from scrolling the page
117
124
  // and enter from submitting a form
118
125
  event.preventDefault()
119
126
  // Click to let the click event do all the necessary action
120
- if (target.click) {
121
- target.click()
127
+ if ($target.click) {
128
+ $target.click()
122
129
  } else {
123
130
  // except Safari 5.1 and under don't support .click() here
124
131
  callback(event)
@@ -128,22 +135,22 @@ Details.prototype.polyfillHandleInputs = function (node, callback) {
128
135
  })
129
136
 
130
137
  // Prevent keyup to prevent clicking twice in Firefox when using space key
131
- node.addEventListener('keyup', function (event) {
132
- var target = event.target
138
+ this.$summary.addEventListener('keyup', function (event) {
139
+ var $target = event.target
133
140
  if (event.keyCode === KEY_SPACE) {
134
- if (target.nodeName.toLowerCase() === 'summary') {
141
+ if ($target.nodeName.toLowerCase() === 'summary') {
135
142
  event.preventDefault()
136
143
  }
137
144
  }
138
145
  })
139
146
 
140
- node.addEventListener('click', callback)
147
+ this.$summary.addEventListener('click', callback)
141
148
  }
142
149
 
143
150
  export default Details
144
151
 
145
152
  /**
146
153
  * @callback polyfillHandleInputsCallback
147
- * @param {KeyboardEvent} event - Keyboard event
148
- * @returns {undefined}
154
+ * @param {UIEvent} event - Keyboard or mouse event
155
+ * @returns {void}
149
156
  */