@ministryofjustice/frontend 2.2.4 → 3.0.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.
- package/moj/all.jquery.min.js +11 -3
- package/moj/all.js +327 -138
- package/moj/components/button-menu/_button-menu.scss +71 -109
- package/moj/components/button-menu/button-menu.js +292 -123
- package/moj/components/button-menu/button-menu.spec.js +363 -0
- package/moj/components/button-menu/template.njk +32 -6
- package/moj/components/date-picker/date-picker.js +29 -15
- package/moj/components/date-picker/date-picker.spec.js +571 -0
- package/moj/components/identity-bar/_identity-bar.scss +5 -9
- package/moj/components/identity-bar/template.njk +17 -22
- package/moj/components/page-header-actions/_page-header-actions.scss +9 -39
- package/moj/components/page-header-actions/template.njk +16 -16
- package/moj/objects/_all.scss +1 -0
- package/moj/objects/_button-group.scss +37 -0
- package/package.json +1 -1
package/moj/all.js
CHANGED
|
@@ -133,6 +133,12 @@ MOJFrontend.initAll = function (options) {
|
|
|
133
133
|
MOJFrontend.nodeListForEach($datepickers, function ($datepicker) {
|
|
134
134
|
new MOJFrontend.DatePicker($datepicker, {}).init();
|
|
135
135
|
})
|
|
136
|
+
|
|
137
|
+
const $buttonMenus = scope.querySelectorAll('[data-module="moj-button-menu"]')
|
|
138
|
+
MOJFrontend.nodeListForEach($buttonMenus, function ($buttonmenu) {
|
|
139
|
+
new MOJFrontend.ButtonMenu($buttonmenu, {}).init();
|
|
140
|
+
})
|
|
141
|
+
|
|
136
142
|
}
|
|
137
143
|
|
|
138
144
|
MOJFrontend.AddAnother = function(container) {
|
|
@@ -219,162 +225,331 @@ MOJFrontend.AddAnother.prototype.focusHeading = function() {
|
|
|
219
225
|
this.container.find('.moj-add-another__heading').focus();
|
|
220
226
|
};
|
|
221
227
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
this.menu.attr('role', 'menu');
|
|
229
|
-
this.mq = params.mq;
|
|
230
|
-
this.buttonText = params.buttonText;
|
|
231
|
-
this.buttonClasses = params.buttonClasses || '';
|
|
232
|
-
this.keys = { esc: 27, up: 38, down: 40, tab: 9 };
|
|
233
|
-
this.menu.on('keydown', '[role=menuitem]', $.proxy(this, 'onButtonKeydown'));
|
|
234
|
-
this.createToggleButton();
|
|
235
|
-
this.setupResponsiveChecks();
|
|
236
|
-
$(document).on('click', $.proxy(this, 'onDocumentClick'));
|
|
237
|
-
};
|
|
228
|
+
/**
|
|
229
|
+
* @typedef {object} ButtonMenuConfig
|
|
230
|
+
* @property {string} [buttonText=Actions] - Label for the toggle button
|
|
231
|
+
* @property {"left" | "right"} [alignMenu=left] - the alignment of the menu
|
|
232
|
+
* @property {string} [buttonClasses=govuk-button--secondary] - css classes applied to the toggle button
|
|
233
|
+
*/
|
|
238
234
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
235
|
+
/**
|
|
236
|
+
* @param {HTMLElement} $module
|
|
237
|
+
* @param {ButtonMenuConfig} config
|
|
238
|
+
* @constructor
|
|
239
|
+
*/
|
|
240
|
+
MOJFrontend.ButtonMenu = function ($module, config = {}) {
|
|
241
|
+
if (!$module) {
|
|
242
|
+
return this;
|
|
242
243
|
}
|
|
243
|
-
};
|
|
244
244
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
245
|
+
const schema = Object.freeze({
|
|
246
|
+
properties: {
|
|
247
|
+
buttonText: { type: "string" },
|
|
248
|
+
buttonClasses: { type: "string" },
|
|
249
|
+
alignMenu: { type: "string" },
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const defaults = {
|
|
254
|
+
buttonText: "Actions",
|
|
255
|
+
alignMenu: "left",
|
|
256
|
+
buttonClasses: "",
|
|
257
|
+
};
|
|
258
|
+
// data attributes override JS config, which overrides defaults
|
|
259
|
+
this.config = this.mergeConfigs(
|
|
260
|
+
defaults,
|
|
261
|
+
config,
|
|
262
|
+
this.parseDataset(schema, $module.dataset),
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
this.$module = $module;
|
|
249
266
|
};
|
|
250
267
|
|
|
251
|
-
MOJFrontend.ButtonMenu.prototype.
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
268
|
+
MOJFrontend.ButtonMenu.prototype.init = function () {
|
|
269
|
+
// If only one button is provided, don't initiate a menu and toggle button
|
|
270
|
+
// if classes have been provided for the toggleButton, apply them to the single item
|
|
271
|
+
if (this.$module.children.length == 1) {
|
|
272
|
+
const button = this.$module.children[0];
|
|
273
|
+
button.classList.forEach((className) => {
|
|
274
|
+
if (className.startsWith("govuk-button-")) {
|
|
275
|
+
button.classList.remove(className);
|
|
276
|
+
}
|
|
277
|
+
button.classList.remove("moj-button-menu__item")
|
|
278
|
+
});
|
|
279
|
+
if (this.config.buttonClasses) {
|
|
280
|
+
button.classList.add(...this.config.buttonClasses.split(" "));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Otherwise intialise a button menu
|
|
284
|
+
if (this.$module.children.length > 1) {
|
|
285
|
+
this.initMenu();
|
|
286
|
+
}
|
|
255
287
|
};
|
|
256
288
|
|
|
257
|
-
MOJFrontend.ButtonMenu.prototype.
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
289
|
+
MOJFrontend.ButtonMenu.prototype.initMenu = function () {
|
|
290
|
+
this.$menu = this.createMenu();
|
|
291
|
+
this.$module.insertAdjacentHTML("afterbegin", this.toggleTemplate());
|
|
292
|
+
this.setupMenuItems();
|
|
293
|
+
|
|
294
|
+
this.$menuToggle = this.$module.querySelector(":scope > button");
|
|
295
|
+
this.items = this.$menu.querySelectorAll("a, button");
|
|
296
|
+
|
|
297
|
+
this.$menuToggle.addEventListener("click", (event) => {
|
|
298
|
+
this.toggleMenu(event);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
this.$module.addEventListener("keydown", (event) => {
|
|
302
|
+
this.handleKeyDown(event);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
document.addEventListener("click", (event) => {
|
|
306
|
+
if (!this.$module.contains(event.target)) {
|
|
307
|
+
this.closeMenu(false);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
263
310
|
};
|
|
264
311
|
|
|
265
|
-
MOJFrontend.ButtonMenu.prototype.
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
312
|
+
MOJFrontend.ButtonMenu.prototype.createMenu = function () {
|
|
313
|
+
const $menu = document.createElement("ul");
|
|
314
|
+
$menu.setAttribute("role", "list");
|
|
315
|
+
$menu.hidden = true;
|
|
316
|
+
$menu.classList.add("moj-button-menu__wrapper");
|
|
317
|
+
if (this.config.alignMenu == "right") {
|
|
318
|
+
$menu.classList.add("moj-button-menu__wrapper--right");
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
this.$module.appendChild($menu);
|
|
322
|
+
while (this.$module.firstChild !== $menu) {
|
|
323
|
+
$menu.appendChild(this.$module.firstChild);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return $menu;
|
|
271
327
|
};
|
|
272
328
|
|
|
273
|
-
MOJFrontend.ButtonMenu.prototype.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
329
|
+
MOJFrontend.ButtonMenu.prototype.setupMenuItems = function () {
|
|
330
|
+
Array.from(this.$menu.children).forEach((item) => {
|
|
331
|
+
// wrap item in li tag
|
|
332
|
+
const listItem = document.createElement("li");
|
|
333
|
+
this.$menu.insertBefore(listItem, item);
|
|
334
|
+
listItem.appendChild(item);
|
|
335
|
+
|
|
336
|
+
item.setAttribute("tabindex", -1);
|
|
337
|
+
|
|
338
|
+
if (item.tagName == "BUTTON") {
|
|
339
|
+
item.setAttribute("type", "button");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
item.classList.forEach((className) => {
|
|
343
|
+
if (className.startsWith("govuk-button")) {
|
|
344
|
+
item.classList.remove(className);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// add a slight delay after click before closing the menu, makes it *feel* better
|
|
349
|
+
item.addEventListener("click", (event) => {
|
|
350
|
+
setTimeout(() => {
|
|
351
|
+
this.closeMenu(false);
|
|
352
|
+
}, 50);
|
|
353
|
+
});
|
|
354
|
+
});
|
|
279
355
|
};
|
|
280
356
|
|
|
281
|
-
MOJFrontend.ButtonMenu.prototype.
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
$(el).removeClass('govuk-button');
|
|
292
|
-
});
|
|
357
|
+
MOJFrontend.ButtonMenu.prototype.toggleTemplate = function () {
|
|
358
|
+
return `
|
|
359
|
+
<button type="button" class="govuk-button moj-button-menu__toggle-button ${this.config.buttonClasses || ""}" aria-haspopup="true" aria-expanded="false">
|
|
360
|
+
<span>
|
|
361
|
+
${this.config.buttonText}
|
|
362
|
+
<svg width="11" height="5" viewBox="0 0 11 5" xmlns="http://www.w3.org/2000/svg">
|
|
363
|
+
<path d="M5.5 0L11 5L0 5L5.5 0Z" fill="currentColor"/>
|
|
364
|
+
</svg>
|
|
365
|
+
</span>
|
|
366
|
+
</button>`;
|
|
293
367
|
};
|
|
294
368
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if($(el).attr('data-warning') == 'true') {
|
|
301
|
-
$(el).addClass('govuk-button--warning');
|
|
302
|
-
}
|
|
303
|
-
$(el).addClass('govuk-button');
|
|
304
|
-
});
|
|
369
|
+
/**
|
|
370
|
+
* @returns {boolean}
|
|
371
|
+
*/
|
|
372
|
+
MOJFrontend.ButtonMenu.prototype.isOpen = function () {
|
|
373
|
+
return this.$menuToggle.getAttribute("aria-expanded") === "true";
|
|
305
374
|
};
|
|
306
375
|
|
|
307
|
-
MOJFrontend.ButtonMenu.prototype.
|
|
308
|
-
|
|
376
|
+
MOJFrontend.ButtonMenu.prototype.toggleMenu = function (event) {
|
|
377
|
+
event.preventDefault();
|
|
378
|
+
|
|
379
|
+
// If menu is triggered with mouse don't move focus to first item
|
|
380
|
+
const keyboardEvent = event.detail == 0;
|
|
381
|
+
const focusIndex = keyboardEvent ? 0 : -1;
|
|
382
|
+
|
|
383
|
+
if (this.isOpen()) {
|
|
384
|
+
this.closeMenu();
|
|
385
|
+
} else {
|
|
386
|
+
this.openMenu(focusIndex);
|
|
387
|
+
}
|
|
309
388
|
};
|
|
310
389
|
|
|
311
|
-
|
|
312
|
-
|
|
390
|
+
/**
|
|
391
|
+
* Opens the menu and optionally sets the focus to the item with given index
|
|
392
|
+
*
|
|
393
|
+
* @param {number} focusIndex - The index of the item to focus
|
|
394
|
+
*/
|
|
395
|
+
MOJFrontend.ButtonMenu.prototype.openMenu = function (focusIndex = 0) {
|
|
396
|
+
this.$menu.hidden = false;
|
|
397
|
+
this.$menuToggle.setAttribute("aria-expanded", "true");
|
|
398
|
+
if (focusIndex !== -1) {
|
|
399
|
+
this.focusItem(focusIndex);
|
|
400
|
+
}
|
|
313
401
|
};
|
|
314
402
|
|
|
315
|
-
|
|
316
|
-
|
|
403
|
+
/**
|
|
404
|
+
* Closes the menu and optionally returns focus back to menuToggle
|
|
405
|
+
*
|
|
406
|
+
* @param {boolean} moveFocus - whether to return focus to the toggle button
|
|
407
|
+
*/
|
|
408
|
+
MOJFrontend.ButtonMenu.prototype.closeMenu = function (moveFocus = true) {
|
|
409
|
+
this.$menu.hidden = true;
|
|
410
|
+
this.$menuToggle.setAttribute("aria-expanded", "false");
|
|
411
|
+
if (moveFocus) {
|
|
412
|
+
this.$menuToggle.focus();
|
|
413
|
+
}
|
|
317
414
|
};
|
|
318
415
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
416
|
+
/**
|
|
417
|
+
* Focuses the menu item at the specified index
|
|
418
|
+
*
|
|
419
|
+
* @param {number} index - the index of the item to focus
|
|
420
|
+
*/
|
|
421
|
+
MOJFrontend.ButtonMenu.prototype.focusItem = function (index) {
|
|
422
|
+
if (index >= this.items.length) index = 0;
|
|
423
|
+
if (index < 0) index = this.items.length - 1;
|
|
424
|
+
|
|
425
|
+
this.items.item(index)?.focus();
|
|
327
426
|
};
|
|
328
427
|
|
|
329
|
-
MOJFrontend.ButtonMenu.prototype.
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
}
|
|
428
|
+
MOJFrontend.ButtonMenu.prototype.currentFocusIndex = function () {
|
|
429
|
+
const activeElement = document.activeElement;
|
|
430
|
+
const menuItems = Array.from(this.items);
|
|
431
|
+
|
|
432
|
+
return menuItems.indexOf(activeElement);
|
|
335
433
|
};
|
|
336
434
|
|
|
337
|
-
MOJFrontend.ButtonMenu.prototype.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
435
|
+
MOJFrontend.ButtonMenu.prototype.handleKeyDown = function (event) {
|
|
436
|
+
if (event.target == this.$menuToggle) {
|
|
437
|
+
switch (event.key) {
|
|
438
|
+
case "ArrowDown":
|
|
439
|
+
event.preventDefault();
|
|
440
|
+
this.openMenu();
|
|
441
|
+
break;
|
|
442
|
+
case "ArrowUp":
|
|
443
|
+
event.preventDefault();
|
|
444
|
+
this.openMenu(this.items.length - 1);
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (this.$menu.contains(event.target) && this.isOpen()) {
|
|
450
|
+
switch (event.key) {
|
|
451
|
+
case "ArrowDown":
|
|
452
|
+
event.preventDefault();
|
|
453
|
+
if (this.currentFocusIndex() !== -1) {
|
|
454
|
+
this.focusItem(this.currentFocusIndex() + 1);
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
case "ArrowUp":
|
|
458
|
+
event.preventDefault();
|
|
459
|
+
if (this.currentFocusIndex() !== -1) {
|
|
460
|
+
this.focusItem(this.currentFocusIndex() - 1);
|
|
461
|
+
}
|
|
462
|
+
break;
|
|
463
|
+
case "Home":
|
|
464
|
+
event.preventDefault();
|
|
465
|
+
this.focusItem(0);
|
|
466
|
+
break;
|
|
467
|
+
case "End":
|
|
468
|
+
event.preventDefault();
|
|
469
|
+
this.focusItem(this.items.length - 1);
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (event.key == "Escape" && this.isOpen()) {
|
|
475
|
+
this.closeMenu();
|
|
476
|
+
}
|
|
477
|
+
if (event.key == "Tab" && this.isOpen()) {
|
|
478
|
+
this.closeMenu(false);
|
|
479
|
+
}
|
|
358
480
|
};
|
|
359
481
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
482
|
+
/**
|
|
483
|
+
* Parse dataset
|
|
484
|
+
*
|
|
485
|
+
* Loop over an object and normalise each value using {@link normaliseString},
|
|
486
|
+
* optionally expanding nested `i18n.field`
|
|
487
|
+
*
|
|
488
|
+
* @param {{ schema: Schema }} Component - Component class
|
|
489
|
+
* @param {DOMStringMap} dataset - HTML element dataset
|
|
490
|
+
* @returns {Object} Normalised dataset
|
|
491
|
+
*/
|
|
492
|
+
MOJFrontend.ButtonMenu.prototype.parseDataset = function (schema, dataset) {
|
|
493
|
+
const parsed = {};
|
|
494
|
+
|
|
495
|
+
for (const [field, attributes] of Object.entries(schema.properties)) {
|
|
496
|
+
if (field in dataset) {
|
|
497
|
+
if (dataset[field]) {
|
|
498
|
+
parsed[field] = dataset[field];
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return parsed;
|
|
367
504
|
};
|
|
368
505
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
506
|
+
/**
|
|
507
|
+
* Config merging function
|
|
508
|
+
*
|
|
509
|
+
* Takes any number of objects and combines them together, with
|
|
510
|
+
* greatest priority on the LAST item passed in.
|
|
511
|
+
*
|
|
512
|
+
* @param {...{ [key: string]: unknown }} configObjects - Config objects to merge
|
|
513
|
+
* @returns {{ [key: string]: unknown }} A merged config object
|
|
514
|
+
*/
|
|
515
|
+
MOJFrontend.ButtonMenu.prototype.mergeConfigs = function (...configObjects) {
|
|
516
|
+
const formattedConfigObject = {};
|
|
517
|
+
|
|
518
|
+
// Loop through each of the passed objects
|
|
519
|
+
for (const configObject of configObjects) {
|
|
520
|
+
for (const key of Object.keys(configObject)) {
|
|
521
|
+
const option = formattedConfigObject[key];
|
|
522
|
+
const override = configObject[key];
|
|
523
|
+
|
|
524
|
+
// Push their keys one-by-one into formattedConfigObject. Any duplicate
|
|
525
|
+
// keys with object values will be merged, otherwise the new value will
|
|
526
|
+
// override the existing value.
|
|
527
|
+
if (typeof option === "object" && typeof override === "object") {
|
|
528
|
+
// @ts-expect-error Index signature for type 'string' is missing
|
|
529
|
+
formattedConfigObject[key] = this.mergeConfigs(option, override);
|
|
530
|
+
} else {
|
|
531
|
+
formattedConfigObject[key] = override;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
return formattedConfigObject;
|
|
376
537
|
};
|
|
377
538
|
|
|
539
|
+
/**
|
|
540
|
+
* Schema for component config
|
|
541
|
+
*
|
|
542
|
+
* @typedef {object} Schema
|
|
543
|
+
* @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties
|
|
544
|
+
*/
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Schema property for component config
|
|
548
|
+
*
|
|
549
|
+
* @typedef {object} SchemaProperty
|
|
550
|
+
* @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
|
|
551
|
+
*/
|
|
552
|
+
|
|
378
553
|
/**
|
|
379
554
|
* Datepicker config
|
|
380
555
|
*
|
|
@@ -471,7 +646,7 @@ Datepicker.prototype.init = function () {
|
|
|
471
646
|
|
|
472
647
|
this.setOptions();
|
|
473
648
|
this.initControls();
|
|
474
|
-
this.$module.setAttribute(
|
|
649
|
+
this.$module.setAttribute("data-initialized", "true");
|
|
475
650
|
};
|
|
476
651
|
|
|
477
652
|
Datepicker.prototype.initControls = function () {
|
|
@@ -580,6 +755,7 @@ Datepicker.prototype.createDialog = function () {
|
|
|
580
755
|
$dialog.setAttribute("aria-modal", "true");
|
|
581
756
|
$dialog.setAttribute("aria-labelledby", titleId);
|
|
582
757
|
$dialog.innerHTML = this.dialogTemplate(titleId);
|
|
758
|
+
$dialog.hidden = true;
|
|
583
759
|
|
|
584
760
|
return $dialog;
|
|
585
761
|
};
|
|
@@ -717,20 +893,14 @@ Datepicker.prototype.setOptions = function () {
|
|
|
717
893
|
|
|
718
894
|
Datepicker.prototype.setMinAndMaxDatesOnCalendar = function () {
|
|
719
895
|
if (this.config.minDate) {
|
|
720
|
-
this.minDate = this.formattedDateFromString(
|
|
721
|
-
this.config.minDate,
|
|
722
|
-
null,
|
|
723
|
-
);
|
|
896
|
+
this.minDate = this.formattedDateFromString(this.config.minDate, null);
|
|
724
897
|
if (this.minDate && this.currentDate < this.minDate) {
|
|
725
898
|
this.currentDate = this.minDate;
|
|
726
899
|
}
|
|
727
900
|
}
|
|
728
901
|
|
|
729
902
|
if (this.config.maxDate) {
|
|
730
|
-
this.maxDate = this.formattedDateFromString(
|
|
731
|
-
this.config.maxDate,
|
|
732
|
-
null,
|
|
733
|
-
);
|
|
903
|
+
this.maxDate = this.formattedDateFromString(this.config.maxDate, null);
|
|
734
904
|
if (this.maxDate && this.currentDate > this.maxDate) {
|
|
735
905
|
this.currentDate = this.maxDate;
|
|
736
906
|
}
|
|
@@ -860,7 +1030,7 @@ Datepicker.prototype.formattedDateFromString = function (
|
|
|
860
1030
|
const month = match[3];
|
|
861
1031
|
const year = match[4];
|
|
862
1032
|
|
|
863
|
-
formattedDate = new Date(`${
|
|
1033
|
+
formattedDate = new Date(`${year}-${month}-${day}`);
|
|
864
1034
|
if (formattedDate instanceof Date && !isNaN(formattedDate)) {
|
|
865
1035
|
return formattedDate;
|
|
866
1036
|
}
|
|
@@ -948,7 +1118,6 @@ Datepicker.prototype.updateCalendar = function () {
|
|
|
948
1118
|
|
|
949
1119
|
Datepicker.prototype.setCurrentDate = function (focus = true) {
|
|
950
1120
|
const { currentDate } = this;
|
|
951
|
-
|
|
952
1121
|
this.calendarDays.forEach((calendarDay) => {
|
|
953
1122
|
calendarDay.button.classList.add("moj-datepicker__button");
|
|
954
1123
|
calendarDay.button.classList.add("moj-datepicker__calendar-day");
|
|
@@ -976,10 +1145,10 @@ Datepicker.prototype.setCurrentDate = function (focus = true) {
|
|
|
976
1145
|
calendarDayDate.getTime() === this.inputDate.getTime()
|
|
977
1146
|
) {
|
|
978
1147
|
calendarDay.button.classList.add(this.currentDayButtonClass);
|
|
979
|
-
calendarDay.button.setAttribute("aria-
|
|
1148
|
+
calendarDay.button.setAttribute("aria-current", "date");
|
|
980
1149
|
} else {
|
|
981
1150
|
calendarDay.button.classList.remove(this.currentDayButtonClass);
|
|
982
|
-
calendarDay.button.removeAttribute("aria-
|
|
1151
|
+
calendarDay.button.removeAttribute("aria-current");
|
|
983
1152
|
}
|
|
984
1153
|
|
|
985
1154
|
if (calendarDayDate.getTime() === today.getTime()) {
|
|
@@ -1034,6 +1203,7 @@ Datepicker.prototype.toggleDialog = function (event) {
|
|
|
1034
1203
|
};
|
|
1035
1204
|
|
|
1036
1205
|
Datepicker.prototype.openDialog = function () {
|
|
1206
|
+
this.$dialog.hidden = false;
|
|
1037
1207
|
this.$dialog.classList.add("moj-datepicker__dialog--open");
|
|
1038
1208
|
this.$calendarButton.setAttribute("aria-expanded", "true");
|
|
1039
1209
|
|
|
@@ -1054,6 +1224,7 @@ Datepicker.prototype.openDialog = function () {
|
|
|
1054
1224
|
};
|
|
1055
1225
|
|
|
1056
1226
|
Datepicker.prototype.closeDialog = function () {
|
|
1227
|
+
this.$dialog.hidden = true;
|
|
1057
1228
|
this.$dialog.classList.remove("moj-datepicker__dialog--open");
|
|
1058
1229
|
this.$calendarButton.setAttribute("aria-expanded", "false");
|
|
1059
1230
|
this.$calendarButton.focus();
|
|
@@ -1101,13 +1272,31 @@ Datepicker.prototype.focusPreviousWeek = function () {
|
|
|
1101
1272
|
|
|
1102
1273
|
Datepicker.prototype.focusFirstDayOfWeek = function () {
|
|
1103
1274
|
const date = new Date(this.currentDate);
|
|
1104
|
-
|
|
1275
|
+
const firstDayOfWeekIndex = this.config.weekStartDay == "sunday" ? 0 : 1;
|
|
1276
|
+
const dayOfWeek = date.getDay();
|
|
1277
|
+
const diff =
|
|
1278
|
+
dayOfWeek >= firstDayOfWeekIndex
|
|
1279
|
+
? dayOfWeek - firstDayOfWeekIndex
|
|
1280
|
+
: 6 - dayOfWeek;
|
|
1281
|
+
|
|
1282
|
+
date.setDate(date.getDate() - diff);
|
|
1283
|
+
date.setHours(0, 0, 0, 0);
|
|
1284
|
+
|
|
1105
1285
|
this.goToDate(date);
|
|
1106
1286
|
};
|
|
1107
1287
|
|
|
1108
1288
|
Datepicker.prototype.focusLastDayOfWeek = function () {
|
|
1109
1289
|
const date = new Date(this.currentDate);
|
|
1110
|
-
|
|
1290
|
+
const lastDayOfWeekIndex = this.config.weekStartDay == "sunday" ? 6 : 0;
|
|
1291
|
+
const dayOfWeek = date.getDay();
|
|
1292
|
+
const diff =
|
|
1293
|
+
dayOfWeek <= lastDayOfWeekIndex
|
|
1294
|
+
? lastDayOfWeekIndex - dayOfWeek
|
|
1295
|
+
: 7 - dayOfWeek;
|
|
1296
|
+
|
|
1297
|
+
date.setDate(date.getDate() + diff);
|
|
1298
|
+
date.setHours(0, 0, 0, 0);
|
|
1299
|
+
|
|
1111
1300
|
this.goToDate(date);
|
|
1112
1301
|
};
|
|
1113
1302
|
|