Nichts verschwindet mehr ohne eine Nachfrage, die sagt was passiert
Filipe: "Es darf vor allem keine Stellen geben, an denen ein Benutzer
etwas falsch machen kann, nur weil die Seite es nicht verstaendlich
genug erklaert."
Gemessen: 30 Stellen in 16 Dateien benutzten confirm() oder prompt().
Das Haus hatte die richtige Bauweise laengst -- einen <dialog>, in
aufgaben.html sogar ausfuehrlich begruendet -- aber sie stand IN EINER
SEITE. Wer anderswo etwas loeschen liess, hatte sie nicht.
confirm('Wirklich loeschen?') stellt die falsche Frage: Es fragt, ob
man sicher ist, und nennt nicht, WAS passiert, was BLEIBT und ob es
ZURUECK geht. Jetzt beantwortet jeder der 41 Dialoge alle drei.
Neu: workspace/assets/js/nachfrage.js -- window.frageNach() mit
Pflichtgrund, Zahlenfeld, einzeiliger Eingabe und Abtippsicherung.
Drei Ausgaenge: <dialog> / confirm()-Notnagel fuer Safari vor 15.4 /
Abbruch (Esc, Klick daneben, "Doch nicht" -- immer false).
DREIMAL DERSELBE FALLSTRICK, dreimal nachgemessen statt vermutet:
.dialog stand in aufgaben.css und leistung.css -> auf dateien.html
waere der Dialog ein weisser Systemkasten gewesen. 14 Regeln
klammergenau nach module.css verschoben (Klammern gezaehlt, nicht
per Muster geschnitten -- heute frueh hat ein nicht-gieriges
Muster schon einmal CSS zerrissen).
Das Formular trug .neu neu--blank -- und .neu gibt seine Abstaende
nur in aufgaben.css. Gemessen: padding 0px, und die Felder
verloren ihre height:44px. Jetzt steht alles unter
.nachfrage__form in module.css; der Dialog borgt nichts mehr.
Die erste Fassung der Pruefung zaehlte nachfrage.js SELBST als
Nutzer -- damit war jede Seite trivialerweise "Nutzer" und die
Pruefung gruen ohne Inhalt. Jetzt ausdruecklich ausgenommen.
ZWEI FUNDE NEBENBEI:
hilfeAufraeumen() wird im Betrieb NIE aufgerufen. Der Kommentar
behauptete "wird beim Start aufgerufen (siehe index.js)" -- das
war nie wahr; einziger Aufrufer ist die eigene Pruefung. Folge:
geschlossene vertrauliche Faelle bleiben unbegrenzt stehen. NICHT
eingeschaltet (das loescht echte Daten und ist Filipes
Entscheidung), sondern der Kommentar richtiggestellt.
Einen Hilfe-Fall zu schliessen ist endgueltig -- es gibt keine
Route, die ihn wieder oeffnet. Vorher stand darueber nur die
Frage nach einem Schlusswort. Jetzt sagt der Dialog es.
pruef-struktur hat meine eigene Pruefung von heute Nachmittag
erwischt: Sie bildete ihr Datum aus UTC. Beim Beheben erst
heuteLokal(datum) genommen -- die Funktion nimmt gar kein Argument
und haette still "heute" statt "+3 Tage" geliefert. Jetzt tagLokal(3),
nachgerechnet: Abstand 3 Tage.
Am Bildschirm angesehen (Rechner 1280, Handy 390): passt rein, Esc
ergibt false, Fokus liegt auf dem harmlosen Knopf, Knoepfe 44px auf
Touch. Der Platzhalter im Abtippfeld zeigte den erwarteten Namen --
das sah aus wie ein schon ausgefuelltes Feld, entfernt.
Neu: server/pruef-nachfrage.mjs -- 17/0, mit sechs Gegenproben und
beiden Richtungen (wer fragt, laedt die Datei; wer nie fragt, laedt
sie nicht -- sonst truege die Anmeldewand 4,8 KB fuer nichts).
pruef-meldungen 8/0, pruef-css-klassen gruen, pruef-struktur gruen,
pruef-leistung gruen.
This commit is contained in:
@@ -311,8 +311,14 @@
|
||||
allein sagt nicht, WAS sich ändert -- und es ist der Handgriff,
|
||||
der jemandem den Zugang zu einer ganzen Seite nimmt oder gibt. */
|
||||
const name = $('rolle-wahl').querySelector('.rollenwahl__knopf[data-an="ja"] .rollenwahl__name')?.textContent || gewaehlt;
|
||||
if (!confirm(`${rolleFuer.name} wird von "${ROLLENNAME[rolleFuer.rolle] || rolleFuer.rolle}" zu "${name}".\n\n`
|
||||
+ 'Der Zugangscode bleibt derselbe. Offene Sitzungen werden beendet.')) return;
|
||||
if (!await frageNach({
|
||||
titel: `${rolleFuer.name}: Rolle ändern?`,
|
||||
was: `Von „${ROLLENNAME[rolleFuer.rolle] || rolleFuer.rolle}" zu „${name}".`
|
||||
+ ' Damit ändert sich, welche Seiten die Person öffnen darf.',
|
||||
bleibt: 'Der Zugangscode bleibt derselbe. Offene Sitzungen werden beendet, '
|
||||
+ 'danach kann sie sich mit dem alten Code wieder anmelden.',
|
||||
ja: `Zu „${name}" machen`,
|
||||
})) return;
|
||||
|
||||
const a = await hole(`/workspace/api/verwaltung/personen/${rolleFuer.id}/rolle`, {
|
||||
method: 'PUT',
|
||||
@@ -577,18 +583,17 @@ Der Code gilt einmal fuer die `
|
||||
|
||||
knoepfe.append(tuKnopf('Neuer Code', async () => {
|
||||
const eigen = p.id === ich.id;
|
||||
const frage = eigen
|
||||
/* Der Satz stimmte bis zum 02.09.2026 -- und beschrieb genau die
|
||||
Falle: Man bestätigte, der Code erschien, und im selben Moment
|
||||
war die Sitzung weg. Jetzt bleibt sie bestehen, und der Text
|
||||
sagt, was wirklich passiert. */
|
||||
? 'Neuer Code für dich selbst?\n\n'
|
||||
+ 'Der alte Code gilt danach nicht mehr, und alle ANDEREN Geräte '
|
||||
+ 'werden abgemeldet.\n\n'
|
||||
+ 'Hier bleibst du angemeldet – der neue Code steht danach auf dem '
|
||||
+ 'Bildschirm, bis du ihn selbst wegklickst.'
|
||||
: `Neuer Code für ${p.name}?\n\nDer alte Code gilt dann nicht mehr, offene Sitzungen werden beendet.`;
|
||||
if (!confirm(frage)) return;
|
||||
if (!await frageNach({
|
||||
titel: eigen ? 'Neuer Code für dich selbst?' : `Neuer Code für ${p.name}?`,
|
||||
was: 'Der alte Code gilt danach nicht mehr.',
|
||||
bleibt: eigen
|
||||
? 'Alle ANDEREN Geräte werden abgemeldet – hier bleibst du '
|
||||
+ 'angemeldet. Der neue Code steht danach auf dem Bildschirm, '
|
||||
+ 'bis du ihn selbst wegklickst.'
|
||||
: `Offene Sitzungen von ${p.name} werden beendet. Alles andere `
|
||||
+ 'bleibt unverändert – nur der Code ist neu.',
|
||||
endgueltig: true, ja: 'Neuen Code erzeugen',
|
||||
})) return;
|
||||
const a = await hole(`/workspace/api/verwaltung/personen/${p.id}/code`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -601,7 +606,13 @@ Der Code gilt einmal fuer die `
|
||||
|
||||
if (p.id !== ich.id) {
|
||||
knoepfe.append(tuKnopf(p.aktiv ? 'Sperren' : 'Entsperren', async () => {
|
||||
if (p.aktiv && !confirm(`${p.name} sperren?\n\nOffene Sitzungen werden sofort beendet.`)) return;
|
||||
if (p.aktiv && !await frageNach({
|
||||
titel: `${p.name} sperren?`,
|
||||
was: 'Offene Sitzungen werden sofort beendet. Anmelden geht danach nicht mehr.',
|
||||
bleibt: 'Alle Daten bleiben stehen – Aufgaben, Nachrichten, Steckbrief. '
|
||||
+ 'Entsperren geht jederzeit mit demselben Knopf.',
|
||||
ja: 'Sperren',
|
||||
})) return;
|
||||
const a = await hole(`/workspace/api/verwaltung/personen/${p.id}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -704,43 +715,42 @@ Der Code gilt einmal fuer die `
|
||||
|
||||
if (v.hindernis) { melde(v.hindernis); return; }
|
||||
|
||||
const zeilen = [];
|
||||
const mit = Object.entries(v.mit).filter(([, n]) => n > 0);
|
||||
const bleibt = Object.entries(v.bleibt).filter(([, n]) => n > 0);
|
||||
|
||||
zeilen.push(`„${v.person.name}" wirklich löschen?`, '');
|
||||
if (mit.length) {
|
||||
zeilen.push('Wird MITGELÖSCHT:');
|
||||
for (const [was, n] of mit) zeilen.push(` · ${was}: ${n}`);
|
||||
zeilen.push('');
|
||||
}
|
||||
if (bleibt.length) {
|
||||
zeilen.push('BLEIBT erhalten, verliert nur die Zuordnung:');
|
||||
for (const [was, n] of bleibt) zeilen.push(` · ${was}: ${n}`);
|
||||
zeilen.push('');
|
||||
}
|
||||
if (v.verliertBetreuung.length) {
|
||||
zeilen.push(`ACHTUNG: ${v.verliertBetreuung.join(', ')} `
|
||||
+ `${v.verliertBetreuung.length === 1 ? 'steht' : 'stehen'} danach ohne zuständige Person da.`, '');
|
||||
}
|
||||
if (!mit.length && !bleibt.length && !v.verliertBetreuung.length) {
|
||||
zeilen.push('An dieser Person hängt nichts.', '');
|
||||
}
|
||||
zeilen.push('Vorher wird automatisch eine Sicherung geschrieben.', '',
|
||||
`Zum Bestätigen den Namen genau eingeben: ${v.person.name}`);
|
||||
/* Was mitgeht und was bleibt, sind ZWEI Aussagen -- deshalb stehen
|
||||
sie im Dialog auch in zwei Zeilen und nicht in einer Liste, die
|
||||
man von oben nach unten durchliest und in der Mitte aufgibt. */
|
||||
const wasWeg = mit.length
|
||||
? 'Mitgelöscht wird: ' + mit.map(([w, n]) => `${w} (${n})`).join(', ') + '.'
|
||||
: 'An dieser Person hängt nichts, was mitgelöscht würde.';
|
||||
const wasBleibt = [
|
||||
bleibt.length
|
||||
? 'Erhalten bleibt, verliert aber die Zuordnung: '
|
||||
+ bleibt.map(([w, n]) => `${w} (${n})`).join(', ') + '.'
|
||||
: '',
|
||||
v.verliertBetreuung.length
|
||||
? `${v.verliertBetreuung.join(', ')} `
|
||||
+ `${v.verliertBetreuung.length === 1 ? 'steht' : 'stehen'} danach `
|
||||
+ 'ohne zuständige Person da.'
|
||||
: '',
|
||||
'Vorher wird automatisch eine Sicherung geschrieben.',
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
const eingabe = prompt(zeilen.join('\n'), '');
|
||||
if (eingabe === null) return;
|
||||
if (eingabe.trim() !== v.person.name) {
|
||||
melde('Der Name stimmt nicht – es wurde nichts gelöscht.');
|
||||
return;
|
||||
}
|
||||
if (!await frageNach({
|
||||
titel: `„${v.person.name}" löschen?`,
|
||||
was: wasWeg,
|
||||
bleibt: wasBleibt,
|
||||
endgueltig: true,
|
||||
ja: 'Endgültig löschen',
|
||||
tippen: v.person.name,
|
||||
})) return;
|
||||
|
||||
try {
|
||||
const a = await hole(`/workspace/api/verwaltung/personen/${person.id}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name: eingabe.trim() }),
|
||||
body: JSON.stringify({ name: v.person.name }),
|
||||
});
|
||||
const d = await a.json().catch(() => ({}));
|
||||
if (!a.ok) { melde(sagWas(d.fehler, 'Löschen hat nicht geklappt.')); return; }
|
||||
|
||||
Reference in New Issue
Block a user