// ----------------------------- // Projektübersicht — Board (Listenansicht) // ----------------------------- // Diese Datei rendert das Projektboard (Tab "Projektboard" in `App.html`) als // schlanke, aufklappbare Liste statt der früheren breiten Matrix (eine Spalte // je Person/Leistungsphase): jede Zeile zeigt auf einen Blick Kürzel-Avatare // der zugeordneten Personen, die aktuelle Leistungsphase samt Prozentwert und // eine einzeilige Status-Vorschau; ein Klick auf die Zeile klappt darunter das // Detailpanel auf (voller Status-Editor, vollständige Rollen-Zuordnung, alle // LPH-Balken). Sie wird von `App.html` nach `js/weeks.js` (vor // `js/people/people.js`) geladen und stellt globale Funktionen wie // `renderBoard()`, `toggleBoardRow()`, `cycleAssign()`, // und `editLph()` bereit. Sie nutzt `currentWeek()`/ // `isWeekLocked()` aus `js/weeks.js`, `lpActiveList()` aus `js/load/load.js`, // `assignKey()`, `statusFocus()`, `sanitizeStatusHtml()` und // `getProgressColor()` aus `js/utils.js` sowie `openProjectPlan()` aus // `js/gantt.js` — navigiert bewusst im selben Tab (kein window.open() mehr), // ein Klick auf den Rest der Zeile klappt stattdessen nur das Detailpanel // auf/zu (toggleBoardRow()). editLph()/cycleAssign() rufen zusätzlich // renderWochenbericht() (js/wochenbericht/wochenbericht.js) auf, da dessen // Karten dieselben renderBoardDrawer()-Bedienelemente nutzen, aber in einem // eigenen DOM-Container (#wochenberichtContent) liegen. // boardRowOpen: UI-Zustand, welche Projekt-Zeile ihr Detailpanel aufgeklappt // darstellt (Key = Projekt-ID, Wert = boolean). Reine Anzeige-Steuerung, lebt // außerhalb von renderBoard() und übersteht daher dessen Neuaufbauten (z. B. // nach einer Zuordnungs- oder Prozent-Änderung im offenen Panel). Nicht // persistiert — jede Sitzung startet mit eingeklappten Zeilen. let boardRowOpen = {}; // toggleBoardRow: klappt das Detailpanel einer Projekt-Zeile auf bzw. zu. // Parameter: pid (Projekt-ID). Keine Rückgabe. function toggleBoardRow(pid){ boardRowOpen[pid] = !boardRowOpen[pid]; renderBoard(); // Der Wochenbericht und die Wandtafel rendern dieselben Projektzeilen in // einem eigenen Container. Ohne diesen Aufruf merkten sie sich den Klick // zwar, zeigten die Zeile aber erst nach einem Tab-Wechsel auf- bzw. // zugeklappt. if(typeof renderWochenbericht === 'function') renderWochenbericht(); if(typeof renderWandboard === 'function') renderWandboard(); } // statusPreviewText: liefert eine einzeilige Klartext-Vorschau eines // Status-HTML-Werts (Tags entfernt, überflüssiger Leerraum/Zeilenumbrüche zu // einem Leerzeichen zusammengefasst) für die eingeklappte Zeile — die volle // Formatierung bleibt dem aufgeklappten Editor vorbehalten. Parameter: html // (String). Rückgabe: String. function statusPreviewText(html){ if(!html) return ''; const tmp = document.createElement('div'); // Bereinigen, BEVOR der Wert ins DOM geht: Auch ein nicht eingehängtes // Element lädt Ressourcen und führt deren Fehler-Handler aus, ungefiltertes // innerHTML wäre hier also ein Einfallstor. tmp.innerHTML = sanitizeStatusHtml(html); // Zeilen- und Absatzgrenzen zuerst in Leerzeichen überführen: textContent // ignoriert sie, sonst klebte das letzte Wort einer Zeile am ersten der // nächsten ("… KW 40.Freigabe steht aus"). tmp.querySelectorAll('br').forEach(el => el.replaceWith(document.createTextNode(' '))); tmp.querySelectorAll('p, div').forEach(el => el.append(document.createTextNode(' '))); return (tmp.textContent || tmp.innerText || '').replace(/\s+/g, ' ').trim(); } // HINWEIS: statusBlur() ist entfallen. Seit der Kommentar-Editor ein //