govuk_publishing_components 32.1.0 → 33.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-core.js +175 -0
  3. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-ecommerce-tracker.js +1 -1
  4. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-event-tracker.js +5 -13
  5. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js +80 -309
  6. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-page-views.js +2 -2
  7. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-specialist-link-tracker.js +140 -0
  8. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/init-ga4.js +3 -0
  9. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4.js +1 -0
  10. data/app/assets/javascripts/govuk_publishing_components/components/accordion.js +12 -1
  11. data/app/assets/javascripts/govuk_publishing_components/components/single-page-notification-button.js +24 -8
  12. data/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-reporter.js +83 -86
  13. data/app/assets/stylesheets/govuk_publishing_components/components/_big-number.scss +2 -5
  14. data/app/assets/stylesheets/govuk_publishing_components/components/_image-card.scss +1 -5
  15. data/app/assets/stylesheets/govuk_publishing_components/components/_input.scss +3 -5
  16. data/app/assets/stylesheets/govuk_publishing_components/components/_layout-super-navigation-header.scss +10 -30
  17. data/app/assets/stylesheets/govuk_publishing_components/components/_search.scss +0 -7
  18. data/app/views/govuk_publishing_components/components/_accordion.html.erb +14 -1
  19. data/app/views/govuk_publishing_components/components/_error_summary.html.erb +27 -26
  20. data/app/views/govuk_publishing_components/components/_layout_super_navigation_header.html.erb +2 -2
  21. data/app/views/govuk_publishing_components/components/_phase_banner.html.erb +1 -1
  22. data/app/views/govuk_publishing_components/components/_share_links.html.erb +11 -13
  23. data/app/views/govuk_publishing_components/components/_single_page_notification_button.html.erb +1 -1
  24. data/app/views/govuk_publishing_components/components/docs/accordion.yml +15 -3
  25. data/app/views/govuk_publishing_components/components/docs/button.yml +10 -0
  26. data/app/views/govuk_publishing_components/components/docs/share_links.yml +59 -30
  27. data/app/views/govuk_publishing_components/components/docs/single_page_notification_button.yml +10 -1
  28. data/app/views/govuk_publishing_components/components/feedback/_yes_no_banner.html.erb +3 -3
  29. data/lib/govuk_publishing_components/presenters/button_helper.rb +7 -1
  30. data/lib/govuk_publishing_components/presenters/single_page_notification_button_helper.rb +25 -1
  31. data/lib/govuk_publishing_components/version.rb +1 -1
  32. data/node_modules/axe-core/axe.js +4559 -4673
  33. data/node_modules/axe-core/axe.min.js +2 -2
  34. data/node_modules/axe-core/package.json +2 -2
  35. data/node_modules/axe-core/sri-history.json +4 -0
  36. data/node_modules/govuk-frontend/README.md +1 -2
  37. data/node_modules/govuk-frontend/govuk/all.js +1398 -273
  38. data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js +70 -0
  39. data/node_modules/govuk-frontend/govuk/common/index.js +172 -0
  40. data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js +373 -0
  41. data/node_modules/govuk-frontend/govuk/common.js +138 -3
  42. data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +753 -25
  43. data/node_modules/govuk-frontend/govuk/components/accordion/fixtures.json +54 -22
  44. data/node_modules/govuk-frontend/govuk/components/accordion/macro-options.json +36 -0
  45. data/node_modules/govuk-frontend/govuk/components/accordion/template.njk +7 -1
  46. data/node_modules/govuk-frontend/govuk/components/back-link/fixtures.json +12 -12
  47. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/fixtures.json +22 -22
  48. data/node_modules/govuk-frontend/govuk/components/button/_index.scss +23 -5
  49. data/node_modules/govuk-frontend/govuk/components/button/button.js +365 -107
  50. data/node_modules/govuk-frontend/govuk/components/button/fixtures.json +85 -66
  51. data/node_modules/govuk-frontend/govuk/components/button/template.njk +1 -1
  52. data/node_modules/govuk-frontend/govuk/components/character-count/_index.scss +9 -0
  53. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +1033 -121
  54. data/node_modules/govuk-frontend/govuk/components/character-count/fixtures.json +112 -36
  55. data/node_modules/govuk-frontend/govuk/components/character-count/macro-options.json +42 -0
  56. data/node_modules/govuk-frontend/govuk/components/character-count/template.njk +27 -3
  57. data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +30 -2
  58. data/node_modules/govuk-frontend/govuk/components/checkboxes/fixtures.json +96 -93
  59. data/node_modules/govuk-frontend/govuk/components/cookie-banner/fixtures.json +46 -46
  60. data/node_modules/govuk-frontend/govuk/components/date-input/fixtures.json +50 -50
  61. data/node_modules/govuk-frontend/govuk/components/details/details.js +43 -13
  62. data/node_modules/govuk-frontend/govuk/components/details/fixtures.json +20 -20
  63. data/node_modules/govuk-frontend/govuk/components/error-message/fixtures.json +20 -20
  64. data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js +268 -6
  65. data/node_modules/govuk-frontend/govuk/components/error-summary/fixtures.json +44 -35
  66. data/node_modules/govuk-frontend/govuk/components/error-summary/template.njk +25 -21
  67. data/node_modules/govuk-frontend/govuk/components/fieldset/fixtures.json +51 -39
  68. data/node_modules/govuk-frontend/govuk/components/file-upload/fixtures.json +26 -26
  69. data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +1 -1
  70. data/node_modules/govuk-frontend/govuk/components/footer/fixtures.json +46 -46
  71. data/node_modules/govuk-frontend/govuk/components/footer/macro-options.json +2 -2
  72. data/node_modules/govuk-frontend/govuk/components/header/fixtures.json +93 -38
  73. data/node_modules/govuk-frontend/govuk/components/header/header.js +6 -0
  74. data/node_modules/govuk-frontend/govuk/components/header/macro-options.json +8 -2
  75. data/node_modules/govuk-frontend/govuk/components/header/template.njk +4 -2
  76. data/node_modules/govuk-frontend/govuk/components/hint/fixtures.json +12 -12
  77. data/node_modules/govuk-frontend/govuk/components/input/fixtures.json +80 -80
  78. data/node_modules/govuk-frontend/govuk/components/inset-text/fixtures.json +12 -12
  79. data/node_modules/govuk-frontend/govuk/components/label/fixtures.json +34 -34
  80. data/node_modules/govuk-frontend/govuk/components/notification-banner/fixtures.json +56 -46
  81. data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +252 -2
  82. data/node_modules/govuk-frontend/govuk/components/notification-banner/template.njk +1 -1
  83. data/node_modules/govuk-frontend/govuk/components/pagination/_index.scss +10 -7
  84. data/node_modules/govuk-frontend/govuk/components/pagination/fixtures.json +33 -26
  85. data/node_modules/govuk-frontend/govuk/components/panel/fixtures.json +18 -18
  86. data/node_modules/govuk-frontend/govuk/components/phase-banner/fixtures.json +14 -14
  87. data/node_modules/govuk-frontend/govuk/components/radios/fixtures.json +94 -91
  88. data/node_modules/govuk-frontend/govuk/components/radios/radios.js +30 -2
  89. data/node_modules/govuk-frontend/govuk/components/select/fixtures.json +32 -32
  90. data/node_modules/govuk-frontend/govuk/components/skip-link/fixtures.json +22 -20
  91. data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js +10 -4
  92. data/node_modules/govuk-frontend/govuk/components/summary-list/fixtures.json +50 -50
  93. data/node_modules/govuk-frontend/govuk/components/table/_index.scss +1 -1
  94. data/node_modules/govuk-frontend/govuk/components/table/fixtures.json +40 -40
  95. data/node_modules/govuk-frontend/govuk/components/tabs/fixtures.json +29 -29
  96. data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js +28 -0
  97. data/node_modules/govuk-frontend/govuk/components/tag/fixtures.json +28 -28
  98. data/node_modules/govuk-frontend/govuk/components/textarea/fixtures.json +34 -34
  99. data/node_modules/govuk-frontend/govuk/components/warning-text/fixtures.json +14 -14
  100. data/node_modules/govuk-frontend/govuk/core/_section-break.scss +1 -1
  101. data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +2 -2
  102. data/node_modules/govuk-frontend/govuk/helpers/_links.scss +6 -6
  103. data/node_modules/govuk-frontend/govuk/i18n.js +390 -0
  104. data/node_modules/govuk-frontend/govuk/macros/i18n.njk +15 -0
  105. data/node_modules/govuk-frontend/govuk/settings/_all.scss +1 -0
  106. data/node_modules/govuk-frontend/govuk/settings/_colours-palette.scss +12 -0
  107. data/node_modules/govuk-frontend/govuk/settings/_compatibility.scss +26 -0
  108. data/node_modules/govuk-frontend/govuk/settings/_typography-font.scss +23 -0
  109. data/node_modules/govuk-frontend/govuk/settings/_typography-responsive.scss +12 -0
  110. data/node_modules/govuk-frontend/govuk/settings/_warnings.scss +53 -0
  111. data/node_modules/govuk-frontend/govuk/tools/_compatibility.scss +20 -6
  112. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js +21 -0
  113. data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js +300 -0
  114. data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js +21 -0
  115. data/node_modules/govuk-frontend/govuk-esm/all.mjs +50 -27
  116. data/node_modules/govuk-frontend/govuk-esm/common/closest-attribute-value.mjs +15 -0
  117. data/node_modules/govuk-frontend/govuk-esm/common/index.mjs +159 -0
  118. data/node_modules/govuk-frontend/govuk-esm/common/normalise-dataset.mjs +58 -0
  119. data/node_modules/govuk-frontend/govuk-esm/common.mjs +6 -28
  120. data/node_modules/govuk-frontend/govuk-esm/components/accordion/accordion.mjs +113 -43
  121. data/node_modules/govuk-frontend/govuk-esm/components/button/button.mjs +67 -30
  122. data/node_modules/govuk-frontend/govuk-esm/components/character-count/character-count.mjs +325 -123
  123. data/node_modules/govuk-frontend/govuk-esm/components/checkboxes/checkboxes.mjs +9 -3
  124. data/node_modules/govuk-frontend/govuk-esm/components/details/details.mjs +22 -8
  125. data/node_modules/govuk-frontend/govuk-esm/components/error-summary/error-summary.mjs +48 -6
  126. data/node_modules/govuk-frontend/govuk-esm/components/header/header.mjs +6 -0
  127. data/node_modules/govuk-frontend/govuk-esm/components/notification-banner/notification-banner.mjs +32 -2
  128. data/node_modules/govuk-frontend/govuk-esm/components/radios/radios.mjs +9 -3
  129. data/node_modules/govuk-frontend/govuk-esm/components/skip-link/skip-link.mjs +10 -4
  130. data/node_modules/govuk-frontend/govuk-esm/components/tabs/tabs.mjs +8 -2
  131. data/node_modules/govuk-frontend/govuk-esm/i18n.mjs +380 -0
  132. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Date/now.mjs +13 -0
  133. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Element/prototype/dataset.mjs +68 -0
  134. data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/String/prototype/trim.mjs +13 -0
  135. data/node_modules/govuk-frontend/govuk-prototype-kit/init.js +7 -0
  136. data/node_modules/govuk-frontend/govuk-prototype-kit/init.scss +12 -0
  137. data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +138 -7
  138. data/node_modules/govuk-frontend/package.json +1 -1
  139. metadata +22 -3
