Initial commit

This commit is contained in:
2026-09-04 19:50:29 +02:00
parent 742e5bc6b2
commit 3ae0ab0a88
37 changed files with 3459 additions and 0 deletions

125
ui/options.js Normal file
View File

@@ -0,0 +1,125 @@
/**
* options.js - Einstellungsseite.
*
* Beim Speichern wird zusätzlich das Zugriffsrecht für genau die
* eingetragene Adresse angefordert. Es steht bewusst nicht pauschal im
* Manifest: Eine Erweiterung, die von Haus aus jede Adresse erreichen
* darf, ist eine unnötig grosse Angriffsfläche.
*/
import { ladeEinstellungen, speichereEinstellungen } from "../lib/settings.js";
import { uebersetzeSeite, ruf, fehlerAnzeigen, meldungAnzeigen }
from "./gemeinsam.js";
const $ = (id) => document.getElementById(id);
const FELDER = ["baseUrl", "token", "versionLabel", "shareDays", "shareTag",
"ignorierteKleiner"];
document.addEventListener("DOMContentLoaded", async () => {
uebersetzeSeite();
const s = await ladeEinstellungen();
for (const f of FELDER) if ($(f)) $(f).value = s[f] ?? "";
$("speichern").addEventListener("click", speichern);
$("pruefen").addEventListener("click", pruefen);
await rechtAnzeigen();
});
/**
* Zustand des Zugriffsrechts anzeigen.
*
* Es ist die häufigste Ursache für ein scheiterndes fetch, und ohne
* Anzeige merkt man erst beim ersten Ablegen, dass es fehlt.
*/
async function rechtAnzeigen() {
// Diese Anzeige ist Beiwerk. Fehlt das Element - etwa weil eine ältere
// options.html geladen ist -, darf das nicht das Speichern verhindern.
const ziel = $("recht");
if (!ziel) return;
const url = $("baseUrl").value.trim();
if (!url) {
ziel.textContent = "";
return;
}
let origin;
try {
origin = new URL(url).origin + "/*";
} catch {
ziel.className = "fehler";
ziel.textContent = browser.i18n.getMessage("errBadUrl") || "Ungültige Adresse.";
return;
}
const erteilt = await browser.permissions.contains({ origins: [origin] });
ziel.className = erteilt ? "hinweis" : "fehler";
ziel.textContent = erteilt
? `Zugriffsrecht erteilt für ${origin}`
: `Zugriffsrecht fehlt für ${origin} — auf Speichern klicken.`;
}
function gelesen() {
return {
baseUrl: $("baseUrl").value.trim().replace(/\/+$/, ""),
token: $("token").value.trim(),
versionLabel: $("versionLabel").value.trim() || "Thunderbird {datum}",
shareDays: Number($("shareDays").value || 0),
shareTag: $("shareTag").value.trim(),
ignorierteKleiner: Number($("ignorierteKleiner").value || 0)
};
}
/**
* Einstellungen speichern und das Zugriffsrecht anfordern.
*
* WICHTIG: permissions.request MUSS als erstes stehen, noch vor jedem
* await. Der Aufruf ist nur aus einer Benutzeraktion heraus zulässig, und
* diese Eigenschaft geht beim ersten await verloren - die Folge wäre
* "permissions.request may only be called from a user input handler".
*
* Ein vorgeschaltetes permissions.contains() ist deshalb ausgeschlossen.
* Das ist auch nicht nötig: request() löst keine Abfrage aus, wenn das
* Recht bereits erteilt ist, sondern liefert sofort true.
*/
function speichern() {
const werte = gelesen();
let origin;
try {
origin = new URL(werte.baseUrl).origin + "/*";
} catch {
fehlerAnzeigen(browser.i18n.getMessage("errBadUrl")
|| "Ungültige Adresse. Erwartet wird https://rechner oder http://rechner.");
return;
}
// Kein await davor. Die Auswertung läuft in der Zusage.
browser.permissions.request({ origins: [origin] })
.then(async (erteilt) => {
if (!erteilt) {
fehlerAnzeigen(browser.i18n.getMessage("errNoPermission")
|| "Ohne Zugriffsrecht auf die Adresse kann die Erweiterung nicht arbeiten.");
await rechtAnzeigen();
return;
}
await speichereEinstellungen(werte);
meldungAnzeigen(browser.i18n.getMessage("msgSaved") || "Gespeichert.");
// Anzeige und Prüfung sind Beiwerk; ein Fehler darin soll nicht
// aussehen, als wäre das Speichern gescheitert.
try { await rechtAnzeigen(); } catch { /* egal */ }
try { await pruefen(); } catch { /* egal */ }
})
.catch((err) => fehlerAnzeigen(err.message));
}
async function pruefen() {
$("status").className = "hinweis";
$("status").textContent = "…";
try {
await speichereEinstellungen(gelesen());
const treffer = await ruf("suchen", { query: "" });
$("status").textContent =
browser.i18n.getMessage("msgConnectionOk", [String(treffer.length)])
|| `Verbindung steht (${treffer.length} Dokumente sichtbar).`;
} catch (err) {
$("status").className = "fehler";
$("status").textContent = String(err.message).slice(0, 200);
}
}