UNPKG

susmodal

Version:

Simple library for displaying modals

181 lines (137 loc) 5.35 kB
/** * SUSModal is used for generating modal window with functionnal and style settings. */ class SUSModal { /** * Constructor. * * @param {*} elements */ constructor(elements = {}) { elements = Object.assign({}, { id: null, animation: "fade", animationDuration: 400, width: "400px", height: "auto", backgroundDark: false, finalPosition: "auto", }, elements); // Properties this.id = elements.id; this.animation = elements.animation; this.animationDuration = elements.animationDuration; this.width = elements.width; this.height = elements.height; this.finalPosition = elements.finalPosition; this.backgroundDark = elements.backgroundDark; // The modal and its content this.SUSModal = document.getElementById(this.id); this.SUSModalContent = this.SUSModal.querySelector("#susmodal-content"); // Declaration of focusables elements (for navigation with keyboard). this.SUSModalShow = false; this.focusElementsType = "button, input, a, textarea"; this.focusElements = Array.from(this.SUSModalContent.querySelectorAll(this.focusElementsType)); // Apply the style configuration to the modal content and the body. this.stylize(); // For closing the modal if(this.SUSModal.querySelectorAll(".susmodal-close-btn").length > 0) { let closeBtnList = Array.from(this.SUSModal.querySelectorAll(".susmodal-close-btn")); closeBtnList.forEach(item => { item.addEventListener("click", () => { this.hide(); }); }) } } /** * Show the modal. */ show() { this.SUSModal.style.display = "block"; // focus on the first element for navigation with keyboard this.focusElements[0].focus(); this.SUSModal.removeAttribute('aria-hidden'); this.SUSModal.setAttribute('aria-modal', 'true'); // if modal has been opened at least once. if(this.SUSModalContent.classList.contains("susmodal-content-reverse")) { this.SUSModalContent.classList.remove("susmodal-content-reverse"); if(this.backgroundDark) document.body.classList.remove("susmodal-body-animation-reverse") } // add animations. this.SUSModalContent.classList.add("susmodal-animation-" + this.animation); if(this.backgroundDark) document.body.classList.add("susmodal-body-animation"); window.onkeydown = event => { this.keydownEvent(event); }; window.onclick = event => { if(event.target === this.SUSModal) this.hide(); }; } /** * Hide the modal. */ hide() { event.preventDefault(); this.SUSModal.setAttribute('aria-hidden', 'true'); this.SUSModal.removeAttribute('aria-modal'); this.SUSModalContent.classList.remove("susmodal-content-animation"); this.SUSModalContent.classList.add("susmodal-content-reverse"); if(this.backgroundDark) document.body.classList.add("susmodal-body-animation-reverse"); // Wait the end of the reverse animations for completely hide setTimeout(() => { this.SUSModal.style.display = "none"; }, this.animationDuration); window.onkeydown = undefined; window.onclick = undefined; } /** * Used to manage the navigation with keyboard. * * @param {*} event */ catchFocus(event) { event.preventDefault(); let indexSUSmodal = this.focusElements.findIndex(f => f === this.SUSModalContent.querySelector(":focus")); if(event.shiftKey === true) { indexsusmodal--; } else { indexSUSmodal++; } if(indexSUSmodal >= this.focusElements.length) indexSUSmodal = 0; if(indexSUSmodal < 0) indexSUSmodal = this.focusElements.length - 1; this.focusElements[indexSUSmodal].focus(); } /** * Used to manage the keydown events. * * @param {*} event */ keydownEvent(event) { if(this.SUSModal && event.key === "Escape" || event.key === "Esc") this.hide(); if(this.SUSModal && event.key === "Tab") this.catchFocus(event); } /** * Used to manage the style */ stylize() { let SUSmodalStyleCss = "margin:"+this.finalPosition+";"; if(this.width) SUSmodalStyleCss += "width:"+this.width+";"; if(this.height) SUSmodalStyleCss += "height:"+this.height+";"; if(this.animationDuration) SUSmodalStyleCss += "animation-duration:"+this.animationDuration+"ms;"; this.SUSModalContent.style.cssText = SUSmodalStyleCss; if(this.backgroundDark) document.body.style.cssText = "animation-duration:"+this.animationDuration+"ms;"; } }