govuk_publishing_components 35.10.0 → 35.12.0
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-core.js +2 -48
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-form-tracker.js +5 -0
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js +2 -2
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-schemas.js +51 -5
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-scroll-tracker.js +225 -0
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/init-ga4.js +0 -5
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4.js +1 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_attachment.scss +7 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_feedback.scss +8 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_tables.scss +41 -0
- data/app/views/govuk_publishing_components/components/_attachment.html.erb +3 -1
- data/app/views/govuk_publishing_components/components/_contents_list.html.erb +9 -9
- data/app/views/govuk_publishing_components/components/_metadata.html.erb +2 -1
- data/app/views/govuk_publishing_components/components/_tabs.html.erb +30 -14
- data/app/views/govuk_publishing_components/components/docs/govspeak.yml +22 -0
- data/app/views/govuk_publishing_components/components/docs/tabs.yml +25 -2
- data/lib/govuk_publishing_components/version.rb +1 -1
- data/node_modules/govuk-frontend/govuk/all.js +406 -1
- data/node_modules/govuk-frontend/govuk/all.js.map +1 -1
- data/node_modules/govuk-frontend/govuk/common/govuk-frontend-version.js +1 -1
- data/node_modules/govuk-frontend/govuk/components/_all.scss +2 -1
- data/node_modules/govuk-frontend/govuk/components/back-link/_index.scss +8 -0
- data/node_modules/govuk-frontend/govuk/components/back-link/fixtures.json +9 -0
- data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +12 -0
- data/node_modules/govuk-frontend/govuk/components/breadcrumbs/fixtures.json +21 -0
- data/node_modules/govuk-frontend/govuk/components/button/_index.scss +41 -3
- data/node_modules/govuk-frontend/govuk/components/button/fixtures.json +44 -0
- data/node_modules/govuk-frontend/govuk/components/checkboxes/macro-options.json +9 -8
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/README.md +15 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/_exit-this-page.scss +2 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/_index.scss +97 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/exit-this-page.js +2120 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/exit-this-page.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/fixtures.json +50 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/macro-options.json +62 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/macro.njk +3 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/template.njk +16 -0
- data/node_modules/govuk-frontend/govuk/components/radios/macro-options.json +9 -8
- data/node_modules/govuk-frontend/govuk/core/_govuk-frontend-version.scss +1 -1
- data/node_modules/govuk-frontend/govuk/helpers/_visually-hidden.scss +12 -0
- data/node_modules/govuk-frontend/govuk/objects/_template.scss +20 -0
- data/node_modules/govuk-frontend/govuk-esm/all.mjs +8 -0
- data/node_modules/govuk-frontend/govuk-esm/all.mjs.map +1 -1
- data/node_modules/govuk-frontend/govuk-esm/common/govuk-frontend-version.mjs +1 -1
- data/node_modules/govuk-frontend/govuk-esm/components/exit-this-page/exit-this-page.mjs +406 -0
- data/node_modules/govuk-frontend/govuk-esm/components/exit-this-page/exit-this-page.mjs.map +1 -0
- data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +4 -0
- data/node_modules/govuk-frontend/package.json +4 -2
- metadata +15 -3
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"all.mjs","sources":["../../src/govuk/all.mjs"],"sourcesContent":["import { version } from './common/govuk-frontend-version.mjs'\nimport { nodeListForEach } from './common/index.mjs'\nimport Accordion from './components/accordion/accordion.mjs'\nimport Button from './components/button/button.mjs'\nimport CharacterCount from './components/character-count/character-count.mjs'\nimport Checkboxes from './components/checkboxes/checkboxes.mjs'\nimport Details from './components/details/details.mjs'\nimport ErrorSummary from './components/error-summary/error-summary.mjs'\nimport Header from './components/header/header.mjs'\nimport NotificationBanner from './components/notification-banner/notification-banner.mjs'\nimport Radios from './components/radios/radios.mjs'\nimport SkipLink from './components/skip-link/skip-link.mjs'\nimport Tabs from './components/tabs/tabs.mjs'\n\n/**\n * Initialise all components\n *\n * Use the `data-module` attributes to find, instantiate and init all of the\n * components provided as part of GOV.UK Frontend.\n *\n * @param {Config} [config] - Config for all components\n */\nfunction initAll (config) {\n config = typeof config !== 'undefined' ? config : {}\n\n // Allow the user to initialise GOV.UK Frontend in only certain sections of the page\n // Defaults to the entire document if nothing is set.\n var $scope = config.scope instanceof HTMLElement ? config.scope : document\n\n var $accordions = $scope.querySelectorAll('[data-module=\"govuk-accordion\"]')\n nodeListForEach($accordions, function ($accordion) {\n new Accordion($accordion, config.accordion).init()\n })\n\n var $buttons = $scope.querySelectorAll('[data-module=\"govuk-button\"]')\n nodeListForEach($buttons, function ($button) {\n new Button($button, config.button).init()\n })\n\n var $characterCounts = $scope.querySelectorAll('[data-module=\"govuk-character-count\"]')\n nodeListForEach($characterCounts, function ($characterCount) {\n new CharacterCount($characterCount, config.characterCount).init()\n })\n\n var $checkboxes = $scope.querySelectorAll('[data-module=\"govuk-checkboxes\"]')\n nodeListForEach($checkboxes, function ($checkbox) {\n new Checkboxes($checkbox).init()\n })\n\n var $details = $scope.querySelectorAll('[data-module=\"govuk-details\"]')\n nodeListForEach($details, function ($detail) {\n new Details($detail).init()\n })\n\n // Find first error summary module to enhance.\n var $errorSummary = $scope.querySelector('[data-module=\"govuk-error-summary\"]')\n if ($errorSummary) {\n new ErrorSummary($errorSummary, config.errorSummary).init()\n }\n\n // Find first header module to enhance.\n var $header = $scope.querySelector('[data-module=\"govuk-header\"]')\n if ($header) {\n new Header($header).init()\n }\n\n var $notificationBanners = $scope.querySelectorAll('[data-module=\"govuk-notification-banner\"]')\n nodeListForEach($notificationBanners, function ($notificationBanner) {\n new NotificationBanner($notificationBanner, config.notificationBanner).init()\n })\n\n var $radios = $scope.querySelectorAll('[data-module=\"govuk-radios\"]')\n nodeListForEach($radios, function ($radio) {\n new Radios($radio).init()\n })\n\n // Find first skip link module to enhance.\n var $skipLink = $scope.querySelector('[data-module=\"govuk-skip-link\"]')\n if ($skipLink) {\n new SkipLink($skipLink).init()\n }\n\n var $tabs = $scope.querySelectorAll('[data-module=\"govuk-tabs\"]')\n nodeListForEach($tabs, function ($tabs) {\n new Tabs($tabs).init()\n })\n}\n\nexport {\n initAll,\n version,\n\n // Components\n Accordion,\n Button,\n Details,\n CharacterCount,\n Checkboxes,\n ErrorSummary,\n Header,\n NotificationBanner,\n Radios,\n SkipLink,\n Tabs\n}\n\n/**\n * Config for all components\n *\n * @typedef {object} Config\n * @property {Element} [scope=document] - Scope to query for components\n * @property {import('./components/accordion/accordion.mjs').AccordionConfig} [accordion] - Accordion config\n * @property {import('./components/button/button.mjs').ButtonConfig} [button] - Button config\n * @property {import('./components/character-count/character-count.mjs').CharacterCountConfig} [characterCount] - Character Count config\n * @property {import('./components/error-summary/error-summary.mjs').ErrorSummaryConfig} [errorSummary] - Error Summary config\n * @property {import('./components/notification-banner/notification-banner.mjs').NotificationBannerConfig} [notificationBanner] - Notification Banner config\n */\n"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"all.mjs","sources":["../../src/govuk/all.mjs"],"sourcesContent":["import { version } from './common/govuk-frontend-version.mjs'\nimport { nodeListForEach } from './common/index.mjs'\nimport Accordion from './components/accordion/accordion.mjs'\nimport Button from './components/button/button.mjs'\nimport CharacterCount from './components/character-count/character-count.mjs'\nimport Checkboxes from './components/checkboxes/checkboxes.mjs'\nimport Details from './components/details/details.mjs'\nimport ErrorSummary from './components/error-summary/error-summary.mjs'\nimport ExitThisPage from './components/exit-this-page/exit-this-page.mjs'\nimport Header from './components/header/header.mjs'\nimport NotificationBanner from './components/notification-banner/notification-banner.mjs'\nimport Radios from './components/radios/radios.mjs'\nimport SkipLink from './components/skip-link/skip-link.mjs'\nimport Tabs from './components/tabs/tabs.mjs'\n\n/**\n * Initialise all components\n *\n * Use the `data-module` attributes to find, instantiate and init all of the\n * components provided as part of GOV.UK Frontend.\n *\n * @param {Config} [config] - Config for all components\n */\nfunction initAll (config) {\n config = typeof config !== 'undefined' ? config : {}\n\n // Allow the user to initialise GOV.UK Frontend in only certain sections of the page\n // Defaults to the entire document if nothing is set.\n var $scope = config.scope instanceof HTMLElement ? config.scope : document\n\n var $accordions = $scope.querySelectorAll('[data-module=\"govuk-accordion\"]')\n nodeListForEach($accordions, function ($accordion) {\n new Accordion($accordion, config.accordion).init()\n })\n\n var $buttons = $scope.querySelectorAll('[data-module=\"govuk-button\"]')\n nodeListForEach($buttons, function ($button) {\n new Button($button, config.button).init()\n })\n\n var $characterCounts = $scope.querySelectorAll('[data-module=\"govuk-character-count\"]')\n nodeListForEach($characterCounts, function ($characterCount) {\n new CharacterCount($characterCount, config.characterCount).init()\n })\n\n var $checkboxes = $scope.querySelectorAll('[data-module=\"govuk-checkboxes\"]')\n nodeListForEach($checkboxes, function ($checkbox) {\n new Checkboxes($checkbox).init()\n })\n\n var $details = $scope.querySelectorAll('[data-module=\"govuk-details\"]')\n nodeListForEach($details, function ($detail) {\n new Details($detail).init()\n })\n\n // Find first error summary module to enhance.\n var $errorSummary = $scope.querySelector('[data-module=\"govuk-error-summary\"]')\n if ($errorSummary) {\n new ErrorSummary($errorSummary, config.errorSummary).init()\n }\n\n var $exitThisPageButtons = $scope.querySelectorAll('[data-module=\"govuk-exit-this-page\"]')\n nodeListForEach($exitThisPageButtons, function ($button) {\n new ExitThisPage($button, config.exitThisPage).init()\n })\n\n // Find first header module to enhance.\n var $header = $scope.querySelector('[data-module=\"govuk-header\"]')\n if ($header) {\n new Header($header).init()\n }\n\n var $notificationBanners = $scope.querySelectorAll('[data-module=\"govuk-notification-banner\"]')\n nodeListForEach($notificationBanners, function ($notificationBanner) {\n new NotificationBanner($notificationBanner, config.notificationBanner).init()\n })\n\n var $radios = $scope.querySelectorAll('[data-module=\"govuk-radios\"]')\n nodeListForEach($radios, function ($radio) {\n new Radios($radio).init()\n })\n\n // Find first skip link module to enhance.\n var $skipLink = $scope.querySelector('[data-module=\"govuk-skip-link\"]')\n if ($skipLink) {\n new SkipLink($skipLink).init()\n }\n\n var $tabs = $scope.querySelectorAll('[data-module=\"govuk-tabs\"]')\n nodeListForEach($tabs, function ($tabs) {\n new Tabs($tabs).init()\n })\n}\n\nexport {\n initAll,\n version,\n\n // Components\n Accordion,\n Button,\n Details,\n CharacterCount,\n Checkboxes,\n ErrorSummary,\n ExitThisPage,\n Header,\n NotificationBanner,\n Radios,\n SkipLink,\n Tabs\n}\n\n/**\n * Config for all components\n *\n * @typedef {object} Config\n * @property {Element} [scope=document] - Scope to query for components\n * @property {import('./components/accordion/accordion.mjs').AccordionConfig} [accordion] - Accordion config\n * @property {import('./components/button/button.mjs').ButtonConfig} [button] - Button config\n * @property {import('./components/character-count/character-count.mjs').CharacterCountConfig} [characterCount] - Character Count config\n * @property {import('./components/error-summary/error-summary.mjs').ErrorSummaryConfig} [errorSummary] - Error Summary config\n * @property {import('./components/exit-this-page/exit-this-page.mjs').ExitThisPageConfig} [exitThisPage] - Exit This Page config\n * @property {import('./components/notification-banner/notification-banner.mjs').NotificationBannerConfig} [notificationBanner] - Notification Banner config\n */\n"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,406 @@
|
|
1
|
+
import { normaliseDataset } from '../../common/normalise-dataset.mjs';
|
2
|
+
import { I18n } from '../../i18n.mjs';
|
3
|
+
import '../../vendor/polyfills/Element/prototype/classList.mjs';
|
4
|
+
import '../../vendor/polyfills/Event.mjs';
|
5
|
+
import '../../vendor/polyfills/Element/prototype/dataset.mjs';
|
6
|
+
import '../../vendor/polyfills/Function/prototype/bind.mjs';
|
7
|
+
import { nodeListForEach, mergeConfigs, extractConfigByNamespace } from '../../common/index.mjs';
|
8
|
+
|
9
|
+
/* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */
|
10
|
+
|
11
|
+
/**
|
12
|
+
* @constant
|
13
|
+
* @type {ExitThisPageTranslations}
|
14
|
+
* @see Default value for {@link ExitThisPageConfig.i18n}
|
15
|
+
* @default
|
16
|
+
*/
|
17
|
+
var EXIT_THIS_PAGE_TRANSLATIONS = {
|
18
|
+
activated: 'Loading.',
|
19
|
+
timedOut: 'Exit this page expired.',
|
20
|
+
pressTwoMoreTimes: 'Shift, press 2 more times to exit.',
|
21
|
+
pressOneMoreTime: 'Shift, press 1 more time to exit.'
|
22
|
+
};
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Exit This Page component
|
26
|
+
*
|
27
|
+
* @class
|
28
|
+
* @param {HTMLElement} $module - HTML element that wraps the Exit This Page button
|
29
|
+
* @param {ExitThisPageConfig} [config] - Exit This Page config
|
30
|
+
*/
|
31
|
+
function ExitThisPage ($module, config) {
|
32
|
+
/** @type {ExitThisPageConfig} */
|
33
|
+
var defaultConfig = {
|
34
|
+
i18n: EXIT_THIS_PAGE_TRANSLATIONS
|
35
|
+
};
|
36
|
+
|
37
|
+
if (!($module instanceof HTMLElement)) {
|
38
|
+
return this
|
39
|
+
}
|
40
|
+
|
41
|
+
var $button = $module.querySelector('.govuk-exit-this-page__button');
|
42
|
+
if (!($button instanceof HTMLElement)) {
|
43
|
+
return this
|
44
|
+
}
|
45
|
+
|
46
|
+
/**
|
47
|
+
* @deprecated Will be made private in v5.0
|
48
|
+
* @type {ExitThisPageConfig}
|
49
|
+
*/
|
50
|
+
this.config = mergeConfigs(
|
51
|
+
defaultConfig,
|
52
|
+
config || {},
|
53
|
+
normaliseDataset($module.dataset)
|
54
|
+
);
|
55
|
+
|
56
|
+
this.i18n = new I18n(extractConfigByNamespace(this.config, 'i18n'));
|
57
|
+
|
58
|
+
/** @deprecated Will be made private in v5.0 */
|
59
|
+
this.$module = $module;
|
60
|
+
|
61
|
+
/** @deprecated Will be made private in v5.0 */
|
62
|
+
this.$button = $button;
|
63
|
+
|
64
|
+
/** @deprecated Will be made private in v5.0 */
|
65
|
+
this.$skiplinkButton = document.querySelector('.govuk-js-exit-this-page-skiplink');
|
66
|
+
|
67
|
+
/** @deprecated Will be made private in v5.0 */
|
68
|
+
this.$updateSpan = null;
|
69
|
+
|
70
|
+
/** @deprecated Will be made private in v5.0 */
|
71
|
+
this.$indicatorContainer = null;
|
72
|
+
|
73
|
+
/** @deprecated Will be made private in v5.0 */
|
74
|
+
this.$overlay = null;
|
75
|
+
|
76
|
+
/** @deprecated Will be made private in v5.0 */
|
77
|
+
this.keypressCounter = 0;
|
78
|
+
|
79
|
+
/** @deprecated Will be made private in v5.0 */
|
80
|
+
this.lastKeyWasModified = false;
|
81
|
+
|
82
|
+
/** @deprecated Will be made private in v5.0 */
|
83
|
+
this.timeoutTime = 5000; // milliseconds
|
84
|
+
|
85
|
+
// Store the timeout events so that we can clear them to avoid user keypresses overlapping
|
86
|
+
// setTimeout returns an id that we can use to clear it with clearTimeout,
|
87
|
+
// hence the 'Id' suffix
|
88
|
+
|
89
|
+
/** @deprecated Will be made private in v5.0 */
|
90
|
+
this.keypressTimeoutId = null;
|
91
|
+
|
92
|
+
/** @deprecated Will be made private in v5.0 */
|
93
|
+
this.timeoutMessageId = null;
|
94
|
+
}
|
95
|
+
|
96
|
+
/**
|
97
|
+
* Create the <span> we use for screen reader announcements.
|
98
|
+
*
|
99
|
+
* @deprecated Will be made private in v5.0
|
100
|
+
*/
|
101
|
+
ExitThisPage.prototype.initUpdateSpan = function () {
|
102
|
+
this.$updateSpan = document.createElement('span');
|
103
|
+
this.$updateSpan.setAttribute('role', 'status');
|
104
|
+
this.$updateSpan.className = 'govuk-visually-hidden';
|
105
|
+
|
106
|
+
this.$module.appendChild(this.$updateSpan);
|
107
|
+
};
|
108
|
+
|
109
|
+
/**
|
110
|
+
* Create button click handlers.
|
111
|
+
*
|
112
|
+
* @deprecated Will be made private in v5.0
|
113
|
+
*/
|
114
|
+
ExitThisPage.prototype.initButtonClickHandler = function () {
|
115
|
+
// Main EtP button
|
116
|
+
this.$button.addEventListener('click', this.handleClick.bind(this));
|
117
|
+
|
118
|
+
// EtP skiplink
|
119
|
+
if (this.$skiplinkButton) {
|
120
|
+
this.$skiplinkButton.addEventListener('click', this.handleClick.bind(this));
|
121
|
+
}
|
122
|
+
};
|
123
|
+
|
124
|
+
/**
|
125
|
+
* Create the HTML for the 'three lights' indicator on the button.
|
126
|
+
*
|
127
|
+
* @deprecated Will be made private in v5.0
|
128
|
+
*/
|
129
|
+
ExitThisPage.prototype.buildIndicator = function () {
|
130
|
+
// Build container
|
131
|
+
// Putting `aria-hidden` on it as it won't contain any readable information
|
132
|
+
this.$indicatorContainer = document.createElement('div');
|
133
|
+
this.$indicatorContainer.className = 'govuk-exit-this-page__indicator';
|
134
|
+
this.$indicatorContainer.setAttribute('aria-hidden', 'true');
|
135
|
+
|
136
|
+
// Create three 'lights' and place them within the container
|
137
|
+
for (var i = 0; i < 3; i++) {
|
138
|
+
var $indicator = document.createElement('div');
|
139
|
+
$indicator.className = 'govuk-exit-this-page__indicator-light';
|
140
|
+
this.$indicatorContainer.appendChild($indicator);
|
141
|
+
}
|
142
|
+
|
143
|
+
// Append it all to the module
|
144
|
+
this.$button.appendChild(this.$indicatorContainer);
|
145
|
+
};
|
146
|
+
|
147
|
+
/**
|
148
|
+
* Update whether the lights are visible and which ones are lit up depending on
|
149
|
+
* the value of `keypressCounter`.
|
150
|
+
*
|
151
|
+
* @deprecated Will be made private in v5.0
|
152
|
+
*/
|
153
|
+
ExitThisPage.prototype.updateIndicator = function () {
|
154
|
+
// Show or hide the indicator container depending on keypressCounter value
|
155
|
+
if (this.keypressCounter > 0) {
|
156
|
+
this.$indicatorContainer.classList.add('govuk-exit-this-page__indicator--visible');
|
157
|
+
} else {
|
158
|
+
this.$indicatorContainer.classList.remove('govuk-exit-this-page__indicator--visible');
|
159
|
+
}
|
160
|
+
|
161
|
+
// Turn on only the indicators we want on
|
162
|
+
var $indicators = this.$indicatorContainer.querySelectorAll(
|
163
|
+
'.govuk-exit-this-page__indicator-light'
|
164
|
+
);
|
165
|
+
nodeListForEach($indicators, function ($indicator, index) {
|
166
|
+
$indicator.classList.toggle(
|
167
|
+
'govuk-exit-this-page__indicator-light--on',
|
168
|
+
index < this.keypressCounter
|
169
|
+
);
|
170
|
+
}.bind(this));
|
171
|
+
};
|
172
|
+
|
173
|
+
/**
|
174
|
+
* Initiates the redirection away from the current page.
|
175
|
+
* Includes the loading overlay functionality, which covers the current page with a
|
176
|
+
* white overlay so that the contents are not visible during the loading
|
177
|
+
* process. This is particularly important on slow network connections.
|
178
|
+
*
|
179
|
+
* @deprecated Will be made private in v5.0
|
180
|
+
*/
|
181
|
+
ExitThisPage.prototype.exitPage = function () {
|
182
|
+
this.$updateSpan.innerText = '';
|
183
|
+
|
184
|
+
// Blank the page
|
185
|
+
// As well as creating an overlay with text, we also set the body to hidden
|
186
|
+
// to prevent screen reader and sequential navigation users potentially
|
187
|
+
// navigating through the page behind the overlay during loading
|
188
|
+
document.body.classList.add('govuk-exit-this-page-hide-content');
|
189
|
+
this.$overlay = document.createElement('div');
|
190
|
+
this.$overlay.className = 'govuk-exit-this-page-overlay';
|
191
|
+
this.$overlay.setAttribute('role', 'alert');
|
192
|
+
|
193
|
+
// we do these this way round, thus incurring a second paint, because changing
|
194
|
+
// the element text after adding it means that screen readers pick up the
|
195
|
+
// announcement more reliably.
|
196
|
+
document.body.appendChild(this.$overlay);
|
197
|
+
this.$overlay.innerText = this.i18n.t('activated');
|
198
|
+
|
199
|
+
window.location.href = this.$button.getAttribute('href');
|
200
|
+
};
|
201
|
+
|
202
|
+
/**
|
203
|
+
* Pre-activation logic for when the button is clicked/activated via mouse or
|
204
|
+
* pointer.
|
205
|
+
*
|
206
|
+
* We do this to differentiate it from the keyboard activation event because we
|
207
|
+
* need to run `e.preventDefault` as the button or skiplink are both links and we
|
208
|
+
* want to apply some additional logic in `exitPage` before navigating.
|
209
|
+
*
|
210
|
+
* @deprecated Will be made private in v5.0
|
211
|
+
* @param {MouseEvent} event - mouse click event
|
212
|
+
*/
|
213
|
+
ExitThisPage.prototype.handleClick = function (event) {
|
214
|
+
event.preventDefault();
|
215
|
+
this.exitPage();
|
216
|
+
};
|
217
|
+
|
218
|
+
/**
|
219
|
+
* Logic for the 'quick escape' keyboard sequence functionality (pressing the
|
220
|
+
* Shift key three times without interruption, within a time limit).
|
221
|
+
*
|
222
|
+
* @deprecated Will be made private in v5.0
|
223
|
+
* @param {KeyboardEvent} event - keyup event
|
224
|
+
*/
|
225
|
+
ExitThisPage.prototype.handleKeypress = function (event) {
|
226
|
+
// Detect if the 'Shift' key has been pressed. We want to only do things if it
|
227
|
+
// was pressed by itself and not in a combination with another key—so we keep
|
228
|
+
// track of whether the preceding keyup had shiftKey: true on it, and if it
|
229
|
+
// did, we ignore the next Shift keyup event.
|
230
|
+
//
|
231
|
+
// This works because using Shift as a modifier key (e.g. pressing Shift + A)
|
232
|
+
// will fire TWO keyup events, one for A (with e.shiftKey: true) and the other
|
233
|
+
// for Shift (with e.shiftKey: false).
|
234
|
+
if (
|
235
|
+
(event.key === 'Shift' || event.keyCode === 16 || event.which === 16) &&
|
236
|
+
!this.lastKeyWasModified
|
237
|
+
) {
|
238
|
+
this.keypressCounter += 1;
|
239
|
+
|
240
|
+
// Update the indicator before the below if statement can reset it back to 0
|
241
|
+
this.updateIndicator();
|
242
|
+
|
243
|
+
// Clear the timeout for the keypress timeout message clearing itself
|
244
|
+
if (this.timeoutMessageId !== null) {
|
245
|
+
clearTimeout(this.timeoutMessageId);
|
246
|
+
this.timeoutMessageId = null;
|
247
|
+
}
|
248
|
+
|
249
|
+
if (this.keypressCounter >= 3) {
|
250
|
+
this.keypressCounter = 0;
|
251
|
+
|
252
|
+
if (this.keypressTimeoutId !== null) {
|
253
|
+
clearTimeout(this.keypressTimeoutId);
|
254
|
+
this.keypressTimeoutId = null;
|
255
|
+
}
|
256
|
+
|
257
|
+
this.exitPage();
|
258
|
+
} else {
|
259
|
+
if (this.keypressCounter === 1) {
|
260
|
+
this.$updateSpan.innerText = this.i18n.t('pressTwoMoreTimes');
|
261
|
+
} else {
|
262
|
+
this.$updateSpan.innerText = this.i18n.t('pressOneMoreTime');
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
266
|
+
this.setKeypressTimer();
|
267
|
+
} else if (this.keypressTimeoutId !== null) {
|
268
|
+
// If the user pressed any key other than 'Shift', after having pressed
|
269
|
+
// 'Shift' and activating the timer, stop and reset the timer.
|
270
|
+
this.resetKeypressTimer();
|
271
|
+
}
|
272
|
+
|
273
|
+
// Keep track of whether the Shift modifier key was held during this keypress
|
274
|
+
this.lastKeyWasModified = event.shiftKey;
|
275
|
+
};
|
276
|
+
|
277
|
+
/**
|
278
|
+
* Starts the 'quick escape' keyboard sequence timer.
|
279
|
+
*
|
280
|
+
* This can be invoked several times. We want this to be possible so that the
|
281
|
+
* timer is restarted each time the shortcut key is pressed (e.g. the user has
|
282
|
+
* up to n seconds between each keypress, rather than n seconds to invoke the
|
283
|
+
* entire sequence.)
|
284
|
+
*
|
285
|
+
* @deprecated Will be made private in v5.0
|
286
|
+
*/
|
287
|
+
ExitThisPage.prototype.setKeypressTimer = function () {
|
288
|
+
// Clear any existing timeout. This is so only one timer is running even if
|
289
|
+
// there are multiple keypresses in quick succession.
|
290
|
+
clearTimeout(this.keypressTimeoutId);
|
291
|
+
|
292
|
+
// Set a fresh timeout
|
293
|
+
this.keypressTimeoutId = setTimeout(
|
294
|
+
this.resetKeypressTimer.bind(this),
|
295
|
+
this.timeoutTime
|
296
|
+
);
|
297
|
+
};
|
298
|
+
|
299
|
+
/**
|
300
|
+
* Stops and resets the 'quick escape' keyboard sequence timer.
|
301
|
+
*
|
302
|
+
* @deprecated Will be made private in v5.0
|
303
|
+
*/
|
304
|
+
ExitThisPage.prototype.resetKeypressTimer = function () {
|
305
|
+
clearTimeout(this.keypressTimeoutId);
|
306
|
+
this.keypressTimeoutId = null;
|
307
|
+
|
308
|
+
this.keypressCounter = 0;
|
309
|
+
this.$updateSpan.innerText = this.i18n.t('timedOut');
|
310
|
+
|
311
|
+
this.timeoutMessageId = setTimeout(function () {
|
312
|
+
this.$updateSpan.innerText = '';
|
313
|
+
}.bind(this), this.timeoutTime);
|
314
|
+
|
315
|
+
this.updateIndicator();
|
316
|
+
};
|
317
|
+
|
318
|
+
/**
|
319
|
+
* Reset the page using the EtP button
|
320
|
+
*
|
321
|
+
* We use this in situations where a user may re-enter a page using the browser
|
322
|
+
* back button. In these cases, the browser can choose to restore the state of
|
323
|
+
* the page as it was previously, including restoring the 'ghost page' overlay,
|
324
|
+
* the announcement span having it's role set to "alert" and the keypress
|
325
|
+
* indicator still active, leaving the page in an unusable state.
|
326
|
+
*
|
327
|
+
* By running this check when the page is shown, we can programatically restore
|
328
|
+
* the page and the component to a "default" state
|
329
|
+
*
|
330
|
+
* @deprecated Will be made private in v5.0
|
331
|
+
*/
|
332
|
+
ExitThisPage.prototype.resetPage = function () {
|
333
|
+
// If an overlay is set, remove it and reset the value
|
334
|
+
document.body.classList.remove('govuk-exit-this-page-hide-content');
|
335
|
+
|
336
|
+
if (this.$overlay) {
|
337
|
+
this.$overlay.remove();
|
338
|
+
this.$overlay = null;
|
339
|
+
}
|
340
|
+
|
341
|
+
// Ensure the announcement span's role is status, not alert and clear any text
|
342
|
+
this.$updateSpan.setAttribute('role', 'status');
|
343
|
+
this.$updateSpan.innerText = '';
|
344
|
+
|
345
|
+
// Sync the keypress indicator lights
|
346
|
+
this.updateIndicator();
|
347
|
+
|
348
|
+
// If the timeouts are active, clear them
|
349
|
+
if (this.keypressTimeoutId) {
|
350
|
+
clearTimeout(this.keypressTimeoutId);
|
351
|
+
}
|
352
|
+
|
353
|
+
if (this.timeoutMessageId) {
|
354
|
+
clearTimeout(this.timeoutMessageId);
|
355
|
+
}
|
356
|
+
};
|
357
|
+
|
358
|
+
/**
|
359
|
+
* Initialise component
|
360
|
+
*/
|
361
|
+
ExitThisPage.prototype.init = function () {
|
362
|
+
this.buildIndicator();
|
363
|
+
this.initUpdateSpan();
|
364
|
+
this.initButtonClickHandler();
|
365
|
+
|
366
|
+
// Check to see if this has already been done by a previous initialisation of ExitThisPage
|
367
|
+
if (!('govukFrontendExitThisPageKeypress' in document.body.dataset)) {
|
368
|
+
document.addEventListener('keyup', this.handleKeypress.bind(this), true);
|
369
|
+
document.body.dataset.govukFrontendExitThisPageKeypress = 'true';
|
370
|
+
}
|
371
|
+
|
372
|
+
// When the page is restored after navigating 'back' in some browsers the
|
373
|
+
// blank overlay remains present, rendering the page unusable. Here, we check
|
374
|
+
// to see if it's present on page (re)load, and remove it if so.
|
375
|
+
window.addEventListener(
|
376
|
+
'onpageshow' in window ? 'pageshow' : 'DOMContentLoaded',
|
377
|
+
this.resetPage.bind(this)
|
378
|
+
);
|
379
|
+
};
|
380
|
+
|
381
|
+
/**
|
382
|
+
* Exit this Page config
|
383
|
+
*
|
384
|
+
* @typedef {object} ExitThisPageConfig
|
385
|
+
* @property {ExitThisPageTranslations} [i18n = EXIT_THIS_PAGE_TRANSLATIONS] - See constant {@link EXIT_THIS_PAGE_TRANSLATIONS}
|
386
|
+
*/
|
387
|
+
|
388
|
+
/**
|
389
|
+
* Exit this Page translations
|
390
|
+
*
|
391
|
+
* @typedef {object} ExitThisPageTranslations
|
392
|
+
*
|
393
|
+
* Messages used by the component programatically inserted text, including
|
394
|
+
* overlay text and screen reader announcements.
|
395
|
+
* @property {string} [activated] - Screen reader announcement for when EtP
|
396
|
+
* keypress functionality has been successfully activated.
|
397
|
+
* @property {string} [timedOut] - Screen reader announcement for when the EtP
|
398
|
+
* keypress functionality has timed out.
|
399
|
+
* @property {string} [pressTwoMoreTimes] - Screen reader announcement informing
|
400
|
+
* the user they must press the activation key two more times.
|
401
|
+
* @property {string} [pressOneMoreTime] - Screen reader announcement informing
|
402
|
+
* the user they must press the activation key one more time.
|
403
|
+
*/
|
404
|
+
|
405
|
+
export default ExitThisPage;
|
406
|
+
//# sourceMappingURL=components/exit-this-page/exit-this-page.mjs.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"exit-this-page.mjs","sources":["../../../../src/govuk/components/exit-this-page/exit-this-page.mjs"],"sourcesContent":["/* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */\n\nimport { normaliseDataset } from '../../common/normalise-dataset.mjs'\nimport { nodeListForEach, mergeConfigs, extractConfigByNamespace } from '../../common.mjs'\nimport { I18n } from '../../i18n.mjs'\nimport '../../vendor/polyfills/Element/prototype/classList.mjs'\nimport '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded\nimport '../../vendor/polyfills/Element/prototype/dataset.mjs'\nimport '../../vendor/polyfills/Function/prototype/bind.mjs'\n\n/**\n * @constant\n * @type {ExitThisPageTranslations}\n * @see Default value for {@link ExitThisPageConfig.i18n}\n * @default\n */\nvar EXIT_THIS_PAGE_TRANSLATIONS = {\n activated: 'Loading.',\n timedOut: 'Exit this page expired.',\n pressTwoMoreTimes: 'Shift, press 2 more times to exit.',\n pressOneMoreTime: 'Shift, press 1 more time to exit.'\n}\n\n/**\n * Exit This Page component\n *\n * @class\n * @param {HTMLElement} $module - HTML element that wraps the Exit This Page button\n * @param {ExitThisPageConfig} [config] - Exit This Page config\n */\nfunction ExitThisPage ($module, config) {\n /** @type {ExitThisPageConfig} */\n var defaultConfig = {\n i18n: EXIT_THIS_PAGE_TRANSLATIONS\n }\n\n if (!($module instanceof HTMLElement)) {\n return this\n }\n\n var $button = $module.querySelector('.govuk-exit-this-page__button')\n if (!($button instanceof HTMLElement)) {\n return this\n }\n\n /**\n * @deprecated Will be made private in v5.0\n * @type {ExitThisPageConfig}\n */\n this.config = mergeConfigs(\n defaultConfig,\n config || {},\n normaliseDataset($module.dataset)\n )\n\n this.i18n = new I18n(extractConfigByNamespace(this.config, 'i18n'))\n\n /** @deprecated Will be made private in v5.0 */\n this.$module = $module\n\n /** @deprecated Will be made private in v5.0 */\n this.$button = $button\n\n /** @deprecated Will be made private in v5.0 */\n this.$skiplinkButton = document.querySelector('.govuk-js-exit-this-page-skiplink')\n\n /** @deprecated Will be made private in v5.0 */\n this.$updateSpan = null\n\n /** @deprecated Will be made private in v5.0 */\n this.$indicatorContainer = null\n\n /** @deprecated Will be made private in v5.0 */\n this.$overlay = null\n\n /** @deprecated Will be made private in v5.0 */\n this.keypressCounter = 0\n\n /** @deprecated Will be made private in v5.0 */\n this.lastKeyWasModified = false\n\n /** @deprecated Will be made private in v5.0 */\n this.timeoutTime = 5000 // milliseconds\n\n // Store the timeout events so that we can clear them to avoid user keypresses overlapping\n // setTimeout returns an id that we can use to clear it with clearTimeout,\n // hence the 'Id' suffix\n\n /** @deprecated Will be made private in v5.0 */\n this.keypressTimeoutId = null\n\n /** @deprecated Will be made private in v5.0 */\n this.timeoutMessageId = null\n}\n\n/**\n * Create the <span> we use for screen reader announcements.\n *\n * @deprecated Will be made private in v5.0\n */\nExitThisPage.prototype.initUpdateSpan = function () {\n this.$updateSpan = document.createElement('span')\n this.$updateSpan.setAttribute('role', 'status')\n this.$updateSpan.className = 'govuk-visually-hidden'\n\n this.$module.appendChild(this.$updateSpan)\n}\n\n/**\n * Create button click handlers.\n *\n * @deprecated Will be made private in v5.0\n */\nExitThisPage.prototype.initButtonClickHandler = function () {\n // Main EtP button\n this.$button.addEventListener('click', this.handleClick.bind(this))\n\n // EtP skiplink\n if (this.$skiplinkButton) {\n this.$skiplinkButton.addEventListener('click', this.handleClick.bind(this))\n }\n}\n\n/**\n * Create the HTML for the 'three lights' indicator on the button.\n *\n * @deprecated Will be made private in v5.0\n */\nExitThisPage.prototype.buildIndicator = function () {\n // Build container\n // Putting `aria-hidden` on it as it won't contain any readable information\n this.$indicatorContainer = document.createElement('div')\n this.$indicatorContainer.className = 'govuk-exit-this-page__indicator'\n this.$indicatorContainer.setAttribute('aria-hidden', 'true')\n\n // Create three 'lights' and place them within the container\n for (var i = 0; i < 3; i++) {\n var $indicator = document.createElement('div')\n $indicator.className = 'govuk-exit-this-page__indicator-light'\n this.$indicatorContainer.appendChild($indicator)\n }\n\n // Append it all to the module\n this.$button.appendChild(this.$indicatorContainer)\n}\n\n/**\n * Update whether the lights are visible and which ones are lit up depending on\n * the value of `keypressCounter`.\n *\n * @deprecated Will be made private in v5.0\n */\nExitThisPage.prototype.updateIndicator = function () {\n // Show or hide the indicator container depending on keypressCounter value\n if (this.keypressCounter > 0) {\n this.$indicatorContainer.classList.add('govuk-exit-this-page__indicator--visible')\n } else {\n this.$indicatorContainer.classList.remove('govuk-exit-this-page__indicator--visible')\n }\n\n // Turn on only the indicators we want on\n var $indicators = this.$indicatorContainer.querySelectorAll(\n '.govuk-exit-this-page__indicator-light'\n )\n nodeListForEach($indicators, function ($indicator, index) {\n $indicator.classList.toggle(\n 'govuk-exit-this-page__indicator-light--on',\n index < this.keypressCounter\n )\n }.bind(this))\n}\n\n/**\n * Initiates the redirection away from the current page.\n * Includes the loading overlay functionality, which covers the current page with a\n * white overlay so that the contents are not visible during the loading\n * process. This is particularly important on slow network connections.\n *\n * @deprecated Will be made private in v5.0\n */\nExitThisPage.prototype.exitPage = function () {\n this.$updateSpan.innerText = ''\n\n // Blank the page\n // As well as creating an overlay with text, we also set the body to hidden\n // to prevent screen reader and sequential navigation users potentially\n // navigating through the page behind the overlay during loading\n document.body.classList.add('govuk-exit-this-page-hide-content')\n this.$overlay = document.createElement('div')\n this.$overlay.className = 'govuk-exit-this-page-overlay'\n this.$overlay.setAttribute('role', 'alert')\n\n // we do these this way round, thus incurring a second paint, because changing\n // the element text after adding it means that screen readers pick up the\n // announcement more reliably.\n document.body.appendChild(this.$overlay)\n this.$overlay.innerText = this.i18n.t('activated')\n\n window.location.href = this.$button.getAttribute('href')\n}\n\n/**\n * Pre-activation logic for when the button is clicked/activated via mouse or\n * pointer.\n *\n * We do this to differentiate it from the keyboard activation event because we\n * need to run `e.preventDefault` as the button or skiplink are both links and we\n * want to apply some additional logic in `exitPage` before navigating.\n *\n * @deprecated Will be made private in v5.0\n * @param {MouseEvent} event - mouse click event\n */\nExitThisPage.prototype.handleClick = function (event) {\n event.preventDefault()\n this.exitPage()\n}\n\n/**\n * Logic for the 'quick escape' keyboard sequence functionality (pressing the\n * Shift key three times without interruption, within a time limit).\n *\n * @deprecated Will be made private in v5.0\n * @param {KeyboardEvent} event - keyup event\n */\nExitThisPage.prototype.handleKeypress = function (event) {\n // Detect if the 'Shift' key has been pressed. We want to only do things if it\n // was pressed by itself and not in a combination with another key—so we keep\n // track of whether the preceding keyup had shiftKey: true on it, and if it\n // did, we ignore the next Shift keyup event.\n //\n // This works because using Shift as a modifier key (e.g. pressing Shift + A)\n // will fire TWO keyup events, one for A (with e.shiftKey: true) and the other\n // for Shift (with e.shiftKey: false).\n if (\n (event.key === 'Shift' || event.keyCode === 16 || event.which === 16) &&\n !this.lastKeyWasModified\n ) {\n this.keypressCounter += 1\n\n // Update the indicator before the below if statement can reset it back to 0\n this.updateIndicator()\n\n // Clear the timeout for the keypress timeout message clearing itself\n if (this.timeoutMessageId !== null) {\n clearTimeout(this.timeoutMessageId)\n this.timeoutMessageId = null\n }\n\n if (this.keypressCounter >= 3) {\n this.keypressCounter = 0\n\n if (this.keypressTimeoutId !== null) {\n clearTimeout(this.keypressTimeoutId)\n this.keypressTimeoutId = null\n }\n\n this.exitPage()\n } else {\n if (this.keypressCounter === 1) {\n this.$updateSpan.innerText = this.i18n.t('pressTwoMoreTimes')\n } else {\n this.$updateSpan.innerText = this.i18n.t('pressOneMoreTime')\n }\n }\n\n this.setKeypressTimer()\n } else if (this.keypressTimeoutId !== null) {\n // If the user pressed any key other than 'Shift', after having pressed\n // 'Shift' and activating the timer, stop and reset the timer.\n this.resetKeypressTimer()\n }\n\n // Keep track of whether the Shift modifier key was held during this keypress\n this.lastKeyWasModified = event.shiftKey\n}\n\n/**\n * Starts the 'quick escape' keyboard sequence timer.\n *\n * This can be invoked several times. We want this to be possible so that the\n * timer is restarted each time the shortcut key is pressed (e.g. the user has\n * up to n seconds between each keypress, rather than n seconds to invoke the\n * entire sequence.)\n *\n * @deprecated Will be made private in v5.0\n */\nExitThisPage.prototype.setKeypressTimer = function () {\n // Clear any existing timeout. This is so only one timer is running even if\n // there are multiple keypresses in quick succession.\n clearTimeout(this.keypressTimeoutId)\n\n // Set a fresh timeout\n this.keypressTimeoutId = setTimeout(\n this.resetKeypressTimer.bind(this),\n this.timeoutTime\n )\n}\n\n/**\n * Stops and resets the 'quick escape' keyboard sequence timer.\n *\n * @deprecated Will be made private in v5.0\n */\nExitThisPage.prototype.resetKeypressTimer = function () {\n clearTimeout(this.keypressTimeoutId)\n this.keypressTimeoutId = null\n\n this.keypressCounter = 0\n this.$updateSpan.innerText = this.i18n.t('timedOut')\n\n this.timeoutMessageId = setTimeout(function () {\n this.$updateSpan.innerText = ''\n }.bind(this), this.timeoutTime)\n\n this.updateIndicator()\n}\n\n/**\n * Reset the page using the EtP button\n *\n * We use this in situations where a user may re-enter a page using the browser\n * back button. In these cases, the browser can choose to restore the state of\n * the page as it was previously, including restoring the 'ghost page' overlay,\n * the announcement span having it's role set to \"alert\" and the keypress\n * indicator still active, leaving the page in an unusable state.\n *\n * By running this check when the page is shown, we can programatically restore\n * the page and the component to a \"default\" state\n *\n * @deprecated Will be made private in v5.0\n */\nExitThisPage.prototype.resetPage = function () {\n // If an overlay is set, remove it and reset the value\n document.body.classList.remove('govuk-exit-this-page-hide-content')\n\n if (this.$overlay) {\n this.$overlay.remove()\n this.$overlay = null\n }\n\n // Ensure the announcement span's role is status, not alert and clear any text\n this.$updateSpan.setAttribute('role', 'status')\n this.$updateSpan.innerText = ''\n\n // Sync the keypress indicator lights\n this.updateIndicator()\n\n // If the timeouts are active, clear them\n if (this.keypressTimeoutId) {\n clearTimeout(this.keypressTimeoutId)\n }\n\n if (this.timeoutMessageId) {\n clearTimeout(this.timeoutMessageId)\n }\n}\n\n/**\n * Initialise component\n */\nExitThisPage.prototype.init = function () {\n this.buildIndicator()\n this.initUpdateSpan()\n this.initButtonClickHandler()\n\n // Check to see if this has already been done by a previous initialisation of ExitThisPage\n if (!('govukFrontendExitThisPageKeypress' in document.body.dataset)) {\n document.addEventListener('keyup', this.handleKeypress.bind(this), true)\n document.body.dataset.govukFrontendExitThisPageKeypress = 'true'\n }\n\n // When the page is restored after navigating 'back' in some browsers the\n // blank overlay remains present, rendering the page unusable. Here, we check\n // to see if it's present on page (re)load, and remove it if so.\n window.addEventListener(\n 'onpageshow' in window ? 'pageshow' : 'DOMContentLoaded',\n this.resetPage.bind(this)\n )\n}\n\nexport default ExitThisPage\n\n/**\n * Exit this Page config\n *\n * @typedef {object} ExitThisPageConfig\n * @property {ExitThisPageTranslations} [i18n = EXIT_THIS_PAGE_TRANSLATIONS] - See constant {@link EXIT_THIS_PAGE_TRANSLATIONS}\n */\n\n/**\n * Exit this Page translations\n *\n * @typedef {object} ExitThisPageTranslations\n *\n * Messages used by the component programatically inserted text, including\n * overlay text and screen reader announcements.\n * @property {string} [activated] - Screen reader announcement for when EtP\n * keypress functionality has been successfully activated.\n * @property {string} [timedOut] - Screen reader announcement for when the EtP\n * keypress functionality has timed out.\n * @property {string} [pressTwoMoreTimes] - Screen reader announcement informing\n * the user they must press the activation key two more times.\n * @property {string} [pressOneMoreTime] - Screen reader announcement informing\n * the user they must press the activation key one more time.\n */\n"],"names":[],"mappings":"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"}
|
@@ -55,6 +55,10 @@
|
|
55
55
|
"importFrom": "govuk/components/error-summary/macro.njk",
|
56
56
|
"macroName": "govukErrorSummary"
|
57
57
|
},
|
58
|
+
{
|
59
|
+
"importFrom": "govuk/components/exit-this-page/macro.njk",
|
60
|
+
"macroName": "govukExitThisPage"
|
61
|
+
},
|
58
62
|
{
|
59
63
|
"importFrom": "govuk/components/fieldset/macro.njk",
|
60
64
|
"macroName": "govukFieldset"
|
@@ -1,9 +1,10 @@
|
|
1
1
|
{
|
2
2
|
"name": "govuk-frontend",
|
3
3
|
"description": "GOV.UK Frontend contains the code you need to start building a user interface for government platforms and services.",
|
4
|
-
"version": "4.
|
4
|
+
"version": "4.7.0",
|
5
5
|
"main": "govuk/all.js",
|
6
6
|
"module": "govuk-esm/all.mjs",
|
7
|
+
"sass": "govuk/all.scss",
|
7
8
|
"exports": {
|
8
9
|
".": {
|
9
10
|
"sass": "./govuk/all.scss",
|
@@ -11,13 +12,14 @@
|
|
11
12
|
"require": "./govuk/all.js"
|
12
13
|
},
|
13
14
|
"./govuk/": "./govuk/",
|
15
|
+
"./govuk/*": "./govuk/*",
|
14
16
|
"./govuk-esm/": "./govuk-esm/",
|
17
|
+
"./govuk-esm/*": "./govuk-esm/*",
|
15
18
|
"./package.json": "./package.json"
|
16
19
|
},
|
17
20
|
"sideEffects": [
|
18
21
|
"govuk-esm/vendor/**"
|
19
22
|
],
|
20
|
-
"sass": "govuk/all.scss",
|
21
23
|
"engines": {
|
22
24
|
"node": ">= 4.2.0"
|
23
25
|
},
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: govuk_publishing_components
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 35.
|
4
|
+
version: 35.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GOV.UK Dev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-07-
|
11
|
+
date: 2023-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: govuk_app_config
|
@@ -448,6 +448,7 @@ files:
|
|
448
448
|
- app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js
|
449
449
|
- app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-page-views.js
|
450
450
|
- app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-schemas.js
|
451
|
+
- app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-scroll-tracker.js
|
451
452
|
- app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-smart-answer-results-tracker.js
|
452
453
|
- app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-specialist-link-tracker.js
|
453
454
|
- app/assets/javascripts/govuk_publishing_components/analytics-ga4/init-ga4.js
|
@@ -1010,6 +1011,8 @@ files:
|
|
1010
1011
|
- node_modules/govuk-frontend/govuk-esm/components/details/details.mjs.map
|
1011
1012
|
- node_modules/govuk-frontend/govuk-esm/components/error-summary/error-summary.mjs
|
1012
1013
|
- node_modules/govuk-frontend/govuk-esm/components/error-summary/error-summary.mjs.map
|
1014
|
+
- node_modules/govuk-frontend/govuk-esm/components/exit-this-page/exit-this-page.mjs
|
1015
|
+
- node_modules/govuk-frontend/govuk-esm/components/exit-this-page/exit-this-page.mjs.map
|
1013
1016
|
- node_modules/govuk-frontend/govuk-esm/components/header/header.mjs
|
1014
1017
|
- node_modules/govuk-frontend/govuk-esm/components/header/header.mjs.map
|
1015
1018
|
- node_modules/govuk-frontend/govuk-esm/components/notification-banner/notification-banner.mjs
|
@@ -1175,6 +1178,15 @@ files:
|
|
1175
1178
|
- node_modules/govuk-frontend/govuk/components/error-summary/macro-options.json
|
1176
1179
|
- node_modules/govuk-frontend/govuk/components/error-summary/macro.njk
|
1177
1180
|
- node_modules/govuk-frontend/govuk/components/error-summary/template.njk
|
1181
|
+
- node_modules/govuk-frontend/govuk/components/exit-this-page/README.md
|
1182
|
+
- node_modules/govuk-frontend/govuk/components/exit-this-page/_exit-this-page.scss
|
1183
|
+
- node_modules/govuk-frontend/govuk/components/exit-this-page/_index.scss
|
1184
|
+
- node_modules/govuk-frontend/govuk/components/exit-this-page/exit-this-page.js
|
1185
|
+
- node_modules/govuk-frontend/govuk/components/exit-this-page/exit-this-page.js.map
|
1186
|
+
- node_modules/govuk-frontend/govuk/components/exit-this-page/fixtures.json
|
1187
|
+
- node_modules/govuk-frontend/govuk/components/exit-this-page/macro-options.json
|
1188
|
+
- node_modules/govuk-frontend/govuk/components/exit-this-page/macro.njk
|
1189
|
+
- node_modules/govuk-frontend/govuk/components/exit-this-page/template.njk
|
1178
1190
|
- node_modules/govuk-frontend/govuk/components/fieldset/README.md
|
1179
1191
|
- node_modules/govuk-frontend/govuk/components/fieldset/_fieldset.scss
|
1180
1192
|
- node_modules/govuk-frontend/govuk/components/fieldset/_index.scss
|
@@ -1455,7 +1467,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1455
1467
|
- !ruby/object:Gem::Version
|
1456
1468
|
version: '0'
|
1457
1469
|
requirements: []
|
1458
|
-
rubygems_version: 3.4.
|
1470
|
+
rubygems_version: 3.4.17
|
1459
1471
|
signing_key:
|
1460
1472
|
specification_version: 4
|
1461
1473
|
summary: A gem to document components in GOV.UK frontend applications
|