govuk_publishing_components 55.0.1 → 55.1.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/govuk_publishing_components/components/file-upload.js +5 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_layout-super-navigation-header.scss +1 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_organisation-logo.scss +5 -2
- data/app/views/govuk_publishing_components/components/_file_upload.html.erb +13 -1
- data/app/views/govuk_publishing_components/components/_layout_super_navigation_header.html.erb +0 -1
- data/app/views/govuk_publishing_components/components/docs/file_upload.yml +6 -0
- data/app/views/govuk_publishing_components/components/feedback/_survey_signup_form.html.erb +1 -1
- data/lib/govuk_publishing_components/version.rb +1 -1
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +313 -47
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +312 -47
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/all.mjs +2 -1
- data/node_modules/govuk-frontend/dist/govuk/all.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs +21 -16
- data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
- data/node_modules/govuk-frontend/dist/govuk/common/index.mjs +3 -0
- data/node_modules/govuk-frontend/dist/govuk/common/index.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/{govuk-frontend-component.mjs → component.mjs} +5 -5
- data/node_modules/govuk-frontend/dist/govuk/component.mjs.map +1 -0
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +27 -19
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +27 -19
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +27 -19
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +27 -19
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/button/macro-options.json +2 -1
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/_index.scss +8 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/_index.scss.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +28 -20
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +28 -20
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/fixtures.json +16 -1
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/macro-options.json +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/template.njk +5 -4
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +8 -5
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +8 -5
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +27 -19
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +27 -19
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +27 -19
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +27 -19
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/_index.scss +167 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/_index.scss.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js +754 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js.map +1 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs +746 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs.map +1 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs +267 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs.map +1 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/fixtures.json +207 -16
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/macro-options.json +52 -3
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-allows-direct-media-capture.html +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-allows-image-files-only.html +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-allows-multiple-files.html +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-disabled.html +6 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-enhanced-disabled.html +13 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-enhanced-with-error-message-and-hint.html +16 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-enhanced.html +10 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-translated.html +10 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template.njk +42 -5
- data/node_modules/govuk-frontend/dist/govuk/components/header/_index.scss +14 -10
- data/node_modules/govuk-frontend/dist/govuk/components/header/_index.scss.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js +8 -5
- data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs +8 -5
- data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/header/header.mjs +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/header/header.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/header/macro-options.json +25 -12
- data/node_modules/govuk-frontend/dist/govuk/components/input/fixtures.json +16 -2
- data/node_modules/govuk-frontend/dist/govuk/components/input/macro-options.json +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/input/template-default.html +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/input/template.njk +5 -4
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +27 -19
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +27 -19
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/fixtures.json +16 -2
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/macro-options.json +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +27 -20
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +27 -20
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs +1 -2
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/template-default.html +3 -3
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/template.njk +4 -2
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +8 -5
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +8 -5
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.mjs +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/select/fixtures.json +16 -1
- data/node_modules/govuk-frontend/dist/govuk/components/select/macro-options.json +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/select/template-id.html +7 -0
- data/node_modules/govuk-frontend/dist/govuk/components/select/template.njk +6 -4
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +8 -5
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +8 -5
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.mjs +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +9 -6
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +9 -6
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs +3 -3
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/summary-list/_index.scss +12 -21
- data/node_modules/govuk-frontend/dist/govuk/components/summary-list/_index.scss.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/summary-list/fixtures.json +142 -0
- data/node_modules/govuk-frontend/dist/govuk/components/summary-list/template-as-a-summary-card-extreme.html +106 -0
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +8 -5
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +8 -5
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.mjs +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/components/textarea/fixtures.json +15 -1
- data/node_modules/govuk-frontend/dist/govuk/components/textarea/macro-options.json +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/textarea/template.njk +6 -4
- data/node_modules/govuk-frontend/dist/govuk/core/_govuk-frontend-properties.scss +1 -1
- data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs +1 -1
- data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css +2 -2
- data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
- data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss +2 -2
- data/node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/init.mjs +11 -11
- data/node_modules/govuk-frontend/dist/govuk/init.mjs.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss +18 -5
- data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss.map +1 -1
- data/node_modules/govuk-frontend/dist/govuk-prototype-kit/init.scss +1 -1
- data/node_modules/govuk-frontend/dist/govuk-prototype-kit/init.scss.map +1 -1
- data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +1 -1
- data/node_modules/govuk-frontend/package.json +7 -7
- metadata +21 -5
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-with-value.html +0 -6
- data/node_modules/govuk-frontend/dist/govuk/govuk-frontend-component.mjs.map +0 -1
@@ -0,0 +1,746 @@
|
|
1
|
+
function closestAttributeValue($element, attributeName) {
|
2
|
+
const $closestElementWithAttribute = $element.closest(`[${attributeName}]`);
|
3
|
+
return $closestElementWithAttribute ? $closestElementWithAttribute.getAttribute(attributeName) : null;
|
4
|
+
}
|
5
|
+
|
6
|
+
function isInitialised($root, moduleName) {
|
7
|
+
return $root instanceof HTMLElement && $root.hasAttribute(`data-${moduleName}-init`);
|
8
|
+
}
|
9
|
+
|
10
|
+
/**
|
11
|
+
* Checks if GOV.UK Frontend is supported on this page
|
12
|
+
*
|
13
|
+
* Some browsers will load and run our JavaScript but GOV.UK Frontend
|
14
|
+
* won't be supported.
|
15
|
+
*
|
16
|
+
* @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support
|
17
|
+
* @returns {boolean} Whether GOV.UK Frontend is supported on this page
|
18
|
+
*/
|
19
|
+
function isSupported($scope = document.body) {
|
20
|
+
if (!$scope) {
|
21
|
+
return false;
|
22
|
+
}
|
23
|
+
return $scope.classList.contains('govuk-frontend-supported');
|
24
|
+
}
|
25
|
+
function isArray(option) {
|
26
|
+
return Array.isArray(option);
|
27
|
+
}
|
28
|
+
function isObject(option) {
|
29
|
+
return !!option && typeof option === 'object' && !isArray(option);
|
30
|
+
}
|
31
|
+
function formatErrorMessage(Component, message) {
|
32
|
+
return `${Component.moduleName}: ${message}`;
|
33
|
+
}
|
34
|
+
/**
|
35
|
+
* @typedef ComponentWithModuleName
|
36
|
+
* @property {string} moduleName - Name of the component
|
37
|
+
*/
|
38
|
+
/**
|
39
|
+
* @import { ObjectNested } from './configuration.mjs'
|
40
|
+
*/
|
41
|
+
|
42
|
+
class GOVUKFrontendError extends Error {
|
43
|
+
constructor(...args) {
|
44
|
+
super(...args);
|
45
|
+
this.name = 'GOVUKFrontendError';
|
46
|
+
}
|
47
|
+
}
|
48
|
+
class SupportError extends GOVUKFrontendError {
|
49
|
+
/**
|
50
|
+
* Checks if GOV.UK Frontend is supported on this page
|
51
|
+
*
|
52
|
+
* @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
|
53
|
+
*/
|
54
|
+
constructor($scope = document.body) {
|
55
|
+
const supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
|
56
|
+
super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`');
|
57
|
+
this.name = 'SupportError';
|
58
|
+
}
|
59
|
+
}
|
60
|
+
class ConfigError extends GOVUKFrontendError {
|
61
|
+
constructor(...args) {
|
62
|
+
super(...args);
|
63
|
+
this.name = 'ConfigError';
|
64
|
+
}
|
65
|
+
}
|
66
|
+
class ElementError extends GOVUKFrontendError {
|
67
|
+
constructor(messageOrOptions) {
|
68
|
+
let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
|
69
|
+
if (typeof messageOrOptions === 'object') {
|
70
|
+
const {
|
71
|
+
component,
|
72
|
+
identifier,
|
73
|
+
element,
|
74
|
+
expectedType
|
75
|
+
} = messageOrOptions;
|
76
|
+
message = identifier;
|
77
|
+
message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';
|
78
|
+
message = formatErrorMessage(component, message);
|
79
|
+
}
|
80
|
+
super(message);
|
81
|
+
this.name = 'ElementError';
|
82
|
+
}
|
83
|
+
}
|
84
|
+
class InitError extends GOVUKFrontendError {
|
85
|
+
constructor(componentOrMessage) {
|
86
|
+
const message = typeof componentOrMessage === 'string' ? componentOrMessage : formatErrorMessage(componentOrMessage, `Root element (\`$root\`) already initialised`);
|
87
|
+
super(message);
|
88
|
+
this.name = 'InitError';
|
89
|
+
}
|
90
|
+
}
|
91
|
+
/**
|
92
|
+
* @import { ComponentWithModuleName } from '../common/index.mjs'
|
93
|
+
*/
|
94
|
+
|
95
|
+
class Component {
|
96
|
+
/**
|
97
|
+
* Returns the root element of the component
|
98
|
+
*
|
99
|
+
* @protected
|
100
|
+
* @returns {RootElementType} - the root element of component
|
101
|
+
*/
|
102
|
+
get $root() {
|
103
|
+
return this._$root;
|
104
|
+
}
|
105
|
+
constructor($root) {
|
106
|
+
this._$root = void 0;
|
107
|
+
const childConstructor = this.constructor;
|
108
|
+
if (typeof childConstructor.moduleName !== 'string') {
|
109
|
+
throw new InitError(`\`moduleName\` not defined in component`);
|
110
|
+
}
|
111
|
+
if (!($root instanceof childConstructor.elementType)) {
|
112
|
+
throw new ElementError({
|
113
|
+
element: $root,
|
114
|
+
component: childConstructor,
|
115
|
+
identifier: 'Root element (`$root`)',
|
116
|
+
expectedType: childConstructor.elementType.name
|
117
|
+
});
|
118
|
+
} else {
|
119
|
+
this._$root = $root;
|
120
|
+
}
|
121
|
+
childConstructor.checkSupport();
|
122
|
+
this.checkInitialised();
|
123
|
+
const moduleName = childConstructor.moduleName;
|
124
|
+
this.$root.setAttribute(`data-${moduleName}-init`, '');
|
125
|
+
}
|
126
|
+
checkInitialised() {
|
127
|
+
const constructor = this.constructor;
|
128
|
+
const moduleName = constructor.moduleName;
|
129
|
+
if (moduleName && isInitialised(this.$root, moduleName)) {
|
130
|
+
throw new InitError(constructor);
|
131
|
+
}
|
132
|
+
}
|
133
|
+
static checkSupport() {
|
134
|
+
if (!isSupported()) {
|
135
|
+
throw new SupportError();
|
136
|
+
}
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
/**
|
141
|
+
* @typedef ChildClass
|
142
|
+
* @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component
|
143
|
+
*/
|
144
|
+
|
145
|
+
/**
|
146
|
+
* @typedef {typeof Component & ChildClass} ChildClassConstructor
|
147
|
+
*/
|
148
|
+
Component.elementType = HTMLElement;
|
149
|
+
|
150
|
+
const configOverride = Symbol.for('configOverride');
|
151
|
+
class ConfigurableComponent extends Component {
|
152
|
+
[configOverride](param) {
|
153
|
+
return {};
|
154
|
+
}
|
155
|
+
|
156
|
+
/**
|
157
|
+
* Returns the root element of the component
|
158
|
+
*
|
159
|
+
* @protected
|
160
|
+
* @returns {ConfigurationType} - the root element of component
|
161
|
+
*/
|
162
|
+
get config() {
|
163
|
+
return this._config;
|
164
|
+
}
|
165
|
+
constructor($root, config) {
|
166
|
+
super($root);
|
167
|
+
this._config = void 0;
|
168
|
+
const childConstructor = this.constructor;
|
169
|
+
if (!isObject(childConstructor.defaults)) {
|
170
|
+
throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
|
171
|
+
}
|
172
|
+
const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
|
173
|
+
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
|
174
|
+
}
|
175
|
+
}
|
176
|
+
function normaliseString(value, property) {
|
177
|
+
const trimmedValue = value ? value.trim() : '';
|
178
|
+
let output;
|
179
|
+
let outputType = property == null ? void 0 : property.type;
|
180
|
+
if (!outputType) {
|
181
|
+
if (['true', 'false'].includes(trimmedValue)) {
|
182
|
+
outputType = 'boolean';
|
183
|
+
}
|
184
|
+
if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {
|
185
|
+
outputType = 'number';
|
186
|
+
}
|
187
|
+
}
|
188
|
+
switch (outputType) {
|
189
|
+
case 'boolean':
|
190
|
+
output = trimmedValue === 'true';
|
191
|
+
break;
|
192
|
+
case 'number':
|
193
|
+
output = Number(trimmedValue);
|
194
|
+
break;
|
195
|
+
default:
|
196
|
+
output = value;
|
197
|
+
}
|
198
|
+
return output;
|
199
|
+
}
|
200
|
+
function normaliseDataset(Component, dataset) {
|
201
|
+
if (!isObject(Component.schema)) {
|
202
|
+
throw new ConfigError(formatErrorMessage(Component, 'Config passed as parameter into constructor but no schema defined'));
|
203
|
+
}
|
204
|
+
const out = {};
|
205
|
+
const entries = Object.entries(Component.schema.properties);
|
206
|
+
for (const entry of entries) {
|
207
|
+
const [namespace, property] = entry;
|
208
|
+
const field = namespace.toString();
|
209
|
+
if (field in dataset) {
|
210
|
+
out[field] = normaliseString(dataset[field], property);
|
211
|
+
}
|
212
|
+
if ((property == null ? void 0 : property.type) === 'object') {
|
213
|
+
out[field] = extractConfigByNamespace(Component.schema, dataset, namespace);
|
214
|
+
}
|
215
|
+
}
|
216
|
+
return out;
|
217
|
+
}
|
218
|
+
function mergeConfigs(...configObjects) {
|
219
|
+
const formattedConfigObject = {};
|
220
|
+
for (const configObject of configObjects) {
|
221
|
+
for (const key of Object.keys(configObject)) {
|
222
|
+
const option = formattedConfigObject[key];
|
223
|
+
const override = configObject[key];
|
224
|
+
if (isObject(option) && isObject(override)) {
|
225
|
+
formattedConfigObject[key] = mergeConfigs(option, override);
|
226
|
+
} else {
|
227
|
+
formattedConfigObject[key] = override;
|
228
|
+
}
|
229
|
+
}
|
230
|
+
}
|
231
|
+
return formattedConfigObject;
|
232
|
+
}
|
233
|
+
function extractConfigByNamespace(schema, dataset, namespace) {
|
234
|
+
const property = schema.properties[namespace];
|
235
|
+
if ((property == null ? void 0 : property.type) !== 'object') {
|
236
|
+
return;
|
237
|
+
}
|
238
|
+
const newObject = {
|
239
|
+
[namespace]: {}
|
240
|
+
};
|
241
|
+
for (const [key, value] of Object.entries(dataset)) {
|
242
|
+
let current = newObject;
|
243
|
+
const keyParts = key.split('.');
|
244
|
+
for (const [index, name] of keyParts.entries()) {
|
245
|
+
if (isObject(current)) {
|
246
|
+
if (index < keyParts.length - 1) {
|
247
|
+
if (!isObject(current[name])) {
|
248
|
+
current[name] = {};
|
249
|
+
}
|
250
|
+
current = current[name];
|
251
|
+
} else if (key !== namespace) {
|
252
|
+
current[name] = normaliseString(value);
|
253
|
+
}
|
254
|
+
}
|
255
|
+
}
|
256
|
+
}
|
257
|
+
return newObject[namespace];
|
258
|
+
}
|
259
|
+
/**
|
260
|
+
* Schema for component config
|
261
|
+
*
|
262
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType
|
263
|
+
* @typedef {object} Schema
|
264
|
+
* @property {Record<keyof ConfigurationType, SchemaProperty | undefined>} properties - Schema properties
|
265
|
+
* @property {SchemaCondition<ConfigurationType>[]} [anyOf] - List of schema conditions
|
266
|
+
*/
|
267
|
+
/**
|
268
|
+
* Schema property for component config
|
269
|
+
*
|
270
|
+
* @typedef {object} SchemaProperty
|
271
|
+
* @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
|
272
|
+
*/
|
273
|
+
/**
|
274
|
+
* Schema condition for component config
|
275
|
+
*
|
276
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType
|
277
|
+
* @typedef {object} SchemaCondition
|
278
|
+
* @property {(keyof ConfigurationType)[]} required - List of required config fields
|
279
|
+
* @property {string} errorMessage - Error message when required config fields not provided
|
280
|
+
*/
|
281
|
+
/**
|
282
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
|
283
|
+
* @typedef ChildClass
|
284
|
+
* @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component
|
285
|
+
* @property {Schema<ConfigurationType>} [schema] - The schema of the component configuration
|
286
|
+
* @property {ConfigurationType} [defaults] - The default values of the configuration of the component
|
287
|
+
*/
|
288
|
+
/**
|
289
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
|
290
|
+
* @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
|
291
|
+
*/
|
292
|
+
|
293
|
+
class I18n {
|
294
|
+
constructor(translations = {}, config = {}) {
|
295
|
+
var _config$locale;
|
296
|
+
this.translations = void 0;
|
297
|
+
this.locale = void 0;
|
298
|
+
this.translations = translations;
|
299
|
+
this.locale = (_config$locale = config.locale) != null ? _config$locale : document.documentElement.lang || 'en';
|
300
|
+
}
|
301
|
+
t(lookupKey, options) {
|
302
|
+
if (!lookupKey) {
|
303
|
+
throw new Error('i18n: lookup key missing');
|
304
|
+
}
|
305
|
+
let translation = this.translations[lookupKey];
|
306
|
+
if (typeof (options == null ? void 0 : options.count) === 'number' && typeof translation === 'object') {
|
307
|
+
const translationPluralForm = translation[this.getPluralSuffix(lookupKey, options.count)];
|
308
|
+
if (translationPluralForm) {
|
309
|
+
translation = translationPluralForm;
|
310
|
+
}
|
311
|
+
}
|
312
|
+
if (typeof translation === 'string') {
|
313
|
+
if (translation.match(/%{(.\S+)}/)) {
|
314
|
+
if (!options) {
|
315
|
+
throw new Error('i18n: cannot replace placeholders in string if no option data provided');
|
316
|
+
}
|
317
|
+
return this.replacePlaceholders(translation, options);
|
318
|
+
}
|
319
|
+
return translation;
|
320
|
+
}
|
321
|
+
return lookupKey;
|
322
|
+
}
|
323
|
+
replacePlaceholders(translationString, options) {
|
324
|
+
const formatter = Intl.NumberFormat.supportedLocalesOf(this.locale).length ? new Intl.NumberFormat(this.locale) : undefined;
|
325
|
+
return translationString.replace(/%{(.\S+)}/g, function (placeholderWithBraces, placeholderKey) {
|
326
|
+
if (Object.prototype.hasOwnProperty.call(options, placeholderKey)) {
|
327
|
+
const placeholderValue = options[placeholderKey];
|
328
|
+
if (placeholderValue === false || typeof placeholderValue !== 'number' && typeof placeholderValue !== 'string') {
|
329
|
+
return '';
|
330
|
+
}
|
331
|
+
if (typeof placeholderValue === 'number') {
|
332
|
+
return formatter ? formatter.format(placeholderValue) : `${placeholderValue}`;
|
333
|
+
}
|
334
|
+
return placeholderValue;
|
335
|
+
}
|
336
|
+
throw new Error(`i18n: no data found to replace ${placeholderWithBraces} placeholder in string`);
|
337
|
+
});
|
338
|
+
}
|
339
|
+
hasIntlPluralRulesSupport() {
|
340
|
+
return Boolean('PluralRules' in window.Intl && Intl.PluralRules.supportedLocalesOf(this.locale).length);
|
341
|
+
}
|
342
|
+
getPluralSuffix(lookupKey, count) {
|
343
|
+
count = Number(count);
|
344
|
+
if (!isFinite(count)) {
|
345
|
+
return 'other';
|
346
|
+
}
|
347
|
+
const translation = this.translations[lookupKey];
|
348
|
+
const preferredForm = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(count) : this.selectPluralFormUsingFallbackRules(count);
|
349
|
+
if (typeof translation === 'object') {
|
350
|
+
if (preferredForm in translation) {
|
351
|
+
return preferredForm;
|
352
|
+
} else if ('other' in translation) {
|
353
|
+
console.warn(`i18n: Missing plural form ".${preferredForm}" for "${this.locale}" locale. Falling back to ".other".`);
|
354
|
+
return 'other';
|
355
|
+
}
|
356
|
+
}
|
357
|
+
throw new Error(`i18n: Plural form ".other" is required for "${this.locale}" locale`);
|
358
|
+
}
|
359
|
+
selectPluralFormUsingFallbackRules(count) {
|
360
|
+
count = Math.abs(Math.floor(count));
|
361
|
+
const ruleset = this.getPluralRulesForLocale();
|
362
|
+
if (ruleset) {
|
363
|
+
return I18n.pluralRules[ruleset](count);
|
364
|
+
}
|
365
|
+
return 'other';
|
366
|
+
}
|
367
|
+
getPluralRulesForLocale() {
|
368
|
+
const localeShort = this.locale.split('-')[0];
|
369
|
+
for (const pluralRule in I18n.pluralRulesMap) {
|
370
|
+
const languages = I18n.pluralRulesMap[pluralRule];
|
371
|
+
if (languages.includes(this.locale) || languages.includes(localeShort)) {
|
372
|
+
return pluralRule;
|
373
|
+
}
|
374
|
+
}
|
375
|
+
}
|
376
|
+
}
|
377
|
+
I18n.pluralRulesMap = {
|
378
|
+
arabic: ['ar'],
|
379
|
+
chinese: ['my', 'zh', 'id', 'ja', 'jv', 'ko', 'ms', 'th', 'vi'],
|
380
|
+
french: ['hy', 'bn', 'fr', 'gu', 'hi', 'fa', 'pa', 'zu'],
|
381
|
+
german: ['af', 'sq', 'az', 'eu', 'bg', 'ca', 'da', 'nl', 'en', 'et', 'fi', 'ka', 'de', 'el', 'hu', 'lb', 'no', 'so', 'sw', 'sv', 'ta', 'te', 'tr', 'ur'],
|
382
|
+
irish: ['ga'],
|
383
|
+
russian: ['ru', 'uk'],
|
384
|
+
scottish: ['gd'],
|
385
|
+
spanish: ['pt-PT', 'it', 'es'],
|
386
|
+
welsh: ['cy']
|
387
|
+
};
|
388
|
+
I18n.pluralRules = {
|
389
|
+
arabic(n) {
|
390
|
+
if (n === 0) {
|
391
|
+
return 'zero';
|
392
|
+
}
|
393
|
+
if (n === 1) {
|
394
|
+
return 'one';
|
395
|
+
}
|
396
|
+
if (n === 2) {
|
397
|
+
return 'two';
|
398
|
+
}
|
399
|
+
if (n % 100 >= 3 && n % 100 <= 10) {
|
400
|
+
return 'few';
|
401
|
+
}
|
402
|
+
if (n % 100 >= 11 && n % 100 <= 99) {
|
403
|
+
return 'many';
|
404
|
+
}
|
405
|
+
return 'other';
|
406
|
+
},
|
407
|
+
chinese() {
|
408
|
+
return 'other';
|
409
|
+
},
|
410
|
+
french(n) {
|
411
|
+
return n === 0 || n === 1 ? 'one' : 'other';
|
412
|
+
},
|
413
|
+
german(n) {
|
414
|
+
return n === 1 ? 'one' : 'other';
|
415
|
+
},
|
416
|
+
irish(n) {
|
417
|
+
if (n === 1) {
|
418
|
+
return 'one';
|
419
|
+
}
|
420
|
+
if (n === 2) {
|
421
|
+
return 'two';
|
422
|
+
}
|
423
|
+
if (n >= 3 && n <= 6) {
|
424
|
+
return 'few';
|
425
|
+
}
|
426
|
+
if (n >= 7 && n <= 10) {
|
427
|
+
return 'many';
|
428
|
+
}
|
429
|
+
return 'other';
|
430
|
+
},
|
431
|
+
russian(n) {
|
432
|
+
const lastTwo = n % 100;
|
433
|
+
const last = lastTwo % 10;
|
434
|
+
if (last === 1 && lastTwo !== 11) {
|
435
|
+
return 'one';
|
436
|
+
}
|
437
|
+
if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) {
|
438
|
+
return 'few';
|
439
|
+
}
|
440
|
+
if (last === 0 || last >= 5 && last <= 9 || lastTwo >= 11 && lastTwo <= 14) {
|
441
|
+
return 'many';
|
442
|
+
}
|
443
|
+
return 'other';
|
444
|
+
},
|
445
|
+
scottish(n) {
|
446
|
+
if (n === 1 || n === 11) {
|
447
|
+
return 'one';
|
448
|
+
}
|
449
|
+
if (n === 2 || n === 12) {
|
450
|
+
return 'two';
|
451
|
+
}
|
452
|
+
if (n >= 3 && n <= 10 || n >= 13 && n <= 19) {
|
453
|
+
return 'few';
|
454
|
+
}
|
455
|
+
return 'other';
|
456
|
+
},
|
457
|
+
spanish(n) {
|
458
|
+
if (n === 1) {
|
459
|
+
return 'one';
|
460
|
+
}
|
461
|
+
if (n % 1000000 === 0 && n !== 0) {
|
462
|
+
return 'many';
|
463
|
+
}
|
464
|
+
return 'other';
|
465
|
+
},
|
466
|
+
welsh(n) {
|
467
|
+
if (n === 0) {
|
468
|
+
return 'zero';
|
469
|
+
}
|
470
|
+
if (n === 1) {
|
471
|
+
return 'one';
|
472
|
+
}
|
473
|
+
if (n === 2) {
|
474
|
+
return 'two';
|
475
|
+
}
|
476
|
+
if (n === 3) {
|
477
|
+
return 'few';
|
478
|
+
}
|
479
|
+
if (n === 6) {
|
480
|
+
return 'many';
|
481
|
+
}
|
482
|
+
return 'other';
|
483
|
+
}
|
484
|
+
};
|
485
|
+
|
486
|
+
/**
|
487
|
+
* File upload component
|
488
|
+
*
|
489
|
+
* @preserve
|
490
|
+
* @augments ConfigurableComponent<FileUploadConfig>
|
491
|
+
*/
|
492
|
+
class FileUpload extends ConfigurableComponent {
|
493
|
+
/**
|
494
|
+
* @param {Element | null} $root - File input element
|
495
|
+
* @param {FileUploadConfig} [config] - File Upload config
|
496
|
+
*/
|
497
|
+
constructor($root, config = {}) {
|
498
|
+
super($root, config);
|
499
|
+
this.$input = void 0;
|
500
|
+
this.$button = void 0;
|
501
|
+
this.$status = void 0;
|
502
|
+
this.i18n = void 0;
|
503
|
+
this.id = void 0;
|
504
|
+
const $input = this.$root.querySelector('input');
|
505
|
+
if ($input === null) {
|
506
|
+
throw new ElementError({
|
507
|
+
component: FileUpload,
|
508
|
+
identifier: 'File inputs (`<input type="file">`)'
|
509
|
+
});
|
510
|
+
}
|
511
|
+
if ($input.type !== 'file') {
|
512
|
+
throw new ElementError(formatErrorMessage(FileUpload, 'File input (`<input type="file">`) attribute (`type`) is not `file`'));
|
513
|
+
}
|
514
|
+
this.$input = $input;
|
515
|
+
this.$input.setAttribute('hidden', 'true');
|
516
|
+
if (!this.$input.id) {
|
517
|
+
throw new ElementError({
|
518
|
+
component: FileUpload,
|
519
|
+
identifier: 'File input (`<input type="file">`) attribute (`id`)'
|
520
|
+
});
|
521
|
+
}
|
522
|
+
this.id = this.$input.id;
|
523
|
+
this.i18n = new I18n(this.config.i18n, {
|
524
|
+
locale: closestAttributeValue(this.$root, 'lang')
|
525
|
+
});
|
526
|
+
const $label = this.findLabel();
|
527
|
+
if (!$label.id) {
|
528
|
+
$label.id = `${this.id}-label`;
|
529
|
+
}
|
530
|
+
this.$input.id = `${this.id}-input`;
|
531
|
+
const $button = document.createElement('button');
|
532
|
+
$button.classList.add('govuk-file-upload-button');
|
533
|
+
$button.type = 'button';
|
534
|
+
$button.id = this.id;
|
535
|
+
$button.classList.add('govuk-file-upload-button--empty');
|
536
|
+
const ariaDescribedBy = this.$input.getAttribute('aria-describedby');
|
537
|
+
if (ariaDescribedBy) {
|
538
|
+
$button.setAttribute('aria-describedby', ariaDescribedBy);
|
539
|
+
}
|
540
|
+
const $status = document.createElement('span');
|
541
|
+
$status.className = 'govuk-body govuk-file-upload-button__status';
|
542
|
+
$status.setAttribute('aria-live', 'polite');
|
543
|
+
$status.innerText = this.i18n.t('noFileChosen');
|
544
|
+
$button.appendChild($status);
|
545
|
+
const commaSpan = document.createElement('span');
|
546
|
+
commaSpan.className = 'govuk-visually-hidden';
|
547
|
+
commaSpan.innerText = ', ';
|
548
|
+
commaSpan.id = `${this.id}-comma`;
|
549
|
+
$button.appendChild(commaSpan);
|
550
|
+
const containerSpan = document.createElement('span');
|
551
|
+
containerSpan.className = 'govuk-file-upload-button__pseudo-button-container';
|
552
|
+
const buttonSpan = document.createElement('span');
|
553
|
+
buttonSpan.className = 'govuk-button govuk-button--secondary govuk-file-upload-button__pseudo-button';
|
554
|
+
buttonSpan.innerText = this.i18n.t('chooseFilesButton');
|
555
|
+
containerSpan.appendChild(buttonSpan);
|
556
|
+
containerSpan.insertAdjacentText('beforeend', ' ');
|
557
|
+
const instructionSpan = document.createElement('span');
|
558
|
+
instructionSpan.className = 'govuk-body govuk-file-upload-button__instruction';
|
559
|
+
instructionSpan.innerText = this.i18n.t('dropInstruction');
|
560
|
+
containerSpan.appendChild(instructionSpan);
|
561
|
+
$button.appendChild(containerSpan);
|
562
|
+
$button.setAttribute('aria-labelledby', `${$label.id} ${commaSpan.id} ${$button.id}`);
|
563
|
+
$button.addEventListener('click', this.onClick.bind(this));
|
564
|
+
$button.addEventListener('dragover', event => {
|
565
|
+
event.preventDefault();
|
566
|
+
});
|
567
|
+
this.$root.insertAdjacentElement('afterbegin', $button);
|
568
|
+
this.$input.setAttribute('tabindex', '-1');
|
569
|
+
this.$input.setAttribute('aria-hidden', 'true');
|
570
|
+
this.$button = $button;
|
571
|
+
this.$status = $status;
|
572
|
+
this.$input.addEventListener('change', this.onChange.bind(this));
|
573
|
+
this.updateDisabledState();
|
574
|
+
this.observeDisabledState();
|
575
|
+
this.$announcements = document.createElement('span');
|
576
|
+
this.$announcements.classList.add('govuk-file-upload-announcements');
|
577
|
+
this.$announcements.classList.add('govuk-visually-hidden');
|
578
|
+
this.$announcements.setAttribute('aria-live', 'assertive');
|
579
|
+
this.$root.insertAdjacentElement('afterend', this.$announcements);
|
580
|
+
this.$button.addEventListener('drop', this.onDrop.bind(this));
|
581
|
+
document.addEventListener('dragenter', this.updateDropzoneVisibility.bind(this));
|
582
|
+
document.addEventListener('dragenter', () => {
|
583
|
+
this.enteredAnotherElement = true;
|
584
|
+
});
|
585
|
+
document.addEventListener('dragleave', () => {
|
586
|
+
if (!this.enteredAnotherElement && !this.$button.disabled) {
|
587
|
+
this.hideDraggingState();
|
588
|
+
this.$announcements.innerText = this.i18n.t('leftDropZone');
|
589
|
+
}
|
590
|
+
this.enteredAnotherElement = false;
|
591
|
+
});
|
592
|
+
}
|
593
|
+
|
594
|
+
/**
|
595
|
+
* Updates the visibility of the dropzone as users enters the various elements on the page
|
596
|
+
*
|
597
|
+
* @param {DragEvent} event - The `dragenter` event
|
598
|
+
*/
|
599
|
+
updateDropzoneVisibility(event) {
|
600
|
+
if (this.$button.disabled) return;
|
601
|
+
if (event.target instanceof Node) {
|
602
|
+
if (this.$root.contains(event.target)) {
|
603
|
+
if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
|
604
|
+
if (!this.$button.classList.contains('govuk-file-upload-button--dragging')) {
|
605
|
+
this.showDraggingState();
|
606
|
+
this.$announcements.innerText = this.i18n.t('enteredDropZone');
|
607
|
+
}
|
608
|
+
}
|
609
|
+
} else {
|
610
|
+
if (this.$button.classList.contains('govuk-file-upload-button--dragging')) {
|
611
|
+
this.hideDraggingState();
|
612
|
+
this.$announcements.innerText = this.i18n.t('leftDropZone');
|
613
|
+
}
|
614
|
+
}
|
615
|
+
}
|
616
|
+
}
|
617
|
+
showDraggingState() {
|
618
|
+
this.$button.classList.add('govuk-file-upload-button--dragging');
|
619
|
+
}
|
620
|
+
hideDraggingState() {
|
621
|
+
this.$button.classList.remove('govuk-file-upload-button--dragging');
|
622
|
+
}
|
623
|
+
|
624
|
+
/**
|
625
|
+
* Handles user dropping on the component
|
626
|
+
*
|
627
|
+
* @param {DragEvent} event - The `dragenter` event
|
628
|
+
*/
|
629
|
+
onDrop(event) {
|
630
|
+
event.preventDefault();
|
631
|
+
if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
|
632
|
+
this.$input.files = event.dataTransfer.files;
|
633
|
+
this.$input.dispatchEvent(new CustomEvent('change'));
|
634
|
+
this.hideDraggingState();
|
635
|
+
}
|
636
|
+
}
|
637
|
+
onChange() {
|
638
|
+
const fileCount = this.$input.files.length;
|
639
|
+
if (fileCount === 0) {
|
640
|
+
this.$status.innerText = this.i18n.t('noFileChosen');
|
641
|
+
this.$button.classList.add('govuk-file-upload-button--empty');
|
642
|
+
} else {
|
643
|
+
if (fileCount === 1) {
|
644
|
+
this.$status.innerText = this.$input.files[0].name;
|
645
|
+
} else {
|
646
|
+
this.$status.innerText = this.i18n.t('multipleFilesChosen', {
|
647
|
+
count: fileCount
|
648
|
+
});
|
649
|
+
}
|
650
|
+
this.$button.classList.remove('govuk-file-upload-button--empty');
|
651
|
+
}
|
652
|
+
}
|
653
|
+
findLabel() {
|
654
|
+
const $label = document.querySelector(`label[for="${this.$input.id}"]`);
|
655
|
+
if (!$label) {
|
656
|
+
throw new ElementError({
|
657
|
+
component: FileUpload,
|
658
|
+
identifier: `Field label (\`<label for=${this.$input.id}>\`)`
|
659
|
+
});
|
660
|
+
}
|
661
|
+
return $label;
|
662
|
+
}
|
663
|
+
onClick() {
|
664
|
+
this.$input.click();
|
665
|
+
}
|
666
|
+
observeDisabledState() {
|
667
|
+
const observer = new MutationObserver(mutationList => {
|
668
|
+
for (const mutation of mutationList) {
|
669
|
+
if (mutation.type === 'attributes' && mutation.attributeName === 'disabled') {
|
670
|
+
this.updateDisabledState();
|
671
|
+
}
|
672
|
+
}
|
673
|
+
});
|
674
|
+
observer.observe(this.$input, {
|
675
|
+
attributes: true
|
676
|
+
});
|
677
|
+
}
|
678
|
+
updateDisabledState() {
|
679
|
+
this.$button.disabled = this.$input.disabled;
|
680
|
+
this.$root.classList.toggle('govuk-drop-zone--disabled', this.$button.disabled);
|
681
|
+
}
|
682
|
+
}
|
683
|
+
FileUpload.moduleName = 'govuk-file-upload';
|
684
|
+
FileUpload.defaults = Object.freeze({
|
685
|
+
i18n: {
|
686
|
+
chooseFilesButton: 'Choose file',
|
687
|
+
dropInstruction: 'or drop file',
|
688
|
+
noFileChosen: 'No file chosen',
|
689
|
+
multipleFilesChosen: {
|
690
|
+
one: '%{count} file chosen',
|
691
|
+
other: '%{count} files chosen'
|
692
|
+
},
|
693
|
+
enteredDropZone: 'Entered drop zone',
|
694
|
+
leftDropZone: 'Left drop zone'
|
695
|
+
}
|
696
|
+
});
|
697
|
+
FileUpload.schema = Object.freeze({
|
698
|
+
properties: {
|
699
|
+
i18n: {
|
700
|
+
type: 'object'
|
701
|
+
}
|
702
|
+
}
|
703
|
+
});
|
704
|
+
function isContainingFiles(dataTransfer) {
|
705
|
+
const hasNoTypesInfo = dataTransfer.types.length === 0;
|
706
|
+
const isDraggingFiles = dataTransfer.types.some(type => type === 'Files');
|
707
|
+
return hasNoTypesInfo || isDraggingFiles;
|
708
|
+
}
|
709
|
+
|
710
|
+
/**
|
711
|
+
* @typedef {HTMLInputElement & {files: FileList}} HTMLFileInputElement
|
712
|
+
*/
|
713
|
+
|
714
|
+
/**
|
715
|
+
* File upload config
|
716
|
+
*
|
717
|
+
* @see {@link FileUpload.defaults}
|
718
|
+
* @typedef {object} FileUploadConfig
|
719
|
+
* @property {FileUploadTranslations} [i18n=FileUpload.defaults.i18n] - File upload translations
|
720
|
+
*/
|
721
|
+
|
722
|
+
/**
|
723
|
+
* File upload translations
|
724
|
+
*
|
725
|
+
* @see {@link FileUpload.defaults.i18n}
|
726
|
+
* @typedef {object} FileUploadTranslations
|
727
|
+
*
|
728
|
+
* Messages used by the component
|
729
|
+
* @property {string} [chooseFile] - The text of the button that opens the file picker
|
730
|
+
* @property {string} [dropInstruction] - The text informing users they can drop files
|
731
|
+
* @property {TranslationPluralForms} [multipleFilesChosen] - The text displayed when multiple files
|
732
|
+
* have been chosen by the user
|
733
|
+
* @property {string} [noFileChosen] - The text to displayed when no file has been chosen by the user
|
734
|
+
* @property {string} [enteredDropZone] - The text announced by assistive technology
|
735
|
+
* when user drags files and enters the drop zone
|
736
|
+
* @property {string} [leftDropZone] - The text announced by assistive technology
|
737
|
+
* when user drags files and leaves the drop zone without dropping
|
738
|
+
*/
|
739
|
+
|
740
|
+
/**
|
741
|
+
* @import { Schema } from '../../common/configuration.mjs'
|
742
|
+
* @import { TranslationPluralForms } from '../../i18n.mjs'
|
743
|
+
*/
|
744
|
+
|
745
|
+
export { FileUpload };
|
746
|
+
//# sourceMappingURL=file-upload.bundle.mjs.map
|