@ministryofjustice/frontend 3.3.0 → 3.4.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 (87) hide show
  1. package/README.md +4 -10
  2. package/govuk-prototype-kit.config.json +5 -16
  3. package/moj/all.jquery.min.js +77 -3
  4. package/moj/all.js +2022 -1444
  5. package/moj/all.scss +2 -0
  6. package/moj/all.spec.js +15 -13
  7. package/moj/components/_all.scss +1 -0
  8. package/moj/components/action-bar/_action-bar.scss +4 -6
  9. package/moj/components/add-another/_add-another.scss +9 -7
  10. package/moj/components/add-another/add-another.js +90 -69
  11. package/moj/components/add-another/add-another.spec.js +165 -0
  12. package/moj/components/alert/README.md +0 -0
  13. package/moj/components/alert/_alert.scss +142 -0
  14. package/moj/components/alert/alert.js +247 -0
  15. package/moj/components/alert/alert.spec.helper.js +67 -0
  16. package/moj/components/alert/alert.spec.js +229 -0
  17. package/moj/components/alert/macro.njk +3 -0
  18. package/moj/components/alert/template.njk +83 -0
  19. package/moj/components/badge/_badge.scss +3 -4
  20. package/moj/components/banner/_banner.scss +5 -10
  21. package/moj/components/button-menu/_button-menu.scss +10 -9
  22. package/moj/components/button-menu/button-menu.js +139 -136
  23. package/moj/components/button-menu/button-menu.spec.js +295 -296
  24. package/moj/components/cookie-banner/_cookie-banner.scss +6 -5
  25. package/moj/components/currency-input/_currency-input.scss +4 -4
  26. package/moj/components/date-picker/README.md +14 -17
  27. package/moj/components/date-picker/_date-picker.scss +122 -106
  28. package/moj/components/date-picker/date-picker.js +473 -471
  29. package/moj/components/date-picker/date-picker.spec.js +962 -914
  30. package/moj/components/filter/README.md +1 -1
  31. package/moj/components/filter/_filter.scss +53 -75
  32. package/moj/components/filter-toggle-button/filter-toggle-button.js +71 -67
  33. package/moj/components/filter-toggle-button/filter-toggle-button.spec.js +203 -205
  34. package/moj/components/form-validator/form-validator.js +117 -109
  35. package/moj/components/header/_header.scss +17 -19
  36. package/moj/components/identity-bar/_identity-bar.scss +5 -5
  37. package/moj/components/interruption-card/_interruption-card.scss +9 -2
  38. package/moj/components/messages/_messages.scss +12 -19
  39. package/moj/components/multi-file-upload/README.md +1 -1
  40. package/moj/components/multi-file-upload/_multi-file-upload.scss +34 -30
  41. package/moj/components/multi-file-upload/multi-file-upload.js +188 -152
  42. package/moj/components/multi-file-upload/multi-file-upload.spec.js +510 -0
  43. package/moj/components/multi-select/_multi-select.scss +4 -3
  44. package/moj/components/multi-select/multi-select.js +55 -50
  45. package/moj/components/multi-select/multi-select.spec.js +128 -0
  46. package/moj/components/notification-badge/_notification-badge.scss +12 -12
  47. package/moj/components/organisation-switcher/_organisation-switcher.scss +1 -1
  48. package/moj/components/page-header-actions/_page-header-actions.scss +3 -2
  49. package/moj/components/pagination/_pagination.scss +26 -31
  50. package/moj/components/password-reveal/_password-reveal.scss +1 -2
  51. package/moj/components/password-reveal/password-reveal.js +22 -21
  52. package/moj/components/password-reveal/password-reveal.spec.js +39 -37
  53. package/moj/components/primary-navigation/_primary-navigation.scss +26 -29
  54. package/moj/components/progress-bar/_progress-bar.scss +21 -26
  55. package/moj/components/rich-text-editor/_rich-text-editor.scss +17 -16
  56. package/moj/components/rich-text-editor/rich-text-editor.js +117 -103
  57. package/moj/components/search/_search.scss +6 -4
  58. package/moj/components/search-toggle/search-toggle.js +29 -30
  59. package/moj/components/search-toggle/search-toggle.scss +21 -15
  60. package/moj/components/search-toggle/search-toggle.spec.js +129 -0
  61. package/moj/components/side-navigation/_side-navigation.scss +12 -21
  62. package/moj/components/sortable-table/_sortable-table.scss +25 -23
  63. package/moj/components/sortable-table/sortable-table.js +139 -117
  64. package/moj/components/sortable-table/sortable-table.spec.js +362 -0
  65. package/moj/components/sub-navigation/_sub-navigation.scss +24 -28
  66. package/moj/components/tag/_tag.scss +8 -9
  67. package/moj/components/task-list/_task-list.scss +8 -7
  68. package/moj/components/ticket-panel/_ticket-panel.scss +14 -6
  69. package/moj/components/timeline/_timeline.scss +18 -20
  70. package/moj/filters/all.js +28 -30
  71. package/moj/filters/prototype-kit-13-filters.js +2 -1
  72. package/moj/helpers/_all.scss +1 -0
  73. package/moj/helpers/_hidden.scss +1 -1
  74. package/moj/helpers/_links.scss +20 -0
  75. package/moj/helpers.js +160 -31
  76. package/moj/helpers.spec.js +235 -0
  77. package/moj/init.js +2 -2
  78. package/moj/moj-frontend.min.css +2 -2
  79. package/moj/moj-frontend.min.js +77 -3
  80. package/moj/namespace.js +2 -1
  81. package/moj/objects/_filter-layout.scss +11 -10
  82. package/moj/objects/_scrollable-pane.scss +11 -14
  83. package/moj/settings/_colours.scss +5 -0
  84. package/moj/settings/_measurements.scss +0 -2
  85. package/moj/utilities/_hidden.scss +3 -3
  86. package/moj/utilities/_width-container.scss +1 -1
  87. package/package.json +1 -1
