CP_EHRENAMT/app/templates/chat.html
2026-06-25 18:58:44 +02:00

82 lines
3.1 KiB
HTML

{% extends shell_base %}
{% block title %}{{ label }} · CheckPoint Ehrenamt{% endblock %}
{% block content %}
<p><a class="cp-muted" href="{{ url_for('main.team') }}">← Team</a></p>
<h1>{{ label }}</h1>
{% if kanal.nur_admin_darf_posten %}
<p class="cp-muted">Nur das Team-Management postet hier. Alle lesen mit.</p>
{% endif %}
{# data-* steuern das Polling (siehe Skript unten). neu-base + id = JSON-Endpunkt. #}
<ul class="cp-chat" id="cp-chat-liste"
data-neu-base="{{ url_for('chat.kanal', art=kanal.art) }}/seit/"
data-letzte="{{ letzte_id }}"
data-meine="{{ current_user.id }}">
{% for n in nachrichten %}
<li class="cp-msg{{ ' cp-msg--eigen' if n.autor_id == current_user.id else '' }}">
<div class="cp-msg__meta">{{ n.autor.anzeigename }} · {{ zeit(n.erstellt_am) }}</div>
<div class="cp-msg__text">{{ n.text }}</div>
</li>
{% else %}
<li class="cp-muted" id="cp-chat-leer">Noch keine Nachrichten.</li>
{% endfor %}
</ul>
{% if darf_posten %}
<form method="post" action="{{ url_for('chat.posten', art=kanal.art) }}" class="cp-form">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="cp-field">
<label for="text">Nachricht</label>
<textarea id="text" name="text" rows="3" maxlength="2000" required
placeholder="Schreib etwas …"></textarea>
</div>
<button type="submit" class="cp-btn cp-btn--primary">Senden</button>
</form>
{% endif %}
{# Einzige v1-JS-Ausnahme: kleines fetch-Polling für neue Nachrichten.
Einfügen ausschließlich per textContent → kein XSS über Nachrichtentext. #}
<script>
(function () {
const liste = document.getElementById("cp-chat-liste");
if (!liste) return;
const basis = liste.dataset.neuBase;
const meine = Number(liste.dataset.meine || 0);
let letzte = Number(liste.dataset.letzte || 0);
function anhaengen(n) {
const leer = document.getElementById("cp-chat-leer");
if (leer) leer.remove();
const li = document.createElement("li");
li.className = "cp-msg" + (n.autor_id === meine || n.eigene ? " cp-msg--eigen" : "");
const meta = document.createElement("div");
meta.className = "cp-msg__meta";
meta.textContent = n.autor + " · " + n.zeit;
const txt = document.createElement("div");
txt.className = "cp-msg__text";
txt.textContent = n.text;
li.appendChild(meta);
li.appendChild(txt);
liste.appendChild(li);
}
async function holen() {
try {
const r = await fetch(basis + letzte, { headers: { "X-Requested-With": "fetch" } });
if (!r.ok) return;
const daten = await r.json();
if (!daten.nachrichten.length) return;
for (const n of daten.nachrichten) {
anhaengen(n);
if (n.id > letzte) letzte = n.id;
}
window.scrollTo(0, document.body.scrollHeight);
} catch (e) { /* stiller Wiederholversuch beim nächsten Intervall */ }
}
setInterval(holen, 5000);
})();
</script>
{% endblock %}