Use internal compose modal for mail actions

This commit is contained in:
DonVoo 2026-07-13 12:16:21 +02:00
parent e8029a177c
commit 29fd3f5cae
3 changed files with 229 additions and 24 deletions

View file

@ -42,11 +42,49 @@
return `${prefix}: ${clean || "(ohne Betreff)"}`;
}
function openMailto(mail) {
const params = new URLSearchParams();
if (mail.subject) params.set("subject", mail.subject);
if (mail.body) params.set("body", mail.body);
window.location.href = `mailto:${encodeURIComponent(mail.to || "")}?${params.toString()}`;
function ensureComposeModal() {
let modal = document.getElementById("mailComposeModal");
if (modal) return modal;
modal = document.createElement("div");
modal.className = "mail-compose-modal";
modal.id = "mailComposeModal";
modal.setAttribute("role", "dialog");
modal.setAttribute("aria-modal", "true");
modal.setAttribute("aria-label", "Mail verfassen");
modal.innerHTML = `
<form class="mail-compose-box">
<div class="mail-compose-head">
<h2>Mail verfassen</h2>
<button class="mail-compose-close" type="button" aria-label="Schliessen" data-compose-close>&times;</button>
</div>
<div class="mail-compose-fields">
<label>An<input name="to" type="text" autocomplete="email" required placeholder="empfaenger@example.com"></label>
<label>Betreff<input name="subject" type="text" placeholder="Betreff"></label>
<label>Nachricht<textarea name="body" rows="14"></textarea></label>
</div>
<div class="mail-compose-status" aria-live="polite"></div>
<div class="mail-compose-actions">
<button class="btn secondary" type="button" data-compose-close>Abbrechen</button>
<button class="btn" type="submit">Senden</button>
</div>
</form>
`;
document.body.appendChild(modal);
return modal;
}
function closeComposeModal() {
document.getElementById("mailComposeModal")?.classList.remove("open");
}
function openCompose(mail) {
const modal = ensureComposeModal();
modal.querySelector("[name='to']").value = mail.to || "";
modal.querySelector("[name='subject']").value = mail.subject || "";
modal.querySelector("[name='body']").value = mail.body || "";
modal.querySelector(".mail-compose-status").textContent = "";
modal.classList.add("open");
setTimeout(() => modal.querySelector("[name='to']").focus(), 0);
}
function quoteBody(message) {
@ -85,7 +123,7 @@
});
document.addEventListener("click", (event) => {
if (event.target.closest("[data-action-new]")) {
openMailto({ to: "", subject: "", body: "" });
openCompose({ to: "", subject: "", body: "" });
}
if (event.target.closest("[data-action-refresh]")) window.location.reload();
if (event.target.closest("[data-action-reply]")) {
@ -94,7 +132,7 @@
window.alert("Bitte zuerst eine Nachricht waehlen.");
return;
}
openMailto({ to: message.from, subject: prefixedSubject("Re", message.subject), body: quoteBody(message) });
openCompose({ to: message.from, subject: prefixedSubject("Re", message.subject), body: quoteBody(message) });
}
if (event.target.closest("[data-action-forward]")) {
const message = selectedPreview();
@ -102,7 +140,38 @@
window.alert("Bitte zuerst eine Nachricht waehlen.");
return;
}
openMailto({ to: "", subject: prefixedSubject("Fw", message.subject), body: forwardBody(message) });
openCompose({ to: "", subject: prefixedSubject("Fw", message.subject), body: forwardBody(message) });
}
if (event.target.closest("[data-compose-close]")) closeComposeModal();
});
document.addEventListener("click", (event) => {
if (event.target.id === "mailComposeModal") closeComposeModal();
});
document.addEventListener("keydown", (event) => {
if (event.key === "Escape") closeComposeModal();
});
document.addEventListener("submit", async (event) => {
const form = event.target.closest(".mail-compose-box");
if (!form) return;
event.preventDefault();
const status = form.querySelector(".mail-compose-status");
const submit = form.querySelector("button[type='submit']");
status.textContent = "Sende...";
submit.disabled = true;
try {
const response = await fetch("/mail/send", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" },
body: new URLSearchParams(new FormData(form)).toString()
});
const text = await response.text();
if (!response.ok) throw new Error(text || "Senden fehlgeschlagen.");
status.textContent = "Gesendet.";
setTimeout(closeComposeModal, 700);
} catch (error) {
status.textContent = error.message || "Senden fehlgeschlagen.";
} finally {
submit.disabled = false;
}
});
document.addEventListener("input", (event) => {