|
|
@@ -3,29 +3,100 @@ class ModalHandler {
|
|
|
return document.getElementById("modal-container") !== null;
|
|
|
}
|
|
|
|
|
|
- static open(fragment) {
|
|
|
+ static getModalContainer() {
|
|
|
+ let container = document.getElementById("modal-container");
|
|
|
+
|
|
|
+ if (container === undefined) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ return container;
|
|
|
+ }
|
|
|
+
|
|
|
+ static getFocusableElements() {
|
|
|
+ let container = this.getModalContainer();
|
|
|
+
|
|
|
+ if (container === undefined) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ return container.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
|
|
|
+ }
|
|
|
+
|
|
|
+ static setupFocusTrap() {
|
|
|
+ let focusableElements = this.getFocusableElements();
|
|
|
+
|
|
|
+ if (focusableElements === undefined) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let firstFocusableElement = focusableElements[0];
|
|
|
+ let lastFocusableElement = focusableElements[focusableElements.length - 1];
|
|
|
+
|
|
|
+ this.getModalContainer().onkeydown = (e) => {
|
|
|
+ if (e.key !== 'Tab') {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If there is only one focusable element in the dialog we always want to focus that one with the tab key.
|
|
|
+ // This handles the special case of having just one focusable element in a dialog where keyboard focus is placed on an element that is not in the tab order.
|
|
|
+ if (focusableElements.length === 1) {
|
|
|
+ firstFocusableElement.focus();
|
|
|
+ e.preventDefault();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (e.shiftKey && document.activeElement === firstFocusableElement) {
|
|
|
+ lastFocusableElement.focus();
|
|
|
+ e.preventDefault();
|
|
|
+ } else if (!e.shiftKey && document.activeElement === lastFocusableElement) {
|
|
|
+ firstFocusableElement.focus();
|
|
|
+ e.preventDefault();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static open(fragment, initialFocusElementId) {
|
|
|
if (ModalHandler.exists()) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ this.activeElement = document.activeElement;
|
|
|
+
|
|
|
let container = document.createElement("div");
|
|
|
container.id = "modal-container";
|
|
|
+ container.setAttribute("role", "dialog");
|
|
|
container.appendChild(document.importNode(fragment, true));
|
|
|
document.body.appendChild(container);
|
|
|
|
|
|
- let closeButton = document.querySelector("a.btn-close-modal");
|
|
|
+ let closeButton = document.querySelector("button.btn-close-modal");
|
|
|
if (closeButton !== null) {
|
|
|
closeButton.onclick = (event) => {
|
|
|
event.preventDefault();
|
|
|
ModalHandler.close();
|
|
|
};
|
|
|
}
|
|
|
+
|
|
|
+ let initialFocusElement;
|
|
|
+ if (initialFocusElementId !== undefined) {
|
|
|
+ initialFocusElement = document.getElementById(initialFocusElementId);
|
|
|
+ } else {
|
|
|
+ initialFocusElement = this.getFocusableElements()[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ initialFocusElement.focus();
|
|
|
+
|
|
|
+ this.setupFocusTrap();
|
|
|
}
|
|
|
|
|
|
static close() {
|
|
|
- let container = document.getElementById("modal-container");
|
|
|
+ let container = this.getModalContainer();
|
|
|
if (container !== null) {
|
|
|
container.parentNode.removeChild(container);
|
|
|
}
|
|
|
+
|
|
|
+ if (this.activeElement !== undefined) {
|
|
|
+ this.activeElement.focus();
|
|
|
+ }
|
|
|
}
|
|
|
}
|