@ministryofjustice/frontend 3.5.0 → 3.6.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.
Files changed (36) hide show
  1. package/moj/all.jquery.js +13378 -0
  2. package/moj/all.jquery.min.js +1 -81
  3. package/moj/all.js +2577 -2853
  4. package/moj/all.mjs +126 -0
  5. package/moj/components/add-another/add-another.js +111 -132
  6. package/moj/components/add-another/add-another.mjs +106 -0
  7. package/moj/components/alert/alert.js +352 -479
  8. package/moj/components/alert/alert.mjs +251 -0
  9. package/moj/components/alert/alert.spec.helper.js +6 -24
  10. package/moj/components/alert/alert.spec.helper.mjs +66 -0
  11. package/moj/components/button-menu/button-menu.js +326 -343
  12. package/moj/components/button-menu/button-menu.mjs +329 -0
  13. package/moj/components/date-picker/date-picker.js +905 -922
  14. package/moj/components/date-picker/date-picker.mjs +961 -0
  15. package/moj/components/filter-toggle-button/filter-toggle-button.js +98 -119
  16. package/moj/components/filter-toggle-button/filter-toggle-button.mjs +93 -0
  17. package/moj/components/form-validator/form-validator.js +201 -396
  18. package/moj/components/form-validator/form-validator.mjs +168 -0
  19. package/moj/components/multi-file-upload/multi-file-upload.js +227 -441
  20. package/moj/components/multi-file-upload/multi-file-upload.mjs +219 -0
  21. package/moj/components/multi-select/multi-select.js +82 -103
  22. package/moj/components/multi-select/multi-select.mjs +77 -0
  23. package/moj/components/password-reveal/password-reveal.js +40 -61
  24. package/moj/components/password-reveal/password-reveal.mjs +35 -0
  25. package/moj/components/rich-text-editor/rich-text-editor.js +162 -183
  26. package/moj/components/rich-text-editor/rich-text-editor.mjs +157 -0
  27. package/moj/components/search-toggle/search-toggle.js +52 -73
  28. package/moj/components/search-toggle/search-toggle.mjs +54 -0
  29. package/moj/components/sortable-table/sortable-table.js +143 -164
  30. package/moj/components/sortable-table/sortable-table.mjs +138 -0
  31. package/moj/helpers.js +196 -215
  32. package/moj/helpers.mjs +123 -0
  33. package/moj/moj-frontend.min.js +1 -81
  34. package/moj/version.js +6 -23
  35. package/moj/version.mjs +3 -0
  36. package/package.json +13 -1
