mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Every browser alert()/confirm() now uses the app's UI instead of native dialogs (no prompt() existed). Two new pieces: - js/ui/confirmDialog.js — showConfirm(message, opts) -> Promise<boolean>, a styled `bv-modal modal-always-on-top` dialog (Confirm/Cancel/backdrop/Escape; danger variant focuses Cancel). Importable anywhere, so future confirmations use it too. It stacks above other modals and is typable thanks to the recent stacked-modal focus fix. - js/ui/appNotify.js — notifyError/notifyStatus/notifySuccess routing to the app's NotificationController, for modules without a local showError; re-exports showConfirm. Migrated: UploadModal (10 alert -> this.showError, 1 confirm), subscriptionHistory (3 alert -> notify*, 1 confirm), MyVideosController (2), ProfileStorage/Wallet/Relay controllers, profileModalController (2), settingsRestorePrompt (default confirm now showConfirm), nostr/client deleteAllVersions. confirmSyncOverwrite helpers made async (syncConflict already awaits confirmOverwrite). Tests: tests/confirm-dialog.test.mjs (6 — confirm/cancel/backdrop/Escape resolution, DOM cleanup, danger focus, no-DOM fallback). Build + lint clean; affected suites green. (Note: build/lint don't parse JS — caught a multi-line-import split + a wrong import path via module-import checks.) Co-Authored-By: Claude Opus 4.8 <[email protected]>
76 lines
2.6 KiB
JavaScript
76 lines
2.6 KiB
JavaScript
// showConfirm() replaces native window.confirm with a styled, promise-based dialog so
|
|
// all confirmations live in the app's UI system. It must resolve true on Confirm, false
|
|
// on Cancel/backdrop/Escape, clean up its DOM, and degrade gracefully without a DOM.
|
|
|
|
import test, { beforeEach, afterEach } from "node:test";
|
|
import { strict as assert } from "node:assert";
|
|
import { JSDOM } from "jsdom";
|
|
import { showConfirm } from "../js/ui/confirmDialog.js";
|
|
|
|
let dom;
|
|
beforeEach(() => {
|
|
dom = new JSDOM("<!doctype html><html><body></body></html>");
|
|
globalThis.document = dom.window.document;
|
|
globalThis.window = dom.window;
|
|
globalThis.HTMLElement = dom.window.HTMLElement;
|
|
globalThis.KeyboardEvent = dom.window.KeyboardEvent;
|
|
});
|
|
afterEach(() => {
|
|
delete globalThis.document;
|
|
delete globalThis.window;
|
|
delete globalThis.HTMLElement;
|
|
delete globalThis.KeyboardEvent;
|
|
});
|
|
|
|
function overlay() {
|
|
return dom.window.document.querySelector(".bv-modal");
|
|
}
|
|
|
|
test("renders a dialog with the message and resolves TRUE when Confirm is clicked", async () => {
|
|
const p = showConfirm("Delete this thing?", { confirmLabel: "Delete", danger: true });
|
|
const modal = overlay();
|
|
assert.ok(modal, "an overlay was added to the DOM");
|
|
assert.match(modal.textContent, /Delete this thing\?/);
|
|
modal.querySelector(".btn").click(); // confirm button (cancel is .btn-ghost)
|
|
assert.equal(await p, true);
|
|
assert.equal(overlay(), null, "overlay removed after resolving");
|
|
});
|
|
|
|
test("resolves FALSE when Cancel is clicked", async () => {
|
|
const p = showConfirm("Sure?");
|
|
overlay().querySelector(".btn-ghost").click();
|
|
assert.equal(await p, false);
|
|
assert.equal(overlay(), null);
|
|
});
|
|
|
|
test("resolves FALSE when the backdrop is clicked", async () => {
|
|
const p = showConfirm("Sure?");
|
|
overlay().querySelector(".bv-modal-backdrop").click();
|
|
assert.equal(await p, false);
|
|
});
|
|
|
|
test("resolves FALSE on Escape", async () => {
|
|
const p = showConfirm("Sure?");
|
|
dom.window.document.dispatchEvent(
|
|
new dom.window.KeyboardEvent("keydown", { key: "Escape", bubbles: true }),
|
|
);
|
|
assert.equal(await p, false);
|
|
assert.equal(overlay(), null);
|
|
});
|
|
|
|
test("a danger prompt focuses Cancel (the safe action) by default", async () => {
|
|
const p = showConfirm("Delete?", { danger: true });
|
|
assert.equal(
|
|
dom.window.document.activeElement,
|
|
overlay().querySelector(".btn-ghost"),
|
|
);
|
|
overlay().querySelector(".btn-ghost").click();
|
|
await p;
|
|
});
|
|
|
|
test("without a DOM it declines rather than throwing", async () => {
|
|
delete globalThis.document;
|
|
delete globalThis.window;
|
|
assert.equal(await showConfirm("anything"), false);
|
|
});
|