diff --git a/backend/00-router.go b/backend/00-router.go
index 5626022..51995be 100644
--- a/backend/00-router.go
+++ b/backend/00-router.go
@@ -73,8 +73,8 @@ func renderStartPage(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `
Mail-Graveyard
-
-
+
+
@@ -121,9 +121,9 @@ func renderShell(w http.ResponseWriter, r *http.Request, active, readingPane str
fmt.Fprintf(w, `
Mail-Graveyard
-
+
-
+
@@ -697,9 +697,9 @@ func renderAccountsPage(w http.ResponseWriter, r *http.Request, accounts []Accou
fmt.Fprintf(w, `
Konten-Verwaltung - Mail-Graveyard
-
+
-
+
@@ -743,9 +743,9 @@ func renderArchivesPage(w http.ResponseWriter, r *http.Request, archives []strin
fmt.Fprintf(w, `
Archiv-mbox Verwaltung - Mail-Graveyard
-
+
-
+
@@ -791,9 +791,9 @@ func renderUsersPage(w http.ResponseWriter, r *http.Request, users []AppUser, ed
fmt.Fprintf(w, `
Benutzerverwaltung - Mail-Graveyard
-
+
-
+
@@ -865,9 +865,9 @@ func renderTransferPage(w http.ResponseWriter, r *http.Request, mode transferMod
fmt.Fprintf(w, `
%s - Mail-Graveyard
-
+
-
+
@@ -1317,9 +1317,9 @@ func renderSourceEmailBoxPage(w http.ResponseWriter, r *http.Request, accounts [
fmt.Fprintf(w, `
Quell-Postfach - Mail-Graveyard
-
+
-
+
@@ -1361,9 +1361,9 @@ func renderTargetEmailBoxPage(w http.ResponseWriter, r *http.Request, accounts [
fmt.Fprintf(w, `
Ziel-Postfach - Mail-Graveyard
-
+
-
+
diff --git a/frontend-js/dist/app.js b/frontend-js/dist/app.js
index dffa2e4..e0b930c 100644
--- a/frontend-js/dist/app.js
+++ b/frontend-js/dist/app.js
@@ -8,26 +8,106 @@
bar.innerHTML = `
-
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
`;
ribbon.insertAdjacentElement("afterend", bar);
}
+ function selectedPreview() {
+ const read = document.querySelector("#read .read-body, #transfer-preview .read-body, .pane-read .read-body");
+ if (!read || read.querySelector(".ef-empty")) return null;
+ const subject = read.querySelector(".read-subject")?.textContent?.trim() || "";
+ const meta = read.querySelector(".read-meta")?.innerText || "";
+ const body = read.querySelector(".read-pre")?.innerText || "";
+ const from = (meta.match(/Von:\s*(.+)/i) || [])[1]?.trim() || document.querySelector(".msg-row.active .msg-from")?.textContent?.trim() || "";
+ const date = (meta.match(/Datum:\s*(.+)/i) || [])[1]?.trim() || document.querySelector(".msg-row.active .msg-date")?.textContent?.trim() || "";
+ return { subject, from, date, body };
+ }
+
+ function prefixedSubject(prefix, subject) {
+ const clean = subject || "";
+ if (new RegExp(`^${prefix}:`, "i").test(clean)) return clean;
+ 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 quoteBody(message) {
+ const lines = (message.body || "").split(/\r?\n/).map((line) => `> ${line}`).join("\n");
+ return `\n\nAm ${message.date || "unbekanntes Datum"} schrieb ${message.from || "unbekannter Absender"}:\n${lines}`;
+ }
+
+ function forwardBody(message) {
+ return `\n\n---------- Weitergeleitete Nachricht ----------\nVon: ${message.from || ""}\nDatum: ${message.date || ""}\nBetreff: ${message.subject || ""}\n\n${message.body || ""}`;
+ }
+
+ function applyListSearch(term) {
+ const q = term.trim().toLowerCase();
+ document.querySelectorAll(".msg-row").forEach((row) => {
+ row.hidden = q !== "" && !row.textContent.toLowerCase().includes(q);
+ });
+ }
+
+ function runSearch(input) {
+ const existing = document.querySelector(".searchbar .search-input");
+ const form = existing?.closest("form");
+ if (existing && form && input.value.trim()) {
+ existing.value = input.value;
+ form.requestSubmit();
+ return;
+ }
+ applyListSearch(input.value);
+ }
+
document.addEventListener("DOMContentLoaded", ensureActionBar);
document.addEventListener("click", (event) => {
+ const row = event.target.closest(".msg-row");
+ if (!row) return;
+ row.closest(".pane")?.querySelectorAll(".msg-row.active").forEach((item) => item.classList.remove("active"));
+ row.classList.add("active");
+ });
+ document.addEventListener("click", (event) => {
+ if (event.target.closest("[data-action-new]")) {
+ openMailto({ to: "", subject: "", body: "" });
+ }
if (event.target.closest("[data-action-refresh]")) window.location.reload();
+ if (event.target.closest("[data-action-reply]")) {
+ const message = selectedPreview();
+ if (!message) {
+ window.alert("Bitte zuerst eine Nachricht waehlen.");
+ return;
+ }
+ openMailto({ to: message.from, subject: prefixedSubject("Re", message.subject), body: quoteBody(message) });
+ }
+ if (event.target.closest("[data-action-forward]")) {
+ const message = selectedPreview();
+ if (!message) {
+ window.alert("Bitte zuerst eine Nachricht waehlen.");
+ return;
+ }
+ openMailto({ to: "", subject: prefixedSubject("Fw", message.subject), body: forwardBody(message) });
+ }
+ });
+ document.addEventListener("input", (event) => {
+ const input = event.target.closest("[data-action-search]");
+ if (input) runSearch(input);
});
})();
diff --git a/frontend-js/dist/style.css b/frontend-js/dist/style.css
index db4e342..802bc40 100644
--- a/frontend-js/dist/style.css
+++ b/frontend-js/dist/style.css
@@ -231,6 +231,14 @@ body.ol2013 {
border-color: #ff9d34;
}
.action-btn.muted { color: #d7e8f5; }
+.action-btn:disabled {
+ cursor: default;
+ opacity: .58;
+}
+.action-btn:disabled:hover {
+ background: transparent;
+ border-color: transparent;
+}
.action-separator {
width: 1px;
height: 26px;