// finder.js – Logik für den Step-basierten Finder im Tab 2 mit YAML-Ausgabe
let steps = []; // Alle geladenen Schritte aus structure.yml
let answers = []; // User-Antworten
let selectedBundesland = ''; // Aktuelles Bundesland
let currentPath = []; // Aktueller Pfad durch den Entscheidungsbaum
// Lädt Finderstruktur aus YML und speichert sie global
async function loadFinderStructure() {
try {
const response = await fetch('Steuerungsdateien/finder.yml');
const text = await response.text();
const data = jsyaml.load(text);
steps = data.steps;
console.log('[DEBUG] Finderstruktur geladen:', steps);
resetFinder();
renderBundeslandStep();
// Verstecke Persona-Empfehlungen beim Finder-Tab (nicht mehr benötigt)
// Zeige Empfehlungsbereich beim Finder-Tab an (nicht mehr benötigt)
} catch (err) {
console.error("Fehler beim Laden der structure.yml:", err);
}
}
// Setzt den Finder zurück
function resetFinder() {
answers = [];
selectedBundesland = '';
currentPath = ['step1'];
document.getElementById('result').style.display = 'none';
document.getElementById('dynamic-steps').innerHTML = '';
}
// Baut das initiale Bundesland-Auswahlfeld mit Arrow und Styling
function renderBundeslandStep() {
const step1 = steps.find(s => s.id === 'step1');
if (!step1) return;
const container = document.getElementById('dynamic-steps');
container.innerHTML = ''; // Reset
const div = document.createElement('div');
div.className = 'step active';
div.id = 'step1';
const label = document.createElement('label');
label.textContent = step1.frage;
div.appendChild(label);
// Erstelle den wrapper mit Klasse für bessere Auswählbarkeit
const wrapper = document.createElement('div');
wrapper.className = 'select-wrapper'; // NEU
wrapper.style.position = 'relative';
wrapper.style.display = 'inline-block'; // NEU
const select = document.createElement('select');
select.className = 'select purple auto-width';
select.id = 'bundesland-steps';
select.name = 'bundesland';
const defaultOpt = document.createElement('option');
defaultOpt.textContent = 'Bitte wählen';
defaultOpt.value = '';
select.appendChild(defaultOpt);
step1.options.forEach(opt => {
const option = document.createElement('option');
option.value = opt.value;
option.textContent = opt.label;
select.appendChild(option);
});
// Vorauswahl des Bundeslandes, falls vorhanden
if (selectedBundesland) {
select.value = selectedBundesland;
}
select.addEventListener('change', (e) => {
const val = e.target.value;
if (val !== '') {
// Wenn Bundesland geändert wird, Pfad neu berechnen und alle nachfolgenden Steps entfernen
recalculatePathFrom('step1', val);
onBundeslandSelected(val);
}
});
const arrow = document.createElement('div');
arrow.className = 'select-arrow';
wrapper.appendChild(select);
wrapper.appendChild(arrow);
div.appendChild(wrapper);
const info = document.createElement('div');
info.className = 'info';
info.textContent = step1.info;
div.appendChild(info);
container.appendChild(div);
setTimeout(() => {
resizeSelect(select);
}, 0);
}
// Wird aufgerufen, wenn das Bundesland gewählt wurde (step1)
function onBundeslandSelected(value) {
selectedBundesland = value;
answers[0] = value;
document.getElementById('result').style.display = 'none';
// Alle nachfolgenden Steps entfernen
removeStepsAfter('step1');
// Step 2 rendern
const step2 = steps.find(s => s.id === 'step2');
if (step2) renderStep(step2);
}
// Rendert einen Step (Frage + Optionen)
function renderStep(step) {
const container = document.getElementById('dynamic-steps');
// Prüfen, ob dieser Step bereits existiert
let stepElement = document.getElementById(step.id);
if (stepElement) {
// Falls der Step bereits existiert, nur Info anzeigen
const info = stepElement.querySelector('.info');
if (info) info.style.display = 'block';
// Falls der Step bereits existiert und eine Antwort hat, markiere den Button
const stepIndex = steps.findIndex(s => s.id === step.id);
const selectedValue = answers[stepIndex];
if (selectedValue) {
const buttons = stepElement.querySelectorAll('button');
buttons.forEach(btn => {
if (btn.dataset.value === selectedValue) {
btn.classList.add('selected');
} else {
btn.classList.remove('selected');
}
});
}
stepElement.scrollIntoView({ behavior: 'smooth' });
return;
}
// Neuen Step erstellen
const div = document.createElement('div');
div.className = 'step active';
div.id = step.id;
const frage = document.createElement('label');
frage.textContent = step.frage;
div.appendChild(frage);
const buttonGroup = document.createElement('div');
buttonGroup.className = 'button-group';
step.options.forEach(opt => {
const btn = document.createElement('button');
btn.type = 'button';
btn.className = 'button';
btn.textContent = opt.label;
btn.dataset.value = opt.value;
// Wenn bereits eine Antwort ausgewählt ist, markieren
const stepIndex = steps.findIndex(s => s.id === step.id);
if (answers[stepIndex] === opt.value) {
btn.classList.add('selected');
}
btn.onclick = () => {
// Vorher ausgewählte Buttons deselektieren
buttonGroup.querySelectorAll('button').forEach(b => b.classList.remove('selected'));
btn.classList.add('selected');
// Antwort speichern
const stepIndex = steps.findIndex(s => s.id === step.id);
answers[stepIndex] = opt.value;
// Info ausblenden
div.querySelector('.info').style.display = 'none';
// Pfad neu berechnen und alle nachfolgenden Steps entfernen
recalculatePathFrom(step.id, opt.value);
removeStepsAfter(step.id);
// Abhängig von der Option weitergehen oder Ergebnis anzeigen
if (opt.result) {
// Am Ende des Pfades - Ergebnis anzeigen
const code = buildResultCode();
loadResult(code);
} else if (opt.next) {
// Nächsten Step anzeigen
const nextStep = steps.find(s => s.id === opt.next);
if (nextStep) renderStep(nextStep);
}
};
buttonGroup.appendChild(btn);
});
div.appendChild(buttonGroup);
const info = document.createElement('div');
info.className = 'info';
info.textContent = step.info;
div.appendChild(info);
container.appendChild(div);
div.scrollIntoView({ behavior: 'smooth' });
// Step zum aktiven Pfad hinzufügen
if (!currentPath.includes(step.id)) {
currentPath.push(step.id);
}
}
// Berechnet den Pfad ausgehend von einem bestimmten Step neu
function recalculatePathFrom(stepId, selectedValue) {
const stepIndex = steps.findIndex(s => s.id === stepId);
// Aktualisiere den aktuellen Pfad (entferne alle nach dem geänderten Step)
currentPath = currentPath.slice(0, currentPath.indexOf(stepId) + 1);
// Aktualisiere die Antworten (behalte nur Antworten bis zum aktuellen Step)
answers = answers.slice(0, stepIndex + 1);
// Setze die ausgewählte Antwort
answers[stepIndex] = selectedValue;
console.log('[DEBUG] Neuer Pfad berechnet ab', stepId, 'Pfad:', currentPath, 'Antworten:', answers);
// Ergebnis ausblenden, da sich der Pfad geändert hat
document.getElementById('result').style.display = 'none';
}
// Entfernt alle Steps nach dem angegebenen Step aus dem DOM
function removeStepsAfter(stepId) {
const container = document.getElementById('dynamic-steps');
const stepElements = container.querySelectorAll('.step');
let removeFlag = false;
stepElements.forEach(el => {
if (removeFlag) {
container.removeChild(el);
}
if (el.id === stepId) {
removeFlag = true;
}
});
// Ergebnis ausblenden
document.getElementById('result').style.display = 'none';
}
// Generiert den Code für das Ergebnis aus den Antworten
function buildResultCode() {
// Bundesland-Code mapping - korrigiert für die tatsächlichen Verzeichnisnamen
const bundeslandMapping = {
'BW': '1_BW', // Baden-Württemberg
'BY': '2_BY', // Bayern
'BE': '3_BE', // Berlin
'BB': '4_BB', // Brandenburg
'HB': '5_HB', // Bremen
'HH': '6_HH', // Hamburg
'HE': '7_HE', // Hessen
'MV': '8_MV', // Mecklenburg-Vorpommern
'NI': '9_NI', // Niedersachsen
'NW': '10_NW', // Nordrhein-Westfalen
'RP': '11_RP', // Rheinland-Pfalz
'SL': '12_SL', // Saarland
'SN': '13_SN', // Sachsen
'ST': '14_ST', // Sachsen-Anhalt
'SH': '15_SH', // Schleswig-Holstein
'TH': '16_TH' // Thüringen
};
console.log('[DEBUG] Alle Antworten vor Filterung:', answers);
// Stelle sicher, dass answers ein Array ist und alle Elemente definiert sind
const cleanAnswers = answers.filter(answer => answer !== undefined && answer !== null && answer !== '');
console.log('[DEBUG] Bereinigte Antworten:', cleanAnswers);
if (cleanAnswers.length === 0) {
console.error('[ERROR] Keine gültigen Antworten gefunden');
return 'error/no-answers';
}
const bundesland = bundeslandMapping[cleanAnswers[0]] || cleanAnswers[0];
// Spezielle Behandlung für HS (Hochschulstudium)
let restCode;
if (cleanAnswers[1] === 'HS') {
// Bei HS: HS-BA-1F oder HS-MA-2F
restCode = cleanAnswers.slice(1).join('-');
} else {
// Bei LA: LA-BA-1F oder LA-MA-2F
restCode = cleanAnswers.slice(1).join('-');
}
const code = `${bundesland}/${restCode}`;
console.log('[DEBUG] Finaler Code:', code);
return code;
}
// Ergebnis anzeigen am Ende des Flows
async function loadResult(code) {
// 1. Ermittle den Pfad zur .md-Datei-Liste (z.B. Bundeslaender/1_BW/BA-2F.md)
// 2. Lade die Datei mit den Pfaden zu den eigentlichen Texten
// 3. Lade alle .md-Dateien in der Reihenfolge, parse sie und zeige sie als an
let codeFile = `Bundeslaender/${code}.md`;
const resultContainer = document.getElementById('result');
if (!resultContainer) {
console.error('Result container nicht gefunden');
return;
}
// Zeige Result-Container an
resultContainer.style.display = 'block';
// Setze Headline
const headlineElement = document.getElementById('finder-headline');
if (headlineElement) {
headlineElement.textContent = 'Finder Ergebnis';
}
// Leere bisherigen Inhalt
const textContentElement = document.getElementById('finder-text-content');
if (textContentElement) {
textContentElement.innerHTML = '';
}
// Hilfsfunktion: Markdown-Abschnitt parsen und als Article rendern
function renderMarkdownArticle(mdText) {
// Splitte in Abschnitte nach ##
const sections = mdText.split(/\n(?=## )/);
return sections.map(section => {
let lines = section.trim().split('\n');
if (!lines[0].startsWith('##')) return '';
let headline = lines[0].replace(/^## /, '');
let marginal = '';
let textStart = 1;
// Prüfe zweite Zeile auf Link
if (lines[1] && lines[1].startsWith('http')) {
const linkLine = lines[1];
// Prüfe ob es ein Markdown-Link mit Text ist: [Text](URL)
const markdownLinkMatch = linkLine.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
if (markdownLinkMatch) {
// Markdown-Link gefunden: [Text](URL)
const linkText = markdownLinkMatch[1];
const linkUrl = markdownLinkMatch[2];
marginal = `${linkText}
`;
} else {
// Nur URL ohne Text - Fallback verwenden
marginal = `Externer Link
`;
}
textStart = 2;
}
let textContent = lines.slice(textStart).join('\n');
textContent = textContent
.replace(/\*\*(.*?)\*\*/g, '$1')
.replace(/\*(.*?)\*/g, '$1')
// Markdown-Links verarbeiten: [Text](URL)
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1')
.replace(/\n\n/g, '
')
.replace(/^(?!<[h1-6])/gm, '
')
.replace(/$/gm, '
')
.replace(/<\/p>/g, '');
return `
${headline}
${textContent}
`;
}).join('');
}
// Lade die Datei mit den Pfaden zu den eigentlichen Texten
try {
const pfadRes = await fetch(codeFile);
if (!pfadRes.ok) throw new Error('Datei nicht gefunden: ' + codeFile);
const pfadText = await pfadRes.text();
const mdFiles = pfadText.split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#'));
let allArticles = '';
for (const mdFile of mdFiles) {
try {
// Entferne führenden Slash falls vorhanden
const cleanPath = mdFile.startsWith('/') ? mdFile.substring(1) : mdFile;
// Füge Bundeslaender-repo/ hinzu, falls nicht bereits vorhanden
const fullPath = cleanPath.startsWith('Bundeslaender-repo/') ? cleanPath : `Bundeslaender-repo/${cleanPath}`;
const mdRes = await fetch(fullPath);
if (!mdRes.ok) throw new Error('Datei nicht gefunden: ' + fullPath);
const mdText = await mdRes.text();
allArticles += renderMarkdownArticle(mdText);
} catch (err) {
allArticles += `Datei nicht gefunden
${mdFile}
`;
}
}
// Zeige alle Artikel im Text-Content-Bereich an
if (textContentElement) {
textContentElement.innerHTML = allArticles;
}
resultContainer.style.display = 'block';
resultContainer.scrollIntoView({ behavior: 'smooth' });
} catch (err) {
if (textContentElement) {
textContentElement.innerHTML = ``;
}
resultContainer.style.display = 'block';
}
}
// Lädt und zeigt die zusätzlichen Abschnitte an (nicht mehr verwendet)
function loadAdditionalSections(sections, resultContainer) {
// Funktion nicht mehr benötigt
return;
// Trennlinie hinzufügen vor den zusätzlichen Abschnitten
const divider = document.createElement('hr');
divider.className = 'section-divider';
resultContainer.appendChild(divider);
// Jeden zusätzlichen Abschnitt laden
sections.forEach((sectionCode, index) => {
const path = `data/finder/texte/${sectionCode}.yml`;
console.log(`[DEBUG] Lade zusätzlichen Abschnitt ${index + 1} von:`, path);
fetch(path)
.then(res => res.ok ? res.text() : null)
.then(txt => txt ? jsyaml.load(txt) : null)
.then(data => {
if (!data) {
console.warn(`[WARN] Zusätzlicher Abschnitt ${sectionCode} konnte nicht geladen werden.`);
return;
}
// Zusätzlichen Abschnitt hinzufügen
appendAdditionalSection(data, index + 1, sectionCode, resultContainer);
})
.catch(err => {
console.error(`[ERROR] Fehler beim Laden des zusätzlichen Abschnitts ${sectionCode}:`, err);
});
});
}
// Fügt einen zusätzlichen Abschnitt zum DOM hinzu
function appendAdditionalSection(data, index, sectionCode, resultContainer) {
if (!resultContainer) {
console.error('[ERROR] Kein gültiger Container zum Anhängen des zusätzlichen Abschnitts');
return;
}
// Neuen Abschnitt erstellen
const section = document.createElement('div');
section.className = 'additional-section';
section.id = `section-${sectionCode}`;
section.innerHTML = `
${data.Headline || `Zusätzliche Information ${index}`}
${data.Text || '...'}
${data.Tags || ''}
${data.Marginal || ''}
`;
resultContainer.appendChild(section);
}
// Fügt einen Reset-Button hinzu (optional)
function addResetButton() {
const container = document.getElementById('dynamic-steps').parentElement;
let resetBtn = document.getElementById('reset-finder');
if (!resetBtn) {
resetBtn = document.createElement('button');
resetBtn.id = 'reset-finder';
resetBtn.className = 'button secondary';
resetBtn.textContent = 'Neu starten';
resetBtn.onclick = () => {
resetFinder();
renderBundeslandStep();
// Stelle sicher, dass der Finder-Tab aktiv bleibt
ensureFinderTabActive();
if (typeof showTab === 'function') showTab('tab2');
};
container.appendChild(resetBtn);
}
}
// Empfehlungsbereich-Funktion entfernt, da Button nicht mehr existiert
// Stellt sicher, dass der Finder-Tab aktiv bleibt
function ensureFinderTabActive() {
// Aktiviere Finder-Tab
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.button-tab').forEach(btn => btn.classList.remove('active'));
const finderTab = document.querySelector('.tab2');
const finderButton = document.querySelector('.button-tab[onclick*="tab2"]');
if (finderTab) finderTab.classList.add('active');
if (finderButton) finderButton.classList.add('active');
}
// Initialisierung beim Seitenladen
window.addEventListener('DOMContentLoaded', () => {
loadFinderStructure();
addResetButton(); // Optional
observeSelectChanges();
});