// Make modal window function makeModal({ title = "Message", text = "No text", type = "info", parent = null, stylePos = "fixed", } = {}) { const overlay = document.createElement("div"); Object.assign(overlay.style, { display: "none", position: stylePos, background: "rgba(0 0 0 / 0.8)", opacity: 0, top: "0", left: "0", right: "0", bottom: "0", zIndex: "500", transition: "all .8s", cursor: "pointer", }); const boxModal = document.createElement("div"); Object.assign(boxModal.style, { transition: "all 0.5s", opacity: 0, display: "none", position: stylePos, top: "50%", left: "50%", transform: "translate(-50%,-50%)", background: "#525252", minWidth: "300px", fontFamily: "sans-serif", zIndex: "501", border: "1px solid rgb(255 255 255 / 45%)", }); boxModal.className = "alekpet_modal_window"; const boxModalBody = document.createElement("div"); Object.assign(boxModalBody.style, { display: "flex", flexDirection: "column", textAlign: "center", }); boxModalBody.className = "alekpet_modal_body"; const boxModalHtml = `
${title}
${text}
`; boxModalBody.innerHTML = boxModalHtml; const alekpet_modal_header = boxModalBody.querySelector( ".alekpet_modal_header" ); Object.assign(alekpet_modal_header.style, { display: "flex", alignItems: "center", }); const close = boxModalBody.querySelector(".alekpet_modal_close"); Object.assign(close.style, { cursor: "pointer", }); let parentElement = document.body; if (parent && parent.nodeType === 1) { parentElement = parent; } boxModal.append(boxModalBody); parentElement.append(overlay, boxModal); const removeEvent = new Event("removeElements"); const remove = () => { animateTransitionProps(boxModal, { opacity: 0 }).then(() => animateTransitionProps(overlay, { opacity: 0 }).then(() => { parentElement.removeChild(boxModal); parentElement.removeChild(overlay); }) ); }; boxModal.addEventListener("removeElements", remove); overlay.addEventListener("removeElements", remove); animateTransitionProps(overlay) .then(() => { overlay.addEventListener("click", () => { overlay.dispatchEvent(removeEvent); }); animateTransitionProps(boxModal); }) .then(() => boxModal .querySelector(".alekpet_modal_close") .addEventListener("click", () => boxModal.dispatchEvent(removeEvent)) ); } function findWidget(node, value, attr = "name", func = "find") { return node?.widgets ? node.widgets[func]((w) => w[attr] === value) : null; } function animateTransitionProps( el, props = { opacity: 1 }, preStyles = { display: "block" } ) { Object.assign(el.style, preStyles); return new Promise((res) => { setTimeout(() => { Object.assign(el.style, props); const transstart = () => (el.isAnimating = true); const transchancel = () => (el.isAnimating = false); el.addEventListener("transitionstart", transstart); el.addEventListener("transitioncancel", transchancel); el.addEventListener("transitionend", function transend() { el.isAnimating = false; el.removeEventListener("transitionend", transend); el.removeEventListener("transitionend", transchancel); el.removeEventListener("transitionend", transstart); res(el); }); }, 100); }); } function animateClick(target, opacityVal = 0.9) { if (target?.isAnimating) return; const hide = +target.style.opacity === 0; return animateTransitionProps(target, { opacity: hide ? opacityVal : 0, }).then(() => showHide({ elements: [target], hide: !hide })); } function showHide({ elements = [], hide = null, displayProp = "block" } = {}) { Array.from(elements).forEach((el) => { if (hide !== null) { el.style.display = !hide ? displayProp : "none"; } else { el.style.display = !el.style.display || el.style.display === "none" ? displayProp : "none"; } }); } function isEmptyObject(obj) { if (!obj) return true; return Object.keys(obj).length === 0 && obj.constructor === Object; } function makeElement(tag, attrs = {}) { if (!tag) tag = "div"; const element = document.createElement(tag); Object.keys(attrs).forEach((key) => { const currValue = attrs[key]; if (key === "class") { if (Array.isArray(currValue)) { element.classList.add(...currValue); } else if (currValue instanceof String && typeof currValue === "string") { element.className = currValue; } } else if (key === "dataset") { try { if (Array.isArray(currValue)) { currValue.forEach((datasetArr) => { const [prop, propval] = Object.entries(datasetArr)[0]; element.dataset[prop] = propval; }); } else { const [prop, propval] = Object.entries(currValue)[0]; element.dataset[prop] = propval; } } catch (err) { console.log(err); } } else if (["for"].includes(key)) { element.setAttribute(key, currValue); } else if (key === "children") { element.append(...(currValue instanceof Array ? currValue : [currValue])); } else if (key === "parent") { currValue.append(element); } else { element[key] = currValue; } }); return element; } function isValidStyle(opt, strColor) { let op = new Option().style; if (!op.hasOwnProperty(opt)) return { result: false, color: "", color_hex: "" }; op[opt] = strColor; return { result: op[opt] !== "", color_rgb: op[opt], color_hex: rgbToHex(op[opt]), }; } function rgbToHex(rgb) { const regEx = new RegExp(/\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/); if (regEx.test(rgb)) { let [, r, g, b] = regEx.exec(rgb); r = parseInt(r).toString(16); g = parseInt(g).toString(16); b = parseInt(b).toString(16); r = r.length === 1 ? r + "0" : r; g = g.length === 1 ? g + "0" : g; b = b.length === 1 ? b + "0" : b; return `#${r}${g}${b}`; } } async function getDataJSON(url) { try { const response = await fetch(url); const jsonData = await response.json(); return jsonData; } catch (err) { return new Error(err); } } function deepMerge(target, source) { if (source?.nodeType) return; for (let key in source) { if (source[key] instanceof Object && key in target) { Object.assign(source[key], deepMerge(target[key], source[key])); } } Object.assign(target || {}, source); return target; } const THEME_MODAL_WINDOW_BASE = { stylesTitle: { background: "#8f210f", padding: "5px", borderRadius: "6px", marginBottom: "5px", alignSelf: "stretch", }, stylesBox: { background: "auto", color: "auto", border: 0, boxShadow: "none", padding: 0, fontFamily: "sans-serif", }, stylesWrapper: { display: "flex", background: "#3b2222", justifyContent: "center", flexDirection: "column", alignItems: "stretch", textAlign: "center", borderRadius: "6px", boxShadow: "3px 3px 6px #141414", border: "1px solid #f91b1b", color: "white", padding: "6px", fontFamily: "sans-serif", lineHeight: 1.5, maxWidth: "300px", }, stylesClose: { background: "#3b2222" }, }; const THEMES_MODAL_WINDOW = { error: { ...THEME_MODAL_WINDOW_BASE }, warning: { stylesTitle: { ...THEME_MODAL_WINDOW_BASE.stylesTitle, background: "#e99818", }, stylesBox: { ...THEME_MODAL_WINDOW_BASE.stylesBox }, stylesWrapper: { ...THEME_MODAL_WINDOW_BASE.stylesWrapper, background: "#594e32", boxShadow: "3px 3px 6px #141414", border: "1px solid #e99818", }, stylesClose: { ...THEME_MODAL_WINDOW_BASE.stylesClose, background: "#594e32", }, }, normal: { stylesTitle: { ...THEME_MODAL_WINDOW_BASE.stylesTitle, background: "#108f0f", }, stylesBox: { ...THEME_MODAL_WINDOW_BASE.stylesBox }, stylesWrapper: { ...THEME_MODAL_WINDOW_BASE.stylesWrapper, background: "#223b2a", boxShadow: "3px 3px 6px #141414", border: "1px solid #108f0f", }, stylesClose: { ...THEME_MODAL_WINDOW_BASE.stylesClose, background: "#223b2a", }, }, }; const defaultOptions = { auto: { autohide: false, autoshow: false, autoremove: false, propStyles: { opacity: 0 }, propPreStyles: {}, timewait: 2000, }, parent: null, }; function createWindowModal({ textTitle = "Message", textBody = "Hello world!", textFooter = null, classesWrapper = [], stylesWrapper = {}, classesBox = [], stylesBox = {}, classesTitle = [], stylesTitle = {}, classesBody = [], stylesBody = {}, classesClose = [], stylesClose = {}, classesFooter = [], stylesFooter = {}, options = defaultOptions, } = {}) { // Check all options exist options = deepMerge({ ...defaultOptions }, options); const { parent, auto: { autohide, autoshow, autoremove, timewait, propStyles, propPreStyles, }, } = options; // Function past text(html) function addText(text, parent) { if (!parent) return; switch (typeof text) { case "string": if (/^\<*.\/?\>$/.test(text)) { parent.innerHTML(text); } else { parent.textContent = text; } break; case "object": default: if (Array.isArray(text)) { text.forEach((element) => parent.append(element)); } else if (text.nodeType === 1 || text.nodeType === 3) parent.append(text); } } // Wrapper const wrapper_settings = makeElement("div", { class: ["alekpet__wrapper__window", ...classesWrapper], }); Object.assign(wrapper_settings.style, { display: "none", opacity: 0, minWidth: "220px", position: "absolute", left: "50%", top: "50%", transform: "translate(-50%, -50%)", opacity: 0, transition: "all .8s", ...stylesWrapper, }); // Box const box__settings = makeElement("div", { class: ["alekpet__window__box", ...classesBox], }); Object.assign(box__settings.style, { display: "flex", flexDirection: "column", background: "#0e0e0e", padding: "10px", justifyContent: "center", alignItems: "center", gap: "10px", textAlign: "center", borderRadius: "6px", color: "white", border: "2px solid silver", fontFamily: "monospace", boxShadow: "2px 2px 4px silver", ...stylesBox, }); // Title const box_settings_title = makeElement("div", { class: ["alekpet__window__title", , ...classesTitle], }); Object.assign(box_settings_title.style, { ...stylesTitle, }); // Add text (html) to title addText(textTitle, box_settings_title); // Body const box_settings_body = makeElement("div", { class: ["alekpet__window__body", ...classesBody], }); Object.assign(box_settings_body.style, { display: "flex", flexDirection: "column", alignItems: "flex-end", gap: "5px", textWrap: "wrap", ...stylesBody, }); // Add text (html) to body addText(textBody, box_settings_body); // Close button const close__box__button = makeElement("div", { class: ["close__box__button", ...classesClose], textContent: "✖", }); Object.assign(close__box__button.style, { position: "absolute", top: "-10px", right: "-10px", background: "silver", borderRadius: "50%", width: "20px", height: "20px", cursor: "pointer", display: "flex", justifyContent: "center", alignItems: "center", fontSize: "0.8rem", ...stylesClose, }); close__box__button.addEventListener("click", () => animateTransitionProps(wrapper_settings, { opacity: 0, }).then(() => { showHide({ elements: [wrapper_settings] }); }) ); close__box__button.onmouseenter = () => { close__box__button.style.opacity = 0.8; }; close__box__button.onmouseleave = () => { close__box__button.style.opacity = 1; }; box__settings.append(box_settings_title, box_settings_body); // Footer if (textFooter) { const box_settings_footer = makeElement("div", { class: [...classesFooter], }); Object.assign(box_settings_footer.style, { ...stylesFooter, }); // Add text (html) to body addText(textFooter, box_settings_footer); box__settings.append(box_settings_footer); } wrapper_settings.append(close__box__button, box__settings); if (parent && parent.nodeType === 1) { parent.append(wrapper_settings); if (autoshow) { animateClick(wrapper_settings).then( () => autohide && setTimeout( () => animateTransitionProps( wrapper_settings, { ...propStyles }, { ...propPreStyles } ).then(() => autoremove && parent.removeChild(wrapper_settings)), timewait ) ); } } return wrapper_settings; } export { makeModal, createWindowModal, animateTransitionProps, animateClick, showHide, makeElement, getDataJSON, isEmptyObject, isValidStyle, rgbToHex, findWidget, THEMES_MODAL_WINDOW, };