const DEFAULT_RANGE_KEY = "last_24h"; const MAX_INTERVAL_MINUTES = 30 * 24 * 60; const RANGE_OPTIONS = { last_hour: { label: "Letzte Stunde", sinceMs: 60 * 60 * 1000 }, last_24h: { label: "Letzte 24 Stunden", sinceMs: 24 * 60 * 60 * 1000 }, last_7d: { label: "Letzte 7 Tage", sinceMs: 7 * 24 * 60 * 60 * 1000 }, last_4w: { label: "Letzte 4 Wochen", sinceMs: 28 * 24 * 60 * 60 * 1000 }, all_time: { label: "Gesamter Zeitraum", sinceMs: null } }; const UNIT_FACTORS = { minutes: 1, hours: 60, days: 24 * 60 }; const elements = {}; function getStorage(keys) { return new Promise((resolve, reject) => { chrome.storage.local.get(keys, (result) => { const error = chrome.runtime.lastError; if (error) { reject(new Error(error.message)); return; } resolve(result || {}); }); }); } function setStorage(values) { return new Promise((resolve, reject) => { chrome.storage.local.set(values, () => { const error = chrome.runtime.lastError; if (error) { reject(new Error(error.message)); return; } resolve(); }); }); } function sendMessage(message) { return new Promise((resolve, reject) => { chrome.runtime.sendMessage(message, (response) => { const error = chrome.runtime.lastError; if (error) { reject(new Error(error.message)); return; } if (!response || response.ok !== true) { reject(new Error(response && response.error ? response.error : "Die Aktion konnte nicht ausgefuehrt werden.")); return; } resolve(response); }); }); } function populateRangeOptions() { elements.rangeSelect.textContent = ""; Object.entries(RANGE_OPTIONS).forEach(([value, option]) => { const item = document.createElement("option"); item.value = value; item.textContent = option.label; elements.rangeSelect.appendChild(item); }); } function formatTimestamp(timestamp, fallbackText) { if (!Number.isFinite(timestamp)) { return fallbackText; } const date = new Date(timestamp); if (Number.isNaN(date.getTime())) { return fallbackText; } return new Intl.DateTimeFormat("de-DE", { dateStyle: "short", timeStyle: "medium" }).format(date); } function setMessage(text, state) { elements.messageValue.textContent = text; elements.messageValue.classList.remove("message-error", "message-success"); if (state === "error") { elements.messageValue.classList.add("message-error"); } if (state === "success") { elements.messageValue.classList.add("message-success"); } } function setBusy(isBusy) { elements.clearNowButton.disabled = isBusy; elements.saveTimerButton.disabled = isBusy; elements.clearTimerButton.disabled = isBusy; } function renderStatus(lastRun, timerConfig) { const timer = timerConfig || {}; elements.lastRunValue.textContent = formatTimestamp(Number(lastRun), "Noch nie"); elements.timerStateValue.textContent = timer.enabled ? `Aktiv (${timer.repeat ? "Wiederholung" : "einmalig"})` : "Inaktiv"; elements.nextRunValue.textContent = timer.enabled ? formatTimestamp(Number(timer.nextRun), "Nicht geplant") : "Nicht geplant"; } function applyState(state) { const selectedRange = RANGE_OPTIONS[state.selectedRange] ? state.selectedRange : DEFAULT_RANGE_KEY; const timerConfig = state.timerConfig || {}; elements.rangeSelect.value = selectedRange; if (Number.isFinite(timerConfig.intervalValue) && timerConfig.intervalValue > 0) { elements.intervalValue.value = String(timerConfig.intervalValue); } if (UNIT_FACTORS[timerConfig.intervalUnit]) { elements.intervalUnit.value = timerConfig.intervalUnit; } elements.repeatCheckbox.checked = Boolean(timerConfig.repeat); renderStatus(state.lastRun, timerConfig); } async function loadState() { const state = await getStorage(["selectedRange", "lastRun", "timerConfig"]); applyState(state); } function validateTimerInput() { const rangeKey = elements.rangeSelect.value; const intervalText = elements.intervalValue.value.trim(); const intervalValue = Number(intervalText); const intervalUnit = elements.intervalUnit.value; if (!RANGE_OPTIONS[rangeKey]) { throw new Error("Bitte einen gueltigen Zeitraum auswaehlen."); } if (intervalText === "" || !Number.isFinite(intervalValue)) { throw new Error("Das Intervall muss eine Zahl sein."); } if (intervalValue <= 0) { throw new Error("Das Intervall muss groesser als 0 sein."); } if (!UNIT_FACTORS[intervalUnit]) { throw new Error("Bitte eine gueltige Einheit auswaehlen."); } const intervalMinutes = intervalValue * UNIT_FACTORS[intervalUnit]; if (intervalMinutes < 1) { throw new Error("Das Mindestintervall betraegt 1 Minute."); } if (intervalMinutes > MAX_INTERVAL_MINUTES) { throw new Error("Das Maximalintervall betraegt 30 Tage."); } return { rangeKey, repeat: elements.repeatCheckbox.checked, intervalValue, intervalUnit, intervalMinutes }; } async function saveSelectedRange() { try { await setStorage({ selectedRange: elements.rangeSelect.value }); } catch (error) { setMessage(error.message, "error"); } } async function handleClearNow() { setBusy(true); setMessage("Cache wird geloescht.", "success"); try { const rangeKey = elements.rangeSelect.value; await sendMessage({ type: "CLEAR_CACHE", rangeKey }); await loadState(); setMessage("Cache wurde geleert.", "success"); } catch (error) { setMessage(error.message, "error"); } finally { setBusy(false); } } async function handleSaveTimer() { setBusy(true); try { const config = validateTimerInput(); await sendMessage({ type: "SET_TIMER", config }); await loadState(); setMessage("Timer gespeichert.", "success"); } catch (error) { setMessage(error.message, "error"); } finally { setBusy(false); } } async function handleClearTimer() { setBusy(true); try { await sendMessage({ type: "CLEAR_TIMER" }); await loadState(); setMessage("Timer deaktiviert.", "success"); } catch (error) { setMessage(error.message, "error"); } finally { setBusy(false); } } function cacheElements() { elements.rangeSelect = document.getElementById("rangeSelect"); elements.clearNowButton = document.getElementById("clearNowButton"); elements.intervalValue = document.getElementById("intervalValue"); elements.intervalUnit = document.getElementById("intervalUnit"); elements.repeatCheckbox = document.getElementById("repeatCheckbox"); elements.saveTimerButton = document.getElementById("saveTimerButton"); elements.clearTimerButton = document.getElementById("clearTimerButton"); elements.lastRunValue = document.getElementById("lastRunValue"); elements.timerStateValue = document.getElementById("timerStateValue"); elements.nextRunValue = document.getElementById("nextRunValue"); elements.messageValue = document.getElementById("messageValue"); } function bindEvents() { elements.rangeSelect.addEventListener("change", saveSelectedRange); elements.clearNowButton.addEventListener("click", handleClearNow); elements.saveTimerButton.addEventListener("click", handleSaveTimer); elements.clearTimerButton.addEventListener("click", handleClearTimer); chrome.storage.onChanged.addListener((changes, areaName) => { if (areaName !== "local") { return; } if (changes.lastRun || changes.timerConfig || changes.selectedRange) { loadState().catch((error) => { setMessage(error.message, "error"); }); } }); } async function init() { cacheElements(); populateRangeOptions(); bindEvents(); try { await loadState(); } catch (error) { setMessage(error.message, "error"); } } document.addEventListener("DOMContentLoaded", init);