313 lines
7.8 KiB
JavaScript
313 lines
7.8 KiB
JavaScript
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);
|