All files / src/web modals.js

97.14% Statements 34/35
83.33% Branches 5/6
100% Functions 11/11
100% Lines 32/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71                  11x 11x 11x 11x   11x 11x 44x   11x 27x 27x         7x       1x 1x       3x 3x       3x 3x 3x         3x 3x 3x 3x 3x 3x 3x 1x 1x   3x   3x     2x 2x       3x        
import * as bootstrap from "bootstrap";
 
/**
 * The dialogs the page raises itself, and the rule that a dialog pauses the
 * emulator: the first one up stops it, and the last one down starts it again
 * if it was running before.
 */
export class Modals {
    constructor({ loop }) {
        this.errorDialog = document.getElementById("error-dialog");
        this.errorModal = new bootstrap.Modal(this.errorDialog);
        this.aysEl = document.getElementById("are-you-sure");
        this.aysModal = new bootstrap.Modal(this.aysEl);
 
        const holds = new WeakMap();
        document.addEventListener("show.bs.modal", (event) => {
            if (!holds.has(event.target)) holds.set(event.target, loop.pause(`the ${event.target.id} dialog`));
        });
        document.addEventListener("hidden.bs.modal", (event) => {
            holds.get(event.target)?.();
            holds.delete(event.target);
        });
    }
 
    anyVisible() {
        return document.querySelectorAll(".modal.show").length !== 0;
    }
 
    show(id) {
        const el = document.getElementById(id);
        Iif (el) bootstrap.Modal.getOrCreateInstance(el).show();
    }
 
    hide(id) {
        const el = document.getElementById(id);
        if (el) bootstrap.Modal.getInstance(el)?.hide();
    }
 
    showError(context, error) {
        this.errorDialog.querySelector(".context").textContent = context;
        this.errorDialog.querySelector(".error").textContent = error;
        this.errorModal.show();
    }
 
    /** @returns {Promise<boolean>} true for the yes button; false for any other way out of the dialog */
    confirm(message, yesText, noText) {
        const yesButton = this.aysEl.querySelector(".ays-yes");
        this.aysEl.querySelector(".context").textContent = message;
        this.aysEl.querySelector(".ays-no").textContent = noText;
        yesButton.textContent = yesText;
        return new Promise((resolve) => {
            let confirmed = false;
            const onYes = () => {
                confirmed = true;
                this.aysModal.hide();
            };
            yesButton.addEventListener("click", onYes, { once: true });
            // The "no" button, Escape and a click outside raise no event of their own: they only hide the modal.
            this.aysEl.addEventListener(
                "hidden.bs.modal",
                () => {
                    yesButton.removeEventListener("click", onYes);
                    resolve(confirmed);
                },
                { once: true },
            );
            this.aysModal.show();
        });
    }
}