@@ -1,399 +1,204 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define(factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.MOJFrontend = factory());
5
- })(this, (function () { 'use strict';
6
-
7
- function getDefaultExportFromCjs (x) {
8
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
9
- }
10
-
11
- var _global_window_jQuery = window.jQuery;
12
-
13
- var helpers;
14
- var hasRequiredHelpers;
15
-
16
- function requireHelpers () {
17
- if (hasRequiredHelpers) return helpers;
18
- hasRequiredHelpers = 1;
19
- function removeAttributeValue(el, attr, value) {
20
- let re, m;
21
- if (el.getAttribute(attr)) {
22
- if (el.getAttribute(attr) === value) {
23
- el.removeAttribute(attr);
24
- } else {
25
- re = new RegExp(`(^|\\s)${value}(\\s|$)`);
26
- m = el.getAttribute(attr).match(re);
27
- if (m && m.length === 3) {
28
- el.setAttribute(
29
- attr,
30
- el.getAttribute(attr).replace(re, m[1] && m[2] ? ' ' : '')
31
- );
32
- }
33
- }
34
- }
35
- }
36
-
37
- function addAttributeValue(el, attr, value) {
38
- let re;
39
- if (!el.getAttribute(attr)) {
40
- el.setAttribute(attr, value);
41
- } else {
42
- re = new RegExp(`(^|\\s)${value}(\\s|$)`);
43
- if (!re.test(el.getAttribute(attr))) {
44
- el.setAttribute(attr, `${el.getAttribute(attr)} ${value}`);
45
- }
46
- }
47
- }
48
-
49
- function dragAndDropSupported() {
50
- const div = document.createElement('div');
51
- return typeof div.ondrop !== 'undefined'
52
- }
53
-
54
- function formDataSupported() {
55
- return typeof FormData === 'function'
56
- }
57
-
58
- function fileApiSupported() {
59
- const input = document.createElement('input');
60
- input.type = 'file';
61
- return typeof input.files !== 'undefined'
62
- }
63
-
64
- function nodeListForEach(nodes, callback) {
65
- if (window.NodeList.prototype.forEach) {
66
- return nodes.forEach(callback)
67
- }
68
- for (let i = 0; i < nodes.length; i++) {
69
- callback.call(window, nodes[i], i, nodes);
70
- }
71
- }
72
-
73
- /**
74
- * Find an elements next sibling
75
- *
76
- * Utility function to find an elements next sibling matching the provided
77
- * selector.
78
- *
79
- * @param {HTMLElement} $element - Element to find siblings for
80
- * @param {string} selector - selector for required sibling
81
- */
82
- function getNextSibling($element, selector) {
83
- if (!$element) return
84
- // Get the next sibling element
85
- let $sibling = $element.nextElementSibling;
86
-
87
- // If there's no selector, return the first sibling
88
- if (!selector) return $sibling
89
-
90
- // If the sibling matches our selector, use it
91
- // If not, jump to the next sibling and continue the loop
92
- while ($sibling) {
93
- if ($sibling.matches(selector)) return $sibling
94
- $sibling = $sibling.nextElementSibling;
95
- }
96
- }
97
-
98
- /**
99
- * Find an elements preceding sibling
100
- *
101
- * Utility function to find an elements previous sibling matching the provided
102
- * selector.
103
- *
104
- * @param {HTMLElement} $element - Element to find siblings for
105
- * @param {string} selector - selector for required sibling
106
- */
107
- function getPreviousSibling($element, selector) {
108
- if (!$element) return
109
- // Get the previous sibling element
110
- let $sibling = $element.previousElementSibling;
111
-
112
- // If there's no selector, return the first sibling
113
- if (!selector) return $sibling
114
-
115
- // If the sibling matches our selector, use it
116
- // If not, jump to the next sibling and continue the loop
117
- while ($sibling) {
118
- if ($sibling.matches(selector)) return $sibling
119
- $sibling = $sibling.previousElementSibling;
120
- }
121
- }
122
-
123
- function findNearestMatchingElement($element, selector) {
124
- // If no element or selector is provided, return null
125
- if (!$element) return
126
- if (!selector) return
127
-
128
- // Start with the current element
129
- let $currentElement = $element;
130
-
131
- while ($currentElement) {
132
- // First check the current element
133
- if ($currentElement.matches(selector)) {
134
- return $currentElement
135
- }
136
-
137
- // Check all previous siblings
138
- let $sibling = $currentElement.previousElementSibling;
139
- while ($sibling) {
140
- // Check if the sibling itself is a heading
141
- if ($sibling.matches(selector)) {
142
- return $sibling
143
- }
144
- $sibling = $sibling.previousElementSibling;
145
- }
146
-
147
- // If no match found in siblings, move up to parent
148
- $currentElement = $currentElement.parentElement;
149
- }
150
- }
151
-
152
- /**
153
- * Move focus to element
154
- *
155
- * Sets tabindex to -1 to make the element programmatically focusable,
156
- * but removes it on blur as the element doesn't need to be focused again.
157
- *
158
- * @param {HTMLElement} $element - HTML element
159
- * @param {object} [options] - Handler options
160
- * @param {function(this: HTMLElement): void} [options.onBeforeFocus] - Callback before focus
161
- * @param {function(this: HTMLElement): void} [options.onBlur] - Callback on blur
162
- */
163
- function setFocus($element, options = {}) {
164
- const isFocusable = $element.getAttribute('tabindex');
165
-
166
- if (!isFocusable) {
167
- $element.setAttribute('tabindex', '-1');
168
- }
169
-
170
- /**
171
- * Handle element focus
172
- */
173
- function onFocus() {
174
- $element.addEventListener('blur', onBlur, { once: true });
175
- }
176
-
177
- /**
178
- * Handle element blur
179
- */
180
- function onBlur() {
181
- if (options.onBlur) {
182
- options.onBlur.call($element);
183
- }
184
-
185
- if (!isFocusable) {
186
- $element.removeAttribute('tabindex');
187
- }
188
- }
189
-
190
- // Add listener to reset element on blur, after focus
191
- $element.addEventListener('focus', onFocus, { once: true });
192
-
193
- // Focus element
194
- if (options.onBeforeFocus) {
195
- options.onBeforeFocus.call($element);
196
- }
197
- $element.focus();
198
- }
199
-
200
- helpers = {
201
- removeAttributeValue,
202
- addAttributeValue,
203
- dragAndDropSupported,
204
- formDataSupported,
205
- fileApiSupported,
206
- nodeListForEach,
207
- getNextSibling,
208
- getPreviousSibling,
209
- findNearestMatchingElement,
210
- setFocus
211
- };
212
- return helpers;
213
- }
214
-
215
- var formValidator$1;
216
- var hasRequiredFormValidator;
217
-
218
- function requireFormValidator () {
219
- if (hasRequiredFormValidator) return formValidator$1;
220
- hasRequiredFormValidator = 1;
221
- const $ = _global_window_jQuery;
222
-
223
- const { addAttributeValue, removeAttributeValue } = requireHelpers();
224
-
225
- function FormValidator(form, options) {
226
- this.form = form;
227
- this.errors = [];
228
- this.validators = [];
229
- $(this.form).on('submit', $.proxy(this, 'onSubmit'));
230
- this.summary =
231
- options && options.summary ? $(options.summary) : $('.govuk-error-summary');
232
- this.originalTitle = document.title;
233
- }
234
-
235
- FormValidator.entityMap = {
236
- '&': '&amp;',
237
- '<': '&lt;',
238
- '>': '&gt;',
239
- '"': '&quot;',
240
- "'": '&#39;',
241
- '/': '&#x2F;',
242
- '`': '&#x60;',
243
- '=': '&#x3D;'
244
- };
245
-
246
- FormValidator.prototype.escapeHtml = function (string) {
247
- return String(string).replace(/[&<>"'`=/]/g, function fromEntityMap(s) {
248
- return FormValidator.entityMap[s]
249
- })
250
- };
251
-
252
- FormValidator.prototype.resetTitle = function () {
253
- document.title = this.originalTitle;
254
- };
255
-
256
- FormValidator.prototype.updateTitle = function () {
257
- document.title = `${this.errors.length} errors - ${document.title}`;
258
- };
259
-
260
- FormValidator.prototype.showSummary = function () {
261
- this.summary.html(this.getSummaryHtml());
262
- this.summary.removeClass('moj-hidden');
263
- this.summary.attr('aria-labelledby', 'errorSummary-heading');
264
- this.summary.focus();
265
- };
266
-
267
- FormValidator.prototype.getSummaryHtml = function () {
268
- let html =
269
- '<h2 id="error-summary-title" class="govuk-error-summary__title">There is a problem</h2>';
270
- html += '<div class="govuk-error-summary__body">';
271
- html += '<ul class="govuk-list govuk-error-summary__list">';
272
- for (let i = 0, j = this.errors.length; i < j; i++) {
273
- const error = this.errors[i];
274
- html += '<li>';
275
- html += `<a href="#${this.escapeHtml(error.fieldName)}">`;
276
- html += this.escapeHtml(error.message);
277
- html += '</a>';
278
- html += '</li>';
279
- }
280
- html += '</ul>';
281
- html += '</div>';
282
- return html
283
- };
284
-
285
- FormValidator.prototype.hideSummary = function () {
286
- this.summary.addClass('moj-hidden');
287
- this.summary.removeAttr('aria-labelledby');
288
- };
289
-
290
- FormValidator.prototype.onSubmit = function (e) {
291
- this.removeInlineErrors();
292
- this.hideSummary();
293
- this.resetTitle();
294
- if (!this.validate()) {
295
- e.preventDefault();
296
- this.updateTitle();
297
- this.showSummary();
298
- this.showInlineErrors();
299
- }
300
- };
301
-
302
- FormValidator.prototype.showInlineErrors = function () {
303
- for (let i = 0, j = this.errors.length; i < j; i++) {
304
- this.showInlineError(this.errors[i]);
305
- }
306
- };
307
-
308
- FormValidator.prototype.showInlineError = function (error) {
309
- const errorSpanId = `${error.fieldName}-error`;
310
- const errorSpan = `<span class="govuk-error-message" id="${
311
- errorSpanId
312
- }">${this.escapeHtml(error.message)}</span>`;
313
- const control = $(`#${error.fieldName}`);
314
- const fieldContainer = control.parents('.govuk-form-group');
315
- const label = fieldContainer.find('label');
316
- const legend = fieldContainer.find('legend');
317
- const fieldset = fieldContainer.find('fieldset');
318
- fieldContainer.addClass('govuk-form-group--error');
319
- if (legend.length) {
320
- legend.after(errorSpan);
321
- fieldContainer.attr('aria-invalid', 'true');
322
- addAttributeValue(fieldset[0], 'aria-describedby', errorSpanId);
323
- } else {
324
- label.after(errorSpan);
325
- control.attr('aria-invalid', 'true');
326
- addAttributeValue(control[0], 'aria-describedby', errorSpanId);
327
- }
328
- };
329
-
330
- FormValidator.prototype.removeInlineErrors = function () {
331
- for (let i = 0; i < this.errors.length; i++) {
332
- this.removeInlineError(this.errors[i]);
333
- }
334
- };
335
-
336
- FormValidator.prototype.removeInlineError = function (error) {
337
- const control = $(`#${error.fieldName}`);
338
- const fieldContainer = control.parents('.govuk-form-group');
339
- fieldContainer.find('.govuk-error-message').remove();
340
- fieldContainer.removeClass('govuk-form-group--error');
341
- fieldContainer.find('[aria-invalid]').attr('aria-invalid', 'false');
342
- const errorSpanId = `${error.fieldName}-error`;
343
- removeAttributeValue(
344
- fieldContainer.find('[aria-describedby]')[0],
345
- 'aria-describedby',
346
- errorSpanId
347
- );
348
- };
349
-
350
- FormValidator.prototype.addValidator = function (fieldName, rules) {
351
- this.validators.push({
352
- fieldName,
353
- rules,
354
- field: this.form.elements[fieldName]
355
- });
356
- };
357
-
358
- FormValidator.prototype.validate = function () {
359
- this.errors = [];
360
- let validator = null;
361
- let validatorReturnValue = true;
362
- let i;
363
- let j;
364
- for (i = 0; i < this.validators.length; i++) {
365
- validator = this.validators[i];
366
- for (j = 0; j < validator.rules.length; j++) {
367
- validatorReturnValue = validator.rules[j].method(
368
- validator.field,
369
- validator.rules[j].params
370
- );
371
-
372
- if (typeof validatorReturnValue === 'boolean' && !validatorReturnValue) {
373
- this.errors.push({
374
- fieldName: validator.fieldName,
375
- message: validator.rules[j].message
376
- });
377
- break
378
- } else if (typeof validatorReturnValue === 'string') {
379
- this.errors.push({
380
- fieldName: validatorReturnValue,
381
- message: validator.rules[j].message
382
- });
383
- break
384
- }
385
- }
386
- }
387
- return this.errors.length === 0
388
- };
389
-
390
- formValidator$1 = { FormValidator };
391
- return formValidator$1;
392
- }
393
-
394
- var formValidatorExports = requireFormValidator();
395
- var formValidator = /*@__PURE__*/getDefaultExportFromCjs(formValidatorExports);
396
-
397
- return formValidator;
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';
6
+
7
+ function removeAttributeValue(el, attr, value) {
8
+ let re, m;
9
+ if (el.getAttribute(attr)) {
10
+ if (el.getAttribute(attr) === value) {
11
+ el.removeAttribute(attr);
12
+ } else {
13
+ re = new RegExp(`(^|\\s)${value}(\\s|$)`);
14
+ m = el.getAttribute(attr).match(re);
15
+ if (m && m.length === 3) {
16
+ el.setAttribute(
17
+ attr,
18
+ el.getAttribute(attr).replace(re, m[1] && m[2] ? ' ' : '')
19
+ );
20
+ }
21
+ }
22
+ }
23
+ }
24
+
25
+ function addAttributeValue(el, attr, value) {
26
+ let re;
27
+ if (!el.getAttribute(attr)) {
28
+ el.setAttribute(attr, value);
29
+ } else {
30
+ re = new RegExp(`(^|\\s)${value}(\\s|$)`);
31
+ if (!re.test(el.getAttribute(attr))) {
32
+ el.setAttribute(attr, `${el.getAttribute(attr)} ${value}`);
33
+ }
34
+ }
35
+ }
36
+
37
+ function FormValidator(form, options) {
38
+ this.form = form;
39
+ this.errors = [];
40
+ this.validators = [];
41
+ window.jQuery(this.form).on('submit', window.jQuery.proxy(this, 'onSubmit'));
42
+ this.summary =
43
+ options && options.summary ? window.jQuery(options.summary) : window.jQuery('.govuk-error-summary');
44
+ this.originalTitle = document.title;
45
+ }
46
+
47
+ FormValidator.entityMap = {
48
+ '&': '&amp;',
49
+ '<': '&lt;',
50
+ '>': '&gt;',
51
+ '"': '&quot;',
52
+ "'": '&#39;',
53
+ '/': '&#x2F;',
54
+ '`': '&#x60;',
55
+ '=': '&#x3D;'
56
+ };
57
+
58
+ FormValidator.prototype.escapeHtml = function (string) {
59
+ return String(string).replace(/[&<>"'`=/]/g, function fromEntityMap(s) {
60
+ return FormValidator.entityMap[s]
61
+ })
62
+ };
63
+
64
+ FormValidator.prototype.resetTitle = function () {
65
+ document.title = this.originalTitle;
66
+ };
67
+
68
+ FormValidator.prototype.updateTitle = function () {
69
+ document.title = `${this.errors.length} errors - ${document.title}`;
70
+ };
71
+
72
+ FormValidator.prototype.showSummary = function () {
73
+ this.summary.html(this.getSummaryHtml());
74
+ this.summary.removeClass('moj-hidden');
75
+ this.summary.attr('aria-labelledby', 'errorSummary-heading');
76
+ this.summary.focus();
77
+ };
78
+
79
+ FormValidator.prototype.getSummaryHtml = function () {
80
+ let html =
81
+ '<h2 id="error-summary-title" class="govuk-error-summary__title">There is a problem</h2>';
82
+ html += '<div class="govuk-error-summary__body">';
83
+ html += '<ul class="govuk-list govuk-error-summary__list">';
84
+ for (let i = 0, j = this.errors.length; i < j; i++) {
85
+ const error = this.errors[i];
86
+ html += '<li>';
87
+ html += `<a href="#${this.escapeHtml(error.fieldName)}">`;
88
+ html += this.escapeHtml(error.message);
89
+ html += '</a>';
90
+ html += '</li>';
91
+ }
92
+ html += '</ul>';
93
+ html += '</div>';
94
+ return html
95
+ };
96
+
97
+ FormValidator.prototype.hideSummary = function () {
98
+ this.summary.addClass('moj-hidden');
99
+ this.summary.removeAttr('aria-labelledby');
100
+ };
101
+
102
+ FormValidator.prototype.onSubmit = function (e) {
103
+ this.removeInlineErrors();
104
+ this.hideSummary();
105
+ this.resetTitle();
106
+ if (!this.validate()) {
107
+ e.preventDefault();
108
+ this.updateTitle();
109
+ this.showSummary();
110
+ this.showInlineErrors();
111
+ }
112
+ };
113
+
114
+ FormValidator.prototype.showInlineErrors = function () {
115
+ for (let i = 0, j = this.errors.length; i < j; i++) {
116
+ this.showInlineError(this.errors[i]);
117
+ }
118
+ };
119
+
120
+ FormValidator.prototype.showInlineError = function (error) {
121
+ const errorSpanId = `${error.fieldName}-error`;
122
+ const errorSpan = `<span class="govuk-error-message" id="${
123
+ errorSpanId
124
+ }">${this.escapeHtml(error.message)}</span>`;
125
+ const control = window.jQuery(`#${error.fieldName}`);
126
+ const fieldContainer = control.parents('.govuk-form-group');
127
+ const label = fieldContainer.find('label');
128
+ const legend = fieldContainer.find('legend');
129
+ const fieldset = fieldContainer.find('fieldset');
130
+ fieldContainer.addClass('govuk-form-group--error');
131
+ if (legend.length) {
132
+ legend.after(errorSpan);
133
+ fieldContainer.attr('aria-invalid', 'true');
134
+ addAttributeValue(fieldset[0], 'aria-describedby', errorSpanId);
135
+ } else {
136
+ label.after(errorSpan);
137
+ control.attr('aria-invalid', 'true');
138
+ addAttributeValue(control[0], 'aria-describedby', errorSpanId);
139
+ }
140
+ };
141
+
142
+ FormValidator.prototype.removeInlineErrors = function () {
143
+ for (let i = 0; i < this.errors.length; i++) {
144
+ this.removeInlineError(this.errors[i]);
145
+ }
146
+ };
147
+
148
+ FormValidator.prototype.removeInlineError = function (error) {
149
+ const control = window.jQuery(`#${error.fieldName}`);
150
+ const fieldContainer = control.parents('.govuk-form-group');
151
+ fieldContainer.find('.govuk-error-message').remove();
152
+ fieldContainer.removeClass('govuk-form-group--error');
153
+ fieldContainer.find('[aria-invalid]').attr('aria-invalid', 'false');
154
+ const errorSpanId = `${error.fieldName}-error`;
155
+ removeAttributeValue(
156
+ fieldContainer.find('[aria-describedby]')[0],
157
+ 'aria-describedby',
158
+ errorSpanId
159
+ );
160
+ };
161
+
162
+ FormValidator.prototype.addValidator = function (fieldName, rules) {
163
+ this.validators.push({
164
+ fieldName,
165
+ rules,
166
+ field: this.form.elements[fieldName]
167
+ });
168
+ };
169
+
170
+ FormValidator.prototype.validate = function () {
171
+ this.errors = [];
172
+ let validator = null;
173
+ let validatorReturnValue = true;
174
+ let i;
175
+ let j;
176
+ for (i = 0; i < this.validators.length; i++) {
177
+ validator = this.validators[i];
178
+ for (j = 0; j < validator.rules.length; j++) {
179
+ validatorReturnValue = validator.rules[j].method(
180
+ validator.field,
181
+ validator.rules[j].params
182
+ );
183
+
184
+ if (typeof validatorReturnValue === 'boolean' && !validatorReturnValue) {
185
+ this.errors.push({
186
+ fieldName: validator.fieldName,
187
+ message: validator.rules[j].message
188
+ });
189
+ break
190
+ } else if (typeof validatorReturnValue === 'string') {
191
+ this.errors.push({
192
+ fieldName: validatorReturnValue,
193
+ message: validator.rules[j].message
194
+ });
195
+ break
196
+ }
197
+ }
198
+ }
199
+ return this.errors.length === 0
200
+ };
201
+
202
+ exports.FormValidator = FormValidator;
398
203
 
399
204
  }));