{ const template = `
`; const css = ` @media print { body * { visibility: hidden; } #Content1, #Content2, #Content3, #Content4 { visibility: visible; } #Content1 * { visibility: visible; } #Content2 * { visibility: visible; } #Content3 * { visibility: visible; } #Content4 * { visibility: visible; } } .hidden-print { display: none !important; } `; window.customElements.define( "renn-historie", class extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); this.shadowRoot.innerHTML = template; const style = new CSSStyleSheet(); style.replaceSync(css); this.shadowRoot.adoptedStyleSheets = [style]; } connectedCallback() { this.fetchRaces(); } // ---------------------------- API Calls --------------------------- \\ //Holt alle Rennen, die bereits abgeschlossen sind (Status 2), ruft generateRaceNodes und setupToggleButtons auf async fetchRaces() { try { const response = await fetch("/api/rennen/byStatus/?status=2"); const data = await response.json(); if (data.status && Array.isArray(data.rennen)) { this.generateRaceNodes(data.rennen); this.setupToggleButtons(); } else { console.error("Expected an array but got:", data); } } catch (error) { console.error("Error fetching race data:", error); } } //Holt die Ergebnisse für die Rennen, die angezeigt werden. Ruft displayRaceResults auf. async fetchRaceResults(raceId) { try { const response = await fetch(`/api/historie/index.php?r_id=${raceId}`); const results = await response.json(); if (results.status && Array.isArray(results.data)) { this.displayRaceResults(raceId, results.data); } else { console.error("Expected an array but got:", results); } } catch (error) { console.error("Error fetching race results:", error); } } // ---------------------------- Nodes'n'Tables --------------------------- \\ //Genereiert eine Node (Collapsible) für jedes abgeschlossene Rennen. Ruft orintSection und fetchRaceResults auf für jedes Rennen. generateRaceNodes(races) { const container = this.shadowRoot.getElementById("race-container"); const noRacesMessage = this.shadowRoot.getElementById("KeineErgebnisse"); container.innerHTML = ""; if (!races.length) { noRacesMessage.style.display = "block"; return; } // Für jedes Rennen wird eine Node erstellt (Collapsible mit Rennen Name, Datum und Überschrift) races.forEach((race) => { const raceNode = document.createElement("div"); raceNode.classList.add("row", "mt-2"); const dateObj = new Date(race.data.r_datum); const year = dateObj.getFullYear(); // Extract the year from the date const monthName = dateObj.toLocaleString("de-DE", { month: "long" }); // "März", "April", etc. const fullDate = dateObj.toLocaleDateString("de-DE", { day: "2-digit", month: "long", year: "numeric", }); // Deutsches Format raceNode.innerHTML = `

${race.data.r_name} ${fullDate}

OFFIZIELLE ERGEBNISLISTE


`; container.appendChild(raceNode); this.fetchRaceResults(race.data.r_id); //Jedes Rennen kann individuell gedruckt werden const printBtn = raceNode.querySelector(".print-button"); let date = new Date().toLocaleString(); if (printBtn) { printBtn.addEventListener("click", () => { this.printSection(`Content${race.data.r_id}`, date); }); } }); } //Zeigt die Rennergebnisse innerhalb der Nodes als Tabellen an, nach Kategorien sortiert. displayRaceResults(raceId, categories) { const container = this.shadowRoot.getElementById(`RaceTableBody${raceId}`) .parentElement.parentElement; //.parentElement().parentElement(
) container.innerHTML = ""; //Für jede Kategorie wird eine eigene Tabelle erstellt, die nur die Teilnehmer dieser Kategorie anzeigen categories.forEach((cat) => { if (cat.results.length == 0) return; // Kategorie Header z.B. Herren const heading = document.createElement("div"); heading.className = "bg-secondary text-white mb-2 mt-3 rounded d-inline-block col-12 col-lg-4 text-center sticky-top"; heading.innerHTML = `

${cat.category}

`; container.appendChild(heading); //Anzahl der Läufe ist dynamisch, weil nicht jedes Rennen die selbe Anzahl an Läufen hat let laufHeaders = ""; for (let i = 1; i <= cat.durchgaenge; i++) { laufHeaders += `
`; } // Tabelle wird erstellt, unterschiedliche Anzeige der Header für große/kleine Bildschirme const table = document.createElement("table"); table.setAttribute("data-durchgaenge", cat.durchgaenge); table.className = "table table-striped caption-top caption-dark table-fixed"; //Design //Erst Head mit dynamischen Läufen, dann Body mit Ergebnissen table.innerHTML = ` ${laufHeaders} ${cat.results .map( (result, idx) => ` ${Array.from( { length: cat.durchgaenge }, (_, i) => `` ).join("")} ` ) .join("")} `; const responsiveDiv = document.createElement("div"); responsiveDiv.className = "table-responsive"; responsiveDiv.appendChild(table); container.appendChild(responsiveDiv); }); } // -------------------- Buttons, Buttons, Buttons ------------------ \\ // Toggle buttons für die Renn-Nodes. Holt alle buttons, die dynamisch erstellt werden und einen dynamischen textContent haben. // Erstellt Eventlistener auf Klick wird entweder der Original Text des Rennens gezeigt oder "Anzeige schließen". setupToggleButtons() { const toggleButtons = this.shadowRoot.querySelectorAll('[id^="ToggleFormButton"]'); //Weil buttons erst dynamisch je nach Rennen erstellt werden toggleButtons.forEach((button) => { const contentId = button.getAttribute("data-bs-target").substring(1); const content = this.shadowRoot.getElementById(contentId); const originalText = button.textContent; // Store the original button text button.addEventListener("click", () => { if (content.classList.contains("show")) { content.classList.remove("show"); button.textContent = originalText; // Restore the original button text } else { content.classList.add("show"); button.textContent = "Anzeige schließen"; } }); }); } //Mitglieder Drucken mit custom Bereich printSection(sectionId, date) { // Section Content aus ShadowDOM holen const sectionContent = this.shadowRoot.getElementById(sectionId); if (!sectionContent) { console.error(`Section with ID ${sectionId} not found.`); return; } // Inhalt Klonen (cloneNode macht deep Copy mit Childelements) zur Sicherheit const clone = sectionContent.cloneNode(true); // Buttons enrfernen, damit sie nicht in der Druckansicht sind clone.querySelectorAll("button").forEach((btn) => btn.remove()); // Öffnet Printfenster bzw. zeigt Pop-Up, wenn Browser blockiert const printWindow = window.open("", "", "height=600,width=800"); if (!printWindow) { alert( "Pop-up blocker is enabled! Please allow pop-ups for this website to print the section." ); return; } // HTML und Style für die Druckansicht printWindow.document.write("Print"); printWindow.document.write( '' ); printWindow.document.write(` `); printWindow.document.write(""); printWindow.document.write(clone.innerHTML); printWindow.document.write(""); printWindow.document.close(); // Print and close printWindow.focus(); printWindow.print(); setTimeout(() => printWindow.close(), 1000); //Damit Print Fenster wieder zugeht } } ); }
Lauf ${i}L${i}
Platz Pl. StNr. Name Jahrgang Jhg. Ziel Zeit Ziel🏁 Abstand Diff.
${idx + 1} ${result.Startnummer ?? ''} ${result.Name} ${result.Jahr}${result["Lauf" + (i + 1)] || ""}${result.Zielzeit} ${result.Abstand == '00:00:00.00' ? "-" : result.Abstand}