/** * BSDialog5 * @version v0.2.2.003 (2024/01/22 2037) */ class BSDialog05 { constructor() { } get #prefix() { return "bsdia5_"; } get #body() { return document.getElementsByTagName("body")[0]; } get #sizeList() { return [ "modal-sm", "modal-md", "modal-lg", "modal-xl", "modal-xxl" ]; } async Show(options) { const a = this; const _options = Object.assign({ ID: null, Title: "", Message: "", URL: null, Size: "md", Colour: "secondary", ShowFooter: true, EasyClose: true, IsMovable: true }, options); a.#addModal(_options.ID, _options.Title, _options.Size, _options.ShowFooter, _options.IsMovable, _options.Colour); (new bootstrap.Modal(document.getElementById(a.#prefix + _options.ID), { backdrop: _options.EasyClose })).show(); if (a.#isURL(_options.URL)) { await a.UpdateBodyRemote(_options.ID, _options.URL); } else { await a.Update({ ID: _options.ID, Body: _options.Message }); } } async Prompt(options) { const a = this; const id = "prompt" + Math.floor(Math.random() * 10000) + 1000; const _options = Object.assign({ Type: "button", Title: "", Message: "", Size: "md", EasyClose: true, IsMovable: true, Buttons: [ { Label: "Yes", Value: "Yes", Colour: "primary" }, { Label: "No", Value: "No", Colour: "secondary" }, { Label: "Cancel", Value: "Cancel", Colour: "secondary" } ], Textbox: { Label: "", LabelSize: 4, Placeholder: "", Value: "", BoxSize: 8 } }, options); switch (_options.Type) { case "textbox": return await a.#showTextboxPrompt(id, _options); case "button": default: return await a.#showButtonPrompt(id, _options); } } async Clear() { const a = this; document.querySelectorAll('.modal').forEach(function(e) { const modal = bootstrap.Modal.getInstance(e); if (modal) { modal.hide(); } }); } async Close(id) { const a = this; if (id.startsWith(a.#prefix)) { id = id.substr(a.#prefix.length); } const node = document.getElementById(a.#prefix + id); const modal = bootstrap.Modal.getInstance(node); if (modal){ modal.hide(); } if (node) { node.parentNode.removeChild(node); } } async Update(options) { const a = this; let _options = Object.assign({ ID: null, Title: null, Body: null, URL: null, Footer: null, Size: null }, options); const modal = a.Find(_options.ID); if (modal === null) { return; } if (!this.#isNullOrWhitespace(_options.Title)) { modal.Title.innerHTML = _options.Title; } if (!this.#isNullOrWhitespace(_options.Body)) { a.#html(modal.Body, _options.Body); } else { if (this.#isURL(_options.URL)) { await a.UpdateBodyRemote(_options.ID, _options.URL); } } if (!this.#isNullOrWhitespace(_options.Footer)) { a.#html(modal.Footer, _options.Footer); } if (!this.#isNullOrWhitespace(_options.Size)) { a.#setSize(_options.ID, "modal-" + _options.Size); } } async UpdateBodyRemote(id, url) { const a = this; if (!a.Exists(id)) { return; } await fetch(url, { cache: 'no-cache', credentials: 'same-origin' }).then(data => data.text()).then(data => { a.Update({ ID: id, Body: data }); }).catch((error) => { a.Update({ ID: id, Body: "Error: " + error }); }); } Exists(id) { return (this.Find(id) !== null); } Find(id) { const a = this; const modal = a.#body.querySelectorAll("#" + a.#prefix + id + ".modal"); if (!modal) { return null; } if (modal.length <= 0) { return null; } return { Title: modal[0].querySelectorAll(".modal-title")[0], Header: modal[0].querySelectorAll(".modal-header")[0], Body: modal[0].querySelectorAll(".modal-body")[0], Footer: modal[0].querySelectorAll(".modal-footer")[0], Close: modal[0].querySelectorAll("[data-bs-dismiss='modal']"), Modal: modal[0] }; } #addModal(id, title, size, showFooter, isMovable, closeColour) { const a = this; // don't allow duplicates let modal = a.Find(id); if (modal !== null) { return; } let html = ""; html += ''; a.#appendHtml(a.#body, html); modal = a.Find(id); if (modal === null) { return; } document.getElementById(a.#prefix + id).addEventListener('hidden.bs.modal', function (event) { a.Close(id); }); modal.Title.addEventListener("dblclick", function(e){ e.stopPropagation(); e.preventDefault(); a.#toggleSize(id); }); if (isMovable) { const panel = modal.Modal.querySelectorAll(".modal-dialog")[0]; let isMovable = false; let currentPos = { X: 0, Y: 0 }; let movePos = { X: 0, Y: 0 }; modal.Title.addEventListener("mousedown", function(e) { if ((e.buttons == 1) && !isMovable) { movePos = { X: e.clientX, Y: e.clientY }; currentPos = { X: (a.#isNullOrWhitespace(panel.style.left) ? 0 : parseInt(panel.style.left.replace("px", ""))), Y: (a.#isNullOrWhitespace(panel.style.top) ? 0 : parseInt(panel.style.top.replace("px", ""))) }; isMovable = true; modal.Title.style.cursor = "move"; e.preventDefault(); } }); document.addEventListener("mouseup", function(e) { if (isMovable) { isMovable = false; modal.Title.style.cursor = "default"; } }); document.addEventListener("mousemove", function(e) { if ((e.buttons == 1) && isMovable) { panel.style.left = ((e.clientX - movePos.X) + currentPos.X) + 'px'; panel.style.top = ((e.clientY - movePos.Y) + currentPos.Y) + 'px'; } }); } } async #showButtonPrompt(id, options) { const a = this; return await new Promise(async (resolve, reject) => { await a.Show({ ID: id, Title: options.Title, Message: options.Message, Size: options.Size, EasyClose: options.EasyClose, IsMovable: options.IsMovable }); let html = ''; options.Buttons.forEach(function(e) { html += ''; }); a.Update({ ID: id, Footer: html }); const modal = a.Find(id); modal.Footer.querySelectorAll("button").forEach(function(button) { button.addEventListener("click", function(e){ e.stopPropagation(); e.preventDefault(); const value = button.getAttribute("data-prompt-value"); a.Close(id); resolve(value); }); }); modal.Close.forEach(function(sender) { sender.addEventListener("click", function(e){ e.stopPropagation(); e.preventDefault(); a.Close(id); resolve(""); }); }); }); } async #showTextboxPrompt(id, options) { const a = this; return await new Promise(async (resolve, reject) => { options.Buttons = [ { Label: "OK", Value: "", Colour: "primary" }, { Label: "Cancel", Value: "", Colour: "secondary" } ]; await a.Show({ ID: id, Title: options.Title, Message: options.Message, Size: options.Size, EasyClose: options.EasyClose, IsMovable: options.IsMovable }); let body = ''; if (!a.#isNullOrWhitespace(options.Message)) { body += '

' + options.Message + '

'; } body += '
'; if (a.#isNullOrWhitespace(options.Textbox.Label) || (options.Textbox.LabelSize <= 0)) { body += '
'; body += ''; body += '
'; } else { body += ''; body += '
'; body += ''; body += '
'; } body += '
'; let footer = ''; options.Buttons.forEach(function(e) { footer += ''; }); a.Update({ ID: id, Body: body, Footer: footer }); const modal = a.Find(id); const buttons = modal.Footer.querySelectorAll("button"); buttons[0].addEventListener("click", async function(e){ e.stopPropagation(); e.preventDefault(); const value = modal.Body.querySelectorAll("input")[0].value; await a.Close(id); resolve(value); }); buttons[1].addEventListener("click", async function(e){ e.stopPropagation(); e.preventDefault(); await a.Close(id); resolve(""); }); modal.Close.forEach(async function(sender) { sender.addEventListener("click", async function(e){ e.stopPropagation(); e.preventDefault(); await a.Close(id); resolve(""); }); }); }); } #appendHtml(el, html) { let node = document.createElement('template'); node.innerHTML = html; node = node.content.firstChild; el.appendChild(node); } #html(el, newHtml) { if (jQuery) { jQuery(el).html(newHtml); } else { el.innerHTML = newHtml; } } #isNullOrWhitespace(e) { if (typeof (e) == "undefined") { return true; } if (e == null) { return true; } if (e == false) { return true; } return (e.trim().length <= 0); } #isURL(value) { const a = this; if (a.#isNullOrWhitespace(value)) { return false; } if (value.startsWith("http://") || value.startsWith("https://") || value.startsWith("/")) { return true; } return false; } #setSize(id, size) { const a = this; const modal = a.Find(id); if (modal === null) { return; } for (let i=0; i (a.#sizeList.length - 1)) { pos = 0; } modal.Modal.classList.add(a.#sizeList[pos]); } } var BSDialog5 = new BSDialog05();