Files
bin/finance/app/templates/base.html
T
rdmsandClaude Opus 5.5 60cd3c4fea fix: Versionskennung an statischen Dateien gegen veraltete Browser-Caches (v0.13.1)
Gecachte style.css ohne Tortenfarben ließ alle Segmente schwarz erscheinen.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 17:54:55 +02:00

107 lines
4.2 KiB
HTML

<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}Finanzberatung{% endblock %}</title>
<link rel="stylesheet" href="/static/style.css?v={{ app_version }}">
<script src="/static/htmx.min.js?v={{ app_version }}"></script>
<script src="/static/sort.js?v={{ app_version }}"></script>
<script src="/static/doppelzaehlung.js?v={{ app_version }}"></script>
</head>
<body>
<nav>
<a href="/">Übersicht</a>
<a href="/import">Import</a>
<a href="/buchungen">Buchungen</a>
<a href="/salden">Salden</a>
<a href="/planung">Planung</a>
<a href="/szenarien">Szenarien</a>
<a href="/aufteilung">Aufteilung</a>
<a href="/admin">Admin</a>
<a href="/hilfe">Hilfe</a>
<a href="{{ grafana_public_base(request) }}" target="_blank" rel="noopener">Grafana</a>
<form method="post" action="/logout">
<button type="submit">Logout</button>
</form>
</nav>
<main>
{% block content %}{% endblock %}
</main>
<dialog id="doppelzaehlung-dialog">
<h2>Mögliche Doppelzählung</h2>
<p class="dz-meldung"></p>
<ul class="dz-konflikte"></ul>
<p>Trotzdem speichern?</p>
<button type="button" id="dz-abbrechen" autofocus>Abbrechen</button>
<button type="button" id="dz-bestaetigen">Trotzdem speichern</button>
</dialog>
<script>
document.body.addEventListener('htmx:responseError', function (e) {
// Mögliche Doppelzählung Kredit/Fixposten: eigenes Warnfenster statt alert.
if (window.FBDoppel && window.FBDoppel.handle(e)) { return; }
alert('Fehler: ' + (e.detail.xhr.responseText || e.detail.xhr.status));
});
// Minimale JSON-Kodierung für htmx-Formulare/Selects, die gegen die JSON-APIs
// (POST/PATCH /api/...) senden. Felder mit data-type="int" werden als Zahl
// kodiert, leere Werte als null, alles andere bleibt String.
htmx.defineExtension('json-form', {
onEvent: function (name, evt) {
if (name === 'htmx:configRequest') {
evt.detail.headers['Content-Type'] = 'application/json';
}
},
encodeParameters: function (xhr, parameters, elt) {
var out = {};
for (var k in parameters) {
var v = parameters[k];
var field = elt.matches && elt.matches('[name="' + k + '"]')
? elt
: elt.querySelector('[name="' + k + '"]');
var kind = field && field.dataset ? field.dataset.type : null;
if (v === '') {
out[k] = null;
} else if (kind === 'int') {
out[k] = parseInt(v, 10);
} else if (kind === 'amount') {
// Deutsche Betragseingabe: "1.234,56" -> "1234.56". Ohne Komma
// bleibt der Wert unveraendert (Punkt-Eingaben funktionieren weiter).
var s = String(v).replace(/[\s€]/g, '');
if (s.indexOf(',') !== -1) {
s = s.replace(/\./g, '').replace(',', '.');
}
out[k] = s;
} else {
out[k] = v;
}
}
// Checkboxen mit data-type="bool" werden unabhaengig vom parameters-Objekt
// ausgelesen, weil unmarkierte Checkboxen beim Serialisieren komplett
// fehlen wuerden (kein Feld => kein "false" moeglich).
if (elt.querySelectorAll) {
elt.querySelectorAll('[data-type="bool"]').forEach(function (field) {
out[field.name] = field.checked;
});
}
// Bestätigte Doppelzählung (Warnfenster „Trotzdem speichern"):
if (elt.getAttribute && elt.getAttribute('data-doppelzaehlung-bestaetigt') === '1') {
out.doppelzaehlung_bestaetigt = true;
}
xhr.overrideMimeType('text/json');
return JSON.stringify(out);
}
});
function toggleEdit(prefix, id, editing) {
// UX-Regel: Zeilen werden versteckt (hidden), nie aus dem DOM entfernt.
document.getElementById(prefix + '-row-' + id).hidden = editing;
document.getElementById(prefix + '-edit-' + id).hidden = !editing;
}
if (window.FBDoppel) { window.FBDoppel.init(document); }
</script>
<footer class="version">Finanzberatungs-Tool v{{ app_version }}</footer>
</body>
</html>