Wunsch: "die sollen nirgendwo Hilfe anfordern koennen, sondern nur Rueckmeldungen." Es ist auch die klarere Loesung. Es gab zwei Wege, dasselbe zu sagen: einen Knopf, der eine Aufgabe erzeugte, und ein Textfeld, das eine Nachricht schrieb. Zwei Wege fuer eine Sache heisst, dass niemand weiss, welcher der richtige ist -- und dass Antworten mal als Aufgabe und mal als Nachricht landen. Wer dann nachsieht, findet die Haelfte nicht. Geblieben ist die Rueckmeldung an jedem Punkt: ein Verlauf, in dem beide Seiten schreiben koennen, sichtbar dort, wo es hingehoert -- am Punkt selbst und nicht in einer zweiten Liste. VOLLSTAENDIG entfernt, nicht nur ausgeblendet: * der Knopf in der Checkliste * der Knopf und die Marke "Hilfe moeglich" im Vorlagenblock * die Route /workspace/api/vorlagen/hilfe * 47 Datenfelder hilfe: true/false in den Vorlagen * die zugehoerigen Stile * der Abschnitt in pruef-vorlagen.mjs Datenfelder, die nichts mehr bewirken, und Routen, die niemand mehr aufruft, werden beim naechsten Mal fuer lebenden Code gehalten und mitgepflegt. Das ist teurer als das Entfernen heute. Co-Authored-By: Claude Opus 5 <[email protected]>
190 lines
7.7 KiB
JavaScript
190 lines
7.7 KiB
JavaScript
/* ===================================================================
|
||
Vorlagen — fertige Inhalte, die man übernehmen kann.
|
||
|
||
EIN Bauteil für mehrere Seiten (Content-Ideen, LIVE-Analyse). Es
|
||
hängt sich an einen Behälter mit `data-vorlagen="<art>"` und baut
|
||
dort eine aufklappbare Liste von Vorschlägen.
|
||
|
||
Warum ausgeklappt-per-Knopf und nicht offen: Wer schon zwanzig eigene
|
||
Einträge hat, braucht die Vorschläge nicht mehr im Weg. Wer noch
|
||
keinen hat, sieht den Knopf sofort -- und er ist dann das Auffälligste
|
||
auf der Seite, weil sonst nichts da ist.
|
||
|
||
Übernehmen macht aus dem Vorschlag einen ganz normalen Eintrag. Ab
|
||
dann ist er unabhängig von der Vorlage: änderbar, löschbar, und
|
||
spätere Änderungen an der Vorlage berühren ihn nicht.
|
||
=================================================================== */
|
||
(() => {
|
||
'use strict';
|
||
|
||
const el = (tag, klasse, text) => {
|
||
const k = document.createElement(tag);
|
||
if (klasse) k.className = klasse;
|
||
if (text !== undefined) k.textContent = text;
|
||
return k;
|
||
};
|
||
|
||
async function hole(pfad, optionen = {}) {
|
||
const a = await fetch(pfad, { credentials: 'same-origin', ...optionen });
|
||
if (a.status === 401) { location.assign('/workspace/'); throw new Error('abgemeldet'); }
|
||
return a;
|
||
}
|
||
|
||
let vorlagen = null;
|
||
|
||
/* Was in dieser Sitzung schon uebernommen wurde. Muss AUSSERHALB des
|
||
Bauvorgangs stehen: Nach dem Uebernehmen wird die Liste neu geladen
|
||
und der Block neu gebaut -- eine Markierung am Element allein waere
|
||
dabei jedes Mal verloren. Genau das hat die Pruefung gemeldet
|
||
("als uebernommen markiert: 0").
|
||
|
||
Bewusst nur fuer diese Sitzung und nicht dauerhaft gespeichert: Wer
|
||
die Seite neu laedt, hat seine Eintraege ja in der Liste stehen --
|
||
dort gehoeren sie hin, nicht in eine zweite Buchfuehrung. */
|
||
const genommen = new Set();
|
||
|
||
/** Baut den Vorlagenblock in einen Behälter.
|
||
* art: 'content' | 'live'
|
||
* unterart: bei live der Abschnitt (vorbereitung | mitschrift | auswertung)
|
||
* creatorId: für wen übernommen wird (Betreuer); bei Creator egal
|
||
* danach: wird nach dem Übernehmen aufgerufen (Liste neu laden) */
|
||
window.vorlagenBlock = async function (behaelter, { art, unterart, creatorId, danach }) {
|
||
if (!behaelter) return;
|
||
if (!vorlagen) {
|
||
try {
|
||
const a = await hole('/workspace/api/vorlagen');
|
||
if (!a.ok) return;
|
||
vorlagen = await a.json();
|
||
} catch { return; }
|
||
}
|
||
|
||
const liste = art === 'content' ? vorlagen.content
|
||
: (vorlagen.live?.[unterart] || []);
|
||
if (!liste.length) return;
|
||
|
||
behaelter.textContent = '';
|
||
const block = el('section', 'vorlagen');
|
||
|
||
/* ---- Kopf mit Aufklappknopf ---- */
|
||
const kopf = el('div', 'vorlagen__kopf');
|
||
const titel = el('div', null);
|
||
titel.append(el('p', 'feldschild', 'Fertige Vorschläge'));
|
||
titel.append(el('p', 'vorlagen__unter',
|
||
art === 'content'
|
||
? `${liste.length} Ideen mit Aufhänger und Format – zum Übernehmen und Anpassen.`
|
||
: `${liste.length} Punkte, die sich bewährt haben. Übernehmen und abhaken.`));
|
||
kopf.append(titel);
|
||
|
||
const auf = el('button', 'knopf knopf--klein');
|
||
auf.type = 'button';
|
||
auf.setAttribute('aria-expanded', 'false');
|
||
auf.textContent = 'Vorschläge zeigen';
|
||
kopf.append(auf);
|
||
block.append(kopf);
|
||
|
||
/* ---- Die Liste ---- */
|
||
const raster = el('div', 'vorlagen__raster');
|
||
raster.hidden = true;
|
||
|
||
for (const [nr, v] of liste.entries()) {
|
||
const k = el('article', 'vorlage');
|
||
const schluessel = art + ':' + (unterart || '') + ':' + nr;
|
||
if (genommen.has(schluessel)) k.dataset.genommen = 'ja';
|
||
if (v.saeule) k.dataset.saeule = v.saeule;
|
||
|
||
k.append(el('h3', 'vorlage__titel', v.titel));
|
||
|
||
/* Der Aufhänger ist der wichtigste Teil einer Content-Idee -- die
|
||
ersten Sekunden entscheiden über die Verbreitung. Deshalb steht
|
||
er hervorgehoben und nicht im Fließtext. */
|
||
if (v.hook) {
|
||
const h = el('p', 'vorlage__hook');
|
||
h.append(el('span', 'vorlage__hookschild', 'Aufhänger'));
|
||
h.append(document.createTextNode(v.hook));
|
||
k.append(h);
|
||
}
|
||
if (v.text) k.append(el('p', 'vorlage__text', v.text));
|
||
|
||
const fuss = el('div', 'vorlage__fuss');
|
||
if (v.format) fuss.append(el('span', 'vorlage__marke', v.format));
|
||
if (v.saeule) fuss.append(el('span', 'vorlage__marke vorlage__marke--saeule', v.saeule));
|
||
|
||
const nehmen = el('button', 'schritt', 'Übernehmen');
|
||
nehmen.type = 'button';
|
||
nehmen.addEventListener('click', async () => {
|
||
nehmen.disabled = true;
|
||
nehmen.textContent = 'wird übernommen …';
|
||
try {
|
||
const a = await hole('/workspace/api/vorlagen/uebernehmen', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ art, unterart, nr, creator_id: creatorId }),
|
||
});
|
||
if (!a.ok) {
|
||
const f = await a.json().catch(() => ({}));
|
||
nehmen.textContent = f.fehler || 'ging nicht';
|
||
nehmen.disabled = false;
|
||
return;
|
||
}
|
||
/* Übernommen bleibt sichtbar markiert -- man soll sehen, was
|
||
man schon geholt hat, ohne die Liste zu verlassen. */
|
||
genommen.add(schluessel);
|
||
k.dataset.genommen = 'ja';
|
||
nehmen.textContent = 'übernommen';
|
||
danach?.();
|
||
} catch { nehmen.disabled = false; nehmen.textContent = 'Übernehmen'; }
|
||
});
|
||
fuss.append(nehmen);
|
||
k.append(fuss);
|
||
raster.append(k);
|
||
}
|
||
|
||
/* ---- Alle auf einmal ---- */
|
||
const alle = el('div', 'vorlagen__alle');
|
||
const allesNehmen = el('button', 'knopf-still',
|
||
art === 'content' ? `Alle ${liste.length} Ideen übernehmen`
|
||
: `Alle ${liste.length} Punkte übernehmen`);
|
||
allesNehmen.type = 'button';
|
||
allesNehmen.addEventListener('click', async () => {
|
||
if (!confirm(`Wirklich alle ${liste.length} übernehmen? `
|
||
+ 'Sie landen als eigene Einträge in der Liste und lassen sich einzeln löschen.')) return;
|
||
allesNehmen.disabled = true;
|
||
allesNehmen.textContent = 'wird übernommen …';
|
||
try {
|
||
const a = await hole('/workspace/api/vorlagen/uebernehmen', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ art: art + '_alle', unterart, creator_id: creatorId }),
|
||
});
|
||
if (!a.ok) { allesNehmen.textContent = 'ging nicht'; allesNehmen.disabled = false; return; }
|
||
const { angelegt } = await a.json();
|
||
/* Alle auf einmal: dann sind auch alle markiert. */
|
||
for (let i = 0; i < liste.length; i++) genommen.add(art + ':' + (unterart || '') + ':' + i);
|
||
allesNehmen.textContent = `${angelegt} übernommen`;
|
||
danach?.();
|
||
} catch { allesNehmen.disabled = false; }
|
||
});
|
||
alle.append(allesNehmen);
|
||
raster.append(alle);
|
||
|
||
block.append(raster);
|
||
|
||
auf.addEventListener('click', () => {
|
||
const offen = auf.getAttribute('aria-expanded') === 'true';
|
||
auf.setAttribute('aria-expanded', offen ? 'false' : 'true');
|
||
raster.hidden = offen;
|
||
auf.textContent = offen ? 'Vorschläge zeigen' : 'Vorschläge ausblenden';
|
||
});
|
||
|
||
behaelter.append(block);
|
||
behaelter.hidden = false;
|
||
};
|
||
|
||
/* Der frühere Knopf "Hilfe anfordern" ist am 01.09.2026 entfallen.
|
||
Es gab damit zwei Wege, dasselbe zu sagen -- einen Knopf, der eine
|
||
Aufgabe erzeugte, und ein Textfeld für eine Nachricht. Zwei Wege
|
||
für eine Sache heißt, dass niemand weiß, welcher der richtige ist,
|
||
und dass Antworten mal hier und mal dort landen. Geblieben ist die
|
||
Rückmeldung an jedem Punkt. */
|
||
})();
|