@ministryofjustice/hmpps-digital-prison-reporting-frontend 9.2.3 → 9.3.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/_networkMocks/dashboard/definitions/visualisations/complete-dataset/scorecardGroup/definiton-no-ts.d.ts +2 -0
- package/_networkMocks/dashboard/definitions/visualisations/mocks.d.ts +1 -0
- package/all.bundle.js +178 -138
- package/all.bundle.js.map +1 -1
- package/all.js +178 -138
- package/all.js.map +1 -1
- package/cjs/dpr/utils/DataTableBuilder/DataTableBuilder.js +6 -14
- package/cjs/dpr/utils/DataTableBuilder/DataTableBuilder.js.map +1 -1
- package/cypress-tests/cypressUtils.d.ts +15 -0
- package/cypress-tests/mockApis/dashboards.d.ts +1 -0
- package/dpr/all.scss +52 -38
- package/dpr/components/_inputs/autocomplete-text-input/view.njk +57 -75
- package/dpr/components/_reports/report-page/report-template/report-section/report-data-table/view.njk +2 -0
- package/dpr/utils/DataTableBuilder/DataTableBuilder.js +6 -14
- package/dpr/utils/DataTableBuilder/DataTableBuilder.js.map +1 -1
- package/package.json +1 -1
- package/src/dpr/components/_inputs/autocomplete-text-input/clientClass.d.ts +18 -15
- package/src/dpr/utils/DataTableBuilder/DataTableBuilder.d.ts +0 -1
|
@@ -11,6 +11,7 @@ export declare const scorecardsInvalidVisDefinitionsMock: import("@networkMocks/
|
|
|
11
11
|
export declare const scorecardsCompletebadDatasetMock: import("@networkMocks/generateNetworkMock").CompleteMockRequest;
|
|
12
12
|
export declare const scorecardGroupCompleteDatasetMock: import("@networkMocks/generateNetworkMock").CompleteMockRequest;
|
|
13
13
|
export declare const scorecardGroupCompleteDatasetInvalidMock: import("@networkMocks/generateNetworkMock").CompleteMockRequest;
|
|
14
|
+
export declare const scorecardGroupCompleteDatasetNoTsMock: import("@networkMocks/generateNetworkMock").CompleteMockRequest;
|
|
14
15
|
export declare const matrixCompleteDatasetMock: import("@networkMocks/generateNetworkMock").CompleteMockRequest;
|
|
15
16
|
export declare const barCompleteDatasetMock: import("@networkMocks/generateNetworkMock").CompleteMockRequest;
|
|
16
17
|
export declare const barPartialDatasetMock: import("@networkMocks/generateNetworkMock").CompleteMockRequest;
|
package/all.bundle.js
CHANGED
|
@@ -780,8 +780,8 @@ class DprFiltersFormClass extends DprClientClass {
|
|
|
780
780
|
updateSingle(params, input) {
|
|
781
781
|
const name = this.normaliseFilterName(input.name);
|
|
782
782
|
let value = input.value;
|
|
783
|
-
if (input instanceof HTMLInputElement && input.dataset['
|
|
784
|
-
value = input.dataset['
|
|
783
|
+
if (input instanceof HTMLInputElement && input.dataset['selectedValue']) {
|
|
784
|
+
value = input.dataset['selectedValue'];
|
|
785
785
|
}
|
|
786
786
|
const isDateInput = input instanceof HTMLInputElement && input.classList.contains('moj-js-datepicker-input');
|
|
787
787
|
if (isDateInput) {
|
|
@@ -1118,183 +1118,223 @@ class AutoCompleteMulti extends DprClientClass {
|
|
|
1118
1118
|
}
|
|
1119
1119
|
}
|
|
1120
1120
|
|
|
1121
|
-
/* eslint-disable class-methods-use-this */
|
|
1122
1121
|
class Autocomplete extends DprClientClass {
|
|
1123
|
-
|
|
1124
|
-
listParentSelector;
|
|
1122
|
+
activeIndex = -1;
|
|
1125
1123
|
static getModuleName() {
|
|
1126
1124
|
return 'autocomplete-text-input';
|
|
1127
1125
|
}
|
|
1128
|
-
constructor(element) {
|
|
1129
|
-
super(element);
|
|
1130
|
-
const listId = this.getTextInput()?.getAttribute('aria-owns');
|
|
1131
|
-
this.listItemsSelector = `#${listId} li`;
|
|
1132
|
-
this.listParentSelector = `#${listId} ul`;
|
|
1133
|
-
}
|
|
1134
1126
|
initialise() {
|
|
1135
1127
|
const textInput = this.getTextInput();
|
|
1136
|
-
textInput
|
|
1137
|
-
|
|
1128
|
+
if (!textInput) {
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
this.initialiseDefaultValue();
|
|
1132
|
+
textInput.addEventListener('input', () => {
|
|
1133
|
+
this.onInput();
|
|
1138
1134
|
});
|
|
1139
|
-
textInput
|
|
1140
|
-
|
|
1141
|
-
e.stopPropagation();
|
|
1142
|
-
e.preventDefault();
|
|
1143
|
-
}
|
|
1135
|
+
textInput.addEventListener('keydown', event => {
|
|
1136
|
+
this.onKeyDown(event);
|
|
1144
1137
|
});
|
|
1145
|
-
textInput
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
}
|
|
1149
|
-
const hiddenInput = this.getHiddenInput();
|
|
1150
|
-
if (hiddenInput) {
|
|
1151
|
-
hiddenInput.value = '';
|
|
1152
|
-
hiddenInput.disabled = true;
|
|
1153
|
-
}
|
|
1154
|
-
delete textInput.dataset['staticOptionNameValue'];
|
|
1155
|
-
textInput.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1138
|
+
textInput.addEventListener('blur', () => {
|
|
1139
|
+
window.setTimeout(() => {
|
|
1140
|
+
this.closeList();
|
|
1141
|
+
}, 100);
|
|
1156
1142
|
});
|
|
1157
|
-
this.
|
|
1158
|
-
.
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
this.onOptionClick(event, textInput, this.getElement());
|
|
1143
|
+
this.getAllOptions().forEach(option => {
|
|
1144
|
+
option.addEventListener('mousedown', event => {
|
|
1145
|
+
event.preventDefault();
|
|
1146
|
+
this.selectOption(option);
|
|
1162
1147
|
});
|
|
1163
1148
|
});
|
|
1164
|
-
|
|
1149
|
+
textInput.addEventListener('focus', () => {
|
|
1150
|
+
const minimumLength = Number(textInput.dataset['minimumLength'] || 0);
|
|
1151
|
+
if (minimumLength === 0) {
|
|
1152
|
+
this.filterOptions('');
|
|
1153
|
+
}
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
getTextInput() {
|
|
1157
|
+
return this.getElement().querySelector('.autocomplete-text-input-box');
|
|
1165
1158
|
}
|
|
1166
|
-
|
|
1159
|
+
getHiddenInput() {
|
|
1160
|
+
return this.getElement().querySelector('[data-autocomplete-hidden]');
|
|
1161
|
+
}
|
|
1162
|
+
getAllOptions() {
|
|
1163
|
+
return Array.from(this.getElement().querySelectorAll('.autocomplete-option'));
|
|
1164
|
+
}
|
|
1165
|
+
getVisibleOptions() {
|
|
1166
|
+
return this.getAllOptions().filter(option => !option.classList.contains('autocomplete-text-input-item-hide'));
|
|
1167
|
+
}
|
|
1168
|
+
initialiseDefaultValue() {
|
|
1167
1169
|
const hiddenInput = this.getHiddenInput();
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
+
const textInput = this.getTextInput();
|
|
1171
|
+
if (!hiddenInput || !textInput) {
|
|
1170
1172
|
return;
|
|
1171
1173
|
}
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
}
|
|
1175
|
-
delete textInput?.dataset['staticOptionNameValue'];
|
|
1176
|
-
if (hiddenInput) {
|
|
1177
|
-
hiddenInput.value = '';
|
|
1174
|
+
const selectedValue = hiddenInput.value;
|
|
1175
|
+
if (!selectedValue) {
|
|
1178
1176
|
hiddenInput.disabled = true;
|
|
1177
|
+
return;
|
|
1179
1178
|
}
|
|
1179
|
+
hiddenInput.disabled = false;
|
|
1180
|
+
const matchingOption = this.getAllOptions().find(option => option.dataset['value'] === selectedValue);
|
|
1181
|
+
if (!matchingOption) {
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
textInput.value = matchingOption.dataset['display'] ?? matchingOption.textContent?.trim() ?? '';
|
|
1185
|
+
textInput.dataset['selectedValue'] = selectedValue;
|
|
1180
1186
|
}
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
const searchValue =
|
|
1188
|
-
if (
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1187
|
+
onInput() {
|
|
1188
|
+
const textInput = this.getTextInput();
|
|
1189
|
+
if (!textInput) {
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
this.clearSelection();
|
|
1193
|
+
const searchValue = textInput.value.trim().toLowerCase();
|
|
1194
|
+
if (!searchValue) {
|
|
1195
|
+
this.closeList();
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
this.filterOptions(searchValue);
|
|
1199
|
+
}
|
|
1200
|
+
filterOptions(searchValue) {
|
|
1201
|
+
const minimumLength = Number(this.getTextInput()?.dataset['minimumLength'] || 0);
|
|
1202
|
+
let visibleCount = 0;
|
|
1203
|
+
this.getAllOptions().forEach(option => {
|
|
1204
|
+
const display = option.dataset['display']?.toLowerCase() ?? '';
|
|
1205
|
+
const value = option.dataset['value']?.toLowerCase() ?? '';
|
|
1206
|
+
const matches = searchValue.length === 0
|
|
1207
|
+
? true
|
|
1208
|
+
: searchValue.length >= minimumLength && (display.includes(searchValue) || value.includes(searchValue));
|
|
1209
|
+
option.classList.toggle('autocomplete-text-input-item-hide', !matches);
|
|
1210
|
+
option.classList.remove('autocomplete-option-selected');
|
|
1211
|
+
option.setAttribute('aria-selected', 'false');
|
|
1212
|
+
if (matches) {
|
|
1213
|
+
visibleCount += 1;
|
|
1195
1214
|
}
|
|
1215
|
+
});
|
|
1216
|
+
this.activeIndex = -1;
|
|
1217
|
+
if (visibleCount > 0) {
|
|
1218
|
+
this.openList();
|
|
1196
1219
|
}
|
|
1197
1220
|
else {
|
|
1198
|
-
this.
|
|
1199
|
-
.querySelectorAll(this.listItemsSelector)
|
|
1200
|
-
.forEach(item => {
|
|
1201
|
-
if (searchValue.length >= minLength &&
|
|
1202
|
-
this.isMatchingStaticOptionNameOrDisplayPrefix(this.getInputListButton(item), searchValue, item)) {
|
|
1203
|
-
item.classList.remove('autocomplete-text-input-item-hide');
|
|
1204
|
-
}
|
|
1205
|
-
else {
|
|
1206
|
-
item.classList.add('autocomplete-text-input-item-hide');
|
|
1207
|
-
}
|
|
1208
|
-
});
|
|
1221
|
+
this.closeList();
|
|
1209
1222
|
}
|
|
1210
|
-
if (searchValue.length === 0) {
|
|
1211
|
-
const changeEvent = new Event('change');
|
|
1212
|
-
textInput.dispatchEvent(changeEvent);
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
getInputListButton(item) {
|
|
1216
|
-
return item.querySelector('.autocomplete-text-input-list-button');
|
|
1217
1223
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1224
|
+
onKeyDown(event) {
|
|
1225
|
+
switch (event.key) {
|
|
1226
|
+
case 'ArrowDown':
|
|
1227
|
+
event.preventDefault();
|
|
1228
|
+
this.moveNext();
|
|
1229
|
+
break;
|
|
1230
|
+
case 'ArrowUp':
|
|
1231
|
+
event.preventDefault();
|
|
1232
|
+
this.movePrevious();
|
|
1233
|
+
break;
|
|
1234
|
+
case 'Enter':
|
|
1235
|
+
this.selectActiveOption(event);
|
|
1236
|
+
break;
|
|
1237
|
+
case 'Escape':
|
|
1238
|
+
event.preventDefault();
|
|
1239
|
+
this.closeList();
|
|
1240
|
+
break;
|
|
1241
|
+
}
|
|
1221
1242
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1243
|
+
moveNext() {
|
|
1244
|
+
const options = this.getVisibleOptions();
|
|
1245
|
+
if (!options.length) {
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
const nextIndex = this.activeIndex < options.length - 1 ? this.activeIndex + 1 : 0;
|
|
1249
|
+
this.highlightOption(nextIndex);
|
|
1224
1250
|
}
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
if (searchValue === textInput?.value.toLowerCase()) {
|
|
1230
|
-
const template = templateProvider();
|
|
1231
|
-
results.forEach((result) => {
|
|
1232
|
-
this.addItem(template, result, event => {
|
|
1233
|
-
this.onOptionClick(event, textInput, this.getElement());
|
|
1234
|
-
});
|
|
1235
|
-
});
|
|
1236
|
-
}
|
|
1251
|
+
movePrevious() {
|
|
1252
|
+
const options = this.getVisibleOptions();
|
|
1253
|
+
if (!options.length) {
|
|
1254
|
+
return;
|
|
1237
1255
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1256
|
+
const previousIndex = this.activeIndex > 0 ? this.activeIndex - 1 : options.length - 1;
|
|
1257
|
+
this.highlightOption(previousIndex);
|
|
1258
|
+
}
|
|
1259
|
+
highlightOption(index) {
|
|
1260
|
+
const textInput = this.getTextInput();
|
|
1261
|
+
const options = this.getVisibleOptions();
|
|
1262
|
+
if (!textInput || !options.length) {
|
|
1263
|
+
return;
|
|
1240
1264
|
}
|
|
1265
|
+
this.activeIndex = index;
|
|
1266
|
+
options.forEach((option, optionIndex) => {
|
|
1267
|
+
const selected = optionIndex === index;
|
|
1268
|
+
option.classList.toggle('autocomplete-option-selected', selected);
|
|
1269
|
+
option.setAttribute('aria-selected', String(selected));
|
|
1270
|
+
});
|
|
1271
|
+
const activeOption = options[index];
|
|
1272
|
+
textInput.setAttribute('aria-activedescendant', activeOption.id);
|
|
1273
|
+
activeOption.scrollIntoView({
|
|
1274
|
+
block: 'nearest',
|
|
1275
|
+
});
|
|
1241
1276
|
}
|
|
1242
|
-
|
|
1277
|
+
selectActiveOption(event) {
|
|
1278
|
+
const options = this.getVisibleOptions();
|
|
1279
|
+
if (this.activeIndex < 0 || !options[this.activeIndex]) {
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1243
1282
|
event.preventDefault();
|
|
1244
|
-
|
|
1283
|
+
this.selectOption(options[this.activeIndex]);
|
|
1284
|
+
}
|
|
1285
|
+
selectOption(option) {
|
|
1286
|
+
const textInput = this.getTextInput();
|
|
1245
1287
|
const hiddenInput = this.getHiddenInput();
|
|
1246
|
-
const
|
|
1247
|
-
const
|
|
1248
|
-
// UI Display Value
|
|
1288
|
+
const display = option.dataset['display'] ?? option.textContent?.trim() ?? '';
|
|
1289
|
+
const value = option.dataset['value'] ?? '';
|
|
1249
1290
|
if (textInput) {
|
|
1250
|
-
|
|
1251
|
-
textInput.dataset['
|
|
1291
|
+
textInput.value = display;
|
|
1292
|
+
textInput.dataset['selectedValue'] = value;
|
|
1252
1293
|
}
|
|
1253
|
-
// submission value
|
|
1254
1294
|
if (hiddenInput) {
|
|
1255
|
-
hiddenInput.value =
|
|
1295
|
+
hiddenInput.value = value;
|
|
1256
1296
|
hiddenInput.disabled = false;
|
|
1257
1297
|
}
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1298
|
+
this.closeList();
|
|
1299
|
+
textInput?.dispatchEvent(new Event('change', {
|
|
1300
|
+
bubbles: true,
|
|
1301
|
+
}));
|
|
1261
1302
|
}
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
textInput.focus();
|
|
1267
|
-
textInput.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1303
|
+
openList() {
|
|
1304
|
+
const textInput = this.getTextInput();
|
|
1305
|
+
textInput?.setAttribute('aria-expanded', 'true');
|
|
1306
|
+
this.getListbox()?.classList.remove('autocomplete-text-input-list--hidden');
|
|
1268
1307
|
}
|
|
1269
|
-
|
|
1270
|
-
const
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1308
|
+
closeList() {
|
|
1309
|
+
const textInput = this.getTextInput();
|
|
1310
|
+
textInput?.setAttribute('aria-expanded', 'false');
|
|
1311
|
+
textInput?.removeAttribute('aria-activedescendant');
|
|
1312
|
+
this.activeIndex = -1;
|
|
1313
|
+
this.getAllOptions().forEach(option => {
|
|
1314
|
+
option.classList.add('autocomplete-text-input-item-hide');
|
|
1315
|
+
option.classList.remove('autocomplete-option-selected');
|
|
1316
|
+
option.setAttribute('aria-selected', 'false');
|
|
1317
|
+
});
|
|
1318
|
+
this.getListbox()?.classList.add('autocomplete-text-input-list--hidden');
|
|
1319
|
+
}
|
|
1320
|
+
clearSelection() {
|
|
1321
|
+
const hiddenInput = this.getHiddenInput();
|
|
1322
|
+
const textInput = this.getTextInput();
|
|
1323
|
+
if (hiddenInput) {
|
|
1324
|
+
hiddenInput.value = '';
|
|
1325
|
+
hiddenInput.disabled = true;
|
|
1274
1326
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
if (clickEvent) {
|
|
1278
|
-
item.addEventListener('mousedown', (event) => {
|
|
1279
|
-
clickEvent(event);
|
|
1280
|
-
});
|
|
1327
|
+
if (textInput) {
|
|
1328
|
+
delete textInput.dataset['selectedValue'];
|
|
1281
1329
|
}
|
|
1282
1330
|
}
|
|
1283
|
-
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
template?.classList.add('autocomplete-text-input-item-hide');
|
|
1288
|
-
this.getElement()
|
|
1289
|
-
.querySelectorAll(this.listItemsSelector)
|
|
1290
|
-
.forEach(e => e.remove());
|
|
1291
|
-
if (template) {
|
|
1292
|
-
this.getElement().querySelector(this.listParentSelector)?.append(template);
|
|
1331
|
+
getListbox() {
|
|
1332
|
+
const textInput = this.getTextInput();
|
|
1333
|
+
if (!textInput) {
|
|
1334
|
+
return null;
|
|
1293
1335
|
}
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
getHiddenInput() {
|
|
1297
|
-
return this.getElement().querySelector('[data-autocomplete-hidden]');
|
|
1336
|
+
const listId = textInput.getAttribute('aria-controls');
|
|
1337
|
+
return listId ? document.getElementById(listId) : null;
|
|
1298
1338
|
}
|
|
1299
1339
|
}
|
|
1300
1340
|
|