@ministryofjustice/frontend 5.0.0 → 5.1.1
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.
- package/moj/all.bundle.js +1598 -1062
- package/moj/all.bundle.js.map +1 -1
- package/moj/all.bundle.mjs +1894 -1054
- package/moj/all.bundle.mjs.map +1 -1
- package/moj/all.mjs +7 -90
- package/moj/all.mjs.map +1 -1
- package/moj/all.scss +1 -0
- package/moj/all.scss.map +1 -1
- package/moj/common/index.mjs +57 -0
- package/moj/common/index.mjs.map +1 -0
- package/moj/common/moj-frontend-version.mjs +14 -0
- package/moj/common/moj-frontend-version.mjs.map +1 -0
- package/moj/components/add-another/add-another.bundle.js +105 -76
- package/moj/components/add-another/add-another.bundle.js.map +1 -1
- package/moj/components/add-another/add-another.bundle.mjs +222 -71
- package/moj/components/add-another/add-another.bundle.mjs.map +1 -1
- package/moj/components/add-another/add-another.mjs +103 -72
- package/moj/components/add-another/add-another.mjs.map +1 -1
- package/moj/components/alert/alert.bundle.js +115 -191
- package/moj/components/alert/alert.bundle.js.map +1 -1
- package/moj/components/alert/alert.bundle.mjs +354 -186
- package/moj/components/alert/alert.bundle.mjs.map +1 -1
- package/moj/components/alert/alert.mjs +55 -140
- package/moj/components/alert/alert.mjs.map +1 -1
- package/moj/components/button-menu/README.md +3 -1
- package/moj/components/button-menu/button-menu.bundle.js +91 -120
- package/moj/components/button-menu/button-menu.bundle.js.map +1 -1
- package/moj/components/button-menu/button-menu.bundle.mjs +329 -114
- package/moj/components/button-menu/button-menu.bundle.mjs.map +1 -1
- package/moj/components/button-menu/button-menu.mjs +89 -116
- package/moj/components/button-menu/button-menu.mjs.map +1 -1
- package/moj/components/date-picker/date-picker.bundle.js +174 -154
- package/moj/components/date-picker/date-picker.bundle.js.map +1 -1
- package/moj/components/date-picker/date-picker.bundle.mjs +411 -147
- package/moj/components/date-picker/date-picker.bundle.mjs.map +1 -1
- package/moj/components/date-picker/date-picker.mjs +172 -150
- package/moj/components/date-picker/date-picker.mjs.map +1 -1
- package/moj/components/filter/template.njk +1 -1
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js +133 -44
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js.map +1 -1
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs +374 -41
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs.map +1 -1
- package/moj/components/filter-toggle-button/filter-toggle-button.mjs +131 -40
- package/moj/components/filter-toggle-button/filter-toggle-button.mjs.map +1 -1
- package/moj/components/form-validator/form-validator.bundle.js +159 -69
- package/moj/components/form-validator/form-validator.bundle.js.map +1 -1
- package/moj/components/form-validator/form-validator.bundle.mjs +399 -65
- package/moj/components/form-validator/form-validator.bundle.mjs.map +1 -1
- package/moj/components/form-validator/form-validator.mjs +134 -54
- package/moj/components/form-validator/form-validator.mjs.map +1 -1
- package/moj/components/multi-file-upload/multi-file-upload.bundle.js +291 -117
- package/moj/components/multi-file-upload/multi-file-upload.bundle.js.map +1 -1
- package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs +527 -109
- package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs.map +1 -1
- package/moj/components/multi-file-upload/multi-file-upload.mjs +288 -101
- package/moj/components/multi-file-upload/multi-file-upload.mjs.map +1 -1
- package/moj/components/multi-file-upload/template.njk +1 -1
- package/moj/components/multi-select/multi-select.bundle.js +106 -41
- package/moj/components/multi-select/multi-select.bundle.js.map +1 -1
- package/moj/components/multi-select/multi-select.bundle.mjs +346 -37
- package/moj/components/multi-select/multi-select.bundle.mjs.map +1 -1
- package/moj/components/multi-select/multi-select.mjs +104 -37
- package/moj/components/multi-select/multi-select.mjs.map +1 -1
- package/moj/components/password-reveal/_password-reveal.scss +3 -1
- package/moj/components/password-reveal/_password-reveal.scss.map +1 -1
- package/moj/components/password-reveal/password-reveal.bundle.js +32 -29
- package/moj/components/password-reveal/password-reveal.bundle.js.map +1 -1
- package/moj/components/password-reveal/password-reveal.bundle.mjs +149 -24
- package/moj/components/password-reveal/password-reveal.bundle.mjs.map +1 -1
- package/moj/components/password-reveal/password-reveal.mjs +30 -25
- package/moj/components/password-reveal/password-reveal.mjs.map +1 -1
- package/moj/components/rich-text-editor/README.md +4 -3
- package/moj/components/rich-text-editor/rich-text-editor.bundle.js +127 -62
- package/moj/components/rich-text-editor/rich-text-editor.bundle.js.map +1 -1
- package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs +367 -58
- package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs.map +1 -1
- package/moj/components/rich-text-editor/rich-text-editor.mjs +125 -58
- package/moj/components/rich-text-editor/rich-text-editor.mjs.map +1 -1
- package/moj/components/search-toggle/search-toggle.bundle.js +94 -26
- package/moj/components/search-toggle/search-toggle.bundle.js.map +1 -1
- package/moj/components/search-toggle/search-toggle.bundle.mjs +334 -22
- package/moj/components/search-toggle/search-toggle.bundle.mjs.map +1 -1
- package/moj/components/search-toggle/search-toggle.mjs +92 -22
- package/moj/components/search-toggle/search-toggle.mjs.map +1 -1
- package/moj/components/sortable-table/_sortable-table.scss +3 -42
- package/moj/components/sortable-table/_sortable-table.scss.map +1 -1
- package/moj/components/sortable-table/sortable-table.bundle.js +200 -83
- package/moj/components/sortable-table/sortable-table.bundle.js.map +1 -1
- package/moj/components/sortable-table/sortable-table.bundle.mjs +439 -78
- package/moj/components/sortable-table/sortable-table.bundle.mjs.map +1 -1
- package/moj/components/sortable-table/sortable-table.mjs +198 -79
- package/moj/components/sortable-table/sortable-table.mjs.map +1 -1
- package/moj/core/_all.scss +3 -0
- package/moj/core/_all.scss.map +1 -0
- package/moj/core/_moj-frontend-properties.scss +7 -0
- package/moj/core/_moj-frontend-properties.scss.map +1 -0
- package/moj/filters/prototype-kit-13-filters.js +4 -3
- package/moj/helpers.bundle.js +22 -77
- package/moj/helpers.bundle.js.map +1 -1
- package/moj/helpers.bundle.mjs +23 -74
- package/moj/helpers.bundle.mjs.map +1 -1
- package/moj/helpers.mjs +23 -74
- package/moj/helpers.mjs.map +1 -1
- package/moj/moj-frontend.min.css +1 -1
- package/moj/moj-frontend.min.css.map +1 -1
- package/moj/moj-frontend.min.js +1 -1
- package/moj/moj-frontend.min.js.map +1 -1
- package/package.json +1 -1
- package/moj/version.bundle.js +0 -12
- package/moj/version.bundle.js.map +0 -1
- package/moj/version.bundle.mjs +0 -4
- package/moj/version.bundle.mjs.map +0 -1
- package/moj/version.mjs +0 -4
- package/moj/version.mjs.map +0 -1
|
@@ -1,32 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { ConfigurableComponent } from 'govuk-frontend';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @augments {ConfigurableComponent<FilterToggleButtonConfig>}
|
|
5
|
+
*/
|
|
6
|
+
class FilterToggleButton extends ConfigurableComponent {
|
|
7
|
+
/**
|
|
8
|
+
* @param {Element | null} $root - HTML element to use for filter toggle button
|
|
9
|
+
* @param {FilterToggleButtonConfig} [config] - Filter toggle button config
|
|
10
|
+
*/
|
|
11
|
+
constructor($root, config = {}) {
|
|
12
|
+
var _this$config$toggleBu, _this$config$closeBut;
|
|
13
|
+
super($root, config);
|
|
14
|
+
const $toggleButtonContainer = (_this$config$toggleBu = this.config.toggleButtonContainer.element) != null ? _this$config$toggleBu : document.querySelector(this.config.toggleButtonContainer.selector);
|
|
15
|
+
const $closeButtonContainer = (_this$config$closeBut = this.config.closeButtonContainer.element) != null ? _this$config$closeBut : this.$root.querySelector(this.config.closeButtonContainer.selector);
|
|
16
|
+
if (!($toggleButtonContainer instanceof HTMLElement && $closeButtonContainer instanceof HTMLElement)) {
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
this.$toggleButtonContainer = $toggleButtonContainer;
|
|
20
|
+
this.$closeButtonContainer = $closeButtonContainer;
|
|
6
21
|
this.createToggleButton();
|
|
7
22
|
this.setupResponsiveChecks();
|
|
8
|
-
this.
|
|
9
|
-
if (this.
|
|
23
|
+
this.$root.setAttribute('tabindex', '-1');
|
|
24
|
+
if (this.config.startHidden) {
|
|
10
25
|
this.hideMenu();
|
|
11
26
|
}
|
|
12
27
|
}
|
|
13
28
|
setupResponsiveChecks() {
|
|
14
|
-
this.mq = window.matchMedia(this.
|
|
29
|
+
this.mq = window.matchMedia(this.config.bigModeMediaQuery);
|
|
15
30
|
this.mq.addListener(this.checkMode.bind(this));
|
|
16
|
-
this.checkMode(
|
|
31
|
+
this.checkMode();
|
|
17
32
|
}
|
|
18
33
|
createToggleButton() {
|
|
19
|
-
this
|
|
20
|
-
this
|
|
21
|
-
this
|
|
22
|
-
this
|
|
23
|
-
this
|
|
24
|
-
this
|
|
25
|
-
this
|
|
26
|
-
this.
|
|
34
|
+
this.$menuButton = document.createElement('button');
|
|
35
|
+
this.$menuButton.setAttribute('type', 'button');
|
|
36
|
+
this.$menuButton.setAttribute('aria-haspopup', 'true');
|
|
37
|
+
this.$menuButton.setAttribute('aria-expanded', 'false');
|
|
38
|
+
this.$menuButton.className = `govuk-button ${this.config.toggleButton.classes}`;
|
|
39
|
+
this.$menuButton.textContent = this.config.toggleButton.showText;
|
|
40
|
+
this.$menuButton.addEventListener('click', this.onMenuButtonClick.bind(this));
|
|
41
|
+
this.$toggleButtonContainer.append(this.$menuButton);
|
|
27
42
|
}
|
|
28
|
-
checkMode(
|
|
29
|
-
if (mq.matches) {
|
|
43
|
+
checkMode() {
|
|
44
|
+
if (this.mq.matches) {
|
|
30
45
|
this.enableBigMode();
|
|
31
46
|
} else {
|
|
32
47
|
this.enableSmallMode();
|
|
@@ -41,48 +56,124 @@ class FilterToggleButton {
|
|
|
41
56
|
this.addCloseButton();
|
|
42
57
|
}
|
|
43
58
|
addCloseButton() {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
this.
|
|
48
|
-
this
|
|
49
|
-
this.closeButton
|
|
50
|
-
this.closeButton.textContent = this.options.closeButton.text;
|
|
51
|
-
this.closeButton.addEventListener('click', this.onCloseClick.bind(this));
|
|
52
|
-
this.options.closeButton.container.append(this.closeButton);
|
|
59
|
+
this.$closeButton = document.createElement('button');
|
|
60
|
+
this.$closeButton.setAttribute('type', 'button');
|
|
61
|
+
this.$closeButton.className = this.config.closeButton.classes;
|
|
62
|
+
this.$closeButton.textContent = this.config.closeButton.text;
|
|
63
|
+
this.$closeButton.addEventListener('click', this.onCloseClick.bind(this));
|
|
64
|
+
this.$closeButtonContainer.append(this.$closeButton);
|
|
53
65
|
}
|
|
54
66
|
onCloseClick() {
|
|
55
67
|
this.hideMenu();
|
|
56
|
-
this
|
|
68
|
+
this.$menuButton.focus();
|
|
57
69
|
}
|
|
58
70
|
removeCloseButton() {
|
|
59
|
-
if (this
|
|
60
|
-
this
|
|
61
|
-
this
|
|
71
|
+
if (this.$closeButton) {
|
|
72
|
+
this.$closeButton.remove();
|
|
73
|
+
this.$closeButton = null;
|
|
62
74
|
}
|
|
63
75
|
}
|
|
64
76
|
hideMenu() {
|
|
65
|
-
this
|
|
66
|
-
this.
|
|
67
|
-
this
|
|
77
|
+
this.$menuButton.setAttribute('aria-expanded', 'false');
|
|
78
|
+
this.$root.classList.add('moj-js-hidden');
|
|
79
|
+
this.$menuButton.textContent = this.config.toggleButton.showText;
|
|
68
80
|
}
|
|
69
81
|
showMenu() {
|
|
70
|
-
this
|
|
71
|
-
this.
|
|
72
|
-
this
|
|
82
|
+
this.$menuButton.setAttribute('aria-expanded', 'true');
|
|
83
|
+
this.$root.classList.remove('moj-js-hidden');
|
|
84
|
+
this.$menuButton.textContent = this.config.toggleButton.hideText;
|
|
73
85
|
}
|
|
74
86
|
onMenuButtonClick() {
|
|
75
87
|
this.toggle();
|
|
76
88
|
}
|
|
77
89
|
toggle() {
|
|
78
|
-
if (this
|
|
90
|
+
if (this.$menuButton.getAttribute('aria-expanded') === 'false') {
|
|
79
91
|
this.showMenu();
|
|
80
|
-
this.
|
|
92
|
+
this.$root.focus();
|
|
81
93
|
} else {
|
|
82
94
|
this.hideMenu();
|
|
83
95
|
}
|
|
84
96
|
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Name for the component used when initialising using data-module attributes.
|
|
100
|
+
*/
|
|
85
101
|
}
|
|
86
102
|
|
|
103
|
+
/**
|
|
104
|
+
* @typedef {object} FilterToggleButtonConfig
|
|
105
|
+
* @property {string} [bigModeMediaQuery] - Media query for big mode
|
|
106
|
+
* @property {boolean} [startHidden] - Whether to start hidden
|
|
107
|
+
* @property {object} [toggleButton] - Toggle button config
|
|
108
|
+
* @property {string} [toggleButton.showText] - Text for show button
|
|
109
|
+
* @property {string} [toggleButton.hideText] - Text for hide button
|
|
110
|
+
* @property {string} [toggleButton.classes] - Classes for toggle button
|
|
111
|
+
* @property {object} [toggleButtonContainer] - Toggle button container config
|
|
112
|
+
* @property {string} [toggleButtonContainer.selector] - Selector for toggle button container
|
|
113
|
+
* @property {Element | null} [toggleButtonContainer.element] - HTML element for toggle button container
|
|
114
|
+
* @property {object} [closeButton] - Close button config
|
|
115
|
+
* @property {string} [closeButton.text] - Text for close button
|
|
116
|
+
* @property {string} [closeButton.classes] - Classes for close button
|
|
117
|
+
* @property {object} [closeButtonContainer] - Close button container config
|
|
118
|
+
* @property {string} [closeButtonContainer.selector] - Selector for close button container
|
|
119
|
+
* @property {Element | null} [closeButtonContainer.element] - HTML element for close button container
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
|
|
124
|
+
*/
|
|
125
|
+
FilterToggleButton.moduleName = 'moj-filter';
|
|
126
|
+
/**
|
|
127
|
+
* Filter toggle button config
|
|
128
|
+
*
|
|
129
|
+
* @type {FilterToggleButtonConfig}
|
|
130
|
+
*/
|
|
131
|
+
FilterToggleButton.defaults = Object.freeze({
|
|
132
|
+
bigModeMediaQuery: '(min-width: 48.0625em)',
|
|
133
|
+
startHidden: true,
|
|
134
|
+
toggleButton: {
|
|
135
|
+
showText: 'Show filter',
|
|
136
|
+
hideText: 'Hide filter',
|
|
137
|
+
classes: 'govuk-button--secondary'
|
|
138
|
+
},
|
|
139
|
+
toggleButtonContainer: {
|
|
140
|
+
selector: '.moj-action-bar__filter'
|
|
141
|
+
},
|
|
142
|
+
closeButton: {
|
|
143
|
+
text: 'Close',
|
|
144
|
+
classes: 'moj-filter__close'
|
|
145
|
+
},
|
|
146
|
+
closeButtonContainer: {
|
|
147
|
+
selector: '.moj-filter__header-action'
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
/**
|
|
151
|
+
* Filter toggle button config schema
|
|
152
|
+
*
|
|
153
|
+
* @satisfies {Schema<FilterToggleButtonConfig>}
|
|
154
|
+
*/
|
|
155
|
+
FilterToggleButton.schema = Object.freeze(/** @type {const} */{
|
|
156
|
+
properties: {
|
|
157
|
+
bigModeMediaQuery: {
|
|
158
|
+
type: 'string'
|
|
159
|
+
},
|
|
160
|
+
startHidden: {
|
|
161
|
+
type: 'boolean'
|
|
162
|
+
},
|
|
163
|
+
toggleButton: {
|
|
164
|
+
type: 'object'
|
|
165
|
+
},
|
|
166
|
+
toggleButtonContainer: {
|
|
167
|
+
type: 'object'
|
|
168
|
+
},
|
|
169
|
+
closeButton: {
|
|
170
|
+
type: 'object'
|
|
171
|
+
},
|
|
172
|
+
closeButtonContainer: {
|
|
173
|
+
type: 'object'
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
87
178
|
export { FilterToggleButton };
|
|
88
179
|
//# sourceMappingURL=filter-toggle-button.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter-toggle-button.mjs","sources":["../../../../src/moj/components/filter-toggle-button/filter-toggle-button.mjs"],"sourcesContent":["export class FilterToggleButton {\n constructor(options) {\n this.options = options\n this.container = this.options.toggleButton.container\n this.filterContainer = this.options.filter.container\n\n this.createToggleButton()\n this.setupResponsiveChecks()\n this.filterContainer.setAttribute('tabindex', '-1')\n if (this.options.startHidden) {\n this.hideMenu()\n }\n }\n\n setupResponsiveChecks() {\n this.mq = window.matchMedia(this.options.bigModeMediaQuery)\n this.mq.addListener(this.checkMode.bind(this))\n this.checkMode(this.mq)\n }\n\n createToggleButton() {\n this.menuButton = document.createElement('button')\n this.menuButton.setAttribute('type', 'button')\n this.menuButton.setAttribute('aria-haspopup', 'true')\n this.menuButton.setAttribute('aria-expanded', 'false')\n\n this.menuButton.className = `govuk-button ${this.options.toggleButton.classes}`\n this.menuButton.textContent = this.options.toggleButton.showText\n\n this.menuButton.addEventListener('click', this.onMenuButtonClick.bind(this))\n this.container.append(this.menuButton)\n }\n\n checkMode(mq) {\n if (mq.matches) {\n this.enableBigMode()\n } else {\n this.enableSmallMode()\n }\n }\n\n enableBigMode() {\n this.showMenu()\n this.removeCloseButton()\n }\n\n enableSmallMode() {\n this.hideMenu()\n this.addCloseButton()\n }\n\n addCloseButton() {\n if (!this.options.closeButton) {\n return\n }\n\n this.closeButton = document.createElement('button')\n this.closeButton.setAttribute('type', 'button')\n\n this.closeButton.className = 'moj-filter__close'\n this.closeButton.textContent = this.options.closeButton.text\n\n this.closeButton.addEventListener('click', this.onCloseClick.bind(this))\n this.options.closeButton.container.append(this.closeButton)\n }\n\n onCloseClick() {\n this.hideMenu()\n this.menuButton.focus()\n }\n\n removeCloseButton() {\n if (this.closeButton) {\n this.closeButton.remove()\n this.closeButton = null\n }\n }\n\n hideMenu() {\n this.menuButton.setAttribute('aria-expanded', 'false')\n this.filterContainer.classList.add('moj-js-hidden')\n this.menuButton.textContent = this.options.toggleButton.showText\n }\n\n showMenu() {\n this.menuButton.setAttribute('aria-expanded', 'true')\n this.filterContainer.classList.remove('moj-js-hidden')\n this.menuButton.textContent = this.options.toggleButton.hideText\n }\n\n onMenuButtonClick() {\n this.toggle()\n }\n\n toggle() {\n if (this.menuButton.getAttribute('aria-expanded') === 'false') {\n this.showMenu()\n this.filterContainer.focus()\n } else {\n this.hideMenu()\n }\n }\n}\n"],"names":["FilterToggleButton","constructor","options","container","toggleButton","filterContainer","filter","createToggleButton","setupResponsiveChecks","setAttribute","startHidden","hideMenu","mq","window","matchMedia","bigModeMediaQuery","addListener","checkMode","bind","menuButton","document","createElement","className","classes","textContent","showText","addEventListener","onMenuButtonClick","append","matches","enableBigMode","enableSmallMode","showMenu","removeCloseButton","addCloseButton","closeButton","text","onCloseClick","focus","remove","classList","add","hideText","toggle","getAttribute"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"filter-toggle-button.mjs","sources":["../../../../src/moj/components/filter-toggle-button/filter-toggle-button.mjs"],"sourcesContent":["import { ConfigurableComponent } from 'govuk-frontend'\n\n/**\n * @augments {ConfigurableComponent<FilterToggleButtonConfig>}\n */\nexport class FilterToggleButton extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for filter toggle button\n * @param {FilterToggleButtonConfig} [config] - Filter toggle button config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n const $toggleButtonContainer =\n this.config.toggleButtonContainer.element ??\n document.querySelector(this.config.toggleButtonContainer.selector)\n\n const $closeButtonContainer =\n this.config.closeButtonContainer.element ??\n this.$root.querySelector(this.config.closeButtonContainer.selector)\n\n if (\n !(\n $toggleButtonContainer instanceof HTMLElement &&\n $closeButtonContainer instanceof HTMLElement\n )\n ) {\n return this\n }\n\n this.$toggleButtonContainer = $toggleButtonContainer\n this.$closeButtonContainer = $closeButtonContainer\n\n this.createToggleButton()\n this.setupResponsiveChecks()\n\n this.$root.setAttribute('tabindex', '-1')\n\n if (this.config.startHidden) {\n this.hideMenu()\n }\n }\n\n setupResponsiveChecks() {\n this.mq = window.matchMedia(this.config.bigModeMediaQuery)\n this.mq.addListener(this.checkMode.bind(this))\n this.checkMode()\n }\n\n createToggleButton() {\n this.$menuButton = document.createElement('button')\n this.$menuButton.setAttribute('type', 'button')\n this.$menuButton.setAttribute('aria-haspopup', 'true')\n this.$menuButton.setAttribute('aria-expanded', 'false')\n\n this.$menuButton.className = `govuk-button ${this.config.toggleButton.classes}`\n this.$menuButton.textContent = this.config.toggleButton.showText\n\n this.$menuButton.addEventListener(\n 'click',\n this.onMenuButtonClick.bind(this)\n )\n\n this.$toggleButtonContainer.append(this.$menuButton)\n }\n\n checkMode() {\n if (this.mq.matches) {\n this.enableBigMode()\n } else {\n this.enableSmallMode()\n }\n }\n\n enableBigMode() {\n this.showMenu()\n this.removeCloseButton()\n }\n\n enableSmallMode() {\n this.hideMenu()\n this.addCloseButton()\n }\n\n addCloseButton() {\n this.$closeButton = document.createElement('button')\n this.$closeButton.setAttribute('type', 'button')\n\n this.$closeButton.className = this.config.closeButton.classes\n this.$closeButton.textContent = this.config.closeButton.text\n\n this.$closeButton.addEventListener('click', this.onCloseClick.bind(this))\n this.$closeButtonContainer.append(this.$closeButton)\n }\n\n onCloseClick() {\n this.hideMenu()\n this.$menuButton.focus()\n }\n\n removeCloseButton() {\n if (this.$closeButton) {\n this.$closeButton.remove()\n this.$closeButton = null\n }\n }\n\n hideMenu() {\n this.$menuButton.setAttribute('aria-expanded', 'false')\n this.$root.classList.add('moj-js-hidden')\n this.$menuButton.textContent = this.config.toggleButton.showText\n }\n\n showMenu() {\n this.$menuButton.setAttribute('aria-expanded', 'true')\n this.$root.classList.remove('moj-js-hidden')\n this.$menuButton.textContent = this.config.toggleButton.hideText\n }\n\n onMenuButtonClick() {\n this.toggle()\n }\n\n toggle() {\n if (this.$menuButton.getAttribute('aria-expanded') === 'false') {\n this.showMenu()\n this.$root.focus()\n } else {\n this.hideMenu()\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'moj-filter'\n\n /**\n * Filter toggle button config\n *\n * @type {FilterToggleButtonConfig}\n */\n static defaults = Object.freeze({\n bigModeMediaQuery: '(min-width: 48.0625em)',\n startHidden: true,\n toggleButton: {\n showText: 'Show filter',\n hideText: 'Hide filter',\n classes: 'govuk-button--secondary'\n },\n toggleButtonContainer: {\n selector: '.moj-action-bar__filter'\n },\n closeButton: {\n text: 'Close',\n classes: 'moj-filter__close'\n },\n closeButtonContainer: {\n selector: '.moj-filter__header-action'\n }\n })\n\n /**\n * Filter toggle button config schema\n *\n * @satisfies {Schema<FilterToggleButtonConfig>}\n */\n static schema = Object.freeze(\n /** @type {const} */ ({\n properties: {\n bigModeMediaQuery: { type: 'string' },\n startHidden: { type: 'boolean' },\n toggleButton: { type: 'object' },\n toggleButtonContainer: { type: 'object' },\n closeButton: { type: 'object' },\n closeButtonContainer: { type: 'object' }\n }\n })\n )\n}\n\n/**\n * @typedef {object} FilterToggleButtonConfig\n * @property {string} [bigModeMediaQuery] - Media query for big mode\n * @property {boolean} [startHidden] - Whether to start hidden\n * @property {object} [toggleButton] - Toggle button config\n * @property {string} [toggleButton.showText] - Text for show button\n * @property {string} [toggleButton.hideText] - Text for hide button\n * @property {string} [toggleButton.classes] - Classes for toggle button\n * @property {object} [toggleButtonContainer] - Toggle button container config\n * @property {string} [toggleButtonContainer.selector] - Selector for toggle button container\n * @property {Element | null} [toggleButtonContainer.element] - HTML element for toggle button container\n * @property {object} [closeButton] - Close button config\n * @property {string} [closeButton.text] - Text for close button\n * @property {string} [closeButton.classes] - Classes for close button\n * @property {object} [closeButtonContainer] - Close button container config\n * @property {string} [closeButtonContainer.selector] - Selector for close button container\n * @property {Element | null} [closeButtonContainer.element] - HTML element for close button container\n */\n\n/**\n * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'\n */\n"],"names":["FilterToggleButton","ConfigurableComponent","constructor","$root","config","_this$config$toggleBu","_this$config$closeBut","$toggleButtonContainer","toggleButtonContainer","element","document","querySelector","selector","$closeButtonContainer","closeButtonContainer","HTMLElement","createToggleButton","setupResponsiveChecks","setAttribute","startHidden","hideMenu","mq","window","matchMedia","bigModeMediaQuery","addListener","checkMode","bind","$menuButton","createElement","className","toggleButton","classes","textContent","showText","addEventListener","onMenuButtonClick","append","matches","enableBigMode","enableSmallMode","showMenu","removeCloseButton","addCloseButton","$closeButton","closeButton","text","onCloseClick","focus","remove","classList","add","hideText","toggle","getAttribute","moduleName","defaults","Object","freeze","schema","properties","type"],"mappings":"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"}
|
|
@@ -1,55 +1,68 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MOJFrontend = global.MOJFrontend || {}));
|
|
5
|
-
})(this, (function (exports) { 'use strict';
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('govuk-frontend')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'govuk-frontend'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MOJFrontend = global.MOJFrontend || {}, global.GOVUKFrontend));
|
|
5
|
+
})(this, (function (exports, govukFrontend) { 'use strict';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @param {Element} $element - Element to remove attribute value from
|
|
9
|
+
* @param {string} attr - Attribute name
|
|
10
|
+
* @param {string} value - Attribute value
|
|
11
|
+
*/
|
|
12
|
+
function removeAttributeValue($element, attr, value) {
|
|
8
13
|
let re, m;
|
|
9
|
-
if (
|
|
10
|
-
if (
|
|
11
|
-
|
|
14
|
+
if ($element.getAttribute(attr)) {
|
|
15
|
+
if ($element.getAttribute(attr) === value) {
|
|
16
|
+
$element.removeAttribute(attr);
|
|
12
17
|
} else {
|
|
13
18
|
re = new RegExp(`(^|\\s)${value}(\\s|$)`);
|
|
14
|
-
m =
|
|
19
|
+
m = $element.getAttribute(attr).match(re);
|
|
15
20
|
if (m && m.length === 3) {
|
|
16
|
-
|
|
21
|
+
$element.setAttribute(attr, $element.getAttribute(attr).replace(re, m[1] && m[2] ? ' ' : ''));
|
|
17
22
|
}
|
|
18
23
|
}
|
|
19
24
|
}
|
|
20
25
|
}
|
|
21
|
-
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {Element} $element - Element to add attribute value to
|
|
29
|
+
* @param {string} attr - Attribute name
|
|
30
|
+
* @param {string} value - Attribute value
|
|
31
|
+
*/
|
|
32
|
+
function addAttributeValue($element, attr, value) {
|
|
22
33
|
let re;
|
|
23
|
-
if (
|
|
24
|
-
|
|
34
|
+
if (!$element.getAttribute(attr)) {
|
|
35
|
+
$element.setAttribute(attr, value);
|
|
25
36
|
} else {
|
|
26
37
|
re = new RegExp(`(^|\\s)${value}(\\s|$)`);
|
|
27
|
-
if (!re.test(
|
|
28
|
-
|
|
38
|
+
if (!re.test($element.getAttribute(attr))) {
|
|
39
|
+
$element.setAttribute(attr, `${$element.getAttribute(attr)} ${value}`);
|
|
29
40
|
}
|
|
30
41
|
}
|
|
31
42
|
}
|
|
32
43
|
|
|
33
|
-
|
|
44
|
+
/**
|
|
45
|
+
* @augments {ConfigurableComponent<FormValidatorConfig, HTMLFormElement>}
|
|
46
|
+
*/
|
|
47
|
+
class FormValidator extends govukFrontend.ConfigurableComponent {
|
|
34
48
|
/**
|
|
35
|
-
* @param {Element | null}
|
|
36
|
-
* @param {FormValidatorConfig} [config] -
|
|
49
|
+
* @param {Element | null} $root - HTML element to use for form validator
|
|
50
|
+
* @param {FormValidatorConfig} [config] - Form validator config
|
|
37
51
|
*/
|
|
38
|
-
constructor(
|
|
39
|
-
|
|
52
|
+
constructor($root, config = {}) {
|
|
53
|
+
super($root, config);
|
|
54
|
+
const $summary = this.config.summary.element || document.querySelector(this.config.summary.selector);
|
|
55
|
+
if (!$summary || !($summary instanceof HTMLElement)) {
|
|
40
56
|
return this;
|
|
41
57
|
}
|
|
42
|
-
this
|
|
43
|
-
this.errors = [];
|
|
44
|
-
this.validators = [];
|
|
45
|
-
this.form.addEventListener('submit', this.onSubmit.bind(this));
|
|
46
|
-
this.summary = config.summary || document.querySelector('.govuk-error-summary');
|
|
58
|
+
this.$summary = $summary;
|
|
59
|
+
this.errors = /** @type {ValidationError[]} */[];
|
|
60
|
+
this.validators = /** @type {Validator[]} */[];
|
|
47
61
|
this.originalTitle = document.title;
|
|
62
|
+
this.$root.addEventListener('submit', this.onSubmit.bind(this));
|
|
48
63
|
}
|
|
49
|
-
escapeHtml(string) {
|
|
50
|
-
return String(string).replace(/[&<>"'`=/]/g,
|
|
51
|
-
return FormValidator.entityMap[s];
|
|
52
|
-
});
|
|
64
|
+
escapeHtml(string = '') {
|
|
65
|
+
return String(string).replace(/[&<>"'`=/]/g, name => FormValidator.entityMap[name]);
|
|
53
66
|
}
|
|
54
67
|
resetTitle() {
|
|
55
68
|
document.title = this.originalTitle;
|
|
@@ -58,10 +71,10 @@
|
|
|
58
71
|
document.title = `${this.errors.length} errors - ${document.title}`;
|
|
59
72
|
}
|
|
60
73
|
showSummary() {
|
|
61
|
-
this
|
|
62
|
-
this
|
|
63
|
-
this
|
|
64
|
-
this
|
|
74
|
+
this.$summary.innerHTML = this.getSummaryHtml();
|
|
75
|
+
this.$summary.classList.remove('moj-hidden');
|
|
76
|
+
this.$summary.setAttribute('aria-labelledby', 'errorSummary-heading');
|
|
77
|
+
this.$summary.focus();
|
|
65
78
|
}
|
|
66
79
|
getSummaryHtml() {
|
|
67
80
|
let html = '<h2 id="error-summary-title" class="govuk-error-summary__title">There is a problem</h2>';
|
|
@@ -79,9 +92,13 @@
|
|
|
79
92
|
return html;
|
|
80
93
|
}
|
|
81
94
|
hideSummary() {
|
|
82
|
-
this
|
|
83
|
-
this
|
|
95
|
+
this.$summary.classList.add('moj-hidden');
|
|
96
|
+
this.$summary.removeAttribute('aria-labelledby');
|
|
84
97
|
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @param {SubmitEvent} event - Form submit event
|
|
101
|
+
*/
|
|
85
102
|
onSubmit(event) {
|
|
86
103
|
this.removeInlineErrors();
|
|
87
104
|
this.hideSummary();
|
|
@@ -98,25 +115,29 @@
|
|
|
98
115
|
this.showInlineError(error);
|
|
99
116
|
}
|
|
100
117
|
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @param {ValidationError} error
|
|
121
|
+
*/
|
|
101
122
|
showInlineError(error) {
|
|
102
|
-
const errorSpan = document.createElement('span');
|
|
103
|
-
errorSpan.id = `${error.fieldName}-error`;
|
|
104
|
-
errorSpan.classList.add('govuk-error-message');
|
|
105
|
-
errorSpan.innerHTML = this.escapeHtml(error.message);
|
|
106
|
-
const control = document.querySelector(`#${error.fieldName}`);
|
|
107
|
-
const fieldset = control.closest('.govuk-fieldset');
|
|
108
|
-
const fieldContainer = (fieldset || control).closest('.govuk-form-group');
|
|
109
|
-
const label = fieldContainer.querySelector('label');
|
|
110
|
-
const legend = fieldContainer.querySelector('legend');
|
|
111
|
-
fieldContainer.classList.add('govuk-form-group--error');
|
|
112
|
-
if (fieldset && legend) {
|
|
113
|
-
legend.after(errorSpan);
|
|
114
|
-
fieldContainer.setAttribute('aria-invalid', 'true');
|
|
115
|
-
addAttributeValue(fieldset, 'aria-describedby', errorSpan.id);
|
|
116
|
-
} else if (label && control) {
|
|
117
|
-
label.after(errorSpan);
|
|
118
|
-
control.setAttribute('aria-invalid', 'true');
|
|
119
|
-
addAttributeValue(control, 'aria-describedby', errorSpan.id);
|
|
123
|
+
const $errorSpan = document.createElement('span');
|
|
124
|
+
$errorSpan.id = `${error.fieldName}-error`;
|
|
125
|
+
$errorSpan.classList.add('govuk-error-message');
|
|
126
|
+
$errorSpan.innerHTML = this.escapeHtml(error.message);
|
|
127
|
+
const $control = document.querySelector(`#${error.fieldName}`);
|
|
128
|
+
const $fieldset = $control.closest('.govuk-fieldset');
|
|
129
|
+
const $fieldContainer = ($fieldset || $control).closest('.govuk-form-group');
|
|
130
|
+
const $label = $fieldContainer.querySelector('label');
|
|
131
|
+
const $legend = $fieldContainer.querySelector('legend');
|
|
132
|
+
$fieldContainer.classList.add('govuk-form-group--error');
|
|
133
|
+
if ($fieldset && $legend) {
|
|
134
|
+
$legend.after($errorSpan);
|
|
135
|
+
$fieldContainer.setAttribute('aria-invalid', 'true');
|
|
136
|
+
addAttributeValue($fieldset, 'aria-describedby', $errorSpan.id);
|
|
137
|
+
} else if ($label && $control) {
|
|
138
|
+
$label.after($errorSpan);
|
|
139
|
+
$control.setAttribute('aria-invalid', 'true');
|
|
140
|
+
addAttributeValue($control, 'aria-describedby', $errorSpan.id);
|
|
120
141
|
}
|
|
121
142
|
}
|
|
122
143
|
removeInlineErrors() {
|
|
@@ -124,33 +145,46 @@
|
|
|
124
145
|
this.removeInlineError(error);
|
|
125
146
|
}
|
|
126
147
|
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @param {ValidationError} error
|
|
151
|
+
*/
|
|
127
152
|
removeInlineError(error) {
|
|
128
|
-
const errorSpan = document.querySelector(`#${error.fieldName}-error`);
|
|
129
|
-
const control = document.querySelector(`#${error.fieldName}`);
|
|
130
|
-
const fieldset = control.closest('.govuk-fieldset');
|
|
131
|
-
const fieldContainer = (fieldset || control).closest('.govuk-form-group');
|
|
132
|
-
const label = fieldContainer.querySelector('label');
|
|
133
|
-
const legend = fieldContainer.querySelector('legend');
|
|
134
|
-
errorSpan.remove();
|
|
135
|
-
fieldContainer.classList.remove('govuk-form-group--error');
|
|
136
|
-
if (fieldset && legend) {
|
|
137
|
-
fieldContainer.removeAttribute('aria-invalid');
|
|
138
|
-
removeAttributeValue(fieldset, 'aria-describedby', errorSpan.id);
|
|
139
|
-
} else if (label && control) {
|
|
140
|
-
control.removeAttribute('aria-invalid');
|
|
141
|
-
removeAttributeValue(control, 'aria-describedby', errorSpan.id);
|
|
153
|
+
const $errorSpan = document.querySelector(`#${error.fieldName}-error`);
|
|
154
|
+
const $control = document.querySelector(`#${error.fieldName}`);
|
|
155
|
+
const $fieldset = $control.closest('.govuk-fieldset');
|
|
156
|
+
const $fieldContainer = ($fieldset || $control).closest('.govuk-form-group');
|
|
157
|
+
const $label = $fieldContainer.querySelector('label');
|
|
158
|
+
const $legend = $fieldContainer.querySelector('legend');
|
|
159
|
+
$errorSpan.remove();
|
|
160
|
+
$fieldContainer.classList.remove('govuk-form-group--error');
|
|
161
|
+
if ($fieldset && $legend) {
|
|
162
|
+
$fieldContainer.removeAttribute('aria-invalid');
|
|
163
|
+
removeAttributeValue($fieldset, 'aria-describedby', $errorSpan.id);
|
|
164
|
+
} else if ($label && $control) {
|
|
165
|
+
$control.removeAttribute('aria-invalid');
|
|
166
|
+
removeAttributeValue($control, 'aria-describedby', $errorSpan.id);
|
|
142
167
|
}
|
|
143
168
|
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @param {string} fieldName - Field name
|
|
172
|
+
* @param {ValidationRule[]} rules - Validation rules
|
|
173
|
+
*/
|
|
144
174
|
addValidator(fieldName, rules) {
|
|
145
175
|
this.validators.push({
|
|
146
176
|
fieldName,
|
|
147
177
|
rules,
|
|
148
|
-
field: this.
|
|
178
|
+
field: this.$root.elements.namedItem(fieldName)
|
|
149
179
|
});
|
|
150
180
|
}
|
|
151
181
|
validate() {
|
|
152
182
|
this.errors = [];
|
|
183
|
+
|
|
184
|
+
/** @type {Validator | null} */
|
|
153
185
|
let validator = null;
|
|
186
|
+
|
|
187
|
+
/** @type {boolean | string} */
|
|
154
188
|
let validatorReturnValue = true;
|
|
155
189
|
let i;
|
|
156
190
|
let j;
|
|
@@ -175,11 +209,41 @@
|
|
|
175
209
|
}
|
|
176
210
|
return this.errors.length === 0;
|
|
177
211
|
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* @type {Record<string, string>}
|
|
215
|
+
*/
|
|
178
216
|
}
|
|
179
217
|
|
|
180
218
|
/**
|
|
181
219
|
* @typedef {object} FormValidatorConfig
|
|
182
|
-
* @property {
|
|
220
|
+
* @property {object} [summary] - Error summary config
|
|
221
|
+
* @property {string} [summary.selector] - Selector for error summary
|
|
222
|
+
* @property {Element | null} [summary.element] - HTML element for error summary
|
|
223
|
+
*/
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* @typedef {object} ValidationRule
|
|
227
|
+
* @property {(field: Validator['field'], params: Record<string, Validator['field']>) => boolean | string} method - Validation method
|
|
228
|
+
* @property {string} message - Error message
|
|
229
|
+
* @property {Record<string, Validator['field']>} [params] - Parameters for validation
|
|
230
|
+
*/
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @typedef {object} ValidationError
|
|
234
|
+
* @property {string} fieldName - Name of the field
|
|
235
|
+
* @property {string} message - Validation error message
|
|
236
|
+
*/
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @typedef {object} Validator
|
|
240
|
+
* @property {string} fieldName - Name of the field
|
|
241
|
+
* @property {ValidationRule[]} rules - Validation rules
|
|
242
|
+
* @property {Element | RadioNodeList} field - Form field
|
|
243
|
+
*/
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
|
|
183
247
|
*/
|
|
184
248
|
FormValidator.entityMap = {
|
|
185
249
|
'&': '&',
|
|
@@ -191,6 +255,32 @@
|
|
|
191
255
|
'`': '`',
|
|
192
256
|
'=': '='
|
|
193
257
|
};
|
|
258
|
+
/**
|
|
259
|
+
* Name for the component used when initialising using data-module attributes.
|
|
260
|
+
*/
|
|
261
|
+
FormValidator.moduleName = 'moj-form-validator';
|
|
262
|
+
/**
|
|
263
|
+
* Multi file upload default config
|
|
264
|
+
*
|
|
265
|
+
* @type {FormValidatorConfig}
|
|
266
|
+
*/
|
|
267
|
+
FormValidator.defaults = Object.freeze({
|
|
268
|
+
summary: {
|
|
269
|
+
selector: '.govuk-error-summary'
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
/**
|
|
273
|
+
* Multi file upload config schema
|
|
274
|
+
*
|
|
275
|
+
* @satisfies {Schema<FormValidatorConfig>}
|
|
276
|
+
*/
|
|
277
|
+
FormValidator.schema = Object.freeze(/** @type {const} */{
|
|
278
|
+
properties: {
|
|
279
|
+
summary: {
|
|
280
|
+
type: 'object'
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
});
|
|
194
284
|
|
|
195
285
|
exports.FormValidator = FormValidator;
|
|
196
286
|
|