mirror of
https://github.com/sissbruecker/linkding.git
synced 2025-08-07 10:58:25 +02:00

* change tag modal into drawer * improve scroll handling * teleport all side bar content * improve naming * fix focus trap in filter drawer
92 lines
2.3 KiB
JavaScript
92 lines
2.3 KiB
JavaScript
import { Behavior } from "./index";
|
|
import { FocusTrapController } from "./focus-utils";
|
|
|
|
export class ModalBehavior extends Behavior {
|
|
constructor(element) {
|
|
super(element);
|
|
|
|
this.onClose = this.onClose.bind(this);
|
|
this.onKeyDown = this.onKeyDown.bind(this);
|
|
|
|
this.overlay = element.querySelector(".modal-overlay");
|
|
this.closeButton = element.querySelector(".modal-header .close");
|
|
|
|
this.overlay.addEventListener("click", this.onClose);
|
|
this.closeButton.addEventListener("click", this.onClose);
|
|
document.addEventListener("keydown", this.onKeyDown);
|
|
|
|
this.init();
|
|
}
|
|
|
|
destroy() {
|
|
this.overlay.removeEventListener("click", this.onClose);
|
|
this.closeButton.removeEventListener("click", this.onClose);
|
|
document.removeEventListener("keydown", this.onKeyDown);
|
|
|
|
this.clearInert();
|
|
this.focusTrap.destroy();
|
|
}
|
|
|
|
init() {
|
|
this.setupInert();
|
|
this.focusTrap = new FocusTrapController(
|
|
this.element.querySelector(".modal-container"),
|
|
);
|
|
}
|
|
|
|
setupInert() {
|
|
// Inert all other elements on the page
|
|
document
|
|
.querySelectorAll("body > *:not(.modals)")
|
|
.forEach((el) => el.setAttribute("inert", ""));
|
|
// Lock scroll on the body
|
|
document.body.classList.add("scroll-lock");
|
|
}
|
|
|
|
clearInert() {
|
|
// Clear inert attribute from all elements to allow focus outside the modal again
|
|
document
|
|
.querySelectorAll("body > *")
|
|
.forEach((el) => el.removeAttribute("inert"));
|
|
// Remove scroll lock from the body
|
|
document.body.classList.remove("scroll-lock");
|
|
}
|
|
|
|
onKeyDown(event) {
|
|
// Skip if event occurred within an input element
|
|
const targetNodeName = event.target.nodeName;
|
|
const isInputTarget =
|
|
targetNodeName === "INPUT" ||
|
|
targetNodeName === "SELECT" ||
|
|
targetNodeName === "TEXTAREA";
|
|
|
|
if (isInputTarget) {
|
|
return;
|
|
}
|
|
|
|
if (event.key === "Escape") {
|
|
this.onClose(event);
|
|
}
|
|
}
|
|
|
|
onClose(event) {
|
|
event.preventDefault();
|
|
this.element.classList.add("closing");
|
|
this.element.addEventListener(
|
|
"animationend",
|
|
(event) => {
|
|
if (event.animationName === "fade-out") {
|
|
this.doClose();
|
|
}
|
|
},
|
|
{ once: true },
|
|
);
|
|
}
|
|
|
|
doClose() {
|
|
this.element.remove();
|
|
this.clearInert();
|
|
this.element.dispatchEvent(new CustomEvent("modal:close"));
|
|
}
|
|
}
|