first commit

This commit is contained in:
2026-04-13 08:32:28 +02:00
commit 1074a91487
72 changed files with 4078 additions and 0 deletions

104
app/static/js/app.js Normal file
View File

@@ -0,0 +1,104 @@
(function () {
const dialog = document.getElementById("completeDialog");
const dialogForm = document.getElementById("completeDialogForm");
const dialogChoice = document.getElementById("completeDialogChoice");
const dialogText = document.getElementById("completeDialogText");
const closeButton = document.getElementById("completeDialogClose");
document.querySelectorAll("[data-complete-action]").forEach((button) => {
button.addEventListener("click", () => {
if (!dialog || !dialogForm || !dialogChoice || !dialogText) {
return;
}
dialogForm.action = button.dataset.completeAction;
dialogText.textContent = `Die Aufgabe "${button.dataset.completeTitle}" war ${button.dataset.completeAssigned} zugewiesen. Wer hat sie erledigt?`;
dialog.showModal();
});
});
document.querySelectorAll("[data-complete-choice]").forEach((button) => {
button.addEventListener("click", () => {
dialogChoice.value = button.dataset.completeChoice || "me";
dialog.close();
dialogForm.submit();
});
});
if (closeButton && dialog) {
closeButton.addEventListener("click", () => dialog.close());
}
const pushButton = document.getElementById("pushToggle");
const pushHint = document.getElementById("pushHint");
const vapidKey = document.body.dataset.pushKey;
const isIos = /iphone|ipad|ipod/i.test(window.navigator.userAgent);
const isStandalone =
window.matchMedia("(display-mode: standalone)").matches ||
window.navigator.standalone === true;
function urlBase64ToUint8Array(base64String) {
const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
const raw = atob(base64);
return Uint8Array.from([...raw].map((char) => char.charCodeAt(0)));
}
async function postJSON(url, payload) {
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
return response.json();
}
async function togglePush() {
if (!("serviceWorker" in navigator) || !("PushManager" in window) || !pushButton) {
return;
}
const registration = await navigator.serviceWorker.register("/service-worker.js");
const existing = await registration.pushManager.getSubscription();
if (existing) {
await postJSON("/settings/push/unsubscribe", { endpoint: existing.endpoint });
await existing.unsubscribe();
pushButton.dataset.subscribed = "0";
pushButton.textContent = "Push aktivieren";
return;
}
const permission = await Notification.requestPermission();
if (permission !== "granted") {
return;
}
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(vapidKey),
});
await postJSON("/settings/push/subscribe", subscription.toJSON());
pushButton.dataset.subscribed = "1";
pushButton.textContent = "Push deaktivieren";
}
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/service-worker.js").catch(() => {});
}
if (pushButton && (!("serviceWorker" in navigator) || !("PushManager" in window))) {
pushButton.disabled = true;
if (pushHint) {
pushHint.textContent = "Dieser Browser unterstützt Web-Push hier aktuell nicht.";
}
} else if (pushButton && isIos && !isStandalone) {
pushButton.disabled = true;
if (pushHint) {
pushHint.textContent = "Auf iPhone/iPad funktioniert Web-Push erst nach „Zum Home-Bildschirm“ und Öffnen als Web-App.";
}
} else if (pushButton && vapidKey) {
pushButton.addEventListener("click", () => {
togglePush().catch((error) => console.error("Push toggle failed", error));
});
}
})();