@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,179 +1,194 @@
|
|
|
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';
|
|
6
|
-
|
|
7
|
-
function dragAndDropSupported() {
|
|
8
|
-
const div = document.createElement('div');
|
|
9
|
-
return typeof div.ondrop !== 'undefined';
|
|
10
|
-
}
|
|
11
|
-
function formDataSupported() {
|
|
12
|
-
return typeof FormData === 'function';
|
|
13
|
-
}
|
|
14
|
-
function fileApiSupported() {
|
|
15
|
-
const input = document.createElement('input');
|
|
16
|
-
input.type = 'file';
|
|
17
|
-
return typeof input.files !== 'undefined';
|
|
18
|
-
}
|
|
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';
|
|
19
6
|
|
|
20
7
|
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
21
8
|
|
|
22
|
-
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @augments {ConfigurableComponent<MultiFileUploadConfig>}
|
|
12
|
+
*/
|
|
13
|
+
class MultiFileUpload extends govukFrontend.ConfigurableComponent {
|
|
23
14
|
/**
|
|
24
|
-
* @param {
|
|
15
|
+
* @param {Element | null} $root - HTML element to use for multi file upload
|
|
16
|
+
* @param {MultiFileUploadConfig} [config] - Multi file upload config
|
|
25
17
|
*/
|
|
26
|
-
constructor(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (!container || !(container instanceof HTMLElement) || !(dragAndDropSupported() && formDataSupported() && fileApiSupported())) {
|
|
18
|
+
constructor($root, config = {}) {
|
|
19
|
+
var _this$config$feedback;
|
|
20
|
+
super($root, config);
|
|
21
|
+
if (!MultiFileUpload.isSupported()) {
|
|
31
22
|
return this;
|
|
32
23
|
}
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
uploadFileErrorHook: () => {},
|
|
39
|
-
fileDeleteHook: () => {},
|
|
40
|
-
uploadStatusText: 'Uploading files, please wait',
|
|
41
|
-
dropzoneHintText: 'Drag and drop files here or',
|
|
42
|
-
dropzoneButtonText: 'Choose files'
|
|
43
|
-
};
|
|
44
|
-
this.params = Object.assign({}, this.defaultParams, params);
|
|
45
|
-
this.feedbackContainer = /** @type {HTMLDivElement} */
|
|
46
|
-
this.container.querySelector('.moj-multi-file__uploaded-files');
|
|
24
|
+
const $feedbackContainer = (_this$config$feedback = this.config.feedbackContainer.element) != null ? _this$config$feedback : this.$root.querySelector(this.config.feedbackContainer.selector);
|
|
25
|
+
if (!$feedbackContainer || !($feedbackContainer instanceof HTMLElement)) {
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
this.$feedbackContainer = $feedbackContainer;
|
|
47
29
|
this.setupFileInput();
|
|
48
30
|
this.setupDropzone();
|
|
49
31
|
this.setupLabel();
|
|
50
32
|
this.setupStatusBox();
|
|
51
|
-
this.
|
|
33
|
+
this.$root.addEventListener('click', this.onFileDeleteClick.bind(this));
|
|
34
|
+
this.$root.classList.add('moj-multi-file-upload--enhanced');
|
|
52
35
|
}
|
|
53
36
|
setupDropzone() {
|
|
54
|
-
this
|
|
55
|
-
this
|
|
56
|
-
this
|
|
57
|
-
this
|
|
58
|
-
this
|
|
59
|
-
this
|
|
60
|
-
this
|
|
37
|
+
this.$dropzone = document.createElement('div');
|
|
38
|
+
this.$dropzone.classList.add('moj-multi-file-upload__dropzone');
|
|
39
|
+
this.$dropzone.addEventListener('dragover', this.onDragOver.bind(this));
|
|
40
|
+
this.$dropzone.addEventListener('dragleave', this.onDragLeave.bind(this));
|
|
41
|
+
this.$dropzone.addEventListener('drop', this.onDrop.bind(this));
|
|
42
|
+
this.$fileInput.replaceWith(this.$dropzone);
|
|
43
|
+
this.$dropzone.appendChild(this.$fileInput);
|
|
61
44
|
}
|
|
62
45
|
setupLabel() {
|
|
63
|
-
const label = document.createElement('label');
|
|
64
|
-
label.setAttribute('for', this
|
|
65
|
-
label.classList.add('govuk-button', 'govuk-button--secondary');
|
|
66
|
-
label.textContent = this.
|
|
67
|
-
const hint = document.createElement('p');
|
|
68
|
-
hint.classList.add('govuk-body');
|
|
69
|
-
hint.textContent = this.
|
|
70
|
-
this
|
|
71
|
-
this
|
|
72
|
-
this
|
|
46
|
+
const $label = document.createElement('label');
|
|
47
|
+
$label.setAttribute('for', this.$fileInput.id);
|
|
48
|
+
$label.classList.add('govuk-button', 'govuk-button--secondary');
|
|
49
|
+
$label.textContent = this.config.dropzoneButtonText;
|
|
50
|
+
const $hint = document.createElement('p');
|
|
51
|
+
$hint.classList.add('govuk-body');
|
|
52
|
+
$hint.textContent = this.config.dropzoneHintText;
|
|
53
|
+
this.$label = $label;
|
|
54
|
+
this.$dropzone.append($hint);
|
|
55
|
+
this.$dropzone.append($label);
|
|
73
56
|
}
|
|
74
57
|
setupFileInput() {
|
|
75
|
-
this
|
|
76
|
-
this.
|
|
77
|
-
this
|
|
78
|
-
this
|
|
79
|
-
this
|
|
58
|
+
this.$fileInput = /** @type {HTMLInputElement} */
|
|
59
|
+
this.$root.querySelector('.moj-multi-file-upload__input');
|
|
60
|
+
this.$fileInput.addEventListener('change', this.onFileChange.bind(this));
|
|
61
|
+
this.$fileInput.addEventListener('focus', this.onFileFocus.bind(this));
|
|
62
|
+
this.$fileInput.addEventListener('blur', this.onFileBlur.bind(this));
|
|
80
63
|
}
|
|
81
64
|
setupStatusBox() {
|
|
82
|
-
this
|
|
83
|
-
this
|
|
84
|
-
this
|
|
85
|
-
this
|
|
86
|
-
this
|
|
65
|
+
this.$status = document.createElement('div');
|
|
66
|
+
this.$status.classList.add('govuk-visually-hidden');
|
|
67
|
+
this.$status.setAttribute('aria-live', 'polite');
|
|
68
|
+
this.$status.setAttribute('role', 'status');
|
|
69
|
+
this.$dropzone.append(this.$status);
|
|
87
70
|
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {DragEvent} event - Drag event
|
|
74
|
+
*/
|
|
88
75
|
onDragOver(event) {
|
|
89
76
|
event.preventDefault();
|
|
90
|
-
this
|
|
77
|
+
this.$dropzone.classList.add('moj-multi-file-upload--dragover');
|
|
91
78
|
}
|
|
92
79
|
onDragLeave() {
|
|
93
|
-
this
|
|
80
|
+
this.$dropzone.classList.remove('moj-multi-file-upload--dragover');
|
|
94
81
|
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param {DragEvent} event - Drag event
|
|
85
|
+
*/
|
|
95
86
|
onDrop(event) {
|
|
96
87
|
event.preventDefault();
|
|
97
|
-
this
|
|
98
|
-
this
|
|
99
|
-
this
|
|
88
|
+
this.$dropzone.classList.remove('moj-multi-file-upload--dragover');
|
|
89
|
+
this.$feedbackContainer.classList.remove('moj-hidden');
|
|
90
|
+
this.$status.textContent = this.config.uploadStatusText;
|
|
100
91
|
this.uploadFiles(event.dataTransfer.files);
|
|
101
92
|
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {FileList} files - File list
|
|
96
|
+
*/
|
|
102
97
|
uploadFiles(files) {
|
|
103
98
|
for (const file of Array.from(files)) {
|
|
104
99
|
this.uploadFile(file);
|
|
105
100
|
}
|
|
106
101
|
}
|
|
107
102
|
onFileChange() {
|
|
108
|
-
this
|
|
109
|
-
this
|
|
110
|
-
this.uploadFiles(this
|
|
111
|
-
const fileInput = this
|
|
112
|
-
if (
|
|
103
|
+
this.$feedbackContainer.classList.remove('moj-hidden');
|
|
104
|
+
this.$status.textContent = this.config.uploadStatusText;
|
|
105
|
+
this.uploadFiles(this.$fileInput.files);
|
|
106
|
+
const $fileInput = this.$fileInput.cloneNode(true);
|
|
107
|
+
if (!$fileInput || !($fileInput instanceof HTMLInputElement)) {
|
|
113
108
|
return;
|
|
114
109
|
}
|
|
115
|
-
fileInput.value = '';
|
|
116
|
-
this
|
|
110
|
+
$fileInput.value = '';
|
|
111
|
+
this.$fileInput.replaceWith($fileInput);
|
|
117
112
|
this.setupFileInput();
|
|
118
|
-
this
|
|
113
|
+
this.$fileInput.focus();
|
|
119
114
|
}
|
|
120
115
|
onFileFocus() {
|
|
121
|
-
this
|
|
116
|
+
this.$label.classList.add('moj-multi-file-upload--focused');
|
|
122
117
|
}
|
|
123
118
|
onFileBlur() {
|
|
124
|
-
this
|
|
119
|
+
this.$label.classList.remove('moj-multi-file-upload--focused');
|
|
125
120
|
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {UploadResponseSuccess['success']} success
|
|
124
|
+
*/
|
|
126
125
|
getSuccessHtml(success) {
|
|
127
126
|
return `<span class="moj-multi-file-upload__success"> <svg class="moj-banner__icon" fill="currentColor" role="presentation" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25" height="25" width="25"><path d="M25,6.2L8.7,23.2L0,14.1l4-4.2l4.7,4.9L21,2L25,6.2z"/></svg>${success.messageHtml}</span>`;
|
|
128
127
|
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @param {UploadResponseError['error']} error
|
|
131
|
+
*/
|
|
129
132
|
getErrorHtml(error) {
|
|
130
133
|
return `<span class="moj-multi-file-upload__error"> <svg class="moj-banner__icon" fill="currentColor" role="presentation" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25" height="25" width="25"><path d="M13.6,15.4h-2.3v-4.5h2.3V15.4z M13.6,19.8h-2.3v-2.2h2.3V19.8z M0,23.2h25L12.5,2L0,23.2z"/></svg>${error.message}</span>`;
|
|
131
134
|
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @param {File} file
|
|
138
|
+
*/
|
|
132
139
|
getFileRow(file) {
|
|
133
|
-
const row = document.createElement('div');
|
|
134
|
-
row.classList.add('govuk-summary-list__row', 'moj-multi-file-upload__row');
|
|
135
|
-
row.innerHTML = `
|
|
140
|
+
const $row = document.createElement('div');
|
|
141
|
+
$row.classList.add('govuk-summary-list__row', 'moj-multi-file-upload__row');
|
|
142
|
+
$row.innerHTML = `
|
|
136
143
|
<div class="govuk-summary-list__value moj-multi-file-upload__message">
|
|
137
144
|
<span class="moj-multi-file-upload__filename">${file.name}</span>
|
|
138
145
|
<span class="moj-multi-file-upload__progress">0%</span>
|
|
139
146
|
</div>
|
|
140
147
|
<div class="govuk-summary-list__actions moj-multi-file-upload__actions"></div>
|
|
141
148
|
`;
|
|
142
|
-
return row;
|
|
149
|
+
return $row;
|
|
143
150
|
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @param {UploadResponseFile} file
|
|
154
|
+
*/
|
|
144
155
|
getDeleteButton(file) {
|
|
145
|
-
const button = document.createElement('button');
|
|
146
|
-
button.setAttribute('type', 'button');
|
|
147
|
-
button.setAttribute('name', 'delete');
|
|
148
|
-
button.setAttribute('value', file.filename);
|
|
149
|
-
button.classList.add('moj-multi-file-upload__delete', 'govuk-button', 'govuk-button--secondary', 'govuk-!-margin-bottom-0');
|
|
150
|
-
button.innerHTML = `Delete <span class="govuk-visually-hidden">${file.originalname}</span>`;
|
|
151
|
-
return button;
|
|
156
|
+
const $button = document.createElement('button');
|
|
157
|
+
$button.setAttribute('type', 'button');
|
|
158
|
+
$button.setAttribute('name', 'delete');
|
|
159
|
+
$button.setAttribute('value', file.filename);
|
|
160
|
+
$button.classList.add('moj-multi-file-upload__delete', 'govuk-button', 'govuk-button--secondary', 'govuk-!-margin-bottom-0');
|
|
161
|
+
$button.innerHTML = `Delete <span class="govuk-visually-hidden">${file.originalname}</span>`;
|
|
162
|
+
return $button;
|
|
152
163
|
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* @param {File} file
|
|
167
|
+
*/
|
|
153
168
|
uploadFile(file) {
|
|
154
|
-
this.
|
|
155
|
-
const item = this.getFileRow(file);
|
|
156
|
-
const message = item.querySelector('.moj-multi-file-upload__message');
|
|
157
|
-
const actions = item.querySelector('.moj-multi-file-upload__actions');
|
|
158
|
-
const progress = item.querySelector('.moj-multi-file-upload__progress');
|
|
169
|
+
this.config.hooks.entryHook(this, file);
|
|
170
|
+
const $item = this.getFileRow(file);
|
|
171
|
+
const $message = $item.querySelector('.moj-multi-file-upload__message');
|
|
172
|
+
const $actions = $item.querySelector('.moj-multi-file-upload__actions');
|
|
173
|
+
const $progress = $item.querySelector('.moj-multi-file-upload__progress');
|
|
159
174
|
const formData = new FormData();
|
|
160
175
|
formData.append('documents', file);
|
|
161
|
-
this
|
|
176
|
+
this.$feedbackContainer.querySelector('.moj-multi-file-upload__list').append($item);
|
|
162
177
|
const xhr = new XMLHttpRequest();
|
|
163
178
|
const onLoad = () => {
|
|
164
179
|
if (xhr.status < 200 || xhr.status >= 300 || !('success' in xhr.response)) {
|
|
165
180
|
return onError();
|
|
166
181
|
}
|
|
167
|
-
message.innerHTML = this.getSuccessHtml(xhr.response.success);
|
|
168
|
-
this
|
|
169
|
-
actions.append(this.getDeleteButton(xhr.response.file));
|
|
170
|
-
this.
|
|
182
|
+
$message.innerHTML = this.getSuccessHtml(xhr.response.success);
|
|
183
|
+
this.$status.textContent = xhr.response.success.messageText;
|
|
184
|
+
$actions.append(this.getDeleteButton(xhr.response.file));
|
|
185
|
+
this.config.hooks.exitHook(this, file, xhr, xhr.responseText);
|
|
171
186
|
};
|
|
172
187
|
const onError = () => {
|
|
173
188
|
const error = new Error(xhr.response && 'error' in xhr.response ? xhr.response.error.message : xhr.statusText || 'Upload failed');
|
|
174
|
-
message.innerHTML = this.getErrorHtml(error);
|
|
175
|
-
this
|
|
176
|
-
this.
|
|
189
|
+
$message.innerHTML = this.getErrorHtml(error);
|
|
190
|
+
this.$status.textContent = error.message;
|
|
191
|
+
this.config.hooks.errorHook(this, file, xhr, xhr.responseText, error);
|
|
177
192
|
};
|
|
178
193
|
xhr.addEventListener('load', onLoad);
|
|
179
194
|
xhr.addEventListener('error', onError);
|
|
@@ -182,15 +197,19 @@
|
|
|
182
197
|
return;
|
|
183
198
|
}
|
|
184
199
|
const percentComplete = Math.round(event.loaded / event.total * 100);
|
|
185
|
-
progress.textContent = ` ${percentComplete}%`;
|
|
200
|
+
$progress.textContent = ` ${percentComplete}%`;
|
|
186
201
|
});
|
|
187
|
-
xhr.open('POST', this.
|
|
202
|
+
xhr.open('POST', this.config.uploadUrl);
|
|
188
203
|
xhr.responseType = 'json';
|
|
189
204
|
xhr.send(formData);
|
|
190
205
|
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @param {MouseEvent} event - Click event
|
|
209
|
+
*/
|
|
191
210
|
onFileDeleteClick(event) {
|
|
192
|
-
const button = event.target;
|
|
193
|
-
if (
|
|
211
|
+
const $button = event.target;
|
|
212
|
+
if (!$button || !($button instanceof HTMLButtonElement) || !$button.classList.contains('moj-multi-file-upload__delete')) {
|
|
194
213
|
return;
|
|
195
214
|
}
|
|
196
215
|
event.preventDefault(); // if user refreshes page and then deletes
|
|
@@ -200,23 +219,178 @@
|
|
|
200
219
|
if (xhr.status < 200 || xhr.status >= 300) {
|
|
201
220
|
return;
|
|
202
221
|
}
|
|
203
|
-
const rows = Array.from(this
|
|
204
|
-
if (rows.length === 1) {
|
|
205
|
-
this
|
|
222
|
+
const $rows = Array.from(this.$feedbackContainer.querySelectorAll('.moj-multi-file-upload__row'));
|
|
223
|
+
if ($rows.length === 1) {
|
|
224
|
+
this.$feedbackContainer.classList.add('moj-hidden');
|
|
206
225
|
}
|
|
207
|
-
const
|
|
208
|
-
if (
|
|
209
|
-
this.
|
|
226
|
+
const $rowDelete = $rows.find($row => $row.contains($button));
|
|
227
|
+
if ($rowDelete) $rowDelete.remove();
|
|
228
|
+
this.config.hooks.deleteHook(this, undefined, xhr, xhr.responseText);
|
|
210
229
|
});
|
|
211
|
-
xhr.open('POST', this.
|
|
230
|
+
xhr.open('POST', this.config.deleteUrl);
|
|
212
231
|
xhr.setRequestHeader('Content-Type', 'application/json');
|
|
213
232
|
xhr.responseType = 'json';
|
|
214
233
|
xhr.send(JSON.stringify({
|
|
215
|
-
[button.name]: button.value
|
|
234
|
+
[$button.name]: $button.value
|
|
216
235
|
}));
|
|
217
236
|
}
|
|
237
|
+
static isSupported() {
|
|
238
|
+
return this.isDragAndDropSupported() && this.isFormDataSupported() && this.isFileApiSupported();
|
|
239
|
+
}
|
|
240
|
+
static isDragAndDropSupported() {
|
|
241
|
+
const div = document.createElement('div');
|
|
242
|
+
return typeof div.ondrop !== 'undefined';
|
|
243
|
+
}
|
|
244
|
+
static isFormDataSupported() {
|
|
245
|
+
return typeof FormData === 'function';
|
|
246
|
+
}
|
|
247
|
+
static isFileApiSupported() {
|
|
248
|
+
const input = document.createElement('input');
|
|
249
|
+
input.type = 'file';
|
|
250
|
+
return typeof input.files !== 'undefined';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Name for the component used when initialising using data-module attributes.
|
|
255
|
+
*/
|
|
218
256
|
}
|
|
219
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Multi file upload config
|
|
260
|
+
*
|
|
261
|
+
* @typedef {object} MultiFileUploadConfig
|
|
262
|
+
* @property {string} [uploadUrl] - File upload URL
|
|
263
|
+
* @property {string} [deleteUrl] - File delete URL
|
|
264
|
+
* @property {string} [uploadStatusText] - Upload status text
|
|
265
|
+
* @property {string} [dropzoneHintText] - Dropzone hint text
|
|
266
|
+
* @property {string} [dropzoneButtonText] - Dropzone button text
|
|
267
|
+
* @property {object} [feedbackContainer] - Feedback container config
|
|
268
|
+
* @property {string} [feedbackContainer.selector] - Selector for feedback container
|
|
269
|
+
* @property {Element | null} [feedbackContainer.element] - HTML element for feedback container
|
|
270
|
+
* @property {MultiFileUploadHooks} [hooks] - Upload hooks
|
|
271
|
+
*/
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Multi file upload hooks
|
|
275
|
+
*
|
|
276
|
+
* @typedef {object} MultiFileUploadHooks
|
|
277
|
+
* @property {OnUploadFileEntryHook} [entryHook] - File upload entry hook
|
|
278
|
+
* @property {OnUploadFileExitHook} [exitHook] - File upload exit hook
|
|
279
|
+
* @property {OnUploadFileErrorHook} [errorHook] - File upload error hook
|
|
280
|
+
* @property {OnUploadFileDeleteHook} [deleteHook] - File delete hook
|
|
281
|
+
*/
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Upload hook: File entry
|
|
285
|
+
*
|
|
286
|
+
* @callback OnUploadFileEntryHook
|
|
287
|
+
* @param {InstanceType<typeof MultiFileUpload>} upload - Multi file upload
|
|
288
|
+
* @param {File} file - File upload
|
|
289
|
+
*/
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Upload hook: File exit
|
|
293
|
+
*
|
|
294
|
+
* @callback OnUploadFileExitHook
|
|
295
|
+
* @param {InstanceType<typeof MultiFileUpload>} upload - Multi file upload
|
|
296
|
+
* @param {File} file - File upload
|
|
297
|
+
* @param {XMLHttpRequest} xhr - XMLHttpRequest
|
|
298
|
+
* @param {string} textStatus - Text status
|
|
299
|
+
*/
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Upload hook: File error
|
|
303
|
+
*
|
|
304
|
+
* @callback OnUploadFileErrorHook
|
|
305
|
+
* @param {InstanceType<typeof MultiFileUpload>} upload - Multi file upload
|
|
306
|
+
* @param {File} file - File upload
|
|
307
|
+
* @param {XMLHttpRequest} xhr - XMLHttpRequest
|
|
308
|
+
* @param {string} textStatus - Text status
|
|
309
|
+
* @param {Error} errorThrown - Error thrown
|
|
310
|
+
*/
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Upload hook: File delete
|
|
314
|
+
*
|
|
315
|
+
* @callback OnUploadFileDeleteHook
|
|
316
|
+
* @param {InstanceType<typeof MultiFileUpload>} upload - Multi file upload
|
|
317
|
+
* @param {File} [file] - File upload
|
|
318
|
+
* @param {XMLHttpRequest} xhr - XMLHttpRequest
|
|
319
|
+
* @param {string} textStatus - Text status
|
|
320
|
+
*/
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* @typedef {object} UploadResponseSuccess
|
|
324
|
+
* @property {{ messageText: string, messageHtml: string }} success - Response success
|
|
325
|
+
* @property {UploadResponseFile} file - Response file
|
|
326
|
+
*/
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* @typedef {object} UploadResponseError
|
|
330
|
+
* @property {{ message: string }} error - Response error
|
|
331
|
+
* @property {UploadResponseFile} file - Response file
|
|
332
|
+
*/
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* @typedef {object} UploadResponseFile
|
|
336
|
+
* @property {string} filename - File name
|
|
337
|
+
* @property {string} originalname - Original file name
|
|
338
|
+
*/
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
|
|
342
|
+
*/
|
|
343
|
+
MultiFileUpload.moduleName = 'moj-multi-file-upload';
|
|
344
|
+
/**
|
|
345
|
+
* Multi file upload default config
|
|
346
|
+
*
|
|
347
|
+
* @type {MultiFileUploadConfig}
|
|
348
|
+
*/
|
|
349
|
+
MultiFileUpload.defaults = Object.freeze({
|
|
350
|
+
uploadStatusText: 'Uploading files, please wait',
|
|
351
|
+
dropzoneHintText: 'Drag and drop files here or',
|
|
352
|
+
dropzoneButtonText: 'Choose files',
|
|
353
|
+
feedbackContainer: {
|
|
354
|
+
selector: '.moj-multi-file__uploaded-files'
|
|
355
|
+
},
|
|
356
|
+
hooks: {
|
|
357
|
+
entryHook: () => {},
|
|
358
|
+
exitHook: () => {},
|
|
359
|
+
errorHook: () => {},
|
|
360
|
+
deleteHook: () => {}
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
/**
|
|
364
|
+
* Multi file upload config schema
|
|
365
|
+
*
|
|
366
|
+
* @satisfies {Schema<MultiFileUploadConfig>}
|
|
367
|
+
*/
|
|
368
|
+
MultiFileUpload.schema = Object.freeze(/** @type {const} */{
|
|
369
|
+
properties: {
|
|
370
|
+
uploadUrl: {
|
|
371
|
+
type: 'string'
|
|
372
|
+
},
|
|
373
|
+
deleteUrl: {
|
|
374
|
+
type: 'string'
|
|
375
|
+
},
|
|
376
|
+
uploadStatusText: {
|
|
377
|
+
type: 'string'
|
|
378
|
+
},
|
|
379
|
+
dropzoneHintText: {
|
|
380
|
+
type: 'string'
|
|
381
|
+
},
|
|
382
|
+
dropzoneButtonText: {
|
|
383
|
+
type: 'string'
|
|
384
|
+
},
|
|
385
|
+
feedbackContainer: {
|
|
386
|
+
type: 'object'
|
|
387
|
+
},
|
|
388
|
+
hooks: {
|
|
389
|
+
type: 'object'
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
|
|
220
394
|
exports.MultiFileUpload = MultiFileUpload;
|
|
221
395
|
|
|
222
396
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multi-file-upload.bundle.js","sources":["../../../../src/moj/helpers.mjs","../../../../src/moj/components/multi-file-upload/multi-file-upload.mjs"],"sourcesContent":["export function removeAttributeValue(el, attr, value) {\n let re, m\n if (el.getAttribute(attr)) {\n if (el.getAttribute(attr) === value) {\n el.removeAttribute(attr)\n } else {\n re = new RegExp(`(^|\\\\s)${value}(\\\\s|$)`)\n m = el.getAttribute(attr).match(re)\n if (m && m.length === 3) {\n el.setAttribute(\n attr,\n el.getAttribute(attr).replace(re, m[1] && m[2] ? ' ' : '')\n )\n }\n }\n }\n}\n\nexport function addAttributeValue(el, attr, value) {\n let re\n if (!el.getAttribute(attr)) {\n el.setAttribute(attr, value)\n } else {\n re = new RegExp(`(^|\\\\s)${value}(\\\\s|$)`)\n if (!re.test(el.getAttribute(attr))) {\n el.setAttribute(attr, `${el.getAttribute(attr)} ${value}`)\n }\n }\n}\n\nexport function dragAndDropSupported() {\n const div = document.createElement('div')\n return typeof div.ondrop !== 'undefined'\n}\n\nexport function formDataSupported() {\n return typeof FormData === 'function'\n}\n\nexport function fileApiSupported() {\n const input = document.createElement('input')\n input.type = 'file'\n return typeof input.files !== 'undefined'\n}\n\n/**\n * Find an elements next sibling\n *\n * Utility function to find an elements next sibling matching the provided\n * selector.\n *\n * @param {Element | null} $element - Element to find siblings for\n * @param {string} [selector] - selector for required sibling\n */\nexport function getNextSibling($element, selector) {\n if (!$element || !($element instanceof HTMLElement)) {\n return\n }\n\n // Get the next sibling element\n let $sibling = $element.nextElementSibling\n\n // If there's no selector, return the first sibling\n if (!selector) return $sibling\n\n // If the sibling matches our selector, use it\n // If not, jump to the next sibling and continue the loop\n while ($sibling) {\n if ($sibling.matches(selector)) return $sibling\n $sibling = $sibling.nextElementSibling\n }\n}\n\n/**\n * Find an elements preceding sibling\n *\n * Utility function to find an elements previous sibling matching the provided\n * selector.\n *\n * @param {Element | null} $element - Element to find siblings for\n * @param {string} [selector] - selector for required sibling\n */\nexport function getPreviousSibling($element, selector) {\n if (!$element || !($element instanceof HTMLElement)) {\n return\n }\n\n // Get the previous sibling element\n let $sibling = $element.previousElementSibling\n\n // If there's no selector, return the first sibling\n if (!selector) return $sibling\n\n // If the sibling matches our selector, use it\n // If not, jump to the next sibling and continue the loop\n while ($sibling) {\n if ($sibling.matches(selector)) return $sibling\n $sibling = $sibling.previousElementSibling\n }\n}\n\n/**\n * @param {Element | null} $element\n * @param {string} [selector]\n */\nexport function findNearestMatchingElement($element, selector) {\n // If no element or selector is provided, return\n if (!$element || !($element instanceof HTMLElement) || !selector) {\n return\n }\n\n // Start with the current element\n let $currentElement = $element\n\n while ($currentElement) {\n // First check the current element\n if ($currentElement.matches(selector)) {\n return $currentElement\n }\n\n // Check all previous siblings\n let $sibling = $currentElement.previousElementSibling\n while ($sibling) {\n // Check if the sibling itself is a heading\n if ($sibling.matches(selector)) {\n return $sibling\n }\n $sibling = $sibling.previousElementSibling\n }\n\n // If no match found in siblings, move up to parent\n $currentElement = $currentElement.parentElement\n }\n}\n\n/**\n * Move focus to element\n *\n * Sets tabindex to -1 to make the element programmatically focusable,\n * but removes it on blur as the element doesn't need to be focused again.\n *\n * @param {HTMLElement} $element - HTML element\n * @param {object} [options] - Handler options\n * @param {function(this: HTMLElement): void} [options.onBeforeFocus] - Callback before focus\n * @param {function(this: HTMLElement): void} [options.onBlur] - Callback on blur\n */\nexport function setFocus($element, options = {}) {\n const isFocusable = $element.getAttribute('tabindex')\n\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1')\n }\n\n /**\n * Handle element focus\n */\n function onFocus() {\n $element.addEventListener('blur', onBlur, { once: true })\n }\n\n /**\n * Handle element blur\n */\n function onBlur() {\n if (options.onBlur) {\n options.onBlur.call($element)\n }\n\n if (!isFocusable) {\n $element.removeAttribute('tabindex')\n }\n }\n\n // Add listener to reset element on blur, after focus\n $element.addEventListener('focus', onFocus, { once: true })\n\n // Focus element\n if (options.onBeforeFocus) {\n options.onBeforeFocus.call($element)\n }\n $element.focus()\n}\n","/* eslint-disable @typescript-eslint/no-empty-function */\n\nimport {\n dragAndDropSupported,\n fileApiSupported,\n formDataSupported\n} from '../../helpers.mjs'\n\nexport class MultiFileUpload {\n /**\n * @param {MultiFileUploadConfig} [params] - Multi file upload config\n */\n constructor(params = {}) {\n const { container } = params\n\n if (\n !container ||\n !(container instanceof HTMLElement) ||\n !(dragAndDropSupported() && formDataSupported() && fileApiSupported())\n ) {\n return this\n }\n\n this.container = container\n this.container.classList.add('moj-multi-file-upload--enhanced')\n\n this.defaultParams = {\n uploadFileEntryHook: () => {},\n uploadFileExitHook: () => {},\n uploadFileErrorHook: () => {},\n fileDeleteHook: () => {},\n uploadStatusText: 'Uploading files, please wait',\n dropzoneHintText: 'Drag and drop files here or',\n dropzoneButtonText: 'Choose files'\n }\n\n this.params = Object.assign({}, this.defaultParams, params)\n\n this.feedbackContainer = /** @type {HTMLDivElement} */ (\n this.container.querySelector('.moj-multi-file__uploaded-files')\n )\n\n this.setupFileInput()\n this.setupDropzone()\n this.setupLabel()\n this.setupStatusBox()\n\n this.container.addEventListener('click', this.onFileDeleteClick.bind(this))\n }\n\n setupDropzone() {\n this.dropzone = document.createElement('div')\n this.dropzone.classList.add('moj-multi-file-upload__dropzone')\n\n this.dropzone.addEventListener('dragover', this.onDragOver.bind(this))\n this.dropzone.addEventListener('dragleave', this.onDragLeave.bind(this))\n this.dropzone.addEventListener('drop', this.onDrop.bind(this))\n\n this.fileInput.replaceWith(this.dropzone)\n this.dropzone.appendChild(this.fileInput)\n }\n\n setupLabel() {\n const label = document.createElement('label')\n label.setAttribute('for', this.fileInput.id)\n label.classList.add('govuk-button', 'govuk-button--secondary')\n label.textContent = this.params.dropzoneButtonText\n\n const hint = document.createElement('p')\n hint.classList.add('govuk-body')\n hint.textContent = this.params.dropzoneHintText\n\n this.label = label\n this.dropzone.append(hint)\n this.dropzone.append(label)\n }\n\n setupFileInput() {\n this.fileInput = /** @type {HTMLInputElement} */ (\n this.container.querySelector('.moj-multi-file-upload__input')\n )\n this.fileInput.addEventListener('change', this.onFileChange.bind(this))\n this.fileInput.addEventListener('focus', this.onFileFocus.bind(this))\n this.fileInput.addEventListener('blur', this.onFileBlur.bind(this))\n }\n\n setupStatusBox() {\n this.status = document.createElement('div')\n this.status.classList.add('govuk-visually-hidden')\n this.status.setAttribute('aria-live', 'polite')\n this.status.setAttribute('role', 'status')\n this.dropzone.append(this.status)\n }\n\n onDragOver(event) {\n event.preventDefault()\n this.dropzone.classList.add('moj-multi-file-upload--dragover')\n }\n\n onDragLeave() {\n this.dropzone.classList.remove('moj-multi-file-upload--dragover')\n }\n\n onDrop(event) {\n event.preventDefault()\n this.dropzone.classList.remove('moj-multi-file-upload--dragover')\n this.feedbackContainer.classList.remove('moj-hidden')\n this.status.textContent = this.params.uploadStatusText\n this.uploadFiles(event.dataTransfer.files)\n }\n\n uploadFiles(files) {\n for (const file of Array.from(files)) {\n this.uploadFile(file)\n }\n }\n\n onFileChange() {\n this.feedbackContainer.classList.remove('moj-hidden')\n this.status.textContent = this.params.uploadStatusText\n this.uploadFiles(this.fileInput.files)\n\n const fileInput = this.fileInput.cloneNode(true)\n if (!fileInput || !(fileInput instanceof HTMLInputElement)) {\n return\n }\n\n fileInput.value = ''\n this.fileInput.replaceWith(fileInput)\n\n this.setupFileInput()\n this.fileInput.focus()\n }\n\n onFileFocus() {\n this.label.classList.add('moj-multi-file-upload--focused')\n }\n\n onFileBlur() {\n this.label.classList.remove('moj-multi-file-upload--focused')\n }\n\n getSuccessHtml(success) {\n return `<span class=\"moj-multi-file-upload__success\"> <svg class=\"moj-banner__icon\" fill=\"currentColor\" role=\"presentation\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 25 25\" height=\"25\" width=\"25\"><path d=\"M25,6.2L8.7,23.2L0,14.1l4-4.2l4.7,4.9L21,2L25,6.2z\"/></svg>${success.messageHtml}</span>`\n }\n\n getErrorHtml(error) {\n return `<span class=\"moj-multi-file-upload__error\"> <svg class=\"moj-banner__icon\" fill=\"currentColor\" role=\"presentation\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 25 25\" height=\"25\" width=\"25\"><path d=\"M13.6,15.4h-2.3v-4.5h2.3V15.4z M13.6,19.8h-2.3v-2.2h2.3V19.8z M0,23.2h25L12.5,2L0,23.2z\"/></svg>${error.message}</span>`\n }\n\n getFileRow(file) {\n const row = document.createElement('div')\n\n row.classList.add('govuk-summary-list__row', 'moj-multi-file-upload__row')\n\n row.innerHTML = `\n <div class=\"govuk-summary-list__value moj-multi-file-upload__message\">\n <span class=\"moj-multi-file-upload__filename\">${file.name}</span>\n <span class=\"moj-multi-file-upload__progress\">0%</span>\n </div>\n <div class=\"govuk-summary-list__actions moj-multi-file-upload__actions\"></div>\n `\n\n return row\n }\n\n getDeleteButton(file) {\n const button = document.createElement('button')\n\n button.setAttribute('type', 'button')\n button.setAttribute('name', 'delete')\n button.setAttribute('value', file.filename)\n\n button.classList.add(\n 'moj-multi-file-upload__delete',\n 'govuk-button',\n 'govuk-button--secondary',\n 'govuk-!-margin-bottom-0'\n )\n\n button.innerHTML = `Delete <span class=\"govuk-visually-hidden\">${file.originalname}</span>`\n\n return button\n }\n\n uploadFile(file) {\n this.params.uploadFileEntryHook(this, file)\n\n const item = this.getFileRow(file)\n const message = item.querySelector('.moj-multi-file-upload__message')\n const actions = item.querySelector('.moj-multi-file-upload__actions')\n const progress = item.querySelector('.moj-multi-file-upload__progress')\n\n const formData = new FormData()\n formData.append('documents', file)\n\n this.feedbackContainer\n .querySelector('.moj-multi-file-upload__list')\n .append(item)\n\n const xhr = new XMLHttpRequest()\n\n const onLoad = () => {\n if (\n xhr.status < 200 ||\n xhr.status >= 300 ||\n !('success' in xhr.response)\n ) {\n return onError()\n }\n\n message.innerHTML = this.getSuccessHtml(xhr.response.success)\n this.status.textContent = xhr.response.success.messageText\n\n actions.append(this.getDeleteButton(xhr.response.file))\n this.params.uploadFileExitHook(this, file, xhr, xhr.responseText)\n }\n\n const onError = () => {\n const error = new Error(\n xhr.response && 'error' in xhr.response\n ? xhr.response.error.message\n : xhr.statusText || 'Upload failed'\n )\n\n message.innerHTML = this.getErrorHtml(error)\n this.status.textContent = error.message\n\n this.params.uploadFileErrorHook(this, file, xhr, xhr.responseText, error)\n }\n\n xhr.addEventListener('load', onLoad)\n xhr.addEventListener('error', onError)\n\n xhr.upload.addEventListener('progress', (event) => {\n if (!event.lengthComputable) {\n return\n }\n\n const percentComplete = Math.round((event.loaded / event.total) * 100)\n progress.textContent = ` ${percentComplete}%`\n })\n\n xhr.open('POST', this.params.uploadUrl)\n xhr.responseType = 'json'\n\n xhr.send(formData)\n }\n\n onFileDeleteClick(event) {\n const button = event.target\n\n if (\n !button ||\n !(button instanceof HTMLButtonElement) ||\n !button.classList.contains('moj-multi-file-upload__delete')\n ) {\n return\n }\n\n event.preventDefault() // if user refreshes page and then deletes\n\n const xhr = new XMLHttpRequest()\n\n xhr.addEventListener('load', () => {\n if (xhr.status < 200 || xhr.status >= 300) {\n return\n }\n\n const rows = Array.from(\n this.feedbackContainer.querySelectorAll('.moj-multi-file-upload__row')\n )\n\n if (rows.length === 1) {\n this.feedbackContainer.classList.add('moj-hidden')\n }\n\n const row = rows.find((row) => row.contains(button))\n if (row) row.remove()\n\n this.params.fileDeleteHook(this, undefined, xhr, xhr.responseText)\n })\n\n xhr.open('POST', this.params.deleteUrl)\n xhr.setRequestHeader('Content-Type', 'application/json')\n xhr.responseType = 'json'\n\n xhr.send(\n JSON.stringify({\n [button.name]: button.value\n })\n )\n }\n}\n"],"names":["dragAndDropSupported","div","document","createElement","ondrop","formDataSupported","FormData","fileApiSupported","input","type","files","MultiFileUpload","constructor","params","container","HTMLElement","classList","add","defaultParams","uploadFileEntryHook","uploadFileExitHook","uploadFileErrorHook","fileDeleteHook","uploadStatusText","dropzoneHintText","dropzoneButtonText","Object","assign","feedbackContainer","querySelector","setupFileInput","setupDropzone","setupLabel","setupStatusBox","addEventListener","onFileDeleteClick","bind","dropzone","onDragOver","onDragLeave","onDrop","fileInput","replaceWith","appendChild","label","setAttribute","id","textContent","hint","append","onFileChange","onFileFocus","onFileBlur","status","event","preventDefault","remove","uploadFiles","dataTransfer","file","Array","from","uploadFile","cloneNode","HTMLInputElement","value","focus","getSuccessHtml","success","messageHtml","getErrorHtml","error","message","getFileRow","row","innerHTML","name","getDeleteButton","button","filename","originalname","item","actions","progress","formData","xhr","XMLHttpRequest","onLoad","response","onError","messageText","responseText","Error","statusText","upload","lengthComputable","percentComplete","Math","round","loaded","total","open","uploadUrl","responseType","send","target","HTMLButtonElement","contains","rows","querySelectorAll","length","find","undefined","deleteUrl","setRequestHeader","JSON","stringify"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"multi-file-upload.bundle.js","sources":["../../../../src/moj/components/multi-file-upload/multi-file-upload.mjs"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-empty-function */\n\nimport { ConfigurableComponent } from 'govuk-frontend'\n\n/**\n * @augments {ConfigurableComponent<MultiFileUploadConfig>}\n */\nexport class MultiFileUpload extends ConfigurableComponent {\n /**\n * @param {Element | null} $root - HTML element to use for multi file upload\n * @param {MultiFileUploadConfig} [config] - Multi file upload config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n if (!MultiFileUpload.isSupported()) {\n return this\n }\n\n const $feedbackContainer =\n this.config.feedbackContainer.element ??\n this.$root.querySelector(this.config.feedbackContainer.selector)\n\n if (!$feedbackContainer || !($feedbackContainer instanceof HTMLElement)) {\n return this\n }\n\n this.$feedbackContainer = $feedbackContainer\n\n this.setupFileInput()\n this.setupDropzone()\n this.setupLabel()\n this.setupStatusBox()\n\n this.$root.addEventListener('click', this.onFileDeleteClick.bind(this))\n this.$root.classList.add('moj-multi-file-upload--enhanced')\n }\n\n setupDropzone() {\n this.$dropzone = document.createElement('div')\n this.$dropzone.classList.add('moj-multi-file-upload__dropzone')\n\n this.$dropzone.addEventListener('dragover', this.onDragOver.bind(this))\n this.$dropzone.addEventListener('dragleave', this.onDragLeave.bind(this))\n this.$dropzone.addEventListener('drop', this.onDrop.bind(this))\n\n this.$fileInput.replaceWith(this.$dropzone)\n this.$dropzone.appendChild(this.$fileInput)\n }\n\n setupLabel() {\n const $label = document.createElement('label')\n $label.setAttribute('for', this.$fileInput.id)\n $label.classList.add('govuk-button', 'govuk-button--secondary')\n $label.textContent = this.config.dropzoneButtonText\n\n const $hint = document.createElement('p')\n $hint.classList.add('govuk-body')\n $hint.textContent = this.config.dropzoneHintText\n\n this.$label = $label\n this.$dropzone.append($hint)\n this.$dropzone.append($label)\n }\n\n setupFileInput() {\n this.$fileInput = /** @type {HTMLInputElement} */ (\n this.$root.querySelector('.moj-multi-file-upload__input')\n )\n this.$fileInput.addEventListener('change', this.onFileChange.bind(this))\n this.$fileInput.addEventListener('focus', this.onFileFocus.bind(this))\n this.$fileInput.addEventListener('blur', this.onFileBlur.bind(this))\n }\n\n setupStatusBox() {\n this.$status = document.createElement('div')\n this.$status.classList.add('govuk-visually-hidden')\n this.$status.setAttribute('aria-live', 'polite')\n this.$status.setAttribute('role', 'status')\n this.$dropzone.append(this.$status)\n }\n\n /**\n * @param {DragEvent} event - Drag event\n */\n onDragOver(event) {\n event.preventDefault()\n this.$dropzone.classList.add('moj-multi-file-upload--dragover')\n }\n\n onDragLeave() {\n this.$dropzone.classList.remove('moj-multi-file-upload--dragover')\n }\n\n /**\n * @param {DragEvent} event - Drag event\n */\n onDrop(event) {\n event.preventDefault()\n this.$dropzone.classList.remove('moj-multi-file-upload--dragover')\n this.$feedbackContainer.classList.remove('moj-hidden')\n this.$status.textContent = this.config.uploadStatusText\n this.uploadFiles(event.dataTransfer.files)\n }\n\n /**\n * @param {FileList} files - File list\n */\n uploadFiles(files) {\n for (const file of Array.from(files)) {\n this.uploadFile(file)\n }\n }\n\n onFileChange() {\n this.$feedbackContainer.classList.remove('moj-hidden')\n this.$status.textContent = this.config.uploadStatusText\n this.uploadFiles(this.$fileInput.files)\n\n const $fileInput = this.$fileInput.cloneNode(true)\n if (!$fileInput || !($fileInput instanceof HTMLInputElement)) {\n return\n }\n\n $fileInput.value = ''\n this.$fileInput.replaceWith($fileInput)\n\n this.setupFileInput()\n this.$fileInput.focus()\n }\n\n onFileFocus() {\n this.$label.classList.add('moj-multi-file-upload--focused')\n }\n\n onFileBlur() {\n this.$label.classList.remove('moj-multi-file-upload--focused')\n }\n\n /**\n * @param {UploadResponseSuccess['success']} success\n */\n getSuccessHtml(success) {\n return `<span class=\"moj-multi-file-upload__success\"> <svg class=\"moj-banner__icon\" fill=\"currentColor\" role=\"presentation\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 25 25\" height=\"25\" width=\"25\"><path d=\"M25,6.2L8.7,23.2L0,14.1l4-4.2l4.7,4.9L21,2L25,6.2z\"/></svg>${success.messageHtml}</span>`\n }\n\n /**\n * @param {UploadResponseError['error']} error\n */\n getErrorHtml(error) {\n return `<span class=\"moj-multi-file-upload__error\"> <svg class=\"moj-banner__icon\" fill=\"currentColor\" role=\"presentation\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 25 25\" height=\"25\" width=\"25\"><path d=\"M13.6,15.4h-2.3v-4.5h2.3V15.4z M13.6,19.8h-2.3v-2.2h2.3V19.8z M0,23.2h25L12.5,2L0,23.2z\"/></svg>${error.message}</span>`\n }\n\n /**\n * @param {File} file\n */\n getFileRow(file) {\n const $row = document.createElement('div')\n\n $row.classList.add('govuk-summary-list__row', 'moj-multi-file-upload__row')\n\n $row.innerHTML = `\n <div class=\"govuk-summary-list__value moj-multi-file-upload__message\">\n <span class=\"moj-multi-file-upload__filename\">${file.name}</span>\n <span class=\"moj-multi-file-upload__progress\">0%</span>\n </div>\n <div class=\"govuk-summary-list__actions moj-multi-file-upload__actions\"></div>\n `\n\n return $row\n }\n\n /**\n * @param {UploadResponseFile} file\n */\n getDeleteButton(file) {\n const $button = document.createElement('button')\n\n $button.setAttribute('type', 'button')\n $button.setAttribute('name', 'delete')\n $button.setAttribute('value', file.filename)\n\n $button.classList.add(\n 'moj-multi-file-upload__delete',\n 'govuk-button',\n 'govuk-button--secondary',\n 'govuk-!-margin-bottom-0'\n )\n\n $button.innerHTML = `Delete <span class=\"govuk-visually-hidden\">${file.originalname}</span>`\n\n return $button\n }\n\n /**\n * @param {File} file\n */\n uploadFile(file) {\n this.config.hooks.entryHook(this, file)\n\n const $item = this.getFileRow(file)\n const $message = $item.querySelector('.moj-multi-file-upload__message')\n const $actions = $item.querySelector('.moj-multi-file-upload__actions')\n const $progress = $item.querySelector('.moj-multi-file-upload__progress')\n\n const formData = new FormData()\n formData.append('documents', file)\n\n this.$feedbackContainer\n .querySelector('.moj-multi-file-upload__list')\n .append($item)\n\n const xhr = new XMLHttpRequest()\n\n const onLoad = () => {\n if (\n xhr.status < 200 ||\n xhr.status >= 300 ||\n !('success' in xhr.response)\n ) {\n return onError()\n }\n\n $message.innerHTML = this.getSuccessHtml(xhr.response.success)\n this.$status.textContent = xhr.response.success.messageText\n\n $actions.append(this.getDeleteButton(xhr.response.file))\n this.config.hooks.exitHook(this, file, xhr, xhr.responseText)\n }\n\n const onError = () => {\n const error = new Error(\n xhr.response && 'error' in xhr.response\n ? xhr.response.error.message\n : xhr.statusText || 'Upload failed'\n )\n\n $message.innerHTML = this.getErrorHtml(error)\n this.$status.textContent = error.message\n\n this.config.hooks.errorHook(this, file, xhr, xhr.responseText, error)\n }\n\n xhr.addEventListener('load', onLoad)\n xhr.addEventListener('error', onError)\n\n xhr.upload.addEventListener('progress', (event) => {\n if (!event.lengthComputable) {\n return\n }\n\n const percentComplete = Math.round((event.loaded / event.total) * 100)\n $progress.textContent = ` ${percentComplete}%`\n })\n\n xhr.open('POST', this.config.uploadUrl)\n xhr.responseType = 'json'\n\n xhr.send(formData)\n }\n\n /**\n * @param {MouseEvent} event - Click event\n */\n onFileDeleteClick(event) {\n const $button = event.target\n\n if (\n !$button ||\n !($button instanceof HTMLButtonElement) ||\n !$button.classList.contains('moj-multi-file-upload__delete')\n ) {\n return\n }\n\n event.preventDefault() // if user refreshes page and then deletes\n\n const xhr = new XMLHttpRequest()\n\n xhr.addEventListener('load', () => {\n if (xhr.status < 200 || xhr.status >= 300) {\n return\n }\n\n const $rows = Array.from(\n this.$feedbackContainer.querySelectorAll('.moj-multi-file-upload__row')\n )\n\n if ($rows.length === 1) {\n this.$feedbackContainer.classList.add('moj-hidden')\n }\n\n const $rowDelete = $rows.find(($row) => $row.contains($button))\n if ($rowDelete) $rowDelete.remove()\n\n this.config.hooks.deleteHook(this, undefined, xhr, xhr.responseText)\n })\n\n xhr.open('POST', this.config.deleteUrl)\n xhr.setRequestHeader('Content-Type', 'application/json')\n xhr.responseType = 'json'\n\n xhr.send(\n JSON.stringify({\n [$button.name]: $button.value\n })\n )\n }\n\n static isSupported() {\n return (\n this.isDragAndDropSupported() &&\n this.isFormDataSupported() &&\n this.isFileApiSupported()\n )\n }\n\n static isDragAndDropSupported() {\n const div = document.createElement('div')\n return typeof div.ondrop !== 'undefined'\n }\n\n static isFormDataSupported() {\n return typeof FormData === 'function'\n }\n\n static isFileApiSupported() {\n const input = document.createElement('input')\n input.type = 'file'\n return typeof input.files !== 'undefined'\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'moj-multi-file-upload'\n\n /**\n * Multi file upload default config\n *\n * @type {MultiFileUploadConfig}\n */\n static defaults = Object.freeze({\n uploadStatusText: 'Uploading files, please wait',\n dropzoneHintText: 'Drag and drop files here or',\n dropzoneButtonText: 'Choose files',\n feedbackContainer: {\n selector: '.moj-multi-file__uploaded-files'\n },\n hooks: {\n entryHook: () => {},\n exitHook: () => {},\n errorHook: () => {},\n deleteHook: () => {}\n }\n })\n\n /**\n * Multi file upload config schema\n *\n * @satisfies {Schema<MultiFileUploadConfig>}\n */\n static schema = Object.freeze(\n /** @type {const} */ ({\n properties: {\n uploadUrl: { type: 'string' },\n deleteUrl: { type: 'string' },\n uploadStatusText: { type: 'string' },\n dropzoneHintText: { type: 'string' },\n dropzoneButtonText: { type: 'string' },\n feedbackContainer: { type: 'object' },\n hooks: { type: 'object' }\n }\n })\n )\n}\n\n/**\n * Multi file upload config\n *\n * @typedef {object} MultiFileUploadConfig\n * @property {string} [uploadUrl] - File upload URL\n * @property {string} [deleteUrl] - File delete URL\n * @property {string} [uploadStatusText] - Upload status text\n * @property {string} [dropzoneHintText] - Dropzone hint text\n * @property {string} [dropzoneButtonText] - Dropzone button text\n * @property {object} [feedbackContainer] - Feedback container config\n * @property {string} [feedbackContainer.selector] - Selector for feedback container\n * @property {Element | null} [feedbackContainer.element] - HTML element for feedback container\n * @property {MultiFileUploadHooks} [hooks] - Upload hooks\n */\n\n/**\n * Multi file upload hooks\n *\n * @typedef {object} MultiFileUploadHooks\n * @property {OnUploadFileEntryHook} [entryHook] - File upload entry hook\n * @property {OnUploadFileExitHook} [exitHook] - File upload exit hook\n * @property {OnUploadFileErrorHook} [errorHook] - File upload error hook\n * @property {OnUploadFileDeleteHook} [deleteHook] - File delete hook\n */\n\n/**\n * Upload hook: File entry\n *\n * @callback OnUploadFileEntryHook\n * @param {InstanceType<typeof MultiFileUpload>} upload - Multi file upload\n * @param {File} file - File upload\n */\n\n/**\n * Upload hook: File exit\n *\n * @callback OnUploadFileExitHook\n * @param {InstanceType<typeof MultiFileUpload>} upload - Multi file upload\n * @param {File} file - File upload\n * @param {XMLHttpRequest} xhr - XMLHttpRequest\n * @param {string} textStatus - Text status\n */\n\n/**\n * Upload hook: File error\n *\n * @callback OnUploadFileErrorHook\n * @param {InstanceType<typeof MultiFileUpload>} upload - Multi file upload\n * @param {File} file - File upload\n * @param {XMLHttpRequest} xhr - XMLHttpRequest\n * @param {string} textStatus - Text status\n * @param {Error} errorThrown - Error thrown\n */\n\n/**\n * Upload hook: File delete\n *\n * @callback OnUploadFileDeleteHook\n * @param {InstanceType<typeof MultiFileUpload>} upload - Multi file upload\n * @param {File} [file] - File upload\n * @param {XMLHttpRequest} xhr - XMLHttpRequest\n * @param {string} textStatus - Text status\n */\n\n/**\n * @typedef {object} UploadResponseSuccess\n * @property {{ messageText: string, messageHtml: string }} success - Response success\n * @property {UploadResponseFile} file - Response file\n */\n\n/**\n * @typedef {object} UploadResponseError\n * @property {{ message: string }} error - Response error\n * @property {UploadResponseFile} file - Response file\n */\n\n/**\n * @typedef {object} UploadResponseFile\n * @property {string} filename - File name\n * @property {string} originalname - Original file name\n */\n\n/**\n * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'\n */\n"],"names":["MultiFileUpload","ConfigurableComponent","constructor","$root","config","_this$config$feedback","isSupported","$feedbackContainer","feedbackContainer","element","querySelector","selector","HTMLElement","setupFileInput","setupDropzone","setupLabel","setupStatusBox","addEventListener","onFileDeleteClick","bind","classList","add","$dropzone","document","createElement","onDragOver","onDragLeave","onDrop","$fileInput","replaceWith","appendChild","$label","setAttribute","id","textContent","dropzoneButtonText","$hint","dropzoneHintText","append","onFileChange","onFileFocus","onFileBlur","$status","event","preventDefault","remove","uploadStatusText","uploadFiles","dataTransfer","files","file","Array","from","uploadFile","cloneNode","HTMLInputElement","value","focus","getSuccessHtml","success","messageHtml","getErrorHtml","error","message","getFileRow","$row","innerHTML","name","getDeleteButton","$button","filename","originalname","hooks","entryHook","$item","$message","$actions","$progress","formData","FormData","xhr","XMLHttpRequest","onLoad","status","response","onError","messageText","exitHook","responseText","Error","statusText","errorHook","upload","lengthComputable","percentComplete","Math","round","loaded","total","open","uploadUrl","responseType","send","target","HTMLButtonElement","contains","$rows","querySelectorAll","length","$rowDelete","find","deleteHook","undefined","deleteUrl","setRequestHeader","JSON","stringify","isDragAndDropSupported","isFormDataSupported","isFileApiSupported","div","ondrop","input","type","moduleName","defaults","Object","freeze","schema","properties"],"mappings":"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"}
|