1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/static/js/confirm_dialog.js
catborise c401479cf9 feat(templates): every confirmation asks in the page's own dialog
Deleting or detaching a disk, deleting a network card, forcing a VM off,
reverting or deleting a snapshot, stopping or deleting a pool, a
network, an interface, a filter or a secret, and the other actions that
ask first opened the browser's yes/no box (confirm()), and the ISO
upload told its mistakes in the browser's alert().

One dialog in the base page now asks for all of them: its title and
confirming button carry the button's own words, its body the button's
question, the confirming button red for a destructive action. Confirmed,
the button is clicked again, so its form sends what it did before. A
button inside another dialog (the flavors) hides that one while asking
and shows it again after; Cancel gives the focus back, and the
confirming button acts once. The ISO upload's mistakes show in its
dialog's error box, announced.
2026-10-31 20:44:39 +03:00

46 lines
2.3 KiB
JavaScript

// A button with data-confirm asks in the page's confirm dialog before it acts:
// the dialog's title and its confirming button carry the button's own words
// (or its accessible name, for an icon), its body the data-confirm question.
// Confirmed, the button is clicked again, so its form sends its name and value.
// A button in another dialog hides that one while asking (Bootstrap does not
// stack dialogs) and shows it again after; Cancel gives the focus back.
document.addEventListener("click", function (event) {
var button = event.target.closest("button[data-confirm]");
if (!button || button.dataset.confirmed) return;
event.preventDefault();
var dialog = document.getElementById("confirm-dialog");
var parent = button.closest(".modal");
var action = button.textContent.trim() || button.getAttribute("aria-label") || button.title;
var ok = dialog.querySelector("[data-confirm-ok]");
var confirmed = false;
dialog.querySelector(".modal-title").textContent = action;
dialog.querySelector(".modal-body").textContent = button.dataset.confirm;
ok.textContent = action;
ok.className = "btn " + (/\b(btn-|btn-outline-|text-)danger\b/.test(button.className) ? "btn-danger" : "btn-primary");
ok.disabled = false;
ok.onclick = function () {
ok.disabled = true; // once: the dialog is still open while it hides
confirmed = true;
bootstrap.Modal.getInstance(dialog).hide();
button.dataset.confirmed = "1";
button.click();
delete button.dataset.confirmed;
};
dialog.addEventListener("hidden.bs.modal", function () {
if (parent) {
// a form sent in place (the flavors) keeps its dialog; a page sent away does not care
bootstrap.Modal.getOrCreateInstance(parent).show();
} else if (!confirmed) {
// a menu's item is hidden with its menu: its toggle takes the focus
var menu = button.closest(".dropdown");
(menu ? menu.querySelector("[data-bs-toggle=dropdown]") : button).focus();
}
}, {once: true});
var ask = function () { bootstrap.Modal.getOrCreateInstance(dialog).show(); };
if (parent) {
parent.addEventListener("hidden.bs.modal", ask, {once: true});
bootstrap.Modal.getInstance(parent).hide();
} else {
ask();
}
}, true);