feat: dialogues themes et conflits non bloquants pour la visionneuse XLSX #154
CI / lint (push) Successful in 2m31s
CI / security (push) Failing after 1m46s
CI / test (push) Successful in 4m17s
CI / build (push) Successful in 1m40s
CI / e2e (push) Canceled after 42s

This commit is contained in:
2026-09-29 14:50:47 -04:00
parent 605060c51d
commit 8da65611cb
18 changed files with 368 additions and 77 deletions
+82
View File
@@ -1143,6 +1143,88 @@ const FileOperations = {
};
// ---------------------------------------------------------------------------
// Generic themed dialogs (#154-A2)
// ---------------------------------------------------------------------------
// Promise-based replacements for window.confirm() / window.prompt() so the
// Excel viewer's structure actions and lossy-write confirmations stay inside
// the app theme (and are keyboard accessible) instead of native dialogs.
function _closeDialog(overlay, resolve, value) {
overlay.classList.remove("active");
if (overlay._onKey) document.removeEventListener("keydown", overlay._onKey);
setTimeout(() => overlay.remove(), 200);
resolve(value);
}
function _openDialog(innerHtml) {
const overlay = document.createElement("div");
overlay.className = "obsigate-modal-overlay";
const modal = document.createElement("div");
modal.className = "obsigate-modal";
modal.setAttribute("role", "dialog");
modal.setAttribute("aria-modal", "true");
modal.innerHTML = innerHtml;
overlay.appendChild(modal);
document.body.appendChild(overlay);
setTimeout(() => overlay.classList.add("active"), 10);
return { overlay, modal };
}
/** Themed replacement for window.confirm(). Resolves to a boolean. */
export function showConfirm({ title = "", message = "", confirmLabel = "", cancelLabel = "", danger = false } = {}) {
return new Promise((resolve) => {
const { overlay, modal } = _openDialog(`
<div class="obsigate-modal-header"><h3 class="obsigate-modal-title">${escapeHtml(title)}</h3></div>
<div class="obsigate-modal-body"><p class="modal-confirm-text">${escapeHtml(message)}</p></div>
<div class="obsigate-modal-footer">
<button class="modal-btn" data-dialog="cancel">${escapeHtml(cancelLabel || t("common.cancel"))}</button>
<button class="modal-btn ${danger ? "danger" : "primary"}" data-dialog="confirm">${escapeHtml(confirmLabel || t("common.confirm"))}</button>
</div>`);
const done = (v) => _closeDialog(overlay, resolve, v);
overlay.addEventListener("click", (e) => { if (e.target === overlay) done(false); });
modal.querySelector('[data-dialog="confirm"]').addEventListener("click", () => done(true));
modal.querySelector('[data-dialog="cancel"]').addEventListener("click", () => done(false));
overlay._onKey = (e) => {
if (e.key === "Escape") done(false);
else if (e.key === "Enter") done(true);
};
document.addEventListener("keydown", overlay._onKey);
setTimeout(() => modal.querySelector('[data-dialog="confirm"]')?.focus(), 20);
});
}
/** Themed replacement for window.prompt(). Resolves to the string (or null). */
export function showPrompt({ title = "", message = "", value = "", placeholder = "", confirmLabel = "", cancelLabel = "" } = {}) {
return new Promise((resolve) => {
const { overlay, modal } = _openDialog(`
<div class="obsigate-modal-header"><h3 class="obsigate-modal-title">${escapeHtml(title)}</h3></div>
<div class="obsigate-modal-body">
<div class="modal-form-group">
${message ? `<label class="modal-label">${escapeHtml(message)}</label>` : ""}
<input type="text" class="modal-input" data-dialog="input" spellcheck="false"
value="${escapeHtml(value)}" placeholder="${escapeHtml(placeholder)}" />
</div>
</div>
<div class="obsigate-modal-footer">
<button class="modal-btn" data-dialog="cancel">${escapeHtml(cancelLabel || t("common.cancel"))}</button>
<button class="modal-btn primary" data-dialog="confirm">${escapeHtml(confirmLabel || t("common.confirm"))}</button>
</div>`);
const input = modal.querySelector('[data-dialog="input"]');
const done = (v) => _closeDialog(overlay, resolve, v);
overlay.addEventListener("click", (e) => { if (e.target === overlay) done(null); });
modal.querySelector('[data-dialog="confirm"]').addEventListener("click", () => done(input.value));
modal.querySelector('[data-dialog="cancel"]').addEventListener("click", () => done(null));
overlay._onKey = (e) => {
if (e.key === "Escape") done(null);
else if (e.key === "Enter") done(input.value);
};
document.addEventListener("keydown", overlay._onKey);
setTimeout(() => { input.focus(); input.select(); }, 20);
});
}
// ---------------------------------------------------------------------------
// Find in Page Manager
// ---------------------------------------------------------------------------