@@ -0,0 +1,58 @@
1
+ import '../vendor/polyfills/Element/prototype/dataset.mjs'
2
+ import '../vendor/polyfills/String/prototype/trim.mjs'
3
+
4
+ /**
5
+ * Normalise string
6
+ *
7
+ * 'If it looks like a duck, and it quacks like a duck…' 🦆
8
+ *
9
+ * If the passed value looks like a boolean or a number, convert it to a boolean
10
+ * or number.
11
+ *
12
+ * Designed to be used to convert config passed via data attributes (which are
13
+ * always strings) into something sensible.
14
+ *
15
+ * @param {string} value - The value to normalise
16
+ * @returns {string | boolean | number | undefined} Normalised data
17
+ */
18
+ export function normaliseString (value) {
19
+ if (typeof value !== 'string') {
20
+ return value
21
+ }
22
+
23
+ var trimmedValue = value.trim()
24
+
25
+ if (trimmedValue === 'true') {
26
+ return true
27
+ }
28
+
29
+ if (trimmedValue === 'false') {
30
+ return false
31
+ }
32
+
33
+ // Empty / whitespace-only strings are considered finite so we need to check
34
+ // the length of the trimmed string as well
35
+ if (trimmedValue.length > 0 && isFinite(trimmedValue)) {
36
+ return Number(trimmedValue)
37
+ }
38
+
39
+ return value
40
+ }
41
+
42
+ /**
43
+ * Normalise dataset
44
+ *
45
+ * Loop over an object and normalise each value using normaliseData function
46
+ *
47
+ * @param {DOMStringMap} dataset - HTML element dataset
48
+ * @returns {Object<string, string | boolean | number | undefined>} Normalised dataset
49
+ */
50
+ export function normaliseDataset (dataset) {
51
+ var out = {}
52
+
53
+ for (var key in dataset) {
54
+ out[key] = normaliseString(dataset[key])
55
+ }
56
+
57
+ return out
58
+ }
@@ -1,28 +1,6 @@
1
- /**
2
- * TODO: Ideally this would be a NodeList.prototype.forEach polyfill
3
- * This seems to fail in IE8, requires more investigation.
4
- * See: https://github.com/imagitama/nodelist-foreach-polyfill
5
- */
6
- export function nodeListForEach (nodes, callback) {
7
- if (window.NodeList.prototype.forEach) {
8
- return nodes.forEach(callback)
9
- }
10
- for (var i = 0; i < nodes.length; i++) {
11
- callback.call(window, nodes[i], i, nodes)
12
- }
13
- }
14
-
15
- // Used to generate a unique string, allows multiple instances of the component without
16
- // Them conflicting with each other.
17
- // https://stackoverflow.com/a/8809472
18
- export function generateUniqueID () {
19
- var d = new Date().getTime()
20
- if (typeof window.performance !== 'undefined' && typeof window.performance.now === 'function') {
21
- d += window.performance.now() // use high-precision timer if available
22
- }
23
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
24
- var r = (d + Math.random() * 16) % 16 | 0
25
- d = Math.floor(d / 16)
26
- return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
27
- })
28
- }
1
+ // Implementation of common function is gathered in the `common` folder
2
+ // as some are split in their own modules to limit impacts of the polyfills
3
+ // they require.
4
+ // This module exports the non polyfilled methods as they used to be
5
+ // to avoid breaking changes
6
+ export * from './common/index.mjs'
@@ -1,31 +1,56 @@
1
-
2
- /*
3
- Accordion
4
-
5
- This allows a collection of sections to be collapsed by default,
6
- showing only their headers. Sections can be expanded or collapsed
7
- individually by clicking their headers. An "Show all sections" button is
8
- also added to the top of the accordion, which switches to "Hide all sections"
9
- when all the sections are expanded.
10
-
11
- The state of each section is saved to the DOM via the `aria-expanded`
12
- attribute, which also provides accessibility.
13
-
14
- A Chevron icon has been added for extra affordance that this is an interactive element.
15
-
16
- */
17
-
18
- import { nodeListForEach } from '../../common.mjs'
1
+ import { nodeListForEach, mergeConfigs, extractConfigByNamespace } from '../../common/index.mjs'
2
+ import { I18n } from '../../i18n.mjs'
19
3
  import '../../vendor/polyfills/Function/prototype/bind.mjs'
