govuk_publishing_components 34.6.0 → 34.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js +2 -1
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/init-ga4.js +6 -4
- data/app/assets/javascripts/govuk_publishing_components/load-analytics.js +6 -3
- data/app/assets/stylesheets/govuk_publishing_components/components/_document-list.scss +6 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_layout-super-navigation-header.scss +1 -1
- data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_tables.scss +12 -0
- data/app/views/govuk_publishing_components/components/_document_list.html.erb +1 -0
- data/app/views/govuk_publishing_components/components/docs/document_list.yml +18 -1
- data/app/views/govuk_publishing_components/components/docs/govspeak.yml +22 -1
- data/lib/govuk_publishing_components/presenters/related_navigation_helper.rb +0 -7
- data/lib/govuk_publishing_components/version.rb +1 -1
- data/node_modules/govuk-frontend/govuk/all.js +4029 -3792
- data/node_modules/govuk-frontend/govuk/all.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js +52 -51
- data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/common/index.js +153 -145
- data/node_modules/govuk-frontend/govuk/common/index.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js +324 -321
- data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/common.js +154 -146
- data/node_modules/govuk-frontend/govuk/common.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/_all.scss +1 -1
- data/node_modules/govuk-frontend/govuk/components/accordion/_index.scss +23 -4
- data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +2059 -1654
- data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/accordion/fixtures.json +11 -11
- data/node_modules/govuk-frontend/govuk/components/accordion/template.njk +1 -1
- data/node_modules/govuk-frontend/govuk/components/back-link/_index.scss +19 -19
- data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +21 -10
- data/node_modules/govuk-frontend/govuk/components/button/button.js +927 -917
- data/node_modules/govuk-frontend/govuk/components/button/button.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +2050 -2040
- data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +1155 -1147
- data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/cookie-banner/fixtures.json +23 -23
- data/node_modules/govuk-frontend/govuk/components/cookie-banner/template.njk +1 -1
- data/node_modules/govuk-frontend/govuk/components/details/details.js +800 -799
- data/node_modules/govuk-frontend/govuk/components/details/details.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js +1058 -1045
- data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/header/_index.scss +6 -0
- data/node_modules/govuk-frontend/govuk/components/header/header.js +646 -998
- data/node_modules/govuk-frontend/govuk/components/header/header.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +760 -752
- data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/pagination/fixtures.json +61 -0
- data/node_modules/govuk-frontend/govuk/components/pagination/template.njk +1 -1
- data/node_modules/govuk-frontend/govuk/components/phase-banner/macro-options.json +1 -1
- data/node_modules/govuk-frontend/govuk/components/radios/radios.js +1110 -1107
- data/node_modules/govuk-frontend/govuk/components/radios/radios.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js +1017 -1014
- data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/summary-list/_index.scss +107 -0
- data/node_modules/govuk-frontend/govuk/components/summary-list/fixtures.json +318 -23
- data/node_modules/govuk-frontend/govuk/components/summary-list/macro-options.json +110 -0
- data/node_modules/govuk-frontend/govuk/components/summary-list/template.njk +72 -28
- data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js +1392 -1264
- data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/i18n.js +363 -364
- data/node_modules/govuk-frontend/govuk/i18n.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/settings/_measurements.scss +5 -5
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/DOMTokenList.js +242 -241
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/DOMTokenList.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js +13 -12
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Document.js +17 -16
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Document.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/classList.js +547 -546
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/classList.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/closest.js +37 -36
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/closest.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js +251 -250
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/matches.js +21 -20
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/matches.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/nextElementSibling.js +198 -197
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/nextElementSibling.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/previousElementSibling.js +198 -197
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/previousElementSibling.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element.js +106 -105
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Event.js +400 -399
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Event.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Function/prototype/bind.js +239 -238
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Function/prototype/bind.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Object/defineProperty.js +72 -71
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Object/defineProperty.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js +14 -13
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Window.js +17 -16
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Window.js.map +1 -0
- data/node_modules/govuk-frontend/govuk-esm/all.mjs +2 -2
- data/node_modules/govuk-frontend/govuk-esm/common/index.mjs +17 -10
- data/node_modules/govuk-frontend/govuk-esm/common/normalise-dataset.mjs +3 -1
- data/node_modules/govuk-frontend/govuk-esm/components/accordion/accordion.mjs +135 -52
- data/node_modules/govuk-frontend/govuk-esm/components/button/button.mjs +11 -9
- data/node_modules/govuk-frontend/govuk-esm/components/character-count/character-count.mjs +10 -7
- data/node_modules/govuk-frontend/govuk-esm/components/checkboxes/checkboxes.mjs +24 -18
- data/node_modules/govuk-frontend/govuk-esm/components/details/details.mjs +23 -16
- data/node_modules/govuk-frontend/govuk-esm/components/error-summary/error-summary.mjs +15 -11
- data/node_modules/govuk-frontend/govuk-esm/components/header/header.mjs +3 -2
- data/node_modules/govuk-frontend/govuk-esm/components/notification-banner/notification-banner.mjs +3 -4
- data/node_modules/govuk-frontend/govuk-esm/components/radios/radios.mjs +10 -9
- data/node_modules/govuk-frontend/govuk-esm/components/skip-link/skip-link.mjs +5 -3
- data/node_modules/govuk-frontend/govuk-esm/components/tabs/tabs.mjs +165 -38
- data/node_modules/govuk-frontend/govuk-esm/i18n.mjs +9 -11
- data/node_modules/govuk-frontend/package.json +1 -1
- metadata +35 -3
@@ -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
|
-
|
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
|
-
|
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
|
-
|
100
|
-
|
101
|
-
this.$showAllButton.appendChild(
|
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
|
-
|
111
|
-
|
112
|
-
this.$showAllButton.appendChild(
|
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
|
-
|
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
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
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 $
|
172
|
-
$
|
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
|
-
$
|
204
|
+
$showHideToggle.setAttribute('data-nosnippet', '')
|
177
205
|
// Create an inner container to limit the width of the focus state
|
178
|
-
var $
|
179
|
-
$
|
180
|
-
$
|
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 $
|
183
|
-
var $
|
184
|
-
$
|
185
|
-
$
|
186
|
-
$
|
187
|
-
$
|
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($
|
254
|
+
$button.appendChild($showHideToggle)
|
227
255
|
|
228
256
|
$heading.removeChild($span)
|
229
257
|
$heading.appendChild($button)
|
230
258
|
}
|
231
259
|
|
232
|
-
|
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
|
-
|
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
|
-
|
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 $
|
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
|
270
|
-
|
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
|
-
$
|
350
|
+
$showHideIcon.classList.remove(this.downChevronIconClass)
|
293
351
|
} else {
|
352
|
+
$content.setAttribute('hidden', 'until-found')
|
294
353
|
$section.classList.remove(this.sectionExpandedClass)
|
295
|
-
$
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
398
|
+
this.$showAllText.innerText = newButtonText
|
328
399
|
|
329
400
|
// Swap icon, toggle class
|
330
401
|
if (expanded) {
|
331
|
-
|
402
|
+
this.$showAllIcon.classList.remove(this.downChevronIconClass)
|
332
403
|
} else {
|
333
|
-
|
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
|
-
|
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
|
-
|
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',
|
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
|
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 -
|
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}
|
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
|
-
|
2
|
-
|
3
|
-
|
4
|
-
import '../../
|
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 {
|
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 -
|
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
|
-
|
2
|
-
|
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
|
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
|
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 (!
|
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',
|
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
|
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
|
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 $
|
149
|
+
var $clickedInput = event.target
|
144
150
|
|
145
151
|
// Ignore clicks on things that aren't checkbox inputs
|
146
|
-
if ($
|
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 = $
|
157
|
+
var hasAriaControls = $clickedInput.getAttribute('aria-controls')
|
152
158
|
if (hasAriaControls) {
|
153
|
-
this.syncConditionalRevealWithInputState($
|
159
|
+
this.syncConditionalRevealWithInputState($clickedInput)
|
154
160
|
}
|
155
161
|
|
156
162
|
// No further behaviour needed for unchecking
|
157
|
-
if (!$
|
163
|
+
if (!$clickedInput.checked) {
|
158
164
|
return
|
159
165
|
}
|
160
166
|
|
161
167
|
// Handle 'exclusive' checkbox behaviour (ie "None of these")
|
162
|
-
var hasBehaviourExclusive = ($
|
168
|
+
var hasBehaviourExclusive = ($clickedInput.getAttribute('data-behaviour') === 'exclusive')
|
163
169
|
if (hasBehaviourExclusive) {
|
164
|
-
this.unCheckAllInputsExcept($
|
170
|
+
this.unCheckAllInputsExcept($clickedInput)
|
165
171
|
} else {
|
166
|
-
this.unCheckExclusiveInputs($
|
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(
|
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 (
|
111
|
-
|
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
|
-
|
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
|
-
|
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 {
|
148
|
-
* @returns {
|
154
|
+
* @param {UIEvent} event - Keyboard or mouse event
|
155
|
+
* @returns {void}
|
149
156
|
*/
|