von single Page hin zur mehreren Seiten geändert

This commit is contained in:
erik committed 2026-08-14 08:26:46 +02:00
1 parent 8c94fc91f6
commit 31c4bd47cd
36 files changed
+207 -97

No files matched your search

BIN
View File
Binary file not shown.
+24 -22
View File
@@ -5,9 +5,11 @@
und verwaltet wöchentliche Sitzungen (Sitzungswahl, -anlage, -duplikat und -löschung im
seitlichen Menü) je Abteilung (ELT, HLS, Architektur). Sie lädt das gemeinsame Stylesheet
styles.css sowie der Reihe nach die Module js/globals.js, js/utils.js, js/ui.js,
js/date-picker.js, js/csv.js, js/server.js, js/store.js, js/weeks.js, js/board.js,
js/people.js, js/projects.js, js/load.js, js/gantt.js, js/showmode.js, js/tabs-auth.js,
js/pdf.js und js/init.js; crypto-js und pdfmake kommen von einem CDN. Über openProjectPlan()
js/date-picker.js, js/csv.js, js/server.js, js/store.js, js/weeks.js, danach die
tab-spezifischen Module js/board/board.js, js/people/people.js,
js/projects/projects.js, js/load/load.js sowie js/gantt.js, js/showmode.js,
js/tabs-auth.js, js/pdf.js und js/init.js; crypto-js und pdfmake kommen von einem
CDN. Über openProjectPlan()
aus js/gantt.js öffnet diese Seite die Projektplan-Ansicht project-plan.html in einem
neuen Tab, die nur die gemeinsamen Module plus die js/plan/*-Module lädt.
-->
@@ -16,7 +18,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Projektübersicht Elektro</title>
<link rel="stylesheet" href="styles.css?v=3">
<link rel="stylesheet" href="/styles.css?v=3">
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.10/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.10/vfs_fonts.js"></script>
@@ -36,7 +38,7 @@
<header>
<div class="header-bar">
<h1 id="pageTitle">Projektübersicht Elektro</h1>
<img src="dein_bild.ico" alt="Logo" class="header-logo">
<img src="/dein_bild.ico" alt="Logo" class="header-logo">
</div>
</header>
@@ -221,22 +223,22 @@
</div>
</div>
<script src="js/globals.js?v=5"></script>
<script src="js/utils.js?v=5"></script>
<script src="js/ui.js?v=5"></script>
<script src="js/date-picker.js?v=5"></script>
<script src="js/csv.js?v=5"></script>
<script src="js/server.js?v=5"></script>
<script src="js/store.js?v=5"></script>
<script src="js/weeks.js?v=5"></script>
<script src="js/board.js?v=5"></script>
<script src="js/people.js?v=5"></script>
<script src="js/projects.js?v=5"></script>
<script src="js/load.js?v=5"></script>
<script src="js/gantt.js?v=5"></script>
<script src="js/showmode.js?v=5"></script>
<script src="js/tabs-auth.js?v=5"></script>
<script src="js/pdf.js?v=5"></script>
<script src="js/init.js?v=5"></script>
<script src="/js/globals.js?v=5"></script>
<script src="/js/utils.js?v=5"></script>
<script src="/js/ui.js?v=5"></script>
<script src="/js/date-picker.js?v=5"></script>
<script src="/js/csv.js?v=5"></script>
<script src="/js/server.js?v=5"></script>
<script src="/js/store.js?v=5"></script>
<script src="/js/weeks.js?v=5"></script>
<script src="/js/board/board.js?v=6"></script>
<script src="/js/people/people.js?v=6"></script>
<script src="/js/projects/projects.js?v=6"></script>
<script src="/js/load/load.js?v=6"></script>
<script src="/js/gantt.js?v=5"></script>
<script src="/js/showmode.js?v=5"></script>
<script src="/js/tabs-auth.js?v=5"></script>
<script src="/js/pdf.js?v=5"></script>
<script src="/js/init.js?v=5"></script>
</body>
</html>
@@ -4,10 +4,10 @@
// Diese Datei rendert das Projektboard (Tab "Projektboard" in `Test.html`),
// die zentrale Tabelle mit Projekten, Status-Kommentaren, Personen-Spalten
// (Anwesenheit/Zuordnung) und Leistungsphasen in Prozent. Sie wird von
// `Test.html` nach `js/weeks.js` (vor `js/people.js`) geladen und stellt
// `Test.html` nach `js/weeks.js` (vor `js/people/people.js`) geladen und stellt
// globale Funktionen wie `renderBoard()`, `statusFocus()`, `cycleAssign()`,
// `editLph()` und `delProj()` bereit. Sie nutzt `currentWeek()`/
// `isWeekLocked()` aus `js/weeks.js`, `lpActiveList()` aus `js/load.js`,
// `isWeekLocked()` aus `js/weeks.js`, `lpActiveList()` aus `js/load/load.js`,
// `assignKey()` aus `js/utils.js` und `openProjectPlan()` aus `js/gantt.js`.
// currentStatusEditor: aktuell fokussiertes contenteditable-Element des
+1 -1
View File
@@ -9,7 +9,7 @@
// und stellt den Kalender-Picker (Einzeldatum "openDatePicker" und Bereich
// "openRangePicker") bereit. Der Zustand des offenen Popups liegt in der
// Modulvariablen rangePickerState. Genutzt wird der Picker v. a. von
// js/load.js (LP-Bereiche), js/people.js (Abwesenheiten) und den
// js/load/load.js (LP-Bereiche), js/people/people.js (Abwesenheiten) und den
// Plan-Modulen unter js/plan/* (z. B. GANTT-Datumsangaben in plan-modals.js).
// rangePickerState: Zustand des aktuell geöffneten Picker-Popups (Optionen,
+10 -9
View File
@@ -2,9 +2,9 @@
// Projektübersicht — GANTT-Diagramm (gemeinsam genutzt)
// -----------------------------
// Gemeinsames Modul für das GANTT-Diagramm: Es wird von Test.html (nach
// js/load.js) UND von project-plan.html geladen – dort zusammen mit globals,
// js/load/load.js) UND von project-plan.html geladen – dort zusammen mit globals,
// utils, ui, date-picker, csv, server und den js/plan/*-Modulen, aber OHNE
// js/store.js, js/weeks.js, js/board.js usw. Es darf daher auf der Plan-Seite
// js/store.js, js/weeks.js, js/board/board.js usw. Es darf daher auf der Plan-Seite
// keine Hauptseiten-spezifischen Funktionen voraussetzen; Funktionen, die
// currentWeek()/isWeekLocked() aus js/weeks.js brauchen (renderGantt,
// fitGanttRange, openProjectPlan), werden nur vom Hauptfenster aufgerufen.
@@ -328,19 +328,20 @@ function buildGanttHtml(projects, start, end, options = {}){
// ---------- Projektplan-Navigation ----------
// openProjectPlan: öffnet project-plan.html in einem neuen Tab. Weil
// Projekt-IDs nicht persistent sind, werden department, Wochen-Label, Proj.-Nr.
// und -Name als URL-Parameter übergeben. Parameter: pid = Projekt-ID der
// aktuellen Woche. Kein Rückgabewert.
// Projekt-IDs nicht persistent sind, werden Wochen-Label und Proj.-Nr. als
// URL-Parameter übergeben; Abteilung und Projektname stehen im Pfad nach dem
// Schema "/<Abteilung>/Projektplan/<Projektname>". Parameter: pid =
// Projekt-ID der aktuellen Woche. Kein Rückgabewert.
function openProjectPlan(pid){
const w = currentWeek(); if(!w) return;
const p = w.projects.find(x => x.id === pid); if(!p) return;
// IDs sind nicht persistent (werden bei jedem CSV-Laden neu erzeugt).
// Daher werden stabile Werte (Label, Projekt-Nr., Name) in der URL übergeben.
const url = new URL('project-plan.html', window.location.href);
url.searchParams.set('department', currentDepartment);
// Daher werden stabile Werte (Label, Projekt-Nr.) in der URL übergeben.
// Absoluter Pfad mit Abteilung und Projektname als Route-Segment, damit der
// Aufruf auch von Deep-Link-URLs wie "/HLS/Auslastung" funktioniert.
const url = new URL('/' + currentDepartment + '/' + PLAN_SLUG + '/' + encodeURIComponent(p.name || ''), window.location.origin);
url.searchParams.set('weekLabel', w.label);
url.searchParams.set('projNr', p.nr || '');
url.searchParams.set('projName', p.name || '');
window.open(url.toString(), '_blank');
}
+17 -2
View File
@@ -5,7 +5,7 @@
// legt alle zentralen Konstanten (Leistungsphasen, Rollen, Gruppen, Abteilungen,
// Farben, Passwort-Hash) sowie den globalen In-Memory-Zustand (db,
// currentDepartment, currentTab) fest. Sie stellt keine Funktionen, sondern nur
// Daten bereit, auf die alle weiteren Module (js/store.js, js/board.js,
// Daten bereit, auf die alle weiteren Module (js/store.js, js/board/board.js,
// js/gantt.js, js/plan/*, ...) zugreifen. Auf dem Plan-Gantt lädt zusätzlich
// js/plan/plan-state.js Zustand für die Planungsseite.
@@ -46,4 +46,19 @@ const DEPARTMENTS = {
ELT: { label: 'Elektro', icon: '' },
HLS: { label: 'HLS', icon: '' },
ARCH: { label: 'Architektur', icon: '' }
};
};
// TAB_SLUGS / TAB_BY_SLUG: sprechende URL-Abschnitte für die Tabs, damit jede
// Abteilungs-/Tab-Kombination eine eigene Seite hat (z. B. "/HLS/Auslastung").
// Wird von js/ui.js (applyUrlRoute/updateRouteUrl) und dem Server genutzt.
const TAB_SLUGS = {
board: 'Projektübersicht',
load: 'Auslastung',
projects:'Projekte',
people: 'Projektbeteiligte'
};
const TAB_BY_SLUG = Object.fromEntries(Object.entries(TAB_SLUGS).map(([k,v]) => [v,k]));
// PLAN_SLUG: URL-Schlüssel für die Projektplan-Seite (project-plan.html), im
// gleichen Deep-Link-Schema wie die Tabs: "/<Abteilung>/Projektplan".
const PLAN_SLUG = 'Projektplan';
+12 -7
View File
@@ -8,8 +8,8 @@
// initUiState() und syncRangeDisplay() bereit und nutzt loadUiState()/
// loadTheme()/loadHeaderState() aus js/ui.js, switchDepartment() aus
// js/store.js, showTab() aus js/tabs-auth.js sowie die Render-Funktionen
// renderBoard()/renderLoad()/renderProjects()/renderPeople() aus js/board.js,
// js/load.js, js/projects.js, js/people.js.
// renderBoard()/renderLoad()/renderProjects()/renderPeople() aus js/board/board.js,
// js/load/load.js, js/projects/projects.js, js/people/people.js.
// renderAll: Convenience um UI-Elemente zu initialisieren
function renderAll(){
@@ -24,10 +24,16 @@ function renderAll(){
// initUiState: stellt beim Start den UI-Zustand her (LocalStorage-UI-State,
// Theme, Header-Status), setzt Titel und aktive Abteilungs-Schaltfläche und
// zeigt den ersten Tab an – passwortgeschützte Tabs ('projects'/'people')
// werden beim Start nie direkt aktiviert. Kein Rückgabewert.
// zeigt den ersten Tab an. Eine Deep-Link-URL (z. B. "/HLS/Auslastung") aus
// applyUrlRoute() übersteuert dabei Abteilung und Tab; passwortgeschützte Tabs
// öffnen das Passwort-Modal (showTab ohne skipAuth). Kein Rückgabewert.
function initUiState(){
loadUiState();
const route = applyUrlRoute();
if(route && DEPARTMENTS[route.department]){
currentDepartment = route.department;
currentTab = route.tab;
}
loadTheme();
loadHeaderState();
document.querySelectorAll('.dept-tab').forEach(btn => {
@@ -39,9 +45,8 @@ function initUiState(){
if(titleEl) titleEl.textContent = info.icon + ' Projektübersicht ' + info.label;
const tab = ['board','load','projects','people'].includes(currentTab) ? currentTab : DEFAULT_TAB;
// Beim initialen Start niemals einen passwortgeschützten Tab direkt anzeigen.
const safeTab = (tab === 'projects' || tab === 'people') ? DEFAULT_TAB : tab;
showTab(safeTab, true);
// Geschützte Tabs ('projects'/'people') verlangen hier ihr Passwort.
showTab(tab);
}
// syncRangeDisplay: schreibt den aus zwei Datumsfeldern (startId/endId)
+1 -1
View File
@@ -6,7 +6,7 @@
// people → projects → load → gantt → …). Es stellt renderLoad(), das LP-
// Aufwand-Modal und das Neues-Projekt-Modal bereit. Genutzt werden LPHS/ROLES
// aus js/globals.js, currentWeek()/save() aus js/store.js, guardWeekLocked()
// aus js/weeks.js sowie peopleByRole()/assignKey() aus js/board.js/js/utils.js.
// aus js/weeks.js sowie peopleByRole()/assignKey() aus js/board/board.js/js/utils.js.
// Die Auslastungs-Logik (berechneAuslastung, lpActiveList, faktorFormat,
// pdfLoadAmpelColor, LOAD_BAR_MAX) wird zusätzlich von js/pdf.js für den
// PDF-Export wiederverwendet.
+2 -2
View File
@@ -8,10 +8,10 @@
// vor js/init.js); exportPDF() hängt am Export-Button von Test.html und nutzt
// die per CDN eingebundene Bibliothek pdfmake (offline nicht verfügbar). Es
// liest die aktuelle Woche über currentWeek() aus js/store.js, Personen über
// peopleByRole() aus js/board.js, Helfer wie assignKey()/sortGroups()/
// peopleByRole() aus js/board/board.js, Helfer wie assignKey()/sortGroups()/
// formatWeekDate() aus js/utils.js sowie die Auslastungs-Berechnung
// (berechneAuslastung, lpActiveList, faktorFormat, pdfLoadAmpelColor,
// LOAD_BAR_MAX) aus js/load.js. Das Modul stellt ausschließlich exportPDF()
// LOAD_BAR_MAX) aus js/load/load.js. Das Modul stellt ausschließlich exportPDF()
// bereit.
// Farbkonstanten des PDF-Layouts: Rollen-Hintergründe, neutrale bzw.
@@ -4,12 +4,12 @@
// Diese Datei rendert den Personen-Tab (Tab "Projektbeteiligte" in `Test.html`)
// und verwaltet die globale Personenliste pro Abteilung: Anlegen, Bearbeiten,
// Löschen, Rollen-Auswahl, Drag-and-Drop-Sortierung sowie Urlaub/Abwesenheiten.
// Sie wird von `Test.html` nach `js/board.js` (vor `js/projects.js`) geladen
// Sie wird von `Test.html` nach `js/board/board.js` (vor `js/projects/projects.js`) geladen
// und stellt globale Funktionen wie `addPerson()`, `delPerson()`,
// `editPerson()`, `renderPeople()` und `addAbsence()` bereit. Genutzt wird sie
// u.a. von `js/board.js` (`renderBoard`), `js/gantt.js` und
// u.a. von `js/board/board.js` (`renderBoard`), `js/gantt.js` und
// `js/plan/plan-modals.js`; die Sortier-Hilfe `getDragAfterElement()` liegt in
// `js/projects.js`.
// `js/projects/projects.js`.
// addPerson: fügt eine neue Person der globalen Liste hinzu und
// synchronisiert sie in die aktuelle Sitzung.
+9 -4
View File
@@ -3,8 +3,9 @@
// -----------------------------
// Dieses Modul wird als erstes der plan-*-Module von public/project-plan.html
// geladen und definiert window.PlanApp als gemeinsamen Zustand aller
// Projektplan-Module. Es liest die URL-Parameter (department, weekLabel,
// projNr, projName), über die das zu bearbeitende Projekt adressiert wird.
// Projektplan-Module. Es liest die URL-Route (Abteilung + Projektname, z. B.
// "/HLS/Projektplan/Gymnasium%20Hemer") und die URL-Parameter (weekLabel,
// projNr), über die das zu bearbeitende Projekt adressiert wird.
// Nach DOMContentLoaded werden Theme, Toolbar-Buttons und die Sitzungsdaten
// über die Server-API geladen. Die hier definierten Funktionen (savePlan,
// isLocked, showToast u. a.) werden über app.* den anderen plan-Modulen
@@ -33,10 +34,14 @@ window.PlanApp = {
(function(){
const app = window.PlanApp;
app.department = app.params.get('department') || 'ELT';
// Abteilung und Projektname aus dem Deep-Link-Pfad
// "/<Abteilung>/Projektplan/<Projektname>" lesen. Fallback auf die früheren
// Query-Parameter ?department=/&projName= für alte project-plan.html-Links.
const routeMatch = window.location.pathname.match(/^\/([^/]+)\/(?:Projektplan|project-plan\.html)(?:\/(.+))?\/?$/);
app.department = routeMatch ? routeMatch[1] : (app.params.get('department') || 'ELT');
app.weekLabel = app.params.get('weekLabel');
app.projNr = app.params.get('projNr') || '';
app.projName = app.params.get('projName') || '';
app.projName = routeMatch && routeMatch[2] ? decodeURIComponent(routeMatch[2]) : (app.params.get('projName') || '');
// init: Einstiegspunkt nach DOMContentLoaded. Übernimmt das Theme aus
// localStorage/System, prüft die URL-Parameter und bricht mit Fehlermeldung
@@ -4,12 +4,12 @@
// Diese Datei rendert den Projekte-Tab (Tab "Projekte" in `Test.html`) als
// sortierbare Listenansicht: Projekte werden nach Gruppe ("Aktive Projekte",
// "Kleine Projekte" usw.) gruppiert, inline bearbeitbar und per
// Drag-and-Drop umsortiert. Sie wird von `Test.html` nach `js/people.js`
// (vor `js/load.js`) geladen und stellt globale Funktionen wie
// Drag-and-Drop umsortiert. Sie wird von `Test.html` nach `js/people/people.js`
// (vor `js/load/load.js`) geladen und stellt globale Funktionen wie
// `renderProjects()`, `editProjectField()`, `editProjectActiveLP()` sowie die
// Drag-and-Drop-Handler und die Sortier-Hilfe `getDragAfterElement()` bereit.
// Letztere wird auch von `js/people.js` (Personen-Sortierung) genutzt;
// `renderBoard()` aus `js/board.js` wird nach Änderungen aktualisiert.
// Letztere wird auch von `js/people/people.js` (Personen-Sortierung) genutzt;
// `renderBoard()` aus `js/board/board.js` wird nach Änderungen aktualisiert.
// delProjectFromList: löscht ein Projekt (per Bestätigungsdialog) in der
// Listen-Ansicht. Parameter `id`: Projekt-ID. Keine Rückgabe; bei gesperrter
@@ -133,7 +133,7 @@ function handleDragEnd(event){
// gezogene Zeile bei Mausposition `y` abgelegt werden soll (Suche nach dem
// Element mit der kleinsten negativen Distanz zur Mitte). Rückgabe:
// Ziel-Element oder undefined (→ ans Ende anfügen). Wird auch von
// `js/people.js` für die Personen-Sortierung verwendet.
// `js/people/people.js` für die Personen-Sortierung verwendet.
function getDragAfterElement(container, y){
const draggableElements = [...container.querySelectorAll('.person-list-item:not([style*="opacity"])')];
return draggableElements.reduce((closest, child) => {
+1 -1
View File
@@ -7,7 +7,7 @@
// und Auslastung) und zeigt sie in einem Vollbild-Overlay. Genutzt werden
// showTab() aus js/tabs-auth.js, switchDepartment() aus js/store.js,
// setHeaderCollapsed() aus js/ui.js sowie renderBoard()/renderLoad() aus
// js/board.js/js/load.js. Der gesamte Lauf-Zustand liegt in den
// js/board/board.js/js/load/load.js. Der gesamte Lauf-Zustand liegt in den
// Modulvariablen am Dateikopf.
// showModeActive: true, solange der Show Mode läuft
+6 -5
View File
@@ -7,7 +7,7 @@
// Sie wird von `Test.html` nach `js/csv.js` und `js/server.js` geladen und stellt
// die globalen Funktionen `save()`, `syncAllToServer()`, `switchDepartment()`,
// `load()`, `seed()` und `demoProj()` bereit. Aufrufer sind u.a. `js/weeks.js`,
// `js/board.js`, `js/people.js`, `js/projects.js` und `js/load.js`; das Speichern
// `js/board/board.js`, `js/people/people.js`, `js/projects/projects.js` und `js/load/load.js`; das Speichern
// ist über `saveSyncTimer` (in `js/globals.js` deklariert) um 500 ms debounced.
// save: synchronisiert die aktuellen Daten als CSV-Dateien zum Server.
@@ -62,6 +62,7 @@ function switchDepartment(dept){
if(!DEPARTMENTS[dept]) return;
currentDepartment = dept;
saveUiState();
updateRouteUrl(dept, currentTab);
// UI-Status der Abteilungs-Tabs aktualisieren
document.querySelectorAll('.dept-tab').forEach(btn => {
@@ -118,11 +119,11 @@ function load(){
}
console.log(`Server-Load erfolgreich: ${db.weeks.length} Sitzung(en).`);
}
// Geschützte Tabs dürfen nicht ohne Passwort angezeigt werden, auch wenn
// sie im UI-State gespeichert waren.
if(currentTab === 'projects' || currentTab === 'people') currentTab = DEFAULT_TAB;
// Geschützte Tabs ('projects'/'people') dürfen nur mit Passwort angezeigt
// werden. showTab() öffnet dafür automatisch das Passwort-Modal – auch
// wenn der Tab per Deep-Link-URL (z. B. "/ELT/Projekte") gewählt wurde.
renderAll();
showTab(currentTab, true);
showTab(currentTab);
})
.catch(err => {
console.error('Laden vom Server fehlgeschlagen:', err);
+3 -2
View File
@@ -9,8 +9,8 @@
// ausstehende Aktion wird in requestedAction (js/globals.js) gemerkt – davon
// profitieren auch die Passwort-Gates in js/weeks.js (Löschen/Entsperren von
// Sitzungen). Gerendert werden beim Tab-Wechsel renderBoard()/renderLoad()/
// renderProjects()/renderPeople() aus js/board.js, js/load.js, js/projects.js,
// js/people.js.
// renderProjects()/renderPeople() aus js/board/board.js, js/load/load.js, js/projects/projects.js,
// js/people/people.js.
// showTab: wechselt zwischen Ansichten; für sensible Tabs wird ein Passwort verlangt
function showTab(t, skipAuth = false){
@@ -24,6 +24,7 @@ function showTab(t, skipAuth = false){
}
currentTab = t;
saveUiState();
updateRouteUrl(currentDepartment, t);
['board','projects','load','people'].forEach(x=>{
const el = document.getElementById(x);
+30
View File
@@ -33,6 +33,36 @@ function loadUiState(){
}
}
// ---------- Deep-Link-Routen (Abteilung + Tab als URL) ----------
// applyUrlRoute: wertet einen Deep-Link "/<Abteilung>/<Tab>" aus der URL aus,
// z. B. "/HLS/Auslastung" oder "/ELT/Projektübersicht". Gültige Routen liefern
// { department, tab }, alles andere (auch file://-Pfade) liefert null.
function applyUrlRoute(){
try {
const m = window.location.pathname.match(/^\/([^/]+)\/([^/]+)\/?$/);
if(!m) return null;
const dept = m[1];
const tab = TAB_BY_SLUG[decodeURIComponent(m[2])];
if(!DEPARTMENTS[dept] || !tab) return null;
return { department: dept, tab };
} catch (err) {
return null;
}
}
// updateRouteUrl: schreibt Abteilung + aktiven Tab als sprechende URL in die
// Adresszeile (z. B. "/HLS/Auslastung"), ohne die Seite neu zu laden. Nur über
// HTTP (nicht per file://) und nur bei bekannter Abteilung/Tab. Keine Rückgabe.
function updateRouteUrl(dept, tab){
try {
if(!window.location.protocol || window.location.protocol.indexOf('http') !== 0) return;
const slug = TAB_SLUGS[tab];
if(!slug || !DEPARTMENTS[dept]) return;
window.history.replaceState(null, '', '/' + dept + '/' + slug);
} catch (err) {}
}
// ---------- Kollabierbarer Header ----------
// HEADER_COLLAPSED_KEY: LocalStorage-Key für den Einklapp-Zustand des Header-Menüs
+1 -1
View File
@@ -5,7 +5,7 @@
// ID-, Sortier- und Datumsfunktionen) und wird nach js/globals.js von beiden
// HTML-Einstiegspunkten geladen. Sie stellt ausschließlich globale Funktionen
// ohne eigenen Zustand bereit; genutzt wird sie praktisch von allen Modulen,
// u. a. js/csv.js, js/board.js, js/load.js sowie den Plan-Modulen unter js/plan/*
// u. a. js/csv.js, js/board/board.js, js/load/load.js sowie den Plan-Modulen unter js/plan/*
// (z. B. für ISO-Datumsformate und Werktage) und von js/gantt.js.
// departmentParam: gibt ein Query-String-Fragment fuer die aktuelle Abteilung zurueck.
+1 -1
View File
@@ -6,7 +6,7 @@
// Sie wird von `Test.html` nach `js/store.js` geladen und stellt globale
// Funktionen wie `currentWeek()`, `switchWeek()`, `newWeek()`, `cloneWeek()`,
// `applyAutoLock()`, `guardWeekLocked()` und `deleteWeek()` bereit. Genutzt wird
// sie u.a. von `js/board.js` (`renderBoard`, `isWeekLocked`), `js/store.js`
// sie u.a. von `js/board/board.js` (`renderBoard`, `isWeekLocked`), `js/store.js`
// (`load`) und `js/tabs-auth.js` (Passwort-Aktionen für Entsperren/Löschen).
// refreshWeekSelect: aktualisiert das Dropdown `weekSelect` mit allen Sitzungen
+17 -16
View File
@@ -3,8 +3,9 @@
PROJEKTPLAN-ANSICHT: zeigt für ein einzelnes Projekt ein GANTT-Diagramm mit TODO- und
Meilenstein-Zeilen, Abhängigkeiten, Zoom, kritischem Pfad, Auto-Schedule, Ressourcen-
Auslastung und Abwesenheiten der Projektbeteiligten. Die Seite wird über openProjectPlan()
in js/gantt.js in einem neuen Tab geöffnet und über URL-Parameter (Abteilung, Woche,
Projekt-Nr./Name) adressiert. Sie lädt styles.css und ausschließlich die gemeinsamen
in js/gantt.js in einem neuen Tab geöffnet und per Deep-Link-Route
"/<Abteilung>/Projektplan/<Projektname>" adressiert; Woche und Projekt-Nr.
kommen als URL-Parameter (weekLabel, projNr). Sie lädt styles.css und ausschließlich die gemeinsamen
Module js/globals.js, js/utils.js, js/ui.js, js/date-picker.js, js/csv.js, js/server.js
und js/gantt.js sowie danach die Plan-Module js/plan/plan-state.js,
js/plan/plan-build-gantt.js, js/plan/plan-gantt.js, js/plan/plan-drag.js,
@@ -18,7 +19,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Projektplan</title>
<link rel="stylesheet" href="styles.css?v=3">
<link rel="stylesheet" href="/styles.css?v=3">
<style>
.plan-page { min-height: 100vh; display: flex; flex-direction: column; }
.plan-header {
@@ -313,18 +314,18 @@
</div>
</div>
<script src="js/globals.js?v=5"></script>
<script src="js/utils.js?v=5"></script>
<script src="js/ui.js?v=5"></script>
<script src="js/date-picker.js?v=5"></script>
<script src="js/csv.js?v=5"></script>
<script src="js/server.js?v=5"></script>
<script src="js/gantt.js?v=5"></script>
<script src="js/plan/plan-state.js?v=5"></script>
<script src="js/plan/plan-build-gantt.js?v=5"></script>
<script src="js/plan/plan-gantt.js?v=5"></script>
<script src="js/plan/plan-drag.js?v=5"></script>
<script src="js/plan/plan-modals.js?v=5"></script>
<script src="js/plan/plan-schedule.js?v=5"></script>
<script src="/js/globals.js?v=5"></script>
<script src="/js/utils.js?v=5"></script>
<script src="/js/ui.js?v=5"></script>
<script src="/js/date-picker.js?v=5"></script>
<script src="/js/csv.js?v=5"></script>
<script src="/js/server.js?v=5"></script>
<script src="/js/gantt.js?v=5"></script>
<script src="/js/plan/plan-state.js?v=5"></script>
<script src="/js/plan/plan-build-gantt.js?v=5"></script>
<script src="/js/plan/plan-gantt.js?v=5"></script>
<script src="/js/plan/plan-drag.js?v=5"></script>
<script src="/js/plan/plan-modals.js?v=5"></script>
<script src="/js/plan/plan-schedule.js?v=5"></script>
</body>
</html>