@@ -1,5 +1,9 @@
1
- if(MOJFrontend.dragAndDropSupported() && MOJFrontend.formDataSupported() && MOJFrontend.fileApiSupported()) {
2
- MOJFrontend.MultiFileUpload = function(params) {
1
+ if (
2
+ MOJFrontend.dragAndDropSupported() &&
3
+ MOJFrontend.formDataSupported() &&
4
+ MOJFrontend.fileApiSupported()
5
+ ) {
6
+ MOJFrontend.MultiFileUpload = function (params) {
3
7
  this.defaultParams = {
4
8
  uploadFileEntryHook: $.noop,
5
9
  uploadFileExitHook: $.noop,
@@ -8,120 +12,131 @@ if(MOJFrontend.dragAndDropSupported() && MOJFrontend.formDataSupported() && MOJF
8
12
  uploadStatusText: 'Uploading files, please wait',
9
13
  dropzoneHintText: 'Drag and drop files here or',
10
14
  dropzoneButtonText: 'Choose files'
11
- };
12
-
13
- this.params = $.extend({}, this.defaultParams, params);
14
- this.container = $(this.params.container);
15
-
16
- this.container.addClass('moj-multi-file-upload--enhanced');
17
-
18
- this.feedbackContainer = this.container.find('.moj-multi-file__uploaded-files');
19
- this.setupFileInput();
20
- this.setupDropzone();
21
- this.setupLabel();
22
- this.setupStatusBox();
23
- this.container.on('click', '.moj-multi-file-upload__delete', $.proxy(this, 'onFileDeleteClick'));
24
- };
25
-
26
- MOJFrontend.MultiFileUpload.prototype.setupDropzone = function() {
27
- this.fileInput.wrap('<div class="moj-multi-file-upload__dropzone" />');
28
- this.dropzone = this.container.find('.moj-multi-file-upload__dropzone');
29
- this.dropzone.on('dragover', $.proxy(this, 'onDragOver'));
30
- this.dropzone.on('dragleave', $.proxy(this, 'onDragLeave'));
31
- this.dropzone.on('drop', $.proxy(this, 'onDrop'));
32
- };
33
-
34
- MOJFrontend.MultiFileUpload.prototype.setupLabel = function() {
35
- this.label = $('<label for="'+this.fileInput[0].id+'" class="govuk-button govuk-button--secondary">'+ this.params.dropzoneButtonText +'</label>');
36
- this.dropzone.append('<p class="govuk-body">' + this.params.dropzoneHintText + '</p>');
37
- this.dropzone.append(this.label);
38
- };
39
-
40
- MOJFrontend.MultiFileUpload.prototype.setupFileInput = function() {
41
- this.fileInput = this.container.find('.moj-multi-file-upload__input');
42
- this.fileInput.on('change', $.proxy(this, 'onFileChange'));
43
- this.fileInput.on('focus', $.proxy(this, 'onFileFocus'));
44
- this.fileInput.on('blur', $.proxy(this, 'onFileBlur'));
45
- };
46
-
47
- MOJFrontend.MultiFileUpload.prototype.setupStatusBox = function() {
48
- this.status = $('<div aria-live="polite" role="status" class="govuk-visually-hidden" />');
49
- this.dropzone.append(this.status);
50
- };
51
-
52
- MOJFrontend.MultiFileUpload.prototype.onDragOver = function(e) {
53
- e.preventDefault();
54
- this.dropzone.addClass('moj-multi-file-upload--dragover');
55
- };
56
-
57
- MOJFrontend.MultiFileUpload.prototype.onDragLeave = function() {
58
- this.dropzone.removeClass('moj-multi-file-upload--dragover');
59
- };
60
-
61
- MOJFrontend.MultiFileUpload.prototype.onDrop = function(e) {
62
- e.preventDefault();
63
- this.dropzone.removeClass('moj-multi-file-upload--dragover');
64
- this.feedbackContainer.removeClass('moj-hidden');
65
- this.status.html(this.params.uploadStatusText);
66
- this.uploadFiles(e.originalEvent.dataTransfer.files);
67
- };
68
-
69
- MOJFrontend.MultiFileUpload.prototype.uploadFiles = function(files) {
70
- for(var i = 0; i < files.length; i++) {
71
- this.uploadFile(files[i]);
72
15
  }
73
- };
74
-
75
- MOJFrontend.MultiFileUpload.prototype.onFileChange = function(e) {
76
- this.feedbackContainer.removeClass('moj-hidden');
77
- this.status.html(this.params.uploadStatusText);
78
- this.uploadFiles(e.currentTarget.files);
79
- this.fileInput.replaceWith($(e.currentTarget).val('').clone(true));
80
- this.setupFileInput();
81
- this.fileInput.focus();
82
- };
83
-
84
- MOJFrontend.MultiFileUpload.prototype.onFileFocus = function(e) {
85
- this.label.addClass('moj-multi-file-upload--focused');
86
- };
87
-
88
- MOJFrontend.MultiFileUpload.prototype.onFileBlur = function(e) {
89
- this.label.removeClass('moj-multi-file-upload--focused');
90
- };
91
-
92
- MOJFrontend.MultiFileUpload.prototype.getSuccessHtml = function(success) {
93
- 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>';
94
- };
95
-
96
- MOJFrontend.MultiFileUpload.prototype.getErrorHtml = function(error) {
97
- 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>';
98
- };
99
-
100
- MOJFrontend.MultiFileUpload.prototype.getFileRowHtml = function(file) {
101
- var html = '';
102
- html += '<div class="govuk-summary-list__row moj-multi-file-upload__row">';
103
- html += ' <div class="govuk-summary-list__value moj-multi-file-upload__message">';
104
- html += '<span class="moj-multi-file-upload__filename">'+file.name+'</span>';
105
- html += '<span class="moj-multi-file-upload__progress">0%</span>';
106
- html += ' </div>';
107
- html += ' <div class="govuk-summary-list__actions moj-multi-file-upload__actions"></div>';
108
- html += '</div>';
109
- return html;
110
- };
111
-
112
- MOJFrontend.MultiFileUpload.prototype.getDeleteButtonHtml = function(file) {
113
- var html = '<button class="moj-multi-file-upload__delete govuk-button govuk-button--secondary govuk-!-margin-bottom-0" type="button" name="delete" value="' + file.filename + '">';
114
- html += 'Delete <span class="govuk-visually-hidden">' + file.originalname + '</span>';
115
- html += '</button>';
116
- return html;
117
- };
118
-
119
- MOJFrontend.MultiFileUpload.prototype.uploadFile = function(file) {
120
- this.params.uploadFileEntryHook(this, file);
121
- var formData = new FormData();
122
- formData.append('documents', file);
123
- var item = $(this.getFileRowHtml(file));
124
- this.feedbackContainer.find('.moj-multi-file-upload__list').append(item);
16
+
17
+ this.params = $.extend({}, this.defaultParams, params)
18
+ this.container = $(this.params.container)
19
+
20
+ this.container.addClass('moj-multi-file-upload--enhanced')
21
+
22
+ this.feedbackContainer = this.container.find(
23
+ '.moj-multi-file__uploaded-files'
24
+ )
25
+ this.setupFileInput()
26
+ this.setupDropzone()
27
+ this.setupLabel()
28
+ this.setupStatusBox()
29
+ this.container.on(
30
+ 'click',
31
+ '.moj-multi-file-upload__delete',
32
+ $.proxy(this, 'onFileDeleteClick')
33
+ )
34
+ }
35
+
36
+ MOJFrontend.MultiFileUpload.prototype.setupDropzone = function () {
37
+ this.fileInput.wrap('<div class="moj-multi-file-upload__dropzone" />')
38
+ this.dropzone = this.container.find('.moj-multi-file-upload__dropzone')
39
+ this.dropzone.on('dragover', $.proxy(this, 'onDragOver'))
40
+ this.dropzone.on('dragleave', $.proxy(this, 'onDragLeave'))
41
+ this.dropzone.on('drop', $.proxy(this, 'onDrop'))
42
+ }
43
+
44
+ MOJFrontend.MultiFileUpload.prototype.setupLabel = function () {
45
+ this.label = $(
46
+ `<label for="${this.fileInput[0].id}" class="govuk-button govuk-button--secondary">${this.params.dropzoneButtonText}</label>`
47
+ )
48
+ this.dropzone.append(
49
+ `<p class="govuk-body">${this.params.dropzoneHintText}</p>`
50
+ )
51
+ this.dropzone.append(this.label)
52
+ }
53
+
54
+ MOJFrontend.MultiFileUpload.prototype.setupFileInput = function () {
55
+ this.fileInput = this.container.find('.moj-multi-file-upload__input')
56
+ this.fileInput.on('change', $.proxy(this, 'onFileChange'))
57
+ this.fileInput.on('focus', $.proxy(this, 'onFileFocus'))
58
+ this.fileInput.on('blur', $.proxy(this, 'onFileBlur'))
59
+ }
60
+
61
+ MOJFrontend.MultiFileUpload.prototype.setupStatusBox = function () {
62
+ this.status = $(
63
+ '<div aria-live="polite" role="status" class="govuk-visually-hidden" />'
64
+ )
65
+ this.dropzone.append(this.status)
66
+ }
67
+
68
+ MOJFrontend.MultiFileUpload.prototype.onDragOver = function (e) {
69
+ e.preventDefault()
70
+ this.dropzone.addClass('moj-multi-file-upload--dragover')
71
+ }
72
+
73
+ MOJFrontend.MultiFileUpload.prototype.onDragLeave = function () {
74
+ this.dropzone.removeClass('moj-multi-file-upload--dragover')
75
+ }
76
+
77
+ MOJFrontend.MultiFileUpload.prototype.onDrop = function (e) {
78
+ e.preventDefault()
79
+ this.dropzone.removeClass('moj-multi-file-upload--dragover')
80
+ this.feedbackContainer.removeClass('moj-hidden')
81
+ this.status.html(this.params.uploadStatusText)
82
+ this.uploadFiles(e.originalEvent.dataTransfer.files)
83
+ }
84
+
85
+ MOJFrontend.MultiFileUpload.prototype.uploadFiles = function (files) {
86
+ for (let i = 0; i < files.length; i++) {
87
+ this.uploadFile(files[i])
88
+ }
89
+ }
90
+
91
+ MOJFrontend.MultiFileUpload.prototype.onFileChange = function (e) {
92
+ this.feedbackContainer.removeClass('moj-hidden')
93
+ this.status.html(this.params.uploadStatusText)
94
+ this.uploadFiles(e.currentTarget.files)
95
+ this.fileInput.replaceWith($(e.currentTarget).val('').clone(true))
96
+ this.setupFileInput()
97
+ this.fileInput.get(0).focus()
98
+ }
99
+
100
+ MOJFrontend.MultiFileUpload.prototype.onFileFocus = function (e) {
101
+ this.label.addClass('moj-multi-file-upload--focused')
102
+ }
103
+
104
+ MOJFrontend.MultiFileUpload.prototype.onFileBlur = function (e) {
105
+ this.label.removeClass('moj-multi-file-upload--focused')
106
+ }
107
+
108
+ MOJFrontend.MultiFileUpload.prototype.getSuccessHtml = function (success) {
109
+ 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>`
110
+ }
111
+
112
+ MOJFrontend.MultiFileUpload.prototype.getErrorHtml = function (error) {
113
+ 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>`
114
+ }
115
+
116
+ MOJFrontend.MultiFileUpload.prototype.getFileRowHtml = function (file) {
117
+ const html = `
118
+ <div class="govuk-summary-list__row moj-multi-file-upload__row">;
119
+ <div class="govuk-summary-list__value moj-multi-file-upload__message">;
120
+ <span class="moj-multi-file-upload__filename">${file.name}</span>;
121
+ <span class="moj-multi-file-upload__progress">0%</span>;
122
+ </div>';
123
+ <div class="govuk-summary-list__actions moj-multi-file-upload__actions"></div>;
124
+ </div>`
125
+ return html
126
+ }
127
+
128
+ MOJFrontend.MultiFileUpload.prototype.getDeleteButtonHtml = function (file) {
129
+ return `<button class="moj-multi-file-upload__delete govuk-button govuk-button--secondary govuk-!-margin-bottom-0" type="button" name="delete" value="${file.filename}">
130
+ Delete <span class="govuk-visually-hidden">${file.originalname}</span>
131
+ </button>`
132
+ }
133
+
134
+ MOJFrontend.MultiFileUpload.prototype.uploadFile = function (file) {
135
+ this.params.uploadFileEntryHook(this, file)
136
+ const item = $(this.getFileRowHtml(file))
137
+ const formData = new FormData()
138
+ formData.append('documents', file)
139
+ this.feedbackContainer.find('.moj-multi-file-upload__list').append(item)
125
140
 
126
141
  $.ajax({
127
142
  url: this.params.uploadUrl,
@@ -129,55 +144,76 @@ if(MOJFrontend.dragAndDropSupported() && MOJFrontend.formDataSupported() && MOJF
129
144
  data: formData,
130
145
  processData: false,
131
146
  contentType: false,
132
- success: $.proxy(function(response){
133
- if(response.error) {
134
- item.find('.moj-multi-file-upload__message').html(this.getErrorHtml(response.error));
135
- this.status.html(response.error.message);
147
+ success: $.proxy(function (response) {
148
+ if (response.error) {
149
+ item
150
+ .find('.moj-multi-file-upload__message')
151
+ .html(this.getErrorHtml(response.error))
152
+ this.status.html(response.error.message)
136
153
  } else {
137
- item.find('.moj-multi-file-upload__message').html(this.getSuccessHtml(response.success));
138
- this.status.html(response.success.messageText);
154
+ item
155
+ .find('.moj-multi-file-upload__message')
156
+ .html(this.getSuccessHtml(response.success))
157
+ this.status.html(response.success.messageText)
139
158
  }
140
- item.find('.moj-multi-file-upload__actions').append(this.getDeleteButtonHtml(response.file));
141
- this.params.uploadFileExitHook(this, file, response);
159
+ item
160
+ .find('.moj-multi-file-upload__actions')
161
+ .append(this.getDeleteButtonHtml(response.file))
162
+ this.params.uploadFileExitHook(this, file, response)
142
163
  }, this),
143
- error: $.proxy(function(jqXHR, textStatus, errorThrown) {
144
- this.params.uploadFileErrorHook(this, file, jqXHR, textStatus, errorThrown);
164
+ error: $.proxy(function (jqXHR, textStatus, errorThrown) {
165
+ this.params.uploadFileErrorHook(
166
+ this,
167
+ file,
168
+ jqXHR,
169
+ textStatus,
170
+ errorThrown
171
+ )
145
172
  }, this),
146
- xhr: function() {
147
- var xhr = new XMLHttpRequest();
148
- xhr.upload.addEventListener('progress', function(e) {
149
- if (e.lengthComputable) {
150
- var percentComplete = e.loaded / e.total;
151
- percentComplete = parseInt(percentComplete * 100, 10);
152
- item.find('.moj-multi-file-upload__progress').text(' ' + percentComplete + '%');
153
- }
154
- }, false);
155
- return xhr;
173
+ xhr: function () {
174
+ const xhr = new XMLHttpRequest()
175
+ xhr.upload.addEventListener(
176
+ 'progress',
177
+ function (e) {
178
+ if (e.lengthComputable) {
179
+ let percentComplete = e.loaded / e.total
180
+ percentComplete = parseInt(percentComplete * 100, 10)
181
+ item
182
+ .find('.moj-multi-file-upload__progress')
183
+ .text(` ${percentComplete}%`)
184
+ }
185
+ },
186
+ false
187
+ )
188
+ return xhr
156
189
  }
157
- });
158
- };
159
-
160
- MOJFrontend.MultiFileUpload.prototype.onFileDeleteClick = function(e) {
161
- e.preventDefault(); // if user refreshes page and then deletes
162
- var button = $(e.currentTarget);
163
- var data = {};
164
- data[button[0].name] = button[0].value;
190
+ })
191
+ }
192
+
193
+ MOJFrontend.MultiFileUpload.prototype.onFileDeleteClick = function (e) {
194
+ e.preventDefault() // if user refreshes page and then deletes
195
+ const button = $(e.currentTarget)
196
+ const data = {}
197
+ data[button[0].name] = button[0].value
165
198
  $.ajax({
166
199
  url: this.params.deleteUrl,
167
200
  type: 'post',
168
201
  dataType: 'json',
169
- data: data,
170
- success: $.proxy(function(response){
171
- if(response.error) {
202
+ data,
203
+ success: $.proxy(function (response) {
204
+ if (response.error) {
172
205
  // handle error
173
206
  } else {
174
- button.parents('.moj-multi-file-upload__row').remove();
175
- if(this.feedbackContainer.find('.moj-multi-file-upload__row').length === 0) {
176
- this.feedbackContainer.addClass('moj-hidden');
207
+ button.parents('.moj-multi-file-upload__row').remove()
208
+ if (
209
+ this.feedbackContainer.find('.moj-multi-file-upload__row')
210
+ .length === 0
211
+ ) {
212
+ this.feedbackContainer.addClass('moj-hidden')
177
213
  }
178
214
  }
179
- this.params.fileDeleteHook(this, response);
215
+ this.params.fileDeleteHook(this, response)
180
216
  }, this)
181
- });
182
- };
217
+ })
218
+ }
183
219
  }