thunderbird2docuware/dialog/dialog.js

952 lines
36 KiB
JavaScript
Raw Normal View History

// Ablage-Dialog: Schrankwahl, dynamische Felder, Upload.
const $ = (id) => document.getElementById(id);
let STATE = {
messageId: null,
messageIds: [], // alle ausgewählten Nachrichten
settings: null,
meta: null,
attachments: [],
cabinets: [], // alle Ziele (Archive + Briefkörbe)
cabinetId: "",
isBasket: false, // gewähltes Ziel ist ein Briefkorb?
dialogId: null,
fields: [], // Felddefinitionen des Store-Dialogs
existingDoc: null, // Treffer der Dedup-Suche im gewählten Schrank (oder null)
cabinetFieldsByCab: {}, // Cache: cabinetId -> [Feldnamen] (für EML_ID-Erkennung)
// Vollständig abgelegte Nachrichten je Ziel ("<cab>|<mid>") – Tag/Badge nur einmal.
// Ziel im Schlüssel, damit dieselbe Mail bewusst in ein zweites Archiv abgelegt
// werden kann, ohne den Dialog neu zu öffnen.
uploadedIds: new Set(),
// Bereits hochgeladene EINZELTEILE, damit ein Retry nach einem Teilfehler nichts
// doppelt hochlädt. Schlüssel inkl. Ziel-Schrank ("<cab>|<mid>|eml"), damit ein
// Wechsel des Ziels nach einem Fehlversuch wieder alles hochlädt.
uploadedParts: new Set(),
};
// Mail-Token -> Funktion, die den Wert aus den Mail-Metadaten liefert.
// Welches DocuWare-Feld welchen Token bekommt, steht im Mapping (s. effectiveFieldMap).
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
// Zweites Argument ctx trägt Werte, die nicht an der Mail hängen, sondern am
// konkreten Upload: { fileName, attachmentCount }.
const TOKEN_FN = {
senderEmail: (m) => m.senderEmail,
senderName: (m) => m.senderName,
to: (m) => m.to,
cc: (m) => m.cc,
bcc: (m) => m.bcc,
subject: (m) => m.subject,
body: (m) => m.bodyText,
// Nur der Kalendertag: auf lokale Mitternacht gesetzt, damit „Datum" auch in
// einem DateTime- oder Textfeld keine Uhrzeit trägt (gleiche Konvention wie
// archiveDate). Den echten Zeitpunkt liefert dateTime.
date: (m) => dayOnly(m.date),
direction: (m) => m.direction,
size: (m) => m.sizeBytes,
account: (m) => m.account,
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
// Datum/Zeit. date liefert den Kalendertag, dateTime den echten Zeitpunkt –
// in DocuWare braucht letzteres ein Feld vom Typ DateTime, sonst schneidet
// der Server die Uhrzeit ab.
dateTime: (m) => m.date,
time: (m) => fmtTime(m.date),
// archiveDate ist bewusst auf Mitternacht gesetzt: so bleibt es „nur Datum",
// auch wenn es auf ein DateTime-Feld gemappt wird. archiveDateTime trägt die Uhrzeit.
archiveDate: () => dayOnly(new Date()),
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
archiveDateTime: () => new Date(),
// Dokumentbezogen
fileName: (m, ctx) => (ctx && ctx.fileName) || "",
attachmentCount: (m, ctx) => (ctx && ctx.attachmentCount) || 0,
rfcMessageId: (m) => DocuWare.normalizeMessageId(m.rfcMessageId),
// Wer/Woher – aus den Einstellungen bzw. dem Thunderbird-Konto.
dwUser: () => (STATE.settings && STATE.settings.username) || "",
dwOrganization: () => (STATE.settings && STATE.settings.organization) || "",
accountEmail: (m) => m.accountEmail || "",
folder: (m) => m.folder || "",
};
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
// Tokens, deren Wert vom einzelnen hochgeladenen Dokument abhängt. Felder, die
// darauf gemappt sind, werden je Upload neu gesetzt – sonst trüge jeder Anhang
// den Dateinamen der E-Mail.
const PER_FILE_TOKENS = new Set(["fileName"]);
// Aktives Feld-Mapping: eigenes (aus den Einstellungen) wenn gesetzt, sonst Default.
function effectiveFieldMap() {
const m = STATE.settings && STATE.settings.fieldMapping;
return m && Object.keys(m).length ? m : DEFAULT_FIELD_MAP;
}
// Vorbefüllwert für ein DocuWare-Feld (oder undefined). Das Mapping kann je Feld
// entweder einen Mail-Token (String) ODER einen festen Wert ({ const: "NEU" }) tragen.
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
function prefillFor(fieldName, meta, ctx) {
const m = effectiveFieldMap()[fieldName];
if (!m) return undefined;
if (typeof m === "object") {
if (m.const !== undefined && m.const !== null && m.const !== "") return m.const;
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
if (m.token && TOKEN_FN[m.token]) return TOKEN_FN[m.token](meta, ctx);
return undefined;
}
const fn = TOKEN_FN[m];
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
return fn ? fn(meta, ctx) : undefined;
}
// Auf welchen Token ist ein Feld gemappt? (String-Form oder { token }.)
function tokenOf(fieldName) {
const m = effectiveFieldMap()[fieldName];
if (typeof m === "string") return m;
return m && typeof m === "object" ? m.token : undefined;
}
function status(msg, kind) {
const el = $("status");
el.textContent = msg || "";
el.className = kind || "muted";
}
function qs(name) {
return new URLSearchParams(location.search).get(name);
}
async function init() {
// messageIds (Mehrfachauswahl) bevorzugt, sonst einzelnes messageId.
const idsParam = qs("messageIds");
STATE.messageIds = (idsParam ? idsParam.split(",") : [qs("messageId")])
.map((x) => parseInt(x, 10))
.filter((n) => !isNaN(n));
STATE.messageId = STATE.messageIds[0];
STATE.settings = await Settings.get();
if (!STATE.settings.serverUrl) {
status("Bitte zuerst in den Einstellungen Server & Login hinterlegen.", "err");
$("submit").disabled = true;
return;
}
try {
// Anzeige/Vorbefüllung anhand der ersten Nachricht.
STATE.meta = await Mail.getMeta(STATE.messageId);
STATE.attachments = await Mail.listAttachments(STATE.messageId);
} catch (e) {
status(`Mail konnte nicht gelesen werden: ${e.message}`, "err");
return;
}
if (isMulti()) {
$("multiNote").textContent =
`${STATE.messageIds.length} E-Mails werden abgelegt. ` +
"Eingetragene Werte gelten für alle; zugeordnete Felder (Absender/Betreff/Datum …) " +
"werden je E-Mail einzeln übernommen. Anhänge werden – falls aktiviert – je E-Mail " +
"vollständig mit abgelegt. Angezeigt sind die Werte der ersten E-Mail.";
}
renderAttachments();
applyDefaults();
try {
status("Verbinde mit DocuWare …");
await ensureAuth();
await loadCabinets();
status("");
} catch (e) {
status(`Verbindung fehlgeschlagen: ${e.message}`, "err");
}
}
// Holt den Sitzungs-Token vom Hintergrundskript. Ist keiner vorhanden, wird das
// Passwort einmalig abgefragt (nur im RAM, nicht gespeichert) und ein Token geholt.
async function ensureAuth() {
const st = await browser.runtime.sendMessage({ type: "auth:status" });
if (st && st.hasToken && st.token) {
Auth.setToken(st.token);
return;
}
let err = "";
while (true) {
const pw = await askPassword(err);
if (pw === null) throw new Error("Anmeldung abgebrochen.");
status("Anmeldung …");
const res = await browser.runtime.sendMessage({ type: "auth:logon", password: pw });
if (res && res.ok) {
Auth.setToken(res.token);
return;
}
err = (res && res.error) || "Anmeldung fehlgeschlagen.";
}
}
// Zeigt das Passwort-Overlay und löst mit dem eingegebenen Passwort (oder null
// bei Abbruch) auf. Das Passwort verlässt diese Funktion nur Richtung Broker.
function askPassword(errMsg) {
return new Promise((resolve) => {
const ov = $("pwOverlay");
const input = $("pwInput");
$("pwWho").textContent = [STATE.settings.username, STATE.settings.organization]
.filter(Boolean)
.join(" @ ");
$("pwErr").textContent = errMsg || "";
input.value = "";
ov.hidden = false;
input.focus();
const cleanup = (val) => {
ov.hidden = true;
$("pwOk").removeEventListener("click", onOk);
$("pwCancel").removeEventListener("click", onCancel);
input.removeEventListener("keydown", onKey);
resolve(val);
};
const onOk = () => { if (input.value) cleanup(input.value); };
const onCancel = () => cleanup(null);
const onKey = (e) => {
if (e.key === "Enter") { e.preventDefault(); onOk(); }
else if (e.key === "Escape") { e.preventDefault(); onCancel(); }
};
$("pwOk").addEventListener("click", onOk);
$("pwCancel").addEventListener("click", onCancel);
input.addEventListener("keydown", onKey);
});
}
function applyDefaults() {
// Mail-Format (.eml ODER PDF) aus den Einstellungen.
setMailFormat(STATE.settings.mailFormat === "pdf" ? "pdf" : "eml");
const att = $("optAtt");
const want = STATE.settings.storeAttachments !== false;
if (isMulti()) {
// Mehrfachauswahl: STATE.attachments gehört nur zur ERSTEN Mail. Daraus darf
// nicht geschlossen werden, ob die übrigen Anhänge haben – sonst bliebe der
// Haken deaktiviert und die Anhänge aller anderen Mails fielen still weg.
// Ob es etwas hochzuladen gibt, entscheidet submit() je Mail einzeln.
att.checked = want;
att.disabled = false;
$("attList").style.display = "none";
return;
}
// Einzelmail: Haken nur sinnvoll, wenn die Mail überhaupt Anhänge hat.
const hasAtt = STATE.attachments.length > 0;
att.checked = hasAtt && want;
att.disabled = !hasAtt;
$("attList").style.display = hasAtt && att.checked ? "" : "none";
}
function setMailFormat(value) {
const el = document.querySelector(`input[name="mailFormat"][value="${value}"]`);
if (el) el.checked = true;
}
function getMailFormat() {
const el = document.querySelector('input[name="mailFormat"]:checked');
return el ? el.value : "eml";
}
function renderAttachments() {
const ul = $("attList");
ul.innerHTML = "";
// Die Einzelauswahl der Anhänge gilt nur für EINE Mail. Bei Mehrfachauswahl
// würden hier die Anhänge der ersten Mail stehen, die Haken aber nichts tun
// (submit() legt dort je Mail alle Anhänge ab) -> Liste bleibt leer/verborgen.
if (isMulti()) return;
STATE.attachments.forEach((a, i) => {
// Bewusst per DOM-API (nicht innerHTML): der Anhang-Name stammt aus der Mail
// und ist angreiferkontrolliert – als Text einsetzen, nie als HTML.
const li = document.createElement("li");
const cb = document.createElement("input");
cb.type = "checkbox";
cb.id = `att-${i}`;
cb.checked = true;
const label = document.createElement("label");
label.setAttribute("for", `att-${i}`);
label.style.margin = "0";
label.style.fontWeight = "400";
label.textContent = `${a.name} `;
const size = document.createElement("span");
size.className = "muted";
size.textContent = `(${formatSize(a.size)})`;
label.appendChild(size);
li.append(cb, document.createTextNode(" "), label);
ul.appendChild(li);
});
}
async function loadCabinets() {
let cabinets = (await browser.storage.local.get("cabinets")).cabinets;
if (!cabinets || cabinets.length === 0) {
cabinets = await DocuWare.listCabinets(STATE.settings);
await browser.storage.local.set({ cabinets });
}
STATE.cabinets = cabinets;
const sel = $("cabinet");
sel.innerHTML = '<option value="">— bitte wählen —</option>';
const addGroup = (label, list) => {
if (!list.length) return;
const g = document.createElement("optgroup");
g.label = label;
list.forEach((c) => {
const o = document.createElement("option");
o.value = c.id;
o.textContent = c.name;
g.appendChild(o);
});
sel.appendChild(g);
};
addGroup("Archive", cabinets.filter((c) => !c.isBasket));
addGroup("Briefkörbe", cabinets.filter((c) => c.isBasket));
if (STATE.settings.defaultCabinetId) {
sel.value = STATE.settings.defaultCabinetId;
if (sel.value) await onCabinetChange();
}
}
async function onCabinetChange() {
STATE.cabinetId = $("cabinet").value;
STATE.dialogId = null;
STATE.fields = [];
STATE.existingDoc = null;
hideArchivedBanner();
const target = STATE.cabinets.find((c) => String(c.id) === String(STATE.cabinetId));
STATE.isBasket = !!(target && target.isBasket);
$("cabHeading").textContent = target ? `Ablegen in „${target.name}"` : "Ablage";
// Sticky: zuletzt gewählten Schrank als Standard merken.
if (STATE.cabinetId) {
Settings.set({ defaultCabinetId: STATE.cabinetId }).then((s) => (STATE.settings = s));
}
if (!STATE.cabinetId) {
$("fields").innerHTML = '<div class="muted">Ziel wählen …</div>';
return;
}
// Briefkörbe haben keinen Store-Dialog -> keine Indexfelder.
$("dialogRow").style.display = "none";
if (STATE.isBasket) {
$("fields").innerHTML =
'<div class="muted">Briefkorb: keine Indexfelder. Die Dokumente werden ' +
"unindiziert im Briefkorb abgelegt und können dort später archiviert werden.</div>";
return;
}
$("fields").innerHTML = '<div class="muted">Lade Ablagedialog …</div>';
try {
const cands = await DocuWare.listFieldsDialogs(STATE.settings, STATE.cabinetId);
STATE.dialogCands = cands;
if (!cands.length) throw new Error("Kein Store- oder Suchdialog für diesen Schrank gefunden.");
// Auswahl-Dropdown nur zeigen, wenn es mehrere Dialoge gibt.
const ds = $("storeDialog");
ds.innerHTML = "";
cands.forEach((c) => {
const o = document.createElement("option");
o.value = c.id;
o.textContent = c.type === "search" ? `${c.name} (Suchdialog)` : c.name;
ds.appendChild(o);
});
$("dialogRow").style.display = cands.length > 1 ? "grid" : "none";
// Gemerkte Wahl pro Schrank, sonst erster Dialog.
const remembered = (STATE.settings.dialogByCabinet || {})[STATE.cabinetId];
const pick = cands.find((c) => c.id === remembered) || cands[0];
ds.value = pick.id;
await loadDialogFields(pick);
checkExisting(); // „bereits abgelegt?" im gewählten Schrank prüfen (nicht blockierend)
} catch (e) {
$("fields").innerHTML = `<div class="err">${e.message}</div>`;
}
}
// Sucht im gewählten Schrank nach der Message-ID und zeigt ggf. den Banner.
// Setzt STATE.existingDoc als Grundlage für die Dubletten-Warnung beim Ablegen.
async function checkExisting() {
STATE.existingDoc = null;
hideArchivedBanner();
// Bei Mehrfachauswahl nicht prüfen: der Banner bezöge sich nur auf die erste
// Mail, würde aber wie eine Aussage über die ganze Auswahl wirken.
if (isMulti()) return;
if (STATE.isBasket || !STATE.cabinetId || !STATE.meta || !STATE.meta.rfcMessageId) return;
try {
const names = await cabinetFieldNames(STATE.cabinetId);
if (!names.includes("EML_ID")) return; // Schrank ohne Message-ID-Feld -> kein Dedup
const hit = await DocuWare.findByMessageId(
STATE.settings, STATE.cabinetId, STATE.meta.rfcMessageId
);
if (hit) {
STATE.existingDoc = hit;
showArchivedBanner();
}
} catch (_) { /* Dedup ist optional – Fehler ignorieren */ }
}
// Feldnamen eines Schranks (gecacht), um EML_ID-Unterstützung zu erkennen.
async function cabinetFieldNames(cabinetId) {
if (STATE.cabinetFieldsByCab[cabinetId]) return STATE.cabinetFieldsByCab[cabinetId];
const names = await DocuWare.cabinetFieldNames(STATE.settings, cabinetId).catch(() => []);
STATE.cabinetFieldsByCab[cabinetId] = names;
return names;
}
function showArchivedBanner() {
$("archivedBanner").hidden = false;
}
function hideArchivedBanner() {
const el = $("archivedBanner");
if (el) el.hidden = true;
}
// Öffnet das vorhandene DocuWare-Dokument im Browser/Webclient.
function openExistingDoc() {
if (!STATE.existingDoc) return;
const url = DocuWare.documentViewUrl(STATE.settings, STATE.cabinetId, STATE.existingDoc.id);
browser.tabs.create({ url }).catch(() => {
try { window.open(url, "_blank"); } catch (_) {}
});
}
// Dubletten-Abfrage: resolve(true) = trotzdem ablegen, resolve(false) = abbrechen.
function confirmDuplicate() {
return new Promise((resolve) => {
const ov = $("dupOverlay");
ov.hidden = false;
const cleanup = (val) => {
ov.hidden = true;
$("dupProceed").removeEventListener("click", onProceed);
$("dupCancel").removeEventListener("click", onCancel);
$("dupOpen").removeEventListener("click", openExistingDoc);
resolve(val);
};
const onProceed = () => cleanup(true);
const onCancel = () => cleanup(false);
$("dupProceed").addEventListener("click", onProceed);
$("dupCancel").addEventListener("click", onCancel);
$("dupOpen").addEventListener("click", openExistingDoc); // öffnet Doc, Overlay bleibt offen
});
}
// Lädt und rendert die Felder für einen konkreten Dialog.
async function loadDialogFields(pick) {
STATE.dialogId = pick.id;
STATE.dialogType = pick.type;
STATE.fields = [];
$("fields").innerHTML = '<div class="muted">Lade Felder …</div>';
STATE.fields = await DocuWare.getStoreFields(STATE.settings, STATE.cabinetId, STATE.dialogId);
renderFields();
if (pick.type === "search") {
const note = document.createElement("div");
note.className = "muted";
note.style.marginTop = "6px";
note.textContent =
"Hinweis: Kein Store-Dialog verfügbar – Felder stammen aus dem Suchdialog.";
$("fields").appendChild(note);
}
}
// Nutzer wählt einen anderen Ablagedialog -> merken (pro Schrank) und neu laden.
async function onStoreDialogChange() {
const id = $("storeDialog").value;
const pick = (STATE.dialogCands || []).find((c) => c.id === id);
if (!pick) return;
const map = { ...(STATE.settings.dialogByCabinet || {}), [STATE.cabinetId]: id };
STATE.settings = await Settings.set({ dialogByCabinet: map });
try {
await loadDialogFields(pick);
} catch (e) {
$("fields").innerHTML = `<div class="err">${e.message}</div>`;
}
}
function renderFields() {
const container = $("fields");
container.innerHTML = "";
for (const f of STATE.fields) {
const wrap = document.createElement("div");
wrap.className = "field" + (isMemo(f) ? " full" : "");
wrap.dataset.name = f.name;
wrap.dataset.type = f.type;
wrap.dataset.required = f.required ? "1" : "";
const label = document.createElement("label");
label.textContent = f.label;
if (f.required) {
const r = document.createElement("span");
r.className = "req"; r.textContent = " *";
label.appendChild(r);
}
wrap.appendChild(label);
const input = buildInput(f);
wrap.appendChild(input);
if (input._datalist) wrap.appendChild(input._datalist);
container.appendChild(wrap);
}
applyFieldDefaults(); // vordefinierte Werte (PrefillValue) zuerst
prefillFields(); // Mail-Vorbefüllung überschreibt gemappte Felder
populateSelectLists(); // Auswahllisten/Vorschläge asynchron nachladen
}
// Baut das Eingabe-Element (synchron). Auswahllisten werden später befüllt.
function buildInput(f) {
const t = (f.type || "").toLowerCase();
let el;
if (isMemo(f)) {
el = document.createElement("textarea");
} else if (f.isSelectList && f.selectListOnly) {
// Nur Listenwerte erlaubt -> starres Dropdown.
el = document.createElement("select");
el.innerHTML = '<option value=""></option>';
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
} else if (t.includes("datetime")) {
// DateTime-Feld: Tag UND Uhrzeit erfassbar (vor dem reinen date-Zweig prüfen).
el = document.createElement("input");
el.type = "datetime-local";
// Ohne step="1" kennt das Control nur Minuten und schneidet die Sekunden ab.
el.step = "1";
} else if (t.includes("date")) {
el = document.createElement("input");
el.type = "date";
} else if (t.includes("decimal") || t.includes("numeric") || t.includes("int")) {
el = document.createElement("input");
el.type = "number"; el.step = "any";
} else {
el = document.createElement("input");
el.type = "text";
if (f.isSelectList) {
// Combobox: frei tippbar mit Vorschlagsliste (wie in Connect-to-Outlook).
const dl = document.createElement("datalist");
// Feldnamen können Leer-/Sonderzeichen enthalten -> auf gültige id-Zeichen reduzieren.
dl.id = "dl-" + String(f.name).replace(/[^A-Za-z0-9_-]/g, "_");
el.setAttribute("list", dl.id);
el._datalist = dl;
}
}
el.dataset.role = "value";
if (f.readOnly && el.tagName !== "SELECT") el.readOnly = true;
return el;
}
// Vordefinierte Werte (PrefillValue aus dem Dialog) eintragen.
function applyFieldDefaults() {
STATE.fields.forEach((f) => {
if (f.prefill === undefined || f.prefill === null || f.prefill === "") return;
setFieldValue(f.name, f, f.prefill);
});
}
function prefillFields() {
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
const ctx = formCtx();
STATE.fields.forEach((f) => {
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
const val = prefillFor(f.name, STATE.meta, ctx);
if (val === undefined || val === null || val === "") return;
setFieldValue(f.name, f, val);
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
// Dateiname-Felder sind nur eine Vorschau: beim Ablegen trägt jeder Anhang
// seinen eigenen Namen. Im Tooltip erklären, statt still zu überschreiben.
if (PER_FILE_TOKENS.has(tokenOf(f.name))) {
const wrap = document.querySelector(`.field[data-name="${cssEsc(f.name)}"]`);
const el = wrap && wrap.querySelector("[data-role='value']");
if (el) el.title = "Wird beim Ablegen je Dokument gesetzt (Anhänge tragen ihren eigenen Dateinamen).";
}
});
}
// Setzt einen Wert auf das Control eines Feldes (kümmert sich um Datum/Select).
function setFieldValue(name, f, val) {
const wrap = document.querySelector(`.field[data-name="${cssEsc(name)}"]`);
const el = wrap && wrap.querySelector("[data-role='value']");
if (!el) return;
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
if (el.type === "date" || el.type === "datetime-local") {
const d = val instanceof Date ? val : new Date(val);
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
if (!isNaN(d)) el.value = el.type === "date" ? toDateInput(d) : toDateTimeInput(d);
} else if (el.tagName === "SELECT") {
let opt = Array.from(el.options).find((o) => o.value === String(val));
if (!opt) {
opt = document.createElement("option");
opt.value = String(val); opt.textContent = String(val);
el.appendChild(opt);
}
el.value = String(val);
} else {
// Textfeld: Datum lesbar ausschreiben ("04.08.2026 16:28:51"). Früher lief
// hier toDateInput – das warf die Uhrzeit weg, obwohl ein Textfeld sie
// problemlos trägt (genau der Fall „Datum + Uhrzeit" ohne Uhrzeit).
el.value = val instanceof Date ? DocuWare.dateToText(val) : String(val);
}
wrap.classList.add("prefilled");
}
// Lädt die Auswahllisten-Werte und füllt Dropdowns/Vorschlagslisten.
async function populateSelectLists() {
for (const f of STATE.fields) {
if (!f.isSelectList) continue;
let vals = [];
try {
vals = await DocuWare.getSelectList(
STATE.settings, STATE.cabinetId, STATE.dialogId, f.name
);
} catch (_) { /* leere Liste ist ok */ }
if (!vals.length) continue;
const wrap = document.querySelector(`.field[data-name="${cssEsc(f.name)}"]`);
const el = wrap && wrap.querySelector("[data-role='value']");
if (!el) continue;
if (el.tagName === "SELECT") {
const current = el.value;
vals.forEach((v) => {
if (!Array.from(el.options).some((o) => o.value === v)) {
const o = document.createElement("option");
o.value = v; o.textContent = v;
el.appendChild(o);
}
});
if (current) el.value = current;
} else {
const dl = el._datalist || document.getElementById(el.getAttribute("list"));
if (dl) {
dl.innerHTML = "";
vals.forEach((v) => {
const o = document.createElement("option");
o.value = v;
dl.appendChild(o);
});
}
}
}
}
function collectFieldValues() {
const result = {};
let firstInvalid = null;
document.querySelectorAll(".field").forEach((wrap) => {
wrap.classList.remove("invalid");
const el = wrap.querySelector("[data-role='value']");
const name = wrap.dataset.name;
const type = wrap.dataset.type;
const required = wrap.dataset.required === "1";
const raw = el ? el.value : "";
if (required && !String(raw).trim()) {
wrap.classList.add("invalid");
if (!firstInvalid) firstInvalid = name;
}
if (String(raw).trim() !== "") {
// Date-Input als LOKALE Mitternacht parsen (raw+"T00:00:00"), sonst
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
// interpretiert new Date("YYYY-MM-DD") als UTC. datetime-local ist bereits
// lokal und wird direkt geparst.
const value =
el.type === "date" ? new Date(`${raw}T00:00:00`)
: el.type === "datetime-local" ? new Date(raw)
: raw;
result[name] = { value, type };
}
});
return { result, firstInvalid };
}
async function submit() {
if (!STATE.cabinetId) { status("Bitte ein Ziel wählen.", "err"); return; }
let result = {};
if (!STATE.isBasket) {
const collected = collectFieldValues();
if (collected.firstInvalid) {
status(`Pflichtfeld fehlt: ${collected.firstInvalid}`, "err");
return;
}
result = collected.result;
}
const fmt = getMailFormat(); // "eml" ODER "pdf" – nie beides
const wantEml = fmt === "eml";
const wantPdf = fmt === "pdf";
const att = $("optAtt");
const wantAttScope = att.checked && !att.disabled;
// Dubletten-Warnung (nur Einzelmail): liegt die Mail im Ziel schon, warnen –
// „Trotzdem ablegen" bleibt aber möglich.
if (!isMulti() && !STATE.isBasket && STATE.meta.rfcMessageId) {
let hit = STATE.existingDoc;
if (!hit) {
const names = await cabinetFieldNames(STATE.cabinetId);
if (names.includes("EML_ID")) {
hit = await DocuWare.findByMessageId(
STATE.settings, STATE.cabinetId, STATE.meta.rfcMessageId
).catch(() => null);
}
}
if (hit) {
STATE.existingDoc = hit;
showArchivedBanner();
const proceed = await confirmDuplicate();
if (!proceed) return;
}
}
await saveOptionPrefs(fmt, wantAttScope); // Sticky: Format + Anhänge-Wahl merken
$("submit").disabled = true;
const multi = isMulti();
let tagFailed = false;
let current = ""; // zuletzt bearbeitete Mail – für eine brauchbare Fehlermeldung
try {
const fieldNames = STATE.isBasket ? [] : await cabinetFieldNames(STATE.cabinetId);
let mi = 0;
for (const mid of STATE.messageIds) {
mi++;
// Retry-Schutz: in DIESES Ziel bereits vollständig abgelegt -> überspringen.
if (STATE.uploadedIds.has(`${STATE.cabinetId}|${mid}`)) continue;
const prefix = multi ? `Mail ${mi}/${STATE.messageIds.length}: ` : "";
current = multi ? `Mail ${mi}/${STATE.messageIds.length}` : "";
// Meta/Anhänge der jeweiligen Nachricht.
const meta = mid === STATE.messageId ? STATE.meta : await Mail.getMeta(mid);
const atts =
mid === STATE.messageId ? STATE.attachments : await Mail.listAttachments(mid);
// Indexfelder: manuelle Werte für alle gleich; gemappte Felder je Mail neu.
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
const msgCtx = { attachmentCount: atts.length };
const fields = STATE.isBasket ? {} : fieldsForMessage(result, meta, multi, msgCtx);
// Message-ID für Dedup/„bereits abgelegt" mitschreiben (wenn Schrank EML_ID hat).
if (!STATE.isBasket && meta.rfcMessageId && fieldNames.includes("EML_ID")) {
fields.EML_ID = { value: DocuWare.normalizeMessageId(meta.rfcMessageId), type: "Text" };
}
const wantAtt = wantAttScope && atts.length > 0;
if (wantEml) {
await uploadOnce(`${mid}|eml`, async () => {
status(`${prefix}E-Mail …`);
const eml = await Mail.getEmlFile(mid, meta.subject);
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
const ef = applyPerFileFields(fields, meta, { ...msgCtx, fileName: eml.name });
await DocuWare.uploadDocument(STATE.settings, STATE.cabinetId, eml, eml.name, ef);
});
}
if (wantPdf) {
await uploadOnce(`${mid}|pdf`, async () => {
status(`${prefix}PDF …`);
const pdf = Pdf.fromMail(meta);
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
const pf = applyPerFileFields(fields, meta, { ...msgCtx, fileName: pdf.name });
await DocuWare.uploadDocument(STATE.settings, STATE.cabinetId, pdf, pdf.name, pf);
});
}
if (wantAtt) {
// Bei Einzelmail: angehakte Anhänge. Bei Mehrfach: alle Anhänge je Mail.
const indices = multi ? atts.map((_, i) => i) : selectedAttachmentIndices();
for (const i of indices) {
const a = atts[i];
if (!a) continue;
await uploadOnce(`${mid}|att:${a.partName}`, async () => {
status(`${prefix}Anhang ${a.name} …`);
const file = await Mail.getAttachmentFile(mid, a.partName);
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
// Anhang trägt seinen EIGENEN Dateinamen – sowohl in gemappten
// fileName-Feldern als auch im festen DOC_FILE_NAME.
const af = STATE.isBasket
? {}
: {
...applyPerFileFields(fields, meta, { ...msgCtx, fileName: a.name }),
DOC_FILE_NAME: { value: a.name, type: "Text" },
};
await DocuWare.uploadDocument(STATE.settings, STATE.cabinetId, file, a.name, af);
});
}
}
if (STATE.settings.tagOnSuccess) {
try { await tagMessage(mid); }
catch (te) { console.warn("DocuWare-Markierung fehlgeschlagen:", te); tagFailed = true; }
}
// Background-Badge aktualisieren (Mail gilt jetzt als abgelegt).
if (meta.rfcMessageId) {
browser.runtime
.sendMessage({ type: "archive:done", rfcMessageId: meta.rfcMessageId, cabinetId: STATE.cabinetId })
.catch(() => {});
}
// In diesem Ziel vollständig abgelegt -> bei einem späteren Retry überspringen.
STATE.uploadedIds.add(`${STATE.cabinetId}|${mid}`);
}
const base = multi ? `${STATE.messageIds.length} E-Mails abgelegt.` : "Erfolgreich abgelegt.";
status(tagFailed ? `${base} (Markierung nicht möglich)` : base, "ok");
setTimeout(() => window.close(), tagFailed ? 2500 : 1200);
} catch (e) {
// Bei Mehrfachauswahl sagen, WO es hakte – und dass ein erneuter Klick die
// bereits übertragenen E-Mails/Teile überspringt (kein Dublettenrisiko).
const where = current ? ` (${current})` : "";
const hint = multi ? " Bereits abgelegtes wird bei erneutem Klick übersprungen." : "";
status(`Fehler beim Ablegen${where}: ${e.message}${hint}`, "err");
$("submit").disabled = false;
}
}
// Lädt einen Teil (eml/pdf/Anhang) genau EINMAL hoch. Schlägt ein späterer Teil
// fehl und der Nutzer klickt erneut auf „Ablegen", werden die bereits erfolgreich
// übertragenen Teile übersprungen – sonst entstünden Dubletten in DocuWare.
async function uploadOnce(part, doUpload) {
const key = `${STATE.cabinetId}|${part}`;
if (STATE.uploadedParts.has(key)) return;
await doUpload();
STATE.uploadedParts.add(key);
}
// Indexfelder für eine konkrete Nachricht: gemappte Felder (EML_*/generisch)
// werden je Mail aus deren Metadaten neu berechnet, manuelle Werte bleiben.
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
function fieldsForMessage(baseResult, meta, multi, ctx) {
if (!multi) return baseResult; // Einzelmail: manuelle Edits respektieren
const result = { ...baseResult };
STATE.fields.forEach((f) => {
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
const val = prefillFor(f.name, meta, ctx);
if (val === undefined || val === null || val === "") return;
result[f.name] = { value: val, type: f.type };
});
return result;
}
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
// Felder, die auf ein dokumentabhängiges Token (fileName) gemappt sind, für
// GENAU dieses Dokument setzen – auch bei Einzelmail, weil ein Formularwert
// nicht gleichzeitig für .eml und jeden Anhang stimmen kann.
function applyPerFileFields(fields, meta, ctx) {
if (STATE.isBasket) return fields; // Briefkorb: keine Indexfelder
const out = { ...fields };
STATE.fields.forEach((f) => {
if (!PER_FILE_TOKENS.has(tokenOf(f.name))) return;
const val = prefillFor(f.name, meta, ctx);
if (val === undefined || val === null || val === "") return;
out[f.name] = { value: val, type: f.type };
});
return out;
}
// Sticky: zuletzt genutztes Format + Anhänge-Wahl in den Einstellungen merken.
async function saveOptionPrefs(mailFormat, storeAttachments) {
try {
STATE.settings = await Settings.set({ mailFormat, storeAttachments });
} catch (_) { /* nicht kritisch */ }
}
function selectedAttachmentIndices() {
return STATE.attachments
.map((_, i) => i)
.filter((i) => { const c = $(`att-${i}`); return c && c.checked; });
}
// Markiert die Mail mit dem Tag "DocuWare". Wirft bei Fehler (Aufrufer fängt).
async function tagMessage(messageId) {
const KEY = "docuware";
const NAME = "DocuWare";
const COLOR = "#0e8a8a";
// Tags-API unterscheidet sich je nach Thunderbird-Version.
const api = browser.messages.tags;
let list = [];
if (api && api.list) list = await api.list();
else if (browser.messages.listTags) list = await browser.messages.listTags();
let tag = list.find((t) => t.key === KEY || t.tag === NAME);
if (!tag) {
if (api && api.create) await api.create(KEY, NAME, COLOR);
else if (browser.messages.createTag) await browser.messages.createTag(KEY, NAME, COLOR);
tag = { key: KEY };
}
const msg = await browser.messages.get(messageId);
const current = msg.tags || [];
if (!current.includes(tag.key)) {
await browser.messages.update(messageId, { tags: [...current, tag.key] });
}
}
// --- Helfer ---
// Mehrfachauswahl? Steuert Anhang-Liste, Dubletten-Banner und Feldberechnung.
const isMulti = () => STATE.messageIds.length > 1;
const isMemo = (f) => /memo/i.test(f.type) || f.name === "EML_BODY";
// Lokales Datum als YYYY-MM-DD (NICHT toISOString -> das rechnet auf UTC um und
// kippt eine Uhrzeit nahe Mitternacht auf den Vortag).
const toDateInput = (d) => {
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
};
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
// Lokal als YYYY-MM-DDTHH:MM für <input type="datetime-local">.
const toDateTimeInput = (d) => `${toDateInput(d)}T${fmtTime(d)}`;
// Uhrzeit HH:MM lokal (auch als eigenständiger Text-Token nutzbar).
// Kalendertag ohne Uhrzeit (lokale Mitternacht). Funktionsdeklaration, damit
// TOKEN_FN sie oben im Modul schon verwenden kann.
function dayOnly(d) {
const dt = d instanceof Date ? d : new Date(d);
if (isNaN(dt)) return dt;
return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
}
// Uhrzeit inkl. Sekunden ("16:28:51"). Die Sekunden braucht auch
// toDateTimeInput – ein datetime-local mit step="1" nimmt sie entgegen.
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
function fmtTime(d) {
const dt = d instanceof Date ? d : new Date(d);
if (isNaN(dt)) return "";
const p = (n) => String(n).padStart(2, "0");
return `${p(dt.getHours())}:${p(dt.getMinutes())}:${p(dt.getSeconds())}`;
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
}
// Dateiname, den die E-Mail selbst beim Upload bekäme – für die Vorschau im
// Formular. Beim tatsächlichen Upload gilt der echte Name (siehe submit()).
function previewFileName() {
const subj = (STATE.meta && STATE.meta.subject) || "";
const base = subj.replace(/[\\/:*?"<>|]+/g, "_").slice(0, 80).trim() || "email";
return `${base}.${getMailFormat() === "pdf" ? "pdf" : "eml"}`;
}
// Kontext für die Token-Auflösung im Formular (Vorschauwerte).
function formCtx() {
return { fileName: previewFileName(), attachmentCount: STATE.attachments.length };
}
// Sicheres CSS-Escaping für Attribut-Selektoren (Feldnamen aus DocuWare).
const cssEsc = (s) =>
window.CSS && CSS.escape ? CSS.escape(String(s)) : String(s).replace(/["\\\]]/g, "\\$&");
function formatSize(b) {
if (!b) return "–";
if (b < 1024) return `${b} B`;
if (b < 1024 * 1024) return `${(b / 1024).toFixed(0)} KB`;
return `${(b / 1024 / 1024).toFixed(1)} MB`;
}
function resetForm() {
document.querySelectorAll(".field").forEach((wrap) => {
const el = wrap.querySelector("[data-role='value']");
if (el) el.value = "";
wrap.classList.remove("prefilled", "invalid");
});
applyFieldDefaults();
prefillFields();
applyDefaults();
status("");
}
$("cabinet").addEventListener("change", onCabinetChange);
$("storeDialog").addEventListener("change", onStoreDialogChange);
$("openExisting").addEventListener("click", openExistingDoc);
$("submit").addEventListener("click", submit);
$("reset").addEventListener("click", resetForm);
$("cancel").addEventListener("click", () => window.close());
// Sticky: Optionen sofort bei Änderung merken (nicht erst beim Ablegen).
document.querySelectorAll('input[name="mailFormat"]').forEach((r) =>
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
r.addEventListener("change", () => {
refreshPerFilePreview(); // .eml ↔ .pdf: Dateiname-Vorschau nachziehen
saveOptionPrefs(getMailFormat(), $("optAtt").checked);
})
);
Feld-Zuordnung: Dateiname, Datum+Uhrzeit, Benutzer und weitere Werte MAIL_TOKENS wächst von 11 auf 22 auswählbare Werte: - Dokument: fileName (je Dokument), attachmentCount, rfcMessageId - Datum/Zeit: dateTime, time, archiveDate, archiveDateTime - Wer/Woher: dwUser, dwOrganization, accountEmail, folder fileName kann nicht wie die übrigen Tokens einmal je Mail aufgelöst werden: die .eml/PDF trägt den Mailnamen, jeder Anhang seinen eigenen. Darum tragen TOKEN_FN jetzt ein zweites Argument ctx {fileName, attachmentCount}, und Felder, die auf ein Token aus PER_FILE_TOKENS gemappt sind, werden über applyPerFileFields() vor JEDEM Upload neu gesetzt. Im Formular steht nur eine Vorschau (Tooltip erklärt das), die beim Umschalten .eml <-> PDF nachzieht. Fix DateTime-Felder: _field prüfte t.includes("date") zuerst, und "DateTime" enthält "date" — jedes DocuWare-DateTime-Feld wurde damit auf UTC-Mitternacht normalisiert und verlor die Uhrzeit. Das betraf auch bestehende Zuordnungen. Jetzt wird datetime zuerst geprüft; der Dialog rendert solche Felder als datetime-local und liest sie lokal zurück. Date-Felder bleiben unverändert auf dem lokalen Kalendertag als UTC-Mitternacht. Offen und im Code vermerkt: ob DocuWare bei DateTime das "Z" auswertet oder die ISO-Zeichenkette als lokale Wanduhrzeit liest, ist nicht gegen einen Server verifiziert. Mail.getMeta liefert zusätzlich folder und accountEmail; _accountForMessage wurde zu _accountInfo (Name + Identitäts-Adresse). DEFAULT_FIELD_MAP: DOC_FILE_NAME -> fileName. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:55:32 +00:00
// Aktualisiert die Vorschauwerte dokumentabhängiger Felder (Dateiname).
function refreshPerFilePreview() {
const ctx = formCtx();
STATE.fields.forEach((f) => {
if (!PER_FILE_TOKENS.has(tokenOf(f.name))) return;
const val = prefillFor(f.name, STATE.meta, ctx);
if (val !== undefined && val !== null && val !== "") setFieldValue(f.name, f, val);
});
}
$("optAtt").addEventListener("change", () => {
const show = !isMulti() && $("optAtt").checked && STATE.attachments.length > 0;
$("attList").style.display = show ? "" : "none";
saveOptionPrefs(getMailFormat(), $("optAtt").checked);
});
init();