20
4
  import '../../vendor/polyfills/Element/prototype/classList.mjs'
5
+ import '../../vendor/polyfills/String/prototype/trim.mjs'
6
+ import { normaliseDataset } from '../../common/normalise-dataset.mjs'
21
7
 
22
- function Accordion ($module) {
8
+ /**
9
+ * @constant
10
+ * @type {AccordionTranslations}
11
+ * @see Default value for {@link AccordionConfig.i18n}
12
+ * @default
13
+ */
14
+ var ACCORDION_TRANSLATIONS = {
15
+ hideAllSections: 'Hide all sections',
16
+ hideSection: 'Hide',
17
+ hideSectionAriaLabel: 'Hide this section',
18
+ showAllSections: 'Show all sections',
19
+ showSection: 'Show',
20
+ showSectionAriaLabel: 'Show this section'
21
+ }
22
+
23
+ /**
24
+ * Accordion component
25
+ *
26
+ * This allows a collection of sections to be collapsed by default, showing only
27
+ * their headers. Sections can be expanded or collapsed individually by clicking
28
+ * their headers. A "Show all sections" button is also added to the top of the
29
+ * accordion, which switches to "Hide all sections" when all the sections are
30
+ * expanded.
31
+ *
32
+ * The state of each section is saved to the DOM via the `aria-expanded`
33
+ * attribute, which also provides accessibility.
34
+ *
35
+ * @class
36
+ * @param {HTMLElement} $module - HTML element to use for accordion
37
+ * @param {AccordionConfig} [config] - Accordion config
38
+ */
39
+ function Accordion ($module, config) {
23
40
  this.$module = $module
24
- this.moduleId = $module.getAttribute('id')
25
41
  this.$sections = $module.querySelectorAll('.govuk-accordion__section')
26
- this.$showAllButton = ''
27
42
  this.browserSupportsSessionStorage = helper.checkForSessionStorage()
28
43
 
44
+ var defaultConfig = {
45
+ i18n: ACCORDION_TRANSLATIONS
46
+ }
47
+ this.config = mergeConfigs(
48
+ defaultConfig,
49
+ config || {},
50
+ normaliseDataset($module.dataset)
51
+ )
52
+ this.i18n = new I18n(extractConfigByNamespace(this.config, 'i18n'))
53
+
29
54
  this.controlsClass = 'govuk-accordion__controls'
30
55
  this.showAllClass = 'govuk-accordion__show-all'
31
56
  this.showAllTextClass = 'govuk-accordion__show-all-text'
@@ -116,7 +141,7 @@ Accordion.prototype.constructHeaderMarkup = function ($headerWrapper, index) {
116
141
  // Create a button element that will replace the '.govuk-accordion__section-button' span
117
142
  var $button = document.createElement('button')
118
143
  $button.setAttribute('type', 'button')
119
- $button.setAttribute('aria-controls', this.moduleId + '-content-' + (index + 1))
144
+ $button.setAttribute('aria-controls', this.$module.id + '-content-' + (index + 1))
120
145
 
121
146
  // Copy all attributes (https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes) from $span to $button
122
147
  for (var i = 0; i < $span.attributes.length; i++) {
@@ -233,17 +258,34 @@ Accordion.prototype.setExpanded = function (expanded, $section) {
233
258
  var $icon = $section.querySelector('.' + this.upChevronIconClass)
234
259
  var $showHideText = $section.querySelector('.' + this.sectionShowHideTextClass)
235
260
  var $button = $section.querySelector('.' + this.sectionButtonClass)
236
- var newButtonText = expanded ? 'Hide' : 'Show'
237
-
238
- // Build additional copy of "this section" for assistive technology and place inside toggle link
239
- var $visuallyHiddenText = document.createElement('span')
240
- $visuallyHiddenText.classList.add('govuk-visually-hidden')
241
- $visuallyHiddenText.innerHTML = ' this section'
261
+ var newButtonText = expanded
262
+ ? this.i18n.t('hideSection')
263
+ : this.i18n.t('showSection')
242
264
 
243
- $showHideText.innerHTML = newButtonText
244
- $showHideText.appendChild($visuallyHiddenText)
265
+ $showHideText.innerText = newButtonText
245
266
  $button.setAttribute('aria-expanded', expanded)
246
267
 
268
+ // Update aria-label combining
269
+ var $header = $section.querySelector('.' + this.sectionHeadingTextClass)
270
+ var ariaLabelParts = [$header.innerText.trim()]
271
+
272
+ var $summary = $section.querySelector('.' + this.sectionSummaryClass)
273
+ if ($summary) {
274
+ ariaLabelParts.push($summary.innerText.trim())
275
+ }
276
+
277
+ var ariaLabelMessage = expanded
278
+ ? this.i18n.t('hideSectionAriaLabel')
279
+ : this.i18n.t('showSectionAriaLabel')
280
+ ariaLabelParts.push(ariaLabelMessage)
281
+
282
+ /*
283
+ * Join with a comma to add pause for assistive technology.
284
+ * Example: [heading]Section A ,[pause] Show this section.
285
+ * https://accessibility.blog.gov.uk/2017/12/18/what-working-on-gov-uk-navigation-taught-us-about-accessibility/
286
+ */
287
+ $button.setAttribute('aria-label', ariaLabelParts.join(' , '))
288
+
247
289
  // Swap icon, change class
248
290
  if (expanded) {
249
291
  $section.classList.add(this.sectionExpandedClass)
@@ -278,9 +320,11 @@ Accordion.prototype.checkIfAllSectionsOpen = function () {
278
320
  Accordion.prototype.updateShowAllButton = function (expanded) {
279
321
  var $showAllIcon = this.$showAllButton.querySelector('.' + this.upChevronIconClass)
280
322
  var $showAllText = this.$showAllButton.querySelector('.' + this.showAllTextClass)
281
- var newButtonText = expanded ? 'Hide all sections' : 'Show all sections'
323
+ var newButtonText = expanded
324
+ ? this.i18n.t('hideAllSections')
325
+ : this.i18n.t('showAllSections')
282
326
  this.$showAllButton.setAttribute('aria-expanded', expanded)
283
- $showAllText.innerHTML = newButtonText
327
+ $showAllText.innerText = newButtonText
284
328
 
285
329
  // Swap icon, toggle class
286
330
  if (expanded) {
@@ -343,17 +387,14 @@ Accordion.prototype.setInitialState = function ($section) {
343
387
  }
344
388
 
345
389
  /**
346
- * Create an element to improve semantics of the section button with punctuation
347
- * @return {object} DOM element
348
- *
349
- * Used to add pause (with a comma) for assistive technology.
350
- * Example: [heading]Section A ,[pause] Show this section.
351
- * https://accessibility.blog.gov.uk/2017/12/18/what-working-on-gov-uk-navigation-taught-us-about-accessibility/
352
- *
353
- * Adding punctuation to the button can also improve its general semantics by dividing its contents
354
- * into thematic chunks.
355
- * See https://github.com/alphagov/govuk-frontend/issues/2327#issuecomment-922957442
356
- */
390
+ * Create an element to improve semantics of the section button with punctuation
391
+ *
392
+ * @returns {HTMLSpanElement} DOM element
393
+ *
394
+ * Adding punctuation to the button can also improve its general semantics by dividing its contents
395
+ * into thematic chunks.
396
+ * See https://github.com/alphagov/govuk-frontend/issues/2327#issuecomment-922957442
397
+ */
357
398
  Accordion.prototype.getButtonPunctuationEl = function () {
358
399
  var $punctuationEl = document.createElement('span')
359
400
  $punctuationEl.classList.add('govuk-visually-hidden', 'govuk-accordion__section-heading-divider')
@@ -362,3 +403,32 @@ Accordion.prototype.getButtonPunctuationEl = function () {
362
403
  }
363
404
 
364
405
  export default Accordion
406
+
407
+ /**
408
+ * Accordion config
409
+ *
410
+ * @typedef {object} AccordionConfig
411
+ * @property {AccordionTranslations} [i18n = ACCORDION_TRANSLATIONS] - See constant {@link ACCORDION_TRANSLATIONS}
412
+ */
413
+
414
+ /**
415
+ * Accordion translations
416
+ *
417
+ * @typedef {object} AccordionTranslations
418
+ *
419
+ * Messages used by the component for the labels of its buttons. This includes
420
+ * the visible text shown on screen, and text to help assistive technology users
421
+ * for the buttons toggling each section.
422
+ * @property {string} [hideAllSections] - The text content for the 'Hide all
423
+ * sections' button, used when at least one section is expanded.
424
+ * @property {string} [hideSection] - The text content for the 'Hide'
425
+ * button, used when a section is expanded.
426
+ * @property {string} [hideSectionAriaLabel] - The text content appended to the
427
+ * 'Hide' button's accessible name when a section is expanded.
428
+ * @property {string} [showAllSections] - The text content for the 'Show all
429
+ * sections' button, used when all sections are collapsed.
430
+ * @property {string} [showSection] - The text content for the 'Show'
431
+ * button, used when a section is collapsed.
432
+ * @property {string} [showSectionAriaLabel] - The text content appended to the
433
+ * 'Show' button's accessible name when a section is expanded.
434
+ */
@@ -1,47 +1,84 @@
1
+ import { mergeConfigs } from '../../common/index.mjs'
2
+ import { normaliseDataset } from '../../common/normalise-dataset.mjs'
1
3
  import '../../vendor/polyfills/Event.mjs' // addEventListener and event.target normaliziation
2
4
  import '../../vendor/polyfills/Function/prototype/bind.mjs'
3
5
 
4
6
  var KEY_SPACE = 32
5
7
  var DEBOUNCE_TIMEOUT_IN_SECONDS = 1
6
8
 
7
- function Button ($module) {
9
+ /**
10
+ * JavaScript enhancements for the Button component
11
+ *
12
+ * @class
13
+ * @param {HTMLElement} $module - The element this component controls
14
+ * @param {ButtonConfig} config - Button config
15
+ */
16
+ function Button ($module, config) {
17
+ if (!$module) {
18
+ return this
19
+ }
20
+
8
21
  this.$module = $module
9
22
  this.debounceFormSubmitTimer = null
23
+
24
+ var defaultConfig = {
25
+ preventDoubleClick: false
26
+ }
27
+ this.config = mergeConfigs(
28
+ defaultConfig,
29
+ config || {},
30
+ normaliseDataset($module.dataset)
31
+ )
10
32
  }
11
33
 
12
34
  /**
13
- * JavaScript 'shim' to trigger the click event of element(s) when the space key is pressed.
14
- *
15
- * Created since some Assistive Technologies (for example some Screenreaders)
16
- * will tell a user to press space on a 'button', so this functionality needs to be shimmed
17
- * See https://github.com/alphagov/govuk_elements/pull/272#issuecomment-233028270
18
- *
19
- * @param {object} event event
20
- */
35
+ * Initialise component
36
+ */
37
+ Button.prototype.init = function () {
38
+ if (!this.$module) {
39
+ return
40
+ }
41
+
42
+ this.$module.addEventListener('keydown', this.handleKeyDown)
43
+ this.$module.addEventListener('click', this.debounce.bind(this))
44
+ }
45
+
46
+ /**
47
+ * Trigger a click event when the space key is pressed
48
+ *
49
+ * Some screen readers tell users they can activate things with the 'button'
50
+ * role, so we need to match the functionality of native HTML buttons
51
+ *
52
+ * See https://github.com/alphagov/govuk_elements/pull/272#issuecomment-233028270
53
+ *
54
+ * @param {KeyboardEvent} event
55
+ */
21
56
  Button.prototype.handleKeyDown = function (event) {
22
- // get the target element
23
57
  var target = event.target
24
- // if the element has a role='button' and the pressed key is a space, we'll simulate a click
58
+
25
59
  if (target.getAttribute('role') === 'button' && event.keyCode === KEY_SPACE) {
26
- event.preventDefault()
27
- // trigger the target's click event
60
+ event.preventDefault() // prevent the page from scrolling
28
61
  target.click()
29
62
  }
30
63
  }
31
64
 
32
65
  /**
33
- * If the click quickly succeeds a previous click then nothing will happen.
34
- * This stops people accidentally causing multiple form submissions by
35
- * double clicking buttons.
36
- */
66
+ * Debounce double-clicks
67
+ *
68
+ * If the click quickly succeeds a previous click then nothing will happen. This
69
+ * stops people accidentally causing multiple form submissions by double
70
+ * clicking buttons.
71
+ *
72
+ * @param {MouseEvent} event
73
+ * @returns {undefined | false} - Returns undefined, or false when debounced
74
+ */
37
75
  Button.prototype.debounce = function (event) {
38
- var target = event.target
39
- // Check the button that is clicked on has the preventDoubleClick feature enabled
40
- if (target.getAttribute('data-prevent-double-click') !== 'true') {
76
+ // Check the button that was clicked has preventDoubleClick enabled
77
+ if (!this.config.preventDoubleClick) {
41
78
  return
42
79
  }
43
80
 
44
- // If the timer is still running then we want to prevent the click from submitting the form
81
+ // If the timer is still running, prevent the click from submitting the form
45
82
  if (this.debounceFormSubmitTimer) {
46
83
  event.preventDefault()
47
84
  return false
@@ -52,13 +89,13 @@ Button.prototype.debounce = function (event) {
52
89
  }.bind(this), DEBOUNCE_TIMEOUT_IN_SECONDS * 1000)
53
90
  }
54
91
 
55
- /**
56
- * Initialise an event listener for keydown at document level
57
- * this will help listening for later inserted elements with a role="button"
58
- */
59
- Button.prototype.init = function () {
60
- this.$module.addEventListener('keydown', this.handleKeyDown)
61
- this.$module.addEventListener('click', this.debounce)
62
- }
63
-
64
92
  export default Button
93
+
94
+ /**
95
+ * Button config
96
+ *
97
+ * @typedef {object} ButtonConfig
98
+ * @property {boolean} [preventDoubleClick = false] -
99
+ * Prevent accidental double clicks on submit buttons from submitting forms
100
+ * multiple times.
101
+ */