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:
@@ -518,8 +518,13 @@
|
||||
b.type = 'button';
|
||||
b.title = 'Schickt Art, Titel und Text als Nachricht in den Chat.';
|
||||
b.addEventListener('click', async () => {
|
||||
if (!confirm(`„${e.titel}“ als Nachricht schicken?\n\n`
|
||||
+ 'Die Person bekommt Art, Titel und Text im Chat – einmalig.')) return;
|
||||
if (!await frageNach({
|
||||
titel: `„${e.titel}" als Nachricht schicken?`,
|
||||
was: 'Die Person bekommt Art, Titel und Text im Chat – einmalig.',
|
||||
bleibt: 'Der Eintrag bleibt hier stehen. Zurückholen lässt sich '
|
||||
+ 'die Nachricht nicht, sobald sie unterwegs ist.',
|
||||
ja: 'Schicken',
|
||||
})) return;
|
||||
b.disabled = true;
|
||||
const a = await hole(`/workspace/api/bereich/entwicklung/${e.id}/senden`,
|
||||
{ method: 'POST', headers: { 'Content-Type': 'application/json' } });
|
||||
@@ -897,9 +902,17 @@
|
||||
const vomTeam = !!e.erstellt_rolle && e.erstellt_rolle !== 'gast';
|
||||
if (!lage.team && e.erstellt_von !== ich.id && !vomTeam) {
|
||||
zeile.append(tuKnopf('melden', async () => {
|
||||
const grund = prompt('Was ist daran nicht in Ordnung?\n\n'
|
||||
+ 'Bitte schreib es in einem Satz – sonst können wir es nicht prüfen.');
|
||||
if (grund === null) return;
|
||||
const a0 = await frageNach({
|
||||
titel: 'Diesen Beitrag melden?',
|
||||
was: 'Das Team sieht sich den Beitrag an. Du bleibst dabei ungenannt.',
|
||||
bleibt: 'Der Beitrag bleibt vorerst stehen – gemeldet heißt noch '
|
||||
+ 'nicht entfernt.',
|
||||
ja: 'Melden',
|
||||
grund: 'Was ist daran nicht in Ordnung?', grundPflicht: true,
|
||||
platzhalter: 'Bitte in einem Satz – sonst können wir es nicht prüfen.',
|
||||
});
|
||||
if (!a0) return;
|
||||
const grund = a0.grund;
|
||||
const a = await hole('/workspace/api/treff/eintrag/' + e.id + '/melden', {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ grund }),
|
||||
@@ -956,7 +969,13 @@
|
||||
dass er einer wird, entscheidet ein Mensch. */
|
||||
if (bereich === 'mitmachen' && e.erstellt_rolle === 'gast') {
|
||||
zeile.append(tuKnopf('zu den Talenten', async () => {
|
||||
if (!confirm('„' + e.titel + '“ zu den Talenten übernehmen?')) return;
|
||||
if (!await frageNach({
|
||||
titel: '„' + e.titel + '" zu den Talenten übernehmen?',
|
||||
was: 'Die Person erscheint danach in der Talente-Liste.',
|
||||
bleibt: 'Der Beitrag hier bleibt stehen. Übernehmen heißt noch '
|
||||
+ 'keine Zusage – es entscheidet weiterhin ein Mensch.',
|
||||
ja: 'Übernehmen',
|
||||
})) return;
|
||||
const a = await hole('/workspace/api/treff/mitmachen/' + e.id + '/uebernehmen',
|
||||
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' });
|
||||
const j = await a.json().catch(() => ({}));
|
||||
@@ -971,9 +990,17 @@
|
||||
fuer den eigenen Beitrag, und der braucht keine Begruendung. */
|
||||
if (e.erstellt_von !== ich.id) {
|
||||
zeile.append(tuKnopf('entfernen', async () => {
|
||||
const grund = prompt('Warum wird „' + e.titel + '“ entfernt?\n\n'
|
||||
+ 'Der Grund wird festgehalten – die Person hat ein Recht darauf.');
|
||||
if (grund === null) return;
|
||||
const a1 = await frageNach({
|
||||
titel: '„' + e.titel + '" entfernen?',
|
||||
was: 'Der Beitrag verschwindet vom Brett.',
|
||||
bleibt: 'Der Grund wird festgehalten und der Person mitgeteilt – '
|
||||
+ 'sie hat ein Recht darauf (DSA Art. 17).',
|
||||
endgueltig: true, ja: 'Entfernen',
|
||||
grund: 'Warum wird er entfernt?', grundPflicht: true,
|
||||
platzhalter: 'z. B. Beleidigende Sprache gegenüber einem anderen Mitglied.',
|
||||
});
|
||||
if (!a1) return;
|
||||
const grund = a1.grund;
|
||||
/* DER GRUND REIST IN DER ADRESSE, nicht im Koerper -- aus
|
||||
demselben gemessenen Grund wie oben. Er ist kein
|
||||
Geheimnis: Er wird der Person, die den Beitrag
|
||||
@@ -1208,7 +1235,12 @@
|
||||
|
||||
if (LEITUNG.has(ich.rolle) || e.erstellt_von === ich.id) {
|
||||
knoepfe.append(tuKnopf('löschen', async () => {
|
||||
if (!confirm(`„${e.titel}" wirklich löschen?`)) return;
|
||||
if (!await frageNach({
|
||||
titel: `„${e.titel}" löschen?`,
|
||||
was: 'Der Eintrag verschwindet vom Brett – für alle.',
|
||||
bleibt: 'Nachrichten, die dazu geschrieben wurden, gehen mit.',
|
||||
endgueltig: true, ja: 'Löschen',
|
||||
})) return;
|
||||
const a = await hole(`/workspace/api/bereich/${bereich}/${e.id}`, { method: 'DELETE' });
|
||||
if (!a.ok) { melde('Löschen hat nicht geklappt.'); return; }
|
||||
await laden();
|
||||
|
||||
Reference in New Issue
Block a user