govuk_publishing_components 32.0.0 → 33.0.0
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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/component_guide/accessibility-test.js +0 -1
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-core.js +175 -0
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-ecommerce-tracker.js +1 -1
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-event-tracker.js +5 -13
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js +80 -309
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-page-views.js +2 -2
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-specialist-link-tracker.js +140 -0
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/init-ga4.js +3 -0
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4.js +1 -0
- data/app/assets/javascripts/govuk_publishing_components/components/accordion.js +12 -1
- data/app/assets/javascripts/govuk_publishing_components/components/layout-super-navigation-header.js +13 -4
- data/app/assets/javascripts/govuk_publishing_components/components/single-page-notification-button.js +24 -8
- data/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-reporter.js +83 -86
- data/app/assets/stylesheets/govuk_publishing_components/components/_big-number.scss +2 -5
- data/app/assets/stylesheets/govuk_publishing_components/components/_image-card.scss +1 -5
- data/app/assets/stylesheets/govuk_publishing_components/components/_input.scss +3 -5
- data/app/assets/stylesheets/govuk_publishing_components/components/_layout-super-navigation-header.scss +10 -30
- data/app/assets/stylesheets/govuk_publishing_components/components/_search.scss +0 -7
- data/app/assets/stylesheets/govuk_publishing_components/components/_share-links.scss +0 -6
- data/app/views/govuk_publishing_components/components/_accordion.html.erb +14 -1
- data/app/views/govuk_publishing_components/components/_error_summary.html.erb +27 -26
- data/app/views/govuk_publishing_components/components/_layout_super_navigation_header.html.erb +2 -2
- data/app/views/govuk_publishing_components/components/_phase_banner.html.erb +1 -1
- data/app/views/govuk_publishing_components/components/_share_links.html.erb +18 -15
- data/app/views/govuk_publishing_components/components/_single_page_notification_button.html.erb +1 -1
- data/app/views/govuk_publishing_components/components/docs/accordion.yml +15 -3
- data/app/views/govuk_publishing_components/components/docs/button.yml +10 -0
- data/app/views/govuk_publishing_components/components/docs/share_links.yml +59 -30
- data/app/views/govuk_publishing_components/components/docs/single_page_notification_button.yml +10 -1
- data/app/views/govuk_publishing_components/components/feedback/_yes_no_banner.html.erb +3 -3
- data/config/locales/ar.yml +4 -1
- data/config/locales/az.yml +4 -1
- data/config/locales/be.yml +4 -1
- data/config/locales/bg.yml +4 -1
- data/config/locales/bn.yml +4 -1
- data/config/locales/cs.yml +4 -1
- data/config/locales/cy.yml +4 -1
- data/config/locales/da.yml +4 -1
- data/config/locales/de.yml +4 -1
- data/config/locales/dr.yml +4 -1
- data/config/locales/el.yml +4 -1
- data/config/locales/en.yml +20 -17
- data/config/locales/es-419.yml +4 -1
- data/config/locales/es.yml +4 -1
- data/config/locales/et.yml +4 -1
- data/config/locales/fa.yml +4 -1
- data/config/locales/fi.yml +4 -1
- data/config/locales/fr.yml +4 -1
- data/config/locales/gd.yml +4 -1
- data/config/locales/gu.yml +4 -1
- data/config/locales/he.yml +4 -1
- data/config/locales/hi.yml +4 -1
- data/config/locales/hr.yml +4 -1
- data/config/locales/hu.yml +4 -1
- data/config/locales/hy.yml +4 -1
- data/config/locales/id.yml +4 -1
- data/config/locales/is.yml +4 -1
- data/config/locales/it.yml +4 -1
- data/config/locales/ja.yml +4 -1
- data/config/locales/ka.yml +4 -1
- data/config/locales/kk.yml +4 -1
- data/config/locales/ko.yml +4 -1
- data/config/locales/lt.yml +4 -1
- data/config/locales/lv.yml +4 -1
- data/config/locales/ms.yml +4 -1
- data/config/locales/mt.yml +4 -1
- data/config/locales/nl.yml +4 -1
- data/config/locales/no.yml +4 -1
- data/config/locales/pa-pk.yml +4 -1
- data/config/locales/pa.yml +4 -1
- data/config/locales/pl.yml +4 -1
- data/config/locales/ps.yml +4 -1
- data/config/locales/pt.yml +4 -1
- data/config/locales/ro.yml +4 -1
- data/config/locales/ru.yml +4 -1
- data/config/locales/si.yml +4 -1
- data/config/locales/sk.yml +4 -1
- data/config/locales/sl.yml +4 -1
- data/config/locales/so.yml +4 -1
- data/config/locales/sq.yml +4 -1
- data/config/locales/sr.yml +4 -1
- data/config/locales/sv.yml +4 -1
- data/config/locales/sw.yml +4 -1
- data/config/locales/ta.yml +4 -1
- data/config/locales/th.yml +4 -1
- data/config/locales/tk.yml +4 -1
- data/config/locales/tr.yml +4 -1
- data/config/locales/uk.yml +4 -1
- data/config/locales/ur.yml +4 -1
- data/config/locales/uz.yml +4 -1
- data/config/locales/vi.yml +4 -1
- data/config/locales/zh-hk.yml +4 -1
- data/config/locales/zh-tw.yml +4 -1
- data/config/locales/zh.yml +4 -1
- data/lib/govuk_publishing_components/presenters/button_helper.rb +7 -1
- data/lib/govuk_publishing_components/presenters/single_page_notification_button_helper.rb +25 -1
- data/lib/govuk_publishing_components/version.rb +1 -1
- data/node_modules/axe-core/axe.js +4567 -4678
- data/node_modules/axe-core/axe.min.js +2 -2
- data/node_modules/axe-core/package.json +2 -2
- data/node_modules/axe-core/sri-history.json +8 -0
- data/node_modules/govuk-frontend/README.md +1 -2
- data/node_modules/govuk-frontend/govuk/all.js +1398 -273
- data/node_modules/govuk-frontend/govuk/common/closest-attribute-value.js +70 -0
- data/node_modules/govuk-frontend/govuk/common/index.js +172 -0
- data/node_modules/govuk-frontend/govuk/common/normalise-dataset.js +373 -0
- data/node_modules/govuk-frontend/govuk/common.js +138 -3
- data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +753 -25
- data/node_modules/govuk-frontend/govuk/components/accordion/fixtures.json +54 -22
- data/node_modules/govuk-frontend/govuk/components/accordion/macro-options.json +36 -0
- data/node_modules/govuk-frontend/govuk/components/accordion/template.njk +7 -1
- data/node_modules/govuk-frontend/govuk/components/back-link/fixtures.json +12 -12
- data/node_modules/govuk-frontend/govuk/components/breadcrumbs/fixtures.json +22 -22
- data/node_modules/govuk-frontend/govuk/components/button/_index.scss +23 -5
- data/node_modules/govuk-frontend/govuk/components/button/button.js +365 -107
- data/node_modules/govuk-frontend/govuk/components/button/fixtures.json +85 -66
- data/node_modules/govuk-frontend/govuk/components/button/template.njk +1 -1
- data/node_modules/govuk-frontend/govuk/components/character-count/_index.scss +9 -0
- data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +1033 -121
- data/node_modules/govuk-frontend/govuk/components/character-count/fixtures.json +112 -36
- data/node_modules/govuk-frontend/govuk/components/character-count/macro-options.json +42 -0
- data/node_modules/govuk-frontend/govuk/components/character-count/template.njk +27 -3
- data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +30 -2
- data/node_modules/govuk-frontend/govuk/components/checkboxes/fixtures.json +96 -93
- data/node_modules/govuk-frontend/govuk/components/cookie-banner/fixtures.json +46 -46
- data/node_modules/govuk-frontend/govuk/components/date-input/fixtures.json +50 -50
- data/node_modules/govuk-frontend/govuk/components/details/details.js +43 -13
- data/node_modules/govuk-frontend/govuk/components/details/fixtures.json +20 -20
- data/node_modules/govuk-frontend/govuk/components/error-message/fixtures.json +20 -20
- data/node_modules/govuk-frontend/govuk/components/error-summary/error-summary.js +268 -6
- data/node_modules/govuk-frontend/govuk/components/error-summary/fixtures.json +44 -35
- data/node_modules/govuk-frontend/govuk/components/error-summary/template.njk +25 -21
- data/node_modules/govuk-frontend/govuk/components/fieldset/fixtures.json +51 -39
- data/node_modules/govuk-frontend/govuk/components/file-upload/fixtures.json +26 -26
- data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +1 -1
- data/node_modules/govuk-frontend/govuk/components/footer/fixtures.json +46 -46
- data/node_modules/govuk-frontend/govuk/components/footer/macro-options.json +2 -2
- data/node_modules/govuk-frontend/govuk/components/header/fixtures.json +93 -38
- data/node_modules/govuk-frontend/govuk/components/header/header.js +6 -0
- data/node_modules/govuk-frontend/govuk/components/header/macro-options.json +8 -2
- data/node_modules/govuk-frontend/govuk/components/header/template.njk +4 -2
- data/node_modules/govuk-frontend/govuk/components/hint/fixtures.json +12 -12
- data/node_modules/govuk-frontend/govuk/components/input/fixtures.json +80 -80
- data/node_modules/govuk-frontend/govuk/components/inset-text/fixtures.json +12 -12
- data/node_modules/govuk-frontend/govuk/components/label/fixtures.json +34 -34
- data/node_modules/govuk-frontend/govuk/components/notification-banner/fixtures.json +56 -46
- data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +252 -2
- data/node_modules/govuk-frontend/govuk/components/notification-banner/template.njk +1 -1
- data/node_modules/govuk-frontend/govuk/components/pagination/_index.scss +10 -7
- data/node_modules/govuk-frontend/govuk/components/pagination/fixtures.json +33 -26
- data/node_modules/govuk-frontend/govuk/components/panel/fixtures.json +18 -18
- data/node_modules/govuk-frontend/govuk/components/phase-banner/fixtures.json +14 -14
- data/node_modules/govuk-frontend/govuk/components/radios/fixtures.json +94 -91
- data/node_modules/govuk-frontend/govuk/components/radios/radios.js +30 -2
- data/node_modules/govuk-frontend/govuk/components/select/fixtures.json +32 -32
- data/node_modules/govuk-frontend/govuk/components/skip-link/fixtures.json +22 -20
- data/node_modules/govuk-frontend/govuk/components/skip-link/skip-link.js +10 -4
- data/node_modules/govuk-frontend/govuk/components/summary-list/fixtures.json +50 -50
- data/node_modules/govuk-frontend/govuk/components/table/_index.scss +1 -1
- data/node_modules/govuk-frontend/govuk/components/table/fixtures.json +40 -40
- data/node_modules/govuk-frontend/govuk/components/tabs/fixtures.json +29 -29
- data/node_modules/govuk-frontend/govuk/components/tabs/tabs.js +28 -0
- data/node_modules/govuk-frontend/govuk/components/tag/fixtures.json +28 -28
- data/node_modules/govuk-frontend/govuk/components/textarea/fixtures.json +34 -34
- data/node_modules/govuk-frontend/govuk/components/warning-text/fixtures.json +14 -14
- data/node_modules/govuk-frontend/govuk/core/_section-break.scss +1 -1
- data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +2 -2
- data/node_modules/govuk-frontend/govuk/helpers/_links.scss +6 -6
- data/node_modules/govuk-frontend/govuk/i18n.js +390 -0
- data/node_modules/govuk-frontend/govuk/macros/i18n.njk +15 -0
- data/node_modules/govuk-frontend/govuk/settings/_all.scss +1 -0
- data/node_modules/govuk-frontend/govuk/settings/_colours-palette.scss +12 -0
- data/node_modules/govuk-frontend/govuk/settings/_compatibility.scss +26 -0
- data/node_modules/govuk-frontend/govuk/settings/_typography-font.scss +23 -0
- data/node_modules/govuk-frontend/govuk/settings/_typography-responsive.scss +12 -0
- data/node_modules/govuk-frontend/govuk/settings/_warnings.scss +53 -0
- data/node_modules/govuk-frontend/govuk/tools/_compatibility.scss +20 -6
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Date/now.js +21 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/Element/prototype/dataset.js +300 -0
- data/node_modules/govuk-frontend/govuk/vendor/polyfills/String/prototype/trim.js +21 -0
- data/node_modules/govuk-frontend/govuk-esm/all.mjs +50 -27
- data/node_modules/govuk-frontend/govuk-esm/common/closest-attribute-value.mjs +15 -0
- data/node_modules/govuk-frontend/govuk-esm/common/index.mjs +159 -0
- data/node_modules/govuk-frontend/govuk-esm/common/normalise-dataset.mjs +58 -0
- data/node_modules/govuk-frontend/govuk-esm/common.mjs +6 -28
- data/node_modules/govuk-frontend/govuk-esm/components/accordion/accordion.mjs +113 -43
- data/node_modules/govuk-frontend/govuk-esm/components/button/button.mjs +67 -30
- data/node_modules/govuk-frontend/govuk-esm/components/character-count/character-count.mjs +325 -123
- data/node_modules/govuk-frontend/govuk-esm/components/checkboxes/checkboxes.mjs +9 -3
- data/node_modules/govuk-frontend/govuk-esm/components/details/details.mjs +22 -8
- data/node_modules/govuk-frontend/govuk-esm/components/error-summary/error-summary.mjs +48 -6
- data/node_modules/govuk-frontend/govuk-esm/components/header/header.mjs +6 -0
- data/node_modules/govuk-frontend/govuk-esm/components/notification-banner/notification-banner.mjs +32 -2
- data/node_modules/govuk-frontend/govuk-esm/components/radios/radios.mjs +9 -3
- data/node_modules/govuk-frontend/govuk-esm/components/skip-link/skip-link.mjs +10 -4
- data/node_modules/govuk-frontend/govuk-esm/components/tabs/tabs.mjs +8 -2
- data/node_modules/govuk-frontend/govuk-esm/i18n.mjs +380 -0
- data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Date/now.mjs +13 -0
- data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/Element/prototype/dataset.mjs +68 -0
- data/node_modules/govuk-frontend/govuk-esm/vendor/polyfills/String/prototype/trim.mjs +13 -0
- data/node_modules/govuk-frontend/govuk-prototype-kit/init.js +7 -0
- data/node_modules/govuk-frontend/govuk-prototype-kit/init.scss +12 -0
- data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +138 -7
- data/node_modules/govuk-frontend/package.json +1 -1
- metadata +22 -3
@@ -1,8 +1,106 @@
|
|
1
|
+
import '../../vendor/polyfills/Date/now.mjs'
|
1
2
|
import '../../vendor/polyfills/Function/prototype/bind.mjs'
|
2
|
-
import '../../vendor/polyfills/Event.mjs' // addEventListener and event.target
|
3
|
+
import '../../vendor/polyfills/Event.mjs' // addEventListener and event.target normalisation
|
3
4
|
import '../../vendor/polyfills/Element/prototype/classList.mjs'
|
5
|
+
import { extractConfigByNamespace, mergeConfigs } from '../../common/index.mjs'
|
6
|
+
import { I18n } from '../../i18n.mjs'
|
7
|
+
import { normaliseDataset } from '../../common/normalise-dataset.mjs'
|
8
|
+
import { closestAttributeValue } from '../../common/closest-attribute-value.mjs'
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @constant
|
12
|
+
* @type {CharacterCountTranslations}
|
13
|
+
* @see Default value for {@link CharacterCountConfig.i18n}
|
14
|
+
* @default
|
15
|
+
*/
|
16
|
+
var CHARACTER_COUNT_TRANSLATIONS = {
|
17
|
+
// Characters
|
18
|
+
charactersUnderLimit: {
|
19
|
+
one: 'You have %{count} character remaining',
|
20
|
+
other: 'You have %{count} characters remaining'
|
21
|
+
},
|
22
|
+
charactersAtLimit: 'You have 0 characters remaining',
|
23
|
+
charactersOverLimit: {
|
24
|
+
one: 'You have %{count} character too many',
|
25
|
+
other: 'You have %{count} characters too many'
|
26
|
+
},
|
27
|
+
// Words
|
28
|
+
wordsUnderLimit: {
|
29
|
+
one: 'You have %{count} word remaining',
|
30
|
+
other: 'You have %{count} words remaining'
|
31
|
+
},
|
32
|
+
wordsAtLimit: 'You have 0 words remaining',
|
33
|
+
wordsOverLimit: {
|
34
|
+
one: 'You have %{count} word too many',
|
35
|
+
other: 'You have %{count} words too many'
|
36
|
+
},
|
37
|
+
textareaDescription: {
|
38
|
+
other: ''
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
/**
|
43
|
+
* JavaScript enhancements for the CharacterCount component
|
44
|
+
*
|
45
|
+
* Tracks the number of characters or words in the `.govuk-js-character-count`
|
46
|
+
* `<textarea>` inside the element. Displays a message with the remaining number
|
47
|
+
* of characters/words available, or the number of characters/words in excess.
|
48
|
+
*
|
49
|
+
* You can configure the message to only appear after a certain percentage
|
50
|
+
* of the available characters/words has been entered.
|
51
|
+
*
|
52
|
+
* @class
|
53
|
+
* @param {HTMLElement} $module - The element this component controls
|
54
|
+
* @param {CharacterCountConfig} [config] - Character count config
|
55
|
+
*/
|
56
|
+
function CharacterCount ($module, config) {
|
57
|
+
if (!$module) {
|
58
|
+
return this
|
59
|
+
}
|
60
|
+
|
61
|
+
var defaultConfig = {
|
62
|
+
threshold: 0,
|
63
|
+
i18n: CHARACTER_COUNT_TRANSLATIONS
|
64
|
+
}
|
65
|
+
|
66
|
+
// Read config set using dataset ('data-' values)
|
67
|
+
var datasetConfig = normaliseDataset($module.dataset)
|
68
|
+
|
69
|
+
// To ensure data-attributes take complete precedence, even if they change the
|
70
|
+
// type of count, we need to reset the `maxlength` and `maxwords` from the
|
71
|
+
// JavaScript config.
|
72
|
+
//
|
73
|
+
// We can't mutate `config`, though, as it may be shared across multiple
|
74
|
+
// components inside `initAll`.
|
75
|
+
var configOverrides = {}
|
76
|
+
if ('maxwords' in datasetConfig || 'maxlength' in datasetConfig) {
|
77
|
+
configOverrides = {
|
78
|
+
maxlength: false,
|
79
|
+
maxwords: false
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
this.config = mergeConfigs(
|
84
|
+
defaultConfig,
|
85
|
+
config || {},
|
86
|
+
configOverrides,
|
87
|
+
datasetConfig
|
88
|
+
)
|
89
|
+
|
90
|
+
this.i18n = new I18n(extractConfigByNamespace(this.config, 'i18n'), {
|
91
|
+
// Read the fallback if necessary rather than have it set in the defaults
|
92
|
+
locale: closestAttributeValue($module, 'lang')
|
93
|
+
})
|
94
|
+
|
95
|
+
// Determine the limit attribute (characters or words)
|
96
|
+
if (this.config.maxwords) {
|
97
|
+
this.maxLength = this.config.maxwords
|
98
|
+
} else if (this.config.maxlength) {
|
99
|
+
this.maxLength = this.config.maxlength
|
100
|
+
} else {
|
101
|
+
return
|
102
|
+
}
|
4
103
|
|
5
|
-
function CharacterCount ($module) {
|
6
104
|
this.$module = $module
|
7
105
|
this.$textarea = $module.querySelector('.govuk-js-character-count')
|
8
106
|
this.$visibleCountMessage = null
|
@@ -10,26 +108,28 @@ function CharacterCount ($module) {
|
|
10
108
|
this.lastInputTimestamp = null
|
11
109
|
}
|
12
110
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
}
|
17
|
-
|
18
|
-
// Initialize component
|
111
|
+
/**
|
112
|
+
* Initialise component
|
113
|
+
*/
|
19
114
|
CharacterCount.prototype.init = function () {
|
20
115
|
// Check that required elements are present
|
21
116
|
if (!this.$textarea) {
|
22
117
|
return
|
23
118
|
}
|
24
119
|
|
25
|
-
// Check for module
|
26
|
-
var $module = this.$module
|
27
120
|
var $textarea = this.$textarea
|
28
|
-
var $
|
121
|
+
var $textareaDescription = document.getElementById($textarea.id + '-info')
|
122
|
+
|
123
|
+
// Inject a decription for the textarea if none is present already
|
124
|
+
// for when the component was rendered with no maxlength, maxwords
|
125
|
+
// nor custom textareaDescriptionText
|
126
|
+
if ($textareaDescription.innerText.match(/^\s*$/)) {
|
127
|
+
$textareaDescription.innerText = this.i18n.t('textareaDescription', { count: this.maxLength })
|
128
|
+
}
|
29
129
|
|
30
|
-
// Move the
|
130
|
+
// Move the textarea description to be immediately after the textarea
|
31
131
|
// Kept for backwards compatibility
|
32
|
-
$textarea.insertAdjacentElement('afterend', $
|
132
|
+
$textarea.insertAdjacentElement('afterend', $textareaDescription)
|
33
133
|
|
34
134
|
// Create the *screen reader* specific live-updating counter
|
35
135
|
// This doesn't need any styling classes, as it is never visible
|
@@ -37,36 +137,20 @@ CharacterCount.prototype.init = function () {
|
|
37
137
|
$screenReaderCountMessage.className = 'govuk-character-count__sr-status govuk-visually-hidden'
|
38
138
|
$screenReaderCountMessage.setAttribute('aria-live', 'polite')
|
39
139
|
this.$screenReaderCountMessage = $screenReaderCountMessage
|
40
|
-
$
|
140
|
+
$textareaDescription.insertAdjacentElement('afterend', $screenReaderCountMessage)
|
41
141
|
|
42
142
|
// Create our live-updating counter element, copying the classes from the
|
43
|
-
//
|
143
|
+
// textarea description for backwards compatibility as these may have been
|
144
|
+
// configured
|
44
145
|
var $visibleCountMessage = document.createElement('div')
|
45
|
-
$visibleCountMessage.className = $
|
146
|
+
$visibleCountMessage.className = $textareaDescription.className
|
46
147
|
$visibleCountMessage.classList.add('govuk-character-count__status')
|
47
148
|
$visibleCountMessage.setAttribute('aria-hidden', 'true')
|
48
149
|
this.$visibleCountMessage = $visibleCountMessage
|
49
|
-
$
|
150
|
+
$textareaDescription.insertAdjacentElement('afterend', $visibleCountMessage)
|
50
151
|
|
51
|
-
// Hide the
|
52
|
-
$
|
53
|
-
|
54
|
-
// Read options set using dataset ('data-' values)
|
55
|
-
this.options = this.getDataset($module)
|
56
|
-
|
57
|
-
// Determine the limit attribute (characters or words)
|
58
|
-
var countAttribute = this.defaults.characterCountAttribute
|
59
|
-
if (this.options.maxwords) {
|
60
|
-
countAttribute = this.defaults.wordCountAttribute
|
61
|
-
}
|
62
|
-
|
63
|
-
// Save the element limit
|
64
|
-
this.maxLength = $module.getAttribute(countAttribute)
|
65
|
-
|
66
|
-
// Check for limit
|
67
|
-
if (!this.maxLength) {
|
68
|
-
return
|
69
|
-
}
|
152
|
+
// Hide the textarea description
|
153
|
+
$textareaDescription.classList.add('govuk-visually-hidden')
|
70
154
|
|
71
155
|
// Remove hard limit if set
|
72
156
|
$textarea.removeAttribute('maxlength')
|
@@ -74,9 +158,9 @@ CharacterCount.prototype.init = function () {
|
|
74
158
|
this.bindChangeEvents()
|
75
159
|
|
76
160
|
// When the page is restored after navigating 'back' in some browsers the
|
77
|
-
// state of the character count is not restored until *after* the
|
78
|
-
// event is fired, so we need to manually update it after the
|
79
|
-
// in browsers that support it.
|
161
|
+
// state of the character count is not restored until *after* the
|
162
|
+
// DOMContentLoaded event is fired, so we need to manually update it after the
|
163
|
+
// pageshow event in browsers that support it.
|
80
164
|
if ('onpageshow' in window) {
|
81
165
|
window.addEventListener('pageshow', this.updateCountMessage.bind(this))
|
82
166
|
} else {
|
@@ -85,35 +169,12 @@ CharacterCount.prototype.init = function () {
|
|
85
169
|
this.updateCountMessage()
|
86
170
|
}
|
87
171
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
var attribute = attributes[i]
|
95
|
-
var match = attribute.name.match(/^data-(.+)/)
|
96
|
-
if (match) {
|
97
|
-
dataset[match[1]] = attribute.value
|
98
|
-
}
|
99
|
-
}
|
100
|
-
}
|
101
|
-
return dataset
|
102
|
-
}
|
103
|
-
|
104
|
-
// Counts characters or words in text
|
105
|
-
CharacterCount.prototype.count = function (text) {
|
106
|
-
var length
|
107
|
-
if (this.options.maxwords) {
|
108
|
-
var tokens = text.match(/\S+/g) || [] // Matches consecutive non-whitespace chars
|
109
|
-
length = tokens.length
|
110
|
-
} else {
|
111
|
-
length = text.length
|
112
|
-
}
|
113
|
-
return length
|
114
|
-
}
|
115
|
-
|
116
|
-
// Bind input propertychange to the elements and update based on the change
|
172
|
+
/**
|
173
|
+
* Bind change events
|
174
|
+
*
|
175
|
+
* Set up event listeners on the $textarea so that the count messages update
|
176
|
+
* when the user types.
|
177
|
+
*/
|
117
178
|
CharacterCount.prototype.bindChangeEvents = function () {
|
118
179
|
var $textarea = this.$textarea
|
119
180
|
$textarea.addEventListener('keyup', this.handleKeyUp.bind(this))
|
@@ -123,10 +184,52 @@ CharacterCount.prototype.bindChangeEvents = function () {
|
|
123
184
|
$textarea.addEventListener('blur', this.handleBlur.bind(this))
|
124
185
|
}
|
125
186
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
187
|
+
/**
|
188
|
+
* Handle key up event
|
189
|
+
*
|
190
|
+
* Update the visible character counter and keep track of when the last update
|
191
|
+
* happened for each keypress
|
192
|
+
*/
|
193
|
+
CharacterCount.prototype.handleKeyUp = function () {
|
194
|
+
this.updateVisibleCountMessage()
|
195
|
+
this.lastInputTimestamp = Date.now()
|
196
|
+
}
|
197
|
+
|
198
|
+
/**
|
199
|
+
* Handle focus event
|
200
|
+
*
|
201
|
+
* Speech recognition software such as Dragon NaturallySpeaking will modify the
|
202
|
+
* fields by directly changing its `value`. These changes don't trigger events
|
203
|
+
* in JavaScript, so we need to poll to handle when and if they occur.
|
204
|
+
*
|
205
|
+
* Once the keyup event hasn't been detected for at least 1000 ms (1s), check if
|
206
|
+
* the textarea value has changed and update the count message if it has.
|
207
|
+
*
|
208
|
+
* This is so that the update triggered by the manual comparison doesn't
|
209
|
+
* conflict with debounced KeyboardEvent updates.
|
210
|
+
*/
|
211
|
+
CharacterCount.prototype.handleFocus = function () {
|
212
|
+
this.valueChecker = setInterval(function () {
|
213
|
+
if (!this.lastInputTimestamp || (Date.now() - 500) >= this.lastInputTimestamp) {
|
214
|
+
this.updateIfValueChanged()
|
215
|
+
}
|
216
|
+
}.bind(this), 1000)
|
217
|
+
}
|
218
|
+
|
219
|
+
/**
|
220
|
+
* Handle blur event
|
221
|
+
*
|
222
|
+
* Stop checking the textarea value once the textarea no longer has focus
|
223
|
+
*/
|
224
|
+
CharacterCount.prototype.handleBlur = function () {
|
225
|
+
// Cancel value checking on blur
|
226
|
+
clearInterval(this.valueChecker)
|
227
|
+
}
|
228
|
+
|
229
|
+
/**
|
230
|
+
* Update count message if textarea value has changed
|
231
|
+
*/
|
232
|
+
CharacterCount.prototype.updateIfValueChanged = function () {
|
130
233
|
if (!this.$textarea.oldValue) this.$textarea.oldValue = ''
|
131
234
|
if (this.$textarea.value !== this.$textarea.oldValue) {
|
132
235
|
this.$textarea.oldValue = this.$textarea.value
|
@@ -134,14 +237,20 @@ CharacterCount.prototype.checkIfValueChanged = function () {
|
|
134
237
|
}
|
135
238
|
}
|
136
239
|
|
137
|
-
|
138
|
-
|
240
|
+
/**
|
241
|
+
* Update count message
|
242
|
+
*
|
243
|
+
* Helper function to update both the visible and screen reader-specific
|
244
|
+
* counters simultaneously (e.g. on init)
|
245
|
+
*/
|
139
246
|
CharacterCount.prototype.updateCountMessage = function () {
|
140
247
|
this.updateVisibleCountMessage()
|
141
248
|
this.updateScreenReaderCountMessage()
|
142
249
|
}
|
143
250
|
|
144
|
-
|
251
|
+
/**
|
252
|
+
* Update visible count message
|
253
|
+
*/
|
145
254
|
CharacterCount.prototype.updateVisibleCountMessage = function () {
|
146
255
|
var $textarea = this.$textarea
|
147
256
|
var $visibleCountMessage = this.$visibleCountMessage
|
@@ -167,10 +276,12 @@ CharacterCount.prototype.updateVisibleCountMessage = function () {
|
|
167
276
|
}
|
168
277
|
|
169
278
|
// Update message
|
170
|
-
$visibleCountMessage.
|
279
|
+
$visibleCountMessage.innerText = this.getCountMessage()
|
171
280
|
}
|
172
281
|
|
173
|
-
|
282
|
+
/**
|
283
|
+
* Update screen reader count message
|
284
|
+
*/
|
174
285
|
CharacterCount.prototype.updateScreenReaderCountMessage = function () {
|
175
286
|
var $screenReaderCountMessage = this.$screenReaderCountMessage
|
176
287
|
|
@@ -183,69 +294,160 @@ CharacterCount.prototype.updateScreenReaderCountMessage = function () {
|
|
183
294
|
}
|
184
295
|
|
185
296
|
// Update message
|
186
|
-
$screenReaderCountMessage.
|
297
|
+
$screenReaderCountMessage.innerText = this.getCountMessage()
|
187
298
|
}
|
188
299
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
300
|
+
/**
|
301
|
+
* Count the number of characters (or words, if `config.maxwords` is set)
|
302
|
+
* in the given text
|
303
|
+
*
|
304
|
+
* @param {string} text - The text to count the characters of
|
305
|
+
* @returns {number} the number of characters (or words) in the text
|
306
|
+
*/
|
307
|
+
CharacterCount.prototype.count = function (text) {
|
308
|
+
if (this.config.maxwords) {
|
309
|
+
var tokens = text.match(/\S+/g) || [] // Matches consecutive non-whitespace chars
|
310
|
+
return tokens.length
|
311
|
+
} else {
|
312
|
+
return text.length
|
313
|
+
}
|
314
|
+
}
|
315
|
+
|
316
|
+
/**
|
317
|
+
* Get count message
|
318
|
+
*
|
319
|
+
* @returns {string} Status message
|
320
|
+
*/
|
321
|
+
CharacterCount.prototype.getCountMessage = function () {
|
322
|
+
var remainingNumber = this.maxLength - this.count(this.$textarea.value)
|
323
|
+
|
324
|
+
var countType = this.config.maxwords ? 'words' : 'characters'
|
325
|
+
return this.formatCountMessage(remainingNumber, countType)
|
326
|
+
}
|
194
327
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
328
|
+
/**
|
329
|
+
* Formats the message shown to users according to what's counted
|
330
|
+
* and how many remain
|
331
|
+
*
|
332
|
+
* @param {number} remainingNumber - The number of words/characaters remaining
|
333
|
+
* @param {string} countType - "words" or "characters"
|
334
|
+
* @returns {string} Status message
|
335
|
+
*/
|
336
|
+
CharacterCount.prototype.formatCountMessage = function (remainingNumber, countType) {
|
337
|
+
if (remainingNumber === 0) {
|
338
|
+
return this.i18n.t(countType + 'AtLimit')
|
200
339
|
}
|
201
|
-
charNoun = charNoun + ((remainingNumber === -1 || remainingNumber === 1) ? '' : 's')
|
202
340
|
|
203
|
-
|
204
|
-
displayNumber = Math.abs(remainingNumber)
|
341
|
+
var translationKeySuffix = remainingNumber < 0 ? 'OverLimit' : 'UnderLimit'
|
205
342
|
|
206
|
-
return
|
343
|
+
return this.i18n.t(countType + translationKeySuffix, { count: Math.abs(remainingNumber) })
|
207
344
|
}
|
208
345
|
|
209
|
-
|
210
|
-
|
211
|
-
|
346
|
+
/**
|
347
|
+
* Check if count is over threshold
|
348
|
+
*
|
349
|
+
* Checks whether the value is over the configured threshold for the input.
|
350
|
+
* If there is no configured threshold, it is set to 0 and this function will
|
351
|
+
* always return true.
|
352
|
+
*
|
353
|
+
* @returns {boolean} true if the current count is over the config.threshold
|
354
|
+
* (or no threshold is set)
|
355
|
+
*/
|
212
356
|
CharacterCount.prototype.isOverThreshold = function () {
|
357
|
+
// No threshold means we're always above threshold so save some computation
|
358
|
+
if (!this.config.threshold) {
|
359
|
+
return true
|
360
|
+
}
|
361
|
+
|
213
362
|
var $textarea = this.$textarea
|
214
|
-
var options = this.options
|
215
363
|
|
216
364
|
// Determine the remaining number of characters/words
|
217
365
|
var currentLength = this.count($textarea.value)
|
218
366
|
var maxLength = this.maxLength
|
219
367
|
|
220
|
-
|
221
|
-
var thresholdPercent = options.threshold ? options.threshold : 0
|
222
|
-
var thresholdValue = maxLength * thresholdPercent / 100
|
368
|
+
var thresholdValue = maxLength * this.config.threshold / 100
|
223
369
|
|
224
370
|
return (thresholdValue <= currentLength)
|
225
371
|
}
|
226
372
|
|
227
|
-
// Update the visible character counter and keep track of when the last update
|
228
|
-
// happened for each keypress
|
229
|
-
CharacterCount.prototype.handleKeyUp = function () {
|
230
|
-
this.updateVisibleCountMessage()
|
231
|
-
this.lastInputTimestamp = Date.now()
|
232
|
-
}
|
233
|
-
|
234
|
-
CharacterCount.prototype.handleFocus = function () {
|
235
|
-
// If the field is focused, and a keyup event hasn't been detected for at
|
236
|
-
// least 1000 ms (1 second), then run the manual change check.
|
237
|
-
// This is so that the update triggered by the manual comparison doesn't
|
238
|
-
// conflict with debounced KeyboardEvent updates.
|
239
|
-
this.valueChecker = setInterval(function () {
|
240
|
-
if (!this.lastInputTimestamp || (Date.now() - 500) >= this.lastInputTimestamp) {
|
241
|
-
this.checkIfValueChanged()
|
242
|
-
}
|
243
|
-
}.bind(this), 1000)
|
244
|
-
}
|
245
|
-
|
246
|
-
CharacterCount.prototype.handleBlur = function () {
|
247
|
-
// Cancel value checking on blur
|
248
|
-
clearInterval(this.valueChecker)
|
249
|
-
}
|
250
|
-
|
251
373
|
export default CharacterCount
|
374
|
+
|
375
|
+
/**
|
376
|
+
* Character count config
|
377
|
+
*
|
378
|
+
* @typedef {CharacterCountConfigWithMaxLength | CharacterCountConfigWithMaxWords} CharacterCountConfig
|
379
|
+
*/
|
380
|
+
|
381
|
+
/**
|
382
|
+
* Character count config (with maximum number of characters)
|
383
|
+
*
|
384
|
+
* @typedef {object} CharacterCountConfigWithMaxLength
|
385
|
+
* @property {number} [maxlength] - The maximum number of characters.
|
386
|
+
* If maxwords is provided, the maxlength option will be ignored.
|
387
|
+
* @property {number} [threshold = 0] - The percentage value of the limit at
|
388
|
+
* which point the count message is displayed. If this attribute is set, the
|
389
|
+
* count message will be hidden by default.
|
390
|
+
* @property {CharacterCountTranslations} [i18n = CHARACTER_COUNT_TRANSLATIONS] - See constant {@link CHARACTER_COUNT_TRANSLATIONS}
|
391
|
+
*/
|
392
|
+
|
393
|
+
/**
|
394
|
+
* Character count config (with maximum number of words)
|
395
|
+
*
|
396
|
+
* @typedef {object} CharacterCountConfigWithMaxWords
|
397
|
+
* @property {number} [maxwords] - The maximum number of words. If maxwords is
|
398
|
+
* provided, the maxlength option will be ignored.
|
399
|
+
* @property {number} [threshold = 0] - The percentage value of the limit at
|
400
|
+
* which point the count message is displayed. If this attribute is set, the
|
401
|
+
* count message will be hidden by default.
|
402
|
+
* @property {CharacterCountTranslations} [i18n = CHARACTER_COUNT_TRANSLATIONS] - See constant {@link CHARACTER_COUNT_TRANSLATIONS}
|
403
|
+
*/
|
404
|
+
|
405
|
+
/**
|
406
|
+
* Character count translations
|
407
|
+
*
|
408
|
+
* @typedef {object} CharacterCountTranslations
|
409
|
+
*
|
410
|
+
* Messages shown to users as they type. It provides feedback on how many words
|
411
|
+
* or characters they have remaining or if they are over the limit. This also
|
412
|
+
* includes a message used as an accessible description for the textarea.
|
413
|
+
* @property {TranslationPluralForms} [charactersUnderLimit] - Message displayed
|
414
|
+
* when the number of characters is under the configured maximum, `maxlength`.
|
415
|
+
* This message is displayed visually and through assistive technologies. The
|
416
|
+
* component will replace the `%{count}` placeholder with the number of
|
417
|
+
* remaining characters. This is a [pluralised list of
|
418
|
+
* messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).
|
419
|
+
* @property {string} [charactersAtLimit] - Message displayed when the number of
|
420
|
+
* characters reaches the configured maximum, `maxlength`. This message is
|
421
|
+
* displayed visually and through assistive technologies.
|
422
|
+
* @property {TranslationPluralForms} [charactersOverLimit] - Message displayed
|
423
|
+
* when the number of characters is over the configured maximum, `maxlength`.
|
424
|
+
* This message is displayed visually and through assistive technologies. The
|
425
|
+
* component will replace the `%{count}` placeholder with the number of
|
426
|
+
* remaining characters. This is a [pluralised list of
|
427
|
+
* messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).
|
428
|
+
* @property {TranslationPluralForms} [wordsUnderLimit] - Message displayed when
|
429
|
+
* the number of words is under the configured maximum, `maxlength`. This
|
430
|
+
* message is displayed visually and through assistive technologies. The
|
431
|
+
* component will replace the `%{count}` placeholder with the number of
|
432
|
+
* remaining words. This is a [pluralised list of
|
433
|
+
* messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).
|
434
|
+
* @property {string} [wordsAtLimit] - Message displayed when the number of
|
435
|
+
* words reaches the configured maximum, `maxlength`. This message is
|
436
|
+
* displayed visually and through assistive technologies.
|
437
|
+
* @property {TranslationPluralForms} [wordsOverLimit] - Message displayed when
|
438
|
+
* the number of words is over the configured maximum, `maxlength`. This
|
439
|
+
* message is displayed visually and through assistive technologies. The
|
440
|
+
* component will replace the `%{count}` placeholder with the number of
|
441
|
+
* remaining words. This is a [pluralised list of
|
442
|
+
* messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).
|
443
|
+
* @property {TranslationPluralForms} [textareaDescription] - Message made
|
444
|
+
* available to assistive technologies, if none is already present in the
|
445
|
+
* HTML, to describe that the component accepts only a limited amount of
|
446
|
+
* content. It is visible on the page when JavaScript is unavailable. The
|
447
|
+
* component will replace the `%{count}` placeholder with the value of the
|
448
|
+
* `maxlength` or `maxwords` parameter.
|
449
|
+
*/
|
450
|
+
|
451
|
+
/**
|
452
|
+
* @typedef {import('../../i18n.mjs').TranslationPluralForms} TranslationPluralForms
|
453
|
+
*/
|
@@ -2,8 +2,14 @@ import '../../vendor/polyfills/Function/prototype/bind.mjs'
|
|
2
2
|
// addEventListener, event.target normalization and DOMContentLoaded
|
3
3
|
import '../../vendor/polyfills/Event.mjs'
|
4
4
|
import '../../vendor/polyfills/Element/prototype/classList.mjs'
|
5
|
-
import { nodeListForEach } from '../../common.mjs'
|
5
|
+
import { nodeListForEach } from '../../common/index.mjs'
|
6
6
|
|
7
|
+
/**
|
8
|
+
* Checkboxes component
|
9
|
+
*
|
10
|
+
* @class
|
11
|
+
* @param {HTMLElement} $module - HTML element to use for checkboxes
|
12
|
+
*/
|
7
13
|
function Checkboxes ($module) {
|
8
14
|
this.$module = $module
|
9
15
|
this.$inputs = $module.querySelectorAll('input[type="checkbox"]')
|
@@ -73,7 +79,7 @@ Checkboxes.prototype.syncAllConditionalReveals = function () {
|
|
73
79
|
* Synchronise the visibility of the conditional reveal, and its accessible
|
74
80
|
* state, with the input's checked state.
|
75
81
|
*
|
76
|
-
* @param {HTMLInputElement} $input Checkbox input
|
82
|
+
* @param {HTMLInputElement} $input - Checkbox input
|
77
83
|
*/
|
78
84
|
Checkboxes.prototype.syncConditionalRevealWithInputState = function ($input) {
|
79
85
|
var $target = document.getElementById($input.getAttribute('aria-controls'))
|
@@ -131,7 +137,7 @@ Checkboxes.prototype.unCheckExclusiveInputs = function ($input) {
|
|
131
137
|
* Handle a click within the $module – if the click occurred on a checkbox, sync
|
132
138
|
* the state of any associated conditional reveal with the checkbox state.
|
133
139
|
*
|
134
|
-
* @param {MouseEvent} event Click event
|
140
|
+
* @param {MouseEvent} event - Click event
|
135
141
|
*/
|
136
142
|
Checkboxes.prototype.handleClick = function (event) {
|
137
143
|
var $target = event.target
|
@@ -6,11 +6,17 @@
|
|
6
6
|
*/
|
7
7
|
import '../../vendor/polyfills/Function/prototype/bind.mjs'
|
8
8
|
import '../../vendor/polyfills/Event.mjs' // addEventListener and event.target normaliziation
|
9
|
-
import { generateUniqueID } from '../../common.mjs'
|
9
|
+
import { generateUniqueID } from '../../common/index.mjs'
|
10
10
|
|
11
11
|
var KEY_ENTER = 13
|
12
12
|
var KEY_SPACE = 32
|
13
13
|
|
14
|
+
/**
|
15
|
+
* Details component
|
16
|
+
*
|
17
|
+
* @class
|
18
|
+
* @param {HTMLElement} $module - HTML element to use for details
|
19
|
+
*/
|
14
20
|
function Details ($module) {
|
15
21
|
this.$module = $module
|
16
22
|
}
|
@@ -77,9 +83,10 @@ Details.prototype.polyfillDetails = function () {
|
|
77
83
|
}
|
78
84
|
|
79
85
|
/**
|
80
|
-
* Define a statechange function that updates aria-expanded and style.display
|
81
|
-
*
|
82
|
-
|
86
|
+
* Define a statechange function that updates aria-expanded and style.display
|
87
|
+
*
|
88
|
+
* @returns {boolean} Returns true
|
89
|
+
*/
|
83
90
|
Details.prototype.polyfillSetAttributes = function () {
|
84
91
|
if (this.$module.hasAttribute('open')) {
|
85
92
|
this.$module.removeAttribute('open')
|
@@ -95,10 +102,11 @@ Details.prototype.polyfillSetAttributes = function () {
|
|
95
102
|
}
|
96
103
|
|
97
104
|
/**
|
98
|
-
* Handle cross-modal click events
|
99
|
-
*
|
100
|
-
* @param {
|
101
|
-
|
105
|
+
* Handle cross-modal click events
|
106
|
+
*
|
107
|
+
* @param {object} node - element
|
108
|
+
* @param {polyfillHandleInputsCallback} callback - function
|
109
|
+
*/
|
102
110
|
Details.prototype.polyfillHandleInputs = function (node, callback) {
|
103
111
|
node.addEventListener('keypress', function (event) {
|
104
112
|
var target = event.target
|
@@ -133,3 +141,9 @@ Details.prototype.polyfillHandleInputs = function (node, callback) {
|
|
133
141
|
}
|
134
142
|
|
135
143
|
export default Details
|
144
|
+
|
145
|
+
/**
|
146
|
+
* @callback polyfillHandleInputsCallback
|
147
|
+
* @param {KeyboardEvent} event - Keyboard event
|
148
|
+
* @returns {undefined}
|
149
|
+
*/
|