Verbesserung Ablagedialog bei mehreren ausgewählten Dateien

This commit is contained in:
2026-09-09 23:15:14 +02:00
parent 3f96e6f49d
commit 01a972d719
14 changed files with 908 additions and 236 deletions

View File

@@ -256,7 +256,10 @@ async function dialogOeffnen(art, daten) {
// Absender und Dateinamen; das muss nicht bis zum Neustart im Speicher
// liegen, nur weil jemand den Dialog offen stehen liess.
setTimeout(() => auftraege.delete(nummer), 30 * 60 * 1000);
const seite = art === "einfuegen" ? "ui/insert.html" : "ui/store.html";
const seite = {
einfuegen: "ui/insert.html",
schritt: "ui/schritt.html"
}[art] || "ui/store.html";
// Die Adresse MUSS über runtime.getURL aufgelöst werden. Ein relativer
// Pfad wird in Manifest V3 nicht gegen das Erweiterungsverzeichnis
@@ -267,8 +270,12 @@ async function dialogOeffnen(art, daten) {
await browser.windows.create({
url,
type: "popup",
width: art === "einfuegen" ? 760 : 820,
height: art === "einfuegen" ? 640 : 720
// Der Schrittdialog steht zweispaltig. Die Höhe ist auf den Inhalt
// gerechnet: rund 540 px für die Spalten plus Kopf, Meldung und
// Fusszeile, dazu etwas Spielraum - die Systemschrift fällt je
// nach Umgebung anders aus.
width: { schritt: 980, einfuegen: 760 }[art] || 820,
height: { schritt: 760, einfuegen: 640 }[art] || 520
});
} catch (err) {
// Manche Stände lehnen type "popup" ab. Dann ein gewöhnliches Fenster.
@@ -297,6 +304,11 @@ const verbindungen = new Set();
browser.runtime.onConnect.addListener((port) => {
verbindungen.add(port);
console.debug("[paperless] Dialog verbunden, offen:", verbindungen.size);
// Die Lebenszeichen werden nicht ausgewertet - allein ihr Eintreffen
// hält die Ereignisseite wach.
port.onMessage.addListener(() => {});
port.onDisconnect.addListener(() => {
verbindungen.delete(port);
console.debug("[paperless] Dialog getrennt, offen:", verbindungen.size);
@@ -345,8 +357,15 @@ browser.runtime.onMessage.addListener(async (nachricht, absender) => {
return { ok: true, daten: { tags, korr, typen } };
}
case "ablegen":
return { ok: true, daten: await ablegen(nachricht) };
case "schrittOeffnen":
await dialogOeffnen("schritt", nachricht.auftrag);
return { ok: true };
case "dateiListe":
return { ok: true, daten: dateiListe(nachricht.auftrag) };
case "ablegenEine":
return { ok: true, daten: await ablegenEine(nachricht) };
case "klassifizieren": {
const c = await client();
@@ -754,38 +773,91 @@ async function anhangAlsPdf(datei, beschreibung, s) {
};
}
async function ablegen(nachricht) {
/**
* Die Dateien eines Auftrags aufzählen, ohne sie zu laden.
*
* Der Dialog fragt damit ab, wie viele Schritte anstehen, und ruft dann
* jeden einzeln auf.
*/
function dateiListe(auftrag) {
if (auftrag.quelle === "nachricht") {
return [{ art: "nachricht" }];
}
return (auftrag.dateien || [])
.map((d, i) => ({ art: "anhang", index: i, name: d.name }))
.filter((_x, i) => auftrag.dateien[i].ausgewaehlt);
}
/**
* EINE Datei ablegen.
*
* Bewusst je Datei ein eigener Aufruf statt einer Schleife über alle:
*
* * Die Ereignisseite wird in Manifest V3 beendet, sobald sie untätig
* scheint. Ein Aufruf über zehn Anhänge lief regelmäßig in
* "Receiving end does not exist".
* * Der Dialog kann den Fortschritt anzeigen.
* * Scheitert eine Datei, sind die übrigen trotzdem abgelegt.
*/
async function ablegenEine(nachricht) {
const c = await client();
const s = await ladeEinstellungen();
const dateien = await datenHolen(nachricht.auftrag, s);
if (!dateien.length) throw new PaperlessError(t("errNothingSelected"));
const auftrag = nachricht.auftrag;
const eintrag = nachricht.eintrag;
const ergebnisse = [];
for (const datei of dateien) {
if (nachricht.ziel === "vorhanden") {
const antwort = await c.updateVersion(
nachricht.zielId, datei.blob, datei.name,
versionslabel(s.versionLabel));
const id = await c.waitForTask(antwort, (sek) => {
if (sek % 15 === 0) {
console.debug("[paperless] warte auf Aufgabe:", sek, "s");
}
});
ergebnisse.push({ id, name: datei.name, art: "version",
zielId: nachricht.zielId });
let datei;
if (eintrag.art === "nachricht") {
const alle = await datenHolen(auftrag, s);
datei = alle[0];
} else {
const beschreibung = auftrag.dateien[eintrag.index];
const roh = await browser.messages.getAttachmentFile(
beschreibung.messageId, beschreibung.partName);
if (beschreibung.alsPdf
&& umwandelbar(beschreibung.contentType, beschreibung.name)) {
try {
datei = await anhangAlsPdf(roh, beschreibung, s);
} catch (err) {
console.error("[paperless] Aufbereitung gescheitert",
beschreibung.name, err);
datei = { blob: roh, name: sichererName(beschreibung.name) };
}
} else {
const felder = { title: nachricht.titel || datei.name };
if (nachricht.erstellt) felder.created = nachricht.erstellt;
const antwort = await c.postDocument(datei.blob, datei.name, felder);
const id = await c.waitForTask(antwort, (sek) => {
if (sek % 15 === 0) {
console.debug("[paperless] warte auf Aufgabe:", sek, "s");
}
});
ergebnisse.push({ id, name: datei.name, art: "neu" });
datei = { blob: roh, name: sichererName(beschreibung.name) };
}
}
return ergebnisse;
if (!datei) throw new PaperlessError(t("errNothingSelected"));
const melden = (sek) => {
if (sek % 15 === 0) {
console.debug("[paperless] warte auf Aufgabe:", sek, "s");
}
};
if (nachricht.ziel === "vorhanden") {
const antwort = await c.updateVersion(
nachricht.zielId, datei.blob, datei.name,
versionslabel(s.versionLabel));
const id = await c.waitForTask(antwort, melden);
return { id, name: datei.name, art: "version", zielId: nachricht.zielId };
}
// Bei mehreren Dateien wird der Titel um den Dateinamen ergänzt -
// sonst hiessen alle gleich und wären im Archiv nicht auseinander-
// zuhalten.
const grundtitel = nachricht.titel || datei.name;
const titel = nachricht.mehrere
? `${grundtitel} - ${datei.name.replace(/\.[^.]{1,8}$/, "")}`
: grundtitel;
const felder = { title: titel.slice(0, 127) };
if (nachricht.erstellt) felder.created = nachricht.erstellt;
const antwort = await c.postDocument(datei.blob, datei.name, felder);
const id = await c.waitForTask(antwort, melden);
return { id, name: datei.name, art: "neu" };
}
async function aufloesen(c, pfad